diff --git a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java index 6336b997e742..ca89260cbe6e 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java @@ -104,16 +104,11 @@ public MultiJoinOptimizeBushyRule(RelFactories.JoinFactory joinFactory, final RelMetadataQuery mq = call.getMetadataQuery(); final LoptMultiJoin multiJoin = new LoptMultiJoin(multiJoinRel); - for (int i = 0; i < multiJoin.getNumJoinFactors(); i++) { - ImmutableBitSet outerJoinFactors = multiJoin.getOuterJoinFactors(i); - if (outerJoinFactors == null) { - continue; - } - if (!outerJoinFactors.isEmpty()) { - // Refuse to apply this rule to a multijoin with outer joins, - // since this rule cannot handle outer joins. - return; - } + + if (multiJoinRel.isFullOuterJoin() || multiJoinRel.containsOuter()) { + // Refuse to apply this rule to a multijoin with outer joins, + // since this rule cannot handle outer joins. + return; } final List vertexes = new ArrayList<>(); 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 a7945606bc9a..ef9d2ffbb3af 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -4656,6 +4656,24 @@ private void checkPushJoinThroughUnionOnRightDoesNotMatchSemiOrAntiJoin(JoinRelT sql(sql).withPre(preProgram).withProgram(program).check(); } + /** Test case for [CALCITE-7833] + * MULTI_JOIN_OPTIMIZE_BUSHY may turn an outer join into an inner join. */ + @Test void testBushyJoinRuleSkipsFullOuterJoin() { + sql("select * from emp full join dept on emp.deptno = dept.deptno") + .withPreRule(CoreRules.JOIN_TO_MULTI_JOIN) + .withRule(CoreRules.MULTI_JOIN_OPTIMIZE_BUSHY) + .checkUnchanged(); + } + + /** Test case for [CALCITE-7833] + * MULTI_JOIN_OPTIMIZE_BUSHY may turn an outer join into an inner join. */ + @Test void testBushyJoinRuleSkipsLeftJoinOnTrue() { + sql("select * from emp left join dept on true") + .withPreRule(CoreRules.JOIN_TO_MULTI_JOIN) + .withRule(CoreRules.MULTI_JOIN_OPTIMIZE_BUSHY) + .checkUnchanged(); + } + @Test void testConvertMultiJoinRule() { final String sql = "select e1.ename from emp e1, dept d, emp e2\n" + "where e1.deptno = d.deptno and d.deptno = e2.deptno"; 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 97e54f5c7c44..e626fe7018a7 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -1894,6 +1894,32 @@ LogicalProject(ENAME=[$1]) MultiJoin(joinFilter=[true], isFullOuterJoin=[false], joinTypes=[[INNER, LEFT]], outerJoinConditions=[[NULL, =($1, $10)]], projFields=[[ALL, ALL]]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + + + + + + + + + + + + + + + +