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 7a0564a7d0 [CALCITE-6938] Support zero value creation of nested data 
types
7a0564a7d0 is described below

commit 7a0564a7d0b2629d4537fcfd6879528bde378d9f
Author: Zhen Chen <[email protected]>
AuthorDate: Fri Apr 11 06:44:02 2025 +0800

    [CALCITE-6938] Support zero value creation of nested data types
---
 .../java/org/apache/calcite/rex/RexBuilder.java    |  21 ++++
 .../org/apache/calcite/rex/RexBuilderTest.java     | 137 +++++++++++++++++++++
 2 files changed, 158 insertions(+)

diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java 
b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index 641a0cb351..e4317ddbf6 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -1924,6 +1924,27 @@ public RexLiteral makeZeroLiteral(RelDataType type) {
     return makeLiteral(zeroValue(type), type);
   }
 
+  public RexNode makeZeroRexNode(RelDataType type) {
+    switch (type.getSqlTypeName()) {
+    case ARRAY:
+      return makeCast(type,
+          makeCall(type, SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR, 
ImmutableList.of()));
+    case MULTISET:
+      return makeCast(type,
+          makeCall(type, SqlStdOperatorTable.MULTISET_VALUE, 
ImmutableList.of()));
+    case MAP:
+      return makeCast(type,
+          makeCall(type, SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR, 
ImmutableList.of()));
+    case ROW:
+      List<RexNode> zeroFields = type.getFieldList().stream()
+              .map(field -> makeZeroRexNode(field.getType()))
+              .collect(Collectors.toList());
+      return makeCall(type, SqlStdOperatorTable.ROW, zeroFields);
+    default:
+      return makeZeroLiteral(type);
+    }
+  }
+
   private static Comparable zeroValue(RelDataType type) {
     switch (type.getSqlTypeName()) {
     case CHAR:
diff --git a/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java 
b/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
index fb181b423b..f41975262c 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
@@ -31,7 +31,10 @@
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.fun.SqlLibraryOperators;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.ArraySqlType;
 import org.apache.calcite.sql.type.BasicSqlType;
+import org.apache.calcite.sql.type.MapSqlType;
+import org.apache.calcite.sql.type.MultisetSqlType;
 import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.test.CustomTypeSystems;
@@ -1104,6 +1107,140 @@ private static Stream<Arguments> 
testData4testMakeZeroLiteral() {
             relDataType -> new TimestampWithTimeZoneString(0, 1, 1, 0, 0, 0, 
"GMT+00:00")));
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6938";>[CALCITE-6938]
+   * Support zero value creation of nested data types</a>. */
+  @ParameterizedTest
+  @MethodSource("testData4testMakeZeroForNestedType")
+  void testMakeZeroForNestedType(RelDataType type, RexNode expected) {
+    final RelDataTypeFactory typeFactory = new 
SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+    final RexBuilder rexBuilder = new RexBuilder(typeFactory);
+    assertThat(rexBuilder.makeZeroRexNode(type), is(equalTo(expected)));
+  }
+
+  @Test void testCreateCoalesce() {
+    RelDataTypeFactory typeFactory = new 
SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+    RexBuilder b = new RexBuilder(typeFactory);
+    RelDataType varcharType = typeFactory.createSqlType(SqlTypeName.VARCHAR);
+
+    RelDataType arrayType = new ArraySqlType(varcharType, false);
+    RexNode arrayZero = b.makeZeroRexNode(arrayType);
+
+    RexNode array =
+        b.makeCall(arrayType, SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR,
+        ImmutableList.of(
+            b.makeLiteral("1", varcharType)));
+
+    RexNode coalesce1 = b.makeCall(SqlStdOperatorTable.COALESCE, array, 
arrayZero);
+    assertThat(
+        coalesce1, hasToString(
+        "COALESCE(ARRAY('1'), CAST(ARRAY()):VARCHAR NOT NULL ARRAY NOT 
NULL)"));
+
+    RelDataType mapType = new MapSqlType(arrayType, arrayType, true);
+    RexNode mapZero = b.makeZeroRexNode(mapType);
+
+    RexNode map =
+        b.makeCall(new MapSqlType(arrayType, arrayType, true),
+        SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR,
+        ImmutableList.of(array, array));
+
+    RexNode coalesce2 = b.makeCall(SqlStdOperatorTable.COALESCE, map, mapZero);
+    assertThat(
+        coalesce2, hasToString(
+        "COALESCE(MAP(ARRAY('1'), ARRAY('1')), "
+        + "CAST(MAP()):(VARCHAR NOT NULL ARRAY NOT NULL, VARCHAR NOT NULL 
ARRAY NOT NULL) MAP)"));
+  }
+
+  private static Stream<Arguments> testData4testMakeZeroForNestedType() {
+    RelDataTypeFactory typeFactory = new 
SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+    RexBuilder b = new RexBuilder(typeFactory);
+
+    RelDataType integerType = typeFactory.createSqlType(SqlTypeName.INTEGER);
+    RelDataType varcharType = typeFactory.createSqlType(SqlTypeName.VARCHAR);
+
+    // ARRAY<INTEGER>
+    RelDataType arrayType = new ArraySqlType(integerType, false);
+    RexNode expectedArray =
+        b.makeCast(
+            arrayType, b.makeCall(arrayType, 
SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR,
+            ImmutableList.of()));
+
+    // MULTISET<INTEGER>
+    RelDataType multisetType = new MultisetSqlType(integerType, false);
+    RexNode expectedMultiset =
+        b.makeCast(
+            multisetType, b.makeCall(multisetType, 
SqlStdOperatorTable.MULTISET_VALUE,
+            ImmutableList.of()));
+
+    // MAP<VARCHAR, INTEGER>
+    RelDataType mapType = new MapSqlType(varcharType, integerType, false);
+    RexNode expectedMap =
+        b.makeCast(
+            mapType, b.makeCall(mapType, 
SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR,
+            ImmutableList.of()));
+
+    // ROW<INTEGER, VARCHAR>
+    RelDataType rowType =
+        typeFactory.createStructType(
+            ImmutableList.of(
+            new RelDataTypeFieldImpl("integer", 0, integerType),
+            new RelDataTypeFieldImpl("varchar", 1, varcharType)));
+    RexNode expectedRow =
+        b.makeCall(rowType, SqlStdOperatorTable.ROW,
+            ImmutableList.of(b.makeZeroLiteral(integerType),
+                b.makeZeroLiteral(varcharType)));
+
+    // ARRAY<ARRAY<INTEGER>>
+    RelDataType arrayArrayType = new ArraySqlType(arrayType, false);
+    RexNode expectedArrayArray =
+        b.makeCast(
+            arrayArrayType, b.makeCall(arrayArrayType, 
SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR,
+            ImmutableList.of()));
+
+    // ARRAY<MAP<VARCHAR, INTEGER>>
+    RelDataType arrayMapType = new ArraySqlType(mapType, false);
+    RexNode expectedArrayMap =
+        b.makeCast(
+            arrayMapType, b.makeCall(arrayMapType, 
SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR,
+            ImmutableList.of()));
+
+    // MAP<MAP<INTEGER, INTEGER>
+    RelDataType mapMapType = new MapSqlType(mapType, integerType, false);
+    RexNode expectedMapMap =
+        b.makeCast(
+            mapMapType, b.makeCall(mapMapType, 
SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR,
+            ImmutableList.of()));
+
+    // MAP<ARRAY<INTEGER>, INTEGER>
+    RelDataType mapArrayType = new MapSqlType(arrayType, integerType, false);
+    RexNode expectedMapArray =
+        b.makeCast(
+            mapArrayType, b.makeCall(mapArrayType, 
SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR,
+            ImmutableList.of()));
+
+    // ROW<ARRAY<INTEGER>, VARCHAR>
+    RelDataType rowArrayType =
+        typeFactory.createStructType(
+            ImmutableList.of(
+                new RelDataTypeFieldImpl("array", 0, arrayType),
+                new RelDataTypeFieldImpl("varchar", 1, varcharType)));
+    RexNode expectedRowArray =
+        b.makeCall(rowArrayType, SqlStdOperatorTable.ROW,
+            ImmutableList.of(expectedArray,
+                b.makeZeroLiteral(varcharType)));
+
+    return Stream.of(
+        Arguments.of(arrayType, expectedArray),
+        Arguments.of(multisetType, expectedMultiset),
+        Arguments.of(mapType, expectedMap),
+        Arguments.of(rowType, expectedRow),
+        Arguments.of(arrayArrayType, expectedArrayArray),
+        Arguments.of(arrayMapType, expectedArrayMap),
+        Arguments.of(mapMapType, expectedMapMap),
+        Arguments.of(mapArrayType, expectedMapArray),
+        Arguments.of(rowArrayType, expectedRowArray));
+  }
+
   /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-4632";>[CALCITE-4632]
    * Find the least restrictive datatype for SARG</a>. */

Reply via email to