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

tanner 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 2cb8167d5f [CALCITE-5862] Incorrect semantics of ARRAY function (Spark 
library) when elements have Numeric and Character types
2cb8167d5f is described below

commit 2cb8167d5fa9375c35546bd9c827d7d4d8071b7a
Author: Ran Tao <[email protected]>
AuthorDate: Tue Jul 18 22:04:45 2023 +0800

    [CALCITE-5862] Incorrect semantics of ARRAY function (Spark library) when 
elements have Numeric and Character types
---
 .../calcite/sql/fun/SqlLibraryOperators.java       | 44 ++++++++++++++++++++--
 .../org/apache/calcite/test/SqlOperatorTest.java   |  8 ++++
 2 files changed, 48 insertions(+), 4 deletions(-)

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 98ecf893c2..43f5f6b9b4 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
@@ -1011,10 +1011,46 @@ public abstract class SqlLibraryOperators {
           .withKind(SqlKind.CONCAT_WS_MSSQL);
 
   private static RelDataType arrayReturnType(SqlOperatorBinding opBinding) {
-    RelDataType type =
-        opBinding.getOperandCount() > 0
-            ? ReturnTypes.LEAST_RESTRICTIVE.inferReturnType(opBinding)
-            : opBinding.getTypeFactory().createUnknownType();
+    final List<RelDataType> operandTypes = opBinding.collectOperandTypes();
+
+    // only numeric & character types check
+    boolean hasNumeric = false;
+    boolean hasCharacter = false;
+    boolean hasOthers = false;
+    for (RelDataType type : operandTypes) {
+      SqlTypeFamily family = type.getSqlTypeName().getFamily();
+      requireNonNull(family, "array element type family");
+      switch (family) {
+      case NUMERIC:
+        hasNumeric = true;
+        break;
+      case CHARACTER:
+        hasCharacter = true;
+        break;
+      case NULL:
+        // skip it becase we allow null
+        break;
+      default:
+        hasOthers = true;
+        break;
+      }
+    }
+
+    RelDataType type;
+    boolean useCharacterTypes = hasNumeric && hasCharacter && !hasOthers;
+    if (useCharacterTypes) {
+      List<RelDataType> characterTypes =
+          // may include NULL literal
+          operandTypes.stream().filter(
+              t -> t.getSqlTypeName().getFamily() != SqlTypeFamily.NUMERIC)
+              .collect(Collectors.toList());
+      type = opBinding.getTypeFactory().leastRestrictive(characterTypes);
+    } else {
+      type =
+          opBinding.getOperandCount() > 0
+              ? ReturnTypes.LEAST_RESTRICTIVE.inferReturnType(opBinding)
+              : opBinding.getTypeFactory().createUnknownType();
+    }
     requireNonNull(type, "inferred array element type");
     return SqlTypeUtil.createArrayType(opBinding.getTypeFactory(), type, 
false);
   }
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 f2ad858e95..68f3ff3896 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -9941,6 +9941,14 @@ public class SqlOperatorTest {
         "[null, foo]", "CHAR(3) ARRAY NOT NULL");
     f2.checkScalar("array(null)",
         "[null]", "NULL ARRAY NOT NULL");
+    f2.checkScalar("array(1, 2, 'Hi')",
+        "[1, 2, Hi]", "CHAR(2) NOT NULL ARRAY NOT NULL");
+    f2.checkScalar("array(1, 2, 'Hi', 'Hello')",
+        "[1, 2, Hi, Hello]", "CHAR(5) NOT NULL ARRAY NOT NULL");
+    f2.checkScalar("array(1, 2, 'Hi', null)",
+        "[1, 2, Hi, null]", "CHAR(2) ARRAY NOT NULL");
+    f2.checkScalar("array(1, 2, 'Hi', cast(null as char(10)))",
+        "[1, 2, Hi, null]", "CHAR(10) ARRAY NOT NULL");
   }
 
   /**

Reply via email to