This is an automated email from the ASF dual-hosted git repository. jiajunxie 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 baa6b104f3 [CALCITE-5710] Add ARRAY_MAX, ARRAY_MIN function (enabled in Spark library) baa6b104f3 is described below commit baa6b104f33a851e419bd95e18acf3766aa19838 Author: yongen.ly <yongen...@alibaba-inc.com> AuthorDate: Thu May 18 16:51:44 2023 +0800 [CALCITE-5710] Add ARRAY_MAX, ARRAY_MIN function (enabled in Spark library) --- .../calcite/adapter/enumerable/RexImpTable.java | 4 +++ .../org/apache/calcite/runtime/SqlFunctions.java | 28 +++++++++++++++++++ .../main/java/org/apache/calcite/sql/SqlKind.java | 6 +++++ .../calcite/sql/fun/SqlLibraryOperators.java | 14 ++++++++++ .../org/apache/calcite/sql/type/ReturnTypes.java | 17 +++++++++++- .../apache/calcite/sql/type/SqlTypeTransforms.java | 5 ++-- .../org/apache/calcite/util/BuiltInMethod.java | 2 ++ site/_docs/reference.md | 2 ++ .../org/apache/calcite/test/SqlOperatorTest.java | 31 ++++++++++++++++++++++ 9 files changed, 106 insertions(+), 3 deletions(-) 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 925bbec92e..cad65ffa60 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 @@ -123,6 +123,8 @@ import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_CONCAT; import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_CONCAT_AGG; import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_DISTINCT; import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_LENGTH; +import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_MAX; +import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_MIN; 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; @@ -691,6 +693,8 @@ public class RexImpTable { defineMethod(MEMBER_OF, BuiltInMethod.MEMBER_OF.method, NullPolicy.NONE); defineMethod(ARRAY_COMPACT, BuiltInMethod.ARRAY_COMPACT.method, NullPolicy.STRICT); defineMethod(ARRAY_DISTINCT, BuiltInMethod.ARRAY_DISTINCT.method, NullPolicy.STRICT); + defineMethod(ARRAY_MAX, BuiltInMethod.ARRAY_MAX.method, NullPolicy.STRICT); + defineMethod(ARRAY_MIN, BuiltInMethod.ARRAY_MIN.method, NullPolicy.STRICT); defineMethod(ARRAY_REPEAT, BuiltInMethod.ARRAY_REPEAT.method, NullPolicy.NONE); defineMethod(ARRAY_REVERSE, BuiltInMethod.ARRAY_REVERSE.method, NullPolicy.STRICT); defineMethod(ARRAY_SIZE, BuiltInMethod.COLLECTION_SIZE.method, 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 8c68768d1b..0db3921cca 100644 --- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java @@ -3886,6 +3886,34 @@ public class SqlFunctions { return new ArrayList<>(result); } + /** Support the ARRAY_MAX function. */ + public static @Nullable <T extends Object & Comparable<? super T>> T arrayMax( + List<? extends T> list) { + + T max = null; + for (int i = 0; i < list.size(); i++) { + T item = list.get(i); + if (item != null && (max == null || item.compareTo(max) > 0)) { + max = item; + } + } + return max; + } + + /** Support the ARRAY_MIN function. */ + public static @Nullable <T extends Object & Comparable<? super T>> T arrayMin( + List<? extends T> list) { + + T min = null; + for (int i = 0; i < list.size(); i++) { + T item = list.get(i); + if (item != null && (min == null || item.compareTo(min) < 0)) { + min = item; + } + } + return min; + } + /** Support the ARRAY_REPEAT function. */ public static @Nullable List<Object> repeat(Object element, Object count) { if (count == null) { diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java index b1f18b7136..7c2c698e1d 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java @@ -686,6 +686,12 @@ public enum SqlKind { /** {@code ARRAY_DISTINCT} function (Spark semantics). */ ARRAY_DISTINCT, + /** {@code ARRAY_MAX} function (Spark semantics). */ + ARRAY_MAX, + + /** {@code ARRAY_MIN} function (Spark semantics). */ + ARRAY_MIN, + /** {@code ARRAY_REPEAT} function (Spark semantics). */ ARRAY_REPEAT, 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 bcc6e3fa1f..ec0627a89b 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 @@ -886,6 +886,20 @@ public abstract class SqlLibraryOperators { ReturnTypes.INTEGER_NULLABLE, OperandTypes.ARRAY); + /** The "ARRAY_MAX(array)" function. */ + @LibraryOperator(libraries = {SPARK}) + public static final SqlFunction ARRAY_MAX = + SqlBasicFunction.create(SqlKind.ARRAY_MAX, + ReturnTypes.TO_COLLECTION_ELEMENT_FORCE_NULLABLE, + OperandTypes.ARRAY); + + /** The "ARRAY_MAX(array)" function. */ + @LibraryOperator(libraries = {SPARK}) + public static final SqlFunction ARRAY_MIN = + SqlBasicFunction.create(SqlKind.ARRAY_MIN, + ReturnTypes.TO_COLLECTION_ELEMENT_FORCE_NULLABLE, + OperandTypes.ARRAY); + /** The "ARRAY_REPEAT(element, count)" function. */ @LibraryOperator(libraries = {SPARK}) public static final SqlFunction ARRAY_REPEAT = diff --git a/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java b/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java index adf1ca3902..8fdab7ea51 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java +++ b/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java @@ -487,6 +487,21 @@ public abstract class ReturnTypes { -1); }; + /** + * Returns the element type of a ARRAY or MULTISET. + * + * <p>For example, given <code>INTEGER ARRAY or MULTISET ARRAY</code>, returns + * <code>INTEGER</code>. + */ + public static final SqlReturnTypeInference TO_COLLECTION_ELEMENT = + ARG0.andThen(SqlTypeTransforms.TO_COLLECTION_ELEMENT_TYPE); + + public static final SqlReturnTypeInference TO_COLLECTION_ELEMENT_NULLABLE = + TO_COLLECTION_ELEMENT.andThen(SqlTypeTransforms.TO_NULLABLE); + + public static final SqlReturnTypeInference TO_COLLECTION_ELEMENT_FORCE_NULLABLE = + TO_COLLECTION_ELEMENT.andThen(SqlTypeTransforms.FORCE_NULLABLE); + /** * Returns a MULTISET type. * @@ -500,7 +515,7 @@ public abstract class ReturnTypes { * Returns the element type of a MULTISET. */ public static final SqlReturnTypeInference MULTISET_ELEMENT_NULLABLE = - MULTISET.andThen(SqlTypeTransforms.TO_MULTISET_ELEMENT_TYPE); + MULTISET.andThen(SqlTypeTransforms.TO_COLLECTION_ELEMENT_TYPE); /** * Same as {@link #MULTISET} but returns with nullability if any of the diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeTransforms.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeTransforms.java index 4adb1133c5..f4602cfe81 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeTransforms.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeTransforms.java @@ -155,11 +155,12 @@ public abstract class SqlTypeTransforms { /** * Parameter type-inference transform strategy where a derived type must be - * a multiset type and the returned type is the multiset's element type. + * a multiset or array type and the returned type is element type. * * @see MultisetSqlType#getComponentType + * @see ArraySqlType#getComponentType */ - public static final SqlTypeTransform TO_MULTISET_ELEMENT_TYPE = + public static final SqlTypeTransform TO_COLLECTION_ELEMENT_TYPE = (opBinding, typeToTransform) -> requireNonNull( typeToTransform.getComponentType(), () -> "componentType for " + typeToTransform + " in opBinding " + opBinding); 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 ff13006a22..cfc51dfd38 100644 --- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java +++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java @@ -630,6 +630,8 @@ public enum BuiltInMethod { Collection.class), ARRAY_COMPACT(SqlFunctions.class, "compact", List.class), ARRAY_DISTINCT(SqlFunctions.class, "distinct", List.class), + ARRAY_MAX(SqlFunctions.class, "arrayMax", List.class), + ARRAY_MIN(SqlFunctions.class, "arrayMin", List.class), ARRAY_REPEAT(SqlFunctions.class, "repeat", Object.class, Integer.class), ARRAY_REVERSE(SqlFunctions.class, "reverse", List.class), MAP_ENTRIES(SqlFunctions.class, "mapEntries", Map.class), diff --git a/site/_docs/reference.md b/site/_docs/reference.md index cc143f2ee2..a2a816cbfb 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -2656,6 +2656,8 @@ BigQuery's type system uses confusingly different names for types and functions: | 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. | b | ARRAY_LENGTH(array) | Synonym for `CARDINALITY` +| s | ARRAY_MAX(array) | Returns the maximum value in the *array* +| s | ARRAY_MIN(array) | Returns the minimum value in the *array* | 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` 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 aa3ae30eeb..ad7ae34667 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -5376,6 +5376,37 @@ public class SqlOperatorTest { f.checkNull("array_distinct(null)"); } + /** Tests {@code ARRAY_MAX} function from Spark. */ + @Test void testArrayMaxFunc() { + final SqlOperatorFixture f0 = fixture(); + f0.setFor(SqlLibraryOperators.ARRAY_MAX); + f0.checkFails("^array_max(array[1, 2])^", + "No match found for function signature ARRAY_MAX\\(<INTEGER ARRAY>\\)", false); + + final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK); + f.checkScalar("array_max(array[1, 2])", "2", "INTEGER"); + f.checkScalar("array_max(array[1, 2, null])", "2", "INTEGER"); + f.checkScalar("array_max(array[1])", "1", "INTEGER"); + f.checkType("array_max(array())", "UNKNOWN"); + f.checkNull("array_max(array())"); + f.checkNull("array_max(cast(null as integer array))"); + } + + /** Tests {@code ARRAY_MIN} function from Spark. */ + @Test void testArrayMinFunc() { + final SqlOperatorFixture f0 = fixture(); + f0.setFor(SqlLibraryOperators.ARRAY_MIN); + f0.checkFails("^array_min(array[1, 2])^", + "No match found for function signature ARRAY_MIN\\(<INTEGER ARRAY>\\)", false); + + final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK); + f.checkScalar("array_min(array[1, 2])", "1", "INTEGER"); + f.checkScalar("array_min(array[1, 2, null])", "1", "INTEGER"); + f.checkType("array_min(array())", "UNKNOWN"); + f.checkNull("array_min(array())"); + f.checkNull("array_min(cast(null as integer array))"); + } + /** Tests {@code ARRAY_REPEAT} function from Spark. */ @Test void testArrayRepeatFunc() { final SqlOperatorFixture f0 = fixture();