[CALCITE-6314] Add RANDOM function (enabled in Postgres library)
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 1bc88f1..9cabfcb 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
@@ -232,6 +232,7 @@
import static org.apache.calcite.sql.fun.SqlLibraryOperators.PARSE_TIMESTAMP;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.PARSE_URL;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.POW;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.RANDOM;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.REGEXP;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.REGEXP_CONTAINS;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.REGEXP_EXTRACT;
@@ -652,6 +653,7 @@
BuiltInMethod.RAND_SEED.method);
defineReflective(RAND_INTEGER, BuiltInMethod.RAND_INTEGER.method,
BuiltInMethod.RAND_INTEGER_SEED.method);
+ defineReflective(RANDOM, BuiltInMethod.RAND.method);
defineMethod(ACOS, BuiltInMethod.ACOS.method, NullPolicy.STRICT);
defineMethod(ACOSH, BuiltInMethod.ACOSH.method, NullPolicy.STRICT);
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlBasicFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlBasicFunction.java
index 7e3da75..f2f54a6 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlBasicFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlBasicFunction.java
@@ -48,6 +48,7 @@
private final SqlOperandHandler operandHandler;
private final int callValidator;
private final Function<SqlOperatorBinding, SqlMonotonicity> monotonicityInference;
+ private final boolean dynamic;
//~ Constructors -----------------------------------------------------------
@@ -73,7 +74,8 @@
SqlOperandTypeChecker operandTypeChecker,
Integer callValidator,
SqlFunctionCategory category,
- Function<SqlOperatorBinding, SqlMonotonicity> monotonicityInference) {
+ Function<SqlOperatorBinding, SqlMonotonicity> monotonicityInference,
+ boolean dynamic) {
super(name, kind,
requireNonNull(returnTypeInference, "returnTypeInference"),
operandTypeInference,
@@ -84,6 +86,7 @@
this.callValidator = requireNonNull(callValidator, "callValidator");
this.monotonicityInference =
requireNonNull(monotonicityInference, "monotonicityInference");
+ this.dynamic = dynamic;
}
/** Creates a {@code SqlBasicFunction} whose name is the same as its kind
@@ -94,7 +97,7 @@
return new SqlBasicFunction(kind.name(), kind,
SqlSyntax.FUNCTION, true, returnTypeInference, null,
OperandHandlers.DEFAULT, operandTypeChecker, 0,
- SqlFunctionCategory.SYSTEM, call -> SqlMonotonicity.NOT_MONOTONIC);
+ SqlFunctionCategory.SYSTEM, call -> SqlMonotonicity.NOT_MONOTONIC, false);
}
/** Creates a {@code SqlBasicFunction}
@@ -106,7 +109,7 @@
return new SqlBasicFunction(name, SqlKind.OTHER_FUNCTION,
SqlSyntax.FUNCTION, true, returnTypeInference, null,
OperandHandlers.DEFAULT, operandTypeChecker, 0,
- SqlFunctionCategory.NUMERIC, call -> SqlMonotonicity.NOT_MONOTONIC);
+ SqlFunctionCategory.NUMERIC, call -> SqlMonotonicity.NOT_MONOTONIC, false);
}
/** Creates a {@code SqlBasicFunction}
@@ -117,7 +120,7 @@
return new SqlBasicFunction(name, SqlKind.OTHER_FUNCTION,
SqlSyntax.FUNCTION, true, returnTypeInference, null,
OperandHandlers.DEFAULT, operandTypeChecker, 0,
- category, call -> SqlMonotonicity.NOT_MONOTONIC);
+ category, call -> SqlMonotonicity.NOT_MONOTONIC, false);
}
//~ Methods ----------------------------------------------------------------
@@ -151,12 +154,16 @@
super.validateCall(call, validator, scope, operandScope);
}
+ @Override public boolean isDynamicFunction() {
+ return dynamic;
+ }
+
/** Returns a copy of this function with a given name. */
public SqlBasicFunction withName(String name) {
return new SqlBasicFunction(name, kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
- getFunctionType(), monotonicityInference);
+ getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given kind. */
@@ -164,14 +171,14 @@
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
- getFunctionType(), monotonicityInference);
+ getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given category. */
public SqlBasicFunction withFunctionType(SqlFunctionCategory category) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
- getOperandTypeChecker(), callValidator, category, monotonicityInference);
+ getOperandTypeChecker(), callValidator, category, monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given syntax. */
@@ -179,7 +186,7 @@
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
- getFunctionType(), monotonicityInference);
+ getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given strategy for inferring
@@ -189,7 +196,7 @@
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
returnTypeInference, getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
- getFunctionType(), monotonicityInference);
+ getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given strategy for inferring
@@ -199,7 +206,7 @@
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), operandTypeInference, operandHandler,
getOperandTypeChecker(), callValidator,
- getFunctionType(), monotonicityInference);
+ getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given strategy for handling
@@ -208,14 +215,14 @@
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
- getFunctionType(), monotonicityInference);
+ getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given determinism. */
public SqlBasicFunction withDeterministic(boolean deterministic) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
- getFunctionType(), monotonicityInference);
+ getFunctionType(), monotonicityInference, dynamic);
}
/** Returns a copy of this function with a given strategy for inferring
@@ -225,13 +232,27 @@
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
- getFunctionType(), monotonicityInference);
+ getFunctionType(), monotonicityInference, dynamic);
}
- public SqlFunction withValidation(int callValidator) {
+ public SqlBasicFunction withValidation(int callValidator) {
return new SqlBasicFunction(getName(), kind, syntax, deterministic,
getReturnTypeInference(), getOperandTypeInference(), operandHandler,
getOperandTypeChecker(), callValidator,
- getFunctionType(), monotonicityInference);
+ getFunctionType(), monotonicityInference, dynamic);
+ }
+
+ public SqlBasicFunction withDynamic(boolean dynamic) {
+ return new SqlBasicFunction(getName(), kind, syntax, deterministic,
+ getReturnTypeInference(), getOperandTypeInference(), operandHandler,
+ getOperandTypeChecker(), callValidator,
+ getFunctionType(), monotonicityInference, dynamic);
+ }
+
+ public SqlBasicFunction withOperandTypeChecker(SqlOperandTypeChecker operandTypeChecker) {
+ return new SqlBasicFunction(getName(), kind, syntax, deterministic,
+ getReturnTypeInference(), getOperandTypeInference(), operandHandler,
+ operandTypeChecker, callValidator,
+ getFunctionType(), monotonicityInference, dynamic);
}
}
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 0c700d9..b32658f 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
@@ -2311,4 +2311,10 @@
@LibraryOperator(libraries = {SPARK})
public static final SqlFunction GETBIT =
BIT_GET.withName("GETBIT");
+
+ /** The RANDOM() function. Equivalent to RAND(). */
+ @LibraryOperator(libraries = {POSTGRESQL})
+ public static final SqlFunction RANDOM = SqlStdOperatorTable.RAND
+ .withName("RANDOM")
+ .withOperandTypeChecker(OperandTypes.NILADIC);
}
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlRandFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlRandFunction.java
deleted file mode 100644
index 096d6f9..0000000
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlRandFunction.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.sql.fun;
-
-import org.apache.calcite.sql.SqlFunction;
-import org.apache.calcite.sql.SqlFunctionCategory;
-import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.type.OperandTypes;
-import org.apache.calcite.sql.type.ReturnTypes;
-
-/**
- * The <code>RAND</code> function. There are two overloads:
- *
- * <ul>
- * <li>RAND() returns a random double between 0 and 1
- * <li>RAND(seed) returns a random double between 0 and 1, initializing the
- * random number generator with seed on first call
- * </ul>
- */
-public class SqlRandFunction extends SqlFunction {
- //~ Constructors -----------------------------------------------------------
-
- public SqlRandFunction() {
- super("RAND",
- SqlKind.OTHER_FUNCTION,
- ReturnTypes.DOUBLE,
- null,
- OperandTypes.NILADIC.or(OperandTypes.NUMERIC),
- SqlFunctionCategory.NUMERIC);
- }
-
- //~ Methods ----------------------------------------------------------------
-
- // Plans referencing context variables should never be cached
- @Override public boolean isDynamicFunction() {
- return true;
- }
-}
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index bf40fb2..93f5105 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -317,7 +317,10 @@
/** The {@code RAND([seed])} function, which yields a random double,
* optionally with seed. */
- public static final SqlRandFunction RAND = new SqlRandFunction();
+ public static final SqlBasicFunction RAND = SqlBasicFunction
+ .create("RAND", ReturnTypes.DOUBLE,
+ OperandTypes.NILADIC.or(OperandTypes.NUMERIC), SqlFunctionCategory.NUMERIC)
+ .withDynamic(true);
/**
* Internal integer arithmetic division operator, '<code>/INT</code>'. This
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index d8712e5..542b1f6 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2815,6 +2815,7 @@
| b | PARSE_TIMESTAMP(format, string[, timeZone]) | Uses format specified by *format* to convert *string* representation of timestamp to a TIMESTAMP WITH LOCAL TIME ZONE value in *timeZone*
| h s | PARSE_URL(urlString, partToExtract [, keyToExtract] ) | Returns the specified *partToExtract* from the *urlString*. Valid values for *partToExtract* include HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO. *keyToExtract* specifies which query to extract
| b s | POW(numeric1, numeric2) | Returns *numeric1* raised to the power *numeric2*
+| p | RANDOM() | Generates a random double between 0 and 1 inclusive
| s | REGEXP(string, regexp) | Equivalent to `string1 RLIKE string2`
| b | REGEXP_CONTAINS(string, regexp) | Returns whether *string* is a partial match for the *regexp*
| b | REGEXP_EXTRACT(string, regexp [, position [, occurrence]]) | Returns the substring in *string* that matches the *regexp*, starting search at *position* (default 1), and until locating the nth *occurrence* (default 1). Returns NULL if there is no match
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 01f308a..5a772c8 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -6359,6 +6359,22 @@
}
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-6314">[CALCITE-6314]
+ * Add RANDOM function (enabled in Postgres library)</a>. */
+ @Test void testRandomFunc() {
+ final SqlOperatorFixture f = fixture();
+ f.setFor(SqlLibraryOperators.RANDOM, VmName.EXPAND);
+ f.checkFails("^random^", "Column 'RANDOM' not found in any table", false);
+ Consumer<SqlOperatorFixture> consumer = fixture -> {
+ for (int i = 0; i < 100; i++) {
+ // Result must always be between 0 and 1, inclusive.
+ fixture.checkScalarApprox("random()", "DOUBLE NOT NULL", isWithin(0.5, 0.5));
+ }
+ };
+ f.forEachLibrary(list(SqlLibrary.POSTGRESQL), consumer);
+ }
+
@Test void testRandIntegerSeedFunc() {
final SqlOperatorFixture f = fixture();
f.setFor(SqlStdOperatorTable.RAND_INTEGER, VmName.EXPAND);