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

xiong 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 802fce3c41 [CALCITE-6873] FilterProjectTransposeRule should not push 
the Filter past the Project when the Filter contains a Subquery with correlation
802fce3c41 is described below

commit 802fce3c41be76fca899ddb8c856d72c754d1520
Author: Xiong Duan <[email protected]>
AuthorDate: Wed Mar 5 14:47:10 2025 +0800

    [CALCITE-6873] FilterProjectTransposeRule should not push the Filter past 
the Project when the Filter contains a Subquery with correlation
---
 .../main/java/org/apache/calcite/rex/RexUtil.java  | 15 +++++++
 .../org/apache/calcite/test/RelOptRulesTest.java   | 22 ++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 51 ++++++++++++++++++++++
 3 files changed, 88 insertions(+)

diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java 
b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index 2d1e78fb3e..d30a9d8a2b 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -2826,6 +2826,21 @@ private CorrelationFinder() {
     @Override public Void visitCorrelVariable(RexCorrelVariable var) {
       throw Util.FoundOne.NULL;
     }
+
+    @Override public Void visitSubQuery(RexSubQuery subQuery) {
+      if (!deep) {
+        return null;
+      }
+
+      for (RexNode operand : subQuery.operands) {
+        operand.accept(this);
+      }
+
+      if (!RelOptUtil.getVariablesUsed(subQuery.rel).isEmpty()) {
+        throw Util.FoundOne.NULL;
+      }
+      return null;
+    }
   }
 
   /** Shuttle that fixes up an expression to match changes in nullability of
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 baf8fd7183..42d5f6149f 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -521,6 +521,28 @@ private static boolean skipItem(RexNode expr) {
     }
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6873";>[CALCITE-6873]
+   * FilterProjectTransposeRule should not push the Filter past the Project
+   * when the Filter contains a Subquery with correlation</a>. */
+  @Test void testFilterProjectTransposeRule2() {
+    final String sql = "select * from (select deptno from emp) as d\n"
+        + "where NOT EXISTS (\n"
+        + "  select count(*) from emp e where e.deptno = d.deptno)";
+    sql(sql)
+        .withRule(CoreRules.FILTER_PROJECT_TRANSPOSE)
+        .checkUnchanged();
+  }
+
+  @Test void testFilterProjectTransposeRule3() {
+    final String sql = "select * from (select deptno from emp) as d\n"
+        + "where NOT EXISTS (\n"
+        + "  select count(*) from emp e)";
+    sql(sql)
+        .withRule(CoreRules.FILTER_PROJECT_TRANSPOSE)
+        .check();
+  }
+
   /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6031";>[CALCITE-6031]
    * Add the planner rule that pushes the Filter past a Sample</a>. */
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 153864230c..ca64c718e6 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -5245,6 +5245,57 @@ LogicalProject(EMPNO=[$0])
           LogicalFilter(condition=[=($cor0.DEPTNO, $0)])
             LogicalProject(TWICEDEPTNO=[*($0, 2)])
               LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testFilterProjectTransposeRule2">
+    <Resource name="sql">
+      <![CDATA[select * from (select deptno from emp) as d
+where NOT EXISTS (
+  select count(*) from emp e where e.deptno = d.deptno)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0])
+  LogicalFilter(condition=[NOT(EXISTS({
+LogicalAggregate(group=[{}], EXPR$0=[COUNT()])
+  LogicalProject($f0=[0])
+    LogicalFilter(condition=[=($7, $cor0.DEPTNO)])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+}))], variablesSet=[[$cor0]])
+    LogicalProject(DEPTNO=[$7])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testFilterProjectTransposeRule3">
+    <Resource name="sql">
+      <![CDATA[select * from (select deptno from emp) as d
+where NOT EXISTS (
+  select count(*) from emp e)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0])
+  LogicalFilter(condition=[NOT(EXISTS({
+LogicalAggregate(group=[{}], EXPR$0=[COUNT()])
+  LogicalProject($f0=[0])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+}))])
+    LogicalProject(DEPTNO=[$7])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0])
+  LogicalProject(DEPTNO=[$7])
+    LogicalFilter(condition=[NOT(EXISTS({
+LogicalAggregate(group=[{}], EXPR$0=[COUNT()])
+  LogicalProject($f0=[0])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+}))])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
     </Resource>
   </TestCase>

Reply via email to