You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by ru...@apache.org on 2021/07/07 10:49:43 UTC
[calcite] branch master updated: RelOptRulesTest improvements: -
Provide relFn pattern mechanism to test a RelNode function instead of a sql
string - Refactor several tests to use relFn - Refactor similar tests by
using common auxiliary methods - Correct auxiliary methods names (use
"check" prefix instead of "test" prefix)
This is an automated email from the ASF dual-hosted git repository.
rubenql 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 d46137a RelOptRulesTest improvements: - Provide relFn pattern mechanism to test a RelNode function instead of a sql string - Refactor several tests to use relFn - Refactor similar tests by using common auxiliary methods - Correct auxiliary methods names (use "check" prefix instead of "test" prefix)
d46137a is described below
commit d46137a197a2840ea5ff9f3b38bb86d423c9af11
Author: rubenada <ru...@gmail.com>
AuthorDate: Wed Jun 16 15:05:51 2021 +0100
RelOptRulesTest improvements:
- Provide relFn pattern mechanism to test a RelNode function instead of a sql string
- Refactor several tests to use relFn
- Refactor similar tests by using common auxiliary methods
- Correct auxiliary methods names (use "check" prefix instead of "test" prefix)
---
.../org/apache/calcite/test/RelOptRulesTest.java | 1266 ++++++--------------
.../org/apache/calcite/test/RelOptTestBase.java | 58 +-
.../org/apache/calcite/test/TopDownOptTest.java | 2 +-
.../org/apache/calcite/test/RelOptRulesTest.xml | 177 ++-
4 files changed, 573 insertions(+), 930 deletions(-)
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 f76b62e..d2b53c1 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -134,6 +134,7 @@ import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
+import java.util.function.Function;
import java.util.function.Predicate;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -391,105 +392,60 @@ class RelOptRulesTest extends RelOptTestBase {
* <a href="https://issues.apache.org/jira/browse/CALCITE-3170">[CALCITE-3170]
* ANTI join on conditions push down generates wrong plan</a>. */
@Test void testCanNotPushAntiJoinConditionsToLeft() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
// build a rel equivalent to sql:
// select * from emp
// where emp.deptno
// not in (select dept.deptno from dept where emp.deptno > 20)
- RelNode left = relBuilder.scan("EMP").build();
- RelNode right = relBuilder.scan("DEPT").build();
- RelNode relNode = relBuilder.push(left)
- .push(right)
- .antiJoin(
- relBuilder.call(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")),
- relBuilder.call(SqlStdOperatorTable.GREATER_THAN,
- RexInputRef.of(0, left.getRowType()),
- relBuilder.literal(20)))
- .project(relBuilder.field(0))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.JOIN_CONDITION_PUSH)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ checkCanNotPushSemiOrAntiJoinConditionsToLeft(JoinRelType.ANTI);
}
@Test void testCanNotPushAntiJoinConditionsToRight() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
// build a rel equivalent to sql:
// select * from emp
// where emp.deptno
// not in (select dept.deptno from dept where dept.dname = 'ddd')
- RelNode relNode = relBuilder.scan("EMP")
+ final Function<RelBuilder, RelNode> relFn = b -> b
+ .scan("EMP")
.scan("DEPT")
.antiJoin(
- relBuilder.call(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")),
- relBuilder.equals(relBuilder.field(2, 1, "DNAME"),
- relBuilder.literal("ddd")))
- .project(relBuilder.field(0))
+ b.call(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")),
+ b.equals(b.field(2, 1, "DNAME"),
+ b.literal("ddd")))
+ .project(b.field(0))
.build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.JOIN_CONDITION_PUSH)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ relFn(relFn).withRule(CoreRules.JOIN_CONDITION_PUSH).checkUnchanged();
}
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-3171">[CALCITE-3171]
* SemiJoin on conditions push down throws IndexOutOfBoundsException</a>. */
@Test void testPushSemiJoinConditionsToLeft() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
// build a rel equivalent to sql:
// select * from emp
// where emp.deptno
// in (select dept.deptno from dept where emp.empno > 20)
- RelNode left = relBuilder.scan("EMP").build();
- RelNode right = relBuilder.scan("DEPT").build();
- RelNode relNode = relBuilder.push(left)
- .push(right)
- .semiJoin(
- relBuilder.call(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")),
- relBuilder.call(SqlStdOperatorTable.GREATER_THAN,
- RexInputRef.of(0, left.getRowType()),
- relBuilder.literal(20)))
- .project(relBuilder.field(0))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.JOIN_PUSH_EXPRESSIONS)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ checkCanNotPushSemiOrAntiJoinConditionsToLeft(JoinRelType.SEMI);
+ }
+
+ private void checkCanNotPushSemiOrAntiJoinConditionsToLeft(JoinRelType type) {
+ final Function<RelBuilder, RelNode> relFn = b -> {
+ RelNode left = b.scan("EMP").build();
+ RelNode right = b.scan("DEPT").build();
+ return b.push(left)
+ .push(right)
+ .join(type,
+ b.call(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")),
+ b.call(SqlStdOperatorTable.GREATER_THAN,
+ RexInputRef.of(0, left.getRowType()),
+ b.literal(20)))
+ .project(b.field(0))
+ .build();
+ };
+ relFn(relFn).withRule(CoreRules.JOIN_PUSH_EXPRESSIONS).checkUnchanged();
}
/** Test case for
@@ -515,61 +471,54 @@ class RelOptRulesTest extends RelOptTestBase {
* <a href="https://issues.apache.org/jira/browse/CALCITE-3887">[CALCITE-3887]
* Filter and Join conditions may not need to retain nullability during simplifications</a>. */
@Test void testPushSemiJoinConditions() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- RelNode left = relBuilder.scan("EMP")
- .project(
- relBuilder.field("DEPTNO"),
- relBuilder.field("ENAME"))
- .build();
- RelNode right = relBuilder.scan("DEPT")
- .project(
- relBuilder.field("DEPTNO"),
- relBuilder.field("DNAME"))
- .build();
-
- relBuilder.push(left).push(right);
-
- RexInputRef ref1 = relBuilder.field(2, 0, "DEPTNO");
- RexInputRef ref2 = relBuilder.field(2, 1, "DEPTNO");
- RexInputRef ref3 = relBuilder.field(2, 0, "ENAME");
- RexInputRef ref4 = relBuilder.field(2, 1, "DNAME");
-
- // ref1 IS NOT DISTINCT FROM ref2
- RexCall cond1 = (RexCall) relBuilder.call(
- SqlStdOperatorTable.OR,
- relBuilder.call(SqlStdOperatorTable.EQUALS, ref1, ref2),
- relBuilder.call(SqlStdOperatorTable.AND,
- relBuilder.call(SqlStdOperatorTable.IS_NULL, ref1),
- relBuilder.call(SqlStdOperatorTable.IS_NULL, ref2)));
-
- // ref3 IS NOT DISTINCT FROM ref4
- RexCall cond2 = (RexCall) relBuilder.call(
- SqlStdOperatorTable.OR,
- relBuilder.call(SqlStdOperatorTable.EQUALS, ref3, ref4),
- relBuilder.call(SqlStdOperatorTable.AND,
- relBuilder.call(SqlStdOperatorTable.IS_NULL, ref3),
- relBuilder.call(SqlStdOperatorTable.IS_NULL, ref4)));
-
- RexNode cond = relBuilder.call(SqlStdOperatorTable.AND, cond1, cond2);
- RelNode relNode = relBuilder.semiJoin(cond)
- .project(relBuilder.field(0))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.JOIN_PUSH_EXPRESSIONS)
- .addRuleInstance(CoreRules.SEMI_JOIN_PROJECT_TRANSPOSE)
- .addRuleInstance(CoreRules.JOIN_REDUCE_EXPRESSIONS)
- .addRuleInstance(CoreRules.FILTER_REDUCE_EXPRESSIONS)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
+ final Function<RelBuilder, RelNode> relFn = b -> {
+ RelNode left = b.scan("EMP")
+ .project(
+ b.field("DEPTNO"),
+ b.field("ENAME"))
+ .build();
+ RelNode right = b.scan("DEPT")
+ .project(
+ b.field("DEPTNO"),
+ b.field("DNAME"))
+ .build();
+
+ b.push(left).push(right);
+
+ RexInputRef ref1 = b.field(2, 0, "DEPTNO");
+ RexInputRef ref2 = b.field(2, 1, "DEPTNO");
+ RexInputRef ref3 = b.field(2, 0, "ENAME");
+ RexInputRef ref4 = b.field(2, 1, "DNAME");
+
+ // ref1 IS NOT DISTINCT FROM ref2
+ RexCall cond1 = (RexCall) b.call(
+ SqlStdOperatorTable.OR,
+ b.call(SqlStdOperatorTable.EQUALS, ref1, ref2),
+ b.call(SqlStdOperatorTable.AND,
+ b.call(SqlStdOperatorTable.IS_NULL, ref1),
+ b.call(SqlStdOperatorTable.IS_NULL, ref2)));
+
+ // ref3 IS NOT DISTINCT FROM ref4
+ RexCall cond2 = (RexCall) b.call(
+ SqlStdOperatorTable.OR,
+ b.call(SqlStdOperatorTable.EQUALS, ref3, ref4),
+ b.call(SqlStdOperatorTable.AND,
+ b.call(SqlStdOperatorTable.IS_NULL, ref3),
+ b.call(SqlStdOperatorTable.IS_NULL, ref4)));
+
+ RexNode cond = b.call(SqlStdOperatorTable.AND, cond1, cond2);
+ return b.semiJoin(cond)
+ .project(b.field(0))
+ .build();
+ };
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ relFn(relFn)
+ .withRule(
+ CoreRules.JOIN_PUSH_EXPRESSIONS,
+ CoreRules.SEMI_JOIN_PROJECT_TRANSPOSE,
+ CoreRules.JOIN_REDUCE_EXPRESSIONS,
+ CoreRules.FILTER_REDUCE_EXPRESSIONS)
+ .check();
}
@Test void testFullOuterJoinSimplificationToLeftOuter() {
@@ -619,78 +568,43 @@ class RelOptRulesTest extends RelOptTestBase {
* <a href="https://issues.apache.org/jira/browse/CALCITE-3225">[CALCITE-3225]
* JoinToMultiJoinRule should not match SEMI/ANTI LogicalJoin</a>. */
@Test void testJoinToMultiJoinDoesNotMatchSemiJoin() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
// build a rel equivalent to sql:
// select * from
// (select * from emp join dept ON emp.deptno = emp.deptno) t
// where emp.job in (select job from bonus)
- RelNode left = relBuilder.scan("EMP").build();
- RelNode right = relBuilder.scan("DEPT").build();
- RelNode semiRight = relBuilder.scan("BONUS").build();
- RelNode relNode = relBuilder.push(left)
- .push(right)
- .join(JoinRelType.INNER,
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .push(semiRight)
- .semiJoin(
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, "JOB"),
- relBuilder.field(2, 1, "JOB")))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.JOIN_TO_MULTI_JOIN)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ checkJoinToMultiJoinDoesNotMatchSemiOrAntiJoin(JoinRelType.SEMI);
}
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-3225">[CALCITE-3225]
* JoinToMultiJoinRule should not match SEMI/ANTI LogicalJoin</a>. */
@Test void testJoinToMultiJoinDoesNotMatchAntiJoin() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
// build a rel equivalent to sql:
// select * from
// (select * from emp join dept ON emp.deptno = emp.deptno) t
// where not exists (select job from bonus where emp.job = bonus.job)
- RelNode left = relBuilder.scan("EMP").build();
- RelNode right = relBuilder.scan("DEPT").build();
- RelNode antiRight = relBuilder.scan("BONUS").build();
- RelNode relNode = relBuilder.push(left)
- .push(right)
- .join(JoinRelType.INNER,
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .push(antiRight)
- .antiJoin(
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, "JOB"),
- relBuilder.field(2, 1, "JOB")))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.JOIN_TO_MULTI_JOIN)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ checkJoinToMultiJoinDoesNotMatchSemiOrAntiJoin(JoinRelType.ANTI);
+ }
+
+ private void checkJoinToMultiJoinDoesNotMatchSemiOrAntiJoin(JoinRelType type) {
+ final Function<RelBuilder, RelNode> relFn = b -> {
+ RelNode left = b.scan("EMP").build();
+ RelNode right = b.scan("DEPT").build();
+ RelNode semiRight = b.scan("BONUS").build();
+ return b.push(left)
+ .push(right)
+ .join(JoinRelType.INNER,
+ b.call(SqlStdOperatorTable.EQUALS,
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")))
+ .push(semiRight)
+ .join(type,
+ b.call(SqlStdOperatorTable.EQUALS,
+ b.field(2, 0, "JOB"),
+ b.field(2, 1, "JOB")))
+ .build();
+ };
+ relFn(relFn).withRule(CoreRules.JOIN_TO_MULTI_JOIN).check();
}
@Test void testPushFilterPastAgg() {
@@ -802,116 +716,60 @@ class RelOptRulesTest extends RelOptTestBase {
.withDescription("FilterJoinRule:no-filter")
.as(FilterJoinRule.JoinConditionPushRule.Config.class)
.toRule();
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
-
- RelNode left = relBuilder.scan("DEPT").build();
- RelNode right = relBuilder.scan("EMP").build();
- RelNode plan = relBuilder.push(left)
- .push(right)
- .semiJoin(
- relBuilder.and(
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, 0),
- relBuilder.field(2, 1, 7)),
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 1, 5),
- relBuilder.literal(100))))
- .project(relBuilder.field(1))
- .build();
-
- final String planBefore = NL + RelOptUtil.toString(plan);
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(join)
- .build();
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(plan);
- RelNode output = hepPlanner.findBestExp();
+ final Function<RelBuilder, RelNode> relFn = b -> {
+ RelNode left = b.scan("DEPT").build();
+ RelNode right = b.scan("EMP").build();
+ return b.push(left)
+ .push(right)
+ .semiJoin(
+ b.and(
+ b.call(SqlStdOperatorTable.EQUALS,
+ b.field(2, 0, 0),
+ b.field(2, 1, 7)),
+ b.call(SqlStdOperatorTable.EQUALS,
+ b.field(2, 1, 5),
+ b.literal(100))))
+ .project(b.field(1))
+ .build();
+ };
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ relFn(relFn).withRule(join).check();
}
@Test void testSemiJoinProjectTranspose() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
// build a rel equivalent to sql:
// select a.name from dept a
// where a.deptno in (select b.deptno * 2 from dept);
-
- RelNode left = relBuilder.scan("DEPT").build();
- RelNode right = relBuilder.scan("DEPT")
- .project(
- relBuilder.call(
- SqlStdOperatorTable.MULTIPLY, relBuilder.literal(2), relBuilder.field(0)))
- .aggregate(relBuilder.groupKey(ImmutableBitSet.of(0))).build();
-
- RelNode plan = relBuilder.push(left)
- .push(right)
- .semiJoin(
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, 0),
- relBuilder.field(2, 1, 0)))
- .project(relBuilder.field(1))
- .build();
-
- final String planBefore = NL + RelOptUtil.toString(plan);
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.PROJECT_JOIN_TRANSPOSE)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(plan);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ checkSemiOrAntiJoinProjectTranspose(JoinRelType.SEMI);
}
@Test void testAntiJoinProjectTranspose() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
// build a rel equivalent to sql:
// select a.name from dept a
// where a.deptno not in (select b.deptno * 2 from dept);
-
- RelNode left = relBuilder.scan("DEPT").build();
- RelNode right = relBuilder.scan("DEPT")
- .project(
- relBuilder.call(
- SqlStdOperatorTable.MULTIPLY, relBuilder.literal(2), relBuilder.field(0)))
- .aggregate(relBuilder.groupKey(ImmutableBitSet.of(0))).build();
-
- RelNode plan = relBuilder.push(left)
- .push(right)
- .antiJoin(
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, 0),
- relBuilder.field(2, 1, 0)))
- .project(relBuilder.field(1))
- .build();
-
- final String planBefore = NL + RelOptUtil.toString(plan);
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.PROJECT_JOIN_TRANSPOSE)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(plan);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ checkSemiOrAntiJoinProjectTranspose(JoinRelType.ANTI);
+ }
+
+ private void checkSemiOrAntiJoinProjectTranspose(JoinRelType type) {
+ final Function<RelBuilder, RelNode> relFn = b -> {
+ RelNode left = b.scan("DEPT").build();
+ RelNode right = b.scan("DEPT")
+ .project(
+ b.call(
+ SqlStdOperatorTable.MULTIPLY, b.literal(2), b.field(0)))
+ .aggregate(b.groupKey(ImmutableBitSet.of(0))).build();
+
+ return b.push(left)
+ .push(right)
+ .join(type,
+ b.call(SqlStdOperatorTable.EQUALS,
+ b.field(2, 0, 0),
+ b.field(2, 1, 0)))
+ .project(b.field(1))
+ .build();
+ };
+ relFn(relFn).withRule(CoreRules.PROJECT_JOIN_TRANSPOSE).check();
}
@Test void testJoinProjectTranspose1() {
@@ -1712,79 +1570,38 @@ class RelOptRulesTest extends RelOptTestBase {
}
@Test void testProjectCorrelateTransposeRuleSemiCorrelate() {
- RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- RelNode left = relBuilder
- .values(new String[]{"f", "f2"}, "1", "2").build();
-
- CorrelationId correlationId = new CorrelationId(0);
- RexNode rexCorrel =
- relBuilder.getRexBuilder().makeCorrel(
- left.getRowType(),
- correlationId);
-
- RelNode right = relBuilder
- .values(new String[]{"f3", "f4"}, "1", "2")
- .project(relBuilder.field(0),
- relBuilder.getRexBuilder()
- .makeFieldAccess(rexCorrel, 0))
- .build();
- LogicalCorrelate correlate = new LogicalCorrelate(left.getCluster(),
- left.getTraitSet(), left, right, correlationId,
- ImmutableBitSet.of(0), JoinRelType.SEMI);
-
- relBuilder.push(correlate);
- RelNode relNode = relBuilder.project(relBuilder.field(0))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.PROJECT_CORRELATE_TRANSPOSE)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ checkProjectCorrelateTransposeRuleSemiOrAntiCorrelate(JoinRelType.SEMI);
}
@Test void testProjectCorrelateTransposeRuleAntiCorrelate() {
- RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- RelNode left = relBuilder
- .values(new String[]{"f", "f2"}, "1", "2").build();
-
- CorrelationId correlationId = new CorrelationId(0);
- RexNode rexCorrel =
- relBuilder.getRexBuilder().makeCorrel(
- left.getRowType(),
- correlationId);
-
- RelNode right = relBuilder
- .values(new String[]{"f3", "f4"}, "1", "2")
- .project(relBuilder.field(0),
- relBuilder.getRexBuilder().makeFieldAccess(rexCorrel, 0)).build();
- LogicalCorrelate correlate = new LogicalCorrelate(left.getCluster(),
- left.getTraitSet(), left, right, correlationId,
- ImmutableBitSet.of(0), JoinRelType.ANTI);
-
- relBuilder.push(correlate);
- RelNode relNode = relBuilder.project(relBuilder.field(0))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.PROJECT_CORRELATE_TRANSPOSE)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
+ checkProjectCorrelateTransposeRuleSemiOrAntiCorrelate(JoinRelType.ANTI);
+ }
+
+ private void checkProjectCorrelateTransposeRuleSemiOrAntiCorrelate(JoinRelType type) {
+ final Function<RelBuilder, RelNode> relFn = b -> {
+ RelNode left = b
+ .values(new String[]{"f", "f2"}, "1", "2").build();
+
+ CorrelationId correlationId = new CorrelationId(0);
+ RexNode rexCorrel =
+ b.getRexBuilder().makeCorrel(
+ left.getRowType(),
+ correlationId);
+
+ RelNode right = b
+ .values(new String[]{"f3", "f4"}, "1", "2")
+ .project(b.field(0),
+ b.getRexBuilder().makeFieldAccess(rexCorrel, 0)).build();
+ LogicalCorrelate correlate = new LogicalCorrelate(left.getCluster(),
+ left.getTraitSet(), left, right, correlationId,
+ ImmutableBitSet.of(0), type);
+
+ b.push(correlate);
+ return b.project(b.field(0))
+ .build();
+ };
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ relFn(relFn).withRule(CoreRules.PROJECT_CORRELATE_TRANSPOSE).check();
}
@Test void testProjectCorrelateTransposeWithExprCond() {
@@ -2030,97 +1847,52 @@ class RelOptRulesTest extends RelOptTestBase {
}
@Test void testPushJoinThroughUnionOnRightDoesNotMatchSemiJoin() {
- final RelBuilder builder = RelBuilder.create(RelBuilderTest.config().build());
-
// build a rel equivalent to sql:
// select r1.sal from
// emp r1 where r1.deptno in
- // (select deptno from dept d1 where deptno > 100
+ // (select deptno from dept d1 where deptno < 10
// union all
// select deptno from dept d2 where deptno > 20)
- RelNode left = builder.scan("EMP").build();
- RelNode right = builder
- .scan("DEPT")
- .filter(
- builder.call(SqlStdOperatorTable.GREATER_THAN,
- builder.field("DEPTNO"),
- builder.literal(100)))
- .project(builder.field("DEPTNO"))
- .scan("DEPT")
- .filter(
- builder.call(SqlStdOperatorTable.GREATER_THAN,
- builder.field("DEPTNO"),
- builder.literal(20)))
- .project(builder.field("DEPTNO"))
- .union(true)
- .build();
- RelNode relNode = builder.push(left).push(right)
- .semiJoin(
- builder.call(SqlStdOperatorTable.EQUALS,
- builder.field(2, 0, "DEPTNO"),
- builder.field(2, 1, "DEPTNO")))
- .project(builder.field("SAL"))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.JOIN_RIGHT_UNION_TRANSPOSE)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ checkPushJoinThroughUnionOnRightDoesNotMatchSemiOrAntiJoin(JoinRelType.SEMI);
}
@Test void testPushJoinThroughUnionOnRightDoesNotMatchAntiJoin() {
- final RelBuilder builder = RelBuilder.create(RelBuilderTest.config().build());
-
// build a rel equivalent to sql:
// select r1.sal from
// emp r1 where r1.deptno not in
// (select deptno from dept d1 where deptno < 10
// union all
// select deptno from dept d2 where deptno > 20)
- RelNode left = builder.scan("EMP").build();
- RelNode right = builder
- .scan("DEPT")
- .filter(
- builder.call(SqlStdOperatorTable.LESS_THAN,
- builder.field("DEPTNO"),
- builder.literal(10)))
- .project(builder.field("DEPTNO"))
- .scan("DEPT")
- .filter(
- builder.call(SqlStdOperatorTable.GREATER_THAN,
- builder.field("DEPTNO"),
- builder.literal(20)))
- .project(builder.field("DEPTNO"))
- .union(true)
- .build();
- RelNode relNode = builder.push(left).push(right)
- .antiJoin(
- builder.call(SqlStdOperatorTable.EQUALS,
- builder.field(2, 0, "DEPTNO"),
- builder.field(2, 1, "DEPTNO")))
- .project(builder.field("SAL"))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.JOIN_RIGHT_UNION_TRANSPOSE)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ checkPushJoinThroughUnionOnRightDoesNotMatchSemiOrAntiJoin(JoinRelType.ANTI);
+ }
+
+ private void checkPushJoinThroughUnionOnRightDoesNotMatchSemiOrAntiJoin(JoinRelType type) {
+ final Function<RelBuilder, RelNode> relFn = b -> {
+ RelNode left = b.scan("EMP").build();
+ RelNode right = b
+ .scan("DEPT")
+ .filter(
+ b.call(SqlStdOperatorTable.LESS_THAN,
+ b.field("DEPTNO"),
+ b.literal(10)))
+ .project(b.field("DEPTNO"))
+ .scan("DEPT")
+ .filter(
+ b.call(SqlStdOperatorTable.GREATER_THAN,
+ b.field("DEPTNO"),
+ b.literal(20)))
+ .project(b.field("DEPTNO"))
+ .union(true)
+ .build();
+ return b.push(left).push(right)
+ .join(type,
+ b.call(SqlStdOperatorTable.EQUALS,
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")))
+ .project(b.field("SAL"))
+ .build();
+ };
+ relFn(relFn).withRule(CoreRules.JOIN_RIGHT_UNION_TRANSPOSE).checkUnchanged();
}
@Test void testMergeFilterWithJoinCondition() {
@@ -3008,8 +2780,6 @@ class RelOptRulesTest extends RelOptTestBase {
* Constant reducer must not duplicate calls to non-deterministic
* functions</a>. */
@Test void testReduceConstantsNonDeterministicFunction() {
- final DiffRepository diffRepos = getDiffRepos();
-
final SqlOperator nonDeterministicOp =
new SqlSpecialOperator("NDC", SqlKind.OTHER_FUNCTION, 0, false,
ReturnTypes.INTEGER, null, null) {
@@ -3022,34 +2792,18 @@ class RelOptRulesTest extends RelOptTestBase {
// SELECT sal, n
// FROM (SELECT sal, NDC() AS n FROM emp)
// WHERE n > 10
- final RelBuilder builder =
- RelBuilder.create(RelBuilderTest.config().build());
- final RelNode root =
- builder.scan("EMP")
- .project(builder.field("SAL"),
- builder.alias(builder.call(nonDeterministicOp), "N"))
+ final Function<RelBuilder, RelNode> relFn = b ->
+ b.scan("EMP")
+ .project(b.field("SAL"),
+ b.alias(b.call(nonDeterministicOp), "N"))
.filter(
- builder.call(SqlStdOperatorTable.GREATER_THAN,
- builder.field("N"), builder.literal(10)))
+ b.call(SqlStdOperatorTable.GREATER_THAN,
+ b.field("N"), b.literal(10)))
.build();
- HepProgram preProgram = new HepProgramBuilder().build();
- HepPlanner prePlanner = new HepPlanner(preProgram);
- prePlanner.setRoot(root);
- final RelNode relBefore = prePlanner.findBestExp();
- final String planBefore = NL + RelOptUtil.toString(relBefore);
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
-
- final HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.FILTER_REDUCE_EXPRESSIONS)
- .addRuleInstance(CoreRules.PROJECT_REDUCE_EXPRESSIONS)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(root);
- final RelNode relAfter = hepPlanner.findBestExp();
- final String planAfter = NL + RelOptUtil.toString(relAfter);
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ relFn(relFn)
+ .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS, CoreRules.PROJECT_REDUCE_EXPRESSIONS)
+ .checkUnchanged();
}
/** Checks that constant reducer duplicates calls to dynamic functions, if
@@ -3206,12 +2960,7 @@ class RelOptRulesTest extends RelOptTestBase {
final String sql = "select * from (\n"
+ "select * from emp where false) as e\n"
+ "join dept as d on e.deptno = d.deptno";
- sql(sql)
- .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS,
- PruneEmptyRules.PROJECT_INSTANCE,
- PruneEmptyRules.JOIN_LEFT_INSTANCE,
- PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .check();
+ checkEmptyJoin(sql(sql));
}
@Test void testLeftEmptyLeftJoin() {
@@ -3219,12 +2968,7 @@ class RelOptRulesTest extends RelOptTestBase {
final String sql = "select * from (\n"
+ " select * from emp where false) e\n"
+ "left join dept d on e.deptno = d.deptno";
- sql(sql)
- .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS,
- PruneEmptyRules.PROJECT_INSTANCE,
- PruneEmptyRules.JOIN_LEFT_INSTANCE,
- PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .check();
+ checkEmptyJoin(sql(sql));
}
@Test void testLeftEmptyRightJoin() {
@@ -3233,12 +2977,7 @@ class RelOptRulesTest extends RelOptTestBase {
final String sql = "select * from (\n"
+ " select * from emp where false) e\n"
+ "right join dept d on e.deptno = d.deptno";
- sql(sql)
- .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS,
- PruneEmptyRules.PROJECT_INSTANCE,
- PruneEmptyRules.JOIN_LEFT_INSTANCE,
- PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .check();
+ checkEmptyJoin(sql(sql));
}
@Test void testLeftEmptyFullJoin() {
@@ -3247,74 +2986,28 @@ class RelOptRulesTest extends RelOptTestBase {
final String sql = "select * from (\n"
+ " select * from emp where false) e\n"
+ "full join dept d on e.deptno = d.deptno";
- sql(sql)
- .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS,
- PruneEmptyRules.PROJECT_INSTANCE,
- PruneEmptyRules.JOIN_LEFT_INSTANCE,
- PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .check();
+ checkEmptyJoin(sql(sql));
}
@Test void testLeftEmptySemiJoin() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RelNode relNode = relBuilder
- .scan("EMP").empty()
- .scan("DEPT")
- .semiJoin(relBuilder
- .equals(
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .project(relBuilder.field("EMPNO"))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.FILTER_REDUCE_EXPRESSIONS)
- .addRuleInstance(PruneEmptyRules.PROJECT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_LEFT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .build();
-
- final HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- final RelNode output = hepPlanner.findBestExp();
-
- final String planBefore = NL + RelOptUtil.toString(relNode);
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- // Plan should be empty
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ checkLeftEmptySemiOrAntiJoin(JoinRelType.SEMI);
}
@Test void testLeftEmptyAntiJoin() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RelNode relNode = relBuilder
+ checkLeftEmptySemiOrAntiJoin(JoinRelType.ANTI);
+ }
+
+ private void checkLeftEmptySemiOrAntiJoin(JoinRelType type) {
+ final Function<RelBuilder, RelNode> relFn = b -> b
.scan("EMP").empty()
.scan("DEPT")
- .antiJoin(relBuilder
+ .join(type, b
.equals(
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .project(relBuilder.field("EMPNO"))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.FILTER_REDUCE_EXPRESSIONS)
- .addRuleInstance(PruneEmptyRules.PROJECT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_LEFT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_RIGHT_INSTANCE)
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")))
+ .project(b.field("EMPNO"))
.build();
-
- final HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- final RelNode output = hepPlanner.findBestExp();
-
- final String planBefore = NL + RelOptUtil.toString(relNode);
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- // Plan should be empty
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ checkEmptyJoin(relFn(relFn));
}
@Test void testRightEmptyInnerJoin() {
@@ -3322,12 +3015,7 @@ class RelOptRulesTest extends RelOptTestBase {
final String sql = "select * from emp e\n"
+ "join (select * from dept where false) as d\n"
+ "on e.deptno = d.deptno";
- sql(sql)
- .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS,
- PruneEmptyRules.PROJECT_INSTANCE,
- PruneEmptyRules.JOIN_LEFT_INSTANCE,
- PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .check();
+ checkEmptyJoin(sql(sql));
}
@Test void testRightEmptyLeftJoin() {
@@ -3336,12 +3024,7 @@ class RelOptRulesTest extends RelOptTestBase {
final String sql = "select * from emp e\n"
+ "left join (select * from dept where false) as d\n"
+ "on e.deptno = d.deptno";
- sql(sql)
- .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS,
- PruneEmptyRules.PROJECT_INSTANCE,
- PruneEmptyRules.JOIN_LEFT_INSTANCE,
- PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .check();
+ checkEmptyJoin(sql(sql));
}
@Test void testRightEmptyRightJoin() {
@@ -3349,12 +3032,7 @@ class RelOptRulesTest extends RelOptTestBase {
final String sql = "select * from emp e\n"
+ "right join (select * from dept where false) as d\n"
+ "on e.deptno = d.deptno";
- sql(sql)
- .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS,
- PruneEmptyRules.PROJECT_INSTANCE,
- PruneEmptyRules.JOIN_LEFT_INSTANCE,
- PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .check();
+ checkEmptyJoin(sql(sql));
}
@Test void testRightEmptyFullJoin() {
@@ -3363,109 +3041,53 @@ class RelOptRulesTest extends RelOptTestBase {
final String sql = "select * from emp e\n"
+ "full join (select * from dept where false) as d\n"
+ "on e.deptno = d.deptno";
- sql(sql)
- .withRule(CoreRules.FILTER_REDUCE_EXPRESSIONS,
- PruneEmptyRules.PROJECT_INSTANCE,
- PruneEmptyRules.JOIN_LEFT_INSTANCE,
- PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .check();
+ checkEmptyJoin(sql(sql));
}
@Test void testRightEmptySemiJoin() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RelNode relNode = relBuilder
- .scan("EMP")
- .scan("DEPT").empty()
- .semiJoin(relBuilder
- .equals(
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .project(relBuilder.field("EMPNO"))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.FILTER_REDUCE_EXPRESSIONS)
- .addRuleInstance(PruneEmptyRules.PROJECT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_LEFT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .build();
-
- final HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- final RelNode output = hepPlanner.findBestExp();
-
- final String planBefore = NL + RelOptUtil.toString(relNode);
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- // Plan should be empty
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ checkRightEmptyAntiJoin(JoinRelType.SEMI);
}
@Test void testRightEmptyAntiJoin() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RelNode relNode = relBuilder
+ checkRightEmptyAntiJoin(JoinRelType.ANTI);
+ }
+
+ private void checkRightEmptyAntiJoin(JoinRelType type) {
+ final Function<RelBuilder, RelNode> relFn = b -> b
.scan("EMP")
.scan("DEPT").empty()
- .antiJoin(relBuilder
+ .join(type, b
.equals(
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .project(relBuilder.field("EMPNO"))
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")))
+ .project(b.field("EMPNO"))
.build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.FILTER_REDUCE_EXPRESSIONS)
- .addRuleInstance(PruneEmptyRules.PROJECT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_LEFT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_RIGHT_INSTANCE)
- .build();
-
- final HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- final RelNode output = hepPlanner.findBestExp();
-
- final String planBefore = NL + RelOptUtil.toString(relNode);
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- // Plan should be scan("EMP") (i.e. join's left child)
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ checkEmptyJoin(relFn(relFn));
}
@Test void testRightEmptyAntiJoinNonEqui() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RelNode relNode = relBuilder
+ final Function<RelBuilder, RelNode> relFn = b -> b
.scan("EMP")
.scan("DEPT").empty()
- .antiJoin(relBuilder
+ .antiJoin(b
.equals(
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")),
- relBuilder
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")),
+ b
.equals(
- relBuilder.field(2, 0, "SAL"),
- relBuilder.literal(2000)))
- .project(relBuilder.field("EMPNO"))
- .build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.FILTER_REDUCE_EXPRESSIONS)
- .addRuleInstance(PruneEmptyRules.PROJECT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_LEFT_INSTANCE)
- .addRuleInstance(PruneEmptyRules.JOIN_RIGHT_INSTANCE)
+ b.field(2, 0, "SAL"),
+ b.literal(2000)))
+ .project(b.field("EMPNO"))
.build();
+ checkEmptyJoin(relFn(relFn));
+ }
- final HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- final RelNode output = hepPlanner.findBestExp();
-
- final String planBefore = NL + RelOptUtil.toString(relNode);
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- // Plan should be scan("EMP") (i.e. join's left child)
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ private void checkEmptyJoin(RelOptTestBase.Sql sql) {
+ sql.withRule(
+ CoreRules.FILTER_REDUCE_EXPRESSIONS,
+ PruneEmptyRules.PROJECT_INSTANCE,
+ PruneEmptyRules.JOIN_LEFT_INSTANCE,
+ PruneEmptyRules.JOIN_RIGHT_INSTANCE).check();
}
@Test void testEmptySort() {
@@ -3478,27 +3100,13 @@ class RelOptRulesTest extends RelOptTestBase {
}
@Test void testEmptySort2() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RelNode relNode = relBuilder
+ final Function<RelBuilder, RelNode> relFn = b -> b
.scan("DEPT").empty()
.sort(
- relBuilder.field("DNAME"),
- relBuilder.field("DEPTNO"))
- .build();
-
- final HepProgram program = new HepProgramBuilder()
- .addRuleInstance(PruneEmptyRules.SORT_INSTANCE)
+ b.field("DNAME"),
+ b.field("DEPTNO"))
.build();
-
- final HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- final RelNode output = hepPlanner.findBestExp();
-
- final String planBefore = NL + RelOptUtil.toString(relNode);
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ relFn(relFn).withRule(PruneEmptyRules.SORT_INSTANCE).check();
}
@Test void testEmptySortLimitZero() {
@@ -3603,48 +3211,44 @@ class RelOptRulesTest extends RelOptTestBase {
}
@Test void testReduceCaseWhenWithCast() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RexBuilder rexBuilder = relBuilder.getRexBuilder();
- final RelDataType type = rexBuilder.getTypeFactory().createSqlType(SqlTypeName.BIGINT);
-
- RelNode left = relBuilder
- .values(new String[]{"x", "y"}, 1, 2).build();
- RexNode ref = rexBuilder.makeInputRef(left, 0);
- RexLiteral literal1 = rexBuilder.makeLiteral(1, type);
- RexLiteral literal2 = rexBuilder.makeLiteral(2, type);
- RexLiteral literal3 = rexBuilder.makeLiteral(3, type);
-
- // CASE WHEN x % 2 = 1 THEN x < 2
- // WHEN x % 3 = 2 THEN x < 1
- // ELSE x < 3
- final RexNode caseRexNode = rexBuilder.makeCall(SqlStdOperatorTable.CASE,
- rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
- rexBuilder.makeCall(SqlStdOperatorTable.MOD, ref, literal2), literal1),
- rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ref, literal2),
- rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
- rexBuilder.makeCall(SqlStdOperatorTable.MOD, ref, literal3), literal2),
- rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ref, literal1),
- rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ref, literal3));
-
- final RexNode castNode = rexBuilder.makeCast(rexBuilder.getTypeFactory().
- createTypeWithNullability(caseRexNode.getType(), true), caseRexNode);
- final RelNode root = relBuilder
- .push(left)
- .project(castNode)
- .build();
+ final Function<RelBuilder, RelNode> relFn = b -> {
+ final RexBuilder rexBuilder = b.getRexBuilder();
+ final RelDataType type = rexBuilder.getTypeFactory().createSqlType(SqlTypeName.BIGINT);
+
+ RelNode left = b
+ .values(new String[]{"x", "y"}, 1, 2).build();
+ RexNode ref = rexBuilder.makeInputRef(left, 0);
+ RexLiteral literal1 = rexBuilder.makeLiteral(1, type);
+ RexLiteral literal2 = rexBuilder.makeLiteral(2, type);
+ RexLiteral literal3 = rexBuilder.makeLiteral(3, type);
+
+ // CASE WHEN x % 2 = 1 THEN x < 2
+ // WHEN x % 3 = 2 THEN x < 1
+ // ELSE x < 3
+ final RexNode caseRexNode = rexBuilder.makeCall(SqlStdOperatorTable.CASE,
+ rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+ rexBuilder.makeCall(SqlStdOperatorTable.MOD, ref, literal2), literal1),
+ rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ref, literal2),
+ rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+ rexBuilder.makeCall(SqlStdOperatorTable.MOD, ref, literal3), literal2),
+ rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ref, literal1),
+ rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ref, literal3));
+
+ final RexNode castNode = rexBuilder.makeCast(rexBuilder.getTypeFactory().
+ createTypeWithNullability(caseRexNode.getType(), true), caseRexNode);
+ return b
+ .push(left)
+ .project(castNode)
+ .build();
+ };
HepProgramBuilder builder = new HepProgramBuilder();
builder.addRuleClass(ReduceExpressionsRule.class);
HepPlanner hepPlanner = new HepPlanner(builder.build());
hepPlanner.addRule(CoreRules.PROJECT_REDUCE_EXPRESSIONS);
- hepPlanner.setRoot(root);
- RelNode output = hepPlanner.findBestExp();
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ relFn(relFn).with(hepPlanner).checkUnchanged();
}
private void basePushAggThroughUnion() {
@@ -5514,88 +5118,56 @@ class RelOptRulesTest extends RelOptTestBase {
* <a href="https://issues.apache.org/jira/browse/CALCITE-4042">[CALCITE-4042]
* JoinCommuteRule must not match SEMI / ANTI join</a>. */
@Test void testSwapSemiJoin() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RelNode input = relBuilder
- .scan("EMP")
- .scan("DEPT")
- .semiJoin(relBuilder
- .equals(
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .project(relBuilder.field("EMPNO"))
- .build();
- testSwapJoinShouldNotMatch(input);
+ checkSwapJoinShouldNotMatch(JoinRelType.SEMI);
}
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-4042">[CALCITE-4042]
* JoinCommuteRule must not match SEMI / ANTI join</a>. */
@Test void testSwapAntiJoin() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RelNode input = relBuilder
- .scan("EMP")
- .scan("DEPT")
- .antiJoin(relBuilder
- .equals(
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .project(relBuilder.field("EMPNO"))
- .build();
- testSwapJoinShouldNotMatch(input);
+ checkSwapJoinShouldNotMatch(JoinRelType.ANTI);
}
- private void testSwapJoinShouldNotMatch(RelNode input) {
- final HepProgram program = new HepProgramBuilder()
- .addMatchLimit(1)
- .addRuleInstance(CoreRules.JOIN_COMMUTE_OUTER)
+ private void checkSwapJoinShouldNotMatch(JoinRelType type) {
+ final Function<RelBuilder, RelNode> relFn = b -> b
+ .scan("EMP")
+ .scan("DEPT")
+ .join(type,
+ b.equals(
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")))
+ .project(b.field("EMPNO"))
.build();
-
- final HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(input);
- final RelNode output = hepPlanner.findBestExp();
-
- final String planBefore = RelOptUtil.toString(input);
- final String planAfter = RelOptUtil.toString(output);
- assertEquals(planBefore, planAfter);
+ relFn(relFn).withRule(CoreRules.JOIN_COMMUTE_OUTER).checkUnchanged();
}
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-4621">[CALCITE-4621]
* SemiJoinRule throws AssertionError on ANTI join</a>. */
@Test void testJoinToSemiJoinRuleOnAntiJoin() {
- testSemiJoinRuleOnAntiJoin(CoreRules.JOIN_TO_SEMI_JOIN);
+ checkSemiJoinRuleOnAntiJoin(CoreRules.JOIN_TO_SEMI_JOIN);
}
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-4621">[CALCITE-4621]
* SemiJoinRule throws AssertionError on ANTI join</a>. */
@Test void testProjectToSemiJoinRuleOnAntiJoin() {
- testSemiJoinRuleOnAntiJoin(CoreRules.PROJECT_TO_SEMI_JOIN);
+ checkSemiJoinRuleOnAntiJoin(CoreRules.PROJECT_TO_SEMI_JOIN);
}
- private void testSemiJoinRuleOnAntiJoin(RelOptRule rule) {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
- final RelNode input = relBuilder
+ private void checkSemiJoinRuleOnAntiJoin(RelOptRule rule) {
+ final Function<RelBuilder, RelNode> relFn = b -> b
.scan("DEPT")
.scan("EMP")
- .project(relBuilder.field("DEPTNO"))
+ .project(b.field("DEPTNO"))
.distinct()
- .antiJoin(relBuilder
- .equals(
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .project(relBuilder.field("DNAME"))
- .build();
-
- final HepProgram program = new HepProgramBuilder()
- .addRuleInstance(rule)
+ .antiJoin(
+ b.equals(
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")))
+ .project(b.field("DNAME"))
.build();
- final HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(input);
- final RelNode output = hepPlanner.findBestExp();
- final String planBefore = RelOptUtil.toString(input);
- final String planAfter = RelOptUtil.toString(output);
- assertEquals(planBefore, planAfter);
+ relFn(relFn).withRule(rule).checkUnchanged();
}
@Test void testPushJoinCondDownToProject() {
@@ -6069,30 +5641,18 @@ class RelOptRulesTest extends RelOptTestBase {
* <a href="https://issues.apache.org/jira/browse/CALCITE-3188">[CALCITE-3188]
* IndexOutOfBoundsException in ProjectFilterTransposeRule when executing SELECT COUNT(*)</a>. */
@Test void testProjectFilterTransposeRuleOnEmptyRowType() {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
// build a rel equivalent to sql:
// select `empty` from emp
// where emp.deptno = 20
- RelNode relNode = relBuilder.scan("EMP")
- .filter(relBuilder
+ final Function<RelBuilder, RelNode> relFn = b -> b
+ .scan("EMP")
+ .filter(b
.equals(
- relBuilder.field(1, 0, "DEPTNO"),
- relBuilder.literal(20)))
+ b.field(1, 0, "DEPTNO"),
+ b.literal(20)))
.project(ImmutableList.of())
.build();
-
- HepProgram program = new HepProgramBuilder()
- .addRuleInstance(CoreRules.PROJECT_FILTER_TRANSPOSE)
- .build();
-
- HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
-
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ relFn(relFn).withRule(CoreRules.PROJECT_FILTER_TRANSPOSE).check();
}
@Test void testFlattenUncorrelatedCallBelowEquals() {
@@ -6370,31 +5930,13 @@ class RelOptRulesTest extends RelOptTestBase {
}
@Test void testFilterRemoveIsNotDistinctFromRule() {
- final DiffRepository diffRepos = getDiffRepos();
- final RelBuilder builder = RelBuilder.create(RelBuilderTest.config().build());
- RelNode root = builder
+ final Function<RelBuilder, RelNode> relFn = b -> b
.scan("EMP")
.filter(
- builder.call(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
- builder.field("DEPTNO"), builder.literal(20)))
- .build();
-
- HepProgram preProgram = new HepProgramBuilder().build();
- HepPlanner prePlanner = new HepPlanner(preProgram);
- prePlanner.setRoot(root);
- final RelNode relBefore = prePlanner.findBestExp();
- final String planBefore = NL + RelOptUtil.toString(relBefore);
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
-
- HepProgram hepProgram = new HepProgramBuilder()
- .addRuleInstance(CoreRules.FILTER_EXPAND_IS_NOT_DISTINCT_FROM)
+ b.call(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
+ b.field("DEPTNO"), b.literal(20)))
.build();
-
- HepPlanner hepPlanner = new HepPlanner(hepProgram);
- hepPlanner.setRoot(root);
- final RelNode relAfter = hepPlanner.findBestExp();
- final String planAfter = NL + RelOptUtil.toString(relAfter);
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ relFn(relFn).withRule(CoreRules.FILTER_EXPAND_IS_NOT_DISTINCT_FROM).check();
}
/** Creates an environment for testing spatial queries. */
@@ -6499,36 +6041,27 @@ class RelOptRulesTest extends RelOptTestBase {
}
@Test void testExchangeRemoveConstantKeysRule() {
- final DiffRepository diffRepos = getDiffRepos();
- final RelBuilder builder = RelBuilder.create(RelBuilderTest.config().build());
- RelNode root = builder
+ final Function<RelBuilder, RelNode> relFn = b -> b
.scan("EMP")
.filter(
- builder.call(SqlStdOperatorTable.EQUALS,
- builder.field("EMPNO"), builder.literal(10)))
+ b.call(
+ SqlStdOperatorTable.EQUALS,
+ b.field("EMPNO"),
+ b.literal(10)))
.exchange(RelDistributions.hash(ImmutableList.of(0)))
- .project(builder.field(0), builder.field(1))
- .sortExchange(RelDistributions.hash(ImmutableList.of(0, 1)),
- RelCollations.of(new RelFieldCollation(0), new RelFieldCollation(1)))
- .build();
-
- HepProgram preProgram = new HepProgramBuilder().build();
- HepPlanner prePlanner = new HepPlanner(preProgram);
- prePlanner.setRoot(root);
- final RelNode relBefore = prePlanner.findBestExp();
- final String planBefore = NL + RelOptUtil.toString(relBefore);
- diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
-
- HepProgram hepProgram = new HepProgramBuilder()
- .addRuleInstance(CoreRules.EXCHANGE_REMOVE_CONSTANT_KEYS)
- .addRuleInstance(CoreRules.SORT_EXCHANGE_REMOVE_CONSTANT_KEYS)
+ .project(
+ b.field(0),
+ b.field(1))
+ .sortExchange(
+ RelDistributions.hash(ImmutableList.of(0, 1)),
+ RelCollations.of(new RelFieldCollation(0), new RelFieldCollation(1)))
.build();
- HepPlanner hepPlanner = new HepPlanner(hepProgram);
- hepPlanner.setRoot(root);
- final RelNode relAfter = hepPlanner.findBestExp();
- final String planAfter = NL + RelOptUtil.toString(relAfter);
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+ relFn(relFn)
+ .withRule(
+ CoreRules.EXCHANGE_REMOVE_CONSTANT_KEYS,
+ CoreRules.SORT_EXCHANGE_REMOVE_CONSTANT_KEYS)
+ .check();
}
@Test void testReduceAverageWithNoReduceSum() {
@@ -6755,7 +6288,7 @@ class RelOptRulesTest extends RelOptTestBase {
Tester tester = createTester().withDecorrelation(true)
.withClusterFactory(cluster -> RelOptCluster.create(planner, cluster.getRexBuilder()));
return new Sql(tester, sql, null, planner,
- ImmutableMap.of(), ImmutableList.of());
+ ImmutableMap.of(), ImmutableList.of(), null);
}
/**
@@ -7119,15 +6652,11 @@ class RelOptRulesTest extends RelOptTestBase {
}
private void checkJoinCommuteRuleWithAlwaysTrueConditionDisallowed(boolean allowAlwaysTrue) {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
-
- RelNode left = relBuilder.scan("EMP").build();
- RelNode right = relBuilder.scan("DEPT").build();
-
- RelNode relNode = relBuilder.push(left)
- .push(right)
+ final Function<RelBuilder, RelNode> relFn = b -> b
+ .scan("EMP")
+ .scan("DEPT")
.join(JoinRelType.INNER,
- relBuilder.literal(true))
+ b.literal(true))
.build();
JoinCommuteRule.Config ruleConfig = JoinCommuteRule.Config.DEFAULT;
@@ -7139,15 +6668,13 @@ class RelOptRulesTest extends RelOptTestBase {
.addMatchLimit(1)
.addRuleInstance(ruleConfig.toRule())
.build();
-
HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ if (allowAlwaysTrue) {
+ relFn(relFn).with(hepPlanner).check();
+ } else {
+ relFn(relFn).with(hepPlanner).checkUnchanged();
+ }
}
@Test void testJoinAssociateRuleWithBottomAlwaysTrueConditionAllowed() {
@@ -7159,24 +6686,24 @@ class RelOptRulesTest extends RelOptTestBase {
}
private void checkJoinAssociateRuleWithBottomAlwaysTrueCondition(boolean allowAlwaysTrue) {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
-
- RelNode bottomLeft = relBuilder.scan("EMP").build();
- RelNode bottomRight = relBuilder.scan("DEPT").build();
- RelNode top = relBuilder.scan("BONUS").build();
-
- RelNode relNode = relBuilder.push(bottomLeft)
- .push(bottomRight)
- .join(JoinRelType.INNER,
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .push(top)
- .join(JoinRelType.INNER,
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, "JOB"),
- relBuilder.field(2, 1, "JOB")))
- .build();
+ final Function<RelBuilder, RelNode> relFn = b -> {
+ RelNode bottomLeft = b.scan("EMP").build();
+ RelNode bottomRight = b.scan("DEPT").build();
+ RelNode top = b.scan("BONUS").build();
+
+ return b.push(bottomLeft)
+ .push(bottomRight)
+ .join(JoinRelType.INNER,
+ b.call(SqlStdOperatorTable.EQUALS,
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")))
+ .push(top)
+ .join(JoinRelType.INNER,
+ b.call(SqlStdOperatorTable.EQUALS,
+ b.field(2, 0, "JOB"),
+ b.field(2, 1, "JOB")))
+ .build();
+ };
JoinAssociateRule.Config ruleConfig = JoinAssociateRule.Config.DEFAULT;
if (!allowAlwaysTrue) {
@@ -7188,15 +6715,13 @@ class RelOptRulesTest extends RelOptTestBase {
.addMatchOrder(HepMatchOrder.TOP_DOWN)
.addRuleInstance(ruleConfig.toRule())
.build();
-
HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ if (allowAlwaysTrue) {
+ relFn(relFn).with(hepPlanner).check();
+ } else {
+ relFn(relFn).with(hepPlanner).checkUnchanged();
+ }
}
@Test void testJoinAssociateRuleWithTopAlwaysTrueConditionAllowed() {
@@ -7208,22 +6733,23 @@ class RelOptRulesTest extends RelOptTestBase {
}
private void checkJoinAssociateRuleWithTopAlwaysTrueCondition(boolean allowAlwaysTrue) {
- final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
-
- RelNode bottomLeft = relBuilder.scan("EMP").build();
- RelNode bottomRight = relBuilder.scan("BONUS").build();
- RelNode top = relBuilder.scan("DEPT").build();
-
- RelNode relNode = relBuilder.push(bottomLeft)
- .push(bottomRight)
- .join(JoinRelType.INNER,
- relBuilder.literal(true))
- .push(top)
- .join(JoinRelType.INNER,
- relBuilder.call(SqlStdOperatorTable.EQUALS,
- relBuilder.field(2, 0, "DEPTNO"),
- relBuilder.field(2, 1, "DEPTNO")))
- .build();
+ final Function<RelBuilder, RelNode> relFn = b -> {
+
+ RelNode bottomLeft = b.scan("EMP").build();
+ RelNode bottomRight = b.scan("BONUS").build();
+ RelNode top = b.scan("DEPT").build();
+
+ return b.push(bottomLeft)
+ .push(bottomRight)
+ .join(JoinRelType.INNER,
+ b.literal(true))
+ .push(top)
+ .join(JoinRelType.INNER,
+ b.call(SqlStdOperatorTable.EQUALS,
+ b.field(2, 0, "DEPTNO"),
+ b.field(2, 1, "DEPTNO")))
+ .build();
+ };
JoinAssociateRule.Config ruleConfig = JoinAssociateRule.Config.DEFAULT;
if (!allowAlwaysTrue) {
@@ -7235,14 +6761,12 @@ class RelOptRulesTest extends RelOptTestBase {
.addMatchOrder(HepMatchOrder.TOP_DOWN)
.addRuleInstance(ruleConfig.toRule())
.build();
-
HepPlanner hepPlanner = new HepPlanner(program);
- hepPlanner.setRoot(relNode);
- RelNode output = hepPlanner.findBestExp();
- final String planAfter = NL + RelOptUtil.toString(output);
- final DiffRepository diffRepos = getDiffRepos();
- diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
- SqlToRelTestBase.assertValid(output);
+ if (allowAlwaysTrue) {
+ relFn(relFn).with(hepPlanner).check();
+ } else {
+ relFn(relFn).with(hepPlanner).checkUnchanged();
+ }
}
}
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 52bbfaa..5d04585 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
@@ -44,6 +44,8 @@ import org.apache.calcite.util.Closer;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -73,6 +75,22 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
}
/**
+ * Checks the plan for a given {@link RelNode} supplier before/after executing a given rule,
+ * with a pre-program to prepare the tree.
+ *
+ * @param tester Tester
+ * @param preProgram Program to execute before comparing before state
+ * @param planner Planner
+ * @param relFn {@link RelNode} supplier
+ * @param unchanged Whether the rule is to have no effect
+ */
+ private void checkPlanning(Tester tester, HepProgram preProgram,
+ RelOptPlanner planner, Function<RelBuilder, RelNode> relFn, boolean unchanged) {
+ RelNode relInitial = relFn.apply(RelBuilder.create(RelBuilderTest.config().build()));
+ checkPlanning(tester, preProgram, planner, relInitial, unchanged);
+ }
+
+ /**
* Checks the plan for a SQL statement before/after executing a given rule,
* with a pre-program to prepare the tree.
*
@@ -88,9 +106,13 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
String sql2 = diffRepos.expand("sql", sql);
final RelRoot root = tester.convertSqlToRel(sql2);
final RelNode relInitial = root.rel;
+ checkPlanning(tester, preProgram, planner, relInitial, unchanged);
+ }
+ private void checkPlanning(Tester tester, HepProgram preProgram,
+ RelOptPlanner planner, RelNode relInitial, boolean unchanged) {
assertNotNull(relInitial);
-
+ final DiffRepository diffRepos = getDiffRepos();
List<RelMetadataProvider> list = new ArrayList<>();
list.add(DefaultRelMetadataProvider.INSTANCE);
planner.registerMetadataProviders(list);
@@ -144,10 +166,15 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
/** Sets the SQL statement for a test. */
Sql sql(String sql) {
final Sql s =
- new Sql(tester, sql, null, null, ImmutableMap.of(), ImmutableList.of());
+ new Sql(tester, sql, null, null, ImmutableMap.of(), ImmutableList.of(), null);
return s.withRelBuilderConfig(b -> b.withPruneInputOfAggregate(false));
}
+ /** Initiates a test case with a given {@link RelNode} supplier. */
+ Sql relFn(Function<RelBuilder, RelNode> relFn) {
+ return sql("?").relFn(relFn);
+ }
+
/** Allows fluent testing. */
class Sql {
private final Tester tester;
@@ -156,10 +183,12 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
private final RelOptPlanner planner;
private final ImmutableMap<Hook, Consumer> hooks;
private ImmutableList<Function<Tester, Tester>> transforms;
+ private final @Nullable Function<RelBuilder, RelNode> relFn;
Sql(Tester tester, String sql, HepProgram preProgram, RelOptPlanner planner,
ImmutableMap<Hook, Consumer> hooks,
- ImmutableList<Function<Tester, Tester>> transforms) {
+ ImmutableList<Function<Tester, Tester>> transforms,
+ @Nullable Function<RelBuilder, RelNode> relFn) {
this.tester = Objects.requireNonNull(tester, "tester");
this.sql = Objects.requireNonNull(sql, "sql");
if (sql.contains(" \n")) {
@@ -169,15 +198,20 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
this.planner = planner;
this.hooks = Objects.requireNonNull(hooks, "hooks");
this.transforms = Objects.requireNonNull(transforms, "transforms");
+ this.relFn = relFn;
+ }
+
+ Sql relFn(Function<RelBuilder, RelNode> relFn) {
+ return new Sql(tester, sql, null, null, ImmutableMap.of(), ImmutableList.of(), relFn);
}
public Sql withTester(UnaryOperator<Tester> transform) {
final Tester tester2 = transform.apply(tester);
- return new Sql(tester2, sql, preProgram, planner, hooks, transforms);
+ return new Sql(tester2, sql, preProgram, planner, hooks, transforms, relFn);
}
public Sql withPre(HepProgram preProgram) {
- return new Sql(tester, sql, preProgram, planner, hooks, transforms);
+ return new Sql(tester, sql, preProgram, planner, hooks, transforms, relFn);
}
public Sql withPreRule(RelOptRule... rules) {
@@ -189,12 +223,12 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
}
public Sql with(HepPlanner hepPlanner) {
- return new Sql(tester, sql, preProgram, hepPlanner, hooks, transforms);
+ return new Sql(tester, sql, preProgram, hepPlanner, hooks, transforms, relFn);
}
public Sql with(HepProgram program) {
final HepPlanner hepPlanner = new HepPlanner(program);
- return new Sql(tester, sql, preProgram, hepPlanner, hooks, transforms);
+ return new Sql(tester, sql, preProgram, hepPlanner, hooks, transforms, relFn);
}
public Sql withRule(RelOptRule... rules) {
@@ -210,7 +244,7 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
private Sql withTransform(Function<Tester, Tester> transform) {
final ImmutableList<Function<Tester, Tester>> transforms =
FlatLists.append(this.transforms, transform);
- return new Sql(tester, sql, preProgram, planner, hooks, transforms);
+ return new Sql(tester, sql, preProgram, planner, hooks, transforms, relFn);
}
/** Adds a hook and a handler for that hook. Calcite will create a thread
@@ -219,7 +253,7 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
public <T> Sql withHook(Hook hook, Consumer<T> handler) {
final ImmutableMap<Hook, Consumer> hooks =
FlatLists.append(this.hooks, hook, handler);
- return new Sql(tester, sql, preProgram, planner, hooks, transforms);
+ return new Sql(tester, sql, preProgram, planner, hooks, transforms, relFn);
}
// CHECKSTYLE: IGNORE 1
@@ -300,7 +334,11 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
for (Function<Tester, Tester> transform : transforms) {
t = transform.apply(t);
}
- checkPlanning(t, preProgram, planner, sql, unchanged);
+ if (relFn != null) {
+ checkPlanning(t, preProgram, planner, relFn, unchanged);
+ } else {
+ checkPlanning(t, preProgram, planner, sql, unchanged);
+ }
}
}
}
diff --git a/core/src/test/java/org/apache/calcite/test/TopDownOptTest.java b/core/src/test/java/org/apache/calcite/test/TopDownOptTest.java
index c88ac59..c1e006b 100644
--- a/core/src/test/java/org/apache/calcite/test/TopDownOptTest.java
+++ b/core/src/test/java/org/apache/calcite/test/TopDownOptTest.java
@@ -820,7 +820,7 @@ class Query extends RelOptTestBase {
final Sql sql =
new Sql(tester, this.sql, null, planner, ImmutableMap.of(),
- ImmutableList.of());
+ ImmutableList.of(), null);
sql.check();
}
}
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 1a131c1..c60297b 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1265,7 +1265,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
where emp.deptno not in
(select dept.deptno from dept where emp.deptno > 20)]]>
</Resource>
- <Resource name="planAfter">
+ <Resource name="planBefore">
<![CDATA[
LogicalProject(EMPNO=[$0])
LogicalJoin(condition=[AND(IS NOT DISTINCT FROM($7, $8), >($0, 20))], joinType=[anti])
@@ -1280,7 +1280,7 @@ LogicalProject(EMPNO=[$0])
where emp.deptno
not in (select dept.deptno from dept where dept.dname = 'ddd')]]>
</Resource>
- <Resource name="planAfter">
+ <Resource name="planBefore">
<![CDATA[
LogicalProject(EMPNO=[$0])
LogicalJoin(condition=[AND(IS NOT DISTINCT FROM($7, $8), =($9, 'ddd'))], joinType=[anti])
@@ -4078,6 +4078,15 @@ LogicalProject(EMPNO=[$0], DEPTNO=[$1], W_COUNT=[$2])
</Resource>
</TestCase>
<TestCase name="testJoinAssociateRuleWithBottomAlwaysTrueConditionAllowed">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalJoin(condition=[=($2, $12)], joinType=[inner])
+ LogicalJoin(condition=[=($7, $8)], joinType=[inner])
+ LogicalTableScan(table=[[scott, EMP]])
+ LogicalTableScan(table=[[scott, DEPT]])
+ LogicalTableScan(table=[[scott, BONUS]])
+]]>
+ </Resource>
<Resource name="planAfter">
<![CDATA[
LogicalJoin(condition=[AND(=($2, $12), =($7, $8))], joinType=[inner])
@@ -4089,7 +4098,7 @@ LogicalJoin(condition=[AND(=($2, $12), =($7, $8))], joinType=[inner])
</Resource>
</TestCase>
<TestCase name="testJoinAssociateRuleWithBottomAlwaysTrueConditionDisallowed">
- <Resource name="planAfter">
+ <Resource name="planBefore">
<![CDATA[
LogicalJoin(condition=[=($2, $12)], joinType=[inner])
LogicalJoin(condition=[=($7, $8)], joinType=[inner])
@@ -4100,6 +4109,15 @@ LogicalJoin(condition=[=($2, $12)], joinType=[inner])
</Resource>
</TestCase>
<TestCase name="testJoinAssociateRuleWithTopAlwaysTrueConditionAllowed">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalJoin(condition=[=($7, $12)], joinType=[inner])
+ LogicalJoin(condition=[true], joinType=[inner])
+ LogicalTableScan(table=[[scott, EMP]])
+ LogicalTableScan(table=[[scott, BONUS]])
+ LogicalTableScan(table=[[scott, DEPT]])
+]]>
+ </Resource>
<Resource name="planAfter">
<![CDATA[
LogicalJoin(condition=[=($7, $12)], joinType=[inner])
@@ -4111,7 +4129,7 @@ LogicalJoin(condition=[=($7, $12)], joinType=[inner])
</Resource>
</TestCase>
<TestCase name="testJoinAssociateRuleWithTopAlwaysTrueConditionDisallowed">
- <Resource name="planAfter">
+ <Resource name="planBefore">
<![CDATA[
LogicalJoin(condition=[=($7, $12)], joinType=[inner])
LogicalJoin(condition=[true], joinType=[inner])
@@ -4122,6 +4140,13 @@ LogicalJoin(condition=[=($7, $12)], joinType=[inner])
</Resource>
</TestCase>
<TestCase name="testJoinCommuteRuleWithAlwaysTrueConditionAllowed">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalJoin(condition=[true], joinType=[inner])
+ LogicalTableScan(table=[[scott, EMP]])
+ LogicalTableScan(table=[[scott, DEPT]])
+]]>
+ </Resource>
<Resource name="planAfter">
<![CDATA[
LogicalProject(EMPNO=[$3], ENAME=[$4], JOB=[$5], MGR=[$6], HIREDATE=[$7], SAL=[$8], COMM=[$9], DEPTNO=[$10], DEPTNO0=[$0], DNAME=[$1], LOC=[$2])
@@ -4132,7 +4157,7 @@ LogicalProject(EMPNO=[$3], ENAME=[$4], JOB=[$5], MGR=[$6], HIREDATE=[$7], SAL=[$
</Resource>
</TestCase>
<TestCase name="testJoinCommuteRuleWithAlwaysTrueConditionDisallowed">
- <Resource name="planAfter">
+ <Resource name="planBefore">
<![CDATA[
LogicalJoin(condition=[true], joinType=[inner])
LogicalTableScan(table=[[scott, EMP]])
@@ -4468,6 +4493,15 @@ LogicalProject(SAL=[$5])
(select * from emp join dept ON emp.deptno = emp.deptno) t
where not exists (select job from bonus where emp.job = bonus.job)]]>
</Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalJoin(condition=[=($2, $12)], joinType=[anti])
+ LogicalJoin(condition=[=($7, $8)], joinType=[inner])
+ LogicalTableScan(table=[[scott, EMP]])
+ LogicalTableScan(table=[[scott, DEPT]])
+ LogicalTableScan(table=[[scott, BONUS]])
+]]>
+ </Resource>
<Resource name="planAfter">
<![CDATA[
LogicalJoin(condition=[=($2, $12)], joinType=[anti])
@@ -4484,6 +4518,15 @@ LogicalJoin(condition=[=($2, $12)], joinType=[anti])
(select * from emp join dept ON emp.deptno = emp.deptno) t
where emp.job in (select job from bonus))]]>
</Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalJoin(condition=[=($2, $12)], joinType=[semi])
+ LogicalJoin(condition=[=($7, $8)], joinType=[inner])
+ LogicalTableScan(table=[[scott, EMP]])
+ LogicalTableScan(table=[[scott, DEPT]])
+ LogicalTableScan(table=[[scott, BONUS]])
+]]>
+ </Resource>
<Resource name="planAfter">
<![CDATA[
LogicalJoin(condition=[=($2, $12)], joinType=[semi])
@@ -4494,6 +4537,18 @@ LogicalJoin(condition=[=($2, $12)], joinType=[semi])
]]>
</Resource>
</TestCase>
+ <TestCase name="testJoinToSemiJoinRuleOnAntiJoin">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DNAME=[$1])
+ LogicalJoin(condition=[=($0, $3)], joinType=[anti])
+ LogicalTableScan(table=[[scott, DEPT]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(DEPTNO=[$7])
+ LogicalTableScan(table=[[scott, EMP]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testLeftEmptyAntiJoin">
<Resource name="planBefore">
<![CDATA[
@@ -5583,6 +5638,15 @@ LogicalProject(C_NATIONKEY=[$1], FAKE_COL2=[$2])
</Resource>
</TestCase>
<TestCase name="testProjectCorrelateTransposeRuleAntiCorrelate">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(f=[$0])
+ LogicalCorrelate(correlation=[$cor0], joinType=[anti], requiredColumns=[{0}])
+ LogicalValues(tuples=[[{ '1', '2' }]])
+ LogicalProject(f3=[$0], $f1=[$cor0.f])
+ LogicalValues(tuples=[[{ '1', '2' }]])
+]]>
+ </Resource>
<Resource name="planAfter">
<![CDATA[
LogicalCorrelate(correlation=[$cor0], joinType=[anti], requiredColumns=[{0}])
@@ -5629,6 +5693,15 @@ FROM emp e1 where exists (select empno, deptno from dept d2 where e1.deptno = d2
</Resource>
</TestCase>
<TestCase name="testProjectCorrelateTransposeRuleSemiCorrelate">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(f=[$0])
+ LogicalCorrelate(correlation=[$cor0], joinType=[semi], requiredColumns=[{0}])
+ LogicalValues(tuples=[[{ '1', '2' }]])
+ LogicalProject(f3=[$0], $f1=[$cor0.f])
+ LogicalValues(tuples=[[{ '1', '2' }]])
+]]>
+ </Resource>
<Resource name="planAfter">
<![CDATA[
LogicalCorrelate(correlation=[$cor0], joinType=[semi], requiredColumns=[{0}])
@@ -5700,6 +5773,13 @@ LogicalProject(EXPR$0=[SUM($2) OVER (PARTITION BY $0)], EXPR$1=[COUNT($3) OVER (
</Resource>
</TestCase>
<TestCase name="testProjectFilterTransposeRuleOnEmptyRowType">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject
+ LogicalFilter(condition=[=($7, 20)])
+ LogicalTableScan(table=[[scott, EMP]])
+]]>
+ </Resource>
<Resource name="planAfter">
<![CDATA[
LogicalProject
@@ -6053,6 +6133,18 @@ LogicalProject(JOB=[$0], EXPR$1=[SUM($2) OVER (PARTITION BY $1)])
]]>
</Resource>
</TestCase>
+ <TestCase name="testProjectToSemiJoinRuleOnAntiJoin">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DNAME=[$1])
+ LogicalJoin(condition=[=($0, $3)], joinType=[anti])
+ LogicalTableScan(table=[[scott, DEPT]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(DEPTNO=[$7])
+ LogicalTableScan(table=[[scott, EMP]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testProjectToWindowRuleForMultipleWindows">
<Resource name="sql">
<![CDATA[select
@@ -8339,20 +8431,6 @@ LogicalProject(SAL=[$5])
LogicalTableScan(table=[[scott, DEPT]])
]]>
</Resource>
- <Resource name="planAfter">
- <![CDATA[
-LogicalProject(SAL=[$5])
- LogicalJoin(condition=[=($7, $8)], joinType=[anti])
- LogicalTableScan(table=[[scott, EMP]])
- LogicalUnion(all=[true])
- LogicalProject(DEPTNO=[$0])
- LogicalFilter(condition=[<($0, 10)])
- LogicalTableScan(table=[[scott, DEPT]])
- LogicalProject(DEPTNO=[$0])
- LogicalFilter(condition=[>($0, 20)])
- LogicalTableScan(table=[[scott, DEPT]])
-]]>
- </Resource>
</TestCase>
<TestCase name="testPushJoinThroughUnionOnRightDoesNotMatchSemiJoin">
<Resource name="sql">
@@ -8365,21 +8443,7 @@ LogicalProject(SAL=[$5])
LogicalTableScan(table=[[scott, EMP]])
LogicalUnion(all=[true])
LogicalProject(DEPTNO=[$0])
- LogicalFilter(condition=[>($0, 100)])
- LogicalTableScan(table=[[scott, DEPT]])
- LogicalProject(DEPTNO=[$0])
- LogicalFilter(condition=[>($0, 20)])
- LogicalTableScan(table=[[scott, DEPT]])
-]]>
- </Resource>
- <Resource name="planAfter">
- <![CDATA[
-LogicalProject(SAL=[$5])
- LogicalJoin(condition=[=($7, $8)], joinType=[semi])
- LogicalTableScan(table=[[scott, EMP]])
- LogicalUnion(all=[true])
- LogicalProject(DEPTNO=[$0])
- LogicalFilter(condition=[>($0, 100)])
+ LogicalFilter(condition=[<($0, 10)])
LogicalTableScan(table=[[scott, DEPT]])
LogicalProject(DEPTNO=[$0])
LogicalFilter(condition=[>($0, 20)])
@@ -9134,6 +9198,16 @@ LogicalProject(EXPR$0=[+($1, $5)], EXPR$1=[SUM($6) OVER (PARTITION BY $4)])
</Resource>
</TestCase>
<TestCase name="testPushSemiJoinConditions">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0])
+ LogicalJoin(condition=[AND(OR(=($0, $2), AND(IS NULL($0), IS NULL($2))), OR(=($1, $3), AND(IS NULL($1), IS NULL($3))))], joinType=[semi])
+ LogicalProject(DEPTNO=[$7], ENAME=[$1])
+ LogicalTableScan(table=[[scott, EMP]])
+ LogicalProject(DEPTNO=[$0], DNAME=[$1])
+ LogicalTableScan(table=[[scott, DEPT]])
+]]>
+ </Resource>
<Resource name="planAfter">
<![CDATA[
LogicalProject(DEPTNO=[$0])
@@ -9151,7 +9225,7 @@ LogicalProject(DEPTNO=[$0])
where emp.deptno
in (select dept.deptno from dept where emp.empno > 20)]]>
</Resource>
- <Resource name="planAfter">
+ <Resource name="planBefore">
<![CDATA[
LogicalProject(EMPNO=[$0])
LogicalJoin(condition=[AND(IS NOT DISTINCT FROM($7, $8), >($0, 20))], joinType=[semi])
@@ -9710,12 +9784,6 @@ LogicalProject($f0=[CAST(CASE(=(MOD($0, 2:BIGINT), 1), <($0, 2:BIGINT), =(MOD($0
LogicalValues(tuples=[[{ 1, 2 }]])
]]>
</Resource>
- <Resource name="planAfter">
- <![CDATA[
-LogicalProject($f0=[CAST(CASE(=(MOD($0, 2:BIGINT), 1), <($0, 2:BIGINT), =(MOD($0, 3:BIGINT), 2), <($0, 1:BIGINT), <($0, 3:BIGINT))):BOOLEAN])
- LogicalValues(tuples=[[{ 1, 2 }]])
-]]>
- </Resource>
</TestCase>
<TestCase name="testReduceCastAndConsts">
<Resource name="sql">
@@ -10291,13 +10359,6 @@ LogicalFilter(condition=[>($1, 10)])
LogicalTableScan(table=[[scott, EMP]])
]]>
</Resource>
- <Resource name="planAfter">
- <![CDATA[
-LogicalFilter(condition=[>($1, 10)])
- LogicalProject(SAL=[$5], N=[NDC()])
- LogicalTableScan(table=[[scott, EMP]])
-]]>
- </Resource>
</TestCase>
<TestCase name="testReduceConstantsNull">
<Resource name="sql">
@@ -12211,6 +12272,16 @@ EnumerableProject(N_REGIONKEY=[ITEM($0, 'N_REGIONKEY')])
]]>
</Resource>
</TestCase>
+ <TestCase name="testSwapAntiJoin">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EMPNO=[$0])
+ LogicalJoin(condition=[=($7, $8)], joinType=[anti])
+ LogicalTableScan(table=[[scott, EMP]])
+ LogicalTableScan(table=[[scott, DEPT]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testSwapOuterJoin">
<Resource name="sql">
<![CDATA[select 1 from sales.dept d left outer join sales.emp e
@@ -12257,6 +12328,16 @@ LogicalProject(NAME=[$10], ENAME=[$1])
]]>
</Resource>
</TestCase>
+ <TestCase name="testSwapSemiJoin">
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EMPNO=[$0])
+ LogicalJoin(condition=[=($7, $8)], joinType=[semi])
+ LogicalTableScan(table=[[scott, EMP]])
+ LogicalTableScan(table=[[scott, DEPT]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testTransitiveInferenceAggregate">
<Resource name="sql">
<![CDATA[select 1 from (select deptno, count(*) from sales.emp where deptno > 7