This is an automated email from the ASF dual-hosted git repository. tanner pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push: new 01467a1797 [CALCITE-5766] Add SAFE_NEGATE function (enabled for BigQuery library) 01467a1797 is described below commit 01467a17973c0f7b684c2662f81342ab5af3a62f Author: Tanner Clary <tannercl...@google.com> AuthorDate: Thu Aug 24 10:31:42 2023 -0700 [CALCITE-5766] Add SAFE_NEGATE function (enabled for BigQuery library) --- babel/src/test/resources/sql/big-query.iq | 46 ++++++++++++++++++++++ .../calcite/adapter/enumerable/RexImpTable.java | 17 ++++++-- .../calcite/sql/fun/SqlLibraryOperators.java | 9 +++++ site/_docs/reference.md | 1 + .../org/apache/calcite/test/SqlOperatorTest.java | 37 ++++++++++++++++- 5 files changed, 105 insertions(+), 5 deletions(-) diff --git a/babel/src/test/resources/sql/big-query.iq b/babel/src/test/resources/sql/big-query.iq index 515e083f6a..753ce6a5cd 100755 --- a/babel/src/test/resources/sql/big-query.iq +++ b/babel/src/test/resources/sql/big-query.iq @@ -737,6 +737,52 @@ SELECT SAFE_MULTIPLY(CAST('NaN' AS DOUBLE), CAST(3 as BIGINT)) as NaN_result; !ok +##################################################################### +# SAFE_NEGATE +# +# SAFE_NEGATE(value) +# +# Returns value * -1, or NULL on overflow. +SELECT SAFE_NEGATE(5) as result; ++--------+ +| result | ++--------+ +| -5 | ++--------+ +(1 row) + +!ok + +SELECT SAFE_NEGATE(-5) as result; ++--------+ +| result | ++--------+ +| 5 | ++--------+ +(1 row) + +!ok + +SELECT SAFE_NEGATE(-9223372036854775808) as overflow_result; ++-----------------+ +| overflow_result | ++-----------------+ +| | ++-----------------+ +(1 row) + +!ok + +SELECT SAFE_NEGATE(1 + 2 + 3 + 4) as expr_result; ++-------------+ +| expr_result | ++-------------+ +| -10 | ++-------------+ +(1 row) + +!ok + ##################################################################### # SAFE_SUBTRACT # diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java index bfc6342a35..6a1184d86d 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java @@ -228,6 +228,7 @@ import static org.apache.calcite.sql.fun.SqlLibraryOperators.RPAD; import static org.apache.calcite.sql.fun.SqlLibraryOperators.SAFE_ADD; import static org.apache.calcite.sql.fun.SqlLibraryOperators.SAFE_CAST; import static org.apache.calcite.sql.fun.SqlLibraryOperators.SAFE_MULTIPLY; +import static org.apache.calcite.sql.fun.SqlLibraryOperators.SAFE_NEGATE; import static org.apache.calcite.sql.fun.SqlLibraryOperators.SAFE_OFFSET; import static org.apache.calcite.sql.fun.SqlLibraryOperators.SAFE_ORDINAL; import static org.apache.calcite.sql.fun.SqlLibraryOperators.SAFE_SUBTRACT; @@ -646,6 +647,8 @@ public class RexImpTable { new SafeArithmeticImplementor(BuiltInMethod.SAFE_ADD.method)); map.put(SAFE_MULTIPLY, new SafeArithmeticImplementor(BuiltInMethod.SAFE_MULTIPLY.method)); + map.put(SAFE_NEGATE, + new SafeArithmeticImplementor(BuiltInMethod.SAFE_MULTIPLY.method)); map.put(SAFE_SUBTRACT, new SafeArithmeticImplementor(BuiltInMethod.SAFE_SUBTRACT.method)); @@ -2477,10 +2480,16 @@ public class RexImpTable { @Override Expression implementSafe(final RexToLixTranslator translator, final RexCall call, final List<Expression> argValueList) { - Expression arg0 = convertType(argValueList.get(0), call.operands.get(0)); - Expression arg1 = convertType(argValueList.get(1), call.operands.get(1)); - return super.implementSafe(translator, call, - ImmutableList.of(arg0, arg1)); + List<Expression> args = new ArrayList<Expression>(); + args.add(convertType(argValueList.get(0), call.operands.get(0))); + // SAFE_NEGATE only has one argument so create constant -1L to use + // SAFE_MULTIPLY implementation. + if (argValueList.size() == 1) { + args.add(Expressions.constant(-1L)); + } else { + args.add(convertType(argValueList.get(1), call.operands.get(1))); + } + return super.implementSafe(translator, call, args); } // Because BigQuery treats all int types as aliases for BIGINT (Java's long) diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java index 7cf793fc51..18ee78654f 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java @@ -1709,6 +1709,15 @@ public abstract class SqlLibraryOperators { OperandTypes.NUMERIC_NUMERIC, SqlFunctionCategory.NUMERIC); + /** The "SAFE_NEGATE(numeric)" function; negates {@code numeric} and returns null if overflow + * occurs. */ + @LibraryOperator(libraries = {BIG_QUERY}) + public static final SqlFunction SAFE_NEGATE = + SqlBasicFunction.create("SAFE_NEGATE", + ReturnTypes.ARG0_FORCE_NULLABLE, + OperandTypes.NUMERIC, + SqlFunctionCategory.NUMERIC); + /** The "SAFE_SUBTRACT(numeric1, numeric2)" function; equivalent to the {@code -} operator but * returns null if overflow occurs. */ @LibraryOperator(libraries = {BIG_QUERY}) diff --git a/site/_docs/reference.md b/site/_docs/reference.md index ebbc7c2a52..8ecf52568e 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -2796,6 +2796,7 @@ BigQuery's type system uses confusingly different names for types and functions: | b | SAFE_ADD(numeric1, numeric2) | Returns *numeric1* + *numeric2*, or NULL on overflow | b | SAFE_CAST(value AS type) | Converts *value* to *type*, returning NULL if conversion fails | b | SAFE_MULTIPLY(numeric1, numeric2) | Returns *numeric1* * *numeric2*, or NULL on overflow +| b | SAFE_NEGATE(numeric) | Returns *numeric* * -1, or NULL on overflow | b | SAFE_OFFSET(index) | Similar to `OFFSET` except null is returned if *index* is out of bounds | b | SAFE_ORDINAL(index) | Similar to `OFFSET` except *index* begins at 1 and null is returned if *index* is out of bounds | b | SAFE_SUBTRACT(numeric1, numeric2) | Returns *numeric1* - *numeric2*, or NULL on overflow diff --git a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java index 029412b15e..a0a4f9720d 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -7480,7 +7480,42 @@ public class SqlOperatorTest { /** Test case for * <a href="https://issues.apache.org/jira/browse/CALCITE-5770">[CALCITE-5770] - * Add SAFE_SUBTRACT function (enabled in BigQuery library).</a>. + * Add SAFE_NEGATE function (enabled in BigQuery library)</a>. + */ + @Test void testSafeNegateFunc() { + final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.SAFE_NEGATE); + f0.checkFails("^safe_negate(2)^", + "No match found for function signature " + + "SAFE_NEGATE\\(<NUMERIC>\\)", false); + final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.BIG_QUERY); + f.checkScalar("safe_negate(cast(20 as bigint))", "-20", + "BIGINT"); + f.checkScalar("safe_negate(cast(-20 as bigint))", "20", + "BIGINT"); + f.checkScalar("safe_negate(cast(1.5 as decimal(2, 1)))", "-1.5", + "DECIMAL(2, 1)"); + f.checkScalar("safe_negate(cast(-1.5 as decimal(2, 1)))", "1.5", + "DECIMAL(2, 1)"); + f.checkScalar("safe_negate(cast(12.3456 as double))", "-12.3456", + "DOUBLE"); + f.checkScalar("safe_negate(cast(-12.3456 as double))", "12.3456", + "DOUBLE"); + // Infinity and NaN tests + f.checkScalar("safe_negate(cast('Infinity' as double))", + "-Infinity", "DOUBLE"); + f.checkScalar("safe_negate(cast('-Infinity' as double))", + "Infinity", "DOUBLE"); + f.checkScalar("safe_negate(cast('NaN' as double))", + "NaN", "DOUBLE"); + // Null cases are rarer for SAFE_NEGATE + f.checkNull("safe_negate(-9223372036854775808)"); + f.checkNull("safe_negate(-1 + -9223372036854775807)"); + f.checkNull("safe_negate(cast(null as bigint))"); + } + + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-5770">[CALCITE-5770] + * Add SAFE_SUBTRACT function (enabled in BigQuery library)</a>. */ @Test void testSafeSubtractFunc() { final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.SAFE_SUBTRACT);