This is an automated email from the ASF dual-hosted git repository.
jcamacho 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 16c9c36 [CALCITE-3908] JoinCommuteRule should update all input
references in join condition
16c9c36 is described below
commit 16c9c36f319b06ebcf1338f0e40e9de2ee912adf
Author: Jesus Camacho Rodriguez <[email protected]>
AuthorDate: Thu Apr 9 10:52:27 2020 -0700
[CALCITE-3908] JoinCommuteRule should update all input references in join
condition
Close apache/calcite#1906
---
.../apache/calcite/rel/rules/JoinCommuteRule.java | 55 ++++++++--------------
.../org/apache/calcite/test/RelOptRulesTest.java | 17 +++++++
.../org/apache/calcite/test/RelOptRulesTest.xml | 21 +++++++++
3 files changed, 58 insertions(+), 35 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
b/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
index 560a3fb..dfc74fb 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
@@ -29,14 +29,12 @@ import org.apache.calcite.rel.logical.LogicalJoin;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexCall;
import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.tools.RelBuilderFactory;
-import com.google.common.collect.ImmutableList;
-
import java.util.List;
import java.util.function.Predicate;
@@ -130,7 +128,7 @@ public class JoinCommuteRule extends RelOptRule {
final VariableReplacer variableReplacer =
new VariableReplacer(rexBuilder, leftRowType, rightRowType);
final RexNode oldCondition = join.getCondition();
- RexNode condition = variableReplacer.go(oldCondition);
+ RexNode condition = variableReplacer.apply(oldCondition);
// NOTE jvs 14-Mar-2006: We preserve attribute semiJoinDone after the
// swap. This way, we will generate one semijoin for the original
@@ -189,7 +187,7 @@ public class JoinCommuteRule extends RelOptRule {
* greater than leftFieldCount, it must be from the right, so we subtract
* leftFieldCount from it.</p>
*/
- private static class VariableReplacer {
+ private static class VariableReplacer extends RexShuttle {
private final RexBuilder rexBuilder;
private final List<RelDataTypeField> leftFields;
private final List<RelDataTypeField> rightFields;
@@ -203,37 +201,24 @@ public class JoinCommuteRule extends RelOptRule {
this.rightFields = rightType.getFieldList();
}
- public RexNode go(RexNode rex) {
- if (rex instanceof RexCall) {
- ImmutableList.Builder<RexNode> builder =
- ImmutableList.builder();
- final RexCall call = (RexCall) rex;
- for (RexNode operand : call.operands) {
- builder.add(go(operand));
- }
- return call.clone(call.getType(), builder.build());
- } else if (rex instanceof RexInputRef) {
- RexInputRef var = (RexInputRef) rex;
- int index = var.getIndex();
- if (index < leftFields.size()) {
- // Field came from left side of join. Move it to the right.
- return rexBuilder.makeInputRef(
- leftFields.get(index).getType(),
- rightFields.size() + index);
- }
- index -= leftFields.size();
- if (index < rightFields.size()) {
- // Field came from right side of join. Move it to the left.
- return rexBuilder.makeInputRef(
- rightFields.get(index).getType(),
- index);
- }
- throw new AssertionError("Bad field offset: index=" + var.getIndex()
- + ", leftFieldCount=" + leftFields.size()
- + ", rightFieldCount=" + rightFields.size());
- } else {
- return rex;
+ @Override public RexNode visitInputRef(RexInputRef inputRef) {
+ int index = inputRef.getIndex();
+ if (index < leftFields.size()) {
+ // Field came from left side of join. Move it to the right.
+ return rexBuilder.makeInputRef(
+ leftFields.get(index).getType(),
+ rightFields.size() + index);
+ }
+ index -= leftFields.size();
+ if (index < rightFields.size()) {
+ // Field came from right side of join. Move it to the left.
+ return rexBuilder.makeInputRef(
+ rightFields.get(index).getType(),
+ index);
}
+ throw new AssertionError("Bad field offset: index=" + inputRef.getIndex()
+ + ", leftFieldCount=" + leftFields.size()
+ + ", rightFieldCount=" + rightFields.size());
}
}
}
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index c1c5635..5197126 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -1689,6 +1689,23 @@ class RelOptRulesTest extends RelOptTestBase {
sql(sql).withRule(customPCTrans).check();
}
+ @Test void testSwapOuterJoinFieldAccess() {
+ HepProgram preProgram = new HepProgramBuilder()
+ .addMatchLimit(1)
+ .addRuleInstance(JoinProjectTransposeRule.LEFT_PROJECT_INCLUDE_OUTER)
+ .addRuleInstance(ProjectMergeRule.INSTANCE)
+ .build();
+ final HepProgram program = new HepProgramBuilder()
+ .addMatchLimit(1)
+ .addRuleInstance(JoinCommuteRule.SWAP_OUTER)
+ .addRuleInstance(ProjectMergeRule.INSTANCE)
+ .build();
+ final String sql = "select t1.name, e.ename\n"
+ + "from DEPT_NESTED as t1 left outer join sales.emp e\n"
+ + " on t1.skill.type = e.job";
+ sql(sql).withPre(preProgram).with(program).check();
+ }
+
@Test void testProjectCorrelateTranspose() {
ProjectCorrelateTransposeRule customPCTrans =
new ProjectCorrelateTransposeRule(expr -> true,
diff --git
a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 7cb8505..a99eaf2 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -12460,4 +12460,25 @@ LogicalProject(**=[$1])
]]>
</Resource>
</TestCase>
+ <TestCase name="testSwapOuterJoinFieldAccess">
+ <Resource name="sql">
+ <![CDATA[select t1.name, e.ename from DEPT_NESTED as t1 left outer
join sales.emp e on t1.skill.type = e.job]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(NAME=[$1], ENAME=[$5])
+ LogicalJoin(condition=[=($2.TYPE, $6)], joinType=[left])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT_NESTED]])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(NAME=[$10], ENAME=[$1])
+ LogicalJoin(condition=[=($11.TYPE, $2)], joinType=[right])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT_NESTED]])
+]]>
+ </Resource>
+ </TestCase>
</Root>