This is an automated email from the ASF dual-hosted git repository.

abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 3bf1e699ff GREATEST/LEAST function is incorrectly specifying that it 
cannot return null (#12804)
3bf1e699ff is described below

commit 3bf1e699ff09ef13807cc05f00eec032912a1206
Author: Maytas Monsereenusorn <[email protected]>
AuthorDate: Wed Jul 20 02:11:24 2022 -0700

    GREATEST/LEAST function is incorrectly specifying that it cannot return 
null (#12804)
---
 .../builtin/ReductionOperatorConversionHelper.java |  12 ++-
 .../apache/druid/sql/calcite/CalciteQueryTest.java | 110 +++++++++++++++++++++
 2 files changed, 120 insertions(+), 2 deletions(-)

diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ReductionOperatorConversionHelper.java
 
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ReductionOperatorConversionHelper.java
index 4a457b7ad7..a747e9d27d 100644
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ReductionOperatorConversionHelper.java
+++ 
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ReductionOperatorConversionHelper.java
@@ -23,6 +23,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.type.SqlReturnTypeInference;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.druid.common.config.NullHandling;
 import org.apache.druid.java.util.common.IAE;
 import org.apache.druid.math.expr.ExpressionTypeConversion;
 import org.apache.druid.segment.column.ColumnType;
@@ -53,7 +54,7 @@ class ReductionOperatorConversionHelper
 
         SqlTypeName returnSqlTypeName = SqlTypeName.NULL;
         boolean hasDouble = false;
-
+        boolean isString = false;
         for (int i = 0; i < n; i++) {
           RelDataType type = opBinding.getOperandType(i);
           SqlTypeName sqlTypeName = type.getSqlTypeName();
@@ -63,6 +64,7 @@ class ReductionOperatorConversionHelper
           if (valueType != null) {
             if (valueType.is(ValueType.STRING)) {
               returnSqlTypeName = sqlTypeName;
+              isString = true;
               break;
             } else if (valueType.anyOf(ValueType.DOUBLE, ValueType.FLOAT)) {
               returnSqlTypeName = SqlTypeName.DOUBLE;
@@ -75,6 +77,12 @@ class ReductionOperatorConversionHelper
           }
         }
 
-        return typeFactory.createSqlType(returnSqlTypeName);
+        if (isString || NullHandling.sqlCompatible()) {
+          // String can be null in both modes
+          return 
typeFactory.createTypeWithNullability(typeFactory.createSqlType(returnSqlTypeName),
 true);
+        } else {
+          return typeFactory.createSqlType(returnSqlTypeName);
+        }
       };
 }
+
diff --git 
a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java 
b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java
index 77e6ca22d2..666967c410 100644
--- a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java
@@ -39,6 +39,7 @@ import org.apache.druid.query.Druids;
 import org.apache.druid.query.InlineDataSource;
 import org.apache.druid.query.JoinDataSource;
 import org.apache.druid.query.LookupDataSource;
+import org.apache.druid.query.Query;
 import org.apache.druid.query.QueryContext;
 import org.apache.druid.query.QueryContexts;
 import org.apache.druid.query.QueryDataSource;
@@ -13902,4 +13903,113 @@ public class CalciteQueryTest extends 
BaseCalciteQueryTest
         null
     );
   }
+
+  @Test
+  public void testGreatestFunctionForNumberWithIsNull() throws Exception
+  {
+    String query = "SELECT dim1, MAX(GREATEST(l1, l2)) IS NULL FROM 
druid.numfoo GROUP BY dim1";
+
+    List<Object[]> expectedResult;
+    List<Query> expectedQueries;
+
+    if (NullHandling.replaceWithDefault()) {
+      expectedResult = ImmutableList.of(
+          new Object[]{"", false},
+          new Object[]{"1", false},
+          new Object[]{"10.1", false},
+          new Object[]{"2", false},
+          new Object[]{"abc", false},
+          new Object[]{"def", false}
+      );
+      expectedQueries = ImmutableList.of(
+          GroupByQuery.builder()
+                      .setDataSource(CalciteTests.DATASOURCE3)
+                      .setInterval(querySegmentSpec(Intervals.ETERNITY))
+                      .setGranularity(Granularities.ALL)
+                      .addDimension(new DefaultDimensionSpec("dim1", "_d0"))
+                      .setPostAggregatorSpecs(ImmutableList.of(
+                          expressionPostAgg("p0", "0")
+                      ))
+                      .build()
+      );
+    } else {
+      cannotVectorize();
+      expectedResult = ImmutableList.of(
+          new Object[]{"", false},
+          new Object[]{"1", true},
+          new Object[]{"10.1", false},
+          new Object[]{"2", false},
+          new Object[]{"abc", true},
+          new Object[]{"def", true}
+      );
+      expectedQueries = ImmutableList.of(
+          GroupByQuery.builder()
+                      .setDataSource(CalciteTests.DATASOURCE3)
+                      .setInterval(querySegmentSpec(Intervals.ETERNITY))
+                      .setVirtualColumns(
+                          expressionVirtualColumn(
+                              "v0",
+                              "greatest(\"l1\",\"l2\")",
+                              ColumnType.LONG
+                          )
+                      )
+                      .setGranularity(Granularities.ALL)
+                      .addDimension(new DefaultDimensionSpec("dim1", "_d0"))
+                      .addAggregator(new LongMaxAggregatorFactory("a0", "v0"))
+                      .setPostAggregatorSpecs(ImmutableList.of(
+                          expressionPostAgg("p0", "isnull(\"a0\")")
+                      ))
+                      .build()
+      );
+    }
+
+    testQuery(
+        query,
+        expectedQueries,
+        expectedResult
+    );
+  }
+
+  @Test
+  public void testGreatestFunctionForStringWithIsNull() throws Exception
+  {
+    cannotVectorize();
+
+    String query = "SELECT l1, LATEST(GREATEST(dim1, dim2)) IS NULL FROM 
druid.numfoo GROUP BY l1";
+
+    testQuery(
+        query,
+        ImmutableList.of(
+            GroupByQuery.builder()
+                        .setDataSource(CalciteTests.DATASOURCE3)
+                        .setInterval(querySegmentSpec(Intervals.ETERNITY))
+                        .setVirtualColumns(
+                            expressionVirtualColumn(
+                                "v0",
+                                "CAST(greatest(\"dim1\",\"dim2\"), 'DOUBLE')",
+                                ColumnType.DOUBLE
+                            )
+                        )
+                        .setGranularity(Granularities.ALL)
+                        .addDimension(new DefaultDimensionSpec("l1", "_d0", 
ColumnType.LONG))
+                        .addAggregator(new DoubleLastAggregatorFactory("a0", 
"v0", null))
+                        .setPostAggregatorSpecs(ImmutableList.of(
+                            expressionPostAgg("p0", "isnull(\"a0\")")
+                        ))
+                        .build()
+        ),
+        NullHandling.replaceWithDefault() ?
+        ImmutableList.of(
+            new Object[]{0L, false},
+            new Object[]{7L, false},
+            new Object[]{325323L, false}
+        ) :
+        ImmutableList.of(
+            new Object[]{null, true},
+            new Object[]{0L, false},
+            new Object[]{7L, true},
+            new Object[]{325323L, false}
+        )
+    );
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to