This is an automated email from the ASF dual-hosted git repository. zabetak 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 62d933c [CALCITE-2621] Add rule to execute semi joins with correlation (Ruben Quesada Lopez) 62d933c is described below commit 62d933c769b4af19d82d2266cfe94804eae1544c Author: rubenada <rube...@gmail.com> AuthorDate: Thu Oct 11 14:15:30 2018 +0200 [CALCITE-2621] Add rule to execute semi joins with correlation (Ruben Quesada Lopez) --- .../calcite/rel/rules/JoinToCorrelateRule.java | 62 +++++++++++++++++++--- .../calcite/rel/rules/SortRemoveRuleTest.java | 2 +- .../test/enumerable/EnumerableCorrelateTest.java | 28 +++++++++- 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java index 47a128d..cbf36bf 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java @@ -22,7 +22,9 @@ import org.apache.calcite.plan.RelOptRule; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.CorrelationId; +import org.apache.calcite.rel.core.Join; import org.apache.calcite.rel.core.RelFactories; +import org.apache.calcite.rel.core.SemiJoin; import org.apache.calcite.rel.logical.LogicalCorrelate; import org.apache.calcite.rel.logical.LogicalJoin; import org.apache.calcite.rex.RexBuilder; @@ -35,8 +37,10 @@ import org.apache.calcite.tools.RelBuilderFactory; import org.apache.calcite.util.ImmutableBitSet; import org.apache.calcite.util.Util; +import java.util.function.Function; + /** - * Rule that converts a {@link org.apache.calcite.rel.logical.LogicalJoin} + * Rule that converts a {@link org.apache.calcite.rel.core.Join} * into a {@link org.apache.calcite.rel.logical.LogicalCorrelate}, which can * then be implemented using nested loops. * @@ -58,18 +62,42 @@ import org.apache.calcite.util.Util; * employees, and Correlator cannot do that.</p> */ public class JoinToCorrelateRule extends RelOptRule { + + /** + * Function to extract the {@link org.apache.calcite.sql.SemiJoinType} parameter + * for the creation of the {@link org.apache.calcite.rel.logical.LogicalCorrelate} + */ + private final Function<Join, SemiJoinType> semiJoinTypeExtractor; + //~ Static fields/initializers --------------------------------------------- - public static final JoinToCorrelateRule INSTANCE = - new JoinToCorrelateRule(RelFactories.LOGICAL_BUILDER); + /** + * Rule that converts a {@link org.apache.calcite.rel.logical.LogicalJoin} + * into a {@link org.apache.calcite.rel.logical.LogicalCorrelate} + */ + public static final JoinToCorrelateRule JOIN = + new JoinToCorrelateRule(LogicalJoin.class, RelFactories.LOGICAL_BUILDER, + "JoinToCorrelateRule", join -> SemiJoinType.of(join.getJoinType())); + + @Deprecated // to be removed (should use JOIN instead), kept for backwards compatibility + public static final JoinToCorrelateRule INSTANCE = JOIN; + + /** + * Rule that converts a {@link org.apache.calcite.rel.core.SemiJoin} + * into a {@link org.apache.calcite.rel.logical.LogicalCorrelate} + */ + public static final JoinToCorrelateRule SEMI = + new JoinToCorrelateRule(SemiJoin.class, RelFactories.LOGICAL_BUILDER, + "SemiJoinToCorrelateRule", join -> SemiJoinType.SEMI); //~ Constructors ----------------------------------------------------------- /** - * Creates a JoinToCorrelateRule. + * Creates a rule that converts a {@link org.apache.calcite.rel.logical.LogicalJoin} + * into a {@link org.apache.calcite.rel.logical.LogicalCorrelate} */ public JoinToCorrelateRule(RelBuilderFactory relBuilderFactory) { - super(operand(LogicalJoin.class, any()), relBuilderFactory, null); + this(LogicalJoin.class, relBuilderFactory, null, join -> SemiJoinType.of(join.getJoinType())); } @Deprecated // to be removed before 2.0 @@ -77,10 +105,28 @@ public class JoinToCorrelateRule extends RelOptRule { this(RelBuilder.proto(Contexts.of(filterFactory))); } + /** + * Creates a JoinToCorrelateRule for a certain sub-class of + * {@link org.apache.calcite.rel.core.Join} to be transformed into a + * {@link org.apache.calcite.rel.logical.LogicalCorrelate} + * @param clazz Class of relational expression to match (must not be null) + * @param relBuilderFactory Builder for relational expressions + * @param description Description, or null to guess description + * @param semiJoinTypeExtractor Function to get the {@link org.apache.calcite.sql.SemiJoinType} + * for the {@link org.apache.calcite.rel.logical.LogicalCorrelate} + */ + private JoinToCorrelateRule(Class<? extends Join> clazz, + RelBuilderFactory relBuilderFactory, + String description, + Function<Join, SemiJoinType> semiJoinTypeExtractor) { + super(operand(clazz, any()), relBuilderFactory, description); + this.semiJoinTypeExtractor = semiJoinTypeExtractor; + } + //~ Methods ---------------------------------------------------------------- public boolean matches(RelOptRuleCall call) { - LogicalJoin join = call.rel(0); + Join join = call.rel(0); switch (join.getJoinType()) { case INNER: case LEFT: @@ -95,7 +141,7 @@ public class JoinToCorrelateRule extends RelOptRule { public void onMatch(RelOptRuleCall call) { assert matches(call); - final LogicalJoin join = call.rel(0); + final Join join = call.rel(0); RelNode right = join.getRight(); final RelNode left = join.getLeft(); final int leftFieldCount = left.getRowType().getFieldCount(); @@ -127,7 +173,7 @@ public class JoinToCorrelateRule extends RelOptRule { relBuilder.build(), correlationId, requiredColumns.build(), - SemiJoinType.of(join.getJoinType())); + semiJoinTypeExtractor.apply(join)); call.transformTo(newRel); } } diff --git a/core/src/test/java/org/apache/calcite/rel/rules/SortRemoveRuleTest.java b/core/src/test/java/org/apache/calcite/rel/rules/SortRemoveRuleTest.java index 16529ae..a8c430b 100644 --- a/core/src/test/java/org/apache/calcite/rel/rules/SortRemoveRuleTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rules/SortRemoveRuleTest.java @@ -153,7 +153,7 @@ public final class SortRemoveRuleTest { RuleSet prepareRules = RuleSets.ofList( SortProjectTransposeRule.INSTANCE, - JoinToCorrelateRule.INSTANCE, + JoinToCorrelateRule.JOIN, EnumerableRules.ENUMERABLE_SORT_RULE, EnumerableRules.ENUMERABLE_PROJECT_RULE, EnumerableRules.ENUMERABLE_CORRELATE_RULE, diff --git a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java index 876c18f..9e3793a 100644 --- a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java +++ b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java @@ -44,7 +44,7 @@ public class EnumerableCorrelateTest { "select e.empid, e.name, d.name as dept from emps e left outer join depts d on e.deptno=d.deptno") .withHook(Hook.PLANNER, (Consumer<RelOptPlanner>) planner -> { // force the left outer join to run via EnumerableCorrelate instead of EnumerableJoin - planner.addRule(JoinToCorrelateRule.INSTANCE); + planner.addRule(JoinToCorrelateRule.JOIN); planner.removeRule(EnumerableRules.ENUMERABLE_JOIN_RULE); }) .explainContains("" @@ -77,6 +77,32 @@ public class EnumerableCorrelateTest { "empid=150; name=Sebastian"); } + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-2621">[CALCITE-2621] + * Add rule to execute semi joins with correlation</a> */ + @Test public void semiJoinCorrelate() { + tester(false, new JdbcTest.HrSchema()) + .query( + "select empid, name from emps e where e.deptno in (select d.deptno from depts d)") + .withHook(Hook.PLANNER, (Consumer<RelOptPlanner>) planner -> { + // force the semi-join to run via EnumerableCorrelate instead of EnumerableJoin/SemiJoin + planner.addRule(JoinToCorrelateRule.SEMI); + planner.removeRule(EnumerableRules.ENUMERABLE_JOIN_RULE); + planner.removeRule(EnumerableRules.ENUMERABLE_SEMI_JOIN_RULE); + }) + .explainContains("" + + "EnumerableCalc(expr#0..2=[{inputs}], empid=[$t0], name=[$t2])\n" + + " EnumerableCorrelate(correlation=[$cor1], joinType=[semi], requiredColumns=[{1}])\n" + + " EnumerableCalc(expr#0..4=[{inputs}], proj#0..2=[{exprs}])\n" + + " EnumerableTableScan(table=[[s, emps]])\n" + + " EnumerableCalc(expr#0..3=[{inputs}], expr#4=[$cor1], expr#5=[$t4.deptno], expr#6=[=($t5, $t0)], proj#0..3=[{exprs}], $condition=[$t6])\n" + + " EnumerableTableScan(table=[[s, depts]])") + .returnsUnordered( + "empid=100; name=Bill", + "empid=110; name=Theodore", + "empid=150; name=Sebastian"); + } + @Test public void simpleCorrelate() { tester(false, new JdbcTest.HrSchema()) .query(