From a7d887cf021da71f7b5a29cac70b6cd907c310ca Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Wed, 8 Feb 2023 19:21:07 -0800 Subject: [PATCH 1/7] fix filtering nested field virtual column when used with non nested column input --- .../query/dimension/DefaultDimensionSpec.java | 5 + .../nested/NestedDataComplexColumn.java | 26 --- .../virtual/NestedFieldVirtualColumn.java | 43 +++-- .../groupby/NestedDataGroupByQueryTest.java | 167 ++++++++++++++++++ 4 files changed, 200 insertions(+), 41 deletions(-) diff --git a/processing/src/main/java/org/apache/druid/query/dimension/DefaultDimensionSpec.java b/processing/src/main/java/org/apache/druid/query/dimension/DefaultDimensionSpec.java index 0a869a92271a..5f613e59642e 100644 --- a/processing/src/main/java/org/apache/druid/query/dimension/DefaultDimensionSpec.java +++ b/processing/src/main/java/org/apache/druid/query/dimension/DefaultDimensionSpec.java @@ -41,6 +41,11 @@ public static DefaultDimensionSpec of(String dimensionName) return new DefaultDimensionSpec(dimensionName, dimensionName); } + public static DefaultDimensionSpec of(String dimensionName, ColumnType columnType) + { + return new DefaultDimensionSpec(dimensionName, dimensionName, columnType); + } + private static final byte CACHE_TYPE_ID = 0x0; private final String dimension; private final String outputName; diff --git a/processing/src/main/java/org/apache/druid/segment/nested/NestedDataComplexColumn.java b/processing/src/main/java/org/apache/druid/segment/nested/NestedDataComplexColumn.java index 2cc9cfb7b08b..2ee1a5808e90 100644 --- a/processing/src/main/java/org/apache/druid/segment/nested/NestedDataComplexColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/nested/NestedDataComplexColumn.java @@ -20,12 +20,9 @@ package org.apache.druid.segment.nested; -import org.apache.druid.java.util.common.IAE; import org.apache.druid.query.extraction.ExtractionFn; -import org.apache.druid.segment.ColumnSelector; import org.apache.druid.segment.ColumnValueSelector; import org.apache.druid.segment.DimensionSelector; -import org.apache.druid.segment.column.BaseColumn; import org.apache.druid.segment.column.ColumnHolder; import org.apache.druid.segment.column.ColumnIndexSupplier; import org.apache.druid.segment.column.ColumnType; @@ -47,29 +44,6 @@ */ public abstract class NestedDataComplexColumn implements ComplexColumn { - @Nullable - public static NestedDataComplexColumn fromColumnSelector( - ColumnSelector columnSelector, - String columnName - ) - { - ColumnHolder holder = columnSelector.getColumnHolder(columnName); - if (holder == null) { - return null; - } - BaseColumn theColumn = holder.getColumn(); - if (theColumn instanceof CompressedNestedDataComplexColumn) { - return (CompressedNestedDataComplexColumn) theColumn; - } - throw new IAE( - "Column [%s] is invalid type, found [%s] instead of [%s]", - columnName, - theColumn.getClass(), - NestedDataComplexColumn.class.getSimpleName() - ); - } - - /** * Make a {@link DimensionSelector} for a nested literal field column associated with this nested * complex column specified by a sequence of {@link NestedPathPart}. diff --git a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java index 86e9c95a803e..8b1d38940c4c 100644 --- a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java @@ -54,12 +54,14 @@ import org.apache.druid.segment.column.ValueTypes; import org.apache.druid.segment.data.IndexedInts; import org.apache.druid.segment.data.ReadableOffset; +import org.apache.druid.segment.nested.CompressedNestedDataComplexColumn; import org.apache.druid.segment.nested.NestedDataComplexColumn; import org.apache.druid.segment.nested.NestedDataComplexTypeSerde; import org.apache.druid.segment.nested.NestedPathArrayElement; import org.apache.druid.segment.nested.NestedPathFinder; import org.apache.druid.segment.nested.NestedPathPart; import org.apache.druid.segment.nested.StructuredData; +import org.apache.druid.segment.serde.NoIndexesColumnIndexSupplier; import org.apache.druid.segment.vector.BaseDoubleVectorValueSelector; import org.apache.druid.segment.vector.BaseLongVectorValueSelector; import org.apache.druid.segment.vector.NilVectorSelector; @@ -416,7 +418,7 @@ public VectorObjectSelector makeVectorObjectSelector( this.columnName, theColumn.makeVectorValueSelector(offset), capabilities.toColumnType(), - expectedType + expectedType != null ? expectedType : capabilities.toColumnType() // cast to itself in case the underlying column doesn't support object selector... ); } return theColumn.makeVectorObjectSelector(offset); @@ -600,12 +602,18 @@ public ColumnIndexSupplier getIndexSupplier( ColumnSelector selector ) { - final NestedDataComplexColumn column = NestedDataComplexColumn.fromColumnSelector(selector, this.columnName); - - if (column == null) { + ColumnHolder holder = selector.getColumnHolder(this.columnName); + if (holder == null) { return null; } - return column.getColumnIndexSupplier(parts); + BaseColumn theColumn = holder.getColumn(); + if (theColumn instanceof CompressedNestedDataComplexColumn) { + return ((CompressedNestedDataComplexColumn) theColumn).getColumnIndexSupplier(parts); + } + if (parts.isEmpty()) { + return holder.getIndexSupplier(); + } + return NoIndexesColumnIndexSupplier.getInstance(); } @Override @@ -637,17 +645,22 @@ public ColumnCapabilities capabilities(ColumnInspector inspector, String columnN } // ColumnInspector isn't really enough... we need the ability to read the complex column itself to examine // the nested fields type information to really be accurate here, so we rely on the expectedType to guide us - final ColumnCapabilities complexCapabilites = inspector.getColumnCapabilities(this.columnName); - if (complexCapabilites != null && complexCapabilites.isDictionaryEncoded().isTrue()) { - return ColumnCapabilitiesImpl.createDefault() - .setType(expectedType != null ? expectedType : ColumnType.STRING) - .setDictionaryEncoded(true) - .setDictionaryValuesSorted(true) - .setDictionaryValuesUnique(true) - .setHasBitmapIndexes(true) - .setHasNulls(expectedType == null || (expectedType.isNumeric() - && NullHandling.sqlCompatible())); + final ColumnCapabilities capabilities = inspector.getColumnCapabilities(this.columnName); + + if (capabilities != null) { + if (!capabilities.isPrimitive() && capabilities.isDictionaryEncoded().isTrue()) { + return ColumnCapabilitiesImpl.createDefault() + .setType(expectedType != null ? expectedType : ColumnType.STRING) + .setDictionaryEncoded(true) + .setDictionaryValuesSorted(true) + .setDictionaryValuesUnique(true) + .setHasBitmapIndexes(true) + .setHasNulls(expectedType == null || (expectedType.isNumeric() + && NullHandling.sqlCompatible())); + } + return capabilities; } + return capabilities(columnName); } diff --git a/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java b/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java index 9f33735c03da..cae7a3bc02da 100644 --- a/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java +++ b/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java @@ -37,6 +37,7 @@ import org.apache.druid.query.dimension.DefaultDimensionSpec; import org.apache.druid.query.expression.TestExprMacroTable; import org.apache.druid.query.filter.InDimFilter; +import org.apache.druid.query.filter.SelectorDimFilter; import org.apache.druid.query.groupby.strategy.GroupByStrategySelector; import org.apache.druid.segment.Segment; import org.apache.druid.segment.column.ColumnType; @@ -312,6 +313,172 @@ public void testGroupByNonExistentVirtualColumn() ); } + @Test + public void testGroupBySomeFieldOnStringColumn() + { + GroupByQuery groupQuery = GroupByQuery.builder() + .setDataSource("test_datasource") + .setGranularity(Granularities.ALL) + .setInterval(Intervals.ETERNITY) + .setDimensions(DefaultDimensionSpec.of("v0"), DefaultDimensionSpec.of("v1")) + .setVirtualColumns( + new NestedFieldVirtualColumn("dim", "$", "v0"), + new NestedFieldVirtualColumn("dim", "$.x", "v1") + ) + .setAggregatorSpecs(new CountAggregatorFactory("count")) + .setContext(getContext()) + .build(); + + + runResults( + groupQuery, + ImmutableList.of( + new Object[]{"100", null, 2L}, + new Object[]{"hello", null, 12L}, + new Object[]{"world", null, 2L} + ) + ); + } + + @Test + public void testGroupBySomeFieldOnStringColumnWithFilter() + { + List vals = new ArrayList<>(); + vals.add("100"); + vals.add("200"); + vals.add("300"); + GroupByQuery groupQuery = GroupByQuery.builder() + .setDataSource("test_datasource") + .setGranularity(Granularities.ALL) + .setInterval(Intervals.ETERNITY) + .setDimensions(DefaultDimensionSpec.of("v0")) + .setVirtualColumns(new NestedFieldVirtualColumn("dim", "$", "v0")) + .setAggregatorSpecs(new CountAggregatorFactory("count")) + .setContext(getContext()) + .setDimFilter(new InDimFilter("v0", vals, null)) + .build(); + + + runResults( + groupQuery, + ImmutableList.of( + new Object[]{"100", 2L} + ) + ); + } + + @Test + public void testGroupBySomeFieldOnStringColumnWithFilterNil() + { + List vals = new ArrayList<>(); + vals.add("100"); + vals.add("200"); + vals.add("300"); + GroupByQuery groupQuery = GroupByQuery.builder() + .setDataSource("test_datasource") + .setGranularity(Granularities.ALL) + .setInterval(Intervals.ETERNITY) + .setDimensions(DefaultDimensionSpec.of("v0")) + .setVirtualColumns(new NestedFieldVirtualColumn("dim", "$.x", "v0")) + .setAggregatorSpecs(new CountAggregatorFactory("count")) + .setContext(getContext()) + .setDimFilter(new InDimFilter("v0", vals, null)) + .build(); + + + runResults( + groupQuery, + ImmutableList.of() + ); + } + + @Test + public void testGroupBySomeFieldOnLongColumn() + { + GroupByQuery groupQuery = GroupByQuery.builder() + .setDataSource("test_datasource") + .setGranularity(Granularities.ALL) + .setInterval(Intervals.ETERNITY) + .setDimensions( + DefaultDimensionSpec.of("v0", ColumnType.LONG), + DefaultDimensionSpec.of("v1", ColumnType.LONG) + ) + .setVirtualColumns( + new NestedFieldVirtualColumn("__time", "$", "v0"), + new NestedFieldVirtualColumn("__time", "$.x", "v1") + ) + .setAggregatorSpecs(new CountAggregatorFactory("count")) + .setContext(getContext()) + .build(); + + + runResults( + groupQuery, + ImmutableList.of( + new Object[]{1609459200000L, NullHandling.defaultLongValue(), 8L}, + new Object[]{1609545600000L, NullHandling.defaultLongValue(), 8L} + ), + false, + true + ); + } + + @Test + public void testGroupBySomeFieldOnLongColumnFilter() + { + GroupByQuery groupQuery = GroupByQuery.builder() + .setDataSource("test_datasource") + .setGranularity(Granularities.ALL) + .setInterval(Intervals.ETERNITY) + .setDimensions( + DefaultDimensionSpec.of("v0", ColumnType.LONG) + ) + .setVirtualColumns( + new NestedFieldVirtualColumn("__time", "$", "v0") + ) + .setAggregatorSpecs(new CountAggregatorFactory("count")) + .setDimFilter(new SelectorDimFilter("v0", "1609459200000", null)) + .setContext(getContext()) + .build(); + + + runResults( + groupQuery, + ImmutableList.of( + new Object[]{1609459200000L, 8L} + ), + false, + true + ); + } + + @Test + public void testGroupBySomeFieldOnLongColumnFilterNil() + { + GroupByQuery groupQuery = GroupByQuery.builder() + .setDataSource("test_datasource") + .setGranularity(Granularities.ALL) + .setInterval(Intervals.ETERNITY) + .setDimensions( + DefaultDimensionSpec.of("v0", ColumnType.LONG) + ) + .setVirtualColumns( + new NestedFieldVirtualColumn("__time", "$.x", "v0") + ) + .setAggregatorSpecs(new CountAggregatorFactory("count")) + .setDimFilter(new SelectorDimFilter("v0", "1609459200000", null)) + .setContext(getContext()) + .build(); + + + runResults( + groupQuery, + ImmutableList.of(), + false, + true + ); + } + private void runResults(GroupByQuery groupQuery, List expectedResults) { runResults(groupQuery, expectedResults, false, false); From b35df6d23cc439705458f0c9f65b5d9a9a4ba733 Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Wed, 8 Feb 2023 19:26:25 -0800 Subject: [PATCH 2/7] null, not no indexes if parts is a non-empty path --- .../apache/druid/segment/virtual/NestedFieldVirtualColumn.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java index 8b1d38940c4c..a06efc685583 100644 --- a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java @@ -61,7 +61,6 @@ import org.apache.druid.segment.nested.NestedPathFinder; import org.apache.druid.segment.nested.NestedPathPart; import org.apache.druid.segment.nested.StructuredData; -import org.apache.druid.segment.serde.NoIndexesColumnIndexSupplier; import org.apache.druid.segment.vector.BaseDoubleVectorValueSelector; import org.apache.druid.segment.vector.BaseLongVectorValueSelector; import org.apache.druid.segment.vector.NilVectorSelector; @@ -613,7 +612,7 @@ public ColumnIndexSupplier getIndexSupplier( if (parts.isEmpty()) { return holder.getIndexSupplier(); } - return NoIndexesColumnIndexSupplier.getInstance(); + return null; } @Override From 99126abe3dc386596eb191f0023dc9dc5953360e Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Wed, 8 Feb 2023 19:51:26 -0800 Subject: [PATCH 3/7] clearer --- .../virtual/NestedFieldVirtualColumn.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java index a06efc685583..95f019cbe8b6 100644 --- a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java @@ -411,13 +411,16 @@ public VectorObjectSelector makeVectorObjectSelector( // not a nested column, but we can still do stuff if the path is the 'root', indicated by an empty path parts if (parts.isEmpty()) { ColumnCapabilities capabilities = holder.getCapabilities(); + // expectedType shouldn't possibly be null if we are being asked for an object selector and the underlying column + // is numeric, else we would have been asked for a value selector + Preconditions.checkArgument(expectedType != null, "Asked for a VectorObjectSelector on a numeric column, 'expectedType' must not be null"); if (capabilities.isNumeric()) { return ExpressionVectorSelectors.castValueSelectorToObject( offset, this.columnName, theColumn.makeVectorValueSelector(offset), capabilities.toColumnType(), - expectedType != null ? expectedType : capabilities.toColumnType() // cast to itself in case the underlying column doesn't support object selector... + expectedType ); } return theColumn.makeVectorObjectSelector(offset); @@ -647,7 +650,10 @@ public ColumnCapabilities capabilities(ColumnInspector inspector, String columnN final ColumnCapabilities capabilities = inspector.getColumnCapabilities(this.columnName); if (capabilities != null) { - if (!capabilities.isPrimitive() && capabilities.isDictionaryEncoded().isTrue()) { + // if the underlying column is a nested column (and persisted to disk, re: the dictionary encoded check) + if (capabilities.is(ValueType.COMPLEX) && + capabilities.getComplexTypeName().equals(NestedDataComplexTypeSerde.TYPE_NAME) && + capabilities.isDictionaryEncoded().isTrue()) { return ColumnCapabilitiesImpl.createDefault() .setType(expectedType != null ? expectedType : ColumnType.STRING) .setDictionaryEncoded(true) @@ -657,7 +663,12 @@ public ColumnCapabilities capabilities(ColumnInspector inspector, String columnN .setHasNulls(expectedType == null || (expectedType.isNumeric() && NullHandling.sqlCompatible())); } - return capabilities; + // column is not nested, use underlying column capabilities, adjusted for expectedType as necessary + ColumnCapabilitiesImpl copy = ColumnCapabilitiesImpl.copyOf(capabilities); + if (expectedType != null) { + copy.setType(expectedType); + } + return copy; } return capabilities(columnName); From 40e50e12449922c4efbdee0fa89dfaf911e2eb05 Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Wed, 8 Feb 2023 19:55:17 -0800 Subject: [PATCH 4/7] more test more better --- .../groupby/NestedDataGroupByQueryTest.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java b/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java index cae7a3bc02da..079307eadf71 100644 --- a/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java +++ b/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java @@ -367,6 +367,35 @@ public void testGroupBySomeFieldOnStringColumnWithFilter() ); } + @Test + public void testGroupBySomeFieldOnStringColumnWithFilterExpectedType() + { + List vals = new ArrayList<>(); + vals.add("100"); + vals.add("200"); + vals.add("300"); + GroupByQuery groupQuery = GroupByQuery.builder() + .setDataSource("test_datasource") + .setGranularity(Granularities.ALL) + .setInterval(Intervals.ETERNITY) + .setDimensions(DefaultDimensionSpec.of("v0", ColumnType.LONG)) + .setVirtualColumns(new NestedFieldVirtualColumn("dim", "$", "v0", ColumnType.LONG)) + .setAggregatorSpecs(new CountAggregatorFactory("count")) + .setContext(getContext()) + .setDimFilter(new InDimFilter("v0", vals, null)) + .build(); + + + runResults( + groupQuery, + ImmutableList.of( + new Object[]{100L, 2L} + ), + false, + true + ); + } + @Test public void testGroupBySomeFieldOnStringColumnWithFilterNil() { @@ -452,6 +481,35 @@ public void testGroupBySomeFieldOnLongColumnFilter() ); } + @Test + public void testGroupBySomeFieldOnLongColumnFilterExpectedType() + { + GroupByQuery groupQuery = GroupByQuery.builder() + .setDataSource("test_datasource") + .setGranularity(Granularities.ALL) + .setInterval(Intervals.ETERNITY) + .setDimensions( + DefaultDimensionSpec.of("v0", ColumnType.STRING) + ) + .setVirtualColumns( + new NestedFieldVirtualColumn("__time", "$", "v0", ColumnType.STRING) + ) + .setAggregatorSpecs(new CountAggregatorFactory("count")) + .setDimFilter(new SelectorDimFilter("v0", "1609459200000", null)) + .setContext(getContext()) + .build(); + + + runResults( + groupQuery, + ImmutableList.of( + new Object[]{"1609459200000", 8L} + ), + true, + false + ); + } + @Test public void testGroupBySomeFieldOnLongColumnFilterNil() { From 626da2f7e678fa25b43dd6740fe5034bc7077a3a Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Wed, 8 Feb 2023 21:00:34 -0800 Subject: [PATCH 5/7] more fix --- .../segment/virtual/NestedFieldVirtualColumn.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java index 95f019cbe8b6..d139d627fc99 100644 --- a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java @@ -664,11 +664,16 @@ public ColumnCapabilities capabilities(ColumnInspector inspector, String columnN && NullHandling.sqlCompatible())); } // column is not nested, use underlying column capabilities, adjusted for expectedType as necessary - ColumnCapabilitiesImpl copy = ColumnCapabilitiesImpl.copyOf(capabilities); - if (expectedType != null) { - copy.setType(expectedType); + if (parts.isEmpty()) { + ColumnCapabilitiesImpl copy = ColumnCapabilitiesImpl.copyOf(capabilities); + if (expectedType != null) { + copy.setType(expectedType); + } + return copy; + } else if (capabilities.isPrimitive()) { + // path doesn't exist and column isn't nested, so effectively column doesn't exist + return null; } - return copy; } return capabilities(columnName); From 00170680ef294e79e585ae6a2201689916d965b9 Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Wed, 8 Feb 2023 22:42:33 -0800 Subject: [PATCH 6/7] oops, coercion can make nulls too --- .../apache/druid/segment/virtual/NestedFieldVirtualColumn.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java index d139d627fc99..6c4eebb77daa 100644 --- a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java @@ -668,6 +668,9 @@ public ColumnCapabilities capabilities(ColumnInspector inspector, String columnN ColumnCapabilitiesImpl copy = ColumnCapabilitiesImpl.copyOf(capabilities); if (expectedType != null) { copy.setType(expectedType); + copy.setHasNulls( + copy.hasNulls().or(ColumnCapabilities.Capable.of(expectedType.getType() != capabilities.getType())) + ); } return copy; } else if (capabilities.isPrimitive()) { From 8a029d29426076532566243e22c15e6a41a14b80 Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Wed, 8 Feb 2023 23:56:00 -0800 Subject: [PATCH 7/7] style --- .../main/java/org/apache/druid/segment/VirtualColumn.java | 5 +++-- .../druid/segment/virtual/ExpressionVirtualColumn.java | 1 + .../apache/druid/segment/virtual/FallbackVirtualColumn.java | 1 + .../druid/segment/virtual/ListFilteredVirtualColumn.java | 1 + .../druid/segment/virtual/NestedFieldVirtualColumn.java | 1 + 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/processing/src/main/java/org/apache/druid/segment/VirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/VirtualColumn.java index b32f54186def..e79baa00b1bf 100644 --- a/processing/src/main/java/org/apache/druid/segment/VirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/VirtualColumn.java @@ -257,10 +257,10 @@ default VectorObjectSelector makeVectorObjectSelector( /** * Return the {@link ColumnCapabilities} which best describe the optimal selector to read from this virtual column. - * + *

* The {@link ColumnInspector} (most likely corresponding to an underlying {@link ColumnSelectorFactory} of a query) * allows the virtual column to consider this information if necessary to compute its output type details. - * + *

* Examples of this include the {@link ExpressionVirtualColumn}, which takes input from other columns and uses the * {@link ColumnInspector} to infer the output type of expressions based on the types of the inputs. * @@ -268,6 +268,7 @@ default VectorObjectSelector makeVectorObjectSelector( * @param columnName the name this virtual column was referenced with * @return capabilities, must not be null */ + @Nullable default ColumnCapabilities capabilities(ColumnInspector inspector, String columnName) { return capabilities(columnName); diff --git a/processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVirtualColumn.java index b9a9366b8367..286626baf80a 100644 --- a/processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVirtualColumn.java @@ -194,6 +194,7 @@ public ColumnCapabilities capabilities(String columnName) return new ColumnCapabilitiesImpl().setType(outputType == null ? ColumnType.FLOAT : outputType); } + @Nullable @Override public ColumnCapabilities capabilities(ColumnInspector inspector, String columnName) { diff --git a/processing/src/main/java/org/apache/druid/segment/virtual/FallbackVirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/virtual/FallbackVirtualColumn.java index 3a9209fb33be..461a6b68dff7 100644 --- a/processing/src/main/java/org/apache/druid/segment/virtual/FallbackVirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/virtual/FallbackVirtualColumn.java @@ -163,6 +163,7 @@ public ColumnCapabilities capabilities(String columnName) return ColumnCapabilitiesImpl.createDefault(); } + @Nullable @SuppressWarnings("ConstantConditions") @Override public ColumnCapabilities capabilities(ColumnInspector inspector, String columnName) diff --git a/processing/src/main/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumn.java index f5f7e94d3746..3cdaf24508ff 100644 --- a/processing/src/main/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumn.java @@ -158,6 +158,7 @@ public ColumnCapabilities capabilities(String columnName) .setHasBitmapIndexes(true); } + @Nullable @Override public ColumnCapabilities capabilities(ColumnInspector inspector, String columnName) { diff --git a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java index 6c4eebb77daa..62cd303bc933 100644 --- a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java +++ b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java @@ -635,6 +635,7 @@ public ColumnCapabilities capabilities(String columnName) .setHasNulls(expectedType == null || !expectedType.isNumeric() || (expectedType.isNumeric() && NullHandling.sqlCompatible())); } + @Nullable @Override public ColumnCapabilities capabilities(ColumnInspector inspector, String columnName) {