diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/select/MatchFilter.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/MatchFilter.java index a88925fd583..a4b8a25e71d 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/select/MatchFilter.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/MatchFilter.java @@ -267,7 +267,15 @@ Object convertParamValue(Object paramValue) { return paramValue; } - final void convertValue( + /** + * Convert the string value to the appropriate type for the column. + * @param column the column definition + * @param strValue the string value to convert + * @param queryScopeVariables the query scope variables + * @param valueConsumer the consumer for the converted value + * @return whether the value was an array or collection + */ + final boolean convertValue( @NotNull final ColumnDefinition column, @NotNull final String strValue, @NotNull final Map queryScopeVariables, @@ -279,10 +287,12 @@ final void convertValue( for (int ai = 0; ai < accessor.length(); ++ai) { valueConsumer.accept(convertParamValue(accessor.get(ai))); } + return true; } else if (paramValue != null && Collection.class.isAssignableFrom(paramValue.getClass())) { for (final Object paramValueMember : (Collection) paramValue) { valueConsumer.accept(convertParamValue(paramValueMember)); } + return true; } else { valueConsumer.accept(convertParamValue(paramValue)); } @@ -294,6 +304,7 @@ final void convertValue( "> for column \"" + column.getName() + "\" of type " + column.getDataType().getName(), t); } } + return false; } } diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/select/RangeConditionFilter.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/RangeConditionFilter.java index 162b56a5538..ae357b93981 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/select/RangeConditionFilter.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/RangeConditionFilter.java @@ -160,13 +160,12 @@ public void init( MatchFilter.ColumnTypeConvertorFactory.getConvertor(def.getDataType()); final MutableObject realValue = new MutableObject<>(); - convertor.convertValue(def, value, compilationProcessor.getQueryScopeVariables(), - parsedValue -> { - if (realValue.getValue() != null) { - throw new IllegalArgumentException(value + " is an array type"); - } - realValue.setValue(parsedValue); - }); + boolean wasAnArrayType = convertor.convertValue( + def, value, compilationProcessor.getQueryScopeVariables(), realValue::setValue); + if (wasAnArrayType) { + throw new IllegalArgumentException("RangeConditionFilter does not support array types for column " + + columnName + " with value <" + value + ">"); + } if (colClass == double.class || colClass == Double.class) { filter = DoubleRangeFilter.makeDoubleRangeFilter(columnName, condition, (double) realValue.getValue()); @@ -231,6 +230,21 @@ private static LongRangeFilter makeInstantRangeFilter(String columnName, Conditi } } + private static LongRangeFilter makeZonedDateTimeRangeFilter(String columnName, Condition condition, long value) { + switch (condition) { + case LESS_THAN: + return new ZonedDateTimeRangeFilter(columnName, value, Long.MIN_VALUE, true, false); + case LESS_THAN_OR_EQUAL: + return new ZonedDateTimeRangeFilter(columnName, value, Long.MIN_VALUE, true, true); + case GREATER_THAN: + return new ZonedDateTimeRangeFilter(columnName, value, Long.MAX_VALUE, false, true); + case GREATER_THAN_OR_EQUAL: + return new ZonedDateTimeRangeFilter(columnName, value, Long.MAX_VALUE, true, true); + default: + throw new IllegalArgumentException("RangeConditionFilter does not support condition " + condition); + } + } + private static SingleSidedComparableRangeFilter makeComparableRangeFilter(String columnName, Condition condition, Comparable comparable) { switch (condition) { diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/select/ZonedDateTimeRangeFilter.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/ZonedDateTimeRangeFilter.java new file mode 100644 index 00000000000..bf3e292c289 --- /dev/null +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/select/ZonedDateTimeRangeFilter.java @@ -0,0 +1,109 @@ +// +// Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.table.impl.select; + +import io.deephaven.base.verify.Assert; +import io.deephaven.engine.table.ColumnDefinition; +import io.deephaven.engine.table.TableDefinition; +import io.deephaven.engine.table.impl.chunkfilter.ChunkFilter; +import io.deephaven.engine.rowset.chunkattributes.OrderedRowKeys; +import io.deephaven.engine.table.ColumnSource; +import io.deephaven.engine.table.impl.sources.ReinterpretUtils; +import io.deephaven.chunk.*; +import io.deephaven.chunk.attributes.Values; +import io.deephaven.engine.rowset.WritableRowSet; +import io.deephaven.engine.rowset.RowSet; +import io.deephaven.time.DateTimeUtils; +import org.jetbrains.annotations.NotNull; + +import java.time.ZonedDateTime; + +public class ZonedDateTimeRangeFilter extends LongRangeFilter { + + public ZonedDateTimeRangeFilter(String columnName, ZonedDateTime val1, ZonedDateTime val2) { + super(columnName, DateTimeUtils.epochNanos(val1), DateTimeUtils.epochNanos(val2), true, true); + } + + public ZonedDateTimeRangeFilter( + String columnName, ZonedDateTime val1, ZonedDateTime val2, boolean lowerInclusive, boolean upperInclusive) { + super(columnName, DateTimeUtils.epochNanos(val1), DateTimeUtils.epochNanos(val2), + lowerInclusive, upperInclusive); + } + + public ZonedDateTimeRangeFilter( + String columnName, long val1, long val2, boolean lowerInclusive, boolean upperInclusive) { + super(columnName, val1, val2, lowerInclusive, upperInclusive); + } + + @Override + public void init(@NotNull final TableDefinition tableDefinition) { + if (chunkFilter != null) { + return; + } + + final ColumnDefinition def = tableDefinition.getColumn(columnName); + if (def == null) { + throw new RuntimeException("Column \"" + columnName + "\" doesn't exist in this table, available columns: " + + tableDefinition.getColumnNames()); + } + + final Class colClass = def.getDataType(); + Assert.eq(colClass, "colClass", ZonedDateTime.class); + + longFilter = super.initChunkFilter(); + chunkFilter = new ZonedDateTimeLongChunkFilterAdapter(); + } + + @Override + public ZonedDateTimeRangeFilter copy() { + final ZonedDateTimeRangeFilter copy = + new ZonedDateTimeRangeFilter(columnName, lower, upper, lowerInclusive, upperInclusive); + copy.chunkFilter = chunkFilter; + copy.longFilter = longFilter; + return copy; + } + + @Override + public String toString() { + return "ZonedDateTimeRangeFilter(" + columnName + " in " + + (lowerInclusive ? "[" : "(") + + DateTimeUtils.epochNanosToInstant(lower) + "," + DateTimeUtils.epochNanosToInstant(upper) + + (upperInclusive ? "]" : ")") + ")"; + } + + @NotNull + @Override + WritableRowSet binarySearch( + @NotNull final RowSet selection, + @NotNull final ColumnSource columnSource, + final boolean usePrev, + final boolean reverse) { + if (selection.isEmpty()) { + return selection.copy(); + } + + // noinspection unchecked + final ColumnSource instantColumnSource = + ReinterpretUtils.zonedDateTimeToLongSource((ColumnSource) columnSource); + return super.binarySearch(selection, instantColumnSource, usePrev, reverse); + } + + private class ZonedDateTimeLongChunkFilterAdapter implements ChunkFilter { + @Override + public void filter(Chunk values, LongChunk keys, + WritableLongChunk results) { + try (final WritableLongChunk writableLongChunk = + WritableLongChunk.makeWritableChunk(values.size())) { + + final ObjectChunk objectValues = values.asObjectChunk(); + for (int ii = 0; ii < values.size(); ++ii) { + final ZonedDateTime instant = objectValues.get(ii); + writableLongChunk.set(ii, DateTimeUtils.epochNanos(instant)); + } + writableLongChunk.setSize(values.size()); + longFilter.filter(writableLongChunk, keys, results); + } + } + } +}