diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayContainsOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayContainsOperatorConversion.java index d1e24b6429ef..8bfc3aecb3e7 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayContainsOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayContainsOperatorConversion.java @@ -34,6 +34,7 @@ import org.apache.druid.query.filter.ArrayContainsElementFilter; import org.apache.druid.query.filter.DimFilter; import org.apache.druid.query.filter.EqualityFilter; +import org.apache.druid.query.filter.NullFilter; import org.apache.druid.segment.column.ColumnType; import org.apache.druid.segment.column.RowSignature; import org.apache.druid.sql.calcite.expression.DruidExpression; @@ -129,14 +130,18 @@ public DimFilter toDruidFilter( leftExpr, leftExpr.getDruidType() ); - filters.add( - new EqualityFilter( - column, - ExpressionType.toColumnType(ExpressionType.elementType(exprEval.type())), - val, - null - ) - ); + if (val == null) { + filters.add(NullFilter.forColumn(column)); + } else { + filters.add( + new EqualityFilter( + column, + ExpressionType.toColumnType(ExpressionType.elementType(exprEval.type())), + val, + null + ) + ); + } } } diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayOverlapOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayOverlapOperatorConversion.java index f979ba073c53..23cfcfaa4a45 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayOverlapOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayOverlapOperatorConversion.java @@ -34,6 +34,7 @@ import org.apache.druid.query.filter.DimFilter; import org.apache.druid.query.filter.EqualityFilter; import org.apache.druid.query.filter.InDimFilter; +import org.apache.druid.query.filter.NullFilter; import org.apache.druid.query.filter.OrDimFilter; import org.apache.druid.segment.column.ColumnType; import org.apache.druid.segment.column.RowSignature; @@ -135,10 +136,14 @@ public DimFilter toDruidFilter( simpleExtractionExpr, simpleExtractionExpr.getDruidType() ); + final Object elementValue = arrayElements[0]; + if (elementValue == null) { + return NullFilter.forColumn(column); + } return new EqualityFilter( column, ExpressionType.toColumnType(exprEval.type()), - arrayElements[0], + elementValue, null ); } diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteMultiValueStringQueryTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteMultiValueStringQueryTest.java index e186476ef50e..ac6e6ba33a00 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteMultiValueStringQueryTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteMultiValueStringQueryTest.java @@ -37,6 +37,7 @@ import org.apache.druid.query.extraction.SubstringDimExtractionFn; import org.apache.druid.query.filter.InDimFilter; import org.apache.druid.query.filter.LikeDimFilter; +import org.apache.druid.query.filter.NullFilter; import org.apache.druid.query.groupby.GroupByQuery; import org.apache.druid.query.groupby.GroupByQueryConfig; import org.apache.druid.query.groupby.orderby.DefaultLimitSpec; @@ -285,6 +286,37 @@ public void testMultiValueStringOverlapFilter() ); } + @Test + public void testMultiValueStringOverlapFilterNull() + { + testQuery( + "SELECT dim3 FROM druid.numfoo WHERE MV_OVERLAP(dim3, ARRAY[NULL]) LIMIT 5", + ImmutableList.of( + newScanQueryBuilder() + .dataSource(CalciteTests.DATASOURCE3) + .eternityInterval() + .filters( + NullHandling.sqlCompatible() ? NullFilter.forColumn("dim3") : selector("dim3", null) + ) + .columns("dim3") + .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) + .limit(5) + .context(QUERY_CONTEXT_DEFAULT) + .build() + ), + NullHandling.sqlCompatible() + ? ImmutableList.of( + new Object[]{null}, + new Object[]{null} + ) + : ImmutableList.of( + new Object[]{""}, + new Object[]{""}, + new Object[]{""} + ) + ); + } + @Test public void testMultiValueStringOverlapFilterNonLiteral() { @@ -332,6 +364,37 @@ public void testMultiValueStringContainsFilter() ); } + @Test + public void testMultiValueStringContainsFilterNull() + { + testQuery( + "SELECT dim3 FROM druid.numfoo WHERE MV_CONTAINS(dim3, ARRAY[NULL]) LIMIT 5", + ImmutableList.of( + newScanQueryBuilder() + .dataSource(CalciteTests.DATASOURCE3) + .eternityInterval() + .filters( + NullHandling.sqlCompatible() ? NullFilter.forColumn("dim3") : selector("dim3", null) + ) + .columns("dim3") + .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) + .limit(5) + .context(QUERY_CONTEXT_DEFAULT) + .build() + ), + NullHandling.sqlCompatible() + ? ImmutableList.of( + new Object[]{null}, + new Object[]{null} + ) + : ImmutableList.of( + new Object[]{""}, + new Object[]{""}, + new Object[]{""} + ) + ); + } + @Test public void testMultiValueStringContainsArrayOfOneElement() {