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

alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new ecd554c1d89 IGNITE-18186 SQL Calcite: Push not correlated filter part 
to the table scan - Fixes #10383.
ecd554c1d89 is described below

commit ecd554c1d89957280ccd56dd68da742851016427
Author: Aleksey Plekhanov <plehanov.a...@gmail.com>
AuthorDate: Fri Nov 18 13:14:38 2022 +0300

    IGNITE-18186 SQL Calcite: Push not correlated filter part to the table scan 
- Fixes #10383.
    
    Signed-off-by: Aleksey Plekhanov <plehanov.a...@gmail.com>
---
 .../calcite/rule/logical/FilterScanMergeRule.java  | 50 +++++++++++++++++++---
 .../calcite/planner/HashIndexSpoolPlannerTest.java | 18 ++++++++
 2 files changed, 62 insertions(+), 6 deletions(-)

diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/FilterScanMergeRule.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/FilterScanMergeRule.java
index 76459398d86..7254435b7ed 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/FilterScanMergeRule.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/FilterScanMergeRule.java
@@ -16,10 +16,13 @@
  */
 package org.apache.ignite.internal.processors.query.calcite.rule.logical;
 
+import java.util.ArrayList;
+import java.util.List;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelRule;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
@@ -71,8 +74,32 @@ public abstract class FilterScanMergeRule<T extends 
ProjectableFilterableTableSc
         RelOptCluster cluster = scan.getCluster();
         RexBuilder builder = RexUtils.builder(cluster);
 
+        RexNode remainCondition = null;
         RexNode condition = filter.getCondition();
 
+        if (config.isSkipCorrelated() && RexUtils.hasCorrelation(condition)) {
+            RexNode cnf = RexUtil.toCnf(builder, condition);
+            List<RexNode> conjunctions = RelOptUtil.conjunctions(cnf);
+
+            List<RexNode> correlated = new ArrayList<>();
+            List<RexNode> notCorrelated = new ArrayList<>();
+
+            for (RexNode node : conjunctions) {
+                if (RexUtils.hasCorrelation(node))
+                    correlated.add(node);
+                else
+                    notCorrelated.add(node);
+            }
+
+            if (notCorrelated.isEmpty())
+                return;
+
+            if (!correlated.isEmpty()) {
+                remainCondition = RexUtil.composeConjunction(builder, 
correlated);
+                condition = RexUtil.composeConjunction(builder, notCorrelated);
+            }
+        }
+
         if (scan.projects() != null) {
             RexShuttle shuttle = new RexShuttle() {
                 @Override public RexNode visitInputRef(RexInputRef ref) {
@@ -102,6 +129,9 @@ public abstract class FilterScanMergeRule<T extends 
ProjectableFilterableTableSc
         if (res == null)
             return;
 
+        if (remainCondition != null)
+            res = call.builder().push(res).filter(remainCondition).build();
+
         call.transformTo(res);
     }
 
@@ -163,28 +193,36 @@ public abstract class FilterScanMergeRule<T extends 
ProjectableFilterableTableSc
 
         /** */
         Config TABLE_SCAN = DEFAULT
-            .withScanRuleConfig(IgniteLogicalTableScan.class, 
"FilterTableScanMergeRule", false);
+            .withScanRuleConfig(IgniteLogicalTableScan.class, 
"FilterTableScanMergeRule");
 
         /** */
         Config TABLE_SCAN_SKIP_CORRELATED = DEFAULT
-            .withScanRuleConfig(IgniteLogicalTableScan.class, 
"FilterTableScanMergeSkipCorrelatedRule", true);
+            .withScanRuleConfig(IgniteLogicalTableScan.class, 
"FilterTableScanMergeSkipCorrelatedRule")
+            .withSkipCorrelated(true);
 
         /** */
         Config INDEX_SCAN = DEFAULT
             .withRuleFactory(FilterIndexScanMergeRule::new)
-            .withScanRuleConfig(IgniteLogicalIndexScan.class, 
"FilterIndexScanMergeRule", false);
+            .withScanRuleConfig(IgniteLogicalIndexScan.class, 
"FilterIndexScanMergeRule");
 
         /** */
         default Config withScanRuleConfig(
             Class<? extends ProjectableFilterableTableScan> scanCls,
-            String desc,
-            boolean skipCorrelated
+            String desc
         ) {
             return withDescription(desc)
                 .withOperandSupplier(b -> b.operand(LogicalFilter.class)
-                    .predicate(p -> !skipCorrelated || 
!RexUtils.hasCorrelation(p.getCondition()))
                     .oneInput(b1 -> b1.operand(scanCls).noInputs()))
                 .as(Config.class);
         }
+
+        /** Whether to split correlated and not correlated conditions and do 
not push correlated into scan. */
+        @Value.Default
+        default boolean isSkipCorrelated() {
+            return false;
+        }
+
+        /** Sets {@link #isSkipCorrelated()}. */
+        Config withSkipCorrelated(boolean skipCorrelated);
     }
 }
diff --git 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/HashIndexSpoolPlannerTest.java
 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/HashIndexSpoolPlannerTest.java
index 49cb57cd692..b0b0ccb447c 100644
--- 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/HashIndexSpoolPlannerTest.java
+++ 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/HashIndexSpoolPlannerTest.java
@@ -24,6 +24,7 @@ import org.apache.calcite.rex.RexFieldAccess;
 import org.apache.calcite.rex.RexNode;
 import 
org.apache.ignite.internal.processors.query.calcite.rel.IgniteHashIndexSpool;
 import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRel;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableScan;
 import org.apache.ignite.internal.processors.query.calcite.schema.IgniteSchema;
 import 
org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistribution;
 import 
org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistributions;
@@ -227,4 +228,21 @@ public class HashIndexSpoolPlannerTest extends 
AbstractPlannerTest {
         assertTrue(searchRow.get(1) instanceof RexFieldAccess);
         assertNull(searchRow.get(2));
     }
+
+    /**
+     * Test that hash spool can be used with not correlated condition 
(condition is pushed below the spool).
+     */
+    @Test
+    public void testCorrelatedFilterSplit() throws Exception {
+        TestTable tbl = createTable("TBL", IgniteDistributions.random(), "ID", 
Integer.class);
+        IgniteSchema publicSchema = createSchema(tbl);
+
+        String sql = "SELECT (SELECT id FROM tbl AS t2 WHERE t2.id < 50 AND 
t2.id = t1.id) FROM tbl AS t1";
+
+        assertPlan(sql, publicSchema,
+            hasChildThat(isInstanceOf(IgniteHashIndexSpool.class)
+                .and(s -> "=($0, $cor0.ID)".equals(s.condition().toString()))
+                .and(hasChildThat(isInstanceOf(IgniteTableScan.class)
+                    .and(t -> "<($t0, 
50)".equals(t.condition().toString()))))));
+    }
 }

Reply via email to