You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2016/12/02 05:24:52 UTC
[1/3] calcite git commit: [CALCITE-1495] SemiJoinRule should not
apply to RIGHT and FULL JOIN, and should strip LEFT JOIN
Repository: calcite
Updated Branches:
refs/heads/master 46654ad2a -> 565d63926
[CALCITE-1495] SemiJoinRule should not apply to RIGHT and FULL JOIN, and should strip LEFT JOIN
Also, update SemiJoinRule to accept RelBuilderFactory and class parameters.
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/565d6392
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/565d6392
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/565d6392
Branch: refs/heads/master
Commit: 565d639261d126462a78e57ff7f21527f38697a9
Parents: bac9ee7
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Dec 1 16:02:13 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Dec 1 20:10:18 2016 -0800
----------------------------------------------------------------------
.../apache/calcite/rel/rules/SemiJoinRule.java | 79 +++++++++----
.../apache/calcite/test/RelOptRulesTest.java | 95 ++++++++++++++-
.../org/apache/calcite/test/RelOptRulesTest.xml | 115 ++++++++++++++++---
core/src/test/resources/sql/misc.iq | 29 +++--
4 files changed, 271 insertions(+), 47 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/565d6392/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinRule.java
index db87da3..13ad991 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinRule.java
@@ -25,12 +25,15 @@ import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.JoinInfo;
import org.apache.calcite.rel.core.Project;
-import org.apache.calcite.rel.core.SemiJoin;
+import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.ImmutableIntList;
+import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import java.util.List;
@@ -41,15 +44,34 @@ import java.util.List;
* {@link org.apache.calcite.rel.logical.LogicalAggregate}.
*/
public class SemiJoinRule extends RelOptRule {
- public static final SemiJoinRule INSTANCE = new SemiJoinRule();
+ private static final Predicate<Join> IS_LEFT_OR_INNER =
+ new Predicate<Join>() {
+ public boolean apply(Join input) {
+ switch (input.getJoinType()) {
+ case LEFT:
+ case INNER:
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
- private SemiJoinRule() {
+ public static final SemiJoinRule INSTANCE =
+ new SemiJoinRule(Project.class, Join.class, Aggregate.class,
+ RelFactories.LOGICAL_BUILDER, "SemiJoinRule");
+
+ /** Creates a SemiJoinRule. */
+ public SemiJoinRule(Class<Project> projectClass, Class<Join> joinClass,
+ Class<Aggregate> aggregateClass, RelBuilderFactory relBuilderFactory,
+ String description) {
super(
- operand(Project.class,
+ operand(projectClass,
some(
- operand(Join.class,
+ operand(joinClass, null, IS_LEFT_OR_INNER,
some(operand(RelNode.class, any()),
- operand(Aggregate.class, any()))))));
+ operand(aggregateClass, any()))))),
+ relBuilderFactory, description);
}
@Override public void onMatch(RelOptRuleCall call) {
@@ -77,24 +99,35 @@ public class SemiJoinRule extends RelOptRule {
if (!joinInfo.isEqui()) {
return;
}
- final List<Integer> newRightKeyBuilder = Lists.newArrayList();
- final List<Integer> aggregateKeys = aggregate.getGroupSet().asList();
- for (int key : joinInfo.rightKeys) {
- newRightKeyBuilder.add(aggregateKeys.get(key));
+ final RelBuilder relBuilder = call.builder();
+ relBuilder.push(left);
+ switch (join.getJoinType()) {
+ case INNER:
+ final List<Integer> newRightKeyBuilder = Lists.newArrayList();
+ final List<Integer> aggregateKeys = aggregate.getGroupSet().asList();
+ for (int key : joinInfo.rightKeys) {
+ newRightKeyBuilder.add(aggregateKeys.get(key));
+ }
+ final ImmutableIntList newRightKeys = ImmutableIntList.copyOf(newRightKeyBuilder);
+ relBuilder.push(aggregate.getInput());
+ final RexNode newCondition =
+ RelOptUtil.createEquiJoinCondition(relBuilder.peek(2, 0),
+ joinInfo.leftKeys, relBuilder.peek(2, 1), newRightKeys,
+ rexBuilder);
+ relBuilder.semiJoin(newCondition);
+ break;
+
+ case LEFT:
+ // The right-hand side produces no more than 1 row (because of the
+ // Aggregate) and no fewer than 1 row (because of LEFT), and therefore
+ // we can eliminate the semi-join.
+ break;
+
+ default:
+ throw new AssertionError(join.getJoinType());
}
- final ImmutableIntList newRightKeys =
- ImmutableIntList.copyOf(newRightKeyBuilder);
- final RelNode newRight = aggregate.getInput();
- final RexNode newCondition =
- RelOptUtil.createEquiJoinCondition(left, joinInfo.leftKeys, newRight,
- newRightKeys, rexBuilder);
- final SemiJoin semiJoin =
- SemiJoin.create(left, newRight, newCondition, joinInfo.leftKeys,
- newRightKeys);
- final Project newProject =
- project.copy(project.getTraitSet(), semiJoin, project.getProjects(),
- project.getRowType());
- call.transformTo(ProjectRemoveRule.strip(newProject));
+ relBuilder.project(project.getProjects(), project.getRowType().getFieldNames());
+ call.transformTo(relBuilder.build());
}
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/565d6392/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 3097d47..ebc0e99 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -493,7 +493,7 @@ public class RelOptRulesTest extends RelOptTestBase {
checkPlanning(program, sql);
}
- @Test public void testSemiJoinRule() {
+ @Test public void testSemiJoinRuleExists() {
final HepProgram preProgram =
HepProgram.builder()
.addRuleInstance(FilterProjectTransposeRule.INSTANCE)
@@ -516,6 +516,99 @@ public class RelOptRulesTest extends RelOptTestBase {
.check();
}
+ @Test public void testSemiJoinRule() {
+ final HepProgram preProgram =
+ HepProgram.builder()
+ .addRuleInstance(FilterProjectTransposeRule.INSTANCE)
+ .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
+ .addRuleInstance(ProjectMergeRule.INSTANCE)
+ .build();
+ final HepProgram program =
+ HepProgram.builder()
+ .addRuleInstance(SemiJoinRule.INSTANCE)
+ .build();
+ final String sql = "select dept.* from dept join (\n"
+ + " select distinct deptno from emp\n"
+ + " where sal > 100) using (deptno)";
+ sql(sql)
+ .withDecorrelation(true)
+ .withTrim(true)
+ .withPre(preProgram)
+ .with(program)
+ .check();
+ }
+
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-1495">[CALCITE-1495]
+ * SemiJoinRule should not apply to RIGHT and FULL JOIN</a>. */
+ @Test public void testSemiJoinRuleRight() {
+ final HepProgram preProgram =
+ HepProgram.builder()
+ .addRuleInstance(FilterProjectTransposeRule.INSTANCE)
+ .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
+ .addRuleInstance(ProjectMergeRule.INSTANCE)
+ .build();
+ final HepProgram program =
+ HepProgram.builder()
+ .addRuleInstance(SemiJoinRule.INSTANCE)
+ .build();
+ final String sql = "select dept.* from dept right join (\n"
+ + " select distinct deptno from emp\n"
+ + " where sal > 100) using (deptno)";
+ sql(sql)
+ .withPre(preProgram)
+ .with(program)
+ .withDecorrelation(true)
+ .withTrim(true)
+ .checkUnchanged();
+ }
+
+ /** Similar to {@link #testSemiJoinRuleRight()} but FULL. */
+ @Test public void testSemiJoinRuleFull() {
+ final HepProgram preProgram =
+ HepProgram.builder()
+ .addRuleInstance(FilterProjectTransposeRule.INSTANCE)
+ .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
+ .addRuleInstance(ProjectMergeRule.INSTANCE)
+ .build();
+ final HepProgram program =
+ HepProgram.builder()
+ .addRuleInstance(SemiJoinRule.INSTANCE)
+ .build();
+ final String sql = "select dept.* from dept full join (\n"
+ + " select distinct deptno from emp\n"
+ + " where sal > 100) using (deptno)";
+ sql(sql)
+ .withPre(preProgram)
+ .with(program)
+ .withDecorrelation(true)
+ .withTrim(true)
+ .checkUnchanged();
+ }
+
+ /** Similar to {@link #testSemiJoinRule()} but LEFT. */
+ @Test public void testSemiJoinRuleLeft() {
+ final HepProgram preProgram =
+ HepProgram.builder()
+ .addRuleInstance(FilterProjectTransposeRule.INSTANCE)
+ .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
+ .addRuleInstance(ProjectMergeRule.INSTANCE)
+ .build();
+ final HepProgram program =
+ HepProgram.builder()
+ .addRuleInstance(SemiJoinRule.INSTANCE)
+ .build();
+ final String sql = "select name from dept left join (\n"
+ + " select distinct deptno from emp\n"
+ + " where sal > 100) using (deptno)";
+ sql(sql)
+ .withPre(preProgram)
+ .with(program)
+ .withDecorrelation(true)
+ .withTrim(true)
+ .check();
+ }
+
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-438">[CALCITE-438]
* Push predicates through SemiJoin</a>. */
http://git-wip-us.apache.org/repos/asf/calcite/blob/565d6392/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index ba017bd..5313698 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3842,7 +3842,7 @@ LogicalProject(DEPTNO=[$0], NAME=[$1], EMPNO=[$2], ENAME=[$3], JOB=[$4], MGR=[$5
]]>
</Resource>
</TestCase>
- <TestCase name="testSemiJoinRule">
+ <TestCase name="testSemiJoinRuleExists">
<Resource name="sql">
<![CDATA[select * from dept where exists (
select * from emp
@@ -5130,6 +5130,93 @@ LogicalProject(DEPTNO=[$3], SUM_SAL=[$1], C=[$2])
]]>
</Resource>
</TestCase>
+ <TestCase name="testSemiJoinRule">
+ <Resource name="sql">
+ <![CDATA[select dept.* from dept join (
+ select distinct deptno from emp
+ where sal > 100) using (deptno)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1])
+ LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(DEPTNO=[$7])
+ LogicalFilter(condition=[>($5, 100)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+SemiJoin(condition=[=($0, $2)], joinType=[inner])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalProject(DEPTNO=[$7])
+ LogicalFilter(condition=[>($5, 100)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testSemiJoinRuleFull">
+ <Resource name="sql">
+ <![CDATA[select dept.* from dept full join (
+ select distinct deptno from emp
+ where sal > 100) using (deptno)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1])
+ LogicalJoin(condition=[=($0, $2)], joinType=[full])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(DEPTNO=[$7])
+ LogicalFilter(condition=[>($5, 100)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testSemiJoinRuleLeft">
+ <Resource name="sql">
+ <![CDATA[select name from dept left join (
+ select distinct deptno from emp
+ where sal > 100) using (deptno)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(NAME=[$1])
+ LogicalJoin(condition=[=($0, $2)], joinType=[left])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(DEPTNO=[$7])
+ LogicalFilter(condition=[>($5, 100)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(NAME=[$1])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testSemiJoinRuleRight">
+ <Resource name="sql">
+ <![CDATA[select dept.* from dept right join (
+ select distinct deptno from emp
+ where sal > 100) using (deptno)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1])
+ LogicalJoin(condition=[=($0, $2)], joinType=[right])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(DEPTNO=[$7])
+ LogicalFilter(condition=[>($5, 100)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testSortJoinTranspose1">
<Resource name="sql">
<![CDATA[select * from sales.emp e left join (
@@ -6192,7 +6279,10 @@ LogicalProject(JOB=[$0], EMPNO=[10], SAL=[$1], S=[$2])
</TestCase>
<TestCase name="testWhereNotInCorrelated">
<Resource name="sql">
- <![CDATA[select sal from emp where empno NOT IN (select deptno from dept where emp.job = dept.name)]]>
+ <![CDATA[select sal from emp
+where empno NOT IN (
+ select deptno from dept
+ where emp.job = dept.name)]]>
</Resource>
<Resource name="planBefore">
<![CDATA[
@@ -6209,20 +6299,15 @@ LogicalProject(DEPTNO=[$0])
<![CDATA[
LogicalProject(SAL=[$5])
LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
- LogicalFilter(condition=[IS NULL($11)])
- LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[CAST($9):INTEGER], JOB0=[CAST($10):VARCHAR(10) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary"], $f2=[CAST($11):BOOLEAN])
- LogicalJoin(condition=[AND(=($2, $10), =($0, $9))], joinType=[inner])
+ LogicalFilter(condition=[IS NULL($10)])
+ LogicalFilter(condition=[=($0, $9)])
+ LogicalCorrelate(correlation=[$cor0], joinType=[LEFT], requiredColumns=[{2}])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalProject(DEPTNO=[$0], JOB=[$1], $f2=[true])
- LogicalAggregate(group=[{0, 1}])
- LogicalProject(DEPTNO=[$0], JOB=[$2], i=[$1])
- LogicalProject(DEPTNO=[$0], i=[true], JOB=[$1])
- LogicalProject(DEPTNO=[$0], JOB=[$2])
- LogicalJoin(condition=[=($2, $1)], joinType=[inner])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
- LogicalAggregate(group=[{0}])
- LogicalProject(JOB=[$2])
- LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}])
+ LogicalProject(DEPTNO=[$0], i=[true])
+ LogicalProject(DEPTNO=[$0])
+ LogicalFilter(condition=[=($cor0.JOB, $1)])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
http://git-wip-us.apache.org/repos/asf/calcite/blob/565d6392/core/src/test/resources/sql/misc.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.iq b/core/src/test/resources/sql/misc.iq
index 0378e26..972b73c 100644
--- a/core/src/test/resources/sql/misc.iq
+++ b/core/src/test/resources/sql/misc.iq
@@ -424,18 +424,31 @@ EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NULL($t5)], expr#9=[IS NULL($t7)
EnumerableJoin(condition=[=($1, $3)], joinType=[inner])
EnumerableCalc(expr#0=[{inputs}], expr#1=[CAST($t0):INTEGER NOT NULL], proj#0..1=[{exprs}])
EnumerableAggregate(group=[{0}])
- EnumerableSemiJoin(condition=[=($1, $2)], joinType=[inner])
- EnumerableCalc(expr#0..4=[{inputs}], proj#0..1=[{exprs}])
- EnumerableTableScan(table=[[hr, emps]])
- EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
- EnumerableAggregate(group=[{1}])
- EnumerableTableScan(table=[[hr, emps]])
- EnumerableCalc(expr#0..3=[{inputs}], deptno=[$t0])
- EnumerableTableScan(table=[[hr, depts]])
+ EnumerableTableScan(table=[[hr, emps]])
EnumerableCalc(expr#0..3=[{inputs}], expr#4=[90], expr#5=[+($t0, $t4)], deptno=[$t0], $f1=[$t5])
EnumerableTableScan(table=[[hr, depts]])
!plan
+# Left join to a relation with one row is recognized as a trivial semi-join
+# and eliminated.
+select e."deptno"
+from "hr"."emps" as e
+left join (select count(*) from "hr"."depts") on true;
++--------+
+| deptno |
++--------+
+| 10 |
+| 10 |
+| 10 |
+| 20 |
++--------+
+(4 rows)
+
+!ok
+EnumerableCalc(expr#0..4=[{inputs}], deptno=[$t1])
+ EnumerableTableScan(table=[[hr, emps]])
+!plan
+
# Filter combined with an OR filter.
select * from (
select * from "hr"."emps" as e
[2/3] calcite git commit: Test case for [CALCITE-1493],
and clean up test infrastructure
Posted by jh...@apache.org.
Test case for [CALCITE-1493], and clean up test infrastructure
Also, fix a minor performance issue when tracing is disabled.
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/bac9ee7c
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/bac9ee7c
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/bac9ee7c
Branch: refs/heads/master
Commit: bac9ee7cb7e76d6307e34091b5a132e3d068dfd7
Parents: 751e2b0
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Nov 30 11:57:20 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Dec 1 20:10:18 2016 -0800
----------------------------------------------------------------------
.../org/apache/calcite/prepare/Prepare.java | 6 +-
.../org/apache/calcite/runtime/FlatLists.java | 14 +++
.../org/apache/calcite/test/CalciteAssert.java | 8 +-
.../java/org/apache/calcite/test/JdbcTest.java | 6 +-
.../apache/calcite/test/RelOptRulesTest.java | 108 +++++++++++++------
.../org/apache/calcite/test/RelOptTestBase.java | 84 ++++++++++++---
.../apache/calcite/test/SqlToRelTestBase.java | 65 +++++++----
.../org/apache/calcite/test/RelOptRulesTest.xml | 36 +++++++
8 files changed, 250 insertions(+), 77 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/main/java/org/apache/calcite/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
index 2064567..aa4ba8b 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -156,8 +156,10 @@ public abstract class Prepare {
}
final RelNode rootRel4 = program.run(planner, root.rel, desiredTraits);
- LOGGER.debug("Plan after physical tweaks: {}",
- RelOptUtil.toString(rootRel4, SqlExplainLevel.ALL_ATTRIBUTES));
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Plan after physical tweaks: {}",
+ RelOptUtil.toString(rootRel4, SqlExplainLevel.ALL_ATTRIBUTES));
+ }
return root.withRel(rootRel4);
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/FlatLists.java b/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
index 4ab4ef2..73344c4 100644
--- a/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
+++ b/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
@@ -19,6 +19,7 @@ package org.apache.calcite.runtime;
import org.apache.calcite.util.ImmutableNullableList;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import java.util.AbstractList;
import java.util.ArrayList;
@@ -26,6 +27,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.RandomAccess;
@@ -252,6 +254,18 @@ public class FlatLists {
return FlatLists.of(newList);
}
+ /** Returns a list that consists of a given list plus an element, guaranteed
+ * to be an {@link ImmutableList}. */
+ public static <E> ImmutableList<E> append(ImmutableList<E> list, E e) {
+ return ImmutableList.<E>builder().addAll(list).add(e).build();
+ }
+
+ /** Returns a map that consists of a given map plus an (key, value),
+ * guaranteed to be an {@link ImmutableMap}. */
+ public static <K, V> ImmutableMap<K, V> append(Map<K, V> map, K k, V v) {
+ return ImmutableMap.<K, V>builder().putAll(map).put(k, v).build();
+ }
+
/** Base class for flat lists. */
public abstract static class AbstractFlatList<T>
extends AbstractImmutableList<T> implements RandomAccess {
http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index c5efd87..e0f8a6b 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -28,6 +28,7 @@ import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.materialize.Lattice;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.runtime.FlatLists;
import org.apache.calcite.runtime.Hook;
import org.apache.calcite.schema.Schema;
import org.apache.calcite.schema.SchemaPlus;
@@ -1124,10 +1125,9 @@ public class CalciteAssert {
}
public ConnectionFactory with(String property, Object value) {
- ImmutableMap.Builder<String, String> b = ImmutableMap.builder();
- b.putAll(this.map);
- b.put(property, value.toString());
- return new MapConnectionFactory(b.build(), postProcessors);
+ return new MapConnectionFactory(
+ FlatLists.append(this.map, property, value.toString()),
+ postProcessors);
}
public ConnectionFactory with(
http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index bc214c2..2740c41 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -99,7 +99,6 @@ import org.apache.calcite.util.Util;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import org.hsqldb.jdbcDriver;
@@ -6892,10 +6891,7 @@ public class JdbcTest {
final Map<String, Table> tableMap = super.getTableMap();
final Table table = tableMap.get("emps");
final String tableName = (String) operand.get("tableName");
- return ImmutableMap.<String, Table>builder()
- .putAll(tableMap)
- .put(tableName, table)
- .build();
+ return FlatLists.append(tableMap, tableName, table);
}
@Override public boolean isMutable() {
http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 74e2b03..3097d47 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -274,8 +274,12 @@ public class RelOptRulesTest extends RelOptTestBase {
final String sql = "select *\n"
+ "from dept left join emp using (deptno)\n"
+ "where emp.deptno is not null and emp.sal > 100";
- checkPlanning(tester.withDecorrelation(true).withTrim(true), preProgram,
- new HepPlanner(program), sql);
+ sql(sql)
+ .withDecorrelation(true)
+ .withTrim(true)
+ .withPre(preProgram)
+ .with(program)
+ .check();
}
@Test public void testFullOuterJoinSimplificationToLeftOuter() {
@@ -500,12 +504,16 @@ public class RelOptRulesTest extends RelOptTestBase {
HepProgram.builder()
.addRuleInstance(SemiJoinRule.INSTANCE)
.build();
- checkPlanning(tester.withDecorrelation(true).withTrim(true), preProgram,
- new HepPlanner(program),
- "select * from dept where exists (\n"
- + " select * from emp\n"
- + " where emp.deptno = dept.deptno\n"
- + " and emp.sal > 100)");
+ final String sql = "select * from dept where exists (\n"
+ + " select * from emp\n"
+ + " where emp.deptno = dept.deptno\n"
+ + " and emp.sal > 100)";
+ sql(sql)
+ .withDecorrelation(true)
+ .withTrim(true)
+ .withPre(preProgram)
+ .with(program)
+ .check();
}
/** Test case for
@@ -523,11 +531,16 @@ public class RelOptRulesTest extends RelOptTestBase {
.addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
.addRuleInstance(FilterJoinRule.JOIN)
.build();
- checkPlanning(tester.withDecorrelation(true).withTrim(false), preProgram,
- new HepPlanner(program),
- "select * from (select * from dept where dept.deptno in (\n"
- + " select emp.deptno from emp\n"
- + " ))R where R.deptno <=10 ");
+ final String sql = "select * from (\n"
+ + " select * from dept where dept.deptno in (\n"
+ + " select emp.deptno from emp))R\n"
+ + "where R.deptno <=10";
+ sql(sql)
+ .withDecorrelation(true)
+ .withTrim(false)
+ .withPre(preProgram)
+ .with(program)
+ .check();
}
/** Test case for
@@ -545,8 +558,12 @@ public class RelOptRulesTest extends RelOptTestBase {
+ "from (select * from emp where deptno = 200) as e1\n"
+ "where e1.deptno in (\n"
+ " select e2.deptno from emp e2 where e2.sal = 100)";
- checkPlanning(tester.withDecorrelation(false).withTrim(true), preProgram,
- new HepPlanner(program), sql, true);
+ sql(sql)
+ .withDecorrelation(false)
+ .withTrim(true)
+ .withPre(preProgram)
+ .with(program)
+ .checkUnchanged();
}
@Test public void testSemiJoinTrim() {
@@ -1973,7 +1990,6 @@ public class RelOptRulesTest extends RelOptTestBase {
@Test public void testPullConstantThroughUnion()
throws Exception {
- HepProgram preProgram = HepProgram.builder().build();
HepProgram program = HepProgram.builder()
.addRuleInstance(UnionPullUpConstantsRule.INSTANCE)
.addRuleInstance(ProjectMergeRule.INSTANCE)
@@ -1981,7 +1997,10 @@ public class RelOptRulesTest extends RelOptTestBase {
final String sql = "select 2, deptno, job from emp as e1\n"
+ "union all\n"
+ "select 2, deptno, job from emp as e2";
- checkPlanning(tester.withTrim(true), preProgram, new HepPlanner(program), sql);
+ sql(sql)
+ .withTrim(true)
+ .with(program)
+ .check();
}
@Test public void testPullConstantThroughUnion2()
@@ -2000,7 +2019,6 @@ public class RelOptRulesTest extends RelOptTestBase {
@Test public void testPullConstantThroughUnion3()
throws Exception {
// We should leave at least a single column in each Union input
- HepProgram preProgram = HepProgram.builder().build();
HepProgram program = HepProgram.builder()
.addRuleInstance(UnionPullUpConstantsRule.INSTANCE)
.addRuleInstance(ProjectMergeRule.INSTANCE)
@@ -2008,7 +2026,10 @@ public class RelOptRulesTest extends RelOptTestBase {
final String sql = "select 2, 3 from emp as e1\n"
+ "union all\n"
+ "select 2, 3 from emp as e2";
- checkPlanning(tester.withTrim(true), preProgram, new HepPlanner(program), sql);
+ sql(sql)
+ .withTrim(true)
+ .with(program)
+ .check();
}
@Test public void testAggregateProjectMerge() throws Exception {
@@ -2257,8 +2278,6 @@ public class RelOptRulesTest extends RelOptTestBase {
* <a href="https://issues.apache.org/jira/browse/CALCITE-841">[CALCITE-841]
* Redundant windows when window function arguments are expressions</a>. */
@Test public void testExpressionInWindowFunction() {
- HepProgram preProgram = new HepProgramBuilder().build();
-
HepProgramBuilder builder = new HepProgramBuilder();
builder.addRuleClass(ProjectToWindowRule.class);
@@ -2269,16 +2288,15 @@ public class RelOptRulesTest extends RelOptTestBase {
+ " sum(deptno) over(partition by deptno order by sal) as sum1,\n"
+ "sum(deptno + sal) over(partition by deptno order by sal) as sum2\n"
+ "from emp";
- checkPlanning(tester, preProgram, hepPlanner, sql);
+ sql(sql)
+ .with(hepPlanner)
+ .check();
}
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-888">[CALCITE-888]
* Overlay window loses PARTITION BY list</a>. */
@Test public void testWindowInParenthesis() {
- HepProgram preProgram = new HepProgramBuilder()
- .build();
-
HepProgramBuilder builder = new HepProgramBuilder();
builder.addRuleClass(ProjectToWindowRule.class);
HepPlanner hepPlanner = new HepPlanner(builder.build());
@@ -2287,7 +2305,9 @@ public class RelOptRulesTest extends RelOptTestBase {
final String sql = "select count(*) over (w), count(*) over w\n"
+ "from emp\n"
+ "window w as (partition by empno order by empno)";
- checkPlanning(tester, preProgram, hepPlanner, sql);
+ sql(sql)
+ .with(hepPlanner)
+ .check();
}
/** Test case for
@@ -2479,7 +2499,8 @@ public class RelOptRulesTest extends RelOptTestBase {
* Wrong collation trait in SortJoinTransposeRule for right joins</a>. */
@Test public void testSortJoinTranspose4() {
// Create a customized test with RelCollation trait in the test cluster.
- Tester tester = new TesterImpl(getDiffRepos(), true, true, false, null, null) {
+ Tester tester = new TesterImpl(getDiffRepos(), true, true, false, false,
+ null, null) {
@Override public RelOptPlanner createPlanner() {
return new MockRelOptPlanner() {
@Override public List<RelTraitDef> getRelTraitDefs() {
@@ -2591,6 +2612,18 @@ public class RelOptRulesTest extends RelOptTestBase {
checkSubQuery(sql).check();
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-1493">[CALCITE-1493]
+ * Wrong plan for NOT IN correlated queries</a>. */
+ @Ignore("[CALCITE-1493] is not fixed yet")
+ @Test public void testWhereNotInCorrelated() {
+ final String sql = "select sal from emp\n"
+ + "where empno NOT IN (\n"
+ + " select deptno from dept\n"
+ + " where emp.job = dept.name)";
+ checkSubQuery(sql).withLateDecorrelation(false).check();
+ }
+
@Test public void testExpandProjectIn() throws Exception {
final String sql = "select empno,\n"
+ " deptno in (select deptno from sales.emp where empno < 20) as d\n"
@@ -2754,8 +2787,11 @@ public class RelOptRulesTest extends RelOptTestBase {
.addRuleInstance(SubQueryRemoveRule.FILTER)
.addRuleInstance(SubQueryRemoveRule.JOIN)
.build();
- final Tester tester = this.tester.withTrim(true).withExpand(false);
- checkPlanning(tester, null, new HepPlanner(program), sql);
+ sql(sql)
+ .withTrim(true)
+ .expand(false)
+ .with(program)
+ .check();
}
@Test public void testCustomColumnResolvingInCorrelatedSubQuery() {
@@ -2768,8 +2804,11 @@ public class RelOptRulesTest extends RelOptTestBase {
.addRuleInstance(SubQueryRemoveRule.FILTER)
.addRuleInstance(SubQueryRemoveRule.JOIN)
.build();
- final Tester tester = this.tester.withTrim(true).withExpand(false);
- checkPlanning(tester, null, new HepPlanner(program), sql);
+ sql(sql)
+ .withTrim(true)
+ .expand(false)
+ .with(program)
+ .check();
}
@Test public void testCustomColumnResolvingInCorrelatedSubQuery2() {
@@ -2782,8 +2821,11 @@ public class RelOptRulesTest extends RelOptTestBase {
.addRuleInstance(SubQueryRemoveRule.FILTER)
.addRuleInstance(SubQueryRemoveRule.JOIN)
.build();
- final Tester tester = this.tester.withTrim(true).withExpand(false);
- checkPlanning(tester, null, new HepPlanner(program), sql);
+ sql(sql)
+ .withTrim(true)
+ .expand(false)
+ .with(program)
+ .check();
}
/** Test case for
http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
index 4c57833..277d368 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
@@ -27,10 +27,13 @@ import org.apache.calcite.rel.RelRoot;
import org.apache.calcite.rel.metadata.ChainedRelMetadataProvider;
import org.apache.calcite.rel.metadata.DefaultRelMetadataProvider;
import org.apache.calcite.rel.metadata.RelMetadataProvider;
+import org.apache.calcite.runtime.FlatLists;
import org.apache.calcite.runtime.Hook;
+import org.apache.calcite.sql2rel.RelDecorrelator;
import org.apache.calcite.util.Closer;
import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
@@ -160,8 +163,11 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
planner.setRoot(relBefore);
RelNode relAfter = planner.findBestExp();
-
String planAfter = NL + RelOptUtil.toString(relAfter);
+ if (tester.isLateDecorrelate()) {
+ relAfter = RelDecorrelator.decorrelateQuery(relAfter);
+ planAfter = NL + RelOptUtil.toString(relAfter);
+ }
if (unchanged) {
assertThat(planAfter, is(planBefore));
} else {
@@ -176,7 +182,9 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
/** Sets the SQL statement for a test. */
Sql sql(String sql) {
- return new Sql(sql, null, null, true, ImmutableMap.<Hook, Function>of());
+ return new Sql(sql, null, null,
+ ImmutableMap.<Hook, Function>of(),
+ ImmutableList.<Function<Tester, Tester>>of());
}
/** Allows fluent testing. */
@@ -184,47 +192,88 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
private final String sql;
private HepProgram preProgram;
private final HepPlanner hepPlanner;
- private final boolean expand;
private final ImmutableMap<Hook, Function> hooks;
+ private ImmutableList<Function<Tester, Tester>> transforms;
Sql(String sql, HepProgram preProgram, HepPlanner hepPlanner,
- boolean expand, ImmutableMap<Hook, Function> hooks) {
+ ImmutableMap<Hook, Function> hooks,
+ ImmutableList<Function<Tester, Tester>> transforms) {
this.sql = sql;
this.preProgram = preProgram;
this.hepPlanner = hepPlanner;
- this.expand = expand;
this.hooks = hooks;
+ this.transforms = transforms;
}
public Sql withPre(HepProgram preProgram) {
- return new Sql(sql, preProgram, hepPlanner, expand, hooks);
+ return new Sql(sql, preProgram, hepPlanner, hooks, transforms);
}
public Sql with(HepPlanner hepPlanner) {
- return new Sql(sql, preProgram, hepPlanner, expand, hooks);
+ return new Sql(sql, preProgram, hepPlanner, hooks, transforms);
}
public Sql with(HepProgram program) {
- return new Sql(sql, preProgram, new HepPlanner(program), expand, hooks);
+ return new Sql(sql, preProgram, new HepPlanner(program), hooks,
+ transforms);
+ }
+
+ /** Adds a transform that will be applied to {@link #tester}
+ * just before running the query. */
+ private Sql withTransform(Function<Tester, Tester> transform) {
+ return new Sql(sql, preProgram, hepPlanner, hooks,
+ FlatLists.append(transforms, transform));
}
/** Adds a hook and a handler for that hook. Calcite will create a thread
* hook (by calling {@link Hook#addThread(com.google.common.base.Function)})
* just before running the query, and remove the hook afterwards. */
public <T> Sql withHook(Hook hook, Function<T, Void> handler) {
- return new Sql(sql, preProgram, hepPlanner, expand,
- ImmutableMap.<Hook, Function>builder().putAll(hooks)
- .put(hook, handler).build());
+ return new Sql(sql, preProgram, hepPlanner,
+ FlatLists.append(hooks, hook, handler), transforms);
}
public <V> Sql withProperty(Hook hook, V value) {
return withHook(hook, Hook.property(value));
}
- public Sql expand(boolean expand) {
- return new Sql(sql, preProgram, hepPlanner, expand, hooks);
+ public Sql expand(final boolean b) {
+ return withTransform(
+ new Function<Tester, Tester>() {
+ public Tester apply(Tester tester) {
+ return tester.withExpand(b);
+ }
+ });
+ }
+
+ public Sql withLateDecorrelation(final boolean b) {
+ return withTransform(
+ new Function<Tester, Tester>() {
+ public Tester apply(Tester tester) {
+ return tester.withLateDecorrelation(b);
+ }
+ });
+ }
+
+ public Sql withDecorrelation(final boolean b) {
+ return withTransform(
+ new Function<Tester, Tester>() {
+ public Tester apply(Tester tester) {
+ return tester.withDecorrelation(b);
+ }
+ });
+ }
+
+ public Sql withTrim(final boolean b) {
+ return withTransform(
+ new Function<Tester, Tester>() {
+ public Tester apply(Tester tester) {
+ return tester.withTrim(b);
+ }
+ });
}
+
public void check() {
check(false);
}
@@ -238,11 +287,16 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
for (Map.Entry<Hook, Function> entry : hooks.entrySet()) {
closer.add(entry.getKey().addThread(entry.getValue()));
}
- checkPlanning(tester.withExpand(expand), preProgram, hepPlanner, sql,
- unchanged);
+ Tester t = tester;
+ for (Function<Tester, Tester> transform : transforms) {
+ t = transform.apply(t);
+ }
+ checkPlanning(t, preProgram, hepPlanner, sql, unchanged);
}
}
+
}
+
}
// End RelOptTestBase.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
index 166db72..3cfbf35 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -93,7 +93,8 @@ public abstract class SqlToRelTestBase {
}
protected Tester createTester() {
- return new TesterImpl(getDiffRepos(), false, false, true, null, null);
+ return new TesterImpl(getDiffRepos(), false, false, true, false, null,
+ null);
}
/**
@@ -210,6 +211,10 @@ public abstract class SqlToRelTestBase {
/** Returns a tester that optionally decorrelates queries. */
Tester withDecorrelation(boolean enable);
+ /** Returns a tester that optionally decorrelates queries after planner
+ * rules have fired. */
+ Tester withLateDecorrelation(boolean enable);
+
/** Returns a tester that optionally expands sub-queries.
* If {@code expand} is false, the plan contains a
* {@link org.apache.calcite.rex.RexSubQuery} for each sub-query.
@@ -228,6 +233,8 @@ public abstract class SqlToRelTestBase {
Tester withTrim(boolean enable);
Tester withClusterFactory(Function<RelOptCluster, RelOptCluster> function);
+
+ boolean isLateDecorrelate();
}
//~ Inner Classes ----------------------------------------------------------
@@ -466,6 +473,7 @@ public abstract class SqlToRelTestBase {
private SqlOperatorTable opTab;
private final DiffRepository diffRepos;
private final boolean enableDecorrelate;
+ private final boolean enableLateDecorrelate;
private final boolean enableTrim;
private final boolean enableExpand;
private final Function<RelDataTypeFactory, Prepare.CatalogReader>
@@ -486,15 +494,18 @@ public abstract class SqlToRelTestBase {
*/
protected TesterImpl(DiffRepository diffRepos, boolean enableDecorrelate,
boolean enableTrim, boolean enableExpand,
+ boolean enableLateDecorrelate,
Function<RelDataTypeFactory, Prepare.CatalogReader>
catalogReaderFactory,
Function<RelOptCluster, RelOptCluster> clusterFactory) {
this(diffRepos, enableDecorrelate, enableTrim, enableExpand,
- catalogReaderFactory, clusterFactory, SqlToRelConverter.Config.DEFAULT);
+ enableLateDecorrelate, catalogReaderFactory, clusterFactory,
+ SqlToRelConverter.Config.DEFAULT);
}
protected TesterImpl(DiffRepository diffRepos, boolean enableDecorrelate,
boolean enableTrim, boolean enableExpand,
+ boolean enableLateDecorrelate,
Function<RelDataTypeFactory, Prepare.CatalogReader>
catalogReaderFactory,
Function<RelOptCluster, RelOptCluster> clusterFactory,
@@ -503,6 +514,7 @@ public abstract class SqlToRelTestBase {
this.enableDecorrelate = enableDecorrelate;
this.enableTrim = enableTrim;
this.enableExpand = enableExpand;
+ this.enableLateDecorrelate = enableLateDecorrelate;
this.catalogReaderFactory = catalogReaderFactory;
this.clusterFactory = clusterFactory;
this.config = config;
@@ -689,44 +701,61 @@ public abstract class SqlToRelTestBase {
return createValidator(catalogReader, typeFactory);
}
- public TesterImpl withDecorrelation(boolean enable) {
- return this.enableDecorrelate == enable
+ public TesterImpl withDecorrelation(boolean enableDecorrelate) {
+ return this.enableDecorrelate == enableDecorrelate
+ ? this
+ : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
+ enableExpand, enableLateDecorrelate, catalogReaderFactory,
+ clusterFactory);
+ }
+
+ public Tester withLateDecorrelation(boolean enableLateDecorrelate) {
+ return this.enableLateDecorrelate == enableLateDecorrelate
? this
- : new TesterImpl(diffRepos, enable, enableTrim, enableExpand,
- catalogReaderFactory, clusterFactory);
+ : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
+ enableExpand, enableLateDecorrelate, catalogReaderFactory,
+ clusterFactory);
}
public TesterImpl withConfig(SqlToRelConverter.Config config) {
return this.config == config
? this
: new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
- enableExpand, catalogReaderFactory, clusterFactory, config);
+ enableExpand, enableLateDecorrelate, catalogReaderFactory,
+ clusterFactory, config);
}
- public Tester withTrim(boolean enable) {
- return this.enableTrim == enable
+ public Tester withTrim(boolean enableTrim) {
+ return this.enableTrim == enableTrim
? this
- : new TesterImpl(diffRepos, enableDecorrelate, enable, enableExpand,
- catalogReaderFactory, clusterFactory);
+ : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
+ enableExpand, enableLateDecorrelate, catalogReaderFactory,
+ clusterFactory);
}
- public Tester withExpand(boolean expand) {
- return this.enableExpand == expand
+ public Tester withExpand(boolean enableExpand) {
+ return this.enableExpand == enableExpand
? this
- : new TesterImpl(diffRepos, enableDecorrelate, enableTrim, expand,
- catalogReaderFactory, clusterFactory);
+ : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
+ enableExpand, enableLateDecorrelate, catalogReaderFactory,
+ clusterFactory);
}
public Tester withCatalogReaderFactory(
Function<RelDataTypeFactory, Prepare.CatalogReader> factory) {
- return new TesterImpl(diffRepos, enableDecorrelate, false, enableExpand,
- factory, clusterFactory);
+ return new TesterImpl(diffRepos, enableDecorrelate, false,
+ enableExpand, enableLateDecorrelate, factory,
+ clusterFactory);
}
public Tester withClusterFactory(
Function<RelOptCluster, RelOptCluster> clusterFactory) {
return new TesterImpl(diffRepos, enableDecorrelate, false, enableExpand,
- catalogReaderFactory, clusterFactory);
+ enableLateDecorrelate, catalogReaderFactory, clusterFactory);
+ }
+
+ public boolean isLateDecorrelate() {
+ return enableLateDecorrelate;
}
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index e0836dd..ba017bd 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -6190,4 +6190,40 @@ LogicalProject(JOB=[$0], EMPNO=[10], SAL=[$1], S=[$2])
]]>
</Resource>
</TestCase>
+ <TestCase name="testWhereNotInCorrelated">
+ <Resource name="sql">
+ <![CDATA[select sal from emp where empno NOT IN (select deptno from dept where emp.job = dept.name)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(SAL=[$5])
+ LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(DEPTNO=[$0])
+ LogicalFilter(condition=[=($cor0.JOB, $1)])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+}))], variablesSet=[[$cor0]])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(SAL=[$5])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ LogicalFilter(condition=[IS NULL($11)])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[CAST($9):INTEGER], JOB0=[CAST($10):VARCHAR(10) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary"], $f2=[CAST($11):BOOLEAN])
+ LogicalJoin(condition=[AND(=($2, $10), =($0, $9))], joinType=[inner])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(DEPTNO=[$0], JOB=[$1], $f2=[true])
+ LogicalAggregate(group=[{0, 1}])
+ LogicalProject(DEPTNO=[$0], JOB=[$2], i=[$1])
+ LogicalProject(DEPTNO=[$0], i=[true], JOB=[$1])
+ LogicalProject(DEPTNO=[$0], JOB=[$2])
+ LogicalJoin(condition=[=($2, $1)], joinType=[inner])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(JOB=[$2])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
</Root>
[3/3] calcite git commit: [CALCITE-1524] Add a project to the planner
root so that rules know which output fields are used
Posted by jh...@apache.org.
[CALCITE-1524] Add a project to the planner root so that rules know which output fields are used
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/751e2b0c
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/751e2b0c
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/751e2b0c
Branch: refs/heads/master
Commit: 751e2b0c6d6e19bef7f07b1e0acf1ce491b59311
Parents: 46654ad
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Dec 1 17:51:24 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Dec 1 20:10:18 2016 -0800
----------------------------------------------------------------------
.../org/apache/calcite/plan/RelOptMaterialization.java | 2 ++
.../main/java/org/apache/calcite/prepare/Prepare.java | 7 +++++--
core/src/main/java/org/apache/calcite/rel/RelRoot.java | 12 +++++++++++-
3 files changed, 18 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/751e2b0c/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
index df3fac5..7759e7b 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
@@ -31,6 +31,7 @@ import org.apache.calcite.rel.rules.FilterJoinRule;
import org.apache.calcite.rel.rules.JoinProjectTransposeRule;
import org.apache.calcite.rel.rules.ProjectFilterTransposeRule;
import org.apache.calcite.rel.rules.ProjectMergeRule;
+import org.apache.calcite.rel.rules.ProjectRemoveRule;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.schema.Table;
@@ -272,6 +273,7 @@ public class RelOptMaterialization {
JoinProjectTransposeRule.RIGHT_PROJECT,
JoinProjectTransposeRule.LEFT_PROJECT,
FilterJoinRule.FilterIntoJoinRule.FILTER_ON_JOIN,
+ ProjectRemoveRule.INSTANCE,
ProjectMergeRule.INSTANCE),
false,
DefaultRelMetadataProvider.INSTANCE);
http://git-wip-us.apache.org/repos/asf/calcite/blob/751e2b0c/core/src/main/java/org/apache/calcite/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
index 2d97bb9..2064567 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -122,12 +122,15 @@ public abstract class Prepare {
* @param lattices Lattices
* @return an equivalent optimized relational expression
*/
- protected RelRoot optimize(final RelRoot root,
+ protected RelRoot optimize(RelRoot root,
final List<Materialization> materializations,
final List<CalciteSchema.LatticeEntry> lattices) {
final RelOptPlanner planner = root.rel.getCluster().getPlanner();
- planner.setRoot(root.rel);
+ // Add a project to the root. Even if the project is trivial, it informs
+ // rules firing on the relational expression below it which of the fields
+ // are used. SemiJoinRule, for instance.
+ planner.setRoot(root.project(true));
final RelTraitSet desiredTraits = getDesiredRootTraitSet(root);
final Program program = getProgram();
http://git-wip-us.apache.org/repos/asf/calcite/blob/751e2b0c/core/src/main/java/org/apache/calcite/rel/RelRoot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelRoot.java b/core/src/main/java/org/apache/calcite/rel/RelRoot.java
index 82506d2..a2fa71a 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelRoot.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelRoot.java
@@ -140,7 +140,17 @@ public class RelRoot {
/** Returns the root relational expression, creating a {@link LogicalProject}
* if necessary to remove fields that are not needed. */
public RelNode project() {
- if (isRefTrivial()) {
+ return project(false);
+ }
+
+ /** Returns the root relational expression as a {@link LogicalProject}.
+ *
+ * @param force Create a Project even if all fields are used */
+ public RelNode project(boolean force) {
+ if (isRefTrivial()
+ && (SqlKind.DML.contains(kind)
+ || !force
+ || rel instanceof LogicalProject)) {
return rel;
}
final List<RexNode> projects = new ArrayList<>();