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 a2d2a31a70 [CALCITE-5751] Add ARRAY_APPEND, ARRAY_POSITION,
ARRAY_REMOVE, ARRAY_PREPEND function (enabled in Spark library)
a2d2a31a70 is described below
commit a2d2a31a70be3b20f3f2b8f311bf580dd9ae1e24
Author: yongen.ly <[email protected]>
AuthorDate: Sun Jun 11 10:23:19 2023 +0800
[CALCITE-5751] Add ARRAY_APPEND, ARRAY_POSITION, ARRAY_REMOVE,
ARRAY_PREPEND function (enabled in Spark library)
---
.../calcite/adapter/enumerable/RexImpTable.java | 8 ++
.../org/apache/calcite/runtime/SqlFunctions.java | 36 ++++++
.../main/java/org/apache/calcite/sql/SqlKind.java | 12 ++
.../calcite/sql/fun/SqlLibraryOperators.java | 45 ++++++++
.../org/apache/calcite/sql/type/ReturnTypes.java | 8 ++
.../org/apache/calcite/util/BuiltInMethod.java | 4 +
site/_docs/reference.md | 4 +
.../org/apache/calcite/test/SqlOperatorTest.java | 126 +++++++++++++++++++++
8 files changed, 243 insertions(+)
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 1144b140fd..3a27c361b1 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
@@ -118,6 +118,7 @@ import static
org.apache.calcite.sql.fun.SqlInternalOperators.THROW_UNLESS;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.ACOSH;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_AGG;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_APPEND;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_COMPACT;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_CONCAT;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_CONCAT_AGG;
@@ -128,6 +129,9 @@ import static
org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_INTERSECT;
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_POSITION;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_PREPEND;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_REMOVE;
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;
@@ -698,6 +702,7 @@ public class RexImpTable {
defineMethod(ELEMENT, BuiltInMethod.ELEMENT.method, NullPolicy.STRICT);
defineMethod(STRUCT_ACCESS, BuiltInMethod.STRUCT_ACCESS.method,
NullPolicy.ANY);
defineMethod(MEMBER_OF, BuiltInMethod.MEMBER_OF.method, NullPolicy.NONE);
+ defineMethod(ARRAY_APPEND, BuiltInMethod.ARRAY_APPEND.method,
NullPolicy.ARG0);
defineMethod(ARRAY_COMPACT, BuiltInMethod.ARRAY_COMPACT.method,
NullPolicy.STRICT);
defineMethod(ARRAY_CONTAINS, BuiltInMethod.LIST_CONTAINS.method,
NullPolicy.ANY);
defineMethod(ARRAY_DISTINCT, BuiltInMethod.ARRAY_DISTINCT.method,
NullPolicy.STRICT);
@@ -706,6 +711,9 @@ public class RexImpTable {
defineMethod(ARRAY_LENGTH, BuiltInMethod.COLLECTION_SIZE.method,
NullPolicy.STRICT);
defineMethod(ARRAY_MAX, BuiltInMethod.ARRAY_MAX.method,
NullPolicy.STRICT);
defineMethod(ARRAY_MIN, BuiltInMethod.ARRAY_MIN.method,
NullPolicy.STRICT);
+ defineMethod(ARRAY_PREPEND, BuiltInMethod.ARRAY_PREPEND.method,
NullPolicy.ARG0);
+ defineMethod(ARRAY_POSITION, BuiltInMethod.ARRAY_POSITION.method,
NullPolicy.ANY);
+ defineMethod(ARRAY_REMOVE, BuiltInMethod.ARRAY_REMOVE.method,
NullPolicy.ANY);
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 6157af6061..e7473b4790 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -3904,6 +3904,14 @@ public class SqlFunctions {
return result;
}
+ /** Support the ARRAY_APPEND function. */
+ public static List arrayAppend(List list, Object element) {
+ final List result = new ArrayList(list.size() + 1);
+ result.addAll(list);
+ result.add(element);
+ return result;
+ }
+
/** Support the ARRAY_DISTINCT function.
*
* <p>Note: If the list does not contain null,
@@ -3941,6 +3949,34 @@ public class SqlFunctions {
return min;
}
+ /** Support the ARRAY_PREPEND function. */
+ public static List arrayPrepend(List list, Object element) {
+ final List result = new ArrayList(list.size() + 1);
+ result.add(element);
+ result.addAll(list);
+ return result;
+ }
+
+ /** Support the ARRAY_POSITION function. */
+ public static Long arrayPosition(List list, Object element) {
+ final int index = list.indexOf(element);
+ if (index != -1) {
+ return Long.valueOf(index + 1L);
+ }
+ return 0L;
+ }
+
+ /** Support the ARRAY_REMOVE function. */
+ public static List arrayRemove(List list, Object element) {
+ final List result = new ArrayList();
+ for (Object obj : list) {
+ if (obj == null || !obj.equals(element)) {
+ result.add(obj);
+ }
+ }
+ return result;
+ }
+
/** 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 06d4271e4a..ed48b413bf 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -683,6 +683,9 @@ public enum SqlKind {
/** {@code EXTRACT} function. */
EXTRACT,
+ /** {@code ARRAY_APPEND} function (Spark semantics). */
+ ARRAY_APPEND,
+
/** {@code ARRAY_COMPACT} function (Spark semantics). */
ARRAY_COMPACT,
@@ -710,6 +713,15 @@ public enum SqlKind {
/** {@code ARRAY_MIN} function (Spark semantics). */
ARRAY_MIN,
+ /** {@code ARRAY_POSITION} function (Spark semantics). */
+ ARRAY_POSITION,
+
+ /** {@code ARRAY_PREPEND} function (Spark semantics). */
+ ARRAY_PREPEND,
+
+ /** {@code ARRAY_REMOVE} function (Spark semantics). */
+ ARRAY_REMOVE,
+
/** {@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 71f5f1541a..ebcbf20e7f 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
@@ -47,6 +47,8 @@ import org.apache.calcite.util.Litmus;
import org.apache.calcite.util.Optionality;
import org.apache.calcite.util.Static;
+import com.google.common.collect.ImmutableList;
+
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
@@ -907,6 +909,28 @@ public abstract class SqlLibraryOperators {
SqlLibraryOperators::arrayReturnType,
OperandTypes.SAME_VARIADIC);
+ @SuppressWarnings("argument.type.incompatible")
+ private static RelDataType arrayAppendPrependReturnType(SqlOperatorBinding
opBinding) {
+ final RelDataType arrayType = opBinding.collectOperandTypes().get(0);
+ final RelDataType componentType = arrayType.getComponentType();
+ final RelDataType elementType = opBinding.collectOperandTypes().get(1);
+ RelDataType type =
+ opBinding.getTypeFactory().leastRestrictive(
+ ImmutableList.of(componentType, elementType));
+ if (elementType.isNullable()) {
+ type = opBinding.getTypeFactory().createTypeWithNullability(type, true);
+ }
+ requireNonNull(type, "inferred array element type");
+ return SqlTypeUtil.createArrayType(opBinding.getTypeFactory(), type,
arrayType.isNullable());
+ }
+
+ /** The "ARRAY_APPEND(array, element)" function. */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction ARRAY_APPEND =
+ SqlBasicFunction.create(SqlKind.ARRAY_APPEND,
+ SqlLibraryOperators::arrayAppendPrependReturnType,
+ OperandTypes.ARRAY_ELEMENT);
+
/** The "ARRAY_COMPACT(array)" function. */
@LibraryOperator(libraries = {SPARK})
public static final SqlFunction ARRAY_COMPACT =
@@ -974,6 +998,27 @@ public abstract class SqlLibraryOperators {
ReturnTypes.TO_COLLECTION_ELEMENT_FORCE_NULLABLE,
OperandTypes.ARRAY);
+ /** The "ARRAY_POSITION(array, element)" function. */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction ARRAY_POSITION =
+ SqlBasicFunction.create(SqlKind.ARRAY_POSITION,
+ ReturnTypes.BIGINT_NULLABLE,
+ OperandTypes.ARRAY_ELEMENT);
+
+ /** The "ARRAY_PREPEND(array, element)" function. */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction ARRAY_PREPEND =
+ SqlBasicFunction.create(SqlKind.ARRAY_PREPEND,
+ SqlLibraryOperators::arrayAppendPrependReturnType,
+ OperandTypes.ARRAY_ELEMENT);
+
+ /** The "ARRAY_REMOVE(array, element)" function. */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction ARRAY_REMOVE =
+ SqlBasicFunction.create(SqlKind.ARRAY_REMOVE,
+ ReturnTypes.ARG0_NULLABLE,
+ OperandTypes.ARRAY_ELEMENT);
+
/** 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 6699bd8fcf..da77594623 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
@@ -177,6 +177,14 @@ public abstract class ReturnTypes {
public static final SqlReturnTypeInference ARG0_NULLABLE =
ARG0.andThen(SqlTypeTransforms.TO_NULLABLE);
+ /**
+ * Type-inference strategy whereby the result type of a call is the type of
+ * the operand #0 (0-based). If the operand #0 (0-based) is nullable, the
+ * returned type will also be nullable.
+ */
+ public static final SqlReturnTypeInference ARG0_NULLABLE_IF_ARG0_NULLABLE =
+ ARG0.andThen(SqlTypeTransforms.ARG0_NULLABLE);
+
/**
* Type-inference strategy whereby the result type of a call is the type of
* the operand #0 (0-based), with nulls always allowed.
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 e74bc6d553..4e50e002f8 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -631,10 +631,14 @@ public enum BuiltInMethod {
IS_EMPTY(Collection.class, "isEmpty"),
SUBMULTISET_OF(SqlFunctions.class, "submultisetOf", Collection.class,
Collection.class),
+ ARRAY_APPEND(SqlFunctions.class, "arrayAppend", List.class, Object.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_POSITION(SqlFunctions.class, "arrayPosition", List.class,
Object.class),
+ ARRAY_PREPEND(SqlFunctions.class, "arrayPrepend", List.class, Object.class),
+ ARRAY_REMOVE(SqlFunctions.class, "arrayRemove", List.class, Object.class),
ARRAY_REPEAT(SqlFunctions.class, "repeat", Object.class, Integer.class),
ARRAY_EXCEPT(SqlFunctions.class, "arrayExcept", List.class, List.class),
ARRAY_INTERSECT(SqlFunctions.class, "arrayIntersect", List.class,
List.class),
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index fb2e94cbf5..351cbb8b23 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2652,6 +2652,7 @@ BigQuery's type system uses confusingly different names
for types and functions:
| m | expr1 <=> expr2 | Whether two values are
equal, treating null values as the same, and it's similar to `IS NOT DISTINCT
FROM`
| * | ACOSH(numeric) | Returns the inverse
hyperbolic cosine of *numeric*
| s | ARRAY(expr [, expr ]*) | Construct an array in
Apache Spark
+| s | ARRAY_APPEND(array, element) | Appends an *element* to
the end of the *array* and returns the result. Type of *element* should be
similar to type of the elements of the *array*. If the *array* is null, the
function will return null. If an *element* that is null, the null *element*
will be added to the end of the *array*
| s | ARRAY_COMPACT(array) | Removes null values
from the *array*
| b | ARRAY_CONCAT(array [, array ]*) | Concatenates one or
more arrays. If any input argument is `NULL` the function returns `NULL`
| s | ARRAY_CONTAINS(array, element) | Returns true if the
*array* contains the *element*
@@ -2661,6 +2662,9 @@ BigQuery's type system uses confusingly different names
for types and functions:
| 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_POSITION(array, element) | Returns the (1-based)
index of the first *element* of the *array* as long
+| s | ARRAY_REMOVE(array, element) | Remove all elements
that equal to *element* from the *array*
+| s | ARRAY_PREPEND(array, element) | Appends an *element* to
the beginning of the *array* and returns the result. Type of *element* should
be similar to type of the elements of the *array*. If the *array* is null, the
function will return null. If an *element* that is null, the null *element*
will be added to the beginning of 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 49c7d30c03..77d9734afe 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -5353,6 +5353,35 @@ public class SqlOperatorTest {
f.checkScalar("rand_integer(2, 11)", 1, "INTEGER NOT NULL");
}
+ /** Tests {@code ARRAY_APPEND} function from Spark. */
+ @Test void testArrayAppendFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.ARRAY_APPEND);
+ f0.checkFails("^array_append(array[1], 2)^",
+ "No match found for function signature ARRAY_APPEND\\("
+ + "<INTEGER ARRAY>, <NUMERIC>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("array_append(array[1], 2)", "[1, 2]",
+ "INTEGER NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_append(array[1], null)", "[1, null]",
+ "INTEGER ARRAY NOT NULL");
+ f.checkScalar("array_append(array(null), null)", "[null, null]",
+ "NULL ARRAY NOT NULL");
+ f.checkScalar("array_append(array(), null)", "[null]",
+ "UNKNOWN ARRAY NOT NULL");
+ f.checkScalar("array_append(array(), 1)", "[1]",
+ "INTEGER NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_append(array[array[1, 2]], array[3, 4])", "[[1, 2],
[3, 4]]",
+ "INTEGER NOT NULL ARRAY NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_append(array[map[1, 'a']], map[2, 'b'])", "[{1=a},
{2=b}]",
+ "(INTEGER NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL ARRAY NOT NULL");
+ f.checkNull("array_append(cast(null as integer array), 1)");
+ f.checkType("array_append(cast(null as integer array), 1)", "INTEGER NOT
NULL ARRAY");
+ f.checkFails("^array_append(array[1, 2], true)^",
+ "INTEGER is not comparable to BOOLEAN", false);
+ }
+
/** Tests {@code ARRAY_COMPACT} function from Spark. */
@Test void testArrayCompactFunc() {
final SqlOperatorFixture f0 = fixture();
@@ -5465,6 +5494,103 @@ public class SqlOperatorTest {
f.checkNull("array_min(cast(null as integer array))");
}
+ /** Tests {@code ARRAY_POSITION} function from Spark. */
+ @Test void testArrayPositionFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.ARRAY_POSITION);
+ f0.checkFails("^array_position(array[1], 1)^",
+ "No match found for function signature ARRAY_POSITION\\("
+ + "<INTEGER ARRAY>, <NUMERIC>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("array_position(array[1], 1)", "1",
+ "BIGINT NOT NULL");
+ f.checkScalar("array_position(array[1, 2, 2], 2)", "2",
+ "BIGINT NOT NULL");
+ f.checkScalar("array_position(array[1], 2)", "0",
+ "BIGINT NOT NULL");
+ f.checkScalar("array_position(array(), 1)", "0",
+ "BIGINT NOT NULL");
+ f.checkScalar("array_position(array[array[1, 2]], array[1, 2])", "1",
+ "BIGINT NOT NULL");
+ f.checkScalar("array_position(array[map[1, 'a']], map[1, 'a'])", "1",
+ "BIGINT NOT NULL");
+ f.checkNull("array_position(cast(null as integer array), 1)");
+ f.checkType("array_position(cast(null as integer array), 1)", "BIGINT");
+ f.checkNull("array_position(array[1], null)");
+ f.checkType("array_position(array[1], null)", "BIGINT");
+ f.checkFails("^array_position(array[1, 2], true)^",
+ "INTEGER is not comparable to BOOLEAN", false);
+ }
+
+ /** Tests {@code ARRAY_PREPEND} function from Spark. */
+ @Test void testArrayPrependFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.ARRAY_PREPEND);
+ f0.checkFails("^array_prepend(array[1], 2)^",
+ "No match found for function signature ARRAY_PREPEND\\("
+ + "<INTEGER ARRAY>, <NUMERIC>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("array_prepend(array[1], 2)", "[2, 1]",
+ "INTEGER NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_prepend(array[1], null)", "[null, 1]",
+ "INTEGER ARRAY NOT NULL");
+ f.checkScalar("array_prepend(array(null), null)", "[null, null]",
+ "NULL ARRAY NOT NULL");
+ f.checkScalar("array_prepend(array(), null)", "[null]",
+ "UNKNOWN ARRAY NOT NULL");
+ f.checkScalar("array_append(array(), 1)", "[1]",
+ "INTEGER NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_prepend(array[array[1, 2]], array[3, 4])", "[[3, 4],
[1, 2]]",
+ "INTEGER NOT NULL ARRAY NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_prepend(array[map[1, 'a']], map[2, 'b'])", "[{2=b},
{1=a}]",
+ "(INTEGER NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL ARRAY NOT NULL");
+ f.checkNull("array_prepend(cast(null as integer array), 1)");
+ f.checkType("array_prepend(cast(null as integer array), 1)", "INTEGER NOT
NULL ARRAY");
+ f.checkFails("^array_prepend(array[1, 2], true)^",
+ "INTEGER is not comparable to BOOLEAN", false);
+ }
+
+ /** Tests {@code ARRAY_REMOVE} function from Spark. */
+ @Test void testArrayRemoveFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.ARRAY_REMOVE);
+ f0.checkFails("^array_remove(array[1], 1)^",
+ "No match found for function signature ARRAY_REMOVE\\("
+ + "<INTEGER ARRAY>, <NUMERIC>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("array_remove(array[1], 1)", "[]",
+ "INTEGER NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_remove(array[1, 2, 1], 1)", "[2]",
+ "INTEGER NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_remove(array[1, 2, null], 1)", "[2, null]",
+ "INTEGER ARRAY NOT NULL");
+ f.checkScalar("array_remove(array[1, 2, null], 3)", "[1, 2, null]",
+ "INTEGER ARRAY NOT NULL");
+ f.checkScalar("array_remove(array(null), 1)", "[null]",
+ "NULL ARRAY NOT NULL");
+ f.checkScalar("array_remove(array(), 1)", "[]",
+ "UNKNOWN NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_remove(array[array[1, 2]], array[1, 2])", "[]",
+ "INTEGER NOT NULL ARRAY NOT NULL ARRAY NOT NULL");
+ f.checkScalar("array_remove(array[map[1, 'a']], map[1, 'a'])", "[]",
+ "(INTEGER NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL ARRAY NOT NULL");
+ f.checkNull("array_remove(cast(null as integer array), 1)");
+ f.checkType("array_remove(cast(null as integer array), 1)", "INTEGER NOT
NULL ARRAY");
+
+ // Flink and Spark differ on the following. The expression
+ // array_remove(array[1, null], cast(null as integer))
+ // returns [1] in Flink, and returns null in Spark. The current
+ // function has Spark behavior, but if we supported a Flink function
+ // library (i.e. "fun=flink") we could add a function with Flink behavior.
+ f.checkNull("array_remove(array[1, null], cast(null as integer))");
+ f.checkType("array_remove(array[1, null], cast(null as integer))",
"INTEGER ARRAY");
+ f.checkFails("^array_remove(array[1, 2], true)^",
+ "INTEGER is not comparable to BOOLEAN", false);
+ }
+
/** Tests {@code ARRAY_REPEAT} function from Spark. */
@Test void testArrayRepeatFunc() {
final SqlOperatorFixture f0 = fixture();