This is an automated email from the ASF dual-hosted git repository.

mbudiu 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 3cb9fc612a [CALCITE-6522] MAP_KEYS and MAP_VALUES   function should 
throw if a key value is null
3cb9fc612a is described below

commit 3cb9fc612a9d18db162357824fd351a2f8801a31
Author: cancaicai <[email protected]>
AuthorDate: Fri Aug 9 00:12:37 2024 +0800

    [CALCITE-6522] MAP_KEYS and MAP_VALUES   function should throw if a key 
value is null
---
 .../apache/calcite/runtime/CalciteResource.java    |  9 ++++
 .../org/apache/calcite/runtime/SqlFunctions.java   | 11 ++++-
 .../calcite/runtime/CalciteResource.properties     |  5 ++-
 .../org/apache/calcite/test/SqlOperatorTest.java   | 52 +++++++++++++++-------
 4 files changed, 58 insertions(+), 19 deletions(-)

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 67236d9c74..85a995a945 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -933,6 +933,15 @@ public interface CalciteResource {
   @BaseMessage("Illegal arguments for 'FORMAT_NUMBER' function: negative 
decimal value not allowed")
   ExInst<CalciteException> illegalNegativeDecimalValue();
 
+  @BaseMessage("Illegal arguments for 'MAP_ENTRIES' function: using a map with 
a null key is not allowed")
+  ExInst<CalciteException> illegalMapEntriesWithNullKey();
+
+  @BaseMessage("Illegal arguments for 'MAP_KEYS' function: using a map with a 
null key is not allowed")
+  ExInst<CalciteException> illegalMapKeysWithNullKey();
+
+  @BaseMessage("Illegal arguments for 'MAP_VALUES' function: using a map with 
a null key is not allowed")
+  ExInst<CalciteException> illegalMapValuesWithNullKey();
+
   @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);
 
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 f7b208c0a8..9e4250e44b 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -5907,7 +5907,7 @@ public class SqlFunctions {
     final List result = new ArrayList(map.size());
     for (Map.Entry<Object, Object> entry : map.entrySet()) {
       if (entry.getKey() == null) {
-        throw new IllegalArgumentException("Cannot use null as map key");
+        throw RESOURCE.illegalMapEntriesWithNullKey().ex();
       }
       result.add(Arrays.asList(entry.getKey(), entry.getValue()));
     }
@@ -5916,11 +5916,18 @@ public class SqlFunctions {
 
   /** Support the MAP_KEYS function. */
   public static List mapKeys(Map map) {
-    return new ArrayList<>(map.keySet());
+    try {
+      return ImmutableList.copyOf(map.keySet());
+    } catch (NullPointerException e) {
+      throw RESOURCE.illegalMapKeysWithNullKey().ex();
+    }
   }
 
   /** Support the MAP_VALUES function. */
   public static List mapValues(Map map) {
+    if (map.containsKey(null)) {
+      throw RESOURCE.illegalMapValuesWithNullKey().ex();
+    }
     return new ArrayList<>(map.values());
   }
 
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 55bf0ba73c..a16d5469c1 100644
--- 
a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++ 
b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -302,8 +302,11 @@ FunctionNotFound=Function ''{0}'' not found
 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
 IllegalNegativeDecimalValue=Illegal arguments for 'FORMAT_NUMBER' function: 
negative decimal value not allowed
+IllegalNegativeSubstringLength=Substring error: negative substring length not 
allowed
+IllegalMapEntriesWithNullKey=Illegal arguments for 'MAP_ENTRIES' function: 
using a map with a null key is not allowed
+IllegalMapKeysWithNullKey=Illegal arguments for 'MAP_KEYS' function: using a 
map with a null key is not allowed
+IllegalMapValuesWithNullKey=Illegal arguments for 'MAP_VALUES' function: using 
a map with a null key is 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}
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 4b7c5972c9..c5ad9a4b64 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -8517,13 +8517,17 @@ public class SqlOperatorTest {
 
     // 3. check key is not allowed to be null
     f.checkFails("map_entries(map[cast(1 as decimal), 1, null, 2])",
-        "Cannot use null as map key", true);
+        "Illegal arguments for MAP_ENTRIES function: using a map with a null 
key is not allowed",
+        true);
     f.checkFails("map_entries(map[1, cast(1 as bigint), null, 2])",
-        "Cannot use null as map key", true);
+        "Illegal arguments for MAP_ENTRIES function: using a map with a null 
key is not allowed",
+        true);
     f.checkFails("map_entries(map[1, cast(1 as decimal), null, 2])",
-        "Cannot use null as map key", true);
+        "Illegal arguments for MAP_ENTRIES function: using a map with a null 
key is not allowed",
+        true);
     f.checkFails("map_entries(map['foo', 1, null, 2])",
-        "Cannot use null as map key", true);
+        "Illegal arguments for MAP_ENTRIES function: using a map with a null 
key is not allowed",
+        true);
   }
 
   /** Tests {@code MAP_KEYS} function from Spark. */
@@ -8537,23 +8541,15 @@ public class SqlOperatorTest {
     final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SPARK);
     f.checkScalar("map_keys(map['foo', 1, 'bar', 2])", "[foo, bar]",
         "CHAR(3) NOT NULL ARRAY NOT NULL");
-    f.checkScalar("map_keys(map['foo', 1, null, 2])", "[foo, null]",
-        "CHAR(3) ARRAY NOT NULL");
+
     // elements cast
     // key cast
     f.checkScalar("map_keys(map[cast(1 as tinyint), 1, 2, 2])", "[1, 2]",
         "INTEGER NOT NULL ARRAY NOT NULL");
-    f.checkScalar("map_keys(map[cast(1 as bigint), 1, null, 2])", "[1, null]",
-        "BIGINT ARRAY NOT NULL");
-    f.checkScalar("map_keys(map[cast(1 as decimal), 1, null, 2])", "[1, null]",
-        "DECIMAL(19, 0) ARRAY NOT NULL");
+
     // value cast
     f.checkScalar("map_keys(map[1, cast(1 as tinyint), 2, 2])", "[1, 2]",
         "INTEGER NOT NULL ARRAY NOT NULL");
-    f.checkScalar("map_keys(map[1, cast(1 as bigint), null, 2])", "[1, null]",
-        "INTEGER ARRAY NOT NULL");
-    f.checkScalar("map_keys(map[1, cast(1 as decimal), null, 2])", "[1, null]",
-        "INTEGER ARRAY NOT NULL");
 
     // 2. check with map function, map(k, v ...)
     final SqlOperatorFixture f1 = fixture()
@@ -8563,8 +8559,19 @@ public class SqlOperatorTest {
         "UNKNOWN NOT NULL ARRAY NOT NULL");
     f1.checkScalar("map_keys(map('foo', 1, 'bar', 2))", "[foo, bar]",
         "CHAR(3) NOT NULL ARRAY NOT NULL");
-    f1.checkScalar("map_keys(map('foo', 1, null, 2))", "[foo, null]",
-        "CHAR(3) ARRAY NOT NULL");
+
+    f.checkFails("map_keys(map['foo', 1, null, 2])",
+        "Illegal arguments for MAP_KEYS function: using a map with a null key 
is not allowed",
+        true);
+    f.checkFails("map_keys(map[1, cast(1 as decimal), null, 2])",
+        "Illegal arguments for MAP_KEYS function: using a map with a null key 
is not allowed",
+        true);
+    f.checkFails("map_keys(map[1, cast(1 as bigint), null, 2])",
+        "Illegal arguments for MAP_KEYS function: using a map with a null key 
is not allowed",
+        true);
+    f.checkFails("map_keys(map[cast(1 as decimal), 1, null, 2])",
+        "Illegal arguments for MAP_KEYS function: using a map with a null key 
is not allowed",
+        true);
   }
 
   /** Tests {@code MAP_VALUES} function from Spark. */
@@ -8591,6 +8598,19 @@ public class SqlOperatorTest {
         "INTEGER NOT NULL ARRAY NOT NULL");
     f1.checkScalar("map_values(map('foo', 1, 'bar', cast(null as integer)))", 
"[1, null]",
         "INTEGER ARRAY NOT NULL");
+
+    f.checkFails("map_values(map['foo', 1, null, 2])",
+        "Illegal arguments for MAP_VALUES function: using a map with a null 
key is not allowed",
+        true);
+    f.checkFails("map_values(map[1, cast(1 as decimal), null, 2])",
+        "Illegal arguments for MAP_VALUES function: using a map with a null 
key is not allowed",
+        true);
+    f.checkFails("map_values(map[1, cast(1 as bigint), null, 2])",
+        "Illegal arguments for MAP_VALUES function: using a map with a null 
key is not allowed",
+        true);
+    f.checkFails("map_values(map[cast(1 as decimal), 1, null, 2])",
+        "Illegal arguments for MAP_VALUES function: using a map with a null 
key is not allowed",
+        true);
   }
 
   /** Test case for

Reply via email to