Skip to content

Commit fb8b4d0

Browse files
committed
fix(MXP-4112): EnumerableBatchNestedLoopJoin causes infinit plan optimization for single sourced JDBC queries
1 parent 7f13bd7 commit fb8b4d0

File tree

1 file changed

+41
-2
lines changed

1 file changed

+41
-2
lines changed

core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBatchNestedLoopJoinRule.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616
*/
1717
package org.apache.calcite.adapter.enumerable;
1818

19+
import java.util.function.Predicate;
20+
21+
import org.apache.calcite.adapter.jdbc.JdbcConvention;
1922
import org.apache.calcite.plan.RelOptCluster;
2023
import org.apache.calcite.plan.RelOptRuleCall;
2124
import org.apache.calcite.plan.RelRule;
25+
import org.apache.calcite.plan.RelTrait;
2226
import org.apache.calcite.rel.RelNode;
2327
import org.apache.calcite.rel.core.CorrelationId;
2428
import org.apache.calcite.rel.core.Join;
@@ -80,10 +84,45 @@ public EnumerableBatchNestedLoopJoinRule(RelBuilderFactory relBuilderFactory,
8084
@Override public boolean matches(RelOptRuleCall call) {
8185
Join join = call.rel(0);
8286
JoinRelType joinType = join.getJoinType();
83-
return joinType == JoinRelType.INNER
87+
return (joinType == JoinRelType.INNER
8488
|| joinType == JoinRelType.LEFT
8589
|| joinType == JoinRelType.ANTI
86-
|| joinType == JoinRelType.SEMI;
90+
|| joinType == JoinRelType.SEMI )
91+
&& !allLeafsMatch(join, new HasSingleJdbcSource());
92+
}
93+
94+
private static class HasSingleJdbcSource implements Predicate<RelNode> {
95+
private JdbcConvention convention = null;
96+
@Override
97+
public boolean test(RelNode node) {
98+
for (RelTrait trait : node.getTraitSet()) {
99+
if (trait instanceof JdbcConvention) {
100+
JdbcConvention otherConvention = (JdbcConvention) trait;
101+
// The first leaf in the tree sets the convention
102+
if (convention == null) {
103+
convention = otherConvention;
104+
return true;
105+
}
106+
// All other leafs must match the stored convention
107+
return convention == otherConvention;
108+
}
109+
}
110+
return false;
111+
}
112+
}
113+
114+
private boolean allLeafsMatch(RelNode node, HasSingleJdbcSource predicate) {
115+
List<RelNode> inputs = node.getInputs();
116+
if ( inputs.isEmpty()) {
117+
return predicate.test(node);
118+
} else {
119+
for ( RelNode input : inputs) {
120+
if ( !allLeafsMatch(input.stripped(), predicate)) {
121+
return false;
122+
}
123+
}
124+
}
125+
return true;
87126
}
88127

89128
@Override public void onMatch(RelOptRuleCall call) {

0 commit comments

Comments
 (0)