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 25f326cf0a [CALCITE-5827] Add IS_INF and IS_NAN functions (enabled in 
BigQuery library)
25f326cf0a is described below

commit 25f326cf0a94d5e65bd82abc95b676cec6b1fd43
Author: Tanner Clary <[email protected]>
AuthorDate: Sun Jul 9 23:09:53 2023 -0700

    [CALCITE-5827] Add IS_INF and IS_NAN functions (enabled in BigQuery library)
---
 babel/src/test/resources/sql/big-query.iq          | 73 ++++++++++++++++++++++
 .../calcite/adapter/enumerable/RexImpTable.java    |  4 ++
 .../org/apache/calcite/runtime/SqlFunctions.java   | 30 +++++++++
 .../calcite/sql/fun/SqlLibraryOperators.java       | 16 +++++
 site/_docs/reference.md                            |  6 +-
 .../org/apache/calcite/test/SqlOperatorTest.java   | 58 +++++++++++++++++
 6 files changed, 185 insertions(+), 2 deletions(-)

diff --git a/babel/src/test/resources/sql/big-query.iq 
b/babel/src/test/resources/sql/big-query.iq
index 6a6970dfba..a0e7782a30 100755
--- a/babel/src/test/resources/sql/big-query.iq
+++ b/babel/src/test/resources/sql/big-query.iq
@@ -856,6 +856,79 @@ SELECT SPLIT('h,e,l,l,o')[SAFE_ORDINAL(7)] as 
safe_ordinal_idx;
 SELECT OFFSET(1);
 java.sql.SQLException: Error while executing SQL "SELECT OFFSET(1)": parse 
failed: Incorrect syntax near the keyword 'OFFSET' at line 1, column 8.
 !error
+
+#####################################################################
+# IS_INF
+# 
+# IS_INF(x)
+#
+# Returns whether x is infinite.
+SELECT IS_INF(3) AS non_inf_result;
++----------------+
+| non_inf_result |
++----------------+
+| false          |
++----------------+
+(1 row)
+
+!ok
+
+SELECT IS_INF(CAST('Infinity' AS DOUBLE)) AS inf_result;
++------------+
+| inf_result |
++------------+
+| true       |
++------------+
+(1 row)
+
+!ok
+
+SELECT IS_INF(CAST('NaN' AS DOUBLE)) AS nan_result;
++------------+
+| nan_result |
++------------+
+| false      |
++------------+
+(1 row)
+
+!ok
+
+#####################################################################
+# IS_NAN
+# 
+# IS_NAN(x)
+#
+# Returns whether x is NaN.
+SELECT IS_NAN(3) AS non_nan_result;
++----------------+
+| non_nan_result |
++----------------+
+| false          |
++----------------+
+(1 row)
+
+!ok
+
+SELECT IS_NAN(CAST('Infinity' AS DOUBLE)) AS inf_result;
++------------+
+| inf_result |
++------------+
+| false      |
++------------+
+(1 row)
+
+!ok
+
+SELECT IS_NAN(CAST('NaN' AS DOUBLE)) AS nan_result;
++------------+
+| nan_result |
++------------+
+| true       |
++------------+
+(1 row)
+
+!ok
+
 #####################################################################
 # LN
 #
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 7220052d10..531a0ce013 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
@@ -179,6 +179,8 @@ import static 
org.apache.calcite.sql.fun.SqlLibraryOperators.FROM_BASE32;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.FROM_BASE64;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.FROM_HEX;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.ILIKE;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.IS_INF;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.IS_NAN;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.JSON_DEPTH;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.JSON_INSERT;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.JSON_KEYS;
@@ -604,6 +606,8 @@ public class RexImpTable {
       defineMethod(CSC, "csc", NullPolicy.STRICT);
       defineMethod(CSCH, "csch", NullPolicy.STRICT);
       defineMethod(DEGREES, "degrees", NullPolicy.STRICT);
+      defineMethod(IS_INF, "isInf", NullPolicy.STRICT);
+      defineMethod(IS_NAN, "isNaN", NullPolicy.STRICT);
       defineMethod(POW, "power", NullPolicy.STRICT);
       defineMethod(RADIANS, "radians", NullPolicy.STRICT);
       defineMethod(ROUND, "sround", NullPolicy.STRICT);
diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java 
b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index 98fa1330bd..79def765a2 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -2297,6 +2297,36 @@ public class SqlFunctions {
     return Math.toDegrees(b0);
   }
 
+  /** SQL <code>IS_INF</code> operator applied to BigDecimal values. */
+  public static boolean isInf(BigDecimal b0) {
+    return Double.isInfinite(b0.doubleValue());
+  }
+
+  /** SQL <code>IS_INF</code> operator applied to double values. */
+  public static boolean isInf(double b0) {
+    return Double.isInfinite(b0);
+  }
+
+  /** SQL <code>IS_INF</code> operator applied to float values. */
+  public static boolean isInf(float b0) {
+    return Float.isInfinite(b0);
+  }
+
+  /** SQL <code>IS_NAN</code> operator applied to BigDecimal values. */
+  public static boolean isNaN(BigDecimal b0) {
+    return Double.isNaN(b0.doubleValue());
+  }
+
+  /** SQL <code>IS_NAN</code> operator applied to double values. */
+  public static boolean isNaN(double b0) {
+    return Double.isNaN(b0);
+  }
+
+  /** SQL <code>IS_NAN</code> operator applied to float values. */
+  public static boolean isNaN(float b0) {
+    return Float.isNaN(b0);
+  }
+
   // RADIANS
   /** SQL <code>RADIANS</code> operator applied to BigDecimal values. */
   public static double radians(BigDecimal b0) {
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 dce8eb81df..6b234c2165 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
@@ -1794,6 +1794,22 @@ public abstract class SqlLibraryOperators {
           OperandTypes.STRING.or(OperandTypes.BINARY),
           SqlFunctionCategory.STRING);
 
+  /** The "IS_INF(value)" function. Returns whether value is infinite. */
+  @LibraryOperator(libraries = {BIG_QUERY})
+  public static final SqlFunction IS_INF =
+      SqlBasicFunction.create("IS_INF",
+          ReturnTypes.BOOLEAN_NULLABLE,
+          OperandTypes.NUMERIC,
+          SqlFunctionCategory.NUMERIC);
+
+  /** The "IS_NAN(value)" function. Returns whether value is NaN. */
+  @LibraryOperator(libraries = {BIG_QUERY})
+  public static final SqlFunction IS_NAN =
+      SqlBasicFunction.create("IS_NAN",
+          ReturnTypes.BOOLEAN_NULLABLE,
+          OperandTypes.NUMERIC,
+          SqlFunctionCategory.NUMERIC);
+
   /** The "LOG(value [, value2])" function.
    *
    * @see SqlStdOperatorTable#LN
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 63c169a753..cf521bc0ce 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2731,10 +2731,12 @@ BigQuery's type system uses confusingly different names 
for types and functions:
 | b o | GREATEST(expr [, expr ]*)                    | Returns the greatest of 
the expressions
 | b h s | IF(condition, value1, value2)              | Returns *value1* if 
*condition* is TRUE, *value2* otherwise
 | b | IFNULL(value1, value2)                         | Equivalent to 
`NVL(value1, value2)`
-| b o | INSTR(string, substring [, from [, occurrence ] ]) | Returns the 
position of *substring* in *string*, searching starting at *from* (default 1), 
and until locating the nth *occurrence* (default 1) of *substring*
-| m | INSTR(string, substring)                       | Equivalent to 
`POSITION(substring IN string)`
 | p | string1 ILIKE string2 [ ESCAPE string3 ]       | Whether *string1* 
matches pattern *string2*, ignoring case (similar to `LIKE`)
 | p | string1 NOT ILIKE string2 [ ESCAPE string3 ]   | Whether *string1* does 
not match pattern *string2*, ignoring case (similar to `NOT LIKE`)
+| b o | INSTR(string, substring [, from [, occurrence ] ]) | Returns the 
position of *substring* in *string*, searching starting at *from* (default 1), 
and until locating the nth *occurrence* (default 1) of *substring*
+| m | INSTR(string, substring)                       | Equivalent to 
`POSITION(substring IN string)`
+| b | IS_INF(value)                                  | Returns whether *value* 
is infinite
+| b | IS_NAN(value)                                  | Returns whether *value* 
is NaN
 | m | JSON_TYPE(jsonValue)                           | Returns a string value 
indicating the type of *jsonValue*
 | m | JSON_DEPTH(jsonValue)                          | Returns an integer 
value indicating the depth of *jsonValue*
 | m | JSON_PRETTY(jsonValue)                         | Returns a 
pretty-printing of *jsonValue*
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 36e4068c42..53147eb9ac 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -6801,6 +6801,64 @@ public class SqlOperatorTest {
     f.checkNull("pow(cast(null as integer), 2)");
   }
 
+  @Test void testInfinity() {
+    final SqlOperatorFixture f = fixture();
+    f.checkScalar("cast('Infinity' as double)", "Infinity",
+        "DOUBLE NOT NULL");
+    f.checkScalar("cast('-Infinity' as double)", "-Infinity",
+        "DOUBLE NOT NULL");
+    f.checkScalar("cast('Infinity' as real)", "Infinity",
+        "REAL NOT NULL");
+    f.checkScalar("cast('-Infinity' as real)", "-Infinity",
+        "REAL NOT NULL");
+  }
+
+  @Test void testNaN() {
+    final SqlOperatorFixture f = fixture();
+    f.checkScalar("cast('NaN' as double)", "NaN",
+        "DOUBLE NOT NULL");
+    f.checkScalar("cast('NaN' as real)", "NaN",
+        "REAL NOT NULL");
+  }
+
+  @Test void testIsInfFunc() {
+    final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.IS_INF);
+    f0.checkFails("^is_inf(3)^",
+        "No match found for function signature IS_INF\\(<NUMERIC>\\)",
+        false);
+    final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.BIG_QUERY);
+    f.checkBoolean("is_inf(3)", false);
+    f.checkBoolean("is_inf(1.2345)", false);
+    f.checkBoolean("is_inf(cast('NaN' as double))", false);
+    f.checkBoolean("is_inf(cast('NaN' as real))", false);
+    f.checkBoolean("is_inf(cast('Infinity' as double))", true);
+    f.checkBoolean("is_inf(cast('Infinity' as float))", true);
+    f.checkBoolean("is_inf(cast('Infinity' as real))", true);
+    f.checkBoolean("is_inf(cast('-Infinity' as double))", true);
+    f.checkBoolean("is_inf(cast('-Infinity' as float))", true);
+    f.checkBoolean("is_inf(cast('-Infinity' as real))", true);
+    f.checkNull("is_inf(cast(null as double))");
+  }
+
+  @Test void testIsNaNFunc() {
+    final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.IS_NAN);
+    f0.checkFails("^is_nan(3)^",
+        "No match found for function signature IS_NAN\\(<NUMERIC>\\)",
+        false);
+    final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.BIG_QUERY);
+    f.checkBoolean("is_nan(3)", false);
+    f.checkBoolean("is_nan(1.2345)", false);
+    f.checkBoolean("is_nan(cast('Infinity' as double))", false);
+    f.checkBoolean("is_nan(cast('Infinity' as float))", false);
+    f.checkBoolean("is_nan(cast('Infinity' as real))", false);
+    f.checkBoolean("is_nan(cast('-Infinity' as double))", false);
+    f.checkBoolean("is_nan(cast('-Infinity' as float))", false);
+    f.checkBoolean("is_nan(cast('-Infinity' as real))", false);
+    f.checkBoolean("is_nan(cast('NaN' as double))", true);
+    f.checkBoolean("is_nan(cast('NaN' as real))", true);
+    f.checkNull("is_nan(cast(null as double))");
+  }
+
   @Test void testRoundFunc() {
     final SqlOperatorFixture f = fixture();
     f.setFor(SqlStdOperatorTable.ROUND, VmName.EXPAND);

Reply via email to