You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by za...@apache.org on 2019/03/05 16:09:49 UTC

[calcite] branch master updated: [CALCITE-2621] Add rule to execute semi joins with correlation (Ruben Quesada Lopez)

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 <ru...@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(