This is an automated email from the ASF dual-hosted git repository.
jackylau 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 313b958059 [CALCITE-5772] Add MAP_CONCAT, MAP_FROM_ENTRIES function
(enabled in Spark library)
313b958059 is described below
commit 313b9580591f3816e498feb26a8953602c6029c0
Author: yongen.ly <[email protected]>
AuthorDate: Tue Jun 13 13:16:59 2023 +0800
[CALCITE-5772] Add MAP_CONCAT, MAP_FROM_ENTRIES function (enabled in Spark
library)
---
.../calcite/adapter/enumerable/RexImpTable.java | 4 +
.../apache/calcite/runtime/CalciteResource.java | 3 +
.../org/apache/calcite/runtime/SqlFunctions.java | 19 +++++
.../main/java/org/apache/calcite/sql/SqlKind.java | 6 ++
.../calcite/sql/fun/SqlLibraryOperators.java | 46 +++++++++++
.../org/apache/calcite/sql/type/OperandTypes.java | 29 +++++++
.../org/apache/calcite/util/BuiltInMethod.java | 2 +
.../calcite/runtime/CalciteResource.properties | 1 +
site/_docs/reference.md | 6 +-
.../org/apache/calcite/test/SqlOperatorTest.java | 91 ++++++++++++++++++++++
10 files changed, 205 insertions(+), 2 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 6a90116e42..f709aae70e 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
@@ -192,8 +192,10 @@ import static
org.apache.calcite.sql.fun.SqlLibraryOperators.LOG;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.LOGICAL_AND;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.LOGICAL_OR;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.LPAD;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.MAP_CONCAT;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.MAP_ENTRIES;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.MAP_FROM_ARRAYS;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.MAP_FROM_ENTRIES;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.MAP_KEYS;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.MAP_VALUES;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.MAX_BY;
@@ -747,10 +749,12 @@ public class RexImpTable {
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_CONCAT, BuiltInMethod.MAP_CONCAT.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);
defineMethod(MAP_FROM_ARRAYS, BuiltInMethod.MAP_FROM_ARRAYS.method,
NullPolicy.ANY);
+ defineMethod(MAP_FROM_ENTRIES, BuiltInMethod.MAP_FROM_ENTRIES.method,
NullPolicy.STRICT);
map.put(STR_TO_MAP, new StringToMapImplementor());
map.put(ARRAY_CONCAT, new ArrayConcatImplementor());
map.put(SORT_ARRAY, new SortArrayImplementor());
diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index 27024331bc..1b267bc598 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -702,6 +702,9 @@ public interface CalciteResource {
@BaseMessage("Map requires an even number of arguments")
ExInst<SqlValidatorException> mapRequiresEvenArgCount();
+ @BaseMessage("Function ''{0}'' should all be of type map, but it is ''{1}''")
+ ExInst<SqlValidatorException> typesShouldAllBeMap(String funcName, String
type);
+
@BaseMessage("Incompatible types")
ExInst<SqlValidatorException> incompatibleTypes();
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 4f2e0177e1..7338cbfa52 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -4112,6 +4112,13 @@ public class SqlFunctions {
return list;
}
+ /** Support the MAP_CONCAT function. */
+ public static Map mapConcat(Map... maps) {
+ final Map result = new LinkedHashMap();
+ Arrays.stream(maps).forEach(result::putAll);
+ return result;
+ }
+
/** Support the MAP_ENTRIES function. */
public static List mapEntries(Map<Object, Object> map) {
final List result = new ArrayList(map.size());
@@ -4143,6 +4150,18 @@ public class SqlFunctions {
return map;
}
+ /** Support the MAP_FROM_ENTRIES function. */
+ public static @Nullable Map mapFromEntries(List entries) {
+ final Map map = new LinkedHashMap<>();
+ for (Object entry: entries) {
+ if (entry == null) {
+ return null;
+ }
+ map.put(structAccess(entry, 0, null), structAccess(entry, 1, null));
+ }
+ return map;
+ }
+
/** Support the STR_TO_MAP function. */
public static Map strToMap(String string, String stringDelimiter, String
keyValueDelimiter) {
final Map map = new LinkedHashMap();
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 001c3fdea0..b7cbd3f65f 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -752,6 +752,9 @@ public enum SqlKind {
/** {@code SORT_ARRAY} function (Spark semantics). */
SORT_ARRAY,
+ /** {@code MAP_CONCAT} function (Spark semantics). */
+ MAP_CONCAT,
+
/** {@code MAP_ENTRIES} function (Spark semantics). */
MAP_ENTRIES,
@@ -764,6 +767,9 @@ public enum SqlKind {
/** {@code MAP_FROM_ARRAYS} function (Spark semantics). */
MAP_FROM_ARRAYS,
+ /** {@code MAP_FROM_ENTRIES} function (Spark semantics). */
+ MAP_FROM_ENTRIES,
+
/** {@code STR_TO_MAP} function (Spark semantics). */
STR_TO_MAP,
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 6f7485f5e0..58fbaab72a 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
@@ -65,6 +65,7 @@ import static org.apache.calcite.sql.fun.SqlLibrary.MYSQL;
import static org.apache.calcite.sql.fun.SqlLibrary.ORACLE;
import static org.apache.calcite.sql.fun.SqlLibrary.POSTGRESQL;
import static org.apache.calcite.sql.fun.SqlLibrary.SPARK;
+import static org.apache.calcite.util.Static.RESOURCE;
import static java.util.Objects.requireNonNull;
@@ -1168,6 +1169,33 @@ public abstract class SqlLibraryOperators {
ReturnTypes.ARG0_NULLABLE,
OperandTypes.ARRAY.or(OperandTypes.ARRAY_BOOLEAN_LITERAL));
+ private static RelDataType deriveTypeMapConcat(SqlOperatorBinding opBinding)
{
+ if (opBinding.getOperandCount() == 0) {
+ final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
+ final RelDataType type = typeFactory.createSqlType(SqlTypeName.VARCHAR);
+ requireNonNull(type, "type");
+ return SqlTypeUtil.createMapType(typeFactory, type, type, true);
+ } else {
+ final List<RelDataType> operandTypes = opBinding.collectOperandTypes();
+ for (RelDataType operandType: operandTypes) {
+ if (!SqlTypeUtil.isMap(operandType)) {
+ throw opBinding.newError(
+ RESOURCE.typesShouldAllBeMap(
+ opBinding.getOperator().getName(),
+ operandType.getFullTypeString()));
+ }
+ }
+ return
requireNonNull(opBinding.getTypeFactory().leastRestrictive(operandTypes));
+ }
+ }
+
+ /** The "MAP_CONCAT(map [, map]*)" function. */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction MAP_CONCAT =
+ SqlBasicFunction.create(SqlKind.MAP_CONCAT,
+ SqlLibraryOperators::deriveTypeMapConcat,
+ OperandTypes.SAME_VARIADIC);
+
/** The "MAP_ENTRIES(map)" function. */
@LibraryOperator(libraries = {SPARK})
public static final SqlFunction MAP_ENTRIES =
@@ -1207,6 +1235,24 @@ public abstract class SqlLibraryOperators {
SqlLibraryOperators::deriveTypeMapFromArrays,
OperandTypes.ARRAY_ARRAY);
+ private static RelDataType deriveTypeMapFromEntries(SqlOperatorBinding
opBinding) {
+ final RelDataType entriesType = opBinding.collectOperandTypes().get(0);
+ final RelDataType entryType = entriesType.getComponentType();
+ requireNonNull(entryType, () -> "componentType of " + entriesType);
+ return SqlTypeUtil.createMapType(
+ opBinding.getTypeFactory(),
+ requireNonNull(entryType.getFieldList().get(0).getType(), "inferred
key type"),
+ requireNonNull(entryType.getFieldList().get(1).getType(), "inferred
value type"),
+ entriesType.isNullable() || entryType.isNullable());
+ }
+
+ /** The "MAP_FROM_ENTRIES(arrayOfEntries)" function. */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction MAP_FROM_ENTRIES =
+ SqlBasicFunction.create(SqlKind.MAP_FROM_ENTRIES,
+ SqlLibraryOperators::deriveTypeMapFromEntries,
+ OperandTypes.MAP_FROM_ENTRIES);
+
/** The "STR_TO_MAP(string[, stringDelimiter[, keyValueDelimiter]])"
function. */
@LibraryOperator(libraries = {SPARK})
public static final SqlFunction STR_TO_MAP =
diff --git a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
index 37f0f8325d..63b5308abd 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
@@ -527,6 +527,9 @@ public abstract class OperandTypes {
public static final SqlOperandTypeChecker ARRAY_ELEMENT =
new ArrayElementOperandTypeChecker();
+ public static final SqlSingleOperandTypeChecker MAP_FROM_ENTRIES =
+ new MapFromEntriesOperandTypeChecker();
+
/**
* Operand type-checking strategy where type must be a literal or NULL.
*/
@@ -1125,6 +1128,32 @@ public abstract class OperandTypes {
}
};
+ /** Checker that returns whether a value is a array of record type with two
fields. */
+ private static class MapFromEntriesOperandTypeChecker
+ implements SqlSingleOperandTypeChecker {
+ @Override public boolean checkSingleOperandType(SqlCallBinding callBinding,
+ SqlNode node, int iFormalOperand, boolean throwOnFailure) {
+ assert 0 == iFormalOperand;
+ RelDataType type = SqlTypeUtil.deriveType(callBinding, node);
+ RelDataType componentType = requireNonNull(type.getComponentType(),
"componentType");
+ boolean valid = false;
+ if (type.getSqlTypeName() == SqlTypeName.ARRAY
+ && componentType.getSqlTypeName() == SqlTypeName.ROW
+ && componentType.getFieldCount() == 2) {
+ valid = true;
+ }
+ if (!valid && throwOnFailure) {
+ throw callBinding.newValidationSignatureError();
+ }
+ return valid;
+ }
+
+ @Override public String getAllowedSignatures(SqlOperator op, String
opName) {
+ return SqlUtil.getAliasedSignature(op, opName,
+ ImmutableList.of("ARRAY<RECORDTYPE(TWO FIELDS)>"));
+ }
+ }
+
/** Operand type-checker that accepts period types. Examples:
*
* <ul>
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 ca987cc6e5..1b49de90b9 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -656,10 +656,12 @@ public enum BuiltInMethod {
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_CONCAT(SqlFunctions.class, "mapConcat", Map[].class),
MAP_ENTRIES(SqlFunctions.class, "mapEntries", Map.class),
MAP_KEYS(SqlFunctions.class, "mapKeys", Map.class),
MAP_VALUES(SqlFunctions.class, "mapValues", Map.class),
MAP_FROM_ARRAYS(SqlFunctions.class, "mapFromArrays", List.class, List.class),
+ MAP_FROM_ENTRIES(SqlFunctions.class, "mapFromEntries", List.class),
STR_TO_MAP(SqlFunctions.class, "strToMap", String.class, String.class,
String.class),
SELECTIVITY(Selectivity.class, "getSelectivity", RexNode.class),
UNIQUE_KEYS(UniqueKeys.class, "getUniqueKeys", boolean.class),
diff --git
a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
index 4b18925e69..ca9003edfd 100644
---
a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++
b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -230,6 +230,7 @@ DuplicateNameInColumnList=Duplicate name ''{0}'' in column
list
RequireAtLeastOneArg=Require at least 1 argument
MapRequiresTwoOrMoreArgs=Map requires at least 2 arguments
MapRequiresEvenArgCount=Map requires an even number of arguments
+TypesShouldAllBeMap=Function ''{0}'' should all be of type map, but it is
''{1}''
IncompatibleTypes=Incompatible types
ColumnCountMismatch=Number of columns must match number of query columns
DuplicateColumnAndNoColumnList=Column has duplicate column name ''{0}'' and no
column list specified
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 852559b7e0..3f5052db8b 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2753,11 +2753,13 @@ BigQuery's type system uses confusingly different names
for types and functions:
| m | TO_BASE64(string) | Converts the *string*
to base-64 encoded form and returns a encoded string
| b m | FROM_BASE64(string) | Returns the decoded
result of a base-64 *string* as a string
| b o | LTRIM(string) | Returns *string* with
all blanks removed from the start
+| s | MAP_CONCAT(map [, map]*) | Concatenates one or
more maps. If any input argument is `NULL` the function returns `NULL`. Note
that calcite is using the LAST_WIN strategy
| s | MAP_ENTRIES(map) | Returns the entries of
the *map* as an array, the order of the entries is not defined
| s | MAP_KEYS(map) | Returns the keys of the
*map* as an array, the order of the entries is not defined
| s | MAP_VALUES(map) | Returns the values of
the *map* as an array, the order of the entries is not defined
-| s | MAP_FROM_ARRAYS(array1, array2) | Returns a map created
from an *array1* and *array2*. Note that the lengths of two arrays should be
the same
-| s | STR_TO_MAP(string [, stringDelimiter [, keyValueDelimiter]]) | Returns a
map after splitting the *string* into key/value pairs using delimiters. Default
delimiters are ',' for *stringDelimiter* and ':' for *keyValueDelimiter*
+| s | MAP_FROM_ARRAYS(array1, array2) | Returns a map created
from an *array1* and *array2*. Note that the lengths of two arrays should be
the same and calcite is using the LAST_WIN strategy
+| s | MAP_FROM_ENTRIES(arrayOfRows) | Returns a map created
from an arrays of row with two fields. Note that the number of fields in a row
must be 2. Note that calcite is using the LAST_WIN strategy
+| s | STR_TO_MAP(string [, stringDelimiter [, keyValueDelimiter]]) | Returns a
map after splitting the *string* into key/value pairs using delimiters. Default
delimiters are ',' for *stringDelimiter* and ':' for *keyValueDelimiter*. Note
that calcite is using the LAST_WIN strategy
| b m p | MD5(string) | Calculates an MD5
128-bit checksum of *string* and returns it as a hex string
| m | MONTHNAME(date) | Returns the name, in
the connection's locale, of the month in *datetime*; for example, it returns
'二月' for both DATE '2020-02-10' and TIMESTAMP '2020-02-10 10:10:10'
| o | NVL(value1, value2) | Returns *value1* if
*value1* is not null, otherwise *value2*
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 e57c2da9dd..5a67eddf4d 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -5969,6 +5969,55 @@ public class SqlOperatorTest {
+ "'SORT_ARRAY\\(<ARRAY>, <BOOLEAN>\\)'", false);
}
+ /** Tests {@code MAP_CONCAT} function from Spark. */
+ @Test void testMapConcatFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.MAP_CONCAT);
+ f0.checkFails("^map_concat(map['foo', 1], map['bar', 2])^",
+ "No match found for function signature MAP_CONCAT\\("
+ + "<\\(CHAR\\(3\\), INTEGER\\) MAP>, <\\(CHAR\\(3\\), INTEGER\\)
MAP>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("map_concat(map['foo', 1], map['bar', 2])", "{foo=1, bar=2}",
+ "(CHAR(3) NOT NULL, INTEGER NOT NULL) MAP NOT NULL");
+ f.checkScalar("map_concat(map['foo', 1], map['bar', 2], map['foo', 2])",
"{foo=2, bar=2}",
+ "(CHAR(3) NOT NULL, INTEGER NOT NULL) MAP NOT NULL");
+ f.checkScalar("map_concat(map[null, 1], map[null, 2])", "{null=2}",
+ "(NULL, INTEGER NOT NULL) MAP NOT NULL");
+ f.checkScalar("map_concat(map[1, 2], map[1, null])", "{1=null}",
+ "(INTEGER NOT NULL, INTEGER) MAP NOT NULL");
+ // test zero arg, but it should return empty map.
+ f.checkScalar("map_concat()", "{}",
+ "(VARCHAR NOT NULL, VARCHAR NOT NULL) MAP");
+
+ // after calcite supports cast(null as map<string, int>), it should add
these tests.
+ if (TODO) {
+ f.checkNull("map_concat(map['foo', 1], cast(null as map<string, int>))");
+ f.checkType("map_concat(map['foo', 1], cast(null as map<string, int>))",
+ "(VARCHAR NOT NULL, INTEGER NOT NULL) MAP");
+ f.checkNull("map_concat(cast(null as map<string, int>), map['foo', 1])");
+ f.checkType("map_concat(cast(null as map<string, int>), map['foo', 1])",
+ "(VARCHAR NOT NULL, INTEGER NOT NULL) MAP");
+ }
+
+ // test only has one operand, but it is not map type.
+ f.checkFails("^map_concat(1)^",
+ "Function 'MAP_CONCAT' should all be of type map, but it is 'INTEGER
NOT NULL'", false);
+ f.checkFails("^map_concat(null)^",
+ "Function 'MAP_CONCAT' should all be of type map, but it is 'NULL'",
false);
+ // test operands in same type family, but it is not map type.
+ f.checkFails("^map_concat(array[1], array[1])^",
+ "Function 'MAP_CONCAT' should all be of type map, "
+ + "but it is 'INTEGER NOT NULL ARRAY NOT NULL'", false);
+ f.checkFails("^map_concat(map['foo', 1], null)^",
+ "Function 'MAP_CONCAT' should all be of type map, "
+ + "but it is 'NULL'", false);
+ // test operands not in same type family.
+ f.checkFails("^map_concat(map[1, null], array[1])^",
+ "Parameters must be of the same type", false);
+ }
+
+
/** Tests {@code MAP_ENTRIES} function from Spark. */
@Test void testMapEntriesFunc() {
final SqlOperatorFixture f0 = fixture();
@@ -6050,6 +6099,48 @@ public class SqlOperatorTest {
true);
}
+ /** Tests {@code MAP_FROM_ENTRIES} function from Spark. */
+ @Test void testMapFromEntriesFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.MAP_FROM_ENTRIES);
+ f0.checkFails("^map_from_entries(array[row(1, 'a'), row(2, 'b')])^",
+ "No match found for function signature MAP_FROM_ENTRIES\\("
+ + "<RecordType\\(INTEGER EXPR\\$0, CHAR\\(1\\) EXPR\\$1\\)
ARRAY>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("map_from_entries(array[row(1, 'a'), row(2, 'b')])", "{1=a,
2=b}",
+ "(INTEGER NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL");
+ f.checkScalar("map_from_entries(array[row(1, 'a'), row(1, 'b')])", "{1=b}",
+ "(INTEGER NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL");
+ f.checkScalar("map_from_entries(array[row(null, 'a'), row(null, 'b')])",
"{null=b}",
+ "(NULL, CHAR(1) NOT NULL) MAP NOT NULL");
+ f.checkScalar("map_from_entries(array[row(1, 'a'), row(1, null)])",
"{1=null}",
+ "(INTEGER NOT NULL, CHAR(1)) MAP NOT NULL");
+ f.checkScalar("map_from_entries(array[row(array['a'], 1), row(array['b'],
2)])",
+ "{[a]=1, [b]=2}",
+ "(CHAR(1) NOT NULL ARRAY NOT NULL, INTEGER NOT NULL) MAP NOT NULL");
+ f.checkScalar("map_from_entries(array[row(map['a', 1], 2), row(map['a',
1], 3)])",
+ "{{a=1}=3}",
+ "((CHAR(1) NOT NULL, INTEGER NOT NULL) MAP NOT NULL, INTEGER NOT NULL)
MAP NOT NULL");
+ f.checkType("map_from_entries(cast(null as row(f0 int, f1 varchar)
array))",
+ "(INTEGER NOT NULL, VARCHAR NOT NULL) MAP");
+ f.checkNull("map_from_entries(cast(null as row(f0 int, f1 varchar)
array))");
+ f.checkNull("map_from_entries(array[row(1, 'a'), null])");
+ f.checkType("map_from_entries(array[row(1, 'a'), null])",
+ "(INTEGER, CHAR(1)) MAP");
+
+ f.checkFails("^map_from_entries(array[1])^",
+ "Cannot apply 'MAP_FROM_ENTRIES' to arguments of type
'MAP_FROM_ENTRIES\\("
+ + "<INTEGER ARRAY>\\)'. Supported form\\(s\\):
'MAP_FROM_ENTRIES\\("
+ + "<ARRAY<RECORDTYPE\\(TWO FIELDS\\)>>\\)'",
+ false);
+ f.checkFails("^map_from_entries(array[row(1, 'a', 2)])^",
+ "Cannot apply 'MAP_FROM_ENTRIES' to arguments of type
'MAP_FROM_ENTRIES\\("
+ + "<RECORDTYPE\\(INTEGER EXPR\\$0, CHAR\\(1\\) EXPR\\$1, INTEGER
EXPR\\$2\\) ARRAY>\\)'. "
+ + "Supported form\\(s\\):
'MAP_FROM_ENTRIES\\(<ARRAY<RECORDTYPE\\(TWO FIELDS\\)>>\\)'",
+ false);
+ }
+
/** Tests {@code STR_TO_MAP} function from Spark. */
@Test void testStrToMapFunc() {
final SqlOperatorFixture f0 = fixture();