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(