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>