This is an automated email from the ASF dual-hosted git repository. rubenql 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 af2fb7f02b [CALCITE-5608] Implement ASINH, ACOSH, ATANH functions af2fb7f02b is described below commit af2fb7f02b30bf853cf9f4c384fbcfeafefcebdf Author: zoudan <zou...@bytedance.com> AuthorDate: Mon May 15 16:19:49 2023 +0800 [CALCITE-5608] Implement ASINH, ACOSH, ATANH functions --- .../calcite/adapter/enumerable/RexImpTable.java | 6 ++ .../org/apache/calcite/runtime/SqlFunctions.java | 56 ++++++++++++++++++ .../calcite/sql/fun/SqlLibraryOperators.java | 26 ++++++++ site/_docs/reference.md | 3 + .../org/apache/calcite/test/SqlOperatorTest.java | 69 ++++++++++++++++++++++ 5 files changed, 160 insertions(+) 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 6bc1dd18e7..4d8e51bb15 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 @@ -112,6 +112,7 @@ import static org.apache.calcite.linq4j.tree.ExpressionType.NotEqual; import static org.apache.calcite.linq4j.tree.ExpressionType.Subtract; import static org.apache.calcite.linq4j.tree.ExpressionType.UnaryPlus; import static org.apache.calcite.sql.fun.SqlInternalOperators.THROW_UNLESS; +import static org.apache.calcite.sql.fun.SqlLibraryOperators.ACOSH; import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY; import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_AGG; import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_CONCAT; @@ -121,6 +122,8 @@ import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_LENGTH; import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_REPEAT; import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_REVERSE; import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_SIZE; +import static org.apache.calcite.sql.fun.SqlLibraryOperators.ASINH; +import static org.apache.calcite.sql.fun.SqlLibraryOperators.ATANH; import static org.apache.calcite.sql.fun.SqlLibraryOperators.BOOL_AND; import static org.apache.calcite.sql.fun.SqlLibraryOperators.BOOL_OR; import static org.apache.calcite.sql.fun.SqlLibraryOperators.CHAR; @@ -529,9 +532,12 @@ public class RexImpTable { map.put(RAND_INTEGER, new RandIntegerImplementor()); defineMethod(ACOS, "acos", NullPolicy.STRICT); + defineMethod(ACOSH, "acosh", NullPolicy.STRICT); defineMethod(ASIN, "asin", NullPolicy.STRICT); + defineMethod(ASINH, "asinh", NullPolicy.STRICT); defineMethod(ATAN, "atan", NullPolicy.STRICT); defineMethod(ATAN2, "atan2", NullPolicy.STRICT); + defineMethod(ATANH, "atanh", NullPolicy.STRICT); defineMethod(CBRT, "cbrt", NullPolicy.STRICT); defineMethod(COS, "cos", NullPolicy.STRICT); defineMethod(COSH, "cosh", 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 1fc339fc07..d9621c5c1b 100644 --- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java @@ -1854,6 +1854,20 @@ public class SqlFunctions { return Math.acos(b0); } + // ACOSH + /** SQL <code>ACOSH</code> operator applied to BigDecimal values. */ + public static double acosh(BigDecimal b0) { + return acosh(b0.doubleValue()); + } + + /** SQL <code>ACOSH</code> operator applied to double values. */ + public static double acosh(double b0) { + if (b0 < 1) { + throw new IllegalArgumentException("Input parameter of acosh cannot be less than 1!"); + } + return Math.log(Math.sqrt(b0 * b0 - 1.0d) + b0); + } + // ASIN /** SQL <code>ASIN</code> operator applied to BigDecimal values. */ public static double asin(BigDecimal b0) { @@ -1865,6 +1879,25 @@ public class SqlFunctions { return Math.asin(b0); } + // ASINH + /** SQL <code>ASINH</code> operator applied to BigDecimal values. */ + public static double asinh(BigDecimal b0) { + return asinh(b0.doubleValue()); + } + + /** SQL <code>ASINH</code> operator applied to double values. */ + public static double asinh(double b0) { + final double sign; + // check the sign bit of the raw representation to handle -0. + if (Double.doubleToRawLongBits(b0) < 0) { + b0 = Math.abs(b0); + sign = -1.0d; + } else { + sign = 1.0d; + } + return sign * Math.log(Math.sqrt(b0 * b0 + 1.0d) + b0); + } + // ATAN /** SQL <code>ATAN</code> operator applied to BigDecimal values. */ public static double atan(BigDecimal b0) { @@ -1897,6 +1930,29 @@ public class SqlFunctions { return Math.atan2(b0, b1); } + // ATANH + /** SQL <code>ATANH</code> operator applied to BigDecimal values. */ + public static double atanh(BigDecimal b) { + return atanh(b.doubleValue()); + } + + /** SQL <code>ATANH</code> operator applied to double values. */ + public static double atanh(double b) { + if (Math.abs(b) >= 1) { + throw new IllegalArgumentException("Input parameter of atanh cannot be out of the " + + "range (-1, 1)!"); + } + final double mult; + // check the sign bit of the raw representation to handle -0. + if (Double.doubleToRawLongBits(b) < 0) { + b = Math.abs(b); + mult = -0.5d; + } else { + mult = 0.5d; + } + return mult * Math.log((1.0d + b) / (1.0d - b)); + } + // CBRT /** SQL <code>CBRT</code> operator applied to BigDecimal values. */ public static double cbrt(BigDecimal b) { 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 a1952900eb..01c16396c3 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 @@ -1277,6 +1277,32 @@ public abstract class SqlLibraryOperators { OperandTypes.NUMERIC, SqlFunctionCategory.NUMERIC); + /** The {@code ACOSH(numeric)} function; returns the inverse hyperbolic cosine + * of {@code value}. */ + @LibraryOperator(libraries = {ALL}) + public static final SqlFunction ACOSH = + SqlBasicFunction.create("ACOSH", + ReturnTypes.DOUBLE_NULLABLE, + OperandTypes.NUMERIC, + SqlFunctionCategory.NUMERIC); + + /** The {@code ASINH(numeric)} function; returns the inverse hyperbolic sine of {@code value}. */ + @LibraryOperator(libraries = {ALL}) + public static final SqlFunction ASINH = + SqlBasicFunction.create("ASINH", + ReturnTypes.DOUBLE_NULLABLE, + OperandTypes.NUMERIC, + SqlFunctionCategory.NUMERIC); + + /** The {@code ATANH(numeric)} function; returns the inverse hyperbolic tangent + * of {@code value}. */ + @LibraryOperator(libraries = {ALL}) + public static final SqlFunction ATANH = + SqlBasicFunction.create("ATANH", + ReturnTypes.DOUBLE_NULLABLE, + OperandTypes.NUMERIC, + SqlFunctionCategory.NUMERIC); + /** The "COTH(value)" function; returns the hyperbolic secant * of {@code value}. */ @LibraryOperator(libraries = {ALL}) diff --git a/site/_docs/reference.md b/site/_docs/reference.md index 077ecb75c3..7baa3d64df 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -2650,6 +2650,7 @@ BigQuery's type system uses confusingly different names for types and functions: |:- |:-----------------------------------------------|:----------- | p | expr :: type | Casts *expr* to *type* | m | expr1 <=> expr2 | Whether two values are equal, treating null values as the same, and it's similar to `IS NOT DISTINCT FROM` +| * | ACOSH(numeric) | Returns the inverse hyperbolic cosine of *numeric* | s | ARRAY(expr [, expr ]*) | Construct an array in Apache Spark | b | ARRAY_CONCAT(array [, array ]*) | Concatenates one or more arrays. If any input argument is `NULL` the function returns `NULL` | s | ARRAY_DISTINCT(array) | Returns unique elements of *array*. Keeps ordering of elements. @@ -2657,6 +2658,8 @@ BigQuery's type system uses confusingly different names for types and functions: | s | ARRAY_REPEAT(element, count) | Returns the array containing element count times. | b | ARRAY_REVERSE(array) | Reverses elements of *array* | s | ARRAY_SIZE(array) | Synonym for `CARDINALITY` +| * | ASINH(numeric) | Returns the inverse hyperbolic sine of *numeric* +| * | ATANH(numeric) | Returns the inverse hyperbolic tangent of *numeric* | m s | CHAR(integer) | Returns the character whose ASCII code is *integer* % 256, or null if *integer* < 0 | b o p | CHR(integer) | Returns the character whose UTF-8 code is *integer* | o | CONCAT(string, string) | Concatenates two strings 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 57585050b4..bf9412efb6 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -5587,6 +5587,75 @@ public class SqlOperatorTest { f.checkNull("atan2(1, cast(null as double))"); } + @Test void testAcoshFunc() { + final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.ACOSH); + f0.checkFails("^acosh(1)^", + "No match found for function signature ACOSH\\(<NUMERIC>\\)", + false); + final Consumer<SqlOperatorFixture> consumer = f -> { + f.checkType("acosh(1)", "DOUBLE NOT NULL"); + f.checkType("acosh(cast(1 as Decimal))", "DOUBLE NOT NULL"); + f.checkType("acosh(case when false then 1 else null end)", "DOUBLE"); + f.checkType("acosh('abc')", "DOUBLE NOT NULL"); + f.checkScalarApprox("acosh(1)", "DOUBLE NOT NULL", + isWithin(0d, 0.0001d)); + f.checkScalarApprox("acosh(cast(10 as decimal))", "DOUBLE NOT NULL", + isWithin(2.9932d, 0.0001d)); + f.checkNull("acosh(cast(null as integer))"); + f.checkNull("acosh(cast(null as double))"); + f.checkFails("acosh(0.1)", + "Input parameter of acosh cannot be less than 1!", + true); + }; + f0.forEachLibrary(list(SqlLibrary.ALL), consumer); + } + + @Test void testAsinhFunc() { + final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.ASINH); + f0.checkFails("^asinh(1)^", + "No match found for function signature ASINH\\(<NUMERIC>\\)", + false); + final Consumer<SqlOperatorFixture> consumer = f -> { + f.checkType("asinh(1)", "DOUBLE NOT NULL"); + f.checkType("asinh(cast(1 as Decimal))", "DOUBLE NOT NULL"); + f.checkType("asinh(case when false then 1 else null end)", "DOUBLE"); + f.checkType("asinh('abc')", "DOUBLE NOT NULL"); + f.checkScalarApprox("asinh(-2.5)", "DOUBLE NOT NULL", + isWithin(-1.6472d, 0.0001d)); + f.checkScalarApprox("asinh(cast(10 as decimal))", "DOUBLE NOT NULL", + isWithin(2.9982, 0.0001d)); + f.checkNull("asinh(cast(null as integer))"); + f.checkNull("asinh(cast(null as double))"); + }; + f0.forEachLibrary(list(SqlLibrary.ALL), consumer); + } + + @Test void testAtanhFunc() { + final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.ATANH); + f0.checkFails("^atanh(1)^", + "No match found for function signature ATANH\\(<NUMERIC>\\)", + false); + final Consumer<SqlOperatorFixture> consumer = f -> { + f.checkType("atanh(0.1)", "DOUBLE NOT NULL"); + f.checkType("atanh(cast(0 as Decimal))", "DOUBLE NOT NULL"); + f.checkType("atanh(case when false then 0 else null end)", "DOUBLE"); + f.checkType("atanh('abc')", "DOUBLE NOT NULL"); + f.checkScalarApprox("atanh(0.76159416)", "DOUBLE NOT NULL", + isWithin(1d, 0.0001d)); + f.checkScalarApprox("atanh(cast(-0.1 as decimal))", "DOUBLE NOT NULL", + isWithin(-0.1003d, 0.0001d)); + f.checkNull("atanh(cast(null as integer))"); + f.checkNull("atanh(cast(null as double))"); + f.checkFails("atanh(1)", + "Input parameter of atanh cannot be out of the range \\(-1, 1\\)!", + true); + f.checkFails("atanh(-1)", + "Input parameter of atanh cannot be out of the range \\(-1, 1\\)!", + true); + }; + f0.forEachLibrary(list(SqlLibrary.ALL), consumer); + } + @Test void testCbrtFunc() { final SqlOperatorFixture f = fixture(); f.setFor(SqlStdOperatorTable.CBRT, VmName.EXPAND);