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 <[email protected]>
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 <[email protected]>
---
.../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()))))));
+ }
}