From d4881bb616d5ab4faa1f90df35befa307b738e9b Mon Sep 17 00:00:00 2001 From: caicancai <2356672992@qq.com> Date: Fri, 1 Mar 2024 14:13:53 +0800 Subject: [PATCH] [CALCITE-5976] Use explicit casting if inserted element type in ArrayPrepend/ArrayAppend/ArrayInsert does not equal derived component type --- .../org/apache/calcite/sql/fun/SqlLibraryOperators.java | 4 ++-- .../org/apache/calcite/sql/validate/SqlValidatorUtil.java | 7 +++++++ .../main/java/org/apache/calcite/test/SqlOperatorTest.java | 6 +++--- 3 files changed, 12 insertions(+), 5 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 21685b884ff..06a8dab24f8 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 @@ -1187,7 +1187,7 @@ private static RelDataType arrayAppendPrependReturnType(SqlOperatorBinding opBin if (elementType.isNullable()) { type = opBinding.getTypeFactory().createTypeWithNullability(type, true); } - if (!componentType.equalsSansFieldNames(elementType)) { + if (!componentType.isNullable() && !componentType.equalsSansFieldNames(elementType)) { SqlValidatorUtil. adjustTypeForArrayFunctionConstructor(type, opBinding, 0); SqlValidatorUtil. @@ -1280,7 +1280,7 @@ private static RelDataType arrayInsertReturnType(SqlOperatorBinding opBinding) { type = opBinding.getTypeFactory().createTypeWithNullability(type, true); } - if (!componentType.equalsSansFieldNames(elementType)) { + if (!componentType.isNullable() && !componentType.equalsSansFieldNames(elementType)) { SqlValidatorUtil. adjustTypeForArrayFunctionConstructor(type, opBinding, 0); SqlValidatorUtil. diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java index d957c2ff737..9a36da34c3d 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java @@ -1327,6 +1327,13 @@ public static void adjustTypeForArrayConstructor( } } + /** + * When the array element does not equal the biggest type, make explicit casting. + * + * @param componentType derived array component type + * @param opBinding description of call + * @param index index of opBinding + */ public static void adjustTypeForArrayFunctionConstructor( RelDataType componentType, SqlOperatorBinding opBinding, int index) { if (opBinding instanceof SqlCallBinding) { 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 40b119eab9a..9a89d71e008 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -6341,7 +6341,7 @@ void checkRegexpExtract(SqlOperatorFixture f0, FunctionAlias functionAlias) { f.checkType("array_append(cast(null as integer array), 1)", "INTEGER NOT NULL ARRAY"); f.checkFails("^array_append(array[1, 2], true)^", "INTEGER is not comparable to BOOLEAN", false); - + // cast biggest type f.checkScalar("array_append(array(1), cast(2 as tinyint))", "[1, 2]", "INTEGER NOT NULL ARRAY NOT NULL"); f.checkScalar("array_append(array(cast(1 as double)), cast(2 as float))", "[1.0, 2.0]", @@ -6617,7 +6617,7 @@ void checkRegexpExtract(SqlOperatorFixture f0, FunctionAlias functionAlias) { f.checkType("array_prepend(cast(null as integer array), 1)", "INTEGER NOT NULL ARRAY"); f.checkFails("^array_prepend(array[1, 2], true)^", "INTEGER is not comparable to BOOLEAN", false); - + // cast biggest type f.checkScalar("array_prepend(array(1), cast(3 as float))", "[3.0, 1.0]", "FLOAT NOT NULL ARRAY NOT NULL"); f.checkScalar("array_prepend(array(1), cast(3 as bigint))", "[3, 1]", @@ -6922,7 +6922,7 @@ void checkRegexpExtract(SqlOperatorFixture f0, FunctionAlias functionAlias) { "(INTEGER NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL ARRAY NOT NULL"); f1.checkScalar("array_insert(array[map[1, 'a']], -1, map[2, 'b'])", "[{2=b}, {1=a}]", "(INTEGER NOT NULL, CHAR(1) NOT NULL) MAP NOT NULL ARRAY NOT NULL"); - + // cast biggest type f1.checkScalar("array_insert(array(1, 2, 3), 3, cast(4 as tinyint))", "[1, 2, 4, 3]", "INTEGER NOT NULL ARRAY NOT NULL"); f1.checkScalar("array_insert(array(1, 2, 3), 3, cast(4 as double))",