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);

Reply via email to