Skip to content

Commit

Permalink
[CALCITE-6127] The spark array function gives NullPointerException wh…
Browse files Browse the repository at this point in the history
…en element is row type
  • Loading branch information
chucheng92 committed Dec 12, 2023
1 parent 56eb062 commit afd0def
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1061,23 +1061,29 @@ static RelDataType deriveTypeSplit(SqlOperatorBinding operatorBinding,
private static RelDataType arrayReturnType(SqlOperatorBinding opBinding) {
final List<RelDataType> operandTypes = opBinding.collectOperandTypes();

// only numeric & character types check
// only numeric & character types check, this is a special spark array case
// the form like ARRAY(1, 2, '3') will return ["1", "2", "3"]
boolean hasNumeric = false;
boolean hasCharacter = false;
boolean hasOthers = false;
for (RelDataType type : operandTypes) {
SqlTypeFamily family = type.getSqlTypeName().getFamily();
requireNonNull(family, "array element type family");
// some types such as Row, the family is null, fallback to normal inferred type logic
if (family == null) {
hasOthers = true;
break;
}
// skip it because we allow NULL literal
if (SqlTypeUtil.isNull(type)) {
continue;
}
switch (family) {
case NUMERIC:
hasNumeric = true;
break;
case CHARACTER:
hasCharacter = true;
break;
case NULL:
// skip it becase we allow null
break;
default:
hasOthers = true;
break;
Expand Down
23 changes: 23 additions & 0 deletions testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10537,6 +10537,29 @@ private static void checkArrayConcatAggFuncFails(SqlOperatorFixture t) {
"[null, foo]", "CHAR(3) ARRAY NOT NULL");
f2.checkScalar("array(null)",
"[null]", "NULL ARRAY NOT NULL");
// check complex type
f2.checkScalar("array(row(1))", "[{1}]",
"RecordType(INTEGER NOT NULL EXPR$0) NOT NULL ARRAY NOT NULL");
f2.checkScalar("array(row(1, null))", "[{1, null}]",
"RecordType(INTEGER NOT NULL EXPR$0, NULL EXPR$1) NOT NULL ARRAY NOT NULL");
f2.checkScalar("array(row(null, 1))", "[{null, 1}]",
"RecordType(NULL EXPR$0, INTEGER NOT NULL EXPR$1) NOT NULL ARRAY NOT NULL");
f2.checkScalar("array(row(1, 2))", "[{1, 2}]",
"RecordType(INTEGER NOT NULL EXPR$0, INTEGER NOT NULL EXPR$1) NOT NULL ARRAY NOT NULL");
f2.checkFails("^array(row(1, 2), null)^",
"Parameters must be of the same type", false);
f2.checkFails("^array(null, row(1, 2))^",
"Parameters must be of the same type", false);
f2.checkScalar("array(row(1, null), row(2, null))", "[{1, null}, {2, null}]",
"RecordType(INTEGER NOT NULL EXPR$0, NULL EXPR$1) NOT NULL ARRAY NOT NULL");
f2.checkScalar("array(row(null, 1), row(null, 2))", "[{null, 1}, {null, 2}]",
"RecordType(NULL EXPR$0, INTEGER NOT NULL EXPR$1) NOT NULL ARRAY NOT NULL");
f2.checkScalar("array(row(1, null), row(null, 2))", "[{1, null}, {null, 2}]",
"RecordType(INTEGER EXPR$0, INTEGER EXPR$1) NOT NULL ARRAY NOT NULL");
f2.checkScalar("array(row(null, 1), row(2, null))", "[{null, 1}, {2, null}]",
"RecordType(INTEGER EXPR$0, INTEGER EXPR$1) NOT NULL ARRAY NOT NULL");
f2.checkScalar("array(row(1, 2), row(3, 4))", "[{1, 2}, {3, 4}]",
"RecordType(INTEGER NOT NULL EXPR$0, INTEGER NOT NULL EXPR$1) NOT NULL ARRAY NOT NULL");
// calcite default cast char type will fill extra spaces
f2.checkScalar("array(1, 2, 'Hi')",
"[1 , 2 , Hi]", "CHAR(2) NOT NULL ARRAY NOT NULL");
Expand Down

0 comments on commit afd0def

Please sign in to comment.