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>. */