[CALCITE-2468] Validator throws IndexOutOfBoundsException when trying to infer operand type from STRUCT return type (Rong Rong)
Add example in server module's type.iq test. Fix type inference when operator is AS with a complex row of just 1 element. Close apache/calcite#932 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/40d12b74 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/40d12b74 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/40d12b74 Branch: refs/heads/branch-1.18 Commit: 40d12b7419bd544bd829011a18ac37f6bc529ce7 Parents: 4da9c0d Author: Rong Rong <walter_...@hotmail.com> Authored: Mon Aug 20 17:16:19 2018 -0700 Committer: Julian Hyde <jh...@apache.org> Committed: Wed Dec 5 16:19:32 2018 -0800 ---------------------------------------------------------------------- .../calcite/sql/validate/SqlValidatorImpl.java | 31 +++++++++++++------- .../calcite/test/SqlToRelConverterTest.java | 10 +++++++ .../calcite/test/SqlToRelConverterTest.xml | 12 ++++++++ server/src/test/resources/sql/type.iq | 22 ++++++++++++++ 4 files changed, 65 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/40d12b74/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java index 626399f..41fdab5 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java @@ -131,6 +131,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Supplier; +import javax.annotation.Nonnull; import static org.apache.calcite.sql.SqlUtil.stripAs; import static org.apache.calcite.util.Static.RESOURCE; @@ -454,7 +455,9 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { selectItems.add(expanded); aliases.add(alias); - inferUnknownTypes(targetType, scope, expanded); + if (expanded != null) { + inferUnknownTypes(targetType, scope, expanded); + } final RelDataType type = deriveType(selectScope, expanded); setValidatedNodeType(expanded, type); fields.add(Pair.of(alias, type)); @@ -1720,9 +1723,12 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { } protected void inferUnknownTypes( - RelDataType inferredType, - SqlValidatorScope scope, - SqlNode node) { + @Nonnull RelDataType inferredType, + @Nonnull SqlValidatorScope scope, + @Nonnull SqlNode node) { + Objects.requireNonNull(inferredType); + Objects.requireNonNull(scope); + Objects.requireNonNull(node); final SqlValidatorScope newScope = scopes.get(node); if (newScope != null) { scope = newScope; @@ -1790,6 +1796,9 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { } else { setValidatedNodeType(caseCall.getElseOperand(), returnType); } + } else if (node.getKind() == SqlKind.AS) { + // For AS operator, only infer the operand not the alias + inferUnknownTypes(inferredType, scope, ((SqlCall) node).operand(0)); } else if (node instanceof SqlCall) { final SqlCall call = (SqlCall) node; final SqlOperandTypeInference operandTypeInference = @@ -1797,18 +1806,20 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { final SqlCallBinding callBinding = new SqlCallBinding(this, scope, call); final List<SqlNode> operands = callBinding.operands(); final RelDataType[] operandTypes = new RelDataType[operands.size()]; - if (operandTypeInference == null) { - // TODO: eventually should assert(operandTypeInference != null) - // instead; for now just eat it - Arrays.fill(operandTypes, unknownType); - } else { + Arrays.fill(operandTypes, unknownType); + // TODO: eventually should assert(operandTypeInference != null) + // instead; for now just eat it + if (operandTypeInference != null) { operandTypeInference.inferOperandTypes( callBinding, inferredType, operandTypes); } for (int i = 0; i < operands.size(); ++i) { - inferUnknownTypes(operandTypes[i], scope, operands.get(i)); + final SqlNode operand = operands.get(i); + if (operand != null) { + inferUnknownTypes(operandTypes[i], scope, operand); + } } } } http://git-wip-us.apache.org/repos/asf/calcite/blob/40d12b74/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java index 77fa01c..1207020 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -123,6 +123,16 @@ public class SqlToRelConverterTest extends SqlToRelTestBase { sql(sql).ok(); } + /** Test case for: + * <a href="https://issues.apache.org/jira/browse/CALCITE-2468">[CALCITE-2468] + * struct type alias should not cause IOOBE.</a>. + */ + @Test public void testStructTypeAlias() { + final String sql = "select t.r AS myRow \n" + + "from (select row(row(1)) r from dept) t"; + sql(sql).ok(); + } + @Test public void testJoinUsingDynamicTable() { final String sql = "select * from SALES.NATION t1\n" http://git-wip-us.apache.org/repos/asf/calcite/blob/40d12b74/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml ---------------------------------------------------------------------- diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml index 9128946..28d2e3f 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -1459,6 +1459,18 @@ LogicalProject(A=[$0], B=[$1], C=[$2], DEPTNO=[$3], NAME=[$4]) ]]> </Resource> </TestCase> + <TestCase name="testStructTypeAlias"> + <Resource name="sql"> + <![CDATA[select t.r AS myRow +from (select row(row(1)) r from dept) t]]> + </Resource> + <Resource name="plan"> + <![CDATA[ +LogicalProject(MYROW$$0$$0=[1]) + LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) +]]> + </Resource> + </TestCase> <TestCase name="testJoinWithUnion"> <Resource name="sql"> <![CDATA[select grade http://git-wip-us.apache.org/repos/asf/calcite/blob/40d12b74/server/src/test/resources/sql/type.iq ---------------------------------------------------------------------- diff --git a/server/src/test/resources/sql/type.iq b/server/src/test/resources/sql/type.iq index 64314e9..7103be4 100644 --- a/server/src/test/resources/sql/type.iq +++ b/server/src/test/resources/sql/type.iq @@ -49,7 +49,29 @@ select * from t; !ok + +# Create a table with complex structure type +# This is to test struct type inference in +# <a href="https://issues.apache.org/jira/browse/CALCITE-1222">[CALCITE-2468] + +create type mytype1 as (ii int not null); +(0 rows modified) + +!update + +# Create a complex table +create table v (i int not null, j mytype1 not null); +(0 rows modified) + +!update + +select i AS myInt, j AS myStruct from v; +MYINT INTEGER(10) NOT NULL +MYSTRUCT STRUCT NOT NULL +!type + drop table t; +drop table v; (0 rows modified) !update