From b14dcff6964b3f827dee328f54bbfa8536b0e7b2 Mon Sep 17 00:00:00 2001 From: Soumyava Das Date: Wed, 10 Nov 2021 16:34:24 -0800 Subject: [PATCH 1/7] IMPLY-4344: Adding safe divide function along with testcases and documentation updates --- .../org/apache/druid/math/expr/Function.java | 40 +++++++++++++++ .../apache/druid/math/expr/FunctionTest.java | 10 ++++ docs/misc/math-expr.md | 1 + docs/querying/sql.md | 2 + .../builtin/SafeDivideOperatorConversion.java | 34 +++++++++++++ .../calcite/planner/DruidOperatorTable.java | 7 +++ .../druid/sql/calcite/CalciteQueryTest.java | 49 +++++++++++++++++++ 7 files changed, 143 insertions(+) create mode 100644 sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SafeDivideOperatorConversion.java diff --git a/core/src/main/java/org/apache/druid/math/expr/Function.java b/core/src/main/java/org/apache/druid/math/expr/Function.java index 2d45567f3bfc..ab86d26bf251 100644 --- a/core/src/main/java/org/apache/druid/math/expr/Function.java +++ b/core/src/main/java/org/apache/druid/math/expr/Function.java @@ -1165,6 +1165,46 @@ public ExprVectorProcessor asVectorProcessor(Expr.VectorInputBindingInspe } } + class SafeDivide extends BivariateMathFunction + { + public static final String NAME = "safe_divide"; + + @Override + public String name() + { + return NAME ; + } + + @Nullable + @Override + public ExpressionType getOutputType(Expr.InputBindingInspector inspector, List args) + { + return ExpressionTypeConversion.integerMathFunction( + args.get(0).getOutputType(inspector), + args.get(1).getOutputType(inspector) + ); + } + + @Override + protected ExprEval eval(final long x, final long y) + { + if(y==0) { + return ExprEval.of(0); + } + return ExprEval.of(x / y); + } + + @Override + protected ExprEval eval(final double x, final double y) + { + if(y==0) { + return ExprEval.of(0); + } + return ExprEval.of(x/y); + } + + } + class Div extends BivariateMathFunction { @Override diff --git a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java index bc7afa30acc8..f8d960638e04 100644 --- a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java @@ -732,6 +732,16 @@ public void testSizeFormatInvalidArgumentSize() .eval(bindings); } + @Test + public void testSafeDivide() + { + // happy path maths + assertExpr("safe_divide(3, 1)", 3L); + assertExpr("safe_divide(4.5, 2)", 2.25); + assertExpr("safe_divide(3, 0)", 0L); + assertExpr("safe_divide(3.7, 0.0)", 0L); + } + @Test public void testBitwise() { diff --git a/docs/misc/math-expr.md b/docs/misc/math-expr.md index 7f3b036f1561..6dc4152fd700 100644 --- a/docs/misc/math-expr.md +++ b/docs/misc/math-expr.md @@ -154,6 +154,7 @@ See javadoc of java.lang.Math for detailed explanation for each function. |remainder|remainder(x, y) returns the remainder operation on two arguments as prescribed by the IEEE 754 standard| |rint|rint(x) returns value that is closest in value to x and is equal to a mathematical integer| |round|round(x, y) returns the value of the x rounded to the y decimal places. While x can be an integer or floating-point number, y must be an integer. The type of the return value is specified by that of x. y defaults to 0 if omitted. When y is negative, x is rounded on the left side of the y decimal points. If x is `NaN`, x returns 0. If x is infinity, x will be converted to the nearest finite double. | +|safe_divide|safe_divide(x,y) returns the division of x by y if y is not equal to 0, returns 0 otherwise| |scalb|scalb(d, sf) returns d * 2^sf rounded as if performed by a single correctly rounded floating-point multiply to a member of the double value set| |signum|signum(x) returns the signum function of the argument x| |sin|sin(x) returns the trigonometric sine of an angle x| diff --git a/docs/querying/sql.md b/docs/querying/sql.md index 8d658e48b4f9..543aee30f96a 100644 --- a/docs/querying/sql.md +++ b/docs/querying/sql.md @@ -414,9 +414,11 @@ to FLOAT. At runtime, Druid will widen 32-bit floats to 64-bit for most expressi |`BITWISE_SHIFT_LEFT(expr1, expr2)`|Returns the result of `expr1 << expr2`. Double values will be implicitly cast to longs, use `BITWISE_CONVERT_DOUBLE_TO_LONG_BITS` to perform bitwise operations directly with doubles| |`BITWISE_SHIFT_RIGHT(expr1, expr2)`|Returns the result of `expr1 >> expr2`. Double values will be implicitly cast to longs, use `BITWISE_CONVERT_DOUBLE_TO_LONG_BITS` to perform bitwise operations directly with doubles| |`BITWISE_XOR(expr1, expr2)`|Returns the result of `expr1 ^ expr2`. Double values will be implicitly cast to longs, use `BITWISE_CONVERT_DOUBLE_TO_LONG_BITS` to perform bitwise operations directly with doubles| +|`DIV(x,y)`|Returns the result of integer division of x by y | |`HUMAN_READABLE_BINARY_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [IEC](https://en.wikipedia.org/wiki/Binary_prefix) format. For example, HUMAN_READABLE_BINARY_BYTE_FORMAT(1048576) returns `1.00 MiB`. `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [SI](https://en.wikipedia.org/wiki/Binary_prefix) format. HUMAN_READABLE_DECIMAL_BYTE_FORMAT(1048576) returns `1.04 MB`. `precision` must be in the range of [0,3] (default: 2). `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_FORMAT(value[, precision])`| Format a number in human-readable SI format. For example, HUMAN_READABLE_DECIMAL_FORMAT(1048576) returns `1.04 M`. `precision` must be in the range of [0,3] (default: 2). | +|`SAFE_DIVIDE(x,y)`|Returns the division of x by y guarded on division by 0 | ### String functions diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SafeDivideOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SafeDivideOperatorConversion.java new file mode 100644 index 000000000000..6a22049903db --- /dev/null +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SafeDivideOperatorConversion.java @@ -0,0 +1,34 @@ +package org.apache.druid.sql.calcite.expression.builtin; + +import org.apache.calcite.sql.SqlFunction; +import org.apache.calcite.sql.SqlFunctionCategory; +import org.apache.calcite.sql.SqlOperator; +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; +import org.apache.druid.math.expr.Function; +import org.apache.druid.sql.calcite.expression.DirectOperatorConversion; +import org.apache.druid.sql.calcite.expression.OperatorConversions; + +public class SafeDivideOperatorConversion extends DirectOperatorConversion +{ + private static final SqlFunction SQL_FUNCTION = OperatorConversions + .operatorBuilder(StringUtils.toUpperCase(Function.SafeDivide.NAME)) + .operandTypeChecker(OperandTypes.ANY_NUMERIC) + .returnTypeInference(ReturnTypes.QUOTIENT_NULLABLE) + .functionCategory(SqlFunctionCategory.USER_DEFINED_FUNCTION) + .build(); + + public SafeDivideOperatorConversion() + { + super(SQL_FUNCTION, Function.SafeDivide.NAME); + } + + @Override + public SqlOperator calciteOperator() + { + return SQL_FUNCTION; + } +} diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidOperatorTable.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidOperatorTable.java index 118b6efbc671..41ed11ca849e 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidOperatorTable.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidOperatorTable.java @@ -96,6 +96,7 @@ import org.apache.druid.sql.calcite.expression.builtin.ReverseOperatorConversion; import org.apache.druid.sql.calcite.expression.builtin.RightOperatorConversion; import org.apache.druid.sql.calcite.expression.builtin.RoundOperatorConversion; +import org.apache.druid.sql.calcite.expression.builtin.SafeDivideOperatorConversion; import org.apache.druid.sql.calcite.expression.builtin.StringFormatOperatorConversion; import org.apache.druid.sql.calcite.expression.builtin.StringToArrayOperatorConversion; import org.apache.druid.sql.calcite.expression.builtin.StrposOperatorConversion; @@ -260,6 +261,11 @@ public class DruidOperatorTable implements SqlOperatorTable .add(HumanReadableFormatOperatorConversion.DECIMAL_FORMAT) .build(); + private static final List CUSTOM_MATH_OPERATOR_CONVERSIONS = + ImmutableList.builder() + .add(new SafeDivideOperatorConversion()) + .build(); + private static final List BITWISE_OPERATOR_CONVERSIONS = ImmutableList.builder() .add(OperatorConversions.druidBinaryLongFn("BITWISE_AND", "bitwiseAnd")) @@ -354,6 +360,7 @@ public class DruidOperatorTable implements SqlOperatorTable .addAll(IPV4ADDRESS_OPERATOR_CONVERSIONS) .addAll(FORMAT_OPERATOR_CONVERSIONS) .addAll(BITWISE_OPERATOR_CONVERSIONS) + .addAll(CUSTOM_MATH_OPERATOR_CONVERSIONS) .build(); // Operators that have no conversion, but are handled in the convertlet table, so they still need to exist. 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 a632f0eab385..e9eebc83d9f2 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 @@ -1008,6 +1008,55 @@ public void testBitwiseExpressions() throws Exception ); } + @Test + public void testSafeDivideExpressions() throws Exception + { + List expected; + if (useDefault) { + expected = ImmutableList.of( + new Object[]{0.0F,0L,0.0,7.0F}, + new Object[]{1.0F,1L,1.0,3253230.0F}, + new Object[]{0.0F,0L,0.0,0.0F}, + new Object[]{0.0F,0L,0.0,0.0F}, + new Object[]{0.0F,0L,0.0,0.0F}, + new Object[]{0.0F,0L,0.0,0.0F} + ); + } else { + expected = ImmutableList.of( + new Object[]{null,null,null,7.0F}, + new Object[]{1.0F,1L,1.0,3253230.0F}, + new Object[]{0.0F,0L,0,0.0F}, + new Object[]{null,null,null,null}, + new Object[]{null,null,null,null}, + new Object[]{null,null,null,null} + ); + } + testQuery( + "SELECT\n" + + "SAFE_DIVIDE(f1, f2),\n" + + "SAFE_DIVIDE(l1, l2),\n" + + "SAFE_DIVIDE(d2, d1),\n" + + "SAFE_DIVIDE(l1, f1)\n" + + "FROM numfoo", + ImmutableList.of( + Druids.newScanQueryBuilder() + .dataSource(CalciteTests.DATASOURCE3) + .intervals(querySegmentSpec(Filtration.eternity())) + .columns("v0","v1","v2","v3") + .virtualColumns( + expressionVirtualColumn("v0", "safe_divide(\"f1\",\"f2\")", ColumnType.FLOAT), + expressionVirtualColumn("v1", "safe_divide(\"l1\",\"l2\")", ColumnType.LONG), + expressionVirtualColumn("v2", "safe_divide(\"d2\",\"d1\")", ColumnType.DOUBLE), + expressionVirtualColumn("v3", "safe_divide(\"l1\",\"f1\")", ColumnType.FLOAT) + ) + .context(QUERY_CONTEXT_DEFAULT) + .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) + .legacy(false) + .build() + ), + expected + ); + } @Test public void testExplainSelectConstantExpression() throws Exception From b2031be20487a8d91713ed5cdf2e4ced9e4d02d0 Mon Sep 17 00:00:00 2001 From: Soumyava Das Date: Fri, 12 Nov 2021 12:26:52 -0800 Subject: [PATCH 2/7] Changing based on review comments --- .../org/apache/druid/math/expr/Function.java | 25 ++++++++++++------- .../apache/druid/math/expr/FunctionTest.java | 9 +++++-- docs/misc/math-expr.md | 2 +- .../builtin/SafeDivideOperatorConversion.java | 21 ++++++++++++++-- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/apache/druid/math/expr/Function.java b/core/src/main/java/org/apache/druid/math/expr/Function.java index ab86d26bf251..c1448b976f50 100644 --- a/core/src/main/java/org/apache/druid/math/expr/Function.java +++ b/core/src/main/java/org/apache/druid/math/expr/Function.java @@ -1179,28 +1179,35 @@ public String name() @Override public ExpressionType getOutputType(Expr.InputBindingInspector inspector, List args) { - return ExpressionTypeConversion.integerMathFunction( - args.get(0).getOutputType(inspector), - args.get(1).getOutputType(inspector) - ); + ExpressionType type = ExpressionType.DOUBLE; + for (Expr arg : args) { + type = ExpressionTypeConversion.function(type, arg.getOutputType(inspector)); + } + return ExpressionType.asArrayType(type); } @Override protected ExprEval eval(final long x, final long y) { if(y==0) { - return ExprEval.of(0); + if(x!=0){ + return ExprEval.ofLong(NullHandling.defaultLongValue()); + } + return ExprEval.ofLong(0); } - return ExprEval.of(x / y); + return ExprEval.ofLong(x / y); } @Override protected ExprEval eval(final double x, final double y) { - if(y==0) { - return ExprEval.of(0); + if(y==0||Double.isNaN(y)) { + if(x!=0){ + return ExprEval.ofDouble(NullHandling.defaultDoubleValue()); + } + return ExprEval.ofDouble(0); } - return ExprEval.of(x/y); + return ExprEval.ofDouble(x/y); } } diff --git a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java index f8d960638e04..927d0aa214c5 100644 --- a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java @@ -738,8 +738,13 @@ public void testSafeDivide() // happy path maths assertExpr("safe_divide(3, 1)", 3L); assertExpr("safe_divide(4.5, 2)", 2.25); - assertExpr("safe_divide(3, 0)", 0L); - assertExpr("safe_divide(3.7, 0.0)", 0L); + assertExpr("safe_divide(3, 0)", NullHandling.defaultLongValue()); + assertExpr("safe_divide(1, 0.0)", NullHandling.defaultDoubleValue()); + // NaN and Infinity cases + assertExpr("safe_divide(NaN, 0.0)", NullHandling.defaultDoubleValue()); + assertExpr("safe_divide(0, NaN)", NullHandling.defaultDoubleValue()); + assertExpr("safe_divide(0, POSITIVE_INFINITY)", 0L); + assertExpr("safe_divide(POSITIVE_INFINITY,0)", 0L); } @Test diff --git a/docs/misc/math-expr.md b/docs/misc/math-expr.md index 6dc4152fd700..204b988af80f 100644 --- a/docs/misc/math-expr.md +++ b/docs/misc/math-expr.md @@ -154,7 +154,7 @@ See javadoc of java.lang.Math for detailed explanation for each function. |remainder|remainder(x, y) returns the remainder operation on two arguments as prescribed by the IEEE 754 standard| |rint|rint(x) returns value that is closest in value to x and is equal to a mathematical integer| |round|round(x, y) returns the value of the x rounded to the y decimal places. While x can be an integer or floating-point number, y must be an integer. The type of the return value is specified by that of x. y defaults to 0 if omitted. When y is negative, x is rounded on the left side of the y decimal points. If x is `NaN`, x returns 0. If x is infinity, x will be converted to the nearest finite double. | -|safe_divide|safe_divide(x,y) returns the division of x by y if y is not equal to 0, returns 0 otherwise| +|safe_divide|safe_divide(x,y) returns the division of x by y if y is not equal to 0. In case y is 0 it returns null or default values (if returning default values are enabled). | |scalb|scalb(d, sf) returns d * 2^sf rounded as if performed by a single correctly rounded floating-point multiply to a member of the double value set| |signum|signum(x) returns the signum function of the argument x| |sin|sin(x) returns the trigonometric sine of an angle x| diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SafeDivideOperatorConversion.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SafeDivideOperatorConversion.java index 6a22049903db..dd09feefadd9 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SafeDivideOperatorConversion.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/SafeDivideOperatorConversion.java @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.apache.druid.sql.calcite.expression.builtin; import org.apache.calcite.sql.SqlFunction; @@ -5,8 +24,6 @@ import org.apache.calcite.sql.SqlOperator; 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; import org.apache.druid.math.expr.Function; import org.apache.druid.sql.calcite.expression.DirectOperatorConversion; From fd7e3913daf2b4dcf0296ab223f8b36f53cb6641 Mon Sep 17 00:00:00 2001 From: Soumyava Das Date: Mon, 15 Nov 2021 10:02:31 -0800 Subject: [PATCH 3/7] Addressing review comments, fixing coding style, docs and spelling --- .../org/apache/druid/math/expr/Function.java | 22 +++++++++---------- .../apache/druid/math/expr/FunctionTest.java | 2 +- .../druid/math/expr/OutputTypeTest.java | 5 +++++ docs/misc/math-expr.md | 2 +- docs/querying/sql.md | 2 +- website/.spelling | 1 + 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/apache/druid/math/expr/Function.java b/core/src/main/java/org/apache/druid/math/expr/Function.java index c1448b976f50..fb087b8cdc9b 100644 --- a/core/src/main/java/org/apache/druid/math/expr/Function.java +++ b/core/src/main/java/org/apache/druid/math/expr/Function.java @@ -1172,25 +1172,24 @@ class SafeDivide extends BivariateMathFunction @Override public String name() { - return NAME ; + return NAME; } @Nullable @Override public ExpressionType getOutputType(Expr.InputBindingInspector inspector, List args) { - ExpressionType type = ExpressionType.DOUBLE; - for (Expr arg : args) { - type = ExpressionTypeConversion.function(type, arg.getOutputType(inspector)); - } - return ExpressionType.asArrayType(type); + return ExpressionTypeConversion.function( + args.get(0).getOutputType(inspector), + args.get(1).getOutputType(inspector) + ); } @Override protected ExprEval eval(final long x, final long y) { - if(y==0) { - if(x!=0){ + if (y == 0) { + if (x != 0) { return ExprEval.ofLong(NullHandling.defaultLongValue()); } return ExprEval.ofLong(0); @@ -1201,15 +1200,14 @@ protected ExprEval eval(final long x, final long y) @Override protected ExprEval eval(final double x, final double y) { - if(y==0||Double.isNaN(y)) { - if(x!=0){ + if (y == 0 || Double.isNaN(y)) { + if (x != 0) { return ExprEval.ofDouble(NullHandling.defaultDoubleValue()); } return ExprEval.ofDouble(0); } - return ExprEval.ofDouble(x/y); + return ExprEval.ofDouble(x / y); } - } class Div extends BivariateMathFunction diff --git a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java index 927d0aa214c5..e2e79686a4f0 100644 --- a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java @@ -742,7 +742,7 @@ public void testSafeDivide() assertExpr("safe_divide(1, 0.0)", NullHandling.defaultDoubleValue()); // NaN and Infinity cases assertExpr("safe_divide(NaN, 0.0)", NullHandling.defaultDoubleValue()); - assertExpr("safe_divide(0, NaN)", NullHandling.defaultDoubleValue()); + assertExpr("safe_divide(0, NaN)", 0.0); assertExpr("safe_divide(0, POSITIVE_INFINITY)", 0L); assertExpr("safe_divide(POSITIVE_INFINITY,0)", 0L); } diff --git a/core/src/test/java/org/apache/druid/math/expr/OutputTypeTest.java b/core/src/test/java/org/apache/druid/math/expr/OutputTypeTest.java index 07d523a0c816..11d031ebc773 100644 --- a/core/src/test/java/org/apache/druid/math/expr/OutputTypeTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/OutputTypeTest.java @@ -169,6 +169,11 @@ public void testBivariateMathFunctions() assertOutputType("hypot(y,y_)", inspector, ExpressionType.DOUBLE); assertOutputType("hypot(y,z_)", inspector, ExpressionType.DOUBLE); assertOutputType("hypot(z,z_)", inspector, ExpressionType.DOUBLE); + + assertOutputType("safe_divide(y,y_)", inspector, ExpressionType.LONG); + assertOutputType("safe_divide(y,z_)", inspector, ExpressionType.DOUBLE); + assertOutputType("safe_divide(z,z_)", inspector, ExpressionType.DOUBLE); + } @Test diff --git a/docs/misc/math-expr.md b/docs/misc/math-expr.md index 204b988af80f..99e86bd5fc5f 100644 --- a/docs/misc/math-expr.md +++ b/docs/misc/math-expr.md @@ -154,7 +154,7 @@ See javadoc of java.lang.Math for detailed explanation for each function. |remainder|remainder(x, y) returns the remainder operation on two arguments as prescribed by the IEEE 754 standard| |rint|rint(x) returns value that is closest in value to x and is equal to a mathematical integer| |round|round(x, y) returns the value of the x rounded to the y decimal places. While x can be an integer or floating-point number, y must be an integer. The type of the return value is specified by that of x. y defaults to 0 if omitted. When y is negative, x is rounded on the left side of the y decimal points. If x is `NaN`, x returns 0. If x is infinity, x will be converted to the nearest finite double. | -|safe_divide|safe_divide(x,y) returns the division of x by y if y is not equal to 0. In case y is 0 it returns null or default values (if returning default values are enabled). | +|safe_divide|safe_divide(x,y) returns the division of x by y if y is not equal to 0. In case y is 0 it returns 0 or `null` if `druid.generic.useDefaultValueForNull=false` | |scalb|scalb(d, sf) returns d * 2^sf rounded as if performed by a single correctly rounded floating-point multiply to a member of the double value set| |signum|signum(x) returns the signum function of the argument x| |sin|sin(x) returns the trigonometric sine of an angle x| diff --git a/docs/querying/sql.md b/docs/querying/sql.md index 543aee30f96a..040b1573d6e5 100644 --- a/docs/querying/sql.md +++ b/docs/querying/sql.md @@ -418,7 +418,7 @@ to FLOAT. At runtime, Druid will widen 32-bit floats to 64-bit for most expressi |`HUMAN_READABLE_BINARY_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [IEC](https://en.wikipedia.org/wiki/Binary_prefix) format. For example, HUMAN_READABLE_BINARY_BYTE_FORMAT(1048576) returns `1.00 MiB`. `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [SI](https://en.wikipedia.org/wiki/Binary_prefix) format. HUMAN_READABLE_DECIMAL_BYTE_FORMAT(1048576) returns `1.04 MB`. `precision` must be in the range of [0,3] (default: 2). `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_FORMAT(value[, precision])`| Format a number in human-readable SI format. For example, HUMAN_READABLE_DECIMAL_FORMAT(1048576) returns `1.04 M`. `precision` must be in the range of [0,3] (default: 2). | -|`SAFE_DIVIDE(x,y)`|Returns the division of x by y guarded on division by 0 | +|`SAFE_DIVIDE(x,y)`|Returns the division of x by y guarded on division by 0.In case y is 0 it returns 0, or `null` if `druid.generic.useDefaultValueForNull=false` | ### String functions diff --git a/website/.spelling b/website/.spelling index 9d474f7f6eec..bc4a9adf0a01 100644 --- a/website/.spelling +++ b/website/.spelling @@ -1199,6 +1199,7 @@ result2 rint rpad rtrim +safe_divide scalb signum str1 From 4d64aaef64cfb794fd5342c3365de07f37164615 Mon Sep 17 00:00:00 2001 From: Soumyava Das Date: Mon, 15 Nov 2021 11:05:07 -0800 Subject: [PATCH 4/7] Checkstyle passes for all code --- .../org/apache/druid/math/expr/Function.java | 17 +- .../apache/druid/math/expr/FunctionTest.java | 126 +- .../druid/math/expr/OutputTypeTest.java | 187 ++- .../druid/sql/calcite/CalciteQueryTest.java | 1050 ++++++++++------- 4 files changed, 893 insertions(+), 487 deletions(-) diff --git a/core/src/main/java/org/apache/druid/math/expr/Function.java b/core/src/main/java/org/apache/druid/math/expr/Function.java index fb087b8cdc9b..b02f88e55e95 100644 --- a/core/src/main/java/org/apache/druid/math/expr/Function.java +++ b/core/src/main/java/org/apache/druid/math/expr/Function.java @@ -59,7 +59,7 @@ /** * Base interface describing the mechanism used to evaluate a {@link FunctionExpr}. All {@link Function} implementations * are immutable. - * + *

* Do NOT remove "unused" members in this class. They are used by generated Antlr */ @SuppressWarnings("unused") @@ -1977,7 +1977,9 @@ protected ExprEval eval(ExprEval x, ExprEval y) public Set getScalarInputs(List args) { if (args.get(1).isLiteral()) { - ExpressionType castTo = ExpressionType.fromString(StringUtils.toUpperCase(args.get(1).getLiteralValue().toString())); + ExpressionType castTo = ExpressionType.fromString(StringUtils.toUpperCase(args.get(1) + .getLiteralValue() + .toString())); switch (castTo.getType()) { case ARRAY: return Collections.emptySet(); @@ -1993,7 +1995,9 @@ public Set getScalarInputs(List args) public Set getArrayInputs(List args) { if (args.get(1).isLiteral()) { - ExpressionType castTo = ExpressionType.fromString(StringUtils.toUpperCase(args.get(1).getLiteralValue().toString())); + ExpressionType castTo = ExpressionType.fromString(StringUtils.toUpperCase(args.get(1) + .getLiteralValue() + .toString())); switch (castTo.getType()) { case LONG: case DOUBLE: @@ -3282,7 +3286,9 @@ ExprEval doApply(ExprEval arrayExpr, ExprEval scalarExpr) break; } } - return index < 0 ? ExprEval.ofLong(NullHandling.replaceWithDefault() ? -1 : null) : ExprEval.ofLong(index + 1); + return index < 0 + ? ExprEval.ofLong(NullHandling.replaceWithDefault() ? -1 : null) + : ExprEval.ofLong(index + 1); default: throw new IAE("Function[%s] 2nd argument must be a a scalar type", name()); } @@ -3636,7 +3642,8 @@ public ExprEval apply(List args, Expr.ObjectBinding bindings) name() ); } - ExpressionType complexType = ExpressionTypeFactory.getInstance().ofComplex((String) args.get(0).getLiteralValue()); + ExpressionType complexType = ExpressionTypeFactory.getInstance() + .ofComplex((String) args.get(0).getLiteralValue()); ObjectByteStrategy strategy = Types.getStrategy(complexType.getComplexTypeName()); if (strategy == null) { throw new IAE( diff --git a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java index e2e79686a4f0..5377a59850cf 100644 --- a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java @@ -52,30 +52,36 @@ public class FunctionTest extends InitializedNullHandlingTest @BeforeClass public static void setupClass() { - Types.registerStrategy(TypesTest.NULLABLE_TEST_PAIR_TYPE.getComplexTypeName(), new TypesTest.PairObjectByteStrategy()); + Types.registerStrategy( + TypesTest.NULLABLE_TEST_PAIR_TYPE.getComplexTypeName(), + new TypesTest.PairObjectByteStrategy() + ); } @Before public void setup() { ImmutableMap.Builder builder = ImmutableMap.builder() - .put("x", "foo") - .put("y", 2) - .put("z", 3.1) - .put("d", 34.56D) - .put("maxLong", Long.MAX_VALUE) - .put("minLong", Long.MIN_VALUE) - .put("f", 12.34F) - .put("nan", Double.NaN) - .put("inf", Double.POSITIVE_INFINITY) - .put("-inf", Double.NEGATIVE_INFINITY) - .put("o", 0) - .put("od", 0D) - .put("of", 0F) - .put("a", new String[] {"foo", "bar", "baz", "foobar"}) - .put("b", new Long[] {1L, 2L, 3L, 4L, 5L}) - .put("c", new Double[] {3.1, 4.2, 5.3}) - .put("someComplex", new TypesTest.NullableLongPair(1L, 2L)); + .put("x", "foo") + .put("y", 2) + .put("z", 3.1) + .put("d", 34.56D) + .put("maxLong", Long.MAX_VALUE) + .put("minLong", Long.MIN_VALUE) + .put("f", 12.34F) + .put("nan", Double.NaN) + .put("inf", Double.POSITIVE_INFINITY) + .put("-inf", Double.NEGATIVE_INFINITY) + .put("o", 0) + .put("od", 0D) + .put("of", 0F) + .put("a", new String[]{"foo", "bar", "baz", "foobar"}) + .put("b", new Long[]{1L, 2L, 3L, 4L, 5L}) + .put("c", new Double[]{3.1, 4.2, 5.3}) + .put( + "someComplex", + new TypesTest.NullableLongPair(1L, 2L) + ); bindings = InputBindings.withMap(builder.build()); } @@ -350,17 +356,20 @@ public void testArrayCast() assertArrayExpr("cast([1, 2, 3], 'STRING_ARRAY')", new String[]{"1", "2", "3"}); assertArrayExpr("cast([1, 2, 3], 'DOUBLE_ARRAY')", new Double[]{1.0, 2.0, 3.0}); assertArrayExpr("cast(c, 'LONG_ARRAY')", new Long[]{3L, 4L, 5L}); - assertArrayExpr("cast(string_to_array(array_to_string(b, ','), ','), 'LONG_ARRAY')", new Long[]{1L, 2L, 3L, 4L, 5L}); + assertArrayExpr( + "cast(string_to_array(array_to_string(b, ','), ','), 'LONG_ARRAY')", + new Long[]{1L, 2L, 3L, 4L, 5L} + ); assertArrayExpr("cast(['1.0', '2.0', '3.0'], 'LONG_ARRAY')", new Long[]{1L, 2L, 3L}); } @Test public void testArraySlice() { - assertArrayExpr("array_slice([1, 2, 3, 4], 1, 3)", new Long[] {2L, 3L}); - assertArrayExpr("array_slice([1.0, 2.1, 3.2, 4.3], 2)", new Double[] {3.2, 4.3}); - assertArrayExpr("array_slice(['a', 'b', 'c', 'd'], 4, 6)", new String[] {null, null}); - assertArrayExpr("array_slice([1, 2, 3, 4], 2, 2)", new Long[] {}); + assertArrayExpr("array_slice([1, 2, 3, 4], 1, 3)", new Long[]{2L, 3L}); + assertArrayExpr("array_slice([1.0, 2.1, 3.2, 4.3], 2)", new Double[]{3.2, 4.3}); + assertArrayExpr("array_slice(['a', 'b', 'c', 'd'], 4, 6)", new String[]{null, null}); + assertArrayExpr("array_slice([1, 2, 3, 4], 2, 2)", new Long[]{}); assertArrayExpr("array_slice([1, 2, 3, 4], 5, 7)", null); assertArrayExpr("array_slice([1, 2, 3, 4], 2, 1)", null); } @@ -438,12 +447,24 @@ public void testRoundWithExtremeNumbers() assertExpr("round(maxLong)", BigDecimal.valueOf(Long.MAX_VALUE).setScale(0, RoundingMode.HALF_UP).longValue()); assertExpr("round(minLong)", BigDecimal.valueOf(Long.MIN_VALUE).setScale(0, RoundingMode.HALF_UP).longValue()); // overflow - assertExpr("round(maxLong + 1, 1)", BigDecimal.valueOf(Long.MIN_VALUE).setScale(1, RoundingMode.HALF_UP).longValue()); + assertExpr( + "round(maxLong + 1, 1)", + BigDecimal.valueOf(Long.MIN_VALUE).setScale(1, RoundingMode.HALF_UP).longValue() + ); // underflow - assertExpr("round(minLong - 1, -2)", BigDecimal.valueOf(Long.MAX_VALUE).setScale(-2, RoundingMode.HALF_UP).longValue()); + assertExpr( + "round(minLong - 1, -2)", + BigDecimal.valueOf(Long.MAX_VALUE).setScale(-2, RoundingMode.HALF_UP).longValue() + ); - assertExpr("round(CAST(maxLong, 'DOUBLE') + 1, 1)", BigDecimal.valueOf(((double) Long.MAX_VALUE) + 1).setScale(1, RoundingMode.HALF_UP).doubleValue()); - assertExpr("round(CAST(minLong, 'DOUBLE') - 1, -2)", BigDecimal.valueOf(((double) Long.MIN_VALUE) - 1).setScale(-2, RoundingMode.HALF_UP).doubleValue()); + assertExpr( + "round(CAST(maxLong, 'DOUBLE') + 1, 1)", + BigDecimal.valueOf(((double) Long.MAX_VALUE) + 1).setScale(1, RoundingMode.HALF_UP).doubleValue() + ); + assertExpr( + "round(CAST(minLong, 'DOUBLE') - 1, -2)", + BigDecimal.valueOf(((double) Long.MIN_VALUE) - 1).setScale(-2, RoundingMode.HALF_UP).doubleValue() + ); } @Test @@ -643,7 +664,10 @@ public void testSizeForatInvalidArgumentType() Assert.assertTrue(NullHandling.sqlCompatible() ? true : false); } catch (IAE e) { - Assert.assertEquals("Function[human_readable_binary_byte_format] needs a number as its first argument", e.getMessage()); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] needs a number as its first argument", + e.getMessage() + ); } try { @@ -655,7 +679,10 @@ public void testSizeForatInvalidArgumentType() Assert.assertTrue(false); } catch (IAE e) { - Assert.assertEquals("Function[human_readable_binary_byte_format] needs an integer as its second argument", e.getMessage()); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] needs an integer as its second argument", + e.getMessage() + ); } try { @@ -667,7 +694,10 @@ public void testSizeForatInvalidArgumentType() Assert.assertTrue(false); } catch (IAE e) { - Assert.assertEquals("Function[human_readable_binary_byte_format] needs an integer as its second argument", e.getMessage()); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] needs an integer as its second argument", + e.getMessage() + ); } try { @@ -679,7 +709,10 @@ public void testSizeForatInvalidArgumentType() Assert.assertTrue(false); } catch (IAE e) { - Assert.assertEquals("Function[human_readable_binary_byte_format] needs an integer as its second argument", e.getMessage()); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] needs an integer as its second argument", + e.getMessage() + ); } } @@ -692,7 +725,10 @@ public void testSizeFormatInvalidPrecision() Assert.assertTrue(false); } catch (IAE e) { - Assert.assertEquals("Given precision[9223372036854775807] of Function[human_readable_binary_byte_format] must be in the range of [0,3]", e.getMessage()); + Assert.assertEquals( + "Given precision[9223372036854775807] of Function[human_readable_binary_byte_format] must be in the range of [0,3]", + e.getMessage() + ); } try { @@ -701,7 +737,10 @@ public void testSizeFormatInvalidPrecision() Assert.assertTrue(false); } catch (IAE e) { - Assert.assertEquals("Given precision[-9223372036854775808] of Function[human_readable_binary_byte_format] must be in the range of [0,3]", e.getMessage()); + Assert.assertEquals( + "Given precision[-9223372036854775808] of Function[human_readable_binary_byte_format] must be in the range of [0,3]", + e.getMessage() + ); } try { @@ -710,7 +749,10 @@ public void testSizeFormatInvalidPrecision() Assert.assertTrue(false); } catch (IAE e) { - Assert.assertEquals("Given precision[-1] of Function[human_readable_binary_byte_format] must be in the range of [0,3]", e.getMessage()); + Assert.assertEquals( + "Given precision[-1] of Function[human_readable_binary_byte_format] must be in the range of [0,3]", + e.getMessage() + ); } try { @@ -719,7 +761,10 @@ public void testSizeFormatInvalidPrecision() Assert.assertTrue(false); } catch (IAE e) { - Assert.assertEquals("Given precision[4] of Function[human_readable_binary_byte_format] must be in the range of [0,3]", e.getMessage()); + Assert.assertEquals( + "Given precision[4] of Function[human_readable_binary_byte_format] must be in the range of [0,3]", + e.getMessage() + ); } } @@ -778,7 +823,10 @@ public void testBitwise() Assert.fail("Did not throw IllegalArgumentException"); } catch (IllegalArgumentException e) { - Assert.assertEquals("Possible data truncation, param [461168601842738800000000000000.000000] is out of long value range", e.getMessage()); + Assert.assertEquals( + "Possible data truncation, param [461168601842738800000000000000.000000] is out of long value range", + e.getMessage() + ); } // doubles are cast @@ -860,7 +908,8 @@ public void testComplexDecodeBaseWrongArgCount() public void testComplexDecodeBaseArg0BadType() { expectedException.expect(IAE.class); - expectedException.expectMessage("Function[complex_decode_base64] first argument must be constant 'STRING' expression containing a valid complex type name"); + expectedException.expectMessage( + "Function[complex_decode_base64] first argument must be constant 'STRING' expression containing a valid complex type name"); assertExpr( "complex_decode_base64(1, string)", null @@ -871,7 +920,8 @@ public void testComplexDecodeBaseArg0BadType() public void testComplexDecodeBaseArg0Unknown() { expectedException.expect(IAE.class); - expectedException.expectMessage("Function[complex_decode_base64] first argument must be a valid complex type name, unknown complex type [COMPLEX]"); + expectedException.expectMessage( + "Function[complex_decode_base64] first argument must be a valid complex type name, unknown complex type [COMPLEX]"); assertExpr( "complex_decode_base64('unknown', string)", null diff --git a/core/src/test/java/org/apache/druid/math/expr/OutputTypeTest.java b/core/src/test/java/org/apache/druid/math/expr/OutputTypeTest.java index 11d031ebc773..2cb097e85ca7 100644 --- a/core/src/test/java/org/apache/druid/math/expr/OutputTypeTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/OutputTypeTest.java @@ -33,18 +33,18 @@ public class OutputTypeTest extends InitializedNullHandlingTest { private final Expr.InputBindingInspector inspector = inspectorFromMap( ImmutableMap.builder().put("x", ExpressionType.STRING) - .put("x_", ExpressionType.STRING) - .put("y", ExpressionType.LONG) - .put("y_", ExpressionType.LONG) - .put("z", ExpressionType.DOUBLE) - .put("z_", ExpressionType.DOUBLE) - .put("a", ExpressionType.STRING_ARRAY) - .put("a_", ExpressionType.STRING_ARRAY) - .put("b", ExpressionType.LONG_ARRAY) - .put("b_", ExpressionType.LONG_ARRAY) - .put("c", ExpressionType.DOUBLE_ARRAY) - .put("c_", ExpressionType.DOUBLE_ARRAY) - .build() + .put("x_", ExpressionType.STRING) + .put("y", ExpressionType.LONG) + .put("y_", ExpressionType.LONG) + .put("z", ExpressionType.DOUBLE) + .put("z_", ExpressionType.DOUBLE) + .put("a", ExpressionType.STRING_ARRAY) + .put("a_", ExpressionType.STRING_ARRAY) + .put("b", ExpressionType.LONG_ARRAY) + .put("b_", ExpressionType.LONG_ARRAY) + .put("c", ExpressionType.DOUBLE_ARRAY) + .put("c_", ExpressionType.DOUBLE_ARRAY) + .build() ); @Rule @@ -441,19 +441,49 @@ public void testOperatorAutoConversion() Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.operator(ExpressionType.STRING, null)); Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.operator(null, ExpressionType.STRING)); // only long stays long - Assert.assertEquals(ExpressionType.LONG, ExpressionTypeConversion.operator(ExpressionType.LONG, ExpressionType.LONG)); + Assert.assertEquals( + ExpressionType.LONG, + ExpressionTypeConversion.operator(ExpressionType.LONG, ExpressionType.LONG) + ); // only string stays string - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.operator(ExpressionType.STRING, ExpressionType.STRING)); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.operator(ExpressionType.STRING, ExpressionType.STRING) + ); // for operators, doubles is the catch all - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.operator(ExpressionType.LONG, ExpressionType.DOUBLE)); - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.operator(ExpressionType.DOUBLE, ExpressionType.LONG)); - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.operator(ExpressionType.DOUBLE, ExpressionType.DOUBLE)); - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.operator(ExpressionType.DOUBLE, ExpressionType.STRING)); - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.operator(ExpressionType.STRING, ExpressionType.DOUBLE)); - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.operator(ExpressionType.STRING, ExpressionType.LONG)); - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.operator(ExpressionType.LONG, ExpressionType.STRING)); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.operator(ExpressionType.LONG, ExpressionType.DOUBLE) + ); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.operator(ExpressionType.DOUBLE, ExpressionType.LONG) + ); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.operator(ExpressionType.DOUBLE, ExpressionType.DOUBLE) + ); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.operator(ExpressionType.DOUBLE, ExpressionType.STRING) + ); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.operator(ExpressionType.STRING, ExpressionType.DOUBLE) + ); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.operator(ExpressionType.STRING, ExpressionType.LONG) + ); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.operator(ExpressionType.LONG, ExpressionType.STRING) + ); // unless it is an array, and those have to be the same - Assert.assertEquals(ExpressionType.LONG_ARRAY, ExpressionTypeConversion.operator(ExpressionType.LONG_ARRAY, ExpressionType.LONG_ARRAY)); + Assert.assertEquals( + ExpressionType.LONG_ARRAY, + ExpressionTypeConversion.operator(ExpressionType.LONG_ARRAY, ExpressionType.LONG_ARRAY) + ); Assert.assertEquals( ExpressionType.DOUBLE_ARRAY, ExpressionTypeConversion.operator(ExpressionType.DOUBLE_ARRAY, ExpressionType.DOUBLE_ARRAY) @@ -475,19 +505,49 @@ public void testFunctionAutoConversion() Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.function(ExpressionType.STRING, null)); Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.function(null, ExpressionType.STRING)); // only long stays long - Assert.assertEquals(ExpressionType.LONG, ExpressionTypeConversion.function(ExpressionType.LONG, ExpressionType.LONG)); + Assert.assertEquals( + ExpressionType.LONG, + ExpressionTypeConversion.function(ExpressionType.LONG, ExpressionType.LONG) + ); // any double makes all doubles - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.function(ExpressionType.LONG, ExpressionType.DOUBLE)); - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.function(ExpressionType.DOUBLE, ExpressionType.LONG)); - Assert.assertEquals(ExpressionType.DOUBLE, ExpressionTypeConversion.function(ExpressionType.DOUBLE, ExpressionType.DOUBLE)); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.function(ExpressionType.LONG, ExpressionType.DOUBLE) + ); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.function(ExpressionType.DOUBLE, ExpressionType.LONG) + ); + Assert.assertEquals( + ExpressionType.DOUBLE, + ExpressionTypeConversion.function(ExpressionType.DOUBLE, ExpressionType.DOUBLE) + ); // any string makes become string - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.function(ExpressionType.LONG, ExpressionType.STRING)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.function(ExpressionType.STRING, ExpressionType.LONG)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.function(ExpressionType.DOUBLE, ExpressionType.STRING)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.function(ExpressionType.STRING, ExpressionType.DOUBLE)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.function(ExpressionType.STRING, ExpressionType.STRING)); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.function(ExpressionType.LONG, ExpressionType.STRING) + ); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.function(ExpressionType.STRING, ExpressionType.LONG) + ); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.function(ExpressionType.DOUBLE, ExpressionType.STRING) + ); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.function(ExpressionType.STRING, ExpressionType.DOUBLE) + ); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.function(ExpressionType.STRING, ExpressionType.STRING) + ); // unless it is an array, and those have to be the same - Assert.assertEquals(ExpressionType.LONG_ARRAY, ExpressionTypeConversion.function(ExpressionType.LONG_ARRAY, ExpressionType.LONG_ARRAY)); + Assert.assertEquals( + ExpressionType.LONG_ARRAY, + ExpressionTypeConversion.function(ExpressionType.LONG_ARRAY, ExpressionType.LONG_ARRAY) + ); Assert.assertEquals( ExpressionType.DOUBLE_ARRAY, ExpressionTypeConversion.function(ExpressionType.DOUBLE_ARRAY, ExpressionType.DOUBLE_ARRAY) @@ -506,21 +566,60 @@ public void testIntegerFunctionAutoConversion() Assert.assertEquals(ExpressionType.LONG, ExpressionTypeConversion.integerMathFunction(null, ExpressionType.LONG)); Assert.assertEquals(ExpressionType.LONG, ExpressionTypeConversion.integerMathFunction(ExpressionType.DOUBLE, null)); Assert.assertEquals(ExpressionType.LONG, ExpressionTypeConversion.integerMathFunction(null, ExpressionType.DOUBLE)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.integerMathFunction(ExpressionType.STRING, null)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.integerMathFunction(null, ExpressionType.STRING)); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.integerMathFunction(ExpressionType.STRING, null) + ); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.integerMathFunction(null, ExpressionType.STRING) + ); // all numbers are longs - Assert.assertEquals(ExpressionType.LONG, ExpressionTypeConversion.integerMathFunction(ExpressionType.LONG, ExpressionType.LONG)); - Assert.assertEquals(ExpressionType.LONG, ExpressionTypeConversion.integerMathFunction(ExpressionType.LONG, ExpressionType.DOUBLE)); - Assert.assertEquals(ExpressionType.LONG, ExpressionTypeConversion.integerMathFunction(ExpressionType.DOUBLE, ExpressionType.LONG)); - Assert.assertEquals(ExpressionType.LONG, ExpressionTypeConversion.integerMathFunction(ExpressionType.DOUBLE, ExpressionType.DOUBLE)); + Assert.assertEquals( + ExpressionType.LONG, + ExpressionTypeConversion.integerMathFunction(ExpressionType.LONG, ExpressionType.LONG) + ); + Assert.assertEquals( + ExpressionType.LONG, + ExpressionTypeConversion.integerMathFunction(ExpressionType.LONG, ExpressionType.DOUBLE) + ); + Assert.assertEquals( + ExpressionType.LONG, + ExpressionTypeConversion.integerMathFunction(ExpressionType.DOUBLE, ExpressionType.LONG) + ); + Assert.assertEquals( + ExpressionType.LONG, + ExpressionTypeConversion.integerMathFunction(ExpressionType.DOUBLE, ExpressionType.DOUBLE) + ); // any string makes become string - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.integerMathFunction(ExpressionType.LONG, ExpressionType.STRING)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.integerMathFunction(ExpressionType.STRING, ExpressionType.LONG)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.integerMathFunction(ExpressionType.DOUBLE, ExpressionType.STRING)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.integerMathFunction(ExpressionType.STRING, ExpressionType.DOUBLE)); - Assert.assertEquals(ExpressionType.STRING, ExpressionTypeConversion.integerMathFunction(ExpressionType.STRING, ExpressionType.STRING)); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.integerMathFunction(ExpressionType.LONG, ExpressionType.STRING) + ); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.integerMathFunction(ExpressionType.STRING, ExpressionType.LONG) + ); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.integerMathFunction(ExpressionType.DOUBLE, ExpressionType.STRING) + ); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.integerMathFunction(ExpressionType.STRING, ExpressionType.DOUBLE) + ); + Assert.assertEquals( + ExpressionType.STRING, + ExpressionTypeConversion.integerMathFunction(ExpressionType.STRING, ExpressionType.STRING) + ); // unless it is an array - Assert.assertEquals(ExpressionType.LONG_ARRAY, ExpressionTypeConversion.integerMathFunction(ExpressionType.LONG_ARRAY, ExpressionType.LONG_ARRAY)); + Assert.assertEquals( + ExpressionType.LONG_ARRAY, + ExpressionTypeConversion.integerMathFunction( + ExpressionType.LONG_ARRAY, + ExpressionType.LONG_ARRAY + ) + ); Assert.assertEquals( ExpressionType.DOUBLE_ARRAY, ExpressionTypeConversion.integerMathFunction(ExpressionType.DOUBLE_ARRAY, ExpressionType.DOUBLE_ARRAY) 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 e9eebc83d9f2..819b8cd32782 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 @@ -235,7 +235,7 @@ public void testSelectNonNumericNumberLiterals() throws Exception InlineDataSource.fromIterable( ImmutableList.of( new Object[]{Long.MAX_VALUE, Long.MAX_VALUE, Long.MIN_VALUE, Long.MIN_VALUE, 0L} - ), + ), RowSignature.builder() .add("EXPR$0", ColumnType.LONG) .add("EXPR$1", ColumnType.LONG) @@ -252,7 +252,7 @@ public void testSelectNonNumericNumberLiterals() throws Exception .build() ), ImmutableList.of( - new Object[] { + new Object[]{ Long.MAX_VALUE, Long.MAX_VALUE, Long.MIN_VALUE, @@ -288,7 +288,8 @@ public void testSelectConstantExpressionFromTable() throws Exception @Test public void testSelectConstantExpressionEquivalentToNaN() throws Exception { - expectedException.expectMessage("'(log10(0) - log10(0))' evaluates to 'NaN' that is not supported in SQL. You can either cast the expression as bigint ('cast((log10(0) - log10(0)) as bigint)') or char ('cast((log10(0) - log10(0)) as char)') or change the expression itself"); + expectedException.expectMessage( + "'(log10(0) - log10(0))' evaluates to 'NaN' that is not supported in SQL. You can either cast the expression as bigint ('cast((log10(0) - log10(0)) as bigint)') or char ('cast((log10(0) - log10(0)) as char)') or change the expression itself"); testQuery( "SELECT log10(0) - log10(0), dim1 FROM foo LIMIT 1", ImmutableList.of(), @@ -299,7 +300,8 @@ public void testSelectConstantExpressionEquivalentToNaN() throws Exception @Test public void testSelectConstantExpressionEquivalentToInfinity() throws Exception { - expectedException.expectMessage("'log10(0)' evaluates to '-Infinity' that is not supported in SQL. You can either cast the expression as bigint ('cast(log10(0) as bigint)') or char ('cast(log10(0) as char)') or change the expression itself"); + expectedException.expectMessage( + "'log10(0)' evaluates to '-Infinity' that is not supported in SQL. You can either cast the expression as bigint ('cast(log10(0) as bigint)') or char ('cast(log10(0) as char)') or change the expression itself"); testQuery( "SELECT log10(0), dim1 FROM foo LIMIT 1", ImmutableList.of(), @@ -447,8 +449,8 @@ public void testJoinOuterGroupByAndSubqueryHasLimit() throws Exception .setAggregatorSpecs( useDefault ? aggregators( - new DoubleSumAggregatorFactory("a0:sum", "m2"), - new CountAggregatorFactory("a0:count") + new DoubleSumAggregatorFactory("a0:sum", "m2"), + new CountAggregatorFactory("a0:count") ) : aggregators( new DoubleSumAggregatorFactory("a0:sum", "m2"), @@ -586,13 +588,13 @@ public void testJoinWithLimitBeforeJoining() throws Exception .setDataSource( join( new QueryDataSource( - newScanQueryBuilder() - .dataSource(CalciteTests.DATASOURCE1) - .intervals(querySegmentSpec(Filtration.eternity())) - .columns("dim2", "m1", "m2") - .context(QUERY_CONTEXT_DEFAULT) - .limit(10) - .build() + newScanQueryBuilder() + .dataSource(CalciteTests.DATASOURCE1) + .intervals(querySegmentSpec(Filtration.eternity())) + .columns("dim2", "m1", "m2") + .context(QUERY_CONTEXT_DEFAULT) + .limit(10) + .build() ), new QueryDataSource( newScanQueryBuilder() @@ -734,7 +736,8 @@ public void testJoinOnGroupByInsteadOfTimeseriesWithFloorOnTime() throws Excepti new QueryDataSource( GroupByQuery.builder() .setDataSource(CalciteTests.DATASOURCE1) - .setInterval(querySegmentSpec(Intervals.of("1994-04-29/2020-01-11T00:00:00.001Z"))) + .setInterval(querySegmentSpec(Intervals.of( + "1994-04-29/2020-01-11T00:00:00.001Z"))) .setVirtualColumns( expressionVirtualColumn( "v0", @@ -744,7 +747,11 @@ public void testJoinOnGroupByInsteadOfTimeseriesWithFloorOnTime() throws Excepti ) .setDimFilter(selector("dim3", "b", null)) .setGranularity(Granularities.ALL) - .setDimensions(dimensions(new DefaultDimensionSpec("v0", "d0", ColumnType.LONG))) + .setDimensions(dimensions(new DefaultDimensionSpec( + "v0", + "d0", + ColumnType.LONG + ))) .setAggregatorSpecs(aggregators( new FloatMinAggregatorFactory("a0", "m1") )) @@ -1014,21 +1021,21 @@ public void testSafeDivideExpressions() throws Exception List expected; if (useDefault) { expected = ImmutableList.of( - new Object[]{0.0F,0L,0.0,7.0F}, - new Object[]{1.0F,1L,1.0,3253230.0F}, - new Object[]{0.0F,0L,0.0,0.0F}, - new Object[]{0.0F,0L,0.0,0.0F}, - new Object[]{0.0F,0L,0.0,0.0F}, - new Object[]{0.0F,0L,0.0,0.0F} + new Object[]{0.0F, 0L, 0.0, 7.0F}, + new Object[]{1.0F, 1L, 1.0, 3253230.0F}, + new Object[]{0.0F, 0L, 0.0, 0.0F}, + new Object[]{0.0F, 0L, 0.0, 0.0F}, + new Object[]{0.0F, 0L, 0.0, 0.0F}, + new Object[]{0.0F, 0L, 0.0, 0.0F} ); } else { expected = ImmutableList.of( - new Object[]{null,null,null,7.0F}, - new Object[]{1.0F,1L,1.0,3253230.0F}, - new Object[]{0.0F,0L,0,0.0F}, - new Object[]{null,null,null,null}, - new Object[]{null,null,null,null}, - new Object[]{null,null,null,null} + new Object[]{null, null, null, 7.0F}, + new Object[]{1.0F, 1L, 1.0, 3253230.0F}, + new Object[]{0.0F, 0L, 0, 0.0F}, + new Object[]{null, null, null, null}, + new Object[]{null, null, null, null}, + new Object[]{null, null, null, null} ); } testQuery( @@ -1042,7 +1049,7 @@ public void testSafeDivideExpressions() throws Exception Druids.newScanQueryBuilder() .dataSource(CalciteTests.DATASOURCE3) .intervals(querySegmentSpec(Filtration.eternity())) - .columns("v0","v1","v2","v3") + .columns("v0", "v1", "v2", "v3") .virtualColumns( expressionVirtualColumn("v0", "safe_divide(\"f1\",\"f2\")", ColumnType.FLOAT), expressionVirtualColumn("v1", "safe_divide(\"l1\",\"l2\")", ColumnType.LONG), @@ -1068,7 +1075,10 @@ public void testExplainSelectConstantExpression() throws Exception "EXPLAIN PLAN FOR SELECT 1 + 1", ImmutableList.of(), ImmutableList.of( - new Object[]{"DruidQueryRel(query=[{\"queryType\":\"scan\",\"dataSource\":{\"type\":\"inline\",\"columnNames\":[\"EXPR$0\"],\"columnTypes\":[\"LONG\"],\"rows\":[[2]]},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"resultFormat\":\"compactedList\",\"batchSize\":20480,\"order\":\"none\",\"filter\":null,\"columns\":[\"EXPR$0\"],\"legacy\":false,\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\",\"sqlQueryId\":\"dummy\",\"vectorize\":\"false\",\"vectorizeVirtualColumns\":\"false\"},\"descending\":false,\"granularity\":{\"type\":\"all\"}}], signature=[{EXPR$0:LONG}])\n", "[]"} + new Object[]{ + "DruidQueryRel(query=[{\"queryType\":\"scan\",\"dataSource\":{\"type\":\"inline\",\"columnNames\":[\"EXPR$0\"],\"columnTypes\":[\"LONG\"],\"rows\":[[2]]},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"resultFormat\":\"compactedList\",\"batchSize\":20480,\"order\":\"none\",\"filter\":null,\"columns\":[\"EXPR$0\"],\"legacy\":false,\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\",\"sqlQueryId\":\"dummy\",\"vectorize\":\"false\",\"vectorizeVirtualColumns\":\"false\"},\"descending\":false,\"granularity\":{\"type\":\"all\"}}], signature=[{EXPR$0:LONG}])\n", + "[]" + } ) ); } @@ -1098,31 +1108,31 @@ public void testInformationSchemaTables() throws Exception + "WHERE TABLE_TYPE IN ('SYSTEM_TABLE', 'TABLE', 'VIEW')", ImmutableList.of(), ImmutableList.builder() - .add(new Object[]{"druid", CalciteTests.BROADCAST_DATASOURCE, "TABLE", "YES", "YES"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE1, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE2, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE4, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE5, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE3, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.SOME_DATASOURCE, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.SOMEXDATASOURCE, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.USERVISITDATASOURCE, "TABLE", "NO", "NO"}) - .add(new Object[]{"INFORMATION_SCHEMA", "COLUMNS", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"INFORMATION_SCHEMA", "SCHEMATA", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"INFORMATION_SCHEMA", "TABLES", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"lookup", "lookyloo", "TABLE", "YES", "YES"}) - .add(new Object[]{"sys", "segments", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"sys", "server_segments", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"sys", "servers", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"sys", "supervisors", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"sys", "tasks", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"view", "aview", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "bview", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "cview", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "dview", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "invalidView", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "restrictedView", "VIEW", "NO", "NO"}) - .build() + .add(new Object[]{"druid", CalciteTests.BROADCAST_DATASOURCE, "TABLE", "YES", "YES"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE1, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE2, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE4, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE5, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE3, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.SOME_DATASOURCE, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.SOMEXDATASOURCE, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.USERVISITDATASOURCE, "TABLE", "NO", "NO"}) + .add(new Object[]{"INFORMATION_SCHEMA", "COLUMNS", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"INFORMATION_SCHEMA", "SCHEMATA", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"INFORMATION_SCHEMA", "TABLES", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"lookup", "lookyloo", "TABLE", "YES", "YES"}) + .add(new Object[]{"sys", "segments", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"sys", "server_segments", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"sys", "servers", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"sys", "supervisors", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"sys", "tasks", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"view", "aview", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "bview", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "cview", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "dview", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "invalidView", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "restrictedView", "VIEW", "NO", "NO"}) + .build() ); testQuery( @@ -1133,33 +1143,33 @@ public void testInformationSchemaTables() throws Exception CalciteTests.SUPER_USER_AUTH_RESULT, ImmutableList.of(), ImmutableList.builder() - .add(new Object[]{"druid", CalciteTests.BROADCAST_DATASOURCE, "TABLE", "YES", "YES"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE1, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE2, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE4, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.FORBIDDEN_DATASOURCE, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE5, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.DATASOURCE3, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.SOME_DATASOURCE, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.SOMEXDATASOURCE, "TABLE", "NO", "NO"}) - .add(new Object[]{"druid", CalciteTests.USERVISITDATASOURCE, "TABLE", "NO", "NO"}) - .add(new Object[]{"INFORMATION_SCHEMA", "COLUMNS", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"INFORMATION_SCHEMA", "SCHEMATA", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"INFORMATION_SCHEMA", "TABLES", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"lookup", "lookyloo", "TABLE", "YES", "YES"}) - .add(new Object[]{"sys", "segments", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"sys", "server_segments", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"sys", "servers", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"sys", "supervisors", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"sys", "tasks", "SYSTEM_TABLE", "NO", "NO"}) - .add(new Object[]{"view", "aview", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "bview", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "cview", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "dview", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "forbiddenView", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "invalidView", "VIEW", "NO", "NO"}) - .add(new Object[]{"view", "restrictedView", "VIEW", "NO", "NO"}) - .build() + .add(new Object[]{"druid", CalciteTests.BROADCAST_DATASOURCE, "TABLE", "YES", "YES"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE1, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE2, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE4, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.FORBIDDEN_DATASOURCE, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE5, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.DATASOURCE3, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.SOME_DATASOURCE, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.SOMEXDATASOURCE, "TABLE", "NO", "NO"}) + .add(new Object[]{"druid", CalciteTests.USERVISITDATASOURCE, "TABLE", "NO", "NO"}) + .add(new Object[]{"INFORMATION_SCHEMA", "COLUMNS", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"INFORMATION_SCHEMA", "SCHEMATA", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"INFORMATION_SCHEMA", "TABLES", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"lookup", "lookyloo", "TABLE", "YES", "YES"}) + .add(new Object[]{"sys", "segments", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"sys", "server_segments", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"sys", "servers", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"sys", "supervisors", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"sys", "tasks", "SYSTEM_TABLE", "NO", "NO"}) + .add(new Object[]{"view", "aview", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "bview", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "cview", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "dview", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "forbiddenView", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "invalidView", "VIEW", "NO", "NO"}) + .add(new Object[]{"view", "restrictedView", "VIEW", "NO", "NO"}) + .build() ); } @@ -1837,20 +1847,20 @@ public void testSelectLimitWrappingAgainAkaIDontReallyQuiteUnderstandCalciteQuer .intervals(querySegmentSpec(Intervals.of("1990-01-01T00:00:00.000Z/146140482-04-24T15:36:27.903Z"))) .columns( ImmutableList.builder() - .add("__time") - .add("count") - .add("dimHyperUnique") - .add("dimMultivalEnumerated") - .add("dimMultivalEnumerated2") - .add("dimMultivalSequentialWithNulls") - .add("dimSequential") - .add("dimSequentialHalfNull") - .add("dimUniform") - .add("dimZipf") - .add("metFloatNormal") - .add("metFloatZipf") - .add("metLongSequential") - .build() + .add("__time") + .add("count") + .add("dimHyperUnique") + .add("dimMultivalEnumerated") + .add("dimMultivalEnumerated2") + .add("dimMultivalSequentialWithNulls") + .add("dimSequential") + .add("dimSequentialHalfNull") + .add("dimUniform") + .add("dimZipf") + .add("metFloatNormal") + .add("metFloatZipf") + .add("metLongSequential") + .build() ) .limit(2) .order(ScanQuery.Order.DESCENDING) @@ -1905,21 +1915,21 @@ public void testSelectLimitWrappingAgainAkaIDontReallyQuiteUnderstandCalciteQuer .intervals(querySegmentSpec(Intervals.of("1990-01-01T00:00:00.000Z/146140482-04-24T15:36:27.903Z"))) .columns( ImmutableList.builder() - .add("__time") - .add("count") - .add("dimHyperUnique") - .add("dimMultivalEnumerated") - .add("dimMultivalEnumerated2") - .add("dimMultivalSequentialWithNulls") - .add("dimSequential") - .add("dimSequentialHalfNull") - .add("dimUniform") - .add("dimZipf") - .add("metFloatNormal") - .add("metFloatZipf") - .add("metLongSequential") - .add("metLongUniform") - .build() + .add("__time") + .add("count") + .add("dimHyperUnique") + .add("dimMultivalEnumerated") + .add("dimMultivalEnumerated2") + .add("dimMultivalSequentialWithNulls") + .add("dimSequential") + .add("dimSequentialHalfNull") + .add("dimUniform") + .add("dimZipf") + .add("metFloatNormal") + .add("metFloatZipf") + .add("metLongSequential") + .add("metLongUniform") + .build() ) .limit(2) .order(ScanQuery.Order.DESCENDING) @@ -2401,7 +2411,9 @@ public void testAnyAggregator() throws Exception .context(QUERY_CONTEXT_DEFAULT) .build() ), - NullHandling.sqlCompatible() ? ImmutableList.of(new Object[]{1L, 1.0f, 1.0, "", 2L, 2.0f, "1"}) : ImmutableList.of(new Object[]{1L, 1.0f, 1.0, "", 2L, 2.0f, "1"}) + NullHandling.sqlCompatible() + ? ImmutableList.of(new Object[]{1L, 1.0f, 1.0, "", 2L, 2.0f, "1"}) + : ImmutableList.of(new Object[]{1L, 1.0f, 1.0, "", 2L, 2.0f, "1"}) ); } @@ -2442,19 +2454,19 @@ public void testAnyAggregatorsOffHeapNumericNulls() throws Exception "SELECT ANY_VALUE(l1), ANY_VALUE(d1), ANY_VALUE(f1) FROM druid.numfoo GROUP BY dim2", ImmutableList.of( GroupByQuery.builder() - .setDataSource(CalciteTests.DATASOURCE3) - .setInterval(querySegmentSpec(Filtration.eternity())) - .setGranularity(Granularities.ALL) - .setDimensions(dimensions(new DefaultDimensionSpec("dim2", "_d0"))) - .setAggregatorSpecs( - aggregators( - new LongAnyAggregatorFactory("a0", "l1"), - new DoubleAnyAggregatorFactory("a1", "d1"), - new FloatAnyAggregatorFactory("a2", "f1") - ) - ) - .setContext(QUERY_CONTEXT_DEFAULT) - .build() + .setDataSource(CalciteTests.DATASOURCE3) + .setInterval(querySegmentSpec(Filtration.eternity())) + .setGranularity(Granularities.ALL) + .setDimensions(dimensions(new DefaultDimensionSpec("dim2", "_d0"))) + .setAggregatorSpecs( + aggregators( + new LongAnyAggregatorFactory("a0", "l1"), + new DoubleAnyAggregatorFactory("a1", "d1"), + new FloatAnyAggregatorFactory("a2", "f1") + ) + ) + .setContext(QUERY_CONTEXT_DEFAULT) + .build() ), NullHandling.sqlCompatible() @@ -2490,9 +2502,10 @@ public void testPrimitiveLatestInSubquery() throws Exception .setGranularity(Granularities.ALL) .setDimensions(dimensions(new DefaultDimensionSpec("dim2", "d0"))) .setAggregatorSpecs(aggregators( - new FloatLastAggregatorFactory("a0:a", "m1"), - new LongLastAggregatorFactory("a1:a", "cnt"), - new DoubleLastAggregatorFactory("a2:a", "m2")) + new FloatLastAggregatorFactory("a0:a", "m1"), + new LongLastAggregatorFactory("a1:a", "cnt"), + new DoubleLastAggregatorFactory("a2:a", "m2") + ) ) .setPostAggregatorSpecs( ImmutableList.of( @@ -2508,15 +2521,17 @@ public void testPrimitiveLatestInSubquery() throws Exception .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) .setAggregatorSpecs(aggregators( - new DoubleSumAggregatorFactory("_a0", "a0"), - new LongSumAggregatorFactory("_a1", "a1"), - new DoubleSumAggregatorFactory("_a2", "a2") + new DoubleSumAggregatorFactory("_a0", "a0"), + new LongSumAggregatorFactory("_a1", "a1"), + new DoubleSumAggregatorFactory("_a2", "a2") ) ) .setContext(QUERY_CONTEXT_DEFAULT) .build() ), - NullHandling.sqlCompatible() ? ImmutableList.of(new Object[]{18.0, 4L, 18.0}) : ImmutableList.of(new Object[]{15.0, 3L, 15.0}) + NullHandling.sqlCompatible() + ? ImmutableList.of(new Object[]{18.0, 4L, 18.0}) + : ImmutableList.of(new Object[]{15.0, 3L, 15.0}) ); } @@ -2538,9 +2553,10 @@ public void testPrimitiveEarliestInSubquery() throws Exception .setGranularity(Granularities.ALL) .setDimensions(dimensions(new DefaultDimensionSpec("dim2", "d0"))) .setAggregatorSpecs(aggregators( - new FloatFirstAggregatorFactory("a0:a", "m1"), - new LongFirstAggregatorFactory("a1:a", "cnt"), - new DoubleFirstAggregatorFactory("a2:a", "m2")) + new FloatFirstAggregatorFactory("a0:a", "m1"), + new LongFirstAggregatorFactory("a1:a", "cnt"), + new DoubleFirstAggregatorFactory("a2:a", "m2") + ) ) .setPostAggregatorSpecs( ImmutableList.of( @@ -2556,15 +2572,17 @@ public void testPrimitiveEarliestInSubquery() throws Exception .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) .setAggregatorSpecs(aggregators( - new DoubleSumAggregatorFactory("_a0", "a0"), - new LongSumAggregatorFactory("_a1", "a1"), - new DoubleSumAggregatorFactory("_a2", "a2") + new DoubleSumAggregatorFactory("_a0", "a0"), + new LongSumAggregatorFactory("_a1", "a1"), + new DoubleSumAggregatorFactory("_a2", "a2") ) ) .setContext(QUERY_CONTEXT_DEFAULT) .build() ), - NullHandling.sqlCompatible() ? ImmutableList.of(new Object[]{11.0, 4L, 11.0}) : ImmutableList.of(new Object[]{8.0, 3L, 8.0}) + NullHandling.sqlCompatible() + ? ImmutableList.of(new Object[]{11.0, 4L, 11.0}) + : ImmutableList.of(new Object[]{8.0, 3L, 8.0}) ); } @@ -2585,7 +2603,11 @@ public void testStringLatestInSubquery() throws Exception .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) .setDimensions(dimensions(new DefaultDimensionSpec("dim2", "d0"))) - .setAggregatorSpecs(aggregators(new StringLastAggregatorFactory("a0:a", "dim1", 10))) + .setAggregatorSpecs(aggregators(new StringLastAggregatorFactory( + "a0:a", + "dim1", + 10 + ))) .setPostAggregatorSpecs( ImmutableList.of( new FinalizingFieldAccessPostAggregator("a0", "a0:a") @@ -2596,7 +2618,12 @@ public void testStringLatestInSubquery() throws Exception ) .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) - .setAggregatorSpecs(aggregators(new DoubleSumAggregatorFactory("_a0", null, "CAST(\"a0\", 'DOUBLE')", ExprMacroTable.nil()))) + .setAggregatorSpecs(aggregators(new DoubleSumAggregatorFactory( + "_a0", + null, + "CAST(\"a0\", 'DOUBLE')", + ExprMacroTable.nil() + ))) .setContext(QUERY_CONTEXT_DEFAULT) .build() ), @@ -2623,7 +2650,11 @@ public void testStringEarliestInSubquery() throws Exception .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) .setDimensions(dimensions(new DefaultDimensionSpec("dim2", "d0"))) - .setAggregatorSpecs(aggregators(new StringFirstAggregatorFactory("a0:a", "dim1", 10))) + .setAggregatorSpecs(aggregators(new StringFirstAggregatorFactory( + "a0:a", + "dim1", + 10 + ))) .setPostAggregatorSpecs( ImmutableList.of( new FinalizingFieldAccessPostAggregator("a0", "a0:a") @@ -2634,7 +2665,12 @@ public void testStringEarliestInSubquery() throws Exception ) .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) - .setAggregatorSpecs(aggregators(new DoubleSumAggregatorFactory("_a0", null, "CAST(\"a0\", 'DOUBLE')", ExprMacroTable.nil()))) + .setAggregatorSpecs(aggregators(new DoubleSumAggregatorFactory( + "_a0", + null, + "CAST(\"a0\", 'DOUBLE')", + ExprMacroTable.nil() + ))) .setContext(QUERY_CONTEXT_DEFAULT) .build() ), @@ -2674,9 +2710,10 @@ public void testPrimitiveAnyInSubquery() throws Exception .setGranularity(Granularities.ALL) .setDimensions(dimensions(new DefaultDimensionSpec("dim2", "d0"))) .setAggregatorSpecs(aggregators( - new FloatAnyAggregatorFactory("a0:a", "m1"), - new LongAnyAggregatorFactory("a1:a", "cnt"), - new DoubleAnyAggregatorFactory("a2:a", "m2")) + new FloatAnyAggregatorFactory("a0:a", "m1"), + new LongAnyAggregatorFactory("a1:a", "cnt"), + new DoubleAnyAggregatorFactory("a2:a", "m2") + ) ) .setPostAggregatorSpecs( ImmutableList.of( @@ -2692,15 +2729,17 @@ public void testPrimitiveAnyInSubquery() throws Exception .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) .setAggregatorSpecs(aggregators( - new DoubleSumAggregatorFactory("_a0", "a0"), - new LongSumAggregatorFactory("_a1", "a1"), - new DoubleSumAggregatorFactory("_a2", "a2") - ) + new DoubleSumAggregatorFactory("_a0", "a0"), + new LongSumAggregatorFactory("_a1", "a1"), + new DoubleSumAggregatorFactory("_a2", "a2") + ) ) .setContext(QUERY_CONTEXT_DEFAULT) .build() ), - NullHandling.sqlCompatible() ? ImmutableList.of(new Object[]{11.0, 4L, 11.0}) : ImmutableList.of(new Object[]{8.0, 3L, 8.0}) + NullHandling.sqlCompatible() + ? ImmutableList.of(new Object[]{11.0, 4L, 11.0}) + : ImmutableList.of(new Object[]{8.0, 3L, 8.0}) ); } @@ -2718,7 +2757,11 @@ public void testStringAnyInSubquery() throws Exception .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) .setDimensions(dimensions(new DefaultDimensionSpec("dim2", "d0"))) - .setAggregatorSpecs(aggregators(new StringAnyAggregatorFactory("a0:a", "dim1", 10))) + .setAggregatorSpecs(aggregators(new StringAnyAggregatorFactory( + "a0:a", + "dim1", + 10 + ))) .setPostAggregatorSpecs( ImmutableList.of( new FinalizingFieldAccessPostAggregator("a0", "a0:a") @@ -2729,7 +2772,12 @@ public void testStringAnyInSubquery() throws Exception ) .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) - .setAggregatorSpecs(aggregators(new DoubleSumAggregatorFactory("_a0", null, "CAST(\"a0\", 'DOUBLE')", ExprMacroTable.nil()))) + .setAggregatorSpecs(aggregators(new DoubleSumAggregatorFactory( + "_a0", + null, + "CAST(\"a0\", 'DOUBLE')", + ExprMacroTable.nil() + ))) .setContext(QUERY_CONTEXT_DEFAULT) .build() ), @@ -2792,7 +2840,11 @@ public void testLatestAggregatorsNumericNull() throws Exception .build() ), ImmutableList.of( - new Object[]{NullHandling.defaultLongValue(), NullHandling.defaultDoubleValue(), NullHandling.defaultFloatValue()} + new Object[]{ + NullHandling.defaultLongValue(), + NullHandling.defaultDoubleValue(), + NullHandling.defaultFloatValue() + } ) ); } @@ -2958,19 +3010,19 @@ public void testOrderByEarliestFloat() throws Exception "SELECT dim1, EARLIEST(f1) FROM druid.numfoo GROUP BY 1 ORDER BY 2 LIMIT 10", ImmutableList.of( new TopNQueryBuilder() - .dataSource(CalciteTests.DATASOURCE3) - .intervals(querySegmentSpec(Filtration.eternity())) - .granularity(Granularities.ALL) - .dimension(new DefaultDimensionSpec("dim1", "_d0")) - .aggregators( - aggregators( - new FloatFirstAggregatorFactory("a0", "f1") - ) - ) - .metric(new InvertedTopNMetricSpec(new NumericTopNMetricSpec("a0"))) - .threshold(10) - .context(QUERY_CONTEXT_DEFAULT) - .build() + .dataSource(CalciteTests.DATASOURCE3) + .intervals(querySegmentSpec(Filtration.eternity())) + .granularity(Granularities.ALL) + .dimension(new DefaultDimensionSpec("dim1", "_d0")) + .aggregators( + aggregators( + new FloatFirstAggregatorFactory("a0", "f1") + ) + ) + .metric(new InvertedTopNMetricSpec(new NumericTopNMetricSpec("a0"))) + .threshold(10) + .context(QUERY_CONTEXT_DEFAULT) + .build() ), expected ); @@ -4552,12 +4604,12 @@ public void testUnionAllTwoQueriesLeftQueryIsJoin(Map queryConte Druids.newTimeseriesQueryBuilder() .dataSource( join( - new TableDataSource(CalciteTests.DATASOURCE1), - new LookupDataSource("lookyloo"), - "j0.", - equalsCondition(DruidExpression.fromColumn("dim1"), DruidExpression.fromColumn("j0.k")), - JoinType.INNER - )) + new TableDataSource(CalciteTests.DATASOURCE1), + new LookupDataSource("lookyloo"), + "j0.", + equalsCondition(DruidExpression.fromColumn("dim1"), DruidExpression.fromColumn("j0.k")), + JoinType.INNER + )) .intervals(querySegmentSpec(Filtration.eternity())) .granularity(Granularities.ALL) .aggregators(aggregators(new CountAggregatorFactory("a0"))) @@ -5110,35 +5162,39 @@ public void testNullLongTopN() throws Exception public void testLongPredicateIsNull() throws Exception { testQuery( - "SELECT l1 is null FROM druid.numfoo", - ImmutableList.of( + "SELECT l1 is null FROM druid.numfoo", + ImmutableList.of( newScanQueryBuilder() - .dataSource(CalciteTests.DATASOURCE3) - .intervals(querySegmentSpec(Filtration.eternity())) - .columns("v0") - .virtualColumns( - expressionVirtualColumn("v0", NullHandling.replaceWithDefault() ? "0" : "isnull(\"l1\")", ColumnType.LONG) - ) - .context(QUERY_CONTEXT_DEFAULT) - .build() - ), - NullHandling.replaceWithDefault() ? - ImmutableList.of( - new Object[]{false}, - new Object[]{false}, - new Object[]{false}, - new Object[]{false}, - new Object[]{false}, - new Object[]{false} - ) : - ImmutableList.of( - new Object[]{false}, - new Object[]{false}, - new Object[]{false}, - new Object[]{true}, - new Object[]{true}, - new Object[]{true} - ) + .dataSource(CalciteTests.DATASOURCE3) + .intervals(querySegmentSpec(Filtration.eternity())) + .columns("v0") + .virtualColumns( + expressionVirtualColumn( + "v0", + NullHandling.replaceWithDefault() ? "0" : "isnull(\"l1\")", + ColumnType.LONG + ) + ) + .context(QUERY_CONTEXT_DEFAULT) + .build() + ), + NullHandling.replaceWithDefault() ? + ImmutableList.of( + new Object[]{false}, + new Object[]{false}, + new Object[]{false}, + new Object[]{false}, + new Object[]{false}, + new Object[]{false} + ) : + ImmutableList.of( + new Object[]{false}, + new Object[]{false}, + new Object[]{false}, + new Object[]{true}, + new Object[]{true}, + new Object[]{true} + ) ); } @@ -5935,31 +5991,31 @@ public void testViewAndJoin() throws Exception Druids.newTimeseriesQueryBuilder() .dataSource( join( - join( - new TableDataSource(CalciteTests.DATASOURCE1), - new QueryDataSource( - newScanQueryBuilder().dataSource(CalciteTests.DATASOURCE3) - .intervals(querySegmentSpec(Filtration.eternity())) - .columns("dim2") - .context(queryContext) - .build() - ), - "j0.", - "(\"dim2\" == \"j0.dim2\")", - JoinType.INNER, - bound("dim2", "a", "a", false, false, null, null) - ), - new QueryDataSource( - newScanQueryBuilder().dataSource(CalciteTests.DATASOURCE1) - .intervals(querySegmentSpec(Filtration.eternity())) - .columns("dim2") - .context(queryContext) - .build() - ), - "_j0.", - "('a' == \"_j0.dim2\")", - JoinType.INNER - ) + join( + new TableDataSource(CalciteTests.DATASOURCE1), + new QueryDataSource( + newScanQueryBuilder().dataSource(CalciteTests.DATASOURCE3) + .intervals(querySegmentSpec(Filtration.eternity())) + .columns("dim2") + .context(queryContext) + .build() + ), + "j0.", + "(\"dim2\" == \"j0.dim2\")", + JoinType.INNER, + bound("dim2", "a", "a", false, false, null, null) + ), + new QueryDataSource( + newScanQueryBuilder().dataSource(CalciteTests.DATASOURCE1) + .intervals(querySegmentSpec(Filtration.eternity())) + .columns("dim2") + .context(queryContext) + .build() + ), + "_j0.", + "('a' == \"_j0.dim2\")", + JoinType.INNER + ) ) .intervals(querySegmentSpec(Filtration.eternity())) .filters(not(selector("dim1", "z", new SubstringDimExtractionFn(0, 1)))) @@ -6204,16 +6260,16 @@ public void testSimpleLongAggregations() throws Exception "SELECT MIN(l1), MIN(cnt), MAX(l1) FROM druid.numfoo", ImmutableList.of( Druids.newTimeseriesQueryBuilder() - .dataSource(CalciteTests.DATASOURCE3) - .intervals(querySegmentSpec(Filtration.eternity())) - .granularity(Granularities.ALL) - .aggregators(aggregators( - new LongMinAggregatorFactory("a0", "l1"), - new LongMinAggregatorFactory("a1", "cnt"), - new LongMaxAggregatorFactory("a2", "l1") - )) - .context(QUERY_CONTEXT_DEFAULT) - .build() + .dataSource(CalciteTests.DATASOURCE3) + .intervals(querySegmentSpec(Filtration.eternity())) + .granularity(Granularities.ALL) + .aggregators(aggregators( + new LongMinAggregatorFactory("a0", "l1"), + new LongMinAggregatorFactory("a1", "cnt"), + new LongMaxAggregatorFactory("a2", "l1") + )) + .context(QUERY_CONTEXT_DEFAULT) + .build() ), ImmutableList.of( new Object[]{0L, 1L, 325323L} @@ -8122,7 +8178,10 @@ public void testMultipleExactCountDistinctWithGroupingAndOtherAggregators() thro { requireMergeBuffers(4); testQuery( - PLANNER_CONFIG_NO_HLL.withOverrides(ImmutableMap.of(PlannerConfig.CTX_KEY_USE_GROUPING_SET_FOR_EXACT_DISTINCT, "true")), + PLANNER_CONFIG_NO_HLL.withOverrides(ImmutableMap.of( + PlannerConfig.CTX_KEY_USE_GROUPING_SET_FOR_EXACT_DISTINCT, + "true" + )), "SELECT FLOOR(__time to day), COUNT(distinct city), COUNT(distinct user) FROM druid.visits GROUP BY 1", CalciteTests.REGULAR_USER_AUTH_RESULT, ImmutableList.of( @@ -8599,12 +8658,12 @@ public void testMinMaxAvgDailyCountWithLimit() throws Exception .setAggregatorSpecs( useDefault ? aggregators( - new LongMaxAggregatorFactory("_a0", "a0"), - new LongMinAggregatorFactory("_a1", "a0"), - new LongSumAggregatorFactory("_a2:sum", "a0"), - new CountAggregatorFactory("_a2:count"), - new LongMaxAggregatorFactory("_a3", "d0"), - new CountAggregatorFactory("_a4") + new LongMaxAggregatorFactory("_a0", "a0"), + new LongMinAggregatorFactory("_a1", "a0"), + new LongSumAggregatorFactory("_a2:sum", "a0"), + new CountAggregatorFactory("_a2:count"), + new LongMaxAggregatorFactory("_a3", "d0"), + new CountAggregatorFactory("_a4") ) : aggregators( new LongMaxAggregatorFactory("_a0", "a0"), @@ -8683,8 +8742,8 @@ public void testAvgDailyCountDistinct() throws Exception .setAggregatorSpecs( useDefault ? aggregators( - new LongSumAggregatorFactory("_a0:sum", "a0"), - new CountAggregatorFactory("_a0:count") + new LongSumAggregatorFactory("_a0:sum", "a0"), + new CountAggregatorFactory("_a0:count") ) : aggregators( new LongSumAggregatorFactory("_a0:sum", "a0"), @@ -10376,7 +10435,8 @@ public void testFilterAndGroupByLookup() throws Exception @Test @Parameters(source = QueryContextForJoinProvider.class) - public void testFilterAndGroupByLookupUsingJoinOperatorWithValueFilterPushdownMatchesNothig(Map queryContext) throws Exception + public void testFilterAndGroupByLookupUsingJoinOperatorWithValueFilterPushdownMatchesNothig(Map queryContext) + throws Exception { // Cannot vectorize JOIN operator. cannotVectorize(); @@ -10499,7 +10559,8 @@ public void testFilterAndGroupByLookupUsingJoinOperatorBackwards(Map queryContext) throws Exception + public void testFilterAndGroupByLookupUsingJoinOperatorWithNotFilter(Map queryContext) + throws Exception { // Cannot vectorize JOIN operator. cannotVectorize(); @@ -10622,7 +10683,8 @@ public void testFilterAndGroupByLookupUsingJoinOperator(Map quer @Test @Parameters(source = QueryContextForJoinProvider.class) - public void testFilterAndGroupByLookupUsingPostAggregationJoinOperator(Map queryContext) throws Exception + public void testFilterAndGroupByLookupUsingPostAggregationJoinOperator(Map queryContext) + throws Exception { testQuery( "SELECT base.dim2, lookyloo.v, base.cnt FROM (\n" @@ -10867,7 +10929,8 @@ public void testInnerJoinTableLookupLookupWithFilterWithoutLimit(Map queryContext) throws Exception + public void testInnerJoinTableLookupLookupWithFilterWithOuterLimitWithAllColumns(Map queryContext) + throws Exception { testQuery( "SELECT __time, cnt, dim1, dim2, dim3, m1, m2, unique_dim1\n" @@ -10910,7 +10973,8 @@ public void testInnerJoinTableLookupLookupWithFilterWithOuterLimitWithAllColumns @Test @Parameters(source = QueryContextForJoinProvider.class) - public void testInnerJoinTableLookupLookupWithFilterWithoutLimitWithAllColumns(Map queryContext) throws Exception + public void testInnerJoinTableLookupLookupWithFilterWithoutLimitWithAllColumns(Map queryContext) + throws Exception { testQuery( "SELECT __time, cnt, dim1, dim2, dim3, m1, m2, unique_dim1\n" @@ -10999,100 +11063,169 @@ public void testManyManyInnerJoinOnManyManyLookup(Map queryConte join( join( join( - new TableDataSource(CalciteTests.DATASOURCE1), - new LookupDataSource("lookyloo"), + new TableDataSource( + CalciteTests.DATASOURCE1), + new LookupDataSource( + "lookyloo"), "j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("j0.k")), - JoinType.INNER + equalsCondition( + DruidExpression.fromColumn( + "dim2"), + DruidExpression.fromColumn( + "j0.k") ), - new LookupDataSource("lookyloo"), + JoinType.INNER + ), + new LookupDataSource( + "lookyloo"), "_j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("_j0.k")), + equalsCondition( + DruidExpression.fromColumn( + "dim2"), + DruidExpression.fromColumn( + "_j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "__j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("__j0.k")), + equalsCondition( + DruidExpression.fromColumn( + "dim2"), + DruidExpression.fromColumn( + "__j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "___j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("___j0.k")), + equalsCondition( + DruidExpression.fromColumn( + "dim2"), + DruidExpression.fromColumn( + "___j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "____j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("____j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn( + "____j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "_____j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("_____j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("_____j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "______j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("______j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("______j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "_______j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("_______j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("_______j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "_________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("_________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("_________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "__________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("__________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("__________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "___________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("___________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("___________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "____________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("____________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("____________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "_____________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("_____________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("_____________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "______________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("______________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("______________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "_______________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("_______________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("_______________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "________________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("________________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("________________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "_________________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("_________________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("_________________j0.k") + ), JoinType.INNER ), new LookupDataSource("lookyloo"), "__________________j0.", - equalsCondition(DruidExpression.fromColumn("dim2"), DruidExpression.fromColumn("__________________j0.k")), + equalsCondition( + DruidExpression.fromColumn("dim2"), + DruidExpression.fromColumn("__________________j0.k") + ), JoinType.INNER ) ) @@ -11262,7 +11395,8 @@ public void testInnerJoinTwoLookupsToTableUsingNumericColumn(Map @Test @Parameters(source = QueryContextForJoinProvider.class) - public void testInnerJoinTwoLookupsToTableUsingNumericColumnInReverse(Map queryContext) throws Exception + public void testInnerJoinTwoLookupsToTableUsingNumericColumnInReverse(Map queryContext) + throws Exception { // Like "testInnerJoinTwoLookupsToTableUsingNumericColumn", but the tables are specified backwards. @@ -12623,31 +12757,31 @@ public void testTimeseriesDontSkipEmptyBuckets() throws Exception .build() ), ImmutableList.builder() - .add(new Object[]{1L, timestamp("2000-01-01")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T01")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T02")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T03")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T04")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T05")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T06")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T07")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T08")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T09")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T10")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T11")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T12")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T13")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T14")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T15")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T16")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T17")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T18")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T19")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T20")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T21")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T22")}) - .add(new Object[]{defaultVal, timestamp("2000-01-01T23")}) - .build() + .add(new Object[]{1L, timestamp("2000-01-01")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T01")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T02")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T03")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T04")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T05")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T06")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T07")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T08")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T09")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T10")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T11")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T12")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T13")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T14")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T15")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T16")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T17")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T18")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T19")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T20")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T21")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T22")}) + .add(new Object[]{defaultVal, timestamp("2000-01-01T23")}) + .build() ); } @@ -12824,7 +12958,19 @@ public void testTimeseriesEmptyResultsAggregatorDefaultValues() throws Exception ), ImmutableList.of( useDefault - ? new Object[]{0L, 0L, 0L, 0.0, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 0L, Long.MIN_VALUE, Long.MAX_VALUE, 0L, Double.NaN} + ? new Object[]{ + 0L, + 0L, + 0L, + 0.0, + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, + 0L, + Long.MIN_VALUE, + Long.MAX_VALUE, + 0L, + Double.NaN + } : new Object[]{0L, 0L, 0L, null, null, null, null, null, null, null, null} ) ); @@ -12895,21 +13041,21 @@ public void testTimeseriesEmptyResultsAggregatorDefaultValuesNonVectorized() thr not(selector("dim3", null, null)) ), new FilteredAggregatorFactory( - new ExpressionLambdaAggregatorFactory( - "a8", - ImmutableSet.of("l1"), - "__acc", - "0", - "0", - NullHandling.sqlCompatible(), - "bitwiseAnd(\"__acc\", \"l1\")", - "bitwiseAnd(\"__acc\", \"a8\")", - null, - null, - ExpressionLambdaAggregatorFactory.DEFAULT_MAX_SIZE_BYTES, - TestExprMacroTable.INSTANCE - ), - not(selector("l1", null, null)) + new ExpressionLambdaAggregatorFactory( + "a8", + ImmutableSet.of("l1"), + "__acc", + "0", + "0", + NullHandling.sqlCompatible(), + "bitwiseAnd(\"__acc\", \"l1\")", + "bitwiseAnd(\"__acc\", \"a8\")", + null, + null, + ExpressionLambdaAggregatorFactory.DEFAULT_MAX_SIZE_BYTES, + TestExprMacroTable.INSTANCE + ), + not(selector("l1", null, null)) ), new FilteredAggregatorFactory( new ExpressionLambdaAggregatorFactory( @@ -12991,11 +13137,23 @@ public void testGroupByAggregatorDefaultValues() throws Exception selector("dim1", "nonexistent", null) ), new FilteredAggregatorFactory( - new CardinalityAggregatorFactory("a1", null, ImmutableList.of(DefaultDimensionSpec.of("dim1")), false, true), + new CardinalityAggregatorFactory( + "a1", + null, + ImmutableList.of(DefaultDimensionSpec.of("dim1")), + false, + true + ), selector("dim1", "nonexistent", null) ), new FilteredAggregatorFactory( - new CardinalityAggregatorFactory("a2", null, ImmutableList.of(DefaultDimensionSpec.of("dim1")), false, true), + new CardinalityAggregatorFactory( + "a2", + null, + ImmutableList.of(DefaultDimensionSpec.of("dim1")), + false, + true + ), selector("dim1", "nonexistent", null) ), new FilteredAggregatorFactory( @@ -13075,7 +13233,20 @@ public void testGroupByAggregatorDefaultValues() throws Exception ), ImmutableList.of( useDefault - ? new Object[]{"a", 0L, 0L, 0L, 0.0, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 0L, Long.MIN_VALUE, Long.MAX_VALUE, 0L, Double.NaN} + ? new Object[]{ + "a", + 0L, + 0L, + 0L, + 0.0, + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, + 0L, + Long.MIN_VALUE, + Long.MAX_VALUE, + 0L, + Double.NaN + } : new Object[]{"a", 0L, 0L, 0L, null, null, null, null, null, null, null, null} ) ); @@ -14612,7 +14783,8 @@ public void testNestedGroupByOnInlineDataSourceWithFilter(Map qu new QueryDataSource( newScanQueryBuilder() .dataSource(CalciteTests.DATASOURCE1) - .intervals(querySegmentSpec(Intervals.of("2001-01-02T00:00:00.000Z/146140482-04-24T15:36:27.903Z"))) + .intervals(querySegmentSpec(Intervals.of( + "2001-01-02T00:00:00.000Z/146140482-04-24T15:36:27.903Z"))) .columns("dim1") .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) .context(queryContext) @@ -14621,7 +14793,8 @@ public void testNestedGroupByOnInlineDataSourceWithFilter(Map qu new QueryDataSource( newScanQueryBuilder() .dataSource(CalciteTests.DATASOURCE1) - .intervals(querySegmentSpec(Intervals.of("2001-01-02T00:00:00.000Z/146140482-04-24T15:36:27.903Z"))) + .intervals(querySegmentSpec(Intervals.of( + "2001-01-02T00:00:00.000Z/146140482-04-24T15:36:27.903Z"))) .columns("dim1", "m2") .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) .context(queryContext) @@ -14651,7 +14824,7 @@ public void testNestedGroupByOnInlineDataSourceWithFilter(Map qu .setInterval(querySegmentSpec(Filtration.eternity())) .build() ), - ImmutableList.of(new Object[] {1L}) + ImmutableList.of(new Object[]{1L}) ); } @@ -14684,7 +14857,8 @@ public void testGroupByJoinAsNativeQueryWithUnoptimizedFilter(Map= \"_j0._a0\")")) + and( + selector("__j0.p0", null, null), + expressionFilter("(\"_j0._a1\" >= \"_j0._a0\")") + ) ) ) ) @@ -15709,8 +15887,8 @@ public void testSortProjectAfterNestedGroupBy() throws Exception .setInterval(querySegmentSpec(Filtration.eternity())) .setGranularity(Granularities.ALL) .setDimensions( - useDefault - ? dimensions( + useDefault + ? dimensions( new DefaultDimensionSpec("__time", "d0", ColumnType.LONG), new DefaultDimensionSpec("m2", "d1", ColumnType.DOUBLE), new DefaultDimensionSpec("dim1", "d2") @@ -15826,19 +16004,19 @@ public void testPostAggWithTopN() throws Exception .aggregators( useDefault ? aggregators( - new DoubleSumAggregatorFactory("a0:sum", "m2"), - new CountAggregatorFactory("a0:count"), - new DoubleSumAggregatorFactory("a1", "m1"), - new DoubleSumAggregatorFactory("a2", "m2") + new DoubleSumAggregatorFactory("a0:sum", "m2"), + new CountAggregatorFactory("a0:count"), + new DoubleSumAggregatorFactory("a1", "m1"), + new DoubleSumAggregatorFactory("a2", "m2") ) : aggregators( - new DoubleSumAggregatorFactory("a0:sum", "m2"), - new FilteredAggregatorFactory( - new CountAggregatorFactory("a0:count"), - not(selector("m2", null, null)) - ), - new DoubleSumAggregatorFactory("a1", "m1"), - new DoubleSumAggregatorFactory("a2", "m2") + new DoubleSumAggregatorFactory("a0:sum", "m2"), + new FilteredAggregatorFactory( + new CountAggregatorFactory("a0:count"), + not(selector("m2", null, null)) + ), + new DoubleSumAggregatorFactory("a1", "m1"), + new DoubleSumAggregatorFactory("a2", "m2") ) ) .postAggregators( @@ -16809,7 +16987,8 @@ public void testLeftJoinOnTwoInlineDataSourcesWithTimeFilter(Map @Test @Parameters(source = QueryContextForJoinProvider.class) - public void testLeftJoinOnTwoInlineDataSourcesWithTimeFilter_withLeftDirectAccess(Map queryContext) throws Exception + public void testLeftJoinOnTwoInlineDataSourcesWithTimeFilter_withLeftDirectAccess(Map queryContext) + throws Exception { queryContext = withLeftDirectAccessEnabled(queryContext); testQuery( @@ -16921,7 +17100,8 @@ public void testLeftJoinOnTwoInlineDataSourcesWithOuterWhere(Map @Test @Parameters(source = QueryContextForJoinProvider.class) - public void testLeftJoinOnTwoInlineDataSourcesWithOuterWhere_withLeftDirectAccess(Map queryContext) throws Exception + public void testLeftJoinOnTwoInlineDataSourcesWithOuterWhere_withLeftDirectAccess(Map queryContext) + throws Exception { queryContext = withLeftDirectAccessEnabled(queryContext); testQuery( @@ -16947,7 +17127,10 @@ public void testLeftJoinOnTwoInlineDataSourcesWithOuterWhere_withLeftDirectAcces .build() ), "j0.", - equalsCondition(DruidExpression.fromExpression("'10.1'"), DruidExpression.fromColumn("j0.dim1")), + equalsCondition( + DruidExpression.fromExpression("'10.1'"), + DruidExpression.fromColumn("j0.dim1") + ), JoinType.LEFT, selector("dim1", "10.1", null) ) @@ -17045,7 +17228,10 @@ public void testLeftJoinOnTwoInlineDataSources_withLeftDirectAccess(Map queryContext) throws Exception + public void testInnerJoinOnTwoInlineDataSourcesWithOuterWhere_withLeftDirectAccess(Map queryContext) + throws Exception { queryContext = withLeftDirectAccessEnabled(queryContext); testQuery( @@ -17144,7 +17331,10 @@ public void testInnerJoinOnTwoInlineDataSourcesWithOuterWhere_withLeftDirectAcce .build() ), "j0.", - equalsCondition(DruidExpression.fromExpression("'10.1'"), DruidExpression.fromColumn("j0.dim1")), + equalsCondition( + DruidExpression.fromExpression("'10.1'"), + DruidExpression.fromColumn("j0.dim1") + ), JoinType.INNER, selector("dim1", "10.1", null) ) @@ -17216,7 +17406,8 @@ public void testInnerJoinOnTwoInlineDataSources(Map queryContext @Test @Parameters(source = QueryContextForJoinProvider.class) - public void testInnerJoinOnTwoInlineDataSources_withLeftDirectAccess(Map queryContext) throws Exception + public void testInnerJoinOnTwoInlineDataSources_withLeftDirectAccess(Map queryContext) + throws Exception { queryContext = withLeftDirectAccessEnabled(queryContext); testQuery( @@ -17242,7 +17433,10 @@ public void testInnerJoinOnTwoInlineDataSources_withLeftDirectAccess(Map @Test @Parameters(source = QueryContextForJoinProvider.class) - public void testTopNOnStringWithNonSortedOrUniqueDictionaryOrderByDim(Map queryContext) throws Exception + public void testTopNOnStringWithNonSortedOrUniqueDictionaryOrderByDim(Map queryContext) + throws Exception { testQuery( "SELECT druid.broadcast.dim4, COUNT(*)\n" @@ -17461,7 +17656,11 @@ public void testTimeStampAddZeroMonthPeriod() throws Exception .dataSource(CalciteTests.DATASOURCE1) .intervals(querySegmentSpec(Filtration.eternity())) .virtualColumns( - expressionVirtualColumn("v0", "timestamp_shift(\"__time\",'P0M',1,'UTC')", ColumnType.LONG) + expressionVirtualColumn( + "v0", + "timestamp_shift(\"__time\",'P0M',1,'UTC')", + ColumnType.LONG + ) ) .columns("v0") .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) @@ -17488,7 +17687,11 @@ public void testTimeStampAddZeroYearPeriod() throws Exception .dataSource(CalciteTests.DATASOURCE1) .intervals(querySegmentSpec(Filtration.eternity())) .virtualColumns( - expressionVirtualColumn("v0", "timestamp_shift(\"__time\",'P0M',1,'UTC')", ColumnType.LONG) + expressionVirtualColumn( + "v0", + "timestamp_shift(\"__time\",'P0M',1,'UTC')", + ColumnType.LONG + ) ) .columns("v0") .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) @@ -17522,7 +17725,11 @@ public void testTimeStampAddConversion() throws Exception .dataSource(CalciteTests.DATASOURCE1) .intervals(querySegmentSpec(Filtration.eternity())) .virtualColumns( - expressionVirtualColumn("v0", "timestamp_shift(\"__time\",'P1M',1,'UTC')", ColumnType.LONG) + expressionVirtualColumn( + "v0", + "timestamp_shift(\"__time\",'P1M',1,'UTC')", + ColumnType.LONG + ) ) .columns("v0") .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) @@ -17546,7 +17753,11 @@ public void testTimeStampAddConversion() throws Exception .dataSource(CalciteTests.DATASOURCE1) .intervals(querySegmentSpec(Filtration.eternity())) .virtualColumns( - expressionVirtualColumn("v0", "timestamp_shift(\"__time\",concat('P', (1 * \"cnt\"), 'M'),1,'UTC')", ColumnType.LONG) + expressionVirtualColumn( + "v0", + "timestamp_shift(\"__time\",concat('P', (1 * \"cnt\"), 'M'),1,'UTC')", + ColumnType.LONG + ) ) .columns("v0") .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) @@ -17780,7 +17991,16 @@ public void testLeftJoinRightTableCanBeEmpty() throws Exception .dataSource(CalciteTests.DATASOURCE1) .intervals(querySegmentSpec(Filtration.eternity())) .resultFormat(ResultFormat.RESULT_FORMAT_COMPACTED_LIST) - .filters(new BoundDimFilter("m1", "2", null, true, false, null, null, StringComparators.NUMERIC)) + .filters(new BoundDimFilter( + "m1", + "2", + null, + true, + false, + null, + null, + StringComparators.NUMERIC + )) .columns("dim2") .legacy(false) .build() @@ -17998,27 +18218,30 @@ public void testJoinWithTimeDimension() throws Exception "SELECT count(*) FROM druid.foo t1 inner join druid.foo t2 on t1.__time = t2.__time", CalciteTests.REGULAR_USER_AUTH_RESULT, ImmutableList.of(Druids.newTimeseriesQueryBuilder() - .dataSource(JoinDataSource.create(new TableDataSource(CalciteTests.DATASOURCE1), - new QueryDataSource( - Druids.newScanQueryBuilder() - .dataSource(CalciteTests.DATASOURCE1) - .intervals(querySegmentSpec(Filtration.eternity())) - .resultFormat(ResultFormat.RESULT_FORMAT_COMPACTED_LIST) - .columns("__time") - .legacy(false) - .context(QUERY_CONTEXT_DEFAULT) - .build()), - "j0.", - "(\"__time\" == \"j0.__time\")", - JoinType.INNER, - null, - ExprMacroTable.nil())) + .dataSource(JoinDataSource.create( + new TableDataSource(CalciteTests.DATASOURCE1), + new QueryDataSource( + Druids.newScanQueryBuilder() + .dataSource(CalciteTests.DATASOURCE1) + .intervals(querySegmentSpec(Filtration.eternity())) + .resultFormat(ResultFormat.RESULT_FORMAT_COMPACTED_LIST) + .columns("__time") + .legacy(false) + .context(QUERY_CONTEXT_DEFAULT) + .build()), + "j0.", + "(\"__time\" == \"j0.__time\")", + JoinType.INNER, + null, + ExprMacroTable.nil() + )) .intervals(querySegmentSpec(Filtration.eternity())) .granularity(Granularities.ALL) .aggregators(aggregators(new CountAggregatorFactory("a0"))) .context(QUERY_CONTEXT_DEFAULT) .build()), - ImmutableList.of(new Object[]{6L})); + ImmutableList.of(new Object[]{6L}) + ); } @Test @@ -18312,7 +18535,9 @@ public void testLeftJoinSubqueryWithNullKeyFilter(Map queryConte .context(queryContext) .build(); - boolean isJoinFilterRewriteEnabled = queryContext.getOrDefault(JOIN_FILTER_REWRITE_ENABLE_KEY, true).toString().equals("true"); + boolean isJoinFilterRewriteEnabled = queryContext.getOrDefault(JOIN_FILTER_REWRITE_ENABLE_KEY, true) + .toString() + .equals("true"); testQuery( "SELECT dim1, l1.k\n" + "FROM foo\n" @@ -18320,12 +18545,16 @@ public void testLeftJoinSubqueryWithNullKeyFilter(Map queryConte + "WHERE l1.k IS NOT NULL\n", queryContext, ImmutableList.of(NullHandling.sqlCompatible() ? nullCompatibleModePlan : nonNullCompatibleModePlan), - NullHandling.sqlCompatible() || !isJoinFilterRewriteEnabled ? ImmutableList.of(new Object[]{"abc", "abc"}) : ImmutableList.of( - new Object[]{"10.1", ""}, // this result is incorrect. TODO : fix this result when the JoinFilterAnalyzer bug is fixed - new Object[]{"2", ""}, - new Object[]{"1", ""}, - new Object[]{"def", ""}, - new Object[]{"abc", "abc"}) + NullHandling.sqlCompatible() || !isJoinFilterRewriteEnabled + ? ImmutableList.of(new Object[]{"abc", "abc"}) + : ImmutableList.of( + new Object[]{"10.1", ""}, + // this result is incorrect. TODO : fix this result when the JoinFilterAnalyzer bug is fixed + new Object[]{"2", ""}, + new Object[]{"1", ""}, + new Object[]{"def", ""}, + new Object[]{"abc", "abc"} + ) ); } @@ -18338,8 +18567,10 @@ public void testLeftJoinSubqueryWithSelectorFilter(Map queryCont // disable the cost model where inner join is treated like a filter // this leads to cost(left join) < cost(converted inner join) for the below query - queryContext = QueryContextForJoinProvider.withOverrides(queryContext, - ImmutableMap.of("computeInnerJoinCostAsFilter", "false")); + queryContext = QueryContextForJoinProvider.withOverrides( + queryContext, + ImmutableMap.of("computeInnerJoinCostAsFilter", "false") + ); testQuery( "SELECT dim1, l1.k\n" + "FROM foo\n" @@ -18397,12 +18628,12 @@ public void testLeftJoinWithNotNullFilter(Map queryContext) thro join( new TableDataSource(CalciteTests.DATASOURCE1), new QueryDataSource(newScanQueryBuilder() - .dataSource(CalciteTests.DATASOURCE1) - .intervals(querySegmentSpec(Filtration.eternity())) - .columns(ImmutableList.of("dim1")) - .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) - .context(QUERY_CONTEXT_DEFAULT) - .build()), + .dataSource(CalciteTests.DATASOURCE1) + .intervals(querySegmentSpec(Filtration.eternity())) + .columns(ImmutableList.of("dim1")) + .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST) + .context(QUERY_CONTEXT_DEFAULT) + .build()), "j0.", equalsCondition(DruidExpression.fromColumn("dim1"), DruidExpression.fromColumn("j0.dim1")), JoinType.LEFT @@ -18457,7 +18688,10 @@ public void testInnerJoinSubqueryWithSelectorFilter(Map queryCon StringUtils.format( "(%s && %s)", equalsCondition(DruidExpression.fromColumn("dim1"), DruidExpression.fromColumn("j0.d0")), - equalsCondition(DruidExpression.fromExpression("'abc'"), DruidExpression.fromColumn("j0.d0")) + equalsCondition( + DruidExpression.fromExpression("'abc'"), + DruidExpression.fromColumn("j0.d0") + ) ), JoinType.INNER ) @@ -18812,7 +19046,9 @@ public void testStringAggExpression() throws Exception .build() ), ImmutableList.of( - useDefault ? new Object[]{"1a,a,2,abc,10.1,defabc", "1a||a||2||abc||10.1||defabc"} : new Object[]{"1a,a,2,defabc", "1a||a||2||defabc"} + useDefault + ? new Object[]{"1a,a,2,abc,10.1,defabc", "1a||a||2||abc||10.1||defabc"} + : new Object[]{"1a,a,2,defabc", "1a||a||2||defabc"} ) ); } @@ -18914,14 +19150,27 @@ public void testHumanReadableFormatFunction() throws Exception // NOTE: the first expression HUMAN_READABLE_BINARY_BYTE_FORMAT(45678) in SQL is calculated during SQL parse phase, // so the converted Druid native query is its result intead of the raw function call // - .virtualColumns(expressionVirtualColumn("v0", "'44.61 KiB'", ColumnType.STRING), - expressionVirtualColumn("v1", "human_readable_binary_byte_format((\"m1\" * 12345))", ColumnType.STRING), - expressionVirtualColumn("v2", "human_readable_binary_byte_format((\"m1\" * 12345),0)", ColumnType.STRING), - expressionVirtualColumn("v3", "human_readable_decimal_byte_format((\"m1\" * 12345))", ColumnType.STRING), - expressionVirtualColumn("v4", "human_readable_decimal_format((\"m1\" * 12345))", ColumnType.STRING), - expressionVirtualColumn("v5", "human_readable_binary_byte_format(\"l1\")", ColumnType.STRING), - expressionVirtualColumn("v6", "human_readable_decimal_byte_format(\"l1\")", ColumnType.STRING), - expressionVirtualColumn("v7", "human_readable_decimal_format(\"l1\")", ColumnType.STRING) + .virtualColumns( + expressionVirtualColumn("v0", "'44.61 KiB'", ColumnType.STRING), + expressionVirtualColumn( + "v1", + "human_readable_binary_byte_format((\"m1\" * 12345))", + ColumnType.STRING + ), + expressionVirtualColumn( + "v2", + "human_readable_binary_byte_format((\"m1\" * 12345),0)", + ColumnType.STRING + ), + expressionVirtualColumn( + "v3", + "human_readable_decimal_byte_format((\"m1\" * 12345))", + ColumnType.STRING + ), + expressionVirtualColumn("v4", "human_readable_decimal_format((\"m1\" * 12345))", ColumnType.STRING), + expressionVirtualColumn("v5", "human_readable_binary_byte_format(\"l1\")", ColumnType.STRING), + expressionVirtualColumn("v6", "human_readable_decimal_byte_format(\"l1\")", ColumnType.STRING), + expressionVirtualColumn("v7", "human_readable_decimal_format(\"l1\")", ColumnType.STRING) ) .columns("m1", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7") .filters(selector("dim1", "1", null)) @@ -18931,15 +19180,16 @@ public void testHumanReadableFormatFunction() throws Exception .build() ), ImmutableList.of( - new Object[]{(float) 4.0, - "44.61 KiB", // 45678 / 1024 - "48.22 KiB", // = m1(4.0) * 12345 / 1024 - "48 KiB", // = m1(4.0) * 12345 / 1024, precision = 0 - "49.38 KB", // decimal byte format, m1(4.0) * 12345 / 1000, - "49.38 K", // decimal format, m1(4.0) * 12345 / 1000, - NullHandling.replaceWithDefault() ? "0 B" : null, - NullHandling.replaceWithDefault() ? "0 B" : null, - NullHandling.replaceWithDefault() ? "0" : null + new Object[]{ + (float) 4.0, + "44.61 KiB", // 45678 / 1024 + "48.22 KiB", // = m1(4.0) * 12345 / 1024 + "48 KiB", // = m1(4.0) * 12345 / 1024, precision = 0 + "49.38 KB", // decimal byte format, m1(4.0) * 12345 / 1000, + "49.38 K", // decimal format, m1(4.0) * 12345 / 1000, + NullHandling.replaceWithDefault() ? "0 B" : null, + NullHandling.replaceWithDefault() ? "0 B" : null, + NullHandling.replaceWithDefault() ? "0" : null } ) ); From 5fd5cd480dd29706dd6e4b3c736611fe8dc74c85 Mon Sep 17 00:00:00 2001 From: Soumyava Das Date: Mon, 15 Nov 2021 12:29:32 -0800 Subject: [PATCH 5/7] Fixing expected results for infinity --- .../test/java/org/apache/druid/math/expr/FunctionTest.java | 5 +++-- docs/querying/sql.md | 2 +- .../java/org/apache/druid/sql/calcite/CalciteQueryTest.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java index 5377a59850cf..b8e4483c65df 100644 --- a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java @@ -37,6 +37,7 @@ import org.junit.rules.ExpectedException; import javax.annotation.Nullable; +import javax.validation.constraints.Null; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Locale; @@ -788,8 +789,8 @@ public void testSafeDivide() // NaN and Infinity cases assertExpr("safe_divide(NaN, 0.0)", NullHandling.defaultDoubleValue()); assertExpr("safe_divide(0, NaN)", 0.0); - assertExpr("safe_divide(0, POSITIVE_INFINITY)", 0L); - assertExpr("safe_divide(POSITIVE_INFINITY,0)", 0L); + assertExpr("safe_divide(0, POSITIVE_INFINITY)", NullHandling.defaultLongValue()); + assertExpr("safe_divide(POSITIVE_INFINITY,0)", NullHandling.defaultLongValue()); } @Test diff --git a/docs/querying/sql.md b/docs/querying/sql.md index 040b1573d6e5..f86b3197e140 100644 --- a/docs/querying/sql.md +++ b/docs/querying/sql.md @@ -418,7 +418,7 @@ to FLOAT. At runtime, Druid will widen 32-bit floats to 64-bit for most expressi |`HUMAN_READABLE_BINARY_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [IEC](https://en.wikipedia.org/wiki/Binary_prefix) format. For example, HUMAN_READABLE_BINARY_BYTE_FORMAT(1048576) returns `1.00 MiB`. `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [SI](https://en.wikipedia.org/wiki/Binary_prefix) format. HUMAN_READABLE_DECIMAL_BYTE_FORMAT(1048576) returns `1.04 MB`. `precision` must be in the range of [0,3] (default: 2). `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_FORMAT(value[, precision])`| Format a number in human-readable SI format. For example, HUMAN_READABLE_DECIMAL_FORMAT(1048576) returns `1.04 M`. `precision` must be in the range of [0,3] (default: 2). | -|`SAFE_DIVIDE(x,y)`|Returns the division of x by y guarded on division by 0.In case y is 0 it returns 0, or `null` if `druid.generic.useDefaultValueForNull=false` | +|`SAFE_DIVIDE(x,y)`|Returns the division of x by y guarded on division by 0. In case y is 0 it returns 0, or `null` if `druid.generic.useDefaultValueForNull=false` | ### String functions 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 819b8cd32782..7dc1e858a889 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 @@ -1032,7 +1032,7 @@ public void testSafeDivideExpressions() throws Exception expected = ImmutableList.of( new Object[]{null, null, null, 7.0F}, new Object[]{1.0F, 1L, 1.0, 3253230.0F}, - new Object[]{0.0F, 0L, 0, 0.0F}, + new Object[]{0.0F, 0L, 0.0, 0.0F}, new Object[]{null, null, null, null}, new Object[]{null, null, null, null}, new Object[]{null, null, null, null} From bf261b1ccdefe8230255dbab675a358f7059afc8 Mon Sep 17 00:00:00 2001 From: Soumyava Das Date: Mon, 15 Nov 2021 13:42:47 -0800 Subject: [PATCH 6/7] Revert "Fixing expected results for infinity" This reverts commit 5fd5cd480dd29706dd6e4b3c736611fe8dc74c85. --- .../test/java/org/apache/druid/math/expr/FunctionTest.java | 5 ++--- docs/querying/sql.md | 2 +- .../java/org/apache/druid/sql/calcite/CalciteQueryTest.java | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java index b8e4483c65df..5377a59850cf 100644 --- a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java @@ -37,7 +37,6 @@ import org.junit.rules.ExpectedException; import javax.annotation.Nullable; -import javax.validation.constraints.Null; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Locale; @@ -789,8 +788,8 @@ public void testSafeDivide() // NaN and Infinity cases assertExpr("safe_divide(NaN, 0.0)", NullHandling.defaultDoubleValue()); assertExpr("safe_divide(0, NaN)", 0.0); - assertExpr("safe_divide(0, POSITIVE_INFINITY)", NullHandling.defaultLongValue()); - assertExpr("safe_divide(POSITIVE_INFINITY,0)", NullHandling.defaultLongValue()); + assertExpr("safe_divide(0, POSITIVE_INFINITY)", 0L); + assertExpr("safe_divide(POSITIVE_INFINITY,0)", 0L); } @Test diff --git a/docs/querying/sql.md b/docs/querying/sql.md index f86b3197e140..040b1573d6e5 100644 --- a/docs/querying/sql.md +++ b/docs/querying/sql.md @@ -418,7 +418,7 @@ to FLOAT. At runtime, Druid will widen 32-bit floats to 64-bit for most expressi |`HUMAN_READABLE_BINARY_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [IEC](https://en.wikipedia.org/wiki/Binary_prefix) format. For example, HUMAN_READABLE_BINARY_BYTE_FORMAT(1048576) returns `1.00 MiB`. `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [SI](https://en.wikipedia.org/wiki/Binary_prefix) format. HUMAN_READABLE_DECIMAL_BYTE_FORMAT(1048576) returns `1.04 MB`. `precision` must be in the range of [0,3] (default: 2). `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_FORMAT(value[, precision])`| Format a number in human-readable SI format. For example, HUMAN_READABLE_DECIMAL_FORMAT(1048576) returns `1.04 M`. `precision` must be in the range of [0,3] (default: 2). | -|`SAFE_DIVIDE(x,y)`|Returns the division of x by y guarded on division by 0. In case y is 0 it returns 0, or `null` if `druid.generic.useDefaultValueForNull=false` | +|`SAFE_DIVIDE(x,y)`|Returns the division of x by y guarded on division by 0.In case y is 0 it returns 0, or `null` if `druid.generic.useDefaultValueForNull=false` | ### String functions 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 7dc1e858a889..819b8cd32782 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 @@ -1032,7 +1032,7 @@ public void testSafeDivideExpressions() throws Exception expected = ImmutableList.of( new Object[]{null, null, null, 7.0F}, new Object[]{1.0F, 1L, 1.0, 3253230.0F}, - new Object[]{0.0F, 0L, 0.0, 0.0F}, + new Object[]{0.0F, 0L, 0, 0.0F}, new Object[]{null, null, null, null}, new Object[]{null, null, null, null}, new Object[]{null, null, null, null} From 631d424ca38f2065f158d17c415a05b7de1d6f31 Mon Sep 17 00:00:00 2001 From: Soumyava Das Date: Mon, 15 Nov 2021 13:45:42 -0800 Subject: [PATCH 7/7] Updating test result and a space in docs --- .../test/java/org/apache/druid/math/expr/FunctionTest.java | 4 ++-- docs/querying/sql.md | 2 +- .../java/org/apache/druid/sql/calcite/CalciteQueryTest.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java index 5377a59850cf..11d6b239849f 100644 --- a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java @@ -788,8 +788,8 @@ public void testSafeDivide() // NaN and Infinity cases assertExpr("safe_divide(NaN, 0.0)", NullHandling.defaultDoubleValue()); assertExpr("safe_divide(0, NaN)", 0.0); - assertExpr("safe_divide(0, POSITIVE_INFINITY)", 0L); - assertExpr("safe_divide(POSITIVE_INFINITY,0)", 0L); + assertExpr("safe_divide(0, POSITIVE_INFINITY)", NullHandling.defaultLongValue()); + assertExpr("safe_divide(POSITIVE_INFINITY,0)", NullHandling.defaultLongValue()); } @Test diff --git a/docs/querying/sql.md b/docs/querying/sql.md index 040b1573d6e5..f86b3197e140 100644 --- a/docs/querying/sql.md +++ b/docs/querying/sql.md @@ -418,7 +418,7 @@ to FLOAT. At runtime, Druid will widen 32-bit floats to 64-bit for most expressi |`HUMAN_READABLE_BINARY_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [IEC](https://en.wikipedia.org/wiki/Binary_prefix) format. For example, HUMAN_READABLE_BINARY_BYTE_FORMAT(1048576) returns `1.00 MiB`. `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_BYTE_FORMAT(value[, precision])`| Format a number in human-readable [SI](https://en.wikipedia.org/wiki/Binary_prefix) format. HUMAN_READABLE_DECIMAL_BYTE_FORMAT(1048576) returns `1.04 MB`. `precision` must be in the range of [0,3] (default: 2). `precision` must be in the range of [0,3] (default: 2). | |`HUMAN_READABLE_DECIMAL_FORMAT(value[, precision])`| Format a number in human-readable SI format. For example, HUMAN_READABLE_DECIMAL_FORMAT(1048576) returns `1.04 M`. `precision` must be in the range of [0,3] (default: 2). | -|`SAFE_DIVIDE(x,y)`|Returns the division of x by y guarded on division by 0.In case y is 0 it returns 0, or `null` if `druid.generic.useDefaultValueForNull=false` | +|`SAFE_DIVIDE(x,y)`|Returns the division of x by y guarded on division by 0. In case y is 0 it returns 0, or `null` if `druid.generic.useDefaultValueForNull=false` | ### String functions 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 819b8cd32782..7dc1e858a889 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 @@ -1032,7 +1032,7 @@ public void testSafeDivideExpressions() throws Exception expected = ImmutableList.of( new Object[]{null, null, null, 7.0F}, new Object[]{1.0F, 1L, 1.0, 3253230.0F}, - new Object[]{0.0F, 0L, 0, 0.0F}, + new Object[]{0.0F, 0L, 0.0, 0.0F}, new Object[]{null, null, null, null}, new Object[]{null, null, null, null}, new Object[]{null, null, null, null}