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 95089c86fa [CALCITE-5744] Add MAP_FROM_ARRAYS, STR_TO_MAP function
(enabled in Spark library)
95089c86fa is described below
commit 95089c86fafc504a34edda85915433adac419443
Author: yongen.ly <[email protected]>
AuthorDate: Thu Jun 1 19:13:38 2023 +0800
[CALCITE-5744] Add MAP_FROM_ARRAYS, STR_TO_MAP function (enabled in Spark
library)
---
.../calcite/adapter/enumerable/RexImpTable.java | 37 +++++++++++
.../apache/calcite/runtime/CalciteResource.java | 3 +
.../org/apache/calcite/runtime/SqlFunctions.java | 28 ++++++++
.../main/java/org/apache/calcite/sql/SqlKind.java | 6 ++
.../calcite/sql/fun/SqlLibraryOperators.java | 25 +++++++
.../org/apache/calcite/sql/type/OperandTypes.java | 10 +++
.../org/apache/calcite/sql/type/ReturnTypes.java | 16 +++++
.../apache/calcite/sql/type/SqlTypeTransforms.java | 11 ++++
.../org/apache/calcite/util/BuiltInMethod.java | 2 +
.../calcite/runtime/CalciteResource.properties | 1 +
site/_docs/reference.md | 2 +
.../org/apache/calcite/test/SqlOperatorTest.java | 77 ++++++++++++++++++++++
12 files changed, 218 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 f5a27adb3f..f1585e4e30 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
@@ -189,6 +189,7 @@ 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_ENTRIES;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.MAP_FROM_ARRAYS;
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;
@@ -223,6 +224,7 @@ import static
org.apache.calcite.sql.fun.SqlLibraryOperators.SPACE;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.SPLIT;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.STARTS_WITH;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.STRCMP;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.STR_TO_MAP;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.TANH;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.TIME;
import static org.apache.calcite.sql.fun.SqlLibraryOperators.TIMESTAMP;
@@ -436,6 +438,8 @@ public class RexImpTable {
Expressions.constant(true);
public static final ConstantExpression COMMA_EXPR =
Expressions.constant(",");
+ public static final ConstantExpression COLON_EXPR =
+ Expressions.constant(":");
public static final MemberExpression BOXED_FALSE_EXPR =
Expressions.field(null, Boolean.class, "FALSE");
public static final MemberExpression BOXED_TRUE_EXPR =
@@ -736,6 +740,8 @@ public class RexImpTable {
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);
+ map.put(STR_TO_MAP, new StringToMapImplementor());
map.put(ARRAY_CONCAT, new ArrayConcatImplementor());
map.put(SORT_ARRAY, new SortArrayImplementor());
final MethodImplementor isEmptyImplementor =
@@ -3161,6 +3167,37 @@ public class RexImpTable {
}
}
+ /** Implementor for str_to_map. */
+ private static class StringToMapImplementor extends
AbstractRexCallImplementor {
+ StringToMapImplementor() {
+ super("str_to_map", NullPolicy.STRICT, false);
+ }
+
+ @Override Expression implementSafe(RexToLixTranslator translator,
+ RexCall call, List<Expression> argValueList) {
+ switch (call.getOperands().size()) {
+ case 1:
+ return Expressions.call(
+ BuiltInMethod.STR_TO_MAP.method,
+ argValueList.get(0),
+ COMMA_EXPR,
+ COLON_EXPR);
+ case 2:
+ return Expressions.call(
+ BuiltInMethod.STR_TO_MAP.method,
+ argValueList.get(0),
+ argValueList.get(1),
+ COLON_EXPR);
+ case 3:
+ return Expressions.call(
+ BuiltInMethod.STR_TO_MAP.method,
+ argValueList);
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+
/** Implementor for a array or string concat. */
private static class ConcatImplementor extends AbstractRexCallImplementor {
final ArrayConcatImplementor arrayConcatImplementor =
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 fc8fd6fb1e..27024331bc 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -900,6 +900,9 @@ public interface CalciteResource {
@BaseMessage("Substring error: negative substring length not allowed")
ExInst<CalciteException> illegalNegativeSubstringLength();
+ @BaseMessage("Illegal arguments: The length of the keys array {0,number,#}
is not equal to the length of the values array {1,number,#} in MAP_FROM_ARRAYS
function")
+ ExInst<CalciteException> illegalArgumentsInMapFromArraysFunc(int arg0, int
arg1);
+
@BaseMessage("Trim error: trim character must be exactly 1 character")
ExInst<CalciteException> trimError();
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 26990d03f6..0638481ae2 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -92,6 +92,7 @@ import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
@@ -4058,6 +4059,33 @@ public class SqlFunctions {
return new ArrayList<>(map.values());
}
+ /** Support the MAP_FROM_ARRAYS function. */
+ public static Map mapFromArrays(List keysArray, List valuesArray) {
+ if (keysArray.size() != valuesArray.size()) {
+ throw RESOURCE.illegalArgumentsInMapFromArraysFunc(keysArray.size(),
valuesArray.size()).ex();
+ }
+ final Map map = new LinkedHashMap<>();
+ for (int i = 0; i < keysArray.size(); i++) {
+ map.put(keysArray.get(i), valuesArray.get(i));
+ }
+ return map;
+ }
+
+ /** Support the STR_TO_MAP function. */
+ public static Map strToMap(String string, String stringDelimiter, String
keyValueDelimiter) {
+ final Map map = new LinkedHashMap();
+ final String[] keyValues = string.split(stringDelimiter, -1);
+ for (String s : keyValues) {
+ String[] keyValueArray = s.split(keyValueDelimiter, 2);
+ String key = keyValueArray[0];
+ String value = keyValueArray.length < 2
+ ? null
+ : keyValueArray[1];
+ map.put(key, value);
+ }
+ return map;
+ }
+
/** Support the SLICE function. */
public static List slice(List list) {
List result = new ArrayList(list.size());
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 a49423d684..ebeeb7f839 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,12 @@ public enum SqlKind {
/** {@code MAP_VALUES} function (Spark semantics). */
MAP_VALUES,
+ /** {@code MAP_FROM_ARRAYS} function (Spark semantics). */
+ MAP_FROM_ARRAYS,
+
+ /** {@code STR_TO_MAP} function (Spark semantics). */
+ STR_TO_MAP,
+
/** {@code REVERSE} function (SQL Server, MySQL). */
REVERSE,
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 4ceffd43e7..d42beb1ec5 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
@@ -1146,6 +1146,31 @@ public abstract class SqlLibraryOperators {
ReturnTypes.TO_MAP_VALUES_NULLABLE,
OperandTypes.MAP);
+ private static RelDataType deriveTypeMapFromArrays(SqlOperatorBinding
opBinding) {
+ final RelDataType keysArrayType = opBinding.getOperandType(0);
+ final RelDataType valuesArrayType = opBinding.getOperandType(1);
+ final boolean nullable = keysArrayType.isNullable() ||
valuesArrayType.isNullable();
+ return SqlTypeUtil.createMapType(
+ opBinding.getTypeFactory(),
+ requireNonNull(keysArrayType.getComponentType(), "inferred key type"),
+ requireNonNull(valuesArrayType.getComponentType(), "inferred value
type"),
+ nullable);
+ }
+
+ /** The "MAP_FROM_ARRAYS(keysArray, valuesArray)" function. */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction MAP_FROM_ARRAYS =
+ SqlBasicFunction.create(SqlKind.MAP_FROM_ARRAYS,
+ SqlLibraryOperators::deriveTypeMapFromArrays,
+ OperandTypes.ARRAY_ARRAY);
+
+ /** The "STR_TO_MAP(string[, stringDelimiter[, keyValueDelimiter]])"
function. */
+ @LibraryOperator(libraries = {SPARK})
+ public static final SqlFunction STR_TO_MAP =
+ SqlBasicFunction.create(SqlKind.STR_TO_MAP,
+ ReturnTypes.IDENTITY_TO_MAP_NULLABLE,
+ OperandTypes.STRING_OPTIONAL_STRING_OPTIONAL_STRING);
+
@LibraryOperator(libraries = {BIG_QUERY, MYSQL})
public static final SqlFunction REVERSE =
SqlBasicFunction.create(SqlKind.REVERSE,
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 6e85fa8c0c..37f0f8325d 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
@@ -404,6 +404,13 @@ public abstract class OperandTypes {
// Third operand optional (operand index 0, 1, 2)
number -> number == 2);
+ public static final FamilyOperandTypeChecker
STRING_OPTIONAL_STRING_OPTIONAL_STRING =
+ family(
+ ImmutableList.of(SqlTypeFamily.STRING, SqlTypeFamily.STRING,
+ SqlTypeFamily.STRING),
+ // Second and Third operand both are optional (operand index 0, 1, 2)
+ number -> number == 1 || number == 2);
+
public static final FamilyOperandTypeChecker STRING_NUMERIC_OPTIONAL_STRING =
family(
ImmutableList.of(SqlTypeFamily.STRING, SqlTypeFamily.NUMERIC,
@@ -469,6 +476,9 @@ public abstract class OperandTypes {
public static final SqlSingleOperandTypeChecker ARRAY =
family(SqlTypeFamily.ARRAY);
+ public static final SqlSingleOperandTypeChecker ARRAY_ARRAY =
+ family(SqlTypeFamily.ARRAY, SqlTypeFamily.ARRAY);
+
public static final SqlSingleOperandTypeChecker ARRAY_OR_MAP =
OperandTypes.family(SqlTypeFamily.ARRAY)
.or(OperandTypes.family(SqlTypeFamily.MAP))
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 901d3dc395..5b9d7aa73c 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
@@ -628,6 +628,22 @@ public abstract class ReturnTypes {
public static final SqlReturnTypeInference TO_MAP =
ARG0.andThen(SqlTypeTransforms.TO_MAP);
+ /**
+ * Returns a MAP type.
+ *
+ * <p>For example, given {@code STRING}, returns
+ * {@code (STRING, STRING) MAP}.
+ */
+ public static final SqlReturnTypeInference IDENTITY_TO_MAP =
+ ARG0.andThen(SqlTypeTransforms.IDENTITY_TO_MAP);
+
+ /**
+ * Same as {@link #IDENTITY_TO_MAP} but returns with nullability if any of
the
+ * operands is nullable.
+ */
+ public static final SqlReturnTypeInference IDENTITY_TO_MAP_NULLABLE =
+ IDENTITY_TO_MAP.andThen(SqlTypeTransforms.TO_NULLABLE);
+
/**
* Returns a ROW type.
*
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 97562713c9..b9c6f80aa1 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
@@ -244,6 +244,17 @@ public abstract class SqlTypeTransforms {
SqlTypeUtil.createMapTypeFromRecord(opBinding.getTypeFactory(),
typeToTransform);
+ /**
+ * Parameter type-inference transform strategy that converts a type to a MAP
type,
+ * which key and value type is same.
+ *
+ * @see org.apache.calcite.rel.type.RelDataTypeFactory#createMapType
+ */
+ public static final SqlTypeTransform IDENTITY_TO_MAP =
+ (opBinding, typeToTransform) ->
+ SqlTypeUtil.createMapType(opBinding.getTypeFactory(),
+ typeToTransform, typeToTransform, false);
+
/**
* Parameter type-inference transform strategy that converts a MAP type
* to a two-field record type.
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 6dda17513f..64073b3977 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -655,6 +655,8 @@ public enum BuiltInMethod {
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),
+ 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),
AVERAGE_ROW_SIZE(Size.class, "averageRowSize"),
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 c402732059..4b18925e69 100644
---
a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++
b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -294,6 +294,7 @@ DialectDoesNotSupportFeature=Dialect does not support
feature: ''{0}''
IllegalNegativePadLength=Second argument for LPAD/RPAD must not be negative
IllegalEmptyPadPattern=Third argument (pad pattern) for LPAD/RPAD must not be
empty
IllegalNegativeSubstringLength=Substring error: negative substring length not
allowed
+IllegalArgumentsInMapFromArraysFunc=Illegal arguments: The length of the keys
array {0,number,#} is not equal to the length of the values array {1,number,#}
in MAP_FROM_ARRAYS function
TrimError=Trim error: trim character must be exactly 1 character
InvalidTypesForArithmetic=Invalid types for arithmetic: {0} {1} {2}
InvalidTypesForComparison=Invalid types for comparison: {0} {1} {2}
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index a701fe9eda..c45baae259 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2751,6 +2751,8 @@ BigQuery's type system uses confusingly different names
for types and functions:
| 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*
| 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 2add67eb87..cd11a0f8fb 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -5866,6 +5866,82 @@ public class SqlOperatorTest {
"INTEGER ARRAY NOT NULL");
}
+ /** Tests {@code MAP_FROM_ARRAYS} function from Spark. */
+ @Test void testMapFromArraysFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.MAP_FROM_ARRAYS);
+ f0.checkFails("^map_from_arrays(array[1, 2], array['foo', 'bar'])^",
+ "No match found for function signature MAP_FROM_ARRAYS\\(<INTEGER
ARRAY>, "
+ + "<CHAR\\(3\\) ARRAY>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("map_from_arrays(array[1, 2], array['foo', 'bar'])",
"{1=foo, 2=bar}",
+ "(INTEGER NOT NULL, CHAR(3) NOT NULL) MAP NOT NULL");
+ f.checkScalar("map_from_arrays(array[1, 1, null], array['foo', 'bar',
'name'])",
+ "{1=bar, null=name}", "(INTEGER, CHAR(4) NOT NULL) MAP NOT NULL");
+ f.checkScalar("map_from_arrays(array(), array())",
+ "{}", "(UNKNOWN NOT NULL, UNKNOWN NOT NULL) MAP NOT NULL");
+ f.checkType("map_from_arrays(cast(null as integer array), array['foo',
'bar'])",
+ "(INTEGER NOT NULL, CHAR(3) NOT NULL) MAP");
+ f.checkNull("map_from_arrays(cast(null as integer array), array['foo',
'bar'])");
+
+ f.checkFails("^map_from_arrays(array[1, 2], 2)^",
+ "Cannot apply 'MAP_FROM_ARRAYS' to arguments of type
'MAP_FROM_ARRAYS\\(<INTEGER ARRAY>,"
+ + " <INTEGER>\\)'. Supported form\\(s\\):
'MAP_FROM_ARRAYS\\(<ARRAY>, <ARRAY>\\)'",
+ false);
+ f.checkFails("^map_from_arrays(2, array[1, 2])^",
+ "Cannot apply 'MAP_FROM_ARRAYS' to arguments of type
'MAP_FROM_ARRAYS\\(<INTEGER>,"
+ + " <INTEGER ARRAY>\\)'. Supported form\\(s\\):
'MAP_FROM_ARRAYS\\(<ARRAY>, <ARRAY>\\)'",
+ false);
+ f.checkFails("map_from_arrays(^array[1, '1', true]^, array['a', 'b',
'c'])",
+ "Parameters must be of the same type",
+ false);
+ f.checkFails("map_from_arrays(array['a', 'b', 'c'], ^array[1, '1',
true]^)",
+ "Parameters must be of the same type",
+ false);
+ f.checkFails("map_from_arrays(array[1, 2], array['foo'])",
+ "Illegal arguments: The length of the keys array 2 is not equal to the
length "
+ + "of the values array 1 in MAP_FROM_ARRAYS function",
+ true);
+ }
+
+ /** Tests {@code STR_TO_MAP} function from Spark. */
+ @Test void testStrToMapFunc() {
+ final SqlOperatorFixture f0 = fixture();
+ f0.setFor(SqlLibraryOperators.STR_TO_MAP);
+ f0.checkFails("^str_to_map('a=1,b=2', ',', '=')^",
+ "No match found for function signature STR_TO_MAP\\("
+ + "<CHARACTER>, <CHARACTER>, <CHARACTER>\\)", false);
+
+ final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
+ f.checkScalar("str_to_map('a=1,b=2', ',', '=')", "{a=1, b=2}",
+ "(CHAR(7) NOT NULL, CHAR(7) NOT NULL) MAP NOT NULL");
+ f.checkScalar("str_to_map('a:1,b:2')", "{a=1, b=2}",
+ "(CHAR(7) NOT NULL, CHAR(7) NOT NULL) MAP NOT NULL");
+ f.checkScalar("str_to_map('a:1,b:2', ',')", "{a=1, b=2}",
+ "(CHAR(7) NOT NULL, CHAR(7) NOT NULL) MAP NOT NULL");
+ f.checkScalar("str_to_map('a=1&b=2', '&', '=')", "{a=1, b=2}",
+ "(CHAR(7) NOT NULL, CHAR(7) NOT NULL) MAP NOT NULL");
+ f.checkScalar("str_to_map('k#2%v#3', '%', '#')", "{k=2, v=3}",
+ "(CHAR(7) NOT NULL, CHAR(7) NOT NULL) MAP NOT NULL");
+ f.checkScalar("str_to_map('a:1&b:2', '&')", "{a=1, b=2}",
+ "(CHAR(7) NOT NULL, CHAR(7) NOT NULL) MAP NOT NULL");
+ f.checkScalar("str_to_map('k:2%v:3', '%')", "{k=2, v=3}",
+ "(CHAR(7) NOT NULL, CHAR(7) NOT NULL) MAP NOT NULL");
+ f.checkScalar("str_to_map('a')", "{a=null}",
+ "(CHAR(1) NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL");
+ f.checkScalar("str_to_map('a,b,c')", "{a=null, b=null, c=null}",
+ "(CHAR(5) NOT NULL, CHAR(5) NOT NULL) MAP NOT NULL");
+ f.checkScalar("str_to_map('a-b--c', '--')", "{a-b=null, c=null}",
+ "(CHAR(6) NOT NULL, CHAR(6) NOT NULL) MAP NOT NULL");
+ f.checkType("str_to_map(cast(null as varchar))",
+ "(VARCHAR, VARCHAR) MAP");
+ f.checkNull("str_to_map(cast(null as varchar))");
+ f.checkNull("str_to_map(null, ',', ':')");
+ f.checkNull("str_to_map('a:1,b:2,c:3', null, ':')");
+ f.checkNull("str_to_map('a:1,b:2,c:3', ',',null)");
+ }
+
/** Tests {@code UNIX_SECONDS} and other datetime functions from BigQuery. */
@Test void testUnixSecondsFunc() {
SqlOperatorFixture f = fixture()
@@ -8510,6 +8586,7 @@ public class SqlOperatorTest {
// empty array is illegal per SQL spec. presumably because one can't
// infer type
f.checkFails("^Array[]^", "Require at least 1 argument", false);
+ f.checkFails("^array[1, '1', true]^", "Parameters must be of the same
type", false);
}
/** Test case for {@link SqlLibraryOperators#ARRAY} (Spark). */