You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by ch...@apache.org on 2022/05/12 02:51:31 UTC

[calcite] branch main updated: [CALCITE-5125] Extend "||" operator to work with arrays

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

chunwei 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 b7dbee54df [CALCITE-5125] Extend "||" operator to work with arrays
b7dbee54df is described below

commit b7dbee54df60720ece301ba39cd928844e1a42ee
Author: dssysolyatin <dm...@gmail.com>
AuthorDate: Fri Apr 29 16:24:40 2022 +0300

    [CALCITE-5125] Extend "||" operator to work with arrays
    
    Close apache/calcite#2787
---
 .../calcite/adapter/enumerable/RexImpTable.java    | 26 ++++++++++++++++++++--
 .../calcite/sql/fun/SqlStdOperatorTable.java       | 18 ++++++++++++---
 .../org/apache/calcite/sql/type/OperandTypes.java  |  5 ++++-
 .../org/apache/calcite/test/SqlOperatorTest.java   |  9 ++++++++
 4 files changed, 52 insertions(+), 6 deletions(-)

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 3f58b9a678..9738523f2c 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
@@ -373,8 +373,7 @@ public class RexImpTable {
         NullPolicy.STRICT);
     defineMethod(OCTET_LENGTH, BuiltInMethod.OCTET_LENGTH.method,
         NullPolicy.STRICT);
-    defineMethod(CONCAT, BuiltInMethod.STRING_CONCAT.method,
-        NullPolicy.STRICT);
+    map.put(CONCAT, new ConcatImplementor());
     defineMethod(CONCAT_FUNCTION, BuiltInMethod.MULTI_STRING_CONCAT.method,
         NullPolicy.STRICT);
     defineMethod(CONCAT2, BuiltInMethod.STRING_CONCAT.method, NullPolicy.STRICT);
@@ -2699,6 +2698,29 @@ public class RexImpTable {
     }
   }
 
+  /** Implementor for a array or string concat. */
+  private static class ConcatImplementor extends AbstractRexCallImplementor {
+    private ArrayConcatImplementor arrayConcatImplementor =
+        new ArrayConcatImplementor();
+    private MethodImplementor stringConcatImplementor
+        = new MethodImplementor(BuiltInMethod.STRING_CONCAT.method, NullPolicy.STRICT, false);
+    ConcatImplementor() {
+      super(NullPolicy.STRICT, false);
+    }
+
+    @Override String getVariableName() {
+      return "concat";
+    }
+
+    @Override Expression implementSafe(RexToLixTranslator translator, RexCall call,
+        List<Expression> argValueList) {
+      if (call.type.getSqlTypeName() == SqlTypeName.ARRAY) {
+        return arrayConcatImplementor.implementSafe(translator, call, argValueList);
+      }
+      return stringConcatImplementor.implementSafe(translator, call, argValueList);
+    }
+  }
+
   /** Implementor for a value-constructor. */
   private static class ValueConstructorImplementor
       extends AbstractRexCallImplementor {
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index ab1b554e3a..882202f91c 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -61,6 +61,8 @@ import org.apache.calcite.sql.type.InferTypes;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.type.SqlOperandCountRanges;
+import org.apache.calcite.sql.type.SqlReturnTypeInference;
+import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.util.ReflectiveSqlOperatorTable;
 import org.apache.calcite.sql.validate.SqlConformance;
@@ -248,7 +250,7 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
   public static final SqlInternalOperator EXTEND = new SqlExtendOperator();
 
   /**
-   * String concatenation operator, '<code>||</code>'.
+   * String and array-to-array concatenation operator, '<code>||</code>'.
    *
    * @see SqlLibraryOperators#CONCAT_FUNCTION
    */
@@ -258,9 +260,19 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
           SqlKind.OTHER,
           60,
           true,
-          ReturnTypes.DYADIC_STRING_SUM_PRECISION_NULLABLE,
+          ReturnTypes.ARG0.andThen((opBinding, typeToTransform) -> {
+            SqlReturnTypeInference returnType =
+                typeToTransform.getSqlTypeName().getFamily() == SqlTypeFamily.ARRAY
+                    ? ReturnTypes.LEAST_RESTRICTIVE
+                    : ReturnTypes.DYADIC_STRING_SUM_PRECISION_NULLABLE;
+
+            return requireNonNull(returnType.inferReturnType(opBinding),
+                "inferred CONCAT element type");
+          }),
           null,
-          OperandTypes.STRING_SAME_SAME);
+          OperandTypes.STRING_SAME_SAME_OR_ARRAY_SAME_SAME
+      );
+
 
   /**
    * Arithmetic division operator, '<code>/</code>'.
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 534e298b29..67db9053e7 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
@@ -288,7 +288,6 @@ public abstract class OperandTypes {
 
   public static final SqlSingleOperandTypeChecker ARRAY =
       family(SqlTypeFamily.ARRAY);
-
   /** Checks that returns whether a value is a multiset or an array.
    * Cf Java, where list and set are collections but a map is not. */
   public static final SqlSingleOperandTypeChecker COLLECTION =
@@ -520,6 +519,10 @@ public abstract class OperandTypes {
   public static final SqlSingleOperandTypeChecker STRING_SAME_SAME_INTEGER =
       OperandTypes.and(STRING_STRING_INTEGER, SAME_SAME_INTEGER);
 
+  public static final SqlSingleOperandTypeChecker STRING_SAME_SAME_OR_ARRAY_SAME_SAME =
+      or(STRING_SAME_SAME,
+          and(OperandTypes.SAME_SAME, family(SqlTypeFamily.ARRAY, SqlTypeFamily.ARRAY)));
+
   public static final SqlSingleOperandTypeChecker ANY =
       family(SqlTypeFamily.ANY);
 
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 a2337fd985..26919dfb9a 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -1776,6 +1776,15 @@ public class SqlOperatorTest {
     f.checkNull(" cast(null as ANY) || cast(null as ANY) ");
     f.checkString("cast('a' as varchar) || cast('b' as varchar) "
         + "|| cast('c' as varchar)", "abc", "VARCHAR NOT NULL");
+
+    f.checkScalar("array[1, 2] || array[2, 3]", "[1, 2, 2, 3]",
+        "INTEGER NOT NULL ARRAY NOT NULL");
+    f.checkScalar("array[1, 2] || array[2, null]", "[1, 2, 2, null]",
+        "INTEGER ARRAY NOT NULL");
+    f.checkScalar("array['hello', 'world'] || array['!'] || "
+            + "array[cast(null as char)]",
+        "[hello, world, !, null]", "CHAR(5) ARRAY NOT NULL");
+    f.checkNull("cast(null as integer array) || array[1]");
   }
 
   @Test void testConcatFunc() {