This is an automated email from the ASF dual-hosted git repository. xiong pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push: new fc2fd2dd7 [CALCITE-5021] Double JOIN is created for NOT IN when IN-list that the values all non-nullable is converted to Values fc2fd2dd7 is described below commit fc2fd2dd7efe237905f53ed754a2af2dd0a669ff Author: NobiGo <nobigo...@gmail.com> AuthorDate: Fri Feb 25 10:35:13 2022 +0800 [CALCITE-5021] Double JOIN is created for NOT IN when IN-list that the values all non-nullable is converted to Values --- .../org/apache/calcite/sql/type/SqlTypeUtil.java | 28 ++++++++++++++++++ .../apache/calcite/sql2rel/SqlToRelConverter.java | 23 ++++++--------- .../apache/calcite/test/SqlToRelConverterTest.xml | 8 +++--- core/src/test/resources/sql/sub-query.iq | 33 +++++++++++++++++++++- 4 files changed, 73 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java index 0fcff9c33..3f5a8ec96 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java @@ -294,6 +294,34 @@ public abstract class SqlTypeUtil { return false; } + /** + * Creates a RelDataType having the same type of the sourceRelDataType, + * and the same nullability as the targetRelDataType. + */ + public static RelDataType keepSourceTypeAndTargetNullability(RelDataType sourceRelDataType, + RelDataType targetRelDataType, + RelDataTypeFactory typeFactory) { + if (!targetRelDataType.isStruct()) { + return typeFactory.createTypeWithNullability( + sourceRelDataType, targetRelDataType.isNullable()); + } + List<RelDataTypeField> targetFields = targetRelDataType.getFieldList(); + List<RelDataTypeField> sourceFields = sourceRelDataType.getFieldList(); + ImmutableList.Builder<RelDataTypeField> newTargetField = ImmutableList.builder(); + for (int i = 0; i < targetRelDataType.getFieldCount(); i++) { + RelDataTypeField targetField = targetFields.get(i); + RelDataTypeField sourceField = sourceFields.get(i); + newTargetField.add( + new RelDataTypeFieldImpl( + sourceField.getName(), + sourceField.getIndex(), + keepSourceTypeAndTargetNullability( + sourceField.getType(), targetField.getType(), typeFactory))); + } + RelDataType relDataType = typeFactory.createStructType(newTargetField.build()); + return typeFactory.createTypeWithNullability(relDataType, targetRelDataType.isNullable()); + } + /** * Returns typeName.equals(type.getSqlTypeName()). If * typeName.equals(SqlTypeName.Any) true is always returned. 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 c85c70148..c22ecc5a2 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java @@ -1397,15 +1397,16 @@ public class SqlToRelConverter { // // The first two lists contain the same number of fields. final int k = (fieldCount - 1) / 2; + ImmutableList.Builder<RexNode> rexNodeBuilder = ImmutableList.builder(); + rexNodeBuilder.add(rexNode); for (int i = 0; i < k; i++) { - rexNode = + rexNodeBuilder.add( rexBuilder.makeCall( - SqlStdOperatorTable.AND, - rexNode, - rexBuilder.makeCall( - SqlStdOperatorTable.IS_NOT_NULL, - rexBuilder.makeFieldAccess(rex, i))); + SqlStdOperatorTable.IS_NOT_NULL, + rexBuilder.makeFieldAccess(rex, i))); } + rexNode = rexBuilder.makeCall(rexNode.getType(), SqlStdOperatorTable.AND, + RexUtil.flatten(rexNodeBuilder.build(), SqlStdOperatorTable.AND)); return rexNode; case TRUE_FALSE_UNKNOWN: @@ -1717,15 +1718,9 @@ public class SqlToRelConverter { final RelDataType rowType; if (targetRowType != null) { rowType = - typeFactory.createTypeWithNullability( - targetRowType, - SqlTypeUtil.containsNullable(listType)); + SqlTypeUtil.keepSourceTypeAndTargetNullability(targetRowType, listType, typeFactory); } else { - rowType = - SqlTypeUtil.promoteToRowType( - typeFactory, - listType, - null); + rowType = SqlTypeUtil.promoteToRowType(typeFactory, listType, null); } final List<RelNode> unionInputs = new ArrayList<>(); 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 6684c5cbd..407f03ab4 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -2713,7 +2713,7 @@ LogicalTableModify(table=[[CATALOG, SALES, EMPDEFAULTS]], operation=[INSERT], fl <![CDATA[ LogicalTableModify(table=[[SALES, EMPDEFAULTS]], operation=[INSERT], flattened=[true]) LogicalFilter(condition=[=($7, 20)]) - LogicalProject(EMPNO=[$2], ENAME=[$0], JOB=[null:VARCHAR(10)], MGR=[null:INTEGER], HIREDATE=[null:TIMESTAMP(0)], SAL=[$4], COMM=[null:INTEGER], DEPTNO=[$1], SLACKER=[null:BOOLEAN], EXTRA=[null:BOOLEAN], UPDATED=[$3]) + LogicalProject(EMPNO=[$2], ENAME=[$0], JOB=[null:VARCHAR(10)], MGR=[null:INTEGER], HIREDATE=[null:TIMESTAMP(0)], SAL=[CAST($4):INTEGER], COMM=[null:INTEGER], DEPTNO=[CAST($1):INTEGER], SLACKER=[null:BOOLEAN], EXTRA=[null:BOOLEAN], UPDATED=[CAST($3):TIMESTAMP(0)]) LogicalValues(tuples=[[{ 'Fred', 20, 44, 2017-03-12 13:03:05, 999999 }]]) ]]> </Resource> @@ -2725,7 +2725,7 @@ LogicalTableModify(table=[[SALES, EMPDEFAULTS]], operation=[INSERT], flattened=[ <Resource name="plan"> <![CDATA[ LogicalTableModify(table=[[SALES, EMPDEFAULTS]], operation=[INSERT], flattened=[true]) - LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[null:INTEGER], HIREDATE=[null:TIMESTAMP(0)], SAL=[555], COMM=[null:INTEGER], DEPTNO=[20], SLACKER=[null:BOOLEAN]) + LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[CAST($2):VARCHAR(10)], MGR=[null:INTEGER], HIREDATE=[null:TIMESTAMP(0)], SAL=[555], COMM=[null:INTEGER], DEPTNO=[20], SLACKER=[null:BOOLEAN]) LogicalValues(tuples=[[{ 34625, 'nom', 'accountant' }]]) ]]> </Resource> @@ -2764,7 +2764,7 @@ values (10, 'Fred')]]> <![CDATA[ LogicalTableModify(table=[[CATALOG, SALES, EMPNULLABLES]], operation=[INSERT], flattened=[true]) LogicalFilter(condition=[>($5, 1000)]) - LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[null:VARCHAR(10)], MGR=[null:INTEGER], HIREDATE=[null:TIMESTAMP(0)], SAL=[null:INTEGER], COMM=[null:INTEGER], DEPTNO=[20], SLACKER=[null:BOOLEAN]) + LogicalProject(EMPNO=[$0], ENAME=[CAST($1):VARCHAR(20)], JOB=[null:VARCHAR(10)], MGR=[null:INTEGER], HIREDATE=[null:TIMESTAMP(0)], SAL=[null:INTEGER], COMM=[null:INTEGER], DEPTNO=[20], SLACKER=[null:BOOLEAN]) LogicalValues(tuples=[[{ 10, 'Fred' }]]) ]]> </Resource> @@ -2790,7 +2790,7 @@ values (150, 'Fred')]]> <![CDATA[ LogicalTableModify(table=[[CATALOG, SALES, EMPNULLABLES]], operation=[INSERT], flattened=[true]) LogicalFilter(condition=[>($5, 1000)]) - LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[null:VARCHAR(10)], MGR=[null:INTEGER], HIREDATE=[null:TIMESTAMP(0)], SAL=[null:INTEGER], COMM=[null:INTEGER], DEPTNO=[20], SLACKER=[null:BOOLEAN]) + LogicalProject(EMPNO=[$0], ENAME=[CAST($1):VARCHAR(20)], JOB=[null:VARCHAR(10)], MGR=[null:INTEGER], HIREDATE=[null:TIMESTAMP(0)], SAL=[null:INTEGER], COMM=[null:INTEGER], DEPTNO=[20], SLACKER=[null:BOOLEAN]) LogicalValues(tuples=[[{ 150, 'Fred' }]]) ]]> </Resource> diff --git a/core/src/test/resources/sql/sub-query.iq b/core/src/test/resources/sql/sub-query.iq index cbdc992b7..bbad2b6f2 100644 --- a/core/src/test/resources/sql/sub-query.iq +++ b/core/src/test/resources/sql/sub-query.iq @@ -3345,11 +3345,42 @@ EnumerableCalc(expr#0..14=[{inputs}], expr#15=[0:BIGINT], expr#16=[=($t8, $t15)] EnumerableCalc(expr#0..9=[{inputs}], proj#0..9=[{exprs}], EMPNO0=[$t0], DEPTNO0=[$t7]) EnumerableNestedLoopJoin(condition=[true], joinType=[inner]) EnumerableTableScan(table=[[scott, EMP]]) - EnumerableAggregate(group=[{}], agg#0=[COUNT()], agg#1=[COUNT($0, $1)]) + EnumerableAggregate(group=[{}], agg#0=[COUNT()], agg#1=[COUNT($1)]) EnumerableValues(tuples=[[{ 1, 2 }, { 3, null }]]) EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[ASC]) EnumerableCalc(expr#0..1=[{inputs}], expr#2=[true], proj#0..2=[{exprs}]) EnumerableValues(tuples=[[{ 1, 2 }, { 3, null }]]) !plan +select * from "scott".emp where (empno, deptno) not in ((7369, 20), (7499, 30)); ++-------+--------+-----------+------+------------+---------+---------+--------+ +| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | ++-------+--------+-----------+------+------------+---------+---------+--------+ +| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | +| 7566 | JONES | MANAGER | 7839 | 1981-02-04 | 2975.00 | | 20 | +| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | +| 7698 | BLAKE | MANAGER | 7839 | 1981-01-05 | 2850.00 | | 30 | +| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | | 10 | +| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | | 20 | +| 7839 | KING | PRESIDENT | | 1981-11-17 | 5000.00 | | 10 | +| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | +| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | | 20 | +| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | | 30 | +| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | | 20 | +| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | | 10 | ++-------+--------+-----------+------+------------+---------+---------+--------+ +(12 rows) + +!ok + +EnumerableCalc(expr#0..12=[{inputs}], expr#13=[IS NOT TRUE($t12)], expr#14=[IS NULL($t9)], expr#15=[OR($t13, $t14)], proj#0..7=[{exprs}], $condition=[$t15]) + EnumerableMergeJoin(condition=[AND(=($8, $10), =($9, $11))], joinType=[left]) + EnumerableSort(sort0=[$8], sort1=[$9], dir0=[ASC], dir1=[ASC]) + EnumerableCalc(expr#0..7=[{inputs}], proj#0..7=[{exprs}], EMPNO0=[$t0], DEPTNO0=[$t7]) + EnumerableTableScan(table=[[scott, EMP]]) + EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[ASC]) + EnumerableCalc(expr#0..1=[{inputs}], expr#2=[true], proj#0..2=[{exprs}]) + EnumerableValues(tuples=[[{ 7369, 20 }, { 7499, 30 }]]) +!plan + # End sub-query.iq