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 3fe2d90721 [CALCITE-6875] EnumerableFilterRule/EnumerableProjectRule 
should not convert a Logical Filter/Project to Enumerable Filter/Project when 
it contains Subquery
3fe2d90721 is described below

commit 3fe2d9072137da70545c09f2836e7631bc2a964e
Author: Xiong Duan <[email protected]>
AuthorDate: Thu Mar 13 09:41:49 2025 +0800

    [CALCITE-6875] EnumerableFilterRule/EnumerableProjectRule should not 
convert a Logical Filter/Project to Enumerable Filter/Project when it contains 
Subquery
---
 .../adapter/enumerable/EnumerableFilterRule.java   |  4 +-
 .../adapter/enumerable/EnumerableProjectRule.java  |  6 ++-
 .../org/apache/calcite/test/RelOptRulesTest.java   | 38 ++++++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 53 ++++++++++++++++++++++
 4 files changed, 98 insertions(+), 3 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
 
b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
index 7bae121728..742696e665 100644
--- 
a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
+++ 
b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
@@ -21,6 +21,7 @@
 import org.apache.calcite.rel.convert.ConverterRule;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rex.RexUtil;
 
 /**
  * Rule to convert a {@link LogicalFilter} to an {@link EnumerableFilter}.
@@ -31,7 +32,8 @@
 class EnumerableFilterRule extends ConverterRule {
   /** Default configuration. */
   public static final Config DEFAULT_CONFIG = Config.INSTANCE
-      .withConversion(LogicalFilter.class, f -> !f.containsOver(),
+      .withConversion(LogicalFilter.class, f ->
+              !f.containsOver() && !RexUtil.SubQueryFinder.containsSubQuery(f),
           Convention.NONE, EnumerableConvention.INSTANCE,
           "EnumerableFilterRule")
       .withRuleFactory(EnumerableFilterRule::new);
diff --git 
a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
 
b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
index a564c98fd9..8fe54a54bd 100644
--- 
a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
+++ 
b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
@@ -34,8 +34,10 @@ class EnumerableProjectRule extends ConverterRule {
   /** Default configuration. */
   static final Config DEFAULT_CONFIG = Config.INSTANCE
       .as(Config.class)
-      .withConversion(LogicalProject.class,
-          p -> !p.containsOver() && !RexUtil.M2V_FINDER.inProject(p),
+      .withConversion(LogicalProject.class, p ->
+              !p.containsOver()
+                  && !RexUtil.M2V_FINDER.inProject(p)
+                  && !RexUtil.SubQueryFinder.containsSubQuery(p),
           Convention.NONE, EnumerableConvention.INSTANCE,
           "EnumerableProjectRule")
       .withRuleFactory(EnumerableProjectRule::new);
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 e3835355a5..61fc66acab 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -9347,6 +9347,44 @@ public interface Config extends RelRule.Config {
         .checkUnchanged();
   }
 
+  /**
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6875";>[CALCITE-6875]
+   * EnumerableFilterRule/EnumerableProjectRule should not convert a Logical 
Filter/Project
+   * to Enumerable Filter/Project when it contains Subquery</a>. */
+  @Test void testEnumerableFilterRule() {
+    final String sql = "select R_REGIONKEY from SALES.CUSTOMER\n"
+        + "where R_REGIONKEY > all (select R_REGIONKEY from SALES.CUSTOMER)";
+    sql(sql)
+        .withVolcanoPlanner(false, p -> {
+          p.addRelTraitDef(RelDistributionTraitDef.INSTANCE);
+          p.addRule(CoreRules.FILTER_SUB_QUERY_TO_CORRELATE);
+          p.addRule(EnumerableRules.ENUMERABLE_FILTER_RULE);
+          p.addRule(EnumerableRules.ENUMERABLE_PROJECT_RULE);
+          p.addRule(EnumerableRules.ENUMERABLE_TABLE_SCAN_RULE);
+          p.addRule(EnumerableRules.ENUMERABLE_JOIN_RULE);
+          p.addRule(EnumerableRules.ENUMERABLE_AGGREGATE_RULE);
+        })
+        .withDynamicTable()
+        .check();
+  }
+
+  @Test void testEnumerableProjectRule() {
+    final String sql = "select R_REGIONKEY > all (select R_REGIONKEY from 
SALES.CUSTOMER)\n"
+        + "from SALES.CUSTOMER";
+    sql(sql)
+        .withVolcanoPlanner(false, p -> {
+          p.addRelTraitDef(RelDistributionTraitDef.INSTANCE);
+          p.addRule(CoreRules.PROJECT_SUB_QUERY_TO_CORRELATE);
+          p.addRule(EnumerableRules.ENUMERABLE_PROJECT_RULE);
+          p.addRule(EnumerableRules.ENUMERABLE_TABLE_SCAN_RULE);
+          p.addRule(EnumerableRules.ENUMERABLE_JOIN_RULE);
+          p.addRule(EnumerableRules.ENUMERABLE_AGGREGATE_RULE);
+        })
+        .withDynamicTable()
+        .check();
+  }
+
   @Test void testEnumerableCalcRule() {
     final String sql = "select FNAME, LNAME\n"
         + "from SALES.CUSTOMER\n"
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 cde460b25f..11ca9705cb 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -4001,6 +4001,59 @@ LogicalProject(FNAME=[$1], LNAME=[$2])
 EnumerableProject(FNAME=[$1], LNAME=[$2])
   EnumerableCalc(expr#0..2=[{inputs}], expr#3=[10], expr#4=[>($t0, $t3)], 
proj#0..2=[{exprs}], $condition=[$t4])
     EnumerableTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testEnumerableFilterRule">
+    <Resource name="sql">
+      <![CDATA[select R_REGIONKEY from SALES.CUSTOMER
+where R_REGIONKEY > all (select R_REGIONKEY from SALES.CUSTOMER)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(R_REGIONKEY=[$0])
+  LogicalFilter(condition=[NOT(<= SOME($0, {
+LogicalProject(R_REGIONKEY=[$0])
+  LogicalTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+}))])
+    LogicalTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+EnumerableProject(R_REGIONKEY=[$0])
+  EnumerableProject(R_REGIONKEY=[$0])
+    EnumerableFilter(condition=[OR(=($2, 0), AND(>($0, $1), <>($2, 0), IS NOT 
TRUE(OR(<=($0, $1), >($2, $3)))))])
+      EnumerableNestedLoopJoin(condition=[true], joinType=[inner])
+        EnumerableTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+        EnumerableAggregate(group=[{}], m=[MAX($0)], c=[COUNT()], 
d=[COUNT($0)])
+          EnumerableProject(R_REGIONKEY=[$0])
+            EnumerableTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testEnumerableProjectRule">
+    <Resource name="sql">
+      <![CDATA[select R_REGIONKEY > all (select R_REGIONKEY from 
SALES.CUSTOMER)
+from SALES.CUSTOMER]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[NOT(<= SOME($0, {
+LogicalProject(R_REGIONKEY=[$0])
+  LogicalTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+}))])
+  LogicalTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+EnumerableProject(EXPR$0=[OR(=($2, 0), AND(>($2, $3), null, IS NOT TRUE(<=($0, 
$1))), AND(>($0, $1), IS NOT TRUE(<=($0, $1)), <=($2, $3)))])
+  EnumerableNestedLoopJoin(condition=[true], joinType=[inner])
+    EnumerableTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+    EnumerableAggregate(group=[{}], m=[MAX($0)], c=[COUNT()], d=[COUNT($0)])
+      EnumerableProject(R_REGIONKEY=[$0])
+        EnumerableTableScan(table=[[CATALOG, SALES, CUSTOMER]])
 ]]>
     </Resource>
   </TestCase>

Reply via email to