This is an automated email from the ASF dual-hosted git repository.

rubenql pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new cc3c5fed07 [CALCITE-5670] Assertion error in SemiJoinJoinTransposeRule 
when Semi-Join has keys from both tables of the bottom Join
cc3c5fed07 is described below

commit cc3c5fed072dad2efc8d0961e66fea38ba8f3817
Author: Roman Kondakov <rkonda...@querifylabs.com>
AuthorDate: Sun Apr 23 18:35:12 2023 +0700

    [CALCITE-5670] Assertion error in SemiJoinJoinTransposeRule when Semi-Join 
has keys from both tables of the bottom Join
---
 .../rel/rules/SemiJoinJoinTransposeRule.java       |  9 ++++---
 .../org/apache/calcite/test/RelOptRulesTest.java   | 12 +++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 31 ++++++++++++++++++++++
 3 files changed, 48 insertions(+), 4 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinJoinTransposeRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinJoinTransposeRule.java
index 9ad23cc92e..d314b2819a 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinJoinTransposeRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinJoinTransposeRule.java
@@ -76,7 +76,6 @@ public class SemiJoinJoinTransposeRule
     if (join.isSemiJoin()) {
       return;
     }
-    final ImmutableIntList leftKeys = semiJoin.analyzeCondition().leftKeys;
 
     // X is the left child of the join below the semi-join
     // Y is the right child of the join below the semi-join
@@ -102,6 +101,7 @@ public class SemiJoinJoinTransposeRule
 
     // determine which operands below the semi-join are the actual
     // Rels that participate in the semi-join
+    final ImmutableIntList leftKeys = semiJoin.analyzeCondition().leftKeys;
     int nKeysFromX = 0;
     for (int leftKey : leftKeys) {
       if (leftKey < nFieldsX) {
@@ -109,9 +109,10 @@ public class SemiJoinJoinTransposeRule
       }
     }
 
-    // the keys must all originate from either the left or right;
-    // otherwise, a semi-join wouldn't have been created
-    assert (nKeysFromX == 0) || (nKeysFromX == leftKeys.size());
+    if (nKeysFromX != 0 && nKeysFromX != leftKeys.size()) {
+      // We can not push semi-join down if it has keys from both tables of the 
bottom join
+      return;
+    }
 
     // need to convert the semi-join condition and possibly the keys
     final RexNode newSemiJoinFilter;
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 4fd8e82711..841c32a700 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -2666,6 +2666,18 @@ class RelOptRulesTest extends RelOptTestBase {
         .check();
   }
 
+  @Test void testPushSemiJoinPastJoinRuleNotHappensJoinKeysDifferentOrigin() {
+    // tests the case where the semijoin is not pushed because it uses join 
keys from both tables
+    // of the bottom join.
+    final String sql = "select e.ename from emp e, dept d, bonus b\n"
+        + "where e.deptno = d.deptno and e.ename = b.ename and d.name = b.job";
+    sql(sql)
+        .withRule(CoreRules.FILTER_INTO_JOIN,
+            CoreRules.JOIN_ADD_REDUNDANT_SEMI_JOIN,
+            CoreRules.SEMI_JOIN_JOIN_TRANSPOSE)
+        .check();
+  }
+
   @Test void testPushSemiJoinPastFilter() {
     final String sql = "select e.ename from emp e, dept d\n"
         + "where e.deptno = d.deptno and e.ename = 'foo'";
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 91c54a496b..72567797e3 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -10533,6 +10533,37 @@ LogicalProject(ENAME=[$1])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
       LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase 
name="testPushSemiJoinPastJoinRuleNotHappensJoinKeysDifferentOrigin">
+    <Resource name="sql">
+      <![CDATA[select e.ename from emp e, dept d, bonus b
+where e.deptno = d.deptno and e.ename = b.ename and d.name = b.job]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(ENAME=[$1])
+  LogicalFilter(condition=[AND(=($7, $9), =($1, $11), =($10, $12))])
+    LogicalJoin(condition=[true], joinType=[inner])
+      LogicalJoin(condition=[true], joinType=[inner])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+      LogicalTableScan(table=[[CATALOG, SALES, BONUS]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(ENAME=[$1])
+  LogicalJoin(condition=[AND(=($1, $11), =($10, $12))], joinType=[inner], 
semiJoinDone=[true])
+    LogicalJoin(condition=[AND(=($1, $11), =($10, $12))], joinType=[semi])
+      LogicalJoin(condition=[=($7, $9)], joinType=[inner], semiJoinDone=[true])
+        LogicalJoin(condition=[=($7, $9)], joinType=[semi])
+          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+          LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+      LogicalTableScan(table=[[CATALOG, SALES, BONUS]])
+    LogicalTableScan(table=[[CATALOG, SALES, BONUS]])
 ]]>
     </Resource>
   </TestCase>

Reply via email to