From 3d19b748fb9fde49f074a8234e797a46bd894d48 Mon Sep 17 00:00:00 2001 From: Gian Merlino Date: Fri, 23 Jun 2023 16:25:04 -0700 Subject: [PATCH] SQL OperatorConversions: Introduce.aggregatorBuilder, allow CAST-as-literal. (#14249) * SQL OperatorConversions: Introduce.aggregatorBuilder, allow CAST-as-literal. Four main changes: 1) Provide aggregatorBuilder, a more consistent way of defining the SqlAggFunction we need for all of our SQL aggregators. The mechanism is analogous to the one we already use for SQL functions (OperatorConversions.operatorBuilder). 2) Allow CASTs of constants to be considered as "literalOperands". This fixes an issue where various of our operators are defined with OperandTypes.LITERAL as part of their checkers, which doesn't allow casts. However, in these cases we generally _do_ want to allow casts. The important piece is that the value must be reducible to a constant, not that the SQL text is literally a literal. 3) Update DataSketches SQL aggregators to use the new aggregatorBuilder functionality. The main user-visible effect here is [2]: the aggregators would now accept, for example, "CAST(0.99 AS DOUBLE)" as a literal argument. Other aggregators could be updated in a future patch. 4) Rename "requiredOperands" to "requiredOperandCount", because the old name was confusing. (It rhymes with "literalOperands" but the arguments mean different things.) * Adjust method calls. --- ...ketchApproxCountDistinctSqlAggregator.java | 42 +--- .../HllSketchEstimateOperatorConversion.java | 2 +- ...mateWithErrorBoundsOperatorConversion.java | 2 +- .../hll/sql/HllSketchObjectSqlAggregator.java | 41 +--- ...blesSketchApproxQuantileSqlAggregator.java | 44 +--- .../sql/DoublesSketchObjectSqlAggregator.java | 40 +--- ...ketchApproxCountDistinctSqlAggregator.java | 42 +--- .../sql/ThetaSketchObjectSqlAggregator.java | 40 +--- .../hll/sql/HllSketchSqlAggregatorTest.java | 10 +- .../sql/DoublesSketchSqlAggregatorTest.java | 2 +- .../query/sql/SleepOperatorConversion.java | 2 +- .../tools/SleepOperatorConversion.java | 2 +- .../expression/OperatorConversions.java | 226 +++++++++++++----- .../builtin/BTrimOperatorConversion.java | 2 +- .../builtin/ContainsOperatorConversion.java | 2 +- .../builtin/DateTruncOperatorConversion.java | 2 +- .../builtin/LPadOperatorConversion.java | 2 +- .../builtin/LTrimOperatorConversion.java | 2 +- .../builtin/ParseLongOperatorConversion.java | 2 +- .../builtin/RPadOperatorConversion.java | 2 +- .../builtin/RTrimOperatorConversion.java | 2 +- .../RegexpExtractOperatorConversion.java | 2 +- .../builtin/RegexpLikeOperatorConversion.java | 2 +- .../builtin/RoundOperatorConversion.java | 2 +- .../builtin/SubstringOperatorConversion.java | 2 +- .../builtin/TextcatOperatorConversion.java | 2 +- .../builtin/TimeCeilOperatorConversion.java | 2 +- .../TimeExtractOperatorConversion.java | 2 +- .../builtin/TimeFloorOperatorConversion.java | 2 +- .../builtin/TimeFormatOperatorConversion.java | 2 +- .../builtin/TimeParseOperatorConversion.java | 2 +- .../builtin/TimeShiftOperatorConversion.java | 2 +- .../builtin/TruncateOperatorConversion.java | 2 +- .../expression/OperatorConversionsTest.java | 66 +++-- .../planner/DruidOperatorTableTest.java | 2 +- .../calcite/planner/DruidRexExecutorTest.java | 2 +- .../calcite/schema/InformationSchemaTest.java | 6 +- 37 files changed, 324 insertions(+), 287 deletions(-) diff --git a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchApproxCountDistinctSqlAggregator.java b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchApproxCountDistinctSqlAggregator.java index 461b2316f10..29f7c819be1 100644 --- a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchApproxCountDistinctSqlAggregator.java +++ b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchApproxCountDistinctSqlAggregator.java @@ -21,24 +21,30 @@ package org.apache.druid.query.aggregation.datasketches.hll.sql; import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.SqlFunctionCategory; -import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.type.InferTypes; -import org.apache.calcite.sql.type.OperandTypes; -import org.apache.calcite.sql.type.ReturnTypes; import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.druid.query.aggregation.AggregatorFactory; import org.apache.druid.query.aggregation.post.FinalizingFieldAccessPostAggregator; import org.apache.druid.sql.calcite.aggregation.Aggregation; import org.apache.druid.sql.calcite.aggregation.SqlAggregator; +import org.apache.druid.sql.calcite.expression.OperatorConversions; import java.util.Collections; public class HllSketchApproxCountDistinctSqlAggregator extends HllSketchBaseSqlAggregator implements SqlAggregator { public static final String NAME = "APPROX_COUNT_DISTINCT_DS_HLL"; - - private static final SqlAggFunction FUNCTION_INSTANCE = new HllSketchApproxCountDistinctSqlAggFunction(); + private static final SqlAggFunction FUNCTION_INSTANCE = + OperatorConversions.aggregatorBuilder(NAME) + .operandNames("column", "lgK", "tgtHllType") + .operandTypes(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC, SqlTypeFamily.STRING) + .operandTypeInference(InferTypes.VARCHAR_1024) + .requiredOperandCount(1) + .literalOperands(1, 2) + .returnTypeNonNull(SqlTypeName.BIGINT) + .functionCategory(SqlFunctionCategory.NUMERIC) + .build(); public HllSketchApproxCountDistinctSqlAggregator() { @@ -66,30 +72,4 @@ public class HllSketchApproxCountDistinctSqlAggregator extends HllSketchBaseSqlA ) : null ); } - - private static class HllSketchApproxCountDistinctSqlAggFunction extends SqlAggFunction - { - private static final String SIGNATURE = "'" + NAME + "(column, lgK, tgtHllType)'"; - - HllSketchApproxCountDistinctSqlAggFunction() - { - super( - NAME, - null, - SqlKind.OTHER_FUNCTION, - ReturnTypes.explicit(SqlTypeName.BIGINT), - InferTypes.VARCHAR_1024, - OperandTypes.or( - OperandTypes.ANY, - OperandTypes.and( - OperandTypes.sequence(SIGNATURE, OperandTypes.ANY, OperandTypes.LITERAL, OperandTypes.LITERAL), - OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC, SqlTypeFamily.STRING) - ) - ), - SqlFunctionCategory.NUMERIC, - false, - false - ); - } - } } diff --git a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchEstimateOperatorConversion.java b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchEstimateOperatorConversion.java index fa154933531..dbc4bf8bcd3 100644 --- a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchEstimateOperatorConversion.java +++ b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchEstimateOperatorConversion.java @@ -47,7 +47,7 @@ public class HllSketchEstimateOperatorConversion implements SqlOperatorConversio private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder(StringUtils.toUpperCase(FUNCTION_NAME)) .operandTypes(SqlTypeFamily.ANY, SqlTypeFamily.BOOLEAN) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeInference(ReturnTypes.DOUBLE) .build(); diff --git a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchEstimateWithErrorBoundsOperatorConversion.java b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchEstimateWithErrorBoundsOperatorConversion.java index 83a0ce43bf5..cc89d4c7a56 100644 --- a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchEstimateWithErrorBoundsOperatorConversion.java +++ b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchEstimateWithErrorBoundsOperatorConversion.java @@ -46,7 +46,7 @@ public class HllSketchEstimateWithErrorBoundsOperatorConversion implements SqlOp private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder(StringUtils.toUpperCase(FUNCTION_NAME)) .operandTypes(SqlTypeFamily.ANY, SqlTypeFamily.INTEGER) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.OTHER) .build(); diff --git a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchObjectSqlAggregator.java b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchObjectSqlAggregator.java index 56fdbd33811..8e695148b97 100644 --- a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchObjectSqlAggregator.java +++ b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchObjectSqlAggregator.java @@ -21,22 +21,29 @@ package org.apache.druid.query.aggregation.datasketches.hll.sql; import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.SqlFunctionCategory; -import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.type.InferTypes; -import org.apache.calcite.sql.type.OperandTypes; -import org.apache.calcite.sql.type.ReturnTypes; import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.druid.query.aggregation.AggregatorFactory; import org.apache.druid.sql.calcite.aggregation.Aggregation; import org.apache.druid.sql.calcite.aggregation.SqlAggregator; +import org.apache.druid.sql.calcite.expression.OperatorConversions; import java.util.Collections; public class HllSketchObjectSqlAggregator extends HllSketchBaseSqlAggregator implements SqlAggregator { - private static final SqlAggFunction FUNCTION_INSTANCE = new HllSketchSqlAggFunction(); private static final String NAME = "DS_HLL"; + private static final SqlAggFunction FUNCTION_INSTANCE = + OperatorConversions.aggregatorBuilder(NAME) + .operandNames("column", "lgK", "tgtHllType") + .operandTypes(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC, SqlTypeFamily.STRING) + .operandTypeInference(InferTypes.VARCHAR_1024) + .requiredOperandCount(1) + .literalOperands(1, 2) + .returnTypeNonNull(SqlTypeName.OTHER) + .functionCategory(SqlFunctionCategory.USER_DEFINED_FUNCTION) + .build(); public HllSketchObjectSqlAggregator() { @@ -61,30 +68,4 @@ public class HllSketchObjectSqlAggregator extends HllSketchBaseSqlAggregator imp null ); } - - private static class HllSketchSqlAggFunction extends SqlAggFunction - { - private static final String SIGNATURE = "'" + NAME + "(column, lgK, tgtHllType)'"; - - HllSketchSqlAggFunction() - { - super( - NAME, - null, - SqlKind.OTHER_FUNCTION, - ReturnTypes.explicit(SqlTypeName.OTHER), - InferTypes.VARCHAR_1024, - OperandTypes.or( - OperandTypes.ANY, - OperandTypes.and( - OperandTypes.sequence(SIGNATURE, OperandTypes.ANY, OperandTypes.LITERAL, OperandTypes.LITERAL), - OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC, SqlTypeFamily.STRING) - ) - ), - SqlFunctionCategory.USER_DEFINED_FUNCTION, - false, - false - ); - } - } } diff --git a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchApproxQuantileSqlAggregator.java b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchApproxQuantileSqlAggregator.java index 0b4bbd7f11b..7864447c492 100644 --- a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchApproxQuantileSqlAggregator.java +++ b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchApproxQuantileSqlAggregator.java @@ -28,8 +28,6 @@ import org.apache.calcite.rex.RexNode; import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.SqlFunctionCategory; import org.apache.calcite.sql.SqlKind; -import org.apache.calcite.sql.type.OperandTypes; -import org.apache.calcite.sql.type.ReturnTypes; import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.druid.java.util.common.StringUtils; @@ -45,19 +43,27 @@ import org.apache.druid.sql.calcite.aggregation.Aggregations; import org.apache.druid.sql.calcite.aggregation.SqlAggregator; import org.apache.druid.sql.calcite.expression.DruidExpression; import org.apache.druid.sql.calcite.expression.Expressions; +import org.apache.druid.sql.calcite.expression.OperatorConversions; import org.apache.druid.sql.calcite.planner.PlannerContext; import org.apache.druid.sql.calcite.rel.VirtualColumnRegistry; import javax.annotation.Nullable; - import java.util.List; public class DoublesSketchApproxQuantileSqlAggregator implements SqlAggregator { public static final String CTX_APPROX_QUANTILE_DS_MAX_STREAM_LENGTH = "approxQuantileDsMaxStreamLength"; - private static final SqlAggFunction FUNCTION_INSTANCE = new DoublesSketchApproxQuantileSqlAggFunction(); private static final String NAME = "APPROX_QUANTILE_DS"; + private static final SqlAggFunction FUNCTION_INSTANCE = + OperatorConversions.aggregatorBuilder(NAME) + .operandNames("column", "probability", "k") + .operandTypes(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC, SqlTypeFamily.EXACT_NUMERIC) + .returnTypeNonNull(SqlTypeName.DOUBLE) + .requiredOperandCount(2) + .literalOperands(1, 2) + .functionCategory(SqlFunctionCategory.NUMERIC) + .build(); @Override public SqlAggFunction calciteFunction() @@ -212,34 +218,4 @@ public class DoublesSketchApproxQuantileSqlAggregator implements SqlAggregator DoublesSketchAggregatorFactory.DEFAULT_MAX_STREAM_LENGTH ); } - - private static class DoublesSketchApproxQuantileSqlAggFunction extends SqlAggFunction - { - private static final String SIGNATURE1 = "'" + NAME + "(column, probability)'"; - private static final String SIGNATURE2 = "'" + NAME + "(column, probability, k)'"; - - DoublesSketchApproxQuantileSqlAggFunction() - { - super( - NAME, - null, - SqlKind.OTHER_FUNCTION, - ReturnTypes.explicit(SqlTypeName.DOUBLE), - null, - OperandTypes.or( - OperandTypes.and( - OperandTypes.sequence(SIGNATURE1, OperandTypes.ANY, OperandTypes.LITERAL), - OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC) - ), - OperandTypes.and( - OperandTypes.sequence(SIGNATURE2, OperandTypes.ANY, OperandTypes.LITERAL, OperandTypes.LITERAL), - OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC, SqlTypeFamily.EXACT_NUMERIC) - ) - ), - SqlFunctionCategory.NUMERIC, - false, - false - ); - } - } } diff --git a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchObjectSqlAggregator.java b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchObjectSqlAggregator.java index b82f02fc451..049e1284a91 100644 --- a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchObjectSqlAggregator.java +++ b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchObjectSqlAggregator.java @@ -28,8 +28,6 @@ import org.apache.calcite.rex.RexNode; import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.SqlFunctionCategory; import org.apache.calcite.sql.SqlKind; -import org.apache.calcite.sql.type.OperandTypes; -import org.apache.calcite.sql.type.ReturnTypes; import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.druid.java.util.common.StringUtils; @@ -43,17 +41,25 @@ import org.apache.druid.sql.calcite.aggregation.Aggregations; import org.apache.druid.sql.calcite.aggregation.SqlAggregator; import org.apache.druid.sql.calcite.expression.DruidExpression; import org.apache.druid.sql.calcite.expression.Expressions; +import org.apache.druid.sql.calcite.expression.OperatorConversions; import org.apache.druid.sql.calcite.planner.PlannerContext; import org.apache.druid.sql.calcite.rel.VirtualColumnRegistry; import javax.annotation.Nullable; - import java.util.List; public class DoublesSketchObjectSqlAggregator implements SqlAggregator { - private static final SqlAggFunction FUNCTION_INSTANCE = new DoublesSketchSqlAggFunction(); private static final String NAME = "DS_QUANTILES_SKETCH"; + private static final SqlAggFunction FUNCTION_INSTANCE = + OperatorConversions.aggregatorBuilder(NAME) + .operandNames("column", "k") + .operandTypes(SqlTypeFamily.ANY, SqlTypeFamily.EXACT_NUMERIC) + .returnTypeNonNull(SqlTypeName.OTHER) + .requiredOperandCount(1) + .literalOperands(1) + .functionCategory(SqlFunctionCategory.NUMERIC) + .build(); @Override public SqlAggFunction calciteFunction() @@ -139,30 +145,4 @@ public class DoublesSketchObjectSqlAggregator implements SqlAggregator null ); } - - private static class DoublesSketchSqlAggFunction extends SqlAggFunction - { - private static final String SIGNATURE2 = "'" + NAME + "(column, k)'"; - - DoublesSketchSqlAggFunction() - { - super( - NAME, - null, - SqlKind.OTHER_FUNCTION, - ReturnTypes.explicit(SqlTypeName.OTHER), - null, - OperandTypes.or( - OperandTypes.ANY, - OperandTypes.and( - OperandTypes.sequence(SIGNATURE2, OperandTypes.ANY, OperandTypes.LITERAL), - OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.EXACT_NUMERIC) - ) - ), - SqlFunctionCategory.USER_DEFINED_FUNCTION, - false, - false - ); - } - } } diff --git a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/theta/sql/ThetaSketchApproxCountDistinctSqlAggregator.java b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/theta/sql/ThetaSketchApproxCountDistinctSqlAggregator.java index 70eb943a8c7..eac77901f1d 100644 --- a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/theta/sql/ThetaSketchApproxCountDistinctSqlAggregator.java +++ b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/theta/sql/ThetaSketchApproxCountDistinctSqlAggregator.java @@ -21,24 +21,30 @@ package org.apache.druid.query.aggregation.datasketches.theta.sql; import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.SqlFunctionCategory; -import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.type.InferTypes; -import org.apache.calcite.sql.type.OperandTypes; -import org.apache.calcite.sql.type.ReturnTypes; import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.druid.query.aggregation.AggregatorFactory; import org.apache.druid.query.aggregation.post.FinalizingFieldAccessPostAggregator; import org.apache.druid.sql.calcite.aggregation.Aggregation; import org.apache.druid.sql.calcite.aggregation.SqlAggregator; +import org.apache.druid.sql.calcite.expression.OperatorConversions; import java.util.Collections; public class ThetaSketchApproxCountDistinctSqlAggregator extends ThetaSketchBaseSqlAggregator implements SqlAggregator { public static final String NAME = "APPROX_COUNT_DISTINCT_DS_THETA"; - - private static final SqlAggFunction FUNCTION_INSTANCE = new ThetaSketchSqlAggFunction(); + private static final SqlAggFunction FUNCTION_INSTANCE = + OperatorConversions.aggregatorBuilder(NAME) + .operandNames("column", "size") + .operandTypes(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC) + .operandTypeInference(InferTypes.VARCHAR_1024) + .requiredOperandCount(1) + .literalOperands(1) + .returnTypeNonNull(SqlTypeName.BIGINT) + .functionCategory(SqlFunctionCategory.USER_DEFINED_FUNCTION) + .build(); public ThetaSketchApproxCountDistinctSqlAggregator() { @@ -66,30 +72,4 @@ public class ThetaSketchApproxCountDistinctSqlAggregator extends ThetaSketchBase ) : null ); } - - private static class ThetaSketchSqlAggFunction extends SqlAggFunction - { - private static final String SIGNATURE = "'" + NAME + "(column, size)'"; - - ThetaSketchSqlAggFunction() - { - super( - NAME, - null, - SqlKind.OTHER_FUNCTION, - ReturnTypes.explicit(SqlTypeName.BIGINT), - InferTypes.VARCHAR_1024, - OperandTypes.or( - OperandTypes.ANY, - OperandTypes.and( - OperandTypes.sequence(SIGNATURE, OperandTypes.ANY, OperandTypes.LITERAL), - OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC) - ) - ), - SqlFunctionCategory.NUMERIC, - false, - false - ); - } - } } diff --git a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/theta/sql/ThetaSketchObjectSqlAggregator.java b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/theta/sql/ThetaSketchObjectSqlAggregator.java index 91dd36c2fb0..ac9cefd5f9b 100644 --- a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/theta/sql/ThetaSketchObjectSqlAggregator.java +++ b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/theta/sql/ThetaSketchObjectSqlAggregator.java @@ -21,20 +21,28 @@ package org.apache.druid.query.aggregation.datasketches.theta.sql; import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.SqlFunctionCategory; -import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.type.InferTypes; -import org.apache.calcite.sql.type.OperandTypes; import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.druid.query.aggregation.AggregatorFactory; import org.apache.druid.sql.calcite.aggregation.Aggregation; import org.apache.druid.sql.calcite.aggregation.SqlAggregator; +import org.apache.druid.sql.calcite.expression.OperatorConversions; import java.util.Collections; public class ThetaSketchObjectSqlAggregator extends ThetaSketchBaseSqlAggregator implements SqlAggregator { - private static final SqlAggFunction FUNCTION_INSTANCE = new ThetaSketchObjectSqlAggFunction(); private static final String NAME = "DS_THETA"; + private static final SqlAggFunction FUNCTION_INSTANCE = + OperatorConversions.aggregatorBuilder(NAME) + .operandNames("column", "size") + .operandTypes(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC) + .operandTypeInference(InferTypes.VARCHAR_1024) + .requiredOperandCount(1) + .literalOperands(1) + .returnTypeInference(ThetaSketchSqlOperators.RETURN_TYPE_INFERENCE) + .functionCategory(SqlFunctionCategory.USER_DEFINED_FUNCTION) + .build(); public ThetaSketchObjectSqlAggregator() { @@ -59,30 +67,4 @@ public class ThetaSketchObjectSqlAggregator extends ThetaSketchBaseSqlAggregator null ); } - - private static class ThetaSketchObjectSqlAggFunction extends SqlAggFunction - { - private static final String SIGNATURE = "'" + NAME + "(column, size)'"; - - ThetaSketchObjectSqlAggFunction() - { - super( - NAME, - null, - SqlKind.OTHER_FUNCTION, - ThetaSketchSqlOperators.RETURN_TYPE_INFERENCE, - InferTypes.VARCHAR_1024, - OperandTypes.or( - OperandTypes.ANY, - OperandTypes.and( - OperandTypes.sequence(SIGNATURE, OperandTypes.ANY, OperandTypes.LITERAL), - OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC) - ) - ), - SqlFunctionCategory.USER_DEFINED_FUNCTION, - false, - false - ); - } - } } diff --git a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchSqlAggregatorTest.java b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchSqlAggregatorTest.java index 9d7c4b8c03a..99c93a1cedd 100644 --- a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchSqlAggregatorTest.java +++ b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/hll/sql/HllSketchSqlAggregatorTest.java @@ -177,18 +177,19 @@ public class HllSketchSqlAggregatorTest extends BaseCalciteQueryTest + " APPROX_COUNT_DISTINCT(SUBSTRING(dim2, 1, 1)),\n" // on extractionFn, using generic A.C.D. + " COUNT(DISTINCT SUBSTRING(dim2, 1, 1) || 'x'),\n" // on expression, using COUNT DISTINCT + " APPROX_COUNT_DISTINCT_DS_HLL(hllsketch_dim1, 21, 'HLL_8'),\n" // on native HllSketch column - + " APPROX_COUNT_DISTINCT_DS_HLL(hllsketch_dim1)\n" // on native HllSketch column + + " APPROX_COUNT_DISTINCT_DS_HLL(hllsketch_dim1),\n" // on native HllSketch column + + " APPROX_COUNT_DISTINCT_DS_HLL(hllsketch_dim1, CAST(21 AS BIGINT))\n" // also native column + "FROM druid.foo"; final List expectedResults; if (NullHandling.replaceWithDefault()) { expectedResults = ImmutableList.of( - new Object[]{6L, 2L, 2L, 1L, 2L, 5L, 5L} + new Object[]{6L, 2L, 2L, 1L, 2L, 5L, 5L, 5L} ); } else { expectedResults = ImmutableList.of( - new Object[]{6L, 2L, 2L, 1L, 1L, 5L, 5L} + new Object[]{6L, 2L, 2L, 1L, 1L, 5L, 5L, 5L} ); } @@ -252,7 +253,8 @@ public class HllSketchSqlAggregatorTest extends BaseCalciteQueryTest ROUND ), new HllSketchMergeAggregatorFactory("a5", "hllsketch_dim1", 21, "HLL_8", null, ROUND), - new HllSketchMergeAggregatorFactory("a6", "hllsketch_dim1", null, null, null, ROUND) + new HllSketchMergeAggregatorFactory("a6", "hllsketch_dim1", null, null, null, ROUND), + new HllSketchMergeAggregatorFactory("a7", "hllsketch_dim1", 21, "HLL_4", null, ROUND) ) ) .context(QUERY_CONTEXT_DEFAULT) diff --git a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchSqlAggregatorTest.java b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchSqlAggregatorTest.java index 8f244e5302d..184aba375a0 100644 --- a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchSqlAggregatorTest.java +++ b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/quantiles/sql/DoublesSketchSqlAggregatorTest.java @@ -207,7 +207,7 @@ public class DoublesSketchSqlAggregatorTest extends BaseCalciteQueryTest + "APPROX_QUANTILE_DS(qsketch_m1, 0.01),\n" + "APPROX_QUANTILE_DS(qsketch_m1, 0.5, 64),\n" + "APPROX_QUANTILE_DS(qsketch_m1, 0.98, 256),\n" - + "APPROX_QUANTILE_DS(qsketch_m1, 0.99),\n" + + "APPROX_QUANTILE_DS(qsketch_m1, CAST(0.99 AS DOUBLE)),\n" + "APPROX_QUANTILE_DS(qsketch_m1, 0.99) FILTER(WHERE dim1 = 'abc'),\n" + "APPROX_QUANTILE_DS(qsketch_m1, 0.999) FILTER(WHERE dim1 <> 'abc'),\n" + "APPROX_QUANTILE_DS(qsketch_m1, 0.999) FILTER(WHERE dim1 = 'abc')\n" diff --git a/extensions-core/testing-tools/src/main/java/org/apache/druid/query/sql/SleepOperatorConversion.java b/extensions-core/testing-tools/src/main/java/org/apache/druid/query/sql/SleepOperatorConversion.java index 06d841af3ff..d64947d535c 100644 --- a/extensions-core/testing-tools/src/main/java/org/apache/druid/query/sql/SleepOperatorConversion.java +++ b/extensions-core/testing-tools/src/main/java/org/apache/druid/query/sql/SleepOperatorConversion.java @@ -42,7 +42,7 @@ public class SleepOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("SLEEP") .operandTypes(SqlTypeFamily.NUMERIC) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNullable(SqlTypeName.VARCHAR) // always null .functionCategory(SqlFunctionCategory.TIMEDATE) .build(); diff --git a/integration-tests-ex/tools/src/main/java/org/apache/druid/testing/tools/SleepOperatorConversion.java b/integration-tests-ex/tools/src/main/java/org/apache/druid/testing/tools/SleepOperatorConversion.java index cae087cf71e..abc31d3a434 100644 --- a/integration-tests-ex/tools/src/main/java/org/apache/druid/testing/tools/SleepOperatorConversion.java +++ b/integration-tests-ex/tools/src/main/java/org/apache/druid/testing/tools/SleepOperatorConversion.java @@ -42,7 +42,7 @@ public class SleepOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("SLEEP") .operandTypes(SqlTypeFamily.NUMERIC) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNullable(SqlTypeName.VARCHAR) // always null .functionCategory(SqlFunctionCategory.TIMEDATE) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/OperatorConversions.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/OperatorConversions.java index c0efb140174..6e3543d7372 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/OperatorConversions.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/OperatorConversions.java @@ -32,6 +32,7 @@ import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; import org.apache.calcite.runtime.CalciteException; +import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.SqlCallBinding; import org.apache.calcite.sql.SqlFunction; import org.apache.calcite.sql.SqlFunctionCategory; @@ -49,6 +50,7 @@ import org.apache.calcite.sql.type.SqlReturnTypeInference; import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.sql.type.SqlTypeTransforms; +import org.apache.calcite.util.Optionality; import org.apache.calcite.util.Static; import org.apache.druid.java.util.common.IAE; import org.apache.druid.java.util.common.ISE; @@ -57,12 +59,14 @@ import org.apache.druid.query.aggregation.PostAggregator; import org.apache.druid.query.aggregation.post.ExpressionPostAggregator; import org.apache.druid.query.aggregation.post.FieldAccessPostAggregator; import org.apache.druid.segment.column.RowSignature; +import org.apache.druid.sql.calcite.aggregation.SqlAggregator; import org.apache.druid.sql.calcite.planner.Calcites; import org.apache.druid.sql.calcite.planner.DruidTypeSystem; import org.apache.druid.sql.calcite.planner.PlannerContext; import javax.annotation.Nullable; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.stream.IntStream; @@ -316,23 +320,33 @@ public class OperatorConversions * Returns a builder that helps {@link SqlOperatorConversion} implementations create the {@link SqlFunction} * objects they need to return from {@link SqlOperatorConversion#calciteOperator()}. */ - public static OperatorBuilder operatorBuilder(final String name) + public static OperatorBuilder operatorBuilder(final String name) { - return new OperatorBuilder(name); + return new OperatorBuilder<>(name); } - public static class OperatorBuilder + /** + * Returns a builder that helps {@link SqlAggregator} implementations create the {@link SqlAggFunction} objects + * they need to return from {@link SqlAggregator#calciteFunction()}. + */ + public static OperatorBuilder aggregatorBuilder(final String name) { - private final String name; - private SqlKind kind = SqlKind.OTHER_FUNCTION; - private SqlReturnTypeInference returnTypeInference; - private SqlFunctionCategory functionCategory = SqlFunctionCategory.USER_DEFINED_FUNCTION; + return new AggregatorBuilder(name); + } + + public static class OperatorBuilder + { + protected final String name; + protected SqlKind kind = SqlKind.OTHER_FUNCTION; + protected SqlReturnTypeInference returnTypeInference; + protected SqlFunctionCategory functionCategory = SqlFunctionCategory.USER_DEFINED_FUNCTION; // For operand type checking private SqlOperandTypeChecker operandTypeChecker; + private List operandNames = Collections.emptyList(); private List operandTypes; - private Integer requiredOperands = null; - private int[] literalOperands = null; + private Integer requiredOperandCount; + private int[] literalOperands; private SqlOperandTypeInference operandTypeInference; private OperatorBuilder(final String name) @@ -348,7 +362,7 @@ public class OperatorConversions * {@link #returnTypeNullableArrayWithNullableElements}, or {@link #returnTypeInference(SqlReturnTypeInference)} * must be used before calling {@link #build()}. These methods cannot be mixed; you must call exactly one. */ - public OperatorBuilder returnTypeNonNull(final SqlTypeName typeName) + public OperatorBuilder returnTypeNonNull(final SqlTypeName typeName) { Preconditions.checkState(this.returnTypeInference == null, "Cannot set return type multiple times"); @@ -365,7 +379,7 @@ public class OperatorConversions * {@link #returnTypeNullableArrayWithNullableElements}, or {@link #returnTypeInference(SqlReturnTypeInference)} * must be used before calling {@link #build()}. These methods cannot be mixed; you must call exactly one. */ - public OperatorBuilder returnTypeNullable(final SqlTypeName typeName) + public OperatorBuilder returnTypeNullable(final SqlTypeName typeName) { Preconditions.checkState(this.returnTypeInference == null, "Cannot set return type multiple times"); @@ -382,7 +396,7 @@ public class OperatorConversions * {@link #returnTypeNullableArrayWithNullableElements}, or {@link #returnTypeInference(SqlReturnTypeInference)} * must be used before calling {@link #build()}. These methods cannot be mixed; you must call exactly one. */ - public OperatorBuilder returnTypeCascadeNullable(final SqlTypeName typeName) + public OperatorBuilder returnTypeCascadeNullable(final SqlTypeName typeName) { Preconditions.checkState(this.returnTypeInference == null, "Cannot set return type multiple times"); this.returnTypeInference = ReturnTypes.cascade(ReturnTypes.explicit(typeName), SqlTypeTransforms.TO_NULLABLE); @@ -396,7 +410,7 @@ public class OperatorConversions * {@link #returnTypeArrayWithNullableElements}, or {@link #returnTypeInference(SqlReturnTypeInference)} must be * used before calling {@link #build()}. These methods cannot be mixed; you must call exactly one. */ - public OperatorBuilder returnTypeArrayWithNullableElements(final SqlTypeName elementTypeName) + public OperatorBuilder returnTypeArrayWithNullableElements(final SqlTypeName elementTypeName) { Preconditions.checkState(this.returnTypeInference == null, "Cannot set return type multiple times"); @@ -413,7 +427,7 @@ public class OperatorConversions * {@link #returnTypeArrayWithNullableElements}, or {@link #returnTypeInference(SqlReturnTypeInference)} must be * used before calling {@link #build()}. These methods cannot be mixed; you must call exactly one. */ - public OperatorBuilder returnTypeNullableArrayWithNullableElements(final SqlTypeName elementTypeName) + public OperatorBuilder returnTypeNullableArrayWithNullableElements(final SqlTypeName elementTypeName) { this.returnTypeInference = ReturnTypes.cascade( opBinding -> Calcites.createSqlArrayTypeWithNullability( @@ -434,7 +448,7 @@ public class OperatorConversions * {@link #returnTypeNullableArrayWithNullableElements}, or {@link #returnTypeInference(SqlReturnTypeInference)} * must be used before calling {@link #build()}. These methods cannot be mixed; you must call exactly one. */ - public OperatorBuilder returnTypeInference(final SqlReturnTypeInference returnTypeInference) + public OperatorBuilder returnTypeInference(final SqlReturnTypeInference returnTypeInference) { Preconditions.checkState(this.returnTypeInference == null, "Cannot set return type multiple times"); @@ -447,7 +461,7 @@ public class OperatorConversions * * The default, if not provided, is {@link SqlFunctionCategory#USER_DEFINED_FUNCTION}. */ - public OperatorBuilder functionCategory(final SqlFunctionCategory functionCategory) + public OperatorBuilder functionCategory(final SqlFunctionCategory functionCategory) { this.functionCategory = functionCategory; return this; @@ -459,21 +473,32 @@ public class OperatorConversions * One of {@link #operandTypes(SqlTypeFamily...)} or {@link #operandTypeChecker(SqlOperandTypeChecker)} must be used * before calling {@link #build()}. These methods cannot be mixed; you must call exactly one. */ - public OperatorBuilder operandTypeChecker(final SqlOperandTypeChecker operandTypeChecker) + public OperatorBuilder operandTypeChecker(final SqlOperandTypeChecker operandTypeChecker) { this.operandTypeChecker = operandTypeChecker; return this; } + /** + * Signifies that a function accepts operands with the provided names. This is used to implement + * {@link SqlOperandTypeChecker#getAllowedSignatures(SqlOperator, String)}. If not provided, the + * {@link #operandTypes} are used instead. + */ + public OperatorBuilder operandNames(final String... operandNames) + { + this.operandNames = Arrays.asList(operandNames); + return this; + } + /** * Signifies that a function accepts operands of type family given by {@param operandTypes}. * - * May be used in conjunction with {@link #requiredOperands(int)} and {@link #literalOperands(int...)} in order + * May be used in conjunction with {@link #requiredOperandCount(int)} and {@link #literalOperands(int...)} in order * to further refine operand checking logic. * * For deeper control, use {@link #operandTypeChecker(SqlOperandTypeChecker)} instead. */ - public OperatorBuilder operandTypes(final SqlTypeFamily... operandTypes) + public OperatorBuilder operandTypes(final SqlTypeFamily... operandTypes) { this.operandTypes = Arrays.asList(operandTypes); return this; @@ -489,67 +514,97 @@ public class OperatorConversions * Must be used in conjunction with {@link #operandTypes(SqlTypeFamily...)}; this method is not compatible with * {@link #operandTypeChecker(SqlOperandTypeChecker)}. */ - public OperatorBuilder requiredOperands(final int requiredOperands) + public OperatorBuilder requiredOperandCount(final int requiredOperandCount) { - this.requiredOperands = requiredOperands; + this.requiredOperandCount = requiredOperandCount; return this; } + /** + * Alias for {@link #requiredOperandCount(int)}. Deprecated because it means "operand count" rather than + * "specific operands", and therefore the name can cause confusion with {@link #literalOperands(int...)}. The latter + * really does mean "specific operands". + */ + @Deprecated + @SuppressWarnings("unused") // For compatibility with existing extensions + public OperatorBuilder requiredOperands(final int requiredOperands) + { + return requiredOperandCount(requiredOperands); + } + /** * Signifies that the operands at positions given by {@code literalOperands} must be literals. * * Must be used in conjunction with {@link #operandTypes(SqlTypeFamily...)}; this method is not compatible with * {@link #operandTypeChecker(SqlOperandTypeChecker)}. */ - public OperatorBuilder literalOperands(final int... literalOperands) + public OperatorBuilder literalOperands(final int... literalOperands) { this.literalOperands = literalOperands; return this; } - public OperatorBuilder operandTypeInference(SqlOperandTypeInference operandTypeInference) + public OperatorBuilder operandTypeInference(SqlOperandTypeInference operandTypeInference) { this.operandTypeInference = operandTypeInference; return this; } - public OperatorBuilder sqlKind(SqlKind kind) - { - this.kind = kind; - return this; - } - /** * Creates a {@link SqlFunction} from this builder. */ - public SqlFunction build() + @SuppressWarnings("unchecked") + public T build() + { + final IntSet nullableOperands = buildNullableOperands(); + return (T) new SqlFunction( + name, + kind, + Preconditions.checkNotNull(returnTypeInference, "returnTypeInference"), + buildOperandTypeInference(nullableOperands), + buildOperandTypeChecker(nullableOperands), + functionCategory + ); + } + + protected IntSet buildNullableOperands() { // Create "nullableOperands" set including all optional arguments. final IntSet nullableOperands = new IntArraySet(); - if (requiredOperands != null) { - IntStream.range(requiredOperands, operandTypes.size()).forEach(nullableOperands::add); + if (requiredOperandCount != null) { + IntStream.range(requiredOperandCount, operandTypes.size()).forEach(nullableOperands::add); } + return nullableOperands; + } - final SqlOperandTypeChecker theOperandTypeChecker; - + protected SqlOperandTypeChecker buildOperandTypeChecker(final IntSet nullableOperands) + { if (operandTypeChecker == null) { - theOperandTypeChecker = new DefaultOperandTypeChecker( + return new DefaultOperandTypeChecker( + operandNames, operandTypes, - requiredOperands == null ? operandTypes.size() : requiredOperands, + requiredOperandCount == null ? operandTypes.size() : requiredOperandCount, nullableOperands, literalOperands ); - } else if (operandTypes == null && requiredOperands == null && literalOperands == null) { - theOperandTypeChecker = operandTypeChecker; + } else if (operandNames.isEmpty() + && operandTypes == null + && requiredOperandCount == null + && literalOperands == null) { + return operandTypeChecker; } else { throw new ISE( - "Cannot have both 'operandTypeChecker' and 'operandTypes' / 'requiredOperands' / 'literalOperands'" + "Cannot have both 'operandTypeChecker' and " + + "'operandNames' / 'operandTypes' / 'requiredOperands' / 'literalOperands'" ); } + } + protected SqlOperandTypeInference buildOperandTypeInference(final IntSet nullableOperands) + { if (operandTypeInference == null) { SqlOperandTypeInference defaultInference = new DefaultOperandTypeInference(operandTypes, nullableOperands); - operandTypeInference = (callBinding, returnType, types) -> { + return (callBinding, returnType, types) -> { for (int i = 0; i < types.length; i++) { // calcite sql validate tries to do bad things to dynamic parameters if the type is inferred to be a string if (callBinding.operand(i).isA(ImmutableSet.of(SqlKind.DYNAMIC_PARAM))) { @@ -562,15 +617,49 @@ public class OperatorConversions } } }; + } else { + return operandTypeInference; } - return new SqlFunction( - name, - kind, - Preconditions.checkNotNull(returnTypeInference, "returnTypeInference"), - operandTypeInference, - theOperandTypeChecker, - functionCategory - ); + } + } + + public static class AggregatorBuilder extends OperatorBuilder + { + public AggregatorBuilder(String name) + { + super(name); + } + + /** + * Create a {@link SqlAggFunction} from this builder. + */ + @Override + public SqlAggFunction build() + { + final IntSet nullableOperands = buildNullableOperands(); + final SqlOperandTypeInference operandTypeInference = buildOperandTypeInference(nullableOperands); + final SqlOperandTypeChecker operandTypeChecker = buildOperandTypeChecker(nullableOperands); + + class DruidSqlAggFunction extends SqlAggFunction + { + public DruidSqlAggFunction() + { + super( + name, + null, + AggregatorBuilder.this.kind, + returnTypeInference, + operandTypeInference, + operandTypeChecker, + functionCategory, + false, + false, + Optionality.FORBIDDEN + ); + } + } + + return new DruidSqlAggFunction(); } } @@ -655,6 +744,11 @@ public class OperatorConversions @VisibleForTesting static class DefaultOperandTypeChecker implements SqlOperandTypeChecker { + /** + * Operand names for {@link #getAllowedSignatures(SqlOperator, String)}. May be empty, in which case the + * {@link #operandTypes} are used instead. + */ + private final List operandNames; private final List operandTypes; private final int requiredOperands; private final IntSet nullableOperands; @@ -662,6 +756,7 @@ public class OperatorConversions @VisibleForTesting DefaultOperandTypeChecker( + final List operandNames, final List operandTypes, final int requiredOperands, final IntSet nullableOperands, @@ -669,10 +764,15 @@ public class OperatorConversions ) { Preconditions.checkArgument(requiredOperands <= operandTypes.size() && requiredOperands >= 0); + this.operandNames = Preconditions.checkNotNull(operandNames, "operandNames"); this.operandTypes = Preconditions.checkNotNull(operandTypes, "operandTypes"); this.requiredOperands = requiredOperands; this.nullableOperands = Preconditions.checkNotNull(nullableOperands, "nullableOperands"); + if (!operandNames.isEmpty() && operandNames.size() != operandTypes.size()) { + throw new ISE("Operand name count[%s] and type count[%s] must match", operandNames.size(), operandTypes.size()); + } + if (literalOperands == null) { this.literalOperands = IntSets.EMPTY_SET; } else { @@ -688,8 +788,8 @@ public class OperatorConversions final SqlNode operand = callBinding.operands().get(i); if (literalOperands.contains(i)) { - // Verify that 'operand' is a literal. - if (!SqlUtil.isLiteral(operand)) { + // Verify that 'operand' is a literal. Allow CAST, since we can reduce these away later. + if (!SqlUtil.isLiteral(operand, true)) { return throwOrReturn( throwOnFailure, callBinding, @@ -739,7 +839,25 @@ public class OperatorConversions @Override public String getAllowedSignatures(SqlOperator op, String opName) { - return SqlUtil.getAliasedSignature(op, opName, operandTypes); + final List operands = !operandNames.isEmpty() ? operandNames : operandTypes; + final StringBuilder ret = new StringBuilder(); + ret.append("'"); + ret.append(opName); + ret.append("("); + for (int i = 0; i < operands.size(); i++) { + if (i > 0) { + ret.append(", "); + } + if (i >= requiredOperands) { + ret.append("["); + } + ret.append("<").append(operands.get(i)).append(">"); + } + for (int i = requiredOperands; i < operands.size(); i++) { + ret.append("]"); + } + ret.append(")'"); + return ret.toString(); } @Override @@ -772,7 +890,7 @@ public class OperatorConversions { return new DirectOperatorConversion( operatorBuilder(sqlOperator) - .requiredOperands(1) + .requiredOperandCount(1) .operandTypes(SqlTypeFamily.NUMERIC) .returnTypeNullable(SqlTypeName.BIGINT) .functionCategory(SqlFunctionCategory.NUMERIC) @@ -785,7 +903,7 @@ public class OperatorConversions { return new DirectOperatorConversion( operatorBuilder(sqlOperator) - .requiredOperands(2) + .requiredOperandCount(2) .operandTypes(SqlTypeFamily.NUMERIC, SqlTypeFamily.NUMERIC) .returnTypeNullable(SqlTypeName.BIGINT) .functionCategory(SqlFunctionCategory.NUMERIC) @@ -798,7 +916,7 @@ public class OperatorConversions { return new DirectOperatorConversion( operatorBuilder(StringUtils.toUpperCase(sqlOperator)) - .requiredOperands(1) + .requiredOperandCount(1) .operandTypes(SqlTypeFamily.NUMERIC) .returnTypeNullable(SqlTypeName.DOUBLE) .functionCategory(SqlFunctionCategory.NUMERIC) diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/BTrimOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/BTrimOperatorConversion.java index d5a24773fe2..b8ae238dcf4 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/BTrimOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/BTrimOperatorConversion.java @@ -40,7 +40,7 @@ public class BTrimOperatorConversion implements SqlOperatorConversion .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER) .returnTypeCascadeNullable(SqlTypeName.VARCHAR) .functionCategory(SqlFunctionCategory.STRING) - .requiredOperands(1) + .requiredOperandCount(1) .build(); @Override diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ContainsOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ContainsOperatorConversion.java index 98703feb028..5e8071fb90c 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ContainsOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ContainsOperatorConversion.java @@ -80,7 +80,7 @@ public class ContainsOperatorConversion extends DirectOperatorConversion return OperatorConversions .operatorBuilder(StringUtils.toUpperCase(functionName)) .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER) - .requiredOperands(2) + .requiredOperandCount(2) .literalOperands(1) .returnTypeNonNull(SqlTypeName.BOOLEAN) .functionCategory(SqlFunctionCategory.STRING) diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/DateTruncOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/DateTruncOperatorConversion.java index b913cd32caa..361de42862b 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/DateTruncOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/DateTruncOperatorConversion.java @@ -67,7 +67,7 @@ public class DateTruncOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("DATE_TRUNC") .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.TIMESTAMP) - .requiredOperands(2) + .requiredOperandCount(2) .returnTypeCascadeNullable(SqlTypeName.TIMESTAMP) .functionCategory(SqlFunctionCategory.TIMEDATE) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LPadOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LPadOperatorConversion.java index 2dd89e7b7d6..8ccecafa3be 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LPadOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LPadOperatorConversion.java @@ -40,7 +40,7 @@ public class LPadOperatorConversion implements SqlOperatorConversion .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER, SqlTypeFamily.CHARACTER) .returnTypeCascadeNullable(SqlTypeName.VARCHAR) .functionCategory(SqlFunctionCategory.STRING) - .requiredOperands(2) + .requiredOperandCount(2) .build(); @Override diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LTrimOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LTrimOperatorConversion.java index 64d99e84a75..eef7584632e 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LTrimOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/LTrimOperatorConversion.java @@ -40,7 +40,7 @@ public class LTrimOperatorConversion implements SqlOperatorConversion .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER) .returnTypeCascadeNullable(SqlTypeName.VARCHAR) .functionCategory(SqlFunctionCategory.STRING) - .requiredOperands(1) + .requiredOperandCount(1) .build(); @Override diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ParseLongOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ParseLongOperatorConversion.java index 2bb00a22914..53b7b790256 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ParseLongOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ParseLongOperatorConversion.java @@ -40,7 +40,7 @@ public class ParseLongOperatorConversion implements SqlOperatorConversion .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER) .returnTypeCascadeNullable(SqlTypeName.BIGINT) .functionCategory(SqlFunctionCategory.STRING) - .requiredOperands(1) + .requiredOperandCount(1) .build(); @Override diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RPadOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RPadOperatorConversion.java index 68ee6537cd8..8e85d7a0682 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RPadOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RPadOperatorConversion.java @@ -40,7 +40,7 @@ public class RPadOperatorConversion implements SqlOperatorConversion .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER, SqlTypeFamily.CHARACTER) .returnTypeCascadeNullable(SqlTypeName.VARCHAR) .functionCategory(SqlFunctionCategory.STRING) - .requiredOperands(2) + .requiredOperandCount(2) .build(); @Override diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RTrimOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RTrimOperatorConversion.java index 70da7fbb4e6..bf5c9b0fe95 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RTrimOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RTrimOperatorConversion.java @@ -40,7 +40,7 @@ public class RTrimOperatorConversion implements SqlOperatorConversion .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER) .returnTypeCascadeNullable(SqlTypeName.VARCHAR) .functionCategory(SqlFunctionCategory.STRING) - .requiredOperands(1) + .requiredOperandCount(1) .build(); @Override diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RegexpExtractOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RegexpExtractOperatorConversion.java index 95c0e3421b0..804e5cad05d 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RegexpExtractOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RegexpExtractOperatorConversion.java @@ -38,7 +38,7 @@ public class RegexpExtractOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("REGEXP_EXTRACT") .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER) - .requiredOperands(2) + .requiredOperandCount(2) .literalOperands(1, 2) .returnTypeNullable(SqlTypeName.VARCHAR) .functionCategory(SqlFunctionCategory.STRING) diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RegexpLikeOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RegexpLikeOperatorConversion.java index b065b276cc5..cc677215cba 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RegexpLikeOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RegexpLikeOperatorConversion.java @@ -44,7 +44,7 @@ public class RegexpLikeOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("REGEXP_LIKE") .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER) - .requiredOperands(2) + .requiredOperandCount(2) .literalOperands(1) .returnTypeNonNull(SqlTypeName.BOOLEAN) .functionCategory(SqlFunctionCategory.STRING) diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RoundOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RoundOperatorConversion.java index 76e5dc1da95..a14e3a0f0d9 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RoundOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/RoundOperatorConversion.java @@ -35,7 +35,7 @@ public class RoundOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("ROUND") .operandTypes(SqlTypeFamily.NUMERIC, SqlTypeFamily.INTEGER) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeInference(ReturnTypes.ARG0) .functionCategory(SqlFunctionCategory.NUMERIC) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SubstringOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SubstringOperatorConversion.java index 4b9e35b7198..ae470922c1c 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SubstringOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SubstringOperatorConversion.java @@ -43,7 +43,7 @@ public class SubstringOperatorConversion implements SqlOperatorConversion .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER) .functionCategory(SqlFunctionCategory.STRING) .returnTypeInference(ReturnTypes.ARG0) - .requiredOperands(2) + .requiredOperandCount(2) .build(); @Override diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TextcatOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TextcatOperatorConversion.java index 5da41c42c80..40a13479b8c 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TextcatOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TextcatOperatorConversion.java @@ -31,7 +31,7 @@ public class TextcatOperatorConversion extends DirectOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("textcat") .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER) - .requiredOperands(2) + .requiredOperandCount(2) .returnTypeCascadeNullable(SqlTypeName.VARCHAR) .functionCategory(SqlFunctionCategory.STRING) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeCeilOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeCeilOperatorConversion.java index 75680050528..ffa022b0ee8 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeCeilOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeCeilOperatorConversion.java @@ -41,7 +41,7 @@ public class TimeCeilOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("TIME_CEIL") .operandTypes(SqlTypeFamily.TIMESTAMP, SqlTypeFamily.CHARACTER, SqlTypeFamily.TIMESTAMP, SqlTypeFamily.CHARACTER) - .requiredOperands(2) + .requiredOperandCount(2) .returnTypeCascadeNullable(SqlTypeName.TIMESTAMP) .functionCategory(SqlFunctionCategory.TIMEDATE) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeExtractOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeExtractOperatorConversion.java index 69397bc4d3a..6a36bf4dad0 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeExtractOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeExtractOperatorConversion.java @@ -43,7 +43,7 @@ public class TimeExtractOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("TIME_EXTRACT") .operandTypes(SqlTypeFamily.TIMESTAMP, SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER) - .requiredOperands(2) + .requiredOperandCount(2) .returnTypeCascadeNullable(SqlTypeName.BIGINT) .functionCategory(SqlFunctionCategory.TIMEDATE) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeFloorOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeFloorOperatorConversion.java index 9f74e87c797..b0b5b69acc7 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeFloorOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeFloorOperatorConversion.java @@ -56,7 +56,7 @@ public class TimeFloorOperatorConversion implements SqlOperatorConversion public static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder(SQL_FUNCTION_NAME) .operandTypes(SqlTypeFamily.TIMESTAMP, SqlTypeFamily.CHARACTER, SqlTypeFamily.TIMESTAMP, SqlTypeFamily.CHARACTER) - .requiredOperands(2) + .requiredOperandCount(2) .returnTypeCascadeNullable(SqlTypeName.TIMESTAMP) .functionCategory(SqlFunctionCategory.TIMEDATE) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeFormatOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeFormatOperatorConversion.java index 8c07ffdf4ea..60127fc2099 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeFormatOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeFormatOperatorConversion.java @@ -46,7 +46,7 @@ public class TimeFormatOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("TIME_FORMAT") .operandTypes(SqlTypeFamily.TIMESTAMP, SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeCascadeNullable(SqlTypeName.VARCHAR) .functionCategory(SqlFunctionCategory.TIMEDATE) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeParseOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeParseOperatorConversion.java index 99bc94cc8f1..7e515a35168 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeParseOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeParseOperatorConversion.java @@ -43,7 +43,7 @@ public class TimeParseOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("TIME_PARSE") .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNullable(SqlTypeName.TIMESTAMP) .functionCategory(SqlFunctionCategory.TIMEDATE) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeShiftOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeShiftOperatorConversion.java index d2973fb6d18..edda4d07406 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeShiftOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TimeShiftOperatorConversion.java @@ -43,7 +43,7 @@ public class TimeShiftOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("TIME_SHIFT") .operandTypes(SqlTypeFamily.TIMESTAMP, SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER, SqlTypeFamily.CHARACTER) - .requiredOperands(3) + .requiredOperandCount(3) .returnTypeCascadeNullable(SqlTypeName.TIMESTAMP) .functionCategory(SqlFunctionCategory.TIMEDATE) .build(); diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TruncateOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TruncateOperatorConversion.java index 8459bed7d72..d891823dd15 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TruncateOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/TruncateOperatorConversion.java @@ -37,7 +37,7 @@ public class TruncateOperatorConversion implements SqlOperatorConversion private static final SqlFunction SQL_FUNCTION = OperatorConversions .operatorBuilder("TRUNCATE") .operandTypes(SqlTypeFamily.NUMERIC, SqlTypeFamily.INTEGER) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeInference(ReturnTypes.ARG0) .functionCategory(SqlFunctionCategory.NUMERIC) .build(); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/OperatorConversionsTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/OperatorConversionsTest.java index 5f70dc5902a..d3f97eed22b 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/OperatorConversionsTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/OperatorConversionsTest.java @@ -51,6 +51,7 @@ import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; @RunWith(Enclosed.class) @@ -65,6 +66,7 @@ public class OperatorConversionsTest public void testGetOperandCountRange() { SqlOperandTypeChecker typeChecker = new DefaultOperandTypeChecker( + Collections.emptyList(), ImmutableList.of(SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER), 2, IntSets.EMPTY_SET, @@ -79,6 +81,7 @@ public class OperatorConversionsTest public void testIsOptional() { SqlOperandTypeChecker typeChecker = new DefaultOperandTypeChecker( + Collections.emptyList(), ImmutableList.of(SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER), 2, IntSets.EMPTY_SET, @@ -95,7 +98,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testAllowFullOperands") .operandTypes(SqlTypeFamily.INTEGER, SqlTypeFamily.DATE) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -119,7 +122,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testRequiredOperandsOnly") .operandTypes(SqlTypeFamily.INTEGER, SqlTypeFamily.DATE) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -140,7 +143,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testLiteralOperandCheckLiteral") .operandTypes(SqlTypeFamily.INTEGER) - .requiredOperands(1) + .requiredOperandCount(1) .literalOperands(0) .returnTypeNonNull(SqlTypeName.CHAR) .build(); @@ -162,7 +165,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testLiteralOperandCheckLiteralThrow") .operandTypes(SqlTypeFamily.INTEGER) - .requiredOperands(1) + .requiredOperandCount(1) .literalOperands(0) .returnTypeNonNull(SqlTypeName.CHAR) .build(); @@ -184,7 +187,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testAnyTypeOperand") .operandTypes(SqlTypeFamily.ANY) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -205,7 +208,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testCastableFromDatetimeFamilyToTimestamp") .operandTypes(SqlTypeFamily.DATETIME) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -235,7 +238,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testNullForNullableOperand") .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTERVAL_DAY_TIME) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -259,7 +262,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testNullLiteralForNullableOperand") .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTERVAL_DAY_TIME) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -283,7 +286,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testNullForNullableNonnull") .operandTypes(SqlTypeFamily.CHARACTER) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -304,7 +307,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testNullForNullableCascade") .operandTypes(SqlTypeFamily.CHARACTER) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeCascadeNullable(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -325,7 +328,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testNullForNullableNonnull") .operandTypes(SqlTypeFamily.CHARACTER) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNullable(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -346,7 +349,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testNullForNonNullableOperand") .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTERVAL_DAY_TIME) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -372,7 +375,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testNullLiteralForNonNullableOperand") .operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTERVAL_DAY_TIME) - .requiredOperands(1) + .requiredOperandCount(1) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -398,7 +401,7 @@ public class OperatorConversionsTest SqlFunction function = OperatorConversions .operatorBuilder("testNonCastableType") .operandTypes(SqlTypeFamily.CURSOR, SqlTypeFamily.INTERVAL_DAY_TIME) - .requiredOperands(2) + .requiredOperandCount(2) .returnTypeNonNull(SqlTypeName.CHAR) .build(); SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); @@ -418,6 +421,41 @@ public class OperatorConversionsTest ); } + @Test + public void testSignatureWithNames() + { + SqlFunction function = OperatorConversions + .operatorBuilder("testSignatureWithNames") + .operandNames("x", "y", "z") + .operandTypes(SqlTypeFamily.INTEGER, SqlTypeFamily.DATE, SqlTypeFamily.ANY) + .requiredOperandCount(1) + .returnTypeNonNull(SqlTypeName.CHAR) + .build(); + SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); + + Assert.assertEquals( + "'testSignatureWithNames(, [, []])'", + typeChecker.getAllowedSignatures(function, function.getName()) + ); + } + + @Test + public void testSignatureWithoutNames() + { + SqlFunction function = OperatorConversions + .operatorBuilder("testSignatureWithoutNames") + .operandTypes(SqlTypeFamily.INTEGER, SqlTypeFamily.DATE, SqlTypeFamily.ANY) + .requiredOperandCount(1) + .returnTypeNonNull(SqlTypeName.CHAR) + .build(); + SqlOperandTypeChecker typeChecker = function.getOperandTypeChecker(); + + Assert.assertEquals( + "'testSignatureWithoutNames(, [, []])'", + typeChecker.getAllowedSignatures(function, function.getName()) + ); + } + private static SqlCallBinding mockCallBinding( SqlFunction function, List actualOperands diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidOperatorTableTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidOperatorTableTest.java index 1e148517631..02e5c522f27 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidOperatorTableTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidOperatorTableTest.java @@ -68,7 +68,7 @@ public class DruidOperatorTableTest final SqlOperator operator1 = OperatorConversions .operatorBuilder("FOO") .operandTypes(SqlTypeFamily.ANY) - .requiredOperands(0) + .requiredOperandCount(0) .returnTypeInference( opBinding -> RowSignatures.makeComplexType( opBinding.getTypeFactory(), diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidRexExecutorTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidRexExecutorTest.java index bb5edf2d94c..205f3379d71 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidRexExecutorTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidRexExecutorTest.java @@ -69,7 +69,7 @@ public class DruidRexExecutorTest extends InitializedNullHandlingTest private static final SqlOperator OPERATOR = OperatorConversions .operatorBuilder(StringUtils.toUpperCase("hyper_unique")) .operandTypes(SqlTypeFamily.ANY) - .requiredOperands(0) + .requiredOperandCount(0) .returnTypeInference( opBinding -> RowSignatures.makeComplexType( opBinding.getTypeFactory(), diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/schema/InformationSchemaTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/schema/InformationSchemaTest.java index 306599b2f32..43551b3e040 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/schema/InformationSchemaTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/schema/InformationSchemaTest.java @@ -136,7 +136,7 @@ public class InformationSchemaTest extends BaseCalciteQueryTest Assert.assertNotNull(rows); Assert.assertEquals("There should be exactly 2 rows; any non-function syntax operator should get filtered out", 2, rows.size()); - Object[] expectedRow1 = {"druid", "INFORMATION_SCHEMA", "FOO", "FUNCTION", "NO", "'FOO()'"}; + Object[] expectedRow1 = {"druid", "INFORMATION_SCHEMA", "FOO", "FUNCTION", "NO", "'FOO([])'"}; Assert.assertTrue(rows.stream().anyMatch(row -> Arrays.equals(row, expectedRow1))); Object[] expectedRow2 = {"druid", "INFORMATION_SCHEMA", "BAR", "FUNCTION", "NO", "'BAR(, )'"}; @@ -166,7 +166,7 @@ public class InformationSchemaTest extends BaseCalciteQueryTest final SqlOperator operator1 = OperatorConversions .operatorBuilder("FOO") .operandTypes(SqlTypeFamily.ANY) - .requiredOperands(0) + .requiredOperandCount(0) .returnTypeInference( opBinding -> RowSignatures.makeComplexType( opBinding.getTypeFactory(), @@ -182,7 +182,7 @@ public class InformationSchemaTest extends BaseCalciteQueryTest .operatorBuilder("BAR") .operandTypes(SqlTypeFamily.NUMERIC) .operandTypes(SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER) - .requiredOperands(2) + .requiredOperandCount(2) .returnTypeInference( opBinding -> RowSignatures.makeComplexType( opBinding.getTypeFactory(),