xuzifu666 commented on code in PR #5042:
URL: https://github.com/apache/calcite/pull/5042#discussion_r3464332211


##########
testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java:
##########
@@ -9281,9 +9284,10 @@ void checkArrayReverseFunc(SqlOperatorFixture f0, 
SqlFunction function,
     f1.checkType("map_concat(cast(null as map<varchar, int>), map['foo', 1])",
         "(VARCHAR NOT NULL, INTEGER) MAP");
 
-    f1.checkFails("^map_concat(map('foo', 1), null)^",
-        "Function 'MAP_CONCAT' should all be of type map, "
-            + "but it is 'NULL'", false);
+    f1.checkNull("map_concat(map('foo', 1), null)");

Review Comment:
   OK, I had added a test with no arguments, according to Spark behaivor this 
should return Map<StringType, StringType>: 
https://github.com/apache/spark/blob/master/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collectionOperations.scala#L713
   ```
   @transient override lazy val dataType: MapType = {
       if (children.isEmpty) {
         MapType(StringType, StringType)   // default
       } else {
         super.dataType.asInstanceOf[MapType]
       }
   }
   ```



##########
core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java:
##########
@@ -1763,23 +1763,35 @@ private static RelDataType 
deriveTypeArraysZip(SqlOperatorBinding opBinding) {
           OperandTypes.ARRAY.or(OperandTypes.ARRAY_BOOLEAN_LITERAL));
 
   private static RelDataType deriveTypeMapConcat(SqlOperatorBinding opBinding) 
{
+    final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
     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()));
-        }
+    }
+    final List<RelDataType> operandTypes = opBinding.collectOperandTypes();
+    final List<RelDataType> mapTypes = new ArrayList<>();
+    boolean hasNull = false;
+    for (RelDataType operandType : operandTypes) {
+      if (operandType.getSqlTypeName() == SqlTypeName.NULL) {
+        hasNull = true;
+      } else if (SqlTypeUtil.isMap(operandType)) {
+        mapTypes.add(operandType);
+      } else {
+        throw opBinding.newError(
+            RESOURCE.typesShouldAllBeMap(
+                opBinding.getOperator().getName(),
+                operandType.getFullTypeString()));
       }
-      return 
requireNonNull(opBinding.getTypeFactory().leastRestrictive(operandTypes));
     }
+    if (mapTypes.isEmpty()) {

Review Comment:
   Here I'm referencing Spark's behavior:
   ```
   SELECT map_concat(map(1, 'a'), null);
   
   -- result: NULL
   
   SELECT map_concat(null, map(2, 'b'));
   
   -- result: NULL
   
   SELECT map_concat(map(1, 'a'), map(2, 'b'), null);
   
   -- result: NULL
   ```
   
   This should be reasonable according to Spark's standards.



##########
testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java:
##########
@@ -9244,16 +9244,19 @@ void checkArrayReverseFunc(SqlOperatorFixture f0, 
SqlFunction function,
 
     // 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);
+        "Arguments of function 'MAP_CONCAT' should all be of type MAP, "
+            + "but 'INTEGER NOT NULL' was found", false);
+    // test operand is the NULL literal.
+    f.checkNull("map_concat(null)");
     // 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);
+        "Arguments of function 'MAP_CONCAT' should all be of type MAP, "
+            + "but 'INTEGER NOT NULL ARRAY NOT NULL' was found", false);
+    // test map operand with NULL literal.
+    f.checkNull("map_concat(map['foo', 1], null)");
+    f.checkType("map_concat(map['foo', 1], null)",

Review Comment:
   Yes, the main concern here is that the constant `map_concat(map['foo', 1], 
null)` might be collapsed into a NULL literal. This would cause the static type 
to change from MAP to NULL, making `checkType` unstable or even failing. 
Therefore, I've removed this test case.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to