This is an automated email from the ASF dual-hosted git repository.
xiong 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 e969f87aea [CALCITE-5778] Add ARRAY_JOIN, ARRAYS_OVERLAP, ARRAYS_ZIP
function (enabled in Spark library)
e969f87aea is described below
commit e969f87aeac35ffd97b80a2ef39a0f749a645a8a
Author: yongen.ly <[email protected]>
AuthorDate: Wed Jun 14 16:27:31 2023 +0800
[CALCITE-5778] Add ARRAY_JOIN, ARRAYS_OVERLAP, ARRAYS_ZIP function (enabled
in Spark library)
---
.../calcite/adapter/enumerable/RexImpTable.java | 6 ++
.../org/apache/calcite/runtime/SqlFunctions.java | 50 ++++++++++
.../main/java/org/apache/calcite/sql/SqlKind.java | 9 ++
.../calcite/sql/fun/SqlLibraryOperators.java | 44 +++++++++
.../apache/calcite/sql/type/SqlTypeTransforms.java | 21 ++++
.../org/apache/calcite/util/BuiltInMethod.java | 2 +
.../org/apache/calcite/test/SqlFunctionsTest.java | 30 ++++++
site/_docs/reference.md | 3 +
.../org/apache/calcite/test/SqlOperatorTest.java | 109 +++++++++++++++++++++
9 files changed, 274 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 f1585e4e30..06603af460 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
@@ -117,6 +117,8 @@ import static
org.apache.calcite.sql.fun.SqlInternalOperators.LITERAL_AGG;
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.ARRAYS_OVERLAP;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAYS_ZIP;
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;
@@ -126,6 +128,7 @@ import static
org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_CONTAINS;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_DISTINCT;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_EXCEPT;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_INTERSECT;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.ARRAY_JOIN;
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;
@@ -725,6 +728,7 @@ public class RexImpTable {
defineMethod(ARRAY_CONTAINS, BuiltInMethod.LIST_CONTAINS.method,
NullPolicy.ANY);
defineMethod(ARRAY_DISTINCT, BuiltInMethod.ARRAY_DISTINCT.method,
NullPolicy.STRICT);
defineMethod(ARRAY_EXCEPT, BuiltInMethod.ARRAY_EXCEPT.method,
NullPolicy.ANY);
+ defineMethod(ARRAY_JOIN, "arrayToString", NullPolicy.STRICT);
defineMethod(ARRAY_INTERSECT, BuiltInMethod.ARRAY_INTERSECT.method,
NullPolicy.ANY);
defineMethod(ARRAY_LENGTH, BuiltInMethod.COLLECTION_SIZE.method,
NullPolicy.STRICT);
defineMethod(ARRAY_MAX, BuiltInMethod.ARRAY_MAX.method,
NullPolicy.STRICT);
@@ -737,6 +741,8 @@ public class RexImpTable {
defineMethod(ARRAY_SIZE, BuiltInMethod.COLLECTION_SIZE.method,
NullPolicy.STRICT);
defineMethod(ARRAY_TO_STRING, "arrayToString", NullPolicy.STRICT);
defineMethod(ARRAY_UNION, BuiltInMethod.ARRAY_UNION.method,
NullPolicy.ANY);
+ defineMethod(ARRAYS_OVERLAP, BuiltInMethod.ARRAYS_OVERLAP.method,
NullPolicy.ANY);
+ defineMethod(ARRAYS_ZIP, BuiltInMethod.ARRAYS_ZIP.method,
NullPolicy.ANY);
defineMethod(MAP_ENTRIES, BuiltInMethod.MAP_ENTRIES.method,
NullPolicy.STRICT);
defineMethod(MAP_KEYS, BuiltInMethod.MAP_KEYS.method, NullPolicy.STRICT);
defineMethod(MAP_VALUES, BuiltInMethod.MAP_VALUES.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 0638481ae2..486153d423 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -3913,6 +3913,56 @@ public class SqlFunctions {
return atomic;
}
+ /** Support the ARRAYS_OVERLAP function. */
+ public static @Nullable Boolean arraysOverlap(List list1, List list2) {
+ if (list1.size() > list2.size()) {
+ return arraysOverlap(list2, list1);
+ }
+ final List smaller = list1;
+ final List bigger = list2;
+ boolean hasNull = false;
+ if (smaller.size() > 0 && bigger.size() > 0) {
+ final Set smallestSet = new HashSet(smaller);
+ hasNull = smallestSet.remove(null);
+ for (Object element : bigger) {
+ if (element == null) {
+ hasNull = true;
+ } else if (smallestSet.contains(element)) {
+ return true;
+ }
+ }
+ }
+ if (hasNull) {
+ return null;
+ } else {
+ return false;
+ }
+ }
+
+ /** Support the ARRAYS_ZIP function. */
+ @SuppressWarnings("argument.type.incompatible")
+ public static List arraysZip(List... lists) {
+ final int biggestCardinality = lists.length == 0
+ ? 0
+ : Arrays.stream(lists).mapToInt(List::size).max().getAsInt();
+
+ final List result = new ArrayList(biggestCardinality);
+ for (int i = 0; i < biggestCardinality; i++) {
+ List<Object> row = new ArrayList<>();
+ Object value;
+ for (List list : lists) {
+ if (i < list.size() && list.get(i) != null) {
+ value = list.get(i);
+ } else {
+ value = null;
+ }
+ row.add(value);
+ }
+ result.add(row);
+ }
+ return result;
+ }
+
/** Support the ARRAY_COMPACT function. */
public static List compact(List list) {
final List result = new ArrayList();
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 ebeeb7f839..001c3fdea0 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -707,6 +707,9 @@ public enum SqlKind {
/** {@code ARRAY_INTERSECT} function (Spark semantics). */
ARRAY_INTERSECT,
+ /** {@code ARRAY_JOIN} function (Spark semantics). */
+ ARRAY_JOIN,
+
/** {@code ARRAY_LENGTH} function (Spark semantics). */
ARRAY_LENGTH,
@@ -740,6 +743,12 @@ public enum SqlKind {
/** {@code ARRAY_UNION} function (Spark semantics). */
ARRAY_UNION,
+ /** {@code ARRAYS_OVERLAP} function (Spark semantics). */
+ ARRAYS_OVERLAP,
+
+ /** {@code ARRAYS_ZIP} function (Spark semantics). */
+ ARRAYS_ZIP,
+
/** {@code SORT_ARRAY} function (Spark semantics). */
SORT_ARRAY,
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 d42beb1ec5..07b150105a 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
@@ -53,6 +53,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import static org.apache.calcite.sql.fun.SqlLibrary.ALL;
import static org.apache.calcite.sql.fun.SqlLibrary.BIG_QUERY;
@@ -1037,6 +1039,13 @@ public abstract class SqlLibraryOperators {
OperandTypes.SAME_SAME,
OperandTypes.family(SqlTypeFamily.ARRAY, SqlTypeFamily.ARRAY)));
+ /** The "ARRAY_JOIN(array, delimiter [, nullText ])" function. */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction ARRAY_JOIN =
+ SqlBasicFunction.create(SqlKind.ARRAY_JOIN,
+ ReturnTypes.VARCHAR_NULLABLE,
+ OperandTypes.STRING_ARRAY_CHARACTER_OPTIONAL_CHARACTER);
+
/** The "ARRAY_LENGTH(array)" function. */
@LibraryOperator(libraries = {BIG_QUERY})
public static final SqlFunction ARRAY_LENGTH =
@@ -1118,6 +1127,41 @@ public abstract class SqlLibraryOperators {
ReturnTypes.VARCHAR_NULLABLE,
OperandTypes.STRING_ARRAY_CHARACTER_OPTIONAL_CHARACTER);
+ /** The "ARRAYS_OVERLAP(array1, array2)" function (Spark). */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction ARRAYS_OVERLAP =
+ SqlBasicFunction.create(SqlKind.ARRAYS_OVERLAP,
+
ReturnTypes.BOOLEAN_NULLABLE.andThen(SqlTypeTransforms.COLLECTION_ELEMENT_TYPE_NULLABLE),
+ OperandTypes.and(
+ OperandTypes.SAME_SAME,
+ OperandTypes.family(SqlTypeFamily.ARRAY, SqlTypeFamily.ARRAY)));
+
+ private static RelDataType deriveTypeArraysZip(SqlOperatorBinding opBinding)
{
+ final List<RelDataType> argComponentTypes = new ArrayList<>();
+ for (RelDataType arrayType : opBinding.collectOperandTypes()) {
+ final RelDataType componentType =
requireNonNull(arrayType.getComponentType());
+ argComponentTypes.add(componentType);
+ }
+
+ final List<String> indexes = IntStream.range(0, argComponentTypes.size())
+ .mapToObj(i -> String.valueOf(i))
+ .collect(Collectors.toList());
+ final RelDataType structType =
+ opBinding.getTypeFactory().createStructType(argComponentTypes,
indexes);
+ return SqlTypeUtil.createArrayType(
+ opBinding.getTypeFactory(),
+ requireNonNull(structType, "inferred value type"),
+ false);
+ }
+
+ /** The "ARRAYS_ZIP(array, ...)" function (Spark). */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction ARRAYS_ZIP =
+ SqlBasicFunction.create(SqlKind.ARRAYS_ZIP,
+ ((SqlReturnTypeInference) SqlLibraryOperators::deriveTypeArraysZip)
+ .andThen(SqlTypeTransforms.TO_NULLABLE),
+ OperandTypes.SAME_VARIADIC);
+
/** The "SORT_ARRAY(array)" function (Spark). */
@LibraryOperator(libraries = {SPARK})
public static final SqlFunction SORT_ARRAY =
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 b9c6f80aa1..3676653cce 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
@@ -22,6 +22,7 @@ import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.sql.SqlOperatorBinding;
import org.apache.calcite.util.Util;
+import java.util.ArrayList;
import java.util.List;
import static org.apache.calcite.sql.type.NonNullableAccessors.getCharset;
@@ -111,6 +112,26 @@ public abstract class SqlTypeTransforms {
return typeToTransform;
};
+ /**
+ * Parameter type-inference transform strategy where a derived type is
+ * transformed into the same type but nullable if any of element of a calls
operands is
+ * nullable.
+ */
+ public static final SqlTypeTransform COLLECTION_ELEMENT_TYPE_NULLABLE =
+ (opBinding, typeToTransform) -> {
+ final List<RelDataType> argComponentTypes = new ArrayList<>();
+ for (RelDataType arrayType : opBinding.collectOperandTypes()) {
+ final RelDataType componentType =
requireNonNull(arrayType.getComponentType());
+ argComponentTypes.add(componentType);
+ }
+
+ if (argComponentTypes.stream().anyMatch(RelDataType::isNullable)) {
+ return opBinding.getTypeFactory()
+ .createTypeWithNullability(typeToTransform, true);
+ }
+ return typeToTransform;
+ };
+
/**
* Type-inference strategy whereby the result type of a call is VARYING the
* type given. The length returned is the same as length of the first
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 64073b3977..969cc0daf8 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -651,6 +651,8 @@ public enum BuiltInMethod {
ARRAY_INTERSECT(SqlFunctions.class, "arrayIntersect", List.class,
List.class),
ARRAY_UNION(SqlFunctions.class, "arrayUnion", List.class, List.class),
ARRAY_REVERSE(SqlFunctions.class, "reverse", List.class),
+ ARRAYS_OVERLAP(SqlFunctions.class, "arraysOverlap", List.class, List.class),
+ ARRAYS_ZIP(SqlFunctions.class, "arraysZip", List.class, List.class),
SORT_ARRAY(SqlFunctions.class, "sortArray", List.class, boolean.class),
MAP_ENTRIES(SqlFunctions.class, "mapEntries", Map.class),
MAP_KEYS(SqlFunctions.class, "mapKeys", Map.class),
diff --git a/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
b/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
index 2dbce65720..b973d8c2b8 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
@@ -40,6 +40,7 @@ import static
org.apache.calcite.avatica.util.DateTimeUtils.MILLIS_PER_DAY;
import static
org.apache.calcite.avatica.util.DateTimeUtils.dateStringToUnixDate;
import static
org.apache.calcite.avatica.util.DateTimeUtils.timeStringToUnixDate;
import static
org.apache.calcite.avatica.util.DateTimeUtils.timestampStringToUnixDate;
+import static org.apache.calcite.runtime.SqlFunctions.arraysOverlap;
import static org.apache.calcite.runtime.SqlFunctions.charLength;
import static org.apache.calcite.runtime.SqlFunctions.concat;
import static org.apache.calcite.runtime.SqlFunctions.concatMulti;
@@ -99,6 +100,35 @@ class SqlFunctionsTest {
return ImmutableList.of();
}
+ @Test void testArraysOverlap() {
+ final List<Object> listWithOnlyNull = new ArrayList<>();
+ listWithOnlyNull.add(null);
+
+ // list2 is empty
+ assertThat(arraysOverlap(list(), list()), is(false));
+ assertThat(arraysOverlap(listWithOnlyNull, list()), is(false));
+ assertThat(arraysOverlap(list(1, null), list()), is(false));
+ assertThat(arraysOverlap(list(1, 2), list()), is(false));
+
+ // list2 contains only nulls
+ assertThat(arraysOverlap(list(), listWithOnlyNull), is(false));
+ assertThat(arraysOverlap(listWithOnlyNull, listWithOnlyNull),
is(nullValue()));
+ assertThat(arraysOverlap(list(1, null), listWithOnlyNull),
is(nullValue()));
+ assertThat(arraysOverlap(list(1, 2), listWithOnlyNull), is(nullValue()));
+
+ // list2 contains a mixture of nulls and non-nulls
+ assertThat(arraysOverlap(list(), list(1, null)), is(false));
+ assertThat(arraysOverlap(listWithOnlyNull, list(1, null)),
is(nullValue()));
+ assertThat(arraysOverlap(list(1, null), list(1, null)), is(true));
+ assertThat(arraysOverlap(list(1, 2), list(1, null)), is(true));
+
+ // list2 contains only non-null
+ assertThat(arraysOverlap(list(), list(1, 2)), is(false));
+ assertThat(arraysOverlap(listWithOnlyNull, list(1, 2)), is(nullValue()));
+ assertThat(arraysOverlap(list(1, null), list(1, 2)), is(true));
+ assertThat(arraysOverlap(list(1, 2), list(1, 2)), is(true));
+ }
+
@Test void testCharLength() {
assertThat(charLength("xyz"), is(3));
}
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index c45baae259..bd2e612aa3 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2659,6 +2659,7 @@ BigQuery's type system uses confusingly different names
for types and functions:
| s | ARRAY_DISTINCT(array) | Removes duplicate
values from the *array* that keeps ordering of elements
| s | ARRAY_EXCEPT(array1, array2) | Returns an array of the
elements in *array1* but not in *array2*, without duplicates
| s | ARRAY_INTERSECT(array1, array2) | Returns an array of the
elements in the intersection of *array1* and *array2*, without duplicates
+| s | ARRAY_JOIN(array, delimiter [, nullText ]) | Synonym for
`ARRAY_TO_STRING`
| 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*
@@ -2670,6 +2671,8 @@ BigQuery's type system uses confusingly different names
for types and functions:
| s | ARRAY_SIZE(array) | Synonym for
`CARDINALITY`
| b | ARRAY_TO_STRING(array, delimiter [, nullText ])| Returns a concatenation
of the elements in *array* as a STRING and take *delimiter* as the delimiter.
If the *nullText* parameter is used, the function replaces any `NULL` values in
the array with the value of *nullText*. If the *nullText* parameter is not
used, the function omits the `NULL` value and its preceding delimiter
| s | ARRAY_UNION(array1, array2) | Returns an array of the
elements in the union of *array1* and *array2*, without duplicates
+| s | ARRAYS_OVERLAP(array1, array2) | Returns true if *array1
contains at least a non-null element present also in *array2*. If the arrays
have no common element and they are both non-empty and either of them contains
a null element null is returned, false otherwise
+| s | ARRAYS_ZIP(array [, array ]*) | Returns a merged
*array* of structs in which the N-th struct contains all N-th values of input
arrays
| s | SORT_ARRAY(array [, ascendingOrder]) | Sorts the *array* in
ascending or descending order according to the natural ordering of the array
elements. The default order is ascending if *ascendingOrder* is not specified.
Null elements will be placed at the beginning of the returned array in
ascending order or at the end of the returned array in descending order
| * | ASINH(numeric) | Returns the inverse
hyperbolic sine of *numeric*
| * | ATANH(numeric) | Returns the inverse
hyperbolic tangent of *numeric*
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 cd11a0f8fb..424f626f99 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -5515,6 +5515,31 @@ public class SqlOperatorTest {
f.checkNull("array_distinct(null)");
}
+ @Test void testArrayJoinFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.ARRAY_JOIN);
+ f0.checkFails("^array_join(array['aa', 'b', 'c'], '-')^", "No match found
for function"
+ + " signature ARRAY_JOIN\\(<CHAR\\(2\\) ARRAY>, <CHARACTER>\\)",
false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("array_join(array['aa', 'b', 'c'], '-')", "aa-b-c",
+ "VARCHAR NOT NULL");
+ f.checkScalar("array_join(array[null, 'aa', null, 'b', null], '-',
'empty')",
+ "empty-aa-empty-b-empty", "VARCHAR NOT NULL");
+ f.checkScalar("array_join(array[null, 'aa', null, 'b', null], '-')",
"aa-b",
+ "VARCHAR NOT NULL");
+ f.checkScalar("array_join(array[null, x'aa', null, x'bb', null], '-')",
"aa-bb",
+ "VARCHAR NOT NULL");
+ f.checkScalar("array_join(array['', 'b'], '-')", "-b", "VARCHAR NOT NULL");
+ f.checkScalar("array_join(array['', ''], '-')", "-", "VARCHAR NOT NULL");
+ f.checkNull("array_join(null, '-')");
+ f.checkNull("array_join(array['a', 'b', null], null)");
+ f.checkFails("^array_join(array[1, 2, 3], '-', ' ')^",
+ "Cannot apply 'ARRAY_JOIN' to arguments of type 'ARRAY_JOIN\\("
+ + "<INTEGER ARRAY>, <CHAR\\(1\\)>, <CHAR\\(1\\)>\\)'\\. Supported
form\\(s\\):"
+ + " ARRAY_JOIN\\(<STRING ARRAY>, <CHARACTER>\\[,
<CHARACTER>\\]\\)", false);
+ }
+
/** Tests {@code ARRAY_MAX} function from Spark. */
@Test void testArrayMaxFunc() {
final SqlOperatorFixture f0 = fixture();
@@ -5791,6 +5816,90 @@ public class SqlOperatorTest {
f.checkNull("array_union(cast(null as integer array), cast(null as integer
array))");
}
+ /** Tests {@code ARRAYS_OVERLAP} function from Spark. */
+ @Test void testArraysOverlapFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.ARRAYS_OVERLAP);
+ f0.checkFails("^arrays_overlap(array[1, 2], array[2])^",
+ "No match found for function signature ARRAYS_OVERLAP\\("
+ + "<INTEGER ARRAY>, <INTEGER ARRAY>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("arrays_overlap(array[1, 2], array[2])", true,
+ "BOOLEAN NOT NULL");
+ f.checkScalar("arrays_overlap(array[1, 2], array[3])", false,
+ "BOOLEAN NOT NULL");
+ f.checkScalar("arrays_overlap(array[1, null], array[1])", true,
+ "BOOLEAN");
+ f.checkScalar("arrays_overlap(array(), array(2))", false,
+ "BOOLEAN NOT NULL");
+ f.checkScalar("arrays_overlap(array(), array())", false,
+ "BOOLEAN NOT NULL");
+ f.checkScalar("arrays_overlap(array(), array(1, null))", false,
+ "BOOLEAN");
+ f.checkScalar("arrays_overlap(array[array[1, 2], array[3, 4]],
array[array[1, 2]])", true,
+ "BOOLEAN NOT NULL");
+ f.checkScalar("arrays_overlap(array[map[1, 'a'], map[2, 'b']],
array[map[1, 'a']])", true,
+ "BOOLEAN NOT NULL");
+ f.checkNull("arrays_overlap(cast(null as integer array), array[1, 2])");
+ f.checkType("arrays_overlap(cast(null as integer array), array[1, 2])",
"BOOLEAN");
+ f.checkNull("arrays_overlap(array[1, 2], cast(null as integer array))");
+ f.checkType("arrays_overlap(array[1, 2], cast(null as integer array))",
"BOOLEAN");
+ f.checkNull("arrays_overlap(array[1], array[2, null])");
+ f.checkType("arrays_overlap(array[2, null], array[1])", "BOOLEAN");
+ f.checkFails("^arrays_overlap(array[1, 2], true)^",
+ "Cannot apply 'ARRAYS_OVERLAP' to arguments of type 'ARRAYS_OVERLAP\\("
+ + "<INTEGER ARRAY>, <BOOLEAN>\\)'. Supported form\\(s\\):
'ARRAYS_OVERLAP\\("
+ + "<EQUIVALENT_TYPE>, <EQUIVALENT_TYPE>\\)'", false);
+ }
+
+ /** Tests {@code ARRAYS_ZIP} function from Spark. */
+ @Test void testArraysZipFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.ARRAYS_ZIP);
+ f0.checkFails("^arrays_zip(array[1, 2], array[2])^",
+ "No match found for function signature ARRAYS_ZIP\\("
+ + "<INTEGER ARRAY>, <INTEGER ARRAY>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("arrays_zip(array[1, 2], array[2, 3], array[3, 4])", "[{1,
2, 3}, {2, 3, 4}]",
+ "RecordType(INTEGER NOT NULL 0, INTEGER NOT NULL 1, INTEGER NOT NULL
2) "
+ + "NOT NULL ARRAY NOT NULL");
+ f.checkScalar("arrays_zip(array[1, 2], array[2])", "[{1, 2}, {2, null}]",
+ "RecordType(INTEGER NOT NULL 0, INTEGER NOT NULL 1) NOT NULL ARRAY NOT
NULL");
+ f.checkScalar("arrays_zip(array[1], array[2, null])", "[{1, 2}, {null,
null}]",
+ "RecordType(INTEGER NOT NULL 0, INTEGER 1) NOT NULL ARRAY NOT NULL");
+ f.checkScalar("arrays_zip(array[1, 2])", "[{1}, {2}]",
+ "RecordType(INTEGER NOT NULL 0) NOT NULL ARRAY NOT NULL");
+ f.checkScalar("arrays_zip(array(), array(1, 2))", "[{null, 1}, {null, 2}]",
+ "RecordType(UNKNOWN NOT NULL 0, INTEGER NOT NULL 1) NOT NULL ARRAY NOT
NULL");
+ f.checkScalar("arrays_zip(array(), array())", "[]",
+ "RecordType(UNKNOWN NOT NULL 0, UNKNOWN NOT NULL 1) NOT NULL ARRAY NOT
NULL");
+ f.checkScalar("arrays_zip(array())", "[]",
+ "RecordType(UNKNOWN NOT NULL 0) NOT NULL ARRAY NOT NULL");
+ f.checkScalar("arrays_zip()", "[]",
+ "RecordType() NOT NULL ARRAY NOT NULL");
+ f.checkScalar("arrays_zip(array(null), array(1))", "[{null, 1}]",
+ "RecordType(NULL 0, INTEGER NOT NULL 1) NOT NULL ARRAY NOT NULL");
+ f.checkScalar("arrays_zip(array[array[1, 2], array[3, 4]], array[array[1,
2]])",
+ "[{[1, 2], [1, 2]}, {[3, 4], null}]",
+ "RecordType(INTEGER NOT NULL ARRAY NOT NULL 0, INTEGER NOT NULL ARRAY
NOT NULL 1) "
+ + "NOT NULL ARRAY NOT NULL");
+ f.checkScalar("arrays_zip(array[map[1, 'a'], map[2, 'b']], array[map[1,
'a']])",
+ "[{{1=a}, {1=a}}, {{2=b}, null}]",
+ "RecordType((INTEGER NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL 0, "
+ + "(INTEGER NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL 1) NOT NULL
ARRAY NOT NULL");
+
+ f.checkNull("arrays_zip(cast(null as integer array), array[1, 2])");
+ f.checkType("arrays_zip(cast(null as integer array), array[1, 2])",
+ "RecordType(INTEGER NOT NULL 0, INTEGER NOT NULL 1) NOT NULL ARRAY");
+ f.checkNull("arrays_zip(array[1, 2], cast(null as integer array))");
+ f.checkType("arrays_zip(array[1, 2], cast(null as integer array))",
+ "RecordType(INTEGER NOT NULL 0, INTEGER NOT NULL 1) NOT NULL ARRAY");
+ f.checkFails("^arrays_zip(array[1, 2], true)^",
+ "Parameters must be of the same type", false);
+ }
+
/** Tests {@code SORT_ARRAY} function from Spark. */
@Test void testSortArrayFunc() {
final SqlOperatorFixture f0 = fixture();