This is an automated email from the ASF dual-hosted git repository.
adarshsanjeev 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 3ad90699d0c SQL: Stricter validation for GREATEST/LEAST. (#18562)
3ad90699d0c is described below
commit 3ad90699d0ca2351df272ae2c63263d8913e708a
Author: Gian Merlino <[email protected]>
AuthorDate: Mon Sep 22 23:22:36 2025 -0700
SQL: Stricter validation for GREATEST/LEAST. (#18562)
At the execution layer, the greatest and least functions only accept
numbers and strings. They throw errors when encountering other types.
To line up with this, the SQL bindings should verify that the SQL
type is a type that is represented by a string or number.
---
.../qaArray/ops_funcs_scalar_funcs.38.all.iq | 88 ++++++++---------
.../builtin/GreatestOperatorConversion.java | 3 +-
.../builtin/LeastOperatorConversion.java | 3 +-
.../builtin/ReductionOperatorConversionHelper.java | 86 ++++++++++++++---
.../apache/druid/sql/calcite/CalciteQueryTest.java | 104 +++++++++++++++++++++
5 files changed, 222 insertions(+), 62 deletions(-)
diff --git
a/quidem-ut/src/test/quidem/org.apache.druid.quidem.QTest/qaArray/ops_funcs_scalar_funcs.38.all.iq
b/quidem-ut/src/test/quidem/org.apache.druid.quidem.QTest/qaArray/ops_funcs_scalar_funcs.38.all.iq
index fa8df716435..dff176b90eb 100644
---
a/quidem-ut/src/test/quidem/org.apache.druid.quidem.QTest/qaArray/ops_funcs_scalar_funcs.38.all.iq
+++
b/quidem-ut/src/test/quidem/org.apache.druid.quidem.QTest/qaArray/ops_funcs_scalar_funcs.38.all.iq
@@ -22,7 +22,7 @@ Cannot apply 'TIMESTAMPDIFF' to arguments of type
'TIMESTAMPDIFF(
#-------------------------------------------------------------------------
SELECT greatest(a_bool, a_bool) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -30,7 +30,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[0]' RETURNING boolean array),
json_value(a_nested, '$[0]' RETURNING boolean array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -38,7 +38,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[7][0]' RETURNING boolean array),
json_value(a_nested, '$[7][0]' RETURNING boolean array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -46,7 +46,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(a_int, a_int) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -54,7 +54,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[1]' RETURNING bigint array),
json_value(a_nested, '$[1]' RETURNING bigint array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -62,7 +62,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[7][1]' RETURNING bigint array),
json_value(a_nested, '$[7][1]' RETURNING bigint array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -70,7 +70,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(a_float, a_float) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -78,7 +78,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[2]' RETURNING decimal array),
json_value(a_nested, '$[2]' RETURNING decimal array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -86,7 +86,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[7][2]' RETURNING decimal array),
json_value(a_nested, '$[7][2]' RETURNING decimal array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -94,7 +94,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(a_str, a_str) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -102,7 +102,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[3]' RETURNING varchar array),
json_value(a_nested, '$[3]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -110,7 +110,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[7][3]' RETURNING varchar array),
json_value(a_nested, '$[7][3]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -118,7 +118,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(a_null, a_null) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -126,7 +126,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[4]' RETURNING varchar array),
json_value(a_nested, '$[4]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -134,7 +134,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[7][4]' RETURNING varchar array),
json_value(a_nested, '$[7][4]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -142,7 +142,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(a_empty, a_empty) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -150,7 +150,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[5]' RETURNING varchar array),
json_value(a_nested, '$[5]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -158,7 +158,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[7][5]' RETURNING varchar array),
json_value(a_nested, '$[7][5]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -166,7 +166,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(a_mixed, a_mixed) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -174,7 +174,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[6]' RETURNING varchar array),
json_value(a_nested, '$[6]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -182,7 +182,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(json_value(a_nested, '$[7][6]' RETURNING varchar array),
json_value(a_nested, '$[7][6]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -190,7 +190,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT greatest(a_nested, a_nested) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'GREATEST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -198,7 +198,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(a_bool, a_bool) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -206,7 +206,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[0]' RETURNING boolean array),
json_value(a_nested, '$[0]' RETURNING boolean array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -214,7 +214,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[7][0]' RETURNING boolean array),
json_value(a_nested, '$[7][0]' RETURNING boolean array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -222,7 +222,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(a_int, a_int) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -230,7 +230,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[1]' RETURNING bigint array),
json_value(a_nested, '$[1]' RETURNING bigint array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -238,7 +238,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[7][1]' RETURNING bigint array),
json_value(a_nested, '$[7][1]' RETURNING bigint array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -246,7 +246,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(a_float, a_float) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -254,7 +254,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[2]' RETURNING decimal array),
json_value(a_nested, '$[2]' RETURNING decimal array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -262,7 +262,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[7][2]' RETURNING decimal array),
json_value(a_nested, '$[7][2]' RETURNING decimal array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -270,7 +270,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(a_str, a_str) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -278,7 +278,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[3]' RETURNING varchar array),
json_value(a_nested, '$[3]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -286,7 +286,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[7][3]' RETURNING varchar array),
json_value(a_nested, '$[7][3]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -294,7 +294,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(a_null, a_null) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -302,7 +302,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[4]' RETURNING varchar array),
json_value(a_nested, '$[4]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -310,7 +310,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[7][4]' RETURNING varchar array),
json_value(a_nested, '$[7][4]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -318,7 +318,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(a_empty, a_empty) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -326,7 +326,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[5]' RETURNING varchar array),
json_value(a_nested, '$[5]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -334,7 +334,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[7][5]' RETURNING varchar array),
json_value(a_nested, '$[7][5]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -342,7 +342,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(a_mixed, a_mixed) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -350,7 +350,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[6]' RETURNING varchar array),
json_value(a_nested, '$[6]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -358,7 +358,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(json_value(a_nested, '$[7][6]' RETURNING varchar array),
json_value(a_nested, '$[7][6]' RETURNING varchar array)) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
@@ -366,7 +366,7 @@ AvaticaSqlException
#-------------------------------------------------------------------------
SELECT least(a_nested, a_nested) AS col
FROM test_array;
-AvaticaSqlException
+Cannot apply 'LEAST' to arguments of type
!error
#-------------------------------------------------------------------------
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/GreatestOperatorConversion.java
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/GreatestOperatorConversion.java
index a3038e2550a..8177951851a 100644
---
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/GreatestOperatorConversion.java
+++
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/GreatestOperatorConversion.java
@@ -20,7 +20,6 @@
package org.apache.druid.sql.calcite.expression.builtin;
import org.apache.calcite.sql.SqlFunction;
-import org.apache.calcite.sql.type.OperandTypes;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.math.expr.Function;
import org.apache.druid.sql.calcite.expression.DirectOperatorConversion;
@@ -30,7 +29,7 @@ public class GreatestOperatorConversion extends
DirectOperatorConversion
{
private static final SqlFunction SQL_FUNCTION = OperatorConversions
.operatorBuilder(StringUtils.toUpperCase(Function.GreatestFunc.NAME))
- .operandTypeChecker(OperandTypes.VARIADIC)
+
.operandTypeChecker(ReductionOperatorConversionHelper.OPERAND_TYPE_CHECKER)
.returnTypeInference(ReductionOperatorConversionHelper.TYPE_INFERENCE)
.build();
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LeastOperatorConversion.java
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LeastOperatorConversion.java
index 9745dfb3c1d..52d1348605b 100644
---
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LeastOperatorConversion.java
+++
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LeastOperatorConversion.java
@@ -20,7 +20,6 @@
package org.apache.druid.sql.calcite.expression.builtin;
import org.apache.calcite.sql.SqlFunction;
-import org.apache.calcite.sql.type.OperandTypes;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.math.expr.Function;
import org.apache.druid.sql.calcite.expression.DirectOperatorConversion;
@@ -30,7 +29,7 @@ public class LeastOperatorConversion extends
DirectOperatorConversion
{
private static final SqlFunction SQL_FUNCTION = OperatorConversions
.operatorBuilder(StringUtils.toUpperCase(Function.LeastFunc.NAME))
- .operandTypeChecker(OperandTypes.VARIADIC)
+
.operandTypeChecker(ReductionOperatorConversionHelper.OPERAND_TYPE_CHECKER)
.returnTypeInference(ReductionOperatorConversionHelper.TYPE_INFERENCE)
.build();
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 8cd1a781993..5a472cd5042 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
@@ -21,12 +21,21 @@ package org.apache.druid.sql.calcite.expression.builtin;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.sql.SqlCallBinding;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlOperandCountRange;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.type.SqlOperandCountRanges;
+import org.apache.calcite.sql.type.SqlOperandTypeChecker;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
+import org.apache.calcite.sql.type.SqlTypeFamily;
import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.druid.java.util.common.IAE;
+import org.apache.druid.error.DruidException;
import org.apache.druid.math.expr.ExpressionTypeConversion;
+import org.apache.druid.math.expr.Function;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.ValueType;
+import org.apache.druid.sql.calcite.expression.OperatorConversions;
import org.apache.druid.sql.calcite.planner.Calcites;
class ReductionOperatorConversionHelper
@@ -39,7 +48,7 @@ class ReductionOperatorConversionHelper
* Implements type precedence rules similar to:
*
https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_least
*
- * @see org.apache.druid.math.expr.Function.ReduceFunction#apply
+ * @see Function.ReduceFunction#apply
* @see ExpressionTypeConversion#function
*/
static final SqlReturnTypeInference TYPE_INFERENCE =
@@ -53,7 +62,6 @@ class ReductionOperatorConversionHelper
SqlTypeName returnSqlTypeName = SqlTypeName.NULL;
boolean hasDouble = false;
- boolean isString = false;
for (int i = 0; i < n; i++) {
final RelDataType type = opBinding.getOperandType(i);
final SqlTypeName sqlTypeName = type.getSqlTypeName();
@@ -62,28 +70,78 @@ class ReductionOperatorConversionHelper
if (SqlTypeName.INTERVAL_TYPES.contains(type.getSqlTypeName())) {
// handle intervals as a LONG type even though it is a string
valueType = ColumnType.LONG;
+ } else if (SqlTypeName.NULL == type.getSqlTypeName()) {
+ valueType = null;
} else {
valueType = Calcites.getColumnTypeForRelDataType(type);
}
// Return types are listed in order of preference:
- if (valueType != null) {
- if (valueType.is(ValueType.STRING)) {
- returnSqlTypeName = sqlTypeName;
- isString = true;
- break;
- } else if (valueType.anyOf(ValueType.DOUBLE, ValueType.FLOAT)) {
- returnSqlTypeName = SqlTypeName.DOUBLE;
- hasDouble = true;
- } else if (valueType.is(ValueType.LONG) && !hasDouble) {
+ if (valueType == null) {
+ continue;
+ } else if (valueType.is(ValueType.STRING)) {
+ returnSqlTypeName = sqlTypeName;
+ break;
+ } else if (valueType.anyOf(ValueType.DOUBLE, ValueType.FLOAT)) {
+ returnSqlTypeName = SqlTypeName.DOUBLE;
+ hasDouble = true;
+ } else if (valueType.is(ValueType.LONG)) {
+ if (!hasDouble) {
returnSqlTypeName = SqlTypeName.BIGINT;
}
- } else if (sqlTypeName != SqlTypeName.NULL) {
- throw new IAE("Argument %d has invalid type: %s", i, sqlTypeName);
+ } else {
+ // The operand checker of the function should prevent other types
from reaching us.
+ // Throw a defensive exception if we encounter one.
+ throw DruidException.defensive("Got type[%s], which should have
been a validation error.", type);
}
}
return
typeFactory.createTypeWithNullability(typeFactory.createSqlType(returnSqlTypeName),
true);
};
+
+ /**
+ * Type checker that matches the implementation of {@link
Function.ReduceFunction}: only accept SQL types that
+ * are represented by string or number at the execution layer.
+ */
+ static final SqlOperandTypeChecker OPERAND_TYPE_CHECKER = new
SqlOperandTypeChecker()
+ {
+ @Override
+ public boolean checkOperandTypes(
+ final SqlCallBinding callBinding,
+ final boolean throwOnFailure
+ )
+ {
+ for (SqlNode operand : callBinding.operands()) {
+ final RelDataType type =
callBinding.getValidator().deriveType(callBinding.getScope(), operand);
+ final boolean validType =
+ SqlTypeFamily.STRING.contains(type)
+ || SqlTypeFamily.NUMERIC.contains(type)
+ || SqlTypeFamily.TIMESTAMP.contains(type)
+ || SqlTypeFamily.NULL.contains(type);
+
+ if (!validType) {
+ return OperatorConversions.throwOrReturn(
+ throwOnFailure,
+ callBinding,
+ SqlCallBinding::newValidationSignatureError
+ );
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public SqlOperandCountRange getOperandCountRange()
+ {
+ return SqlOperandCountRanges.any();
+ }
+
+ @Override
+ public String getAllowedSignatures(SqlOperator op, String opName)
+ {
+ return opName + "(<STRING | NUMERIC | DATETIME | BOOLEAN | NULL>, ...)";
+ }
+ };
}
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 593d8535663..edd78ae2007 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
@@ -14740,6 +14740,110 @@ public class CalciteQueryTest extends
BaseCalciteQueryTest
);
}
+ @Test
+ public void testGreatestLeastTypes()
+ {
+ cannotVectorizeUnlessFallback();
+ String query = "SELECT\n"
+ + "__time,\n"
+ + "l1,\n"
+ + "m1,\n"
+ + "l2,\n"
+ + "GREATEST(l1, l2),\n"
+ + "GREATEST(l1, dim1),\n"
+ + "GREATEST(dim1, l1),\n"
+ + "GREATEST(l1, m1),\n"
+ + "GREATEST(m1, l1),\n"
+ + "GREATEST(l1, CAST(l2 AS VARCHAR)),\n"
+ + "GREATEST(__time, __time + INTERVAL '1' HOUR),\n"
+ + "GREATEST(l1, NULL),\n"
+ + "GREATEST(NULL, NULL)\n"
+ + "FROM druid.numfoo";
+
+ ScanQuery expectedQuery =
+ Druids.newScanQueryBuilder()
+ .dataSource(CalciteTests.DATASOURCE3)
+ .intervals(querySegmentSpec(Filtration.eternity()))
+ .columns("__time", "l1", "m1", "l2", "v0", "v1", "v2", "v3",
"v4", "v5", "v6", "v7", "v8")
+ .columnTypes(
+ ColumnType.LONG,
+ ColumnType.LONG,
+ ColumnType.FLOAT,
+ ColumnType.LONG,
+ ColumnType.LONG,
+ ColumnType.STRING,
+ ColumnType.STRING,
+ ColumnType.DOUBLE,
+ ColumnType.DOUBLE,
+ ColumnType.STRING,
+ ColumnType.LONG,
+ ColumnType.LONG,
+ ColumnType.STRING
+ )
+ .virtualColumns(
+ expressionVirtualColumn(
+ "v0",
+ "greatest(\"l1\",\"l2\")",
+ ColumnType.LONG
+ ),
+ expressionVirtualColumn(
+ "v1",
+ "greatest(\"l1\",\"dim1\")",
+ ColumnType.STRING
+ ),
+ expressionVirtualColumn(
+ "v2",
+ "greatest(\"dim1\",\"l1\")",
+ ColumnType.STRING
+ ),
+ expressionVirtualColumn(
+ "v3",
+ "greatest(\"l1\",\"m1\")",
+ ColumnType.DOUBLE
+ ),
+ expressionVirtualColumn(
+ "v4",
+ "greatest(\"m1\",\"l1\")",
+ ColumnType.DOUBLE
+ ),
+ expressionVirtualColumn(
+ "v5",
+ "greatest(\"l1\",CAST(\"l2\", 'STRING'))",
+ ColumnType.STRING
+ ),
+ expressionVirtualColumn(
+ "v6",
+ "greatest(\"__time\",(\"__time\" + 3600000))",
+ ColumnType.LONG
+ ),
+ expressionVirtualColumn(
+ "v7",
+ "greatest(\"l1\",null)",
+ ColumnType.LONG
+ ),
+ expressionVirtualColumn(
+ "v8",
+ "null",
+ ColumnType.STRING
+ )
+ )
+ .resultFormat(ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
+ .build();
+
+ testQuery(
+ query,
+ List.of(expectedQuery),
+ List.of(
+ new Object[]{946684800000L, 7L, 1.0F, null, 7L, "7", "7", 7.0D,
7.0D, "7", 946688400000L, 7L, null},
+ new Object[]{946771200000L, 325323L, 2.0F, 325323L, 325323L,
"325323", "325323", 325323.0D, 325323.0D, "325323", 946774800000L, 325323L,
null},
+ new Object[]{946857600000L, 0L, 3.0F, 0L, 0L, "2", "2", 3.0D,
3.0D, "0", 946861200000L, 0L, null},
+ new Object[]{978307200000L, null, 4.0F, null, null, "1", "1",
4.0D, 4.0D, null, 978310800000L, null, null},
+ new Object[]{978393600000L, null, 5.0F, null, null, "def", "def",
5.0D, 5.0D, null, 978397200000L, null, null},
+ new Object[]{978480000000L, null, 6.0F, null, null, "abc", "abc",
6.0D, 6.0D, null, 978483600000L, null, null}
+ )
+ );
+ }
+
@Test
public void testSubqueryTypeMismatchWithLiterals()
{
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]