Skip to content

Commit

Permalink
[CALCITE-6077] Add FACTORIAL function (enabled in Hive and Spark libr…
Browse files Browse the repository at this point in the history
…aries)
  • Loading branch information
herunkang2018 committed Oct 28, 2023
1 parent 7b9660f commit b6619ad
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
import static org.apache.calcite.sql.fun.SqlLibraryOperators.EXISTS_NODE;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.EXTRACT_VALUE;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.EXTRACT_XML;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.FACTORIAL;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.FLOOR_BIG_QUERY;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.FORMAT_DATE;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.FORMAT_DATETIME;
Expand Down Expand Up @@ -655,6 +656,7 @@ Builder populate() {
defineMethod(CSC, BuiltInMethod.CSC.method, NullPolicy.STRICT);
defineMethod(CSCH, BuiltInMethod.CSCH.method, NullPolicy.STRICT);
defineMethod(DEGREES, BuiltInMethod.DEGREES.method, NullPolicy.STRICT);
defineMethod(FACTORIAL, BuiltInMethod.FACTORIAL.method, NullPolicy.STRICT);
defineMethod(IS_INF, BuiltInMethod.IS_INF.method, NullPolicy.STRICT);
defineMethod(IS_NAN, BuiltInMethod.IS_NAN.method, NullPolicy.STRICT);
defineMethod(POW, BuiltInMethod.POWER.method, NullPolicy.STRICT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.language.Soundex;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.math3.util.CombinatoricsUtils;
import org.apache.commons.text.similarity.LevenshteinDistance;

import com.google.common.base.Splitter;
Expand Down Expand Up @@ -3046,6 +3047,14 @@ public static double degrees(double b0) {
return Math.toDegrees(b0);
}

/** SQL <code>FACTORIAL</code> operator. */
public static @Nullable Long factorial(int b0) {
if (b0 < 0 || b0 > 20) {
return null;
}
return CombinatoricsUtils.factorial(b0);
}

/** SQL <code>IS_INF</code> operator applied to BigDecimal values. */
public static boolean isInf(BigDecimal b0) {
return Double.isInfinite(b0.doubleValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2028,6 +2028,16 @@ private static RelDataType deriveTypeMapFromEntries(SqlOperatorBinding opBinding
OperandTypes.NUMERIC,
SqlFunctionCategory.NUMERIC);

/** The {@code FACTORIAL(integer)} function.
* Returns the factorial of integer, the range of integer is [0, 20].
* Otherwise, returns NULL. */
@LibraryOperator(libraries = {HIVE, SPARK})
public static final SqlFunction FACTORIAL =
SqlBasicFunction.create("FACTORIAL",
ReturnTypes.BIGINT_FORCE_NULLABLE,
OperandTypes.INTEGER,
SqlFunctionCategory.NUMERIC);

@LibraryOperator(libraries = {BIG_QUERY, MYSQL, POSTGRESQL})
public static final SqlFunction MD5 =
SqlBasicFunction.create("MD5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ public enum BuiltInMethod {
CSC(SqlFunctions.class, "csc", double.class),
CSCH(SqlFunctions.class, "csch", double.class),
DEGREES(SqlFunctions.class, "degrees", double.class),
FACTORIAL(SqlFunctions.class, "factorial", int.class),
IS_INF(SqlFunctions.class, "isInf", long.class),
IS_NAN(SqlFunctions.class, "isNaN", double.class),
OVERLAY(SqlFunctions.class, "overlay", String.class, String.class, int.class),
Expand Down
1 change: 1 addition & 0 deletions site/_docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2730,6 +2730,7 @@ BigQuery's type system uses confusingly different names for types and functions:
| o | EXTRACT(xml, xpath, [, namespaces ]) | Returns the XML fragment of the element or elements matched by the XPath expression. The optional namespace value that specifies a default mapping or namespace mapping for prefixes, which is used when evaluating the XPath expression
| o | EXISTSNODE(xml, xpath, [, namespaces ]) | Determines whether traversal of a XML document using a specified xpath results in any nodes. Returns 0 if no nodes remain after applying the XPath traversal on the document fragment of the element or elements matched by the XPath expression. Returns 1 if any nodes remain. The optional namespace value that specifies a default mapping or namespace mapping for prefixes, which is used when evaluating the XPath expression.
| m | EXTRACTVALUE(xml, xpathExpr)) | Returns the text of the first text node which is a child of the element or elements matched by the XPath expression.
| h s | FACTORIAL(integer) | Returns the factorial of *integer*, the range of *integer* is [0, 20]. Otherwise, returns NULL
| b | FLOOR(value) | Similar to standard `FLOOR(value)` except if *value* is an integer type, the return type is a double
| b | FORMAT_DATE(string, date) | Formats *date* according to the specified format *string*
| b | FORMAT_DATETIME(string, timestamp) | Formats *timestamp* according to the specified format *string*
Expand Down
21 changes: 21 additions & 0 deletions testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7569,6 +7569,27 @@ private static void checkIf(SqlOperatorFixture f) {
f.checkNull("degrees(cast(null as double))");
}

@Test void testFactorialFunc() {
final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.FACTORIAL);
f0.checkFails("^factorial(5)^",
"No match found for function signature FACTORIAL\\(<NUMERIC>\\)",
false);
final Consumer<SqlOperatorFixture> consumer = f -> {
f.checkScalar("factorial(0)", "1",
"BIGINT");
f.checkScalar("factorial(1)", "1",
"BIGINT");
f.checkScalar("factorial(5)", "120",
"BIGINT");
f.checkScalar("factorial(20)", "2432902008176640000",
"BIGINT");
f.checkNull("factorial(21)");
f.checkNull("factorial(-1)");
f.checkNull("factorial(cast(null as integer))");
};
f0.forEachLibrary(list(SqlLibrary.HIVE, SqlLibrary.SPARK), consumer);
}

@Test void testPiFunc() {
final SqlOperatorFixture f = fixture();
f.setFor(SqlStdOperatorTable.PI, VmName.EXPAND);
Expand Down

0 comments on commit b6619ad

Please sign in to comment.