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();

Reply via email to