Return-Path: X-Original-To: apmail-calcite-commits-archive@www.apache.org Delivered-To: apmail-calcite-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1A87C18A65 for ; Mon, 13 Jul 2015 20:44:27 +0000 (UTC) Received: (qmail 2395 invoked by uid 500); 13 Jul 2015 20:44:27 -0000 Delivered-To: apmail-calcite-commits-archive@calcite.apache.org Received: (qmail 2367 invoked by uid 500); 13 Jul 2015 20:44:27 -0000 Mailing-List: contact commits-help@calcite.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@calcite.incubator.apache.org Delivered-To: mailing list commits@calcite.incubator.apache.org Received: (qmail 2358 invoked by uid 99); 13 Jul 2015 20:44:26 -0000 Received: from Unknown (HELO spamd2-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 13 Jul 2015 20:44:26 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd2-us-west.apache.org (ASF Mail Server at spamd2-us-west.apache.org) with ESMTP id 856AC1A6F15 for ; Mon, 13 Jul 2015 20:44:26 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd2-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 1.77 X-Spam-Level: * X-Spam-Status: No, score=1.77 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, T_RP_MATCHES_RCVD=-0.01] autolearn=disabled Received: from mx1-us-east.apache.org ([10.40.0.8]) by localhost (spamd2-us-west.apache.org [10.40.0.9]) (amavisd-new, port 10024) with ESMTP id ejbL13-Cl8w3 for ; Mon, 13 Jul 2015 20:44:22 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-us-east.apache.org (ASF Mail Server at mx1-us-east.apache.org) with SMTP id 3B6C242AF1 for ; Mon, 13 Jul 2015 20:44:22 +0000 (UTC) Received: (qmail 2246 invoked by uid 99); 13 Jul 2015 20:44:21 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 13 Jul 2015 20:44:21 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 27567E0C07; Mon, 13 Jul 2015 20:44:21 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: jhyde@apache.org To: commits@calcite.incubator.apache.org Date: Mon, 13 Jul 2015 20:44:22 -0000 Message-Id: In-Reply-To: <3bc76ac658ea48b49895391f9fcacf49@git.apache.org> References: <3bc76ac658ea48b49895391f9fcacf49@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [2/3] incubator-calcite git commit: [CALCITE-801] NullPointerException using USING on table alias with column aliases [CALCITE-801] NullPointerException using USING on table alias with column aliases Fix an issue numbering the fields in a RelCrossType Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/c57d8072 Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/c57d8072 Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/c57d8072 Branch: refs/heads/master Commit: c57d80725766c84834a35e4f3b68feb38540b66c Parents: 23396f0 Author: Julian Hyde Authored: Mon Jul 13 12:35:46 2015 -0700 Committer: Julian Hyde Committed: Mon Jul 13 12:44:27 2015 -0700 ---------------------------------------------------------------------- .../apache/calcite/rel/type/RelCrossType.java | 1 - .../rel/type/RelDataTypeFactoryImpl.java | 48 ++++++------- .../calcite/sql2rel/SqlToRelConverter.java | 65 +++++++++-------- .../calcite/test/SqlToRelConverterTest.java | 39 +++++++---- .../calcite/test/SqlToRelConverterTest.xml | 73 +++++++++++++------- core/src/test/resources/sql/join.oq | 20 ++++++ 6 files changed, 148 insertions(+), 98 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java b/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java index d361b7b..ba2ac85 100644 --- a/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java +++ b/core/src/main/java/org/apache/calcite/rel/type/RelCrossType.java @@ -44,7 +44,6 @@ public class RelCrossType extends RelDataTypeImpl { List fields) { super(fields); this.types = ImmutableList.copyOf(types); - assert types != null; assert types.size() >= 1; for (RelDataType type : types) { assert !(type instanceof RelCrossType); http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java index e9016b8..46f8ba3 100644 --- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java +++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java @@ -126,12 +126,10 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory { public RelDataType createJoinType(RelDataType... types) { assert types != null; assert types.length >= 1; - final List flattenedTypes = - getTypeArray(ImmutableList.copyOf(types)); + final List flattenedTypes = new ArrayList<>(); + getTypeList(ImmutableList.copyOf(types), flattenedTypes); return canonize( - new RelCrossType( - flattenedTypes, - getFieldArray(flattenedTypes))); + new RelCrossType(flattenedTypes, getFieldList(flattenedTypes))); } // implement RelDataTypeFactory @@ -359,11 +357,10 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory { } /** - * Returns an array of the fields in an array of types. + * Returns a list of the fields in a list of types. */ - private static List getFieldArray(List types) { - ArrayList fieldList = - new ArrayList(); + private static List getFieldList(List types) { + final List fieldList = new ArrayList<>(); for (RelDataType type : types) { addFields(type, fieldList); } @@ -371,20 +368,14 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory { } /** - * Returns an array of all atomic types in an array. + * Returns a list of all atomic types in a list. */ - private static List getTypeArray(List types) { - List flatTypes = new ArrayList(); - getTypeArray(types, flatTypes); - return flatTypes; - } - - private static void getTypeArray( - List inTypes, + private static void getTypeList( + ImmutableList inTypes, List flatTypes) { for (RelDataType inType : inTypes) { if (inType instanceof RelCrossType) { - getTypeArray(((RelCrossType) inType).types, flatTypes); + getTypeList(((RelCrossType) inType).types, flatTypes); } else { flatTypes.add(inType); } @@ -392,11 +383,13 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory { } /** - * Adds all fields in type to fieldList. + * Adds all fields in type to fieldList, + * renumbering the fields (if necessary) to ensure that their index + * matches their position in the list. */ private static void addFields( RelDataType type, - ArrayList fieldList) { + List fieldList) { if (type instanceof RelCrossType) { final RelCrossType crossType = (RelCrossType) type; for (RelDataType type1 : crossType.types) { @@ -405,6 +398,10 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory { } else { List fields = type.getFieldList(); for (RelDataTypeField field : fields) { + if (field.getIndex() != fieldList.size()) { + field = new RelDataTypeFieldImpl(field.getName(), fieldList.size(), + field.getType()); + } fieldList.add(field); } } @@ -415,8 +412,7 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory { } private List fieldsOf(Class clazz) { - final List list = - new ArrayList(); + final List list = new ArrayList<>(); for (Field field : clazz.getFields()) { if (Modifier.isStatic(field.getModifiers())) { continue; @@ -436,8 +432,10 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory { } /** - * implement RelDataTypeFactory with SQL 2003 compliant behavior. Let p1, s1 - * be the precision and scale of the first operand Let p2, s2 be the + * {@inheritDoc} + * + *

Implement RelDataTypeFactory with SQL 2003 compliant behavior. Let p1, + * s1 be the precision and scale of the first operand Let p2, s2 be the * precision and scale of the second operand Let p, s be the precision and * scale of the result, Then the result type is a decimal with: * http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java index 5ca783f..e733d13 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java @@ -562,8 +562,8 @@ public class SqlToRelConverter { RelDataType validatedRowType = validator.getValidatedNodeType(query); validatedRowType = uniquifyFields(validatedRowType); - return RelOptUtil.equal( - "validated row type", validatedRowType, "converted row type", convertedRowType, false); + return RelOptUtil.equal("validated row type", validatedRowType, + "converted row type", convertedRowType, false); } protected RelDataType uniquifyFields(RelDataType rowType) { @@ -1910,16 +1910,22 @@ public class SqlToRelConverter { RelNode rightRel = rightBlackboard.root; JoinRelType convertedJoinType = convertJoinType(joinType); RexNode conditionExp; + final SqlValidatorNamespace leftNamespace = validator.getNamespace(left); + final SqlValidatorNamespace rightNamespace = validator.getNamespace(right); if (isNatural) { + final RelDataType leftRowType = leftNamespace.getRowType(); + final RelDataType rightRowType = rightNamespace.getRowType(); final List columnList = - SqlValidatorUtil.deriveNaturalJoinColumnList( - validator.getNamespace(left).getRowType(), - validator.getNamespace(right).getRowType()); - conditionExp = convertUsing(leftRel, rightRel, columnList); + SqlValidatorUtil.deriveNaturalJoinColumnList(leftRowType, + rightRowType); + conditionExp = convertUsing(leftNamespace, rightNamespace, + columnList); } else { conditionExp = convertJoinCondition( fromBlackboard, + leftNamespace, + rightNamespace, join.getCondition(), join.getConditionType(), leftRel, @@ -2253,8 +2259,9 @@ public class SqlToRelConverter { return Collections.emptyList(); } - private RexNode convertJoinCondition( - Blackboard bb, + private RexNode convertJoinCondition(Blackboard bb, + SqlValidatorNamespace leftNamespace, + SqlValidatorNamespace rightNamespace, SqlNode condition, JoinConditionType conditionType, RelNode leftRel, @@ -2276,7 +2283,7 @@ public class SqlToRelConverter { String name = id.getSimple(); nameList.add(name); } - return convertUsing(leftRel, rightRel, nameList); + return convertUsing(leftNamespace, rightNamespace, nameList); default: throw Util.unexpected(conditionType); } @@ -2287,37 +2294,29 @@ public class SqlToRelConverter { * from NATURAL JOIN. "a JOIN b USING (x, y)" becomes "a.x = b.x AND a.y = * b.y". Returns null if the column list is empty. * - * @param leftRel Left input to the join - * @param rightRel Right input to the join + * @param leftNamespace Namespace of left input to join + * @param rightNamespace Namespace of right input to join * @param nameList List of column names to join on * @return Expression to match columns from name list, or true if name list * is empty */ - private RexNode convertUsing( - RelNode leftRel, - RelNode rightRel, + private RexNode convertUsing(SqlValidatorNamespace leftNamespace, + SqlValidatorNamespace rightNamespace, List nameList) { final List list = Lists.newArrayList(); for (String name : nameList) { - final RelDataType leftRowType = leftRel.getRowType(); - RelDataTypeField leftField = catalogReader.field(leftRowType, name); - RexNode left = - rexBuilder.makeInputRef( - leftField.getType(), - leftField.getIndex()); - final RelDataType rightRowType = rightRel.getRowType(); - RelDataTypeField rightField = - catalogReader.field(rightRowType, name); - RexNode right = - rexBuilder.makeInputRef( - rightField.getType(), - leftRowType.getFieldList().size() + rightField.getIndex()); - RexNode equalsCall = - rexBuilder.makeCall( - SqlStdOperatorTable.EQUALS, - left, - right); - list.add(equalsCall); + List operands = new ArrayList<>(); + int offset = 0; + for (SqlValidatorNamespace n : ImmutableList.of(leftNamespace, + rightNamespace)) { + final RelDataType rowType = n.getRowType(); + final RelDataTypeField field = catalogReader.field(rowType, name); + operands.add( + rexBuilder.makeInputRef(field.getType(), + offset + field.getIndex())); + offset += rowType.getFieldList().size(); + } + list.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, operands)); } return RexUtil.composeConjunction(rexBuilder, list, false); } http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/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 083367e..ee7f2c9 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -151,6 +151,19 @@ public class SqlToRelConverterTest extends SqlToRelTestBase { "${plan}"); } + /** Test case for + * [CALCITE-801] + * NullPointerException using USING on table alias with column + * aliases. */ + @Test public void testValuesUsing() { + check("select d.deptno, min(e.empid) as empid\n" + + "from (values (100, 'Bill', 1)) as e(empid, name, deptno)\n" + + "join (values (1, 'LeaderShip')) as d(deptno, name)\n" + + " using (deptno)\n" + + "group by d.deptno", + "${plan}"); + } + @Test public void testJoinNatural() { check( "SELECT * FROM emp NATURAL JOIN dept", @@ -1198,7 +1211,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase { @Test public void testSubqueryLimitOne() { sql("select deptno\n" + "from EMP\n" - + "where deptno > (select deptno \n" + + "where deptno > (select deptno\n" + "from EMP order by deptno limit 1)") .convertsTo("${plan}"); } @@ -1222,10 +1235,10 @@ public class SqlToRelConverterTest extends SqlToRelTestBase { * Scan HAVING clause for sub-queries and IN-lists relating to IN. */ @Test public void testHavingAggrFunctionIn() { - sql("select deptno \n" - + "from emp \n" - + "group by deptno \n" - + "having sum(case when deptno in (1, 2) then 0 else 1 end) + \n" + sql("select deptno\n" + + "from emp\n" + + "group by deptno\n" + + "having sum(case when deptno in (1, 2) then 0 else 1 end) +\n" + "sum(case when deptno in (3, 4) then 0 else 1 end) > 10") .convertsTo("${plan}"); } @@ -1237,14 +1250,14 @@ public class SqlToRelConverterTest extends SqlToRelTestBase { * the HAVING clause. */ @Test public void testHavingInSubqueryWithAggrFunction() { - sql("select sal \n" - + "from emp \n" - + "group by sal \n" - + "having sal in \n" - + "(select deptno \n" - + "from dept \n" - + "group by deptno \n" - + "having sum(deptno) > 0)") + sql("select sal\n" + + "from emp\n" + + "group by sal\n" + + "having sal in (\n" + + " select deptno\n" + + " from dept\n" + + " group by deptno\n" + + " having sum(deptno) > 0)") .convertsTo("${plan}"); } http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/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 075ccd2..1130160 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -2438,7 +2438,7 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1) FILTER $2], EXPR$2=[COUNT()]) (select min(deptno) * 2 + 10 from EMP]]> +where deptno > (select min(deptno) * 2 + 10 from EMP)]]> 10)]]> +sum(case when deptno in (3, 4) then 0 else 1 end) > 10]]> 0)]]> +having sal in ( + select deptno + from dept + group by deptno + having sum(deptno) > 0)]]> - + - + + max(e.empno) over (partition by e.deptno) +from emp e, dept d +where e.deptno = d.deptno +group by d.deptno, e.empno, e.deptno +]]> +max(empno) over (partition by deptno) +from emp group by deptno, empno +having empno < 10 and min(deptno) < 20 +]]> - - + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c57d8072/core/src/test/resources/sql/join.oq ---------------------------------------------------------------------- diff --git a/core/src/test/resources/sql/join.oq b/core/src/test/resources/sql/join.oq index 97898bf..83cfb7c 100644 --- a/core/src/test/resources/sql/join.oq +++ b/core/src/test/resources/sql/join.oq @@ -235,4 +235,24 @@ EnumerableCalc(expr#0..3=[{inputs}], DEPTNO=[$t2], DEPTNO0=[$t0]) EnumerableTableScan(table=[[scott, EMP]]) !plan +### [CALCITE-801] NullPointerException using USING on table alias with column aliases +select * +from (values (100, 'Bill', 1), + (200, 'Eric', 1), + (150, 'Sebastian', 3)) as e(empid, name, deptno) +join (values (1, 'LeaderShip'), + (2, 'TestGroup'), + (3, 'Development')) as d(deptno, name) +using (deptno); ++-------+-----------+--------+---------+-------------+ +| EMPID | NAME | DEPTNO | DEPTNO0 | NAME0 | ++-------+-----------+--------+---------+-------------+ +| 100 | Bill | 1 | 1 | LeaderShip | +| 150 | Sebastian | 3 | 3 | Development | +| 200 | Eric | 1 | 1 | LeaderShip | ++-------+-----------+--------+---------+-------------+ +(3 rows) + +!ok + # End join.oq