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

cancai 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 ac81f758da [CALCITE-6300] Function MAP_VALUES/MAP_KEYS gives exception 
when mapVauleType and mapKeyType not equals map Biggest mapKeytype or 
mapValueType
ac81f758da is described below

commit ac81f758da2de2023713bbae594b1deea83a9e1d
Author: Cancai Cai <[email protected]>
AuthorDate: Fri Mar 27 21:31:24 2026 +0800

    [CALCITE-6300] Function MAP_VALUES/MAP_KEYS gives exception when 
mapVauleType and mapKeyType not equals map Biggest mapKeytype or mapValueType
---
 .../org/apache/calcite/sql/type/OperandTypes.java  | 30 ++++++++++++++++++++
 .../org/apache/calcite/test/SqlOperatorTest.java   | 32 +++++++++++++++++++++-
 2 files changed, 61 insertions(+), 1 deletion(-)

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 b67899d761..66b4aab9b6 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
@@ -31,6 +31,8 @@
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlUtil;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.util.SqlBasicVisitor;
 import org.apache.calcite.sql.validate.SqlLambdaScope;
 import org.apache.calcite.sql.validate.SqlValidator;
@@ -1555,9 +1557,37 @@ private static class MapFunctionOperandTypeChecker
         }
         return false;
       }
+      // Insert implicit casts for operands whose SqlTypeName differs
+      // from the inferred key/value type.
+      coerceOperands(callBinding, argTypes,
+          componentType.left, componentType.right);
       return true;
     }
 
+    /** Casts operands whose {@code SqlTypeName} differs from the
+     * target key or value type. Operands at even positions are keys,
+     * odd positions are values. */
+    private static void coerceOperands(SqlCallBinding callBinding,
+        List<RelDataType> operandTypes,
+        RelDataType keyType, RelDataType valueType) {
+      final SqlValidator validator = callBinding.getValidator();
+      final SqlCall call = callBinding.getCall();
+      final List<SqlNode> operands = call.getOperandList();
+      for (int i = 0; i < operands.size(); i++) {
+        final RelDataType targetType = i % 2 == 0 ? keyType : valueType;
+        if (operandTypes.get(i).getSqlTypeName()
+            != targetType.getSqlTypeName()) {
+          final SqlNode castNode =
+              SqlStdOperatorTable.CAST.createCall(SqlParserPos.ZERO,
+                  operands.get(i),
+                  SqlTypeUtil.convertTypeToSpec(targetType)
+                      .withNullable(targetType.isNullable()));
+          call.setOperand(i, castNode);
+          validator.setValidatedNodeType(castNode, targetType);
+        }
+      }
+    }
+
     /**
      * Extract the key type and value type of arg types.
      */
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 b6731f9e63..e79bbe197b 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -9356,6 +9356,20 @@ void checkArrayReverseFunc(SqlOperatorFixture f0, 
SqlFunction function,
     f1.checkScalar("map_keys(map('foo', 1, 'bar', 2))", "[foo, bar]",
         "CHAR(3) NOT NULL ARRAY NOT NULL");
 
+    // [CALCITE-6300] MAP function with mixed key/value types
+    f1.checkScalar("map_keys(map(cast(1 as tinyint), 1, 2, 2))", "[1, 2]",
+        "INTEGER NOT NULL ARRAY NOT NULL");
+    f1.checkScalar("map_keys(map(cast(1 as tinyint), 1, cast(2 as double), 
2))",
+        "[1.0, 2.0]",
+        "DOUBLE NOT NULL ARRAY NOT NULL");
+    f1.checkScalar("map_keys(map(cast(1 as tinyint), 1, cast(2 as float), 2))",
+        "[1.0, 2.0]",
+        "FLOAT NOT NULL ARRAY NOT NULL");
+    f1.checkFails("map_keys(map(cast(1 as tinyint), 1, cast(null as float), 
2))",
+        "Illegal arguments for MAP_KEYS function: "
+            + "using a map with a null key is not allowed",
+        true);
+
     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);
@@ -9395,6 +9409,21 @@ void checkArrayReverseFunc(SqlOperatorFixture f0, 
SqlFunction function,
     f1.checkScalar("map_values(map('foo', 1, 'bar', cast(null as integer)))", 
"[1, null]",
         "INTEGER ARRAY NOT NULL");
 
+    // [CALCITE-6300] MAP function with mixed key/value types
+    f1.checkScalar("map_values(map('foo', null))", "[null]",
+        "NULL ARRAY NOT NULL");
+    f1.checkScalar("map_values(map('foo', 1, 'bar', cast(1 as tinyint)))", 
"[1, 1]",
+        "INTEGER NOT NULL ARRAY NOT NULL");
+    f1.checkScalar("map_values(map('foo', 1, 'bar', cast(1 as double)))",
+        "[1.0, 1.0]",
+        "DOUBLE NOT NULL ARRAY NOT NULL");
+    f1.checkScalar("map_values(map('foo', 1, 'bar', cast(1 as float)))",
+        "[1.0, 1.0]",
+        "FLOAT NOT NULL ARRAY NOT NULL");
+    f1.checkScalar("map_values(map('foo', 1, 'bar', cast(null as float)))",
+        "[1.0, null]",
+        "FLOAT 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);
@@ -13880,8 +13909,9 @@ private static void 
checkArrayConcatAggFuncFails(SqlOperatorFixture t) {
     f1.checkScalar("map('washington', 1, 'obama', 44)",
         "{washington=1, obama=44}",
         "(CHAR(10) NOT NULL, INTEGER NOT NULL) MAP NOT NULL");
+    // [CALCITE-6300] values are coerced to DECIMAL(11, 1)
     f1.checkScalar("map('k1', 1, 'k2', 2.0)",
-        "{k1=1, k2=2.0}",
+        "{k1=1.0, k2=2.0}",
         "(CHAR(2) NOT NULL, DECIMAL(11, 1) NOT NULL) MAP NOT NULL");
   }
 

Reply via email to