zoudan commented on code in PR #3252:
URL: https://github.com/apache/calcite/pull/3252#discussion_r1222374114


##########
core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java:
##########
@@ -1524,6 +1524,43 @@ public static int multiply(int b0, int b1) {
     throw notArithmetic("*", b0, b1);
   }
 
+  /** Helper method for safe arithmetic functions that checks if overflow has 
occurred. */
+  private static boolean isOverflow(BigDecimal ans, BigDecimal min, BigDecimal 
max) {
+    return ans.compareTo(min) > 0 || ans.compareTo(max) < 0;
+  }
+
+  /** SQL <code>SAFE_NEGATE</code> function applied to an integer value. */
+  public static @Nullable Integer safeNegate(int b) {
+    BigDecimal ans = multiply(BigDecimal.valueOf(b), BigDecimal.valueOf(-1));
+    boolean overflow =
+        isOverflow(ans, BigDecimal.valueOf(Integer.MAX_VALUE), 
BigDecimal.valueOf(Integer.MIN_VALUE));
+    return overflow ? null : ans.intValue();
+  }
+
+  /** SQL <code>SAFE_NEGATE</code> function applied to a double value. */
+  public static @Nullable Double safeNegate(double b) {
+    BigDecimal ans = multiply(BigDecimal.valueOf(b), BigDecimal.valueOf(-1));
+    boolean overflow =
+            isOverflow(ans, BigDecimal.valueOf(Double.MAX_VALUE), 
BigDecimal.valueOf(-Double.MAX_VALUE));
+    return overflow ? null : ans.doubleValue();
+  }
+
+  /** SQL <code>SAFE_NEGATE</code> function applied to a long value. */
+  public static @Nullable Long safeNegate(long b) {
+    BigDecimal ans = multiply(BigDecimal.valueOf(b), BigDecimal.valueOf(-1));
+    boolean overflow =
+        isOverflow(ans, BigDecimal.valueOf(Long.MAX_VALUE), 
BigDecimal.valueOf(Long.MIN_VALUE));
+    return overflow ? null : ans.longValue();
+  }
+
+  /** SQL <code>SAFE_NEGATE</code> function applied to a BigDecimal value. */
+  public static @Nullable BigDecimal safeNegate(BigDecimal b) {

Review Comment:
   Should we add methods to handle other data types such as `float`, `smallint`?



##########
testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java:
##########
@@ -5243,6 +5243,23 @@ private static void checkIf(SqlOperatorFixture f) {
         DIVISION_BY_ZERO_MESSAGE, true);
   }
 
+  @Test void testSafeNegateFunc() {
+    final SqlOperatorFixture f0 = 
fixture().setFor(SqlLibraryOperators.SAFE_NEGATE);
+    f0.checkFails("^safe_negate(100)^",
+        "No match found for function signature SAFE_NEGATE\\(<NUMERIC>\\)",
+        false);
+    final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.BIG_QUERY);
+    f.checkScalar("safe_negate(3)", "-3", "INTEGER");
+    f.checkScalar("safe_negate(-3)", "3", "INTEGER");
+    f.checkScalar("safe_negate(0)", "0", "INTEGER");
+    f.checkScalar("safe_negate(cast(3.0 as double))", "-3.0", "DOUBLE");
+    f.checkScalar("safe_negate(cast(3.456 as float))", "-3.456", "FLOAT");
+    f.checkScalar("safe_negate(cast(3.1234 as decimal(5, 4)))",
+        "-3.1234", "DECIMAL(5, 4)");
+    // check overflow returns null
+    f.checkNull("safe_negate(-9223372036854775808)");

Review Comment:
   Maybe we should add more overflow test cases for all kinds of numerical 
types? 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to