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 ca1b2f92768..b4465ab4345 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 @@ -1476,14 +1476,18 @@ private static void adjustTypeForArrayFunctions( // such as spark array, the SqlKind is other function. // however, the name is same for those different array forms. && "ARRAY".equals(((SqlBasicCall) operand).getOperator().getName())) { - call.setOperand(idx, castArrayElementTo(validator, operand, targetType)); + RelDataType elementType = + arrayOperands ? targetType + : requireNonNull(targetType.getComponentType(), + () -> "componentType of " + targetType); + call.setOperand(idx, castArrayElementTo(validator, operand, elementType)); // The rewrite changes the element types of the array constructor, // so the type the validator has recorded for it must change too RelDataType priorType = validator.getValidatedNodeTypeIfKnown(operand); if (priorType != null) { validator.setValidatedNodeType(operand, SqlTypeUtil.createArrayType(opBinding.getTypeFactory(), - targetType, priorType.isNullable())); + elementType, priorType.isNullable())); } } else { RelDataType castType = targetType; 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 95381426f93..6082c27638d 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -8358,6 +8358,10 @@ void checkRegexpExtract(SqlOperatorFixture f0, FunctionAlias functionAlias) { + "array[cast(3 as double)])", "[[1.0, 2.0], [3.0]]", "DOUBLE NOT NULL ARRAY NOT NULL ARRAY NOT NULL"); + // Test case for [CALCITE-7704] + // ARRAY_INSERT crashes in code generation with array-of-arrays argument + f.checkScalar("array_append(array[array[cast(1 as double)]], array[2])", + "[[1.0], [2.0]]", "DOUBLE NOT NULL ARRAY NOT NULL ARRAY NOT NULL"); // element cast to the biggest type f.checkScalar("array_append(array(cast(1 as tinyint)), 2)", "[1, 2]", @@ -8707,6 +8711,10 @@ void checkRegexpExtract(SqlOperatorFixture f0, FunctionAlias functionAlias) { f.checkScalar("array_prepend(array_distinct(array[1, 2, 3]), " + "cast(4 as double))", "[4.0, 1.0, 2.0, 3.0]", "DOUBLE NOT NULL ARRAY NOT NULL"); + // Test case for [CALCITE-7704] + // ARRAY_INSERT crashes in code generation with array-of-arrays argument + f.checkScalar("array_prepend(array[array[cast(1 as double)]], array[2])", + "[[2.0], [1.0]]", "DOUBLE NOT NULL ARRAY NOT NULL ARRAY NOT NULL"); // element cast to the biggest type f.checkScalar("array_prepend(array(1), cast(3 as float))", "[3.0, 1.0]", @@ -9064,6 +9072,12 @@ void checkArrayReverseFunc(SqlOperatorFixture f0, SqlFunction function, + "cast(array[array[1, 2]] as integer array array), 1, " + "array[cast(3 as double)])", "[[3.0], [1.0, 2.0]]", "DOUBLE NOT NULL ARRAY ARRAY NOT NULL"); + // Test case for [CALCITE-7704] + // ARRAY_INSERT crashes in code generation with array-of-arrays argument + f1.checkScalar("array_insert(array[array[cast(1 as double)]], 1, array[2])", + "[[2.0], [1.0]]", "DOUBLE NOT NULL ARRAY ARRAY NOT NULL"); + f1.checkScalar("array_insert(array[array[1]], 1, array[2.5])", + "[[2.5], [1.0]]", "DECIMAL(11, 1) NOT NULL ARRAY ARRAY NOT NULL"); f1.checkScalar("array_insert(array[1, 2, 3], 3, 4)", "[1, 2, 4, 3]", "INTEGER ARRAY NOT NULL");