You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2023/04/11 01:53:22 UTC
[calcite] branch main updated: [CALCITE-5565] Add LOG function (enabled in BigQuery library)
This is an automated email from the ASF dual-hosted git repository.
jhyde 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 74bc025fbb [CALCITE-5565] Add LOG function (enabled in BigQuery library)
74bc025fbb is described below
commit 74bc025fbb5af4f43762926e0bec75acf6ac3025
Author: Tanner Clary <ta...@google.com>
AuthorDate: Wed Mar 8 01:31:11 2023 +0000
[CALCITE-5565] Add LOG function (enabled in BigQuery library)
Close apache/calcite#3099
---
babel/src/test/resources/sql/big-query.iq | 62 ++++++++++++++++++++++
.../calcite/adapter/enumerable/RexImpTable.java | 42 ++++++++++++++-
.../org/apache/calcite/runtime/SqlFunctions.java | 31 +++++------
.../calcite/sql/fun/SqlLibraryOperators.java | 12 +++++
.../org/apache/calcite/sql/type/OperandTypes.java | 5 ++
.../org/apache/calcite/util/BuiltInMethod.java | 1 +
site/_docs/reference.md | 1 +
.../org/apache/calcite/test/SqlOperatorTest.java | 28 +++++++++-
8 files changed, 164 insertions(+), 18 deletions(-)
diff --git a/babel/src/test/resources/sql/big-query.iq b/babel/src/test/resources/sql/big-query.iq
index 82586abaf1..0df376e76a 100755
--- a/babel/src/test/resources/sql/big-query.iq
+++ b/babel/src/test/resources/sql/big-query.iq
@@ -730,6 +730,68 @@ SELECT SPLIT(x'abc2') as result;
Call to function 'SPLIT' with argument of type 'BINARY(2)' requires extra delimiter argument
!error
+#####################################################################
+# LN
+#
+# LN(x)
+#
+# Computes the natural logarithm of x. Generates an error if x is less than or
+# equal to zero.
+
+SELECT LN(100) as result;
++-------------------+
+| result |
++-------------------+
+| 4.605170185988092 |
++-------------------+
+(1 row)
+
+!ok
+
+#####################################################################
+# LOG
+#
+# LOG(x, y)
+#
+# If only x is present, LOG is a synonym of LN. If y is also
+# present, LOG computes the logarithm of x to base y.
+SELECT LOG(64, 8) as result;
++--------+
+| result |
++--------+
+| 2.0 |
++--------+
+(1 row)
+
+!ok
+
+SELECT LOG(100) as result;
++-------------------+
+| result |
++-------------------+
+| 4.605170185988092 |
++-------------------+
+(1 row)
+
+!ok
+
+#####################################################################
+# LOG10
+#
+# LOG10(x)
+#
+# Similar to LOG, but computes logarithm to base 10.
+
+SELECT LOG10(100) as result;
++--------+
+| result |
++--------+
+| 2.0 |
++--------+
+(1 row)
+
+!ok
+
#####################################################################
# STRING
#
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 c2cb550cca..b683216972 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
@@ -153,6 +153,7 @@ import static org.apache.calcite.sql.fun.SqlLibraryOperators.JSON_SET;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.JSON_STORAGE_SIZE;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.JSON_TYPE;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.LEFT;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.LOG;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.LOGICAL_AND;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.LOGICAL_OR;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.LPAD;
@@ -490,10 +491,12 @@ public class RexImpTable {
defineMethod(MOD, "mod", NullPolicy.STRICT);
defineMethod(EXP, "exp", NullPolicy.STRICT);
defineMethod(POWER, "power", NullPolicy.STRICT);
- defineMethod(LN, "ln", NullPolicy.STRICT);
- defineMethod(LOG10, "log10", NullPolicy.STRICT);
defineMethod(ABS, "abs", NullPolicy.STRICT);
+ map.put(LN, new LogImplementor());
+ map.put(LOG, new LogImplementor());
+ map.put(LOG10, new LogImplementor());
+
map.put(RAND, new RandImplementor());
map.put(RAND_INTEGER, new RandIntegerImplementor());
@@ -3684,6 +3687,41 @@ public class RexImpTable {
}
}
+ /** Implementor for the {@code LN}, {@code LOG}, and {@code LOG10} operators.
+ *
+ * <p>Handles all logarithm functions using log rules to determine the
+ * appropriate base (i.e. base e for LN).
+ */
+ private static class LogImplementor extends AbstractRexCallImplementor {
+ LogImplementor() {
+ super("log", NullPolicy.STRICT, true);
+ }
+
+ @Override Expression implementSafe(final RexToLixTranslator translator,
+ final RexCall call, final List<Expression> argValueList) {
+ return Expressions.call(BuiltInMethod.LOG.method, args(call, argValueList));
+ }
+
+ private static List<Expression> args(RexCall call,
+ List<Expression> argValueList) {
+ Expression operand0 = argValueList.get(0);
+ final Expressions.FluentList<Expression> list = Expressions.list(operand0);
+ switch (call.getOperator().getName()) {
+ case "LOG":
+ if (argValueList.size() == 2) {
+ return list.append(argValueList.get(1));
+ }
+ // fall through
+ case "LN":
+ return list.append(Expressions.constant(Math.exp(1)));
+ case "LOG10":
+ return list.append(Expressions.constant(BigDecimal.TEN));
+ default:
+ throw new AssertionError("Operator not found: " + call.getOperator());
+ }
+ }
+ }
+
/**
* Implementation that calls a given {@link java.lang.reflect.Method}.
*
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 fcd88bac1e..d2939dc314 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -1567,28 +1567,29 @@ public class SqlFunctions {
return Math.pow(b0.doubleValue(), b1.doubleValue());
}
- // LN
- /** SQL {@code LN(number)} function applied to double values. */
- public static double ln(double d) {
- return Math.log(d);
- }
+ // LN, LOG, LOG10
- /** SQL {@code LN(number)} function applied to BigDecimal values. */
- public static double ln(BigDecimal d) {
- return Math.log(d.doubleValue());
+ /** SQL {@code LOG(number, number2)} function applied to double values. */
+ public static double log(double d0, double d1) {
+ return Math.log(d0) / Math.log(d1);
}
- // LOG10
+ /** SQL {@code LOG(number, number2)} function applied to
+ * double and BigDecimal values. */
+ public static double log(double d0, BigDecimal d1) {
+ return Math.log(d0) / Math.log(d1.doubleValue());
+ }
- /** SQL <code>LOG10(numeric)</code> operator applied to double values. */
- public static double log10(double b0) {
- return Math.log10(b0);
+ /** SQL {@code LOG(number, number2)} function applied to
+ * BigDecimal and double values. */
+ public static double log(BigDecimal d0, double d1) {
+ return Math.log(d0.doubleValue()) / Math.log(d1);
}
- /** SQL {@code LOG10(number)} function applied to BigDecimal values. */
- public static double log10(BigDecimal d) {
- return Math.log10(d.doubleValue());
+ /** SQL {@code LOG(number, number2)} function applied to double values. */
+ public static double log(BigDecimal d0, BigDecimal d1) {
+ return Math.log(d0.doubleValue()) / Math.log(d1.doubleValue());
}
// MOD
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 af3aa62f27..ae45e899e7 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
@@ -1177,6 +1177,18 @@ public abstract class SqlLibraryOperators {
OperandTypes.STRING.or(OperandTypes.BINARY),
SqlFunctionCategory.STRING);
+ /** The "LOG(value [, value2])" function.
+ *
+ * @see SqlStdOperatorTable#LN
+ * @see SqlStdOperatorTable#LOG10
+ */
+ @LibraryOperator(libraries = {BIG_QUERY})
+ public static final SqlFunction LOG =
+ SqlBasicFunction.create("LOG",
+ ReturnTypes.DOUBLE_NULLABLE,
+ OperandTypes.NUMERIC_OPTIONAL_NUMERIC,
+ SqlFunctionCategory.NUMERIC);
+
@LibraryOperator(libraries = {BIG_QUERY})
public static final SqlFunction POW =
SqlStdOperatorTable.POWER.withName("POW");
diff --git a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
index c336f87b84..b891ba7699 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
@@ -354,6 +354,11 @@ public abstract class OperandTypes {
public static final SqlSingleOperandTypeChecker INTEGER =
family(SqlTypeFamily.INTEGER);
+ public static final SqlSingleOperandTypeChecker NUMERIC_OPTIONAL_NUMERIC =
+ family(ImmutableList.of(SqlTypeFamily.NUMERIC, SqlTypeFamily.NUMERIC),
+ // Second operand optional (operand index 0, 1)
+ number -> number == 1);
+
public static final SqlSingleOperandTypeChecker NUMERIC_OPTIONAL_INTEGER =
family(ImmutableList.of(SqlTypeFamily.NUMERIC, SqlTypeFamily.INTEGER),
// Second operand optional (operand index 0, 1)
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index 9edc77b636..dae7fdc0c0 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -432,6 +432,7 @@ public enum BuiltInMethod {
RAND_INTEGER(RandomFunction.class, "randInteger", int.class),
RAND_INTEGER_SEED(RandomFunction.class, "randIntegerSeed", int.class,
int.class),
+ LOG(SqlFunctions.class, "log", long.class, long.class),
TANH(SqlFunctions.class, "tanh", long.class),
SINH(SqlFunctions.class, "sinh", long.class),
TRUNCATE(SqlFunctions.class, "truncate", String.class, int.class),
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index c1a441db80..f9ea1d9d60 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2706,6 +2706,7 @@ BigQuery's type system uses confusingly different names for types and functions:
| b o | LEAST(expr [, expr ]* ) | Returns the least of the expressions
| b m p | LEFT(string, length) | Returns the leftmost *length* characters from the *string*
| b | LENGTH(string) | Equivalent to `CHAR_LENGTH(string)`
+| b | LOG(numeric1 [, numeric2 ]) | Returns the logarithm of *numeric1* to base *numeric2*, or base e if *numeric2* is not present
| b o | LPAD(string, length[, pattern ]) | Returns a string or bytes value that consists of *string* prepended to *length* with *pattern*
| m | TO_BASE64(string) | Converts the *string* to base-64 encoded form and returns a encoded string
| b m | FROM_BASE64(string) | Returns the decoded result of a base-64 *string* as a string
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 8cd4bff390..a586c264f7 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -5061,7 +5061,7 @@ public class SqlOperatorTest {
f.checkNull("ln(cast(null as tinyint))");
}
- @Test void testLogFunc() {
+ @Test void testLog10Func() {
final SqlOperatorFixture f = fixture();
f.setFor(SqlStdOperatorTable.LOG10, VmName.EXPAND);
f.checkScalarApprox("log10(10)", "DOUBLE NOT NULL",
@@ -5077,6 +5077,32 @@ public class SqlOperatorTest {
f.checkNull("log10(cast(null as real))");
}
+ @Test void testLogFunc() {
+ final SqlOperatorFixture f0 = fixture()
+ .setFor(SqlLibraryOperators.LOG, VmName.EXPAND);
+ f0.checkFails("^log(100, 10)^",
+ "No match found for function signature LOG\\(<NUMERIC>, <NUMERIC>\\)", false);
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.BIG_QUERY);
+ f.checkScalarApprox("log(10, 10)", "DOUBLE NOT NULL",
+ isWithin(1.0, 0.000001));
+ f.checkScalarApprox("log(64, 8)", "DOUBLE NOT NULL",
+ isWithin(2.0, 0.000001));
+ f.checkScalarApprox("log(27,3)", "DOUBLE NOT NULL",
+ isWithin(3.0, 0.000001));
+ f.checkScalarApprox("log(100, 10)", "DOUBLE NOT NULL",
+ isWithin(2.0, 0.000001));
+ f.checkScalarApprox("log(10, 100)", "DOUBLE NOT NULL",
+ isWithin(0.5, 0.000001));
+ f.checkScalarApprox("log(cast(10e6 as double), 10)", "DOUBLE NOT NULL",
+ isWithin(7.0, 0.000001));
+ f.checkScalarApprox("log(cast(10e8 as float), 10)", "DOUBLE NOT NULL",
+ isWithin(9.0, 0.000001));
+ f.checkScalarApprox("log(cast(10e-3 as real), 10)", "DOUBLE NOT NULL",
+ isWithin(-2.0, 0.000001));
+ f.checkNull("log(cast(null as real), 10)");
+ f.checkNull("log(10, cast(null as real))");
+ }
+
@Test void testRandFunc() {
final SqlOperatorFixture f = fixture();
f.setFor(SqlStdOperatorTable.RAND, VmName.EXPAND);