You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by hy...@apache.org on 2020/06/13 21:13:35 UTC
[calcite] branch master updated: [CALCITE-4057] Support trait
propagation for EnumerableBatchNestedLoopJoin (Rui Wang)
This is an automated email from the ASF dual-hosted git repository.
hyuan 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 978bb7e [CALCITE-4057] Support trait propagation for EnumerableBatchNestedLoopJoin (Rui Wang)
978bb7e is described below
commit 978bb7ea44969351468d1b5e240e8f57af7e5770
Author: amaliujia <am...@163.com>
AuthorDate: Thu Jun 11 20:38:32 2020 -0700
[CALCITE-4057] Support trait propagation for EnumerableBatchNestedLoopJoin (Rui Wang)
Close #2023
---
.../enumerable/EnumerableBatchNestedLoopJoin.java | 22 +++++++
.../calcite/adapter/enumerable/EnumerableCalc.java | 4 +-
.../adapter/enumerable/EnumerableCorrelate.java | 34 ++---------
.../adapter/enumerable/EnumerableHashJoin.java | 38 ++----------
.../enumerable/EnumerableNestedLoopJoin.java | 48 +++------------
.../adapter/enumerable/EnumerableProject.java | 4 +-
...TraitsUtils.java => EnumerableTraitsUtils.java} | 69 +++++++++++++++++++++-
.../org/apache/calcite/test/TopDownOptTest.java | 46 ++++++++++-----
.../org/apache/calcite/test/TopDownOptTest.xml | 61 +++++++++++++++++++
9 files changed, 201 insertions(+), 125 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBatchNestedLoopJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBatchNestedLoopJoin.java
index 13ff1e1..de727c0 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBatchNestedLoopJoin.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBatchNestedLoopJoin.java
@@ -22,6 +22,7 @@ import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.linq4j.tree.Expressions;
import org.apache.calcite.linq4j.tree.ParameterExpression;
import org.apache.calcite.linq4j.tree.Primitive;
+import org.apache.calcite.plan.DeriveMode;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptCost;
import org.apache.calcite.plan.RelOptPlanner;
@@ -37,6 +38,7 @@ import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.util.BuiltInMethod;
import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.Pair;
import com.google.common.collect.ImmutableList;
@@ -88,6 +90,26 @@ public class EnumerableBatchNestedLoopJoin extends Join implements EnumerableRel
joinType);
}
+ @Override public Pair<RelTraitSet, List<RelTraitSet>> passThroughTraits(
+ final RelTraitSet required) {
+ return EnumerableTraitsUtils.passThroughTraitsForJoin(
+ required, joinType, getLeft().getRowType().getFieldCount(), traitSet);
+ }
+
+ @Override public Pair<RelTraitSet, List<RelTraitSet>> deriveTraits(
+ final RelTraitSet childTraits, final int childId) {
+ return EnumerableTraitsUtils.deriveTraitsForJoin(
+ childTraits, childId, joinType, traitSet, right.getTraitSet());
+ }
+
+ @Override public DeriveMode getDeriveMode() {
+ if (joinType == JoinRelType.FULL || joinType == JoinRelType.RIGHT) {
+ return DeriveMode.PROHIBITED;
+ }
+
+ return DeriveMode.LEFT_FIRST;
+ }
+
@Override public EnumerableBatchNestedLoopJoin copy(RelTraitSet traitSet,
RexNode condition, RelNode left, RelNode right, JoinRelType joinType,
boolean semiJoinDone) {
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
index f899624..f987cbf 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
@@ -272,7 +272,7 @@ public class EnumerableCalc extends Calc implements EnumerableRel {
final List<RexNode> exps = Lists.transform(program.getProjectList(),
program::expandLocalRef);
- return EnumTraitsUtils.passThroughTraitsForProject(required, exps,
+ return EnumerableTraitsUtils.passThroughTraitsForProject(required, exps,
input.getRowType(), input.getCluster().getTypeFactory(), traitSet);
}
@@ -281,7 +281,7 @@ public class EnumerableCalc extends Calc implements EnumerableRel {
final List<RexNode> exps = Lists.transform(program.getProjectList(),
program::expandLocalRef);
- return EnumTraitsUtils.deriveTraitsForProject(childTraits, childId, exps,
+ return EnumerableTraitsUtils.deriveTraitsForProject(childTraits, childId, exps,
input.getRowType(), input.getCluster().getTypeFactory(), traitSet);
}
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelate.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelate.java
index cc1e56c..86bc042 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelate.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelate.java
@@ -24,10 +24,7 @@ import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.plan.DeriveMode;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollationTraitDef;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Correlate;
import org.apache.calcite.rel.core.CorrelationId;
@@ -89,41 +86,18 @@ public class EnumerableCorrelate extends Correlate
@Override public Pair<RelTraitSet, List<RelTraitSet>> passThroughTraits(
final RelTraitSet required) {
- final RelCollation collation = required.getCollation();
- if (collation == null || collation == RelCollations.EMPTY) {
- return null;
- }
-
// EnumerableCorrelate traits passdown shall only pass through collation to left input.
// This is because for EnumerableCorrelate always uses left input as the outer loop,
// thus only left input can preserve ordering.
-
- for (RelFieldCollation relFieldCollation : collation.getFieldCollations()) {
- // If field collation belongs to right input: bail out.
- if (relFieldCollation.getFieldIndex() >= getLeft().getRowType().getFieldCount()) {
- return null;
- }
- }
-
- final RelTraitSet passThroughTraitSet = traitSet.replace(collation);
- return Pair.of(passThroughTraitSet,
- ImmutableList.of(
- passThroughTraitSet,
- passThroughTraitSet.replace(RelCollations.EMPTY)));
+ return EnumerableTraitsUtils.passThroughTraitsForJoin(
+ required, joinType, left.getRowType().getFieldCount(), getTraitSet());
}
@Override public Pair<RelTraitSet, List<RelTraitSet>> deriveTraits(
final RelTraitSet childTraits, final int childId) {
// should only derive traits (limited to collation for now) from left input.
- assert childId == 0;
-
- final RelCollation collation = childTraits.getCollation();
- if (collation == null || collation == RelCollations.EMPTY) {
- return null;
- }
-
- final RelTraitSet traits = traitSet.replace(collation);
- return Pair.of(traits, ImmutableList.of(traits, right.getTraitSet()));
+ return EnumerableTraitsUtils.deriveTraitsForJoin(
+ childTraits, childId, joinType, traitSet, right.getTraitSet());
}
@Override public DeriveMode getDeriveMode() {
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableHashJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableHashJoin.java
index aa2f41f..918919e 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableHashJoin.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableHashJoin.java
@@ -24,10 +24,7 @@ import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptCost;
import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollationTraitDef;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelNodes;
import org.apache.calcite.rel.core.CorrelationId;
@@ -108,42 +105,15 @@ public class EnumerableHashJoin extends Join implements EnumerableRel {
@Override public Pair<RelTraitSet, List<RelTraitSet>> passThroughTraits(
final RelTraitSet required) {
- RelCollation collation = required.getCollation();
- if (collation == null
- || collation == RelCollations.EMPTY
- || joinType == JoinRelType.FULL
- || joinType == JoinRelType.RIGHT) {
- return null;
- }
-
- for (RelFieldCollation fc : collation.getFieldCollations()) {
- // If field collation belongs to right input: cannot push down collation.
- if (fc.getFieldIndex() >= getLeft().getRowType().getFieldCount()) {
- return null;
- }
- }
-
- RelTraitSet passthroughTraitSet = traitSet.replace(collation);
- return Pair.of(passthroughTraitSet,
- ImmutableList.of(
- passthroughTraitSet,
- passthroughTraitSet.replace(RelCollations.EMPTY)));
+ return EnumerableTraitsUtils.passThroughTraitsForJoin(
+ required, joinType, left.getRowType().getFieldCount(), getTraitSet());
}
@Override public Pair<RelTraitSet, List<RelTraitSet>> deriveTraits(
final RelTraitSet childTraits, final int childId) {
// should only derive traits (limited to collation for now) from left join input.
- assert childId == 0;
-
- RelCollation collation = childTraits.getCollation();
- if (collation == null || collation == RelCollations.EMPTY) {
- return null;
- }
-
- RelTraitSet derivedTraits = getTraitSet().replace(collation);
- return Pair.of(
- derivedTraits,
- ImmutableList.of(derivedTraits, right.getTraitSet()));
+ return EnumerableTraitsUtils.deriveTraitsForJoin(
+ childTraits, childId, joinType, getTraitSet(), right.getTraitSet());
}
@Override public DeriveMode getDeriveMode() {
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableNestedLoopJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableNestedLoopJoin.java
index a10866e..1561d8f 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableNestedLoopJoin.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableNestedLoopJoin.java
@@ -24,10 +24,7 @@ import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptCost;
import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollationTraitDef;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelNodes;
import org.apache.calcite.rel.core.CorrelationId;
@@ -126,50 +123,21 @@ public class EnumerableNestedLoopJoin extends Join implements EnumerableRel {
@Override public Pair<RelTraitSet, List<RelTraitSet>> passThroughTraits(
final RelTraitSet required) {
- RelCollation collation = required.getCollation();
- if (collation == null
- || collation == RelCollations.EMPTY
- || joinType == JoinRelType.FULL
- || joinType == JoinRelType.RIGHT) {
- return null;
- }
-
- // EnumerableNestedLoopJoin traits passdown shall only pass through collation to left input.
- // It is because for EnumerableNestedLoopJoin always uses left input as the outer loop,
- // thus only left input can preserve ordering.
+ // EnumerableNestedLoopJoin traits passdown shall only pass through collation to
+ // left input. It is because for EnumerableNestedLoopJoin always
+ // uses left input as the outer loop, thus only left input can preserve ordering.
// Push sort both to left and right inputs does not help right outer join. It's because in
// implementation, EnumerableNestedLoopJoin produces (null, right_unmatched) all together,
// which does not preserve ordering from right side.
-
-
- for (RelFieldCollation fc : collation.getFieldCollations()) {
- // If field collation belongs to right input: cannot push down collation.
- if (fc.getFieldIndex() >= getLeft().getRowType().getFieldCount()) {
- return null;
- }
- }
-
- RelTraitSet passthroughTraitSet = traitSet.replace(collation);
- return Pair.of(passthroughTraitSet,
- ImmutableList.of(
- passthroughTraitSet,
- passthroughTraitSet.replace(RelCollations.EMPTY)));
+ return EnumerableTraitsUtils.passThroughTraitsForJoin(
+ required, joinType, getLeft().getRowType().getFieldCount(), traitSet);
}
@Override public Pair<RelTraitSet, List<RelTraitSet>> deriveTraits(
final RelTraitSet childTraits, final int childId) {
- // should only derive traits (limited to collation for now) from left join input.
- assert childId == 0;
-
- RelCollation collation = childTraits.getCollation();
- if (collation == null || collation == RelCollations.EMPTY) {
- return null;
- }
-
- RelTraitSet derivedTraits = getTraitSet().replace(collation);
- return Pair.of(
- derivedTraits,
- ImmutableList.of(derivedTraits, right.getTraitSet()));
+ return EnumerableTraitsUtils.deriveTraitsForJoin(
+ childTraits, childId, joinType, traitSet, right.getTraitSet()
+ );
}
@Override public DeriveMode getDeriveMode() {
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java
index d940d97..7c62e2f 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java
@@ -91,13 +91,13 @@ public class EnumerableProject extends Project implements EnumerableRel {
@Override public Pair<RelTraitSet, List<RelTraitSet>> passThroughTraits(
RelTraitSet required) {
- return EnumTraitsUtils.passThroughTraitsForProject(required, exps,
+ return EnumerableTraitsUtils.passThroughTraitsForProject(required, exps,
input.getRowType(), input.getCluster().getTypeFactory(), traitSet);
}
@Override public Pair<RelTraitSet, List<RelTraitSet>> deriveTraits(
final RelTraitSet childTraits, final int childId) {
- return EnumTraitsUtils.deriveTraitsForProject(childTraits, childId, exps,
+ return EnumerableTraitsUtils.deriveTraitsForProject(childTraits, childId, exps,
input.getRowType(), input.getCluster().getTypeFactory(), traitSet);
}
}
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumTraitsUtils.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTraitsUtils.java
similarity index 69%
rename from core/src/main/java/org/apache/calcite/adapter/enumerable/EnumTraitsUtils.java
rename to core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTraitsUtils.java
index 2be158a..16dc2aa 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumTraitsUtils.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTraitsUtils.java
@@ -22,6 +22,7 @@ import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rex.RexCall;
@@ -47,9 +48,9 @@ import java.util.Objects;
* Utilities for traits propagation.
*/
@API(since = "1.24", status = API.Status.INTERNAL)
-class EnumTraitsUtils {
+class EnumerableTraitsUtils {
- private EnumTraitsUtils() {}
+ private EnumerableTraitsUtils() {}
/**
* Determine whether there is mapping between project input and output fields.
@@ -148,4 +149,68 @@ class EnumTraitsUtils {
return null;
}
}
+
+ /**
+ * This function can be reused when a Join's traits pass-down shall only
+ * pass through collation to left input.
+ *
+ * @param required required trait set for the join
+ * @param joinType the join type
+ * @param leftInputFieldCount number of field count of left join input
+ * @param joinTraitSet trait set of the join
+ */
+ static Pair<RelTraitSet, List<RelTraitSet>> passThroughTraitsForJoin(
+ RelTraitSet required, JoinRelType joinType,
+ int leftInputFieldCount, RelTraitSet joinTraitSet) {
+ RelCollation collation = required.getCollation();
+ if (collation == null
+ || collation == RelCollations.EMPTY
+ || joinType == JoinRelType.FULL
+ || joinType == JoinRelType.RIGHT) {
+ return null;
+ }
+
+ for (RelFieldCollation fc : collation.getFieldCollations()) {
+ // If field collation belongs to right input: cannot push down collation.
+ if (fc.getFieldIndex() >= leftInputFieldCount) {
+ return null;
+ }
+ }
+
+ RelTraitSet passthroughTraitSet = joinTraitSet.replace(collation);
+ return Pair.of(passthroughTraitSet,
+ ImmutableList.of(
+ passthroughTraitSet,
+ passthroughTraitSet.replace(RelCollations.EMPTY)));
+ }
+
+ /**
+ * This function can be reused when a Join's traits derivation shall only
+ * derive collation from left input.
+ *
+ * @param childTraits trait set of the child
+ * @param childId id of the child (0 is left join input)
+ * @param joinType the join type
+ * @param joinTraitSet trait set of the join
+ * @param rightTraitSet trait set of the right join input
+ */
+ static Pair<RelTraitSet, List<RelTraitSet>> deriveTraitsForJoin(
+ RelTraitSet childTraits, int childId, JoinRelType joinType,
+ RelTraitSet joinTraitSet, RelTraitSet rightTraitSet) {
+ // should only derive traits (limited to collation for now) from left join input.
+ assert childId == 0;
+
+ RelCollation collation = childTraits.getCollation();
+ if (collation == null
+ || collation == RelCollations.EMPTY
+ || joinType == JoinRelType.FULL
+ || joinType == JoinRelType.RIGHT) {
+ return null;
+ }
+
+ RelTraitSet derivedTraits = joinTraitSet.replace(collation);
+ return Pair.of(
+ derivedTraits,
+ ImmutableList.of(derivedTraits, rightTraitSet));
+ }
}
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 bac5e4d..20f0f36 100644
--- a/core/src/test/java/org/apache/calcite/test/TopDownOptTest.java
+++ b/core/src/test/java/org/apache/calcite/test/TopDownOptTest.java
@@ -379,7 +379,6 @@ class TopDownOptTest extends RelOptTestBase {
+ "order by r.job desc nulls last, r.ename nulls first";
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.check();
}
@@ -393,7 +392,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -408,7 +406,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -423,7 +420,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -438,7 +434,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -453,7 +448,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -468,7 +462,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -483,7 +476,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -499,7 +491,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -513,7 +504,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -527,7 +517,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -541,7 +530,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -555,7 +543,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -569,7 +556,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -583,7 +569,6 @@ class TopDownOptTest extends RelOptTestBase {
Query.create(sql)
.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
- .removeRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
.removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
.check();
}
@@ -693,6 +678,37 @@ class TopDownOptTest extends RelOptTestBase {
.removeRule(EnumerableRules.ENUMERABLE_JOIN_RULE)
.check();
}
+
+ // push sort to left input
+ @Test void testBatchNestedLoopJoinLeftOuterJoinPushDownSort() {
+ final String sql = "select * from\n"
+ + " customer.contact_peek r left outer join\n"
+ + "customer.account s\n"
+ + "on r.contactno>s.acctno and r.email<s.type\n"
+ + "order by r.contactno desc, r.email desc";
+
+ Query.create(sql)
+ .removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
+ .removeRule(EnumerableRules.ENUMERABLE_JOIN_RULE)
+ .removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
+ .addRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
+ .check();
+ }
+
+ // Collation can be derived from left input so that top Sort is removed.
+ @Test void testBatchNestedLoopJoinTraitDerivation() {
+ final String sql = "select * from\n"
+ + "(select ename, job, mgr from sales.emp order by ename desc, job desc, mgr limit 10) r\n"
+ + "join sales.bonus s on r.ename>s.ename and r.job<s.job\n"
+ + "order by r.ename desc, r.job desc";
+
+ Query.create(sql)
+ .removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE)
+ .removeRule(EnumerableRules.ENUMERABLE_JOIN_RULE)
+ .removeRule(EnumerableRules.ENUMERABLE_SORT_RULE)
+ .addRule(EnumerableRules.ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE)
+ .check();
+ }
}
/**
diff --git a/core/src/test/resources/org/apache/calcite/test/TopDownOptTest.xml b/core/src/test/resources/org/apache/calcite/test/TopDownOptTest.xml
index 2f4fa70..3442857 100644
--- a/core/src/test/resources/org/apache/calcite/test/TopDownOptTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/TopDownOptTest.xml
@@ -1192,6 +1192,67 @@ EnumerableCorrelate(correlation=[$cor2], joinType=[semi], requiredColumns=[{0}])
]]>
</Resource>
</TestCase>
+ <TestCase name="testBatchNestedLoopJoinLeftOuterJoinPushDownSort">
+ <Resource name="sql">
+ <![CDATA[select * from
+ customer.contact_peek r left outer join
+customer.account s
+on r.contactno>s.acctno and r.email<s.type
+order by r.contactno desc, r.email desc]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(CONTACTNO=[$0], FNAME=[$1], LNAME=[$2], EMAIL=[$3], X=[$4], Y=[$5], unit=[$6], COORD_NE=[ROW($7, ROW($8, $9))], ACCTNO=[$10], TYPE=[$11], BALANCE=[$12])
+ LogicalSort(sort0=[$0], sort1=[$3], dir0=[DESC], dir1=[DESC])
+ LogicalProject(CONTACTNO=[$0], FNAME=[$1], LNAME=[$2], EMAIL=[$3], X=[$4], Y=[$5], unit=[$6], COORD_NE=[$7], COORD_NE8=[$8], COORD_NE9=[$9], ACCTNO=[$10], TYPE=[$11], BALANCE=[$12])
+ LogicalJoin(condition=[AND(>($0, $10), <($3, $11))], joinType=[left])
+ LogicalProject(CONTACTNO=[$0], FNAME=[$1], LNAME=[$2], EMAIL=[$3], X=[$4.X], Y=[$4.Y], unit=[$4.unit], M=[$5.M], A=[$5.SUB.A], B=[$5.SUB.B])
+ LogicalTableScan(table=[[CATALOG, CUSTOMER, CONTACT_PEEK]])
+ LogicalTableScan(table=[[CATALOG, CUSTOMER, ACCOUNT]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+EnumerableProject(CONTACTNO=[$0], FNAME=[$1], LNAME=[$2], EMAIL=[$3], X=[$4], Y=[$5], unit=[$6], COORD_NE=[ROW($7, ROW($8, $9))], ACCTNO=[$10], TYPE=[$11], BALANCE=[$12])
+ EnumerableBatchNestedLoopJoin(condition=[AND(>($0, $10), <($3, $11))], joinType=[left], batchSize=[100])
+ EnumerableProject(CONTACTNO=[$0], FNAME=[$1], LNAME=[$2], EMAIL=[$3], X=[$4.X], Y=[$4.Y], unit=[$4.unit], M=[$5.M], A=[$5.SUB.A], B=[$5.SUB.B])
+ EnumerableSort(sort0=[$0], sort1=[$3], dir0=[DESC], dir1=[DESC])
+ EnumerableTableScan(table=[[CATALOG, CUSTOMER, CONTACT_PEEK]])
+ EnumerableFilter(condition=[OR(AND(>($cor0.CONTACTNO, $0), <($cor0.EMAIL, $1)), AND(>($cor1.CONTACTNO, $0), <($cor1.EMAIL, $1)), AND(>($cor2.CONTACTNO, $0), <($cor2.EMAIL, $1)), AND(>($cor3.CONTACTNO, $0), <($cor3.EMAIL, $1)), AND(>($cor4.CONTACTNO, $0), <($cor4.EMAIL, $1)), AND(>($cor5.CONTACTNO, $0), <($cor5.EMAIL, $1)), AND(>($cor6.CONTACTNO, $0), <($cor6.EMAIL, $1)), AND(>($cor7.CONTACTNO, $0), <($cor7.EMAIL, $1)), AND(>($cor8.CONTACTNO, $0), <($cor8.EMAIL, $1)), AND(>($cor9.CONT [...]
+ EnumerableTableScan(table=[[CATALOG, CUSTOMER, ACCOUNT]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testBatchNestedLoopJoinTraitDerivation">
+ <Resource name="sql">
+ <![CDATA[select * from
+(select ename, job, mgr from sales.emp order by ename desc, job desc, mgr limit 10) r
+join sales.bonus s on r.ename>s.ename and r.job<s.job
+order by r.ename desc, r.job desc]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalSort(sort0=[$0], sort1=[$1], dir0=[DESC], dir1=[DESC])
+ LogicalProject(ENAME=[$0], JOB=[$1], MGR=[$2], ENAME0=[$3], JOB0=[$4], SAL=[$5], COMM=[$6])
+ LogicalJoin(condition=[AND(>($0, $3), <($1, $4))], joinType=[inner])
+ LogicalSort(sort0=[$0], sort1=[$1], sort2=[$2], dir0=[DESC], dir1=[DESC], dir2=[ASC], fetch=[10])
+ LogicalProject(ENAME=[$1], JOB=[$2], MGR=[$3])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalTableScan(table=[[CATALOG, SALES, BONUS]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+EnumerableBatchNestedLoopJoin(condition=[AND(>($0, $3), <($1, $4))], joinType=[inner], batchSize=[100])
+ EnumerableLimit(fetch=[10])
+ EnumerableProject(ENAME=[$1], JOB=[$2], MGR=[$3])
+ EnumerableSort(sort0=[$1], sort1=[$2], sort2=[$3], dir0=[DESC], dir1=[DESC], dir2=[ASC])
+ EnumerableTableScan(table=[[CATALOG, SALES, EMP]])
+ EnumerableFilter(condition=[OR(AND(>($cor0.ENAME, $0), <($cor0.JOB, $1)), AND(>($cor1.ENAME, $0), <($cor1.JOB, $1)), AND(>($cor2.ENAME, $0), <($cor2.JOB, $1)), AND(>($cor3.ENAME, $0), <($cor3.JOB, $1)), AND(>($cor4.ENAME, $0), <($cor4.JOB, $1)), AND(>($cor5.ENAME, $0), <($cor5.JOB, $1)), AND(>($cor6.ENAME, $0), <($cor6.JOB, $1)), AND(>($cor7.ENAME, $0), <($cor7.JOB, $1)), AND(>($cor8.ENAME, $0), <($cor8.JOB, $1)), AND(>($cor9.ENAME, $0), <($cor9.JOB, $1)), AND(>($cor10.ENAME, $0), <($c [...]
+ EnumerableTableScan(table=[[CATALOG, SALES, BONUS]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testValuesTraitRequest">
<Resource name="sql">
<![CDATA[SELECT * from (values (1, 1), (2, 1), (1, 2), (2, 2))