This is an automated email from the ASF dual-hosted git repository. HappenLee pushed a commit to branch branch-4.2_tpc in repository https://gitbox.apache.org/repos/asf/doris.git
commit 4b728e15cfc3f5270e4316d2aab08a036b2aab43 Author: HappenLee <[email protected]> AuthorDate: Fri Oct 23 17:38:04 2026 +0800 Revert "branch-4.2 [fix](fe) Prune empty and cascading CTE plans (#62828, #61146) (#69308)" This reverts commit 84c3fd0d38ae497db8d0304ef93779863d169637. --- .../doris/nereids/jobs/executor/Optimizer.java | 78 ++------------ .../doris/nereids/rules/rewrite/CTEInliner.java | 86 +--------------- .../doris/nereids/rules/rewrite/ColumnPruning.java | 13 +-- .../doris/nereids/rules/rewrite/CTEInlineTest.java | 38 ------- .../nereids_p0/repeat/test_repeat_output_slot.out | 28 +++-- .../unique_function/agg_with_unique_function.out | 8 +- .../cte/test_cbo_cte_inline_prune.groovy | 113 --------------------- 7 files changed, 38 insertions(+), 326 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Optimizer.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Optimizer.java index 9c9b5aaaf36..38f68aa7cd5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Optimizer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Optimizer.java @@ -18,7 +18,6 @@ package org.apache.doris.nereids.jobs.executor; import org.apache.doris.nereids.CascadesContext; -import org.apache.doris.nereids.StatementContext; import org.apache.doris.nereids.jobs.cascades.DeriveStatsJob; import org.apache.doris.nereids.jobs.cascades.OptimizeGroupJob; import org.apache.doris.nereids.jobs.joinorder.JoinOrderJob; @@ -32,9 +31,6 @@ import org.apache.doris.nereids.rules.rewrite.ColumnPruning; import org.apache.doris.nereids.rules.rewrite.EliminateEmptyRelation; import org.apache.doris.nereids.rules.rewrite.EliminateUnnecessaryProject; import org.apache.doris.nereids.trees.plans.Plan; -import org.apache.doris.nereids.trees.plans.logical.LogicalCTEAnchor; -import org.apache.doris.nereids.trees.plans.logical.LogicalCTEConsumer; -import org.apache.doris.nereids.trees.plans.logical.LogicalCTEProducer; import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; import org.apache.doris.nereids.util.MoreFieldsThread; import org.apache.doris.qe.ConnectContext; @@ -65,12 +61,6 @@ public class Optimizer { */ public void execute() { MoreFieldsThread.keepFunctionSignature(() -> { - Plan rewritePlan = cascadesContext.getRewritePlan(); - if (containsCte(rewritePlan)) { - Plan normalizedPlan = normalizeCtePlan(rewritePlan); - cascadesContext.setRewritePlan(normalizedPlan); - refreshCteContext(normalizedPlan); - } // generate inlined CTE alternative for CBO comparison Plan cboInlinedPlan = generateCTEInlineAlternative(); // init memo @@ -159,9 +149,9 @@ public class Optimizer { private Plan generateFullCTEInline() { Plan rewritePlan = cascadesContext.getRewritePlan(); CTEInliner cteInliner = new CTEInliner(cascadesContext.getStatementContext()); - Plan pushedDownInlinedPlan = generateFilterPushedDownInlinedPlan(cteInliner, rewritePlan); - if (pushedDownInlinedPlan != null) { - return normalizeCtePlan(pushedDownInlinedPlan); + Plan inlinedPlan = cteInliner.generateInlinedPlan(rewritePlan); + if (inlinedPlan != null) { + return rewriteInlinedPlan(inlinedPlan); } return null; } @@ -172,60 +162,22 @@ public class Optimizer { private Plan generateSelectiveCTEInline() { Plan rewritePlan = cascadesContext.getRewritePlan(); CTEInliner cteInliner = new CTEInliner(cascadesContext.getStatementContext(), true); - Plan pushedDownInlinedPlan = generateFilterPushedDownInlinedPlan(cteInliner, rewritePlan); - if (pushedDownInlinedPlan != null) { - if (pushedDownInlinedPlan.anyMatch(p -> p instanceof LogicalEmptyRelation)) { - pushedDownInlinedPlan = normalizeCtePlan(pushedDownInlinedPlan); - cascadesContext.setRewritePlan(pushedDownInlinedPlan); - refreshCteContext(pushedDownInlinedPlan); + Plan inlinedPlan = cteInliner.generateInlinedPlan(rewritePlan); + if (inlinedPlan != null) { + inlinedPlan = rewriteInlinedPlan(inlinedPlan); + if (inlinedPlan.anyMatch(p -> p instanceof LogicalEmptyRelation)) { + inlinedPlan = eliminateEmptyRelation(inlinedPlan); + cascadesContext.setRewritePlan(inlinedPlan); return null; } } return null; } - private Plan normalizeCtePlan(Plan plan) { - Plan currentPlan = plan; - while (true) { - if (currentPlan.anyMatch(p -> p instanceof LogicalEmptyRelation)) { - currentPlan = eliminateEmptyRelation(currentPlan); - } - CTEInliner cteInliner = new CTEInliner(cascadesContext.getStatementContext()); - CTEInliner.InlineResult inlineResult = cteInliner.inlineByCurrentConsumerCount(currentPlan); - Plan normalizedPlan = inlineResult.getPlan(); - // Do not use Plan.equals() as a fixpoint check here. Some logical nodes, - // e.g. LogicalCTEAnchor and LogicalSubQueryAlias, intentionally ignore - // children in equals(), so a child CTE rewrite under a kept parent may be - // missed and block cascading consumer-count-based inlining. - if (!inlineResult.isChanged()) { - return normalizedPlan; - } - currentPlan = normalizedPlan; - } - } - - private boolean containsCte(Plan plan) { - return plan.anyMatch(p -> p instanceof LogicalCTEAnchor || p instanceof LogicalCTEConsumer); - } - - private void refreshCteContext(Plan plan) { - StatementContext statementContext = cascadesContext.getStatementContext(); - statementContext.clearCteEnvironment(); - plan.foreach(p -> { - if (p instanceof LogicalCTEAnchor) { - LogicalCTEAnchor<?, ?> anchor = (LogicalCTEAnchor<?, ?>) p; - statementContext.setCteProducer(anchor.getCteId(), (LogicalCTEProducer<?>) anchor.left()); - } else if (p instanceof LogicalCTEConsumer) { - cascadesContext.putCTEIdToConsumer((LogicalCTEConsumer) p); - } - return false; - }); - } - private Plan eliminateEmptyRelation(Plan plan) { CascadesContext ctx = CascadesContext.initContext( cascadesContext.getStatementContext(), plan, PhysicalProperties.ANY); - // Use getCteChildrenRewriter for the same reason as pushDownFilterAndPruneInlinedPlan: + // Use getCteChildrenRewriter for the same reason as rewriteInlinedPlan: // getWholeTreeRewriterWithCustomJobs would invoke RewriteCteChildren which // reads stale rewrittenCteConsumer cache from the main Rewriter phase, // reverting the inlined CTE subtrees back to the original structure. @@ -236,14 +188,6 @@ public class Optimizer { return ctx.getRewritePlan(); } - private Plan generateFilterPushedDownInlinedPlan(CTEInliner cteInliner, Plan rewritePlan) { - Plan inlinedPlan = cteInliner.generateInlinedPlan(rewritePlan); - if (inlinedPlan == null) { - return null; - } - return pushDownFilterAndPruneInlinedPlan(inlinedPlan); - } - /** * Run filter pushdown and column pruning on the inlined plan using a temporary * CascadesContext. @@ -256,7 +200,7 @@ public class Optimizer { * phase. That cached outer query still contains LogicalCTEConsumer nodes for the inlined CTE, * preventing the filter from ever reaching the inlined union body. */ - private Plan pushDownFilterAndPruneInlinedPlan(Plan inlinedPlan) { + private Plan rewriteInlinedPlan(Plan inlinedPlan) { CascadesContext inlinedContext = CascadesContext.initContext( cascadesContext.getStatementContext(), inlinedPlan, PhysicalProperties.ANY); Rewriter.getCteChildrenRewriter(inlinedContext, ImmutableList.of( diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CTEInliner.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CTEInliner.java index 36e082ecb33..47ec88c0159 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CTEInliner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CTEInliner.java @@ -31,7 +31,6 @@ import org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier; import org.apache.doris.nereids.trees.plans.logical.LogicalCTEAnchor; import org.apache.doris.nereids.trees.plans.logical.LogicalCTEConsumer; import org.apache.doris.nereids.trees.plans.logical.LogicalCTEProducer; -import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.logical.LogicalUnion; @@ -42,10 +41,8 @@ import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; /** * Generate an inlined alternative plan for CTE optimization. @@ -68,7 +65,6 @@ public class CTEInliner extends DefaultPlanRewriter<Void> { private final StatementContext statementContext; // Map from CTEId to the CTE producer node (extracted from CTEAnchor.left()) private final Map<CTEId, LogicalCTEProducer<?>> cteProducers = new HashMap<>(); - private final Set<CTEId> cteIdsToRemove = new HashSet<>(); private final boolean unionAllOnly; public CTEInliner(StatementContext statementContext) { @@ -85,7 +81,6 @@ public class CTEInliner extends DefaultPlanRewriter<Void> { * Returns null if no CTEs can be inlined. */ public Plan generateInlinedPlan(Plan plan) { - clearRewriteCandidates(); // First pass: collect all CTE producers that can be inlined collectCTEProducers(plan); @@ -97,44 +92,6 @@ public class CTEInliner extends DefaultPlanRewriter<Void> { return plan.accept(this, null); } - /** - * Recursively remove unused CTE anchors and inline CTEs whose live consumer count - * is small enough after rewrite rules change the plan shape. - */ - public InlineResult inlineByCurrentConsumerCount(Plan plan) { - Plan currentPlan = plan; - boolean changed = false; - while (collectConsumerDrivenCandidates(currentPlan)) { - changed = true; - currentPlan = currentPlan.accept(this, null); - } - return new InlineResult(currentPlan, changed); - } - - /** Result of one consumer-count-driven CTE normalization round. */ - public static class InlineResult { - private final Plan plan; - private final boolean changed; - - public InlineResult(Plan plan, boolean changed) { - this.plan = plan; - this.changed = changed; - } - - public Plan getPlan() { - return plan; - } - - public boolean isChanged() { - return changed; - } - } - - private void clearRewriteCandidates() { - cteProducers.clear(); - cteIdsToRemove.clear(); - } - private void collectCTEProducers(Plan plan) { plan.foreach(p -> { if (p instanceof LogicalCTEAnchor) { @@ -156,40 +113,6 @@ public class CTEInliner extends DefaultPlanRewriter<Void> { }); } - private boolean collectConsumerDrivenCandidates(Plan plan) { - clearRewriteCandidates(); - Map<CTEId, LogicalCTEProducer<?>> allCteProducers = new HashMap<>(); - Map<CTEId, Integer> cteConsumerCounts = new HashMap<>(); - plan.foreach(p -> { - if (p instanceof LogicalCTEAnchor) { - LogicalCTEAnchor<?, ?> anchor = (LogicalCTEAnchor<?, ?>) p; - allCteProducers.put(anchor.getCteId(), (LogicalCTEProducer<?>) anchor.left()); - } else if (p instanceof LogicalCTEConsumer) { - LogicalCTEConsumer consumer = (LogicalCTEConsumer) p; - cteConsumerCounts.merge(consumer.getCteId(), 1, Integer::sum); - } - }); - - int threshold = statementContext.getConnectContext().getSessionVariable().inlineCTEReferencedThreshold; - for (Map.Entry<CTEId, LogicalCTEProducer<?>> entry : allCteProducers.entrySet()) { - CTEId cteId = entry.getKey(); - LogicalCTEProducer<?> producer = entry.getValue(); - int consumerCount = cteConsumerCounts.getOrDefault(cteId, 0); - if (consumerCount == 0) { - cteIdsToRemove.add(cteId); - } else if (producer.child() instanceof LogicalEmptyRelation - || (consumerCount <= threshold && canInline(producer))) { - cteProducers.put(cteId, producer); - } - } - return !cteProducers.isEmpty() || !cteIdsToRemove.isEmpty(); - } - - private boolean canInline(LogicalCTEProducer<?> producer) { - return !statementContext.isForceMaterializeCTE(producer.getCteId()) - && !containsNondeterministicFunction(producer); - } - private boolean containsNondeterministicFunction(LogicalCTEProducer<?> producer) { List<Expression> nondeterministicFunctions = new ArrayList<>(); producer.accept(NondeterministicFunctionCollector.INSTANCE, nondeterministicFunctions); @@ -204,14 +127,13 @@ public class CTEInliner extends DefaultPlanRewriter<Void> { @Override public Plan visitLogicalCTEAnchor(LogicalCTEAnchor<? extends Plan, ? extends Plan> cteAnchor, Void context) { CTEId cteId = cteAnchor.getCteId(); - if (cteProducers.containsKey(cteId) || cteIdsToRemove.contains(cteId)) { - // Inline or remove: skip anchor and producer, process the right (consumer) subtree + if (cteProducers.containsKey(cteId)) { + // Inline: skip anchor and producer, process the right (consumer) subtree return cteAnchor.right().accept(this, null); } else { - // Keep the structure and continue trimming nested CTEs in both children. - Plan left = cteAnchor.left().accept(this, null); + // Force materialize: keep the structure, only process the right subtree Plan right = cteAnchor.right().accept(this, null); - return cteAnchor.withChildren(left, right); + return cteAnchor.withChildren(cteAnchor.left(), right); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ColumnPruning.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ColumnPruning.java index 84e52d6e57b..4597e3d2707 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ColumnPruning.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ColumnPruning.java @@ -38,7 +38,6 @@ import org.apache.doris.nereids.trees.plans.algebra.Aggregate; import org.apache.doris.nereids.trees.plans.algebra.Project; import org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier; import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; -import org.apache.doris.nereids.trees.plans.logical.LogicalCTEAnchor; import org.apache.doris.nereids.trees.plans.logical.LogicalCTEConsumer; import org.apache.doris.nereids.trees.plans.logical.LogicalCTEProducer; import org.apache.doris.nereids.trees.plans.logical.LogicalExcept; @@ -268,15 +267,9 @@ public class ColumnPruning extends DefaultPlanRewriter<PruneContext> implements return pruneAggregate(repeat, context); } - @Override - public Plan visitLogicalCTEAnchor(LogicalCTEAnchor<? extends Plan, ? extends Plan> cteAnchor, - PruneContext context) { - return skipPruneThisAndFirstLevelChildren(cteAnchor); - } - @Override public Plan visitLogicalCTEProducer(LogicalCTEProducer<? extends Plan> cteProducer, PruneContext context) { - return skipPruneThisAndFirstLevelChildren(cteProducer); + return skipPruneThis(cteProducer); } @Override @@ -321,10 +314,6 @@ public class ColumnPruning extends DefaultPlanRewriter<PruneContext> implements return pruneChildren(plan, plan.getOutputExprIdBitSet()); } - private Plan skipPruneThisAndFirstLevelChildren(Plan plan) { - return pruneChildren(plan, plan.getChildrenOutputExprIdBitSet()); - } - // some rules want to match the aggregate which contains all the group by keys and aggregate functions // in the output of LogicalAggregate, so here we not to prune the group by keys in the output of aggregate, // for example: diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CTEInlineTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CTEInlineTest.java index 7ae9aa1e995..e9767ef524b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CTEInlineTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CTEInlineTest.java @@ -21,9 +21,7 @@ import org.apache.doris.nereids.NereidsPlanner; import org.apache.doris.nereids.StatementContext; import org.apache.doris.nereids.parser.NereidsParser; import org.apache.doris.nereids.properties.PhysicalProperties; -import org.apache.doris.nereids.trees.expressions.CTEId; import org.apache.doris.nereids.trees.plans.commands.ExplainCommand; -import org.apache.doris.nereids.trees.plans.logical.LogicalCTEConsumer; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.util.MemoPatternMatchSupported; import org.apache.doris.nereids.util.MemoTestUtils; @@ -31,24 +29,13 @@ import org.apache.doris.nereids.util.PlanChecker; import org.apache.doris.qe.OriginStatement; import org.apache.doris.utframe.TestWithFeService; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.Map; -import java.util.Set; - public class CTEInlineTest extends TestWithFeService implements MemoPatternMatchSupported { @Override protected void runBeforeAll() throws Exception { createDatabase("test"); connectContext.setDatabase("test"); - createTable("CREATE TABLE cte_inline_tbl (\n" - + " id int NULL,\n" - + " val int NULL\n" - + ") ENGINE=OLAP\n" - + "DUPLICATE KEY(id)\n" - + "DISTRIBUTED BY HASH(id) BUCKETS 1\n" - + "PROPERTIES (\"replication_num\" = \"1\")"); } @Test @@ -94,29 +81,4 @@ public class CTEInlineTest extends TestWithFeService implements MemoPatternMatch ).when(cte -> cte.getCteName().equals("yy")) ); } - - @Test - public void refreshCteConsumersAfterNormalizeEliminatesEmptyBranch() { - int oldCteInlineMode = connectContext.getSessionVariable().cteInlineMode; - int oldInlineCteReferencedThreshold = connectContext.getSessionVariable().inlineCTEReferencedThreshold; - connectContext.getSessionVariable().cteInlineMode = 0; - connectContext.getSessionVariable().inlineCTEReferencedThreshold = 1; - connectContext.getSessionVariable().setDisableNereidsRules("PRUNE_EMPTY_PARTITION"); - String sql = "with cte as (select id, val from cte_inline_tbl) " - + "select * from cte where id = 1 " - + "union all select * from cte where id = 2 " - + "union all select * from cte where 1 = 0"; - try { - PlanChecker.from(connectContext).checkPlannerResult(sql, planner -> { - Map<CTEId, Set<LogicalCTEConsumer>> consumers = - planner.getCascadesContext().getStatementContext().getCteIdToConsumers(); - Assertions.assertEquals(1, consumers.size()); - Assertions.assertEquals(2, consumers.values().iterator().next().size()); - }); - } finally { - connectContext.getSessionVariable().cteInlineMode = oldCteInlineMode; - connectContext.getSessionVariable().inlineCTEReferencedThreshold = oldInlineCteReferencedThreshold; - connectContext.getSessionVariable().setDisableNereidsRules(""); - } - } } diff --git a/regression-test/data/nereids_p0/repeat/test_repeat_output_slot.out b/regression-test/data/nereids_p0/repeat/test_repeat_output_slot.out index 8019e6bf2b5..f8ab9595435 100644 --- a/regression-test/data/nereids_p0/repeat/test_repeat_output_slot.out +++ b/regression-test/data/nereids_p0/repeat/test_repeat_output_slot.out @@ -39,17 +39,22 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) 100000 -- !sql_2_shape -- -PhysicalResultSink ---PhysicalProject -----filter((GROUPING_PREFIX_col_varchar_50__undef_signed__index_inverted_col_datetime_6__undef_signed_col_varchar_50__undef_signed > 0)) -------hashAgg[GLOBAL] ---------hashAgg[LOCAL] -----------PhysicalRepeat -------------PhysicalProject ---------------hashAgg[GLOBAL] -----------------hashAgg[LOCAL] -------------------PhysicalProject ---------------------PhysicalOlapScan[tbl_test_repeat_output_slot] +PhysicalCteAnchor ( cteId=CTEId#0 ) +--PhysicalCteProducer ( cteId=CTEId#0 ) +----hashAgg[GLOBAL] +------hashAgg[LOCAL] +--------PhysicalProject +----------PhysicalOlapScan[tbl_test_repeat_output_slot] +--PhysicalResultSink +----PhysicalProject +------PhysicalUnion +--------PhysicalProject +----------filter((GROUPING_PREFIX_col_varchar_50__undef_signed__index_inverted_col_datetime_6__undef_signed_col_varchar_50__undef_signed > 0)) +------------hashAgg[GLOBAL] +--------------hashAgg[LOCAL] +----------------PhysicalRepeat +------------------PhysicalCteConsumer ( cteId=CTEId#0 ) +--------PhysicalEmptyRelation -- !sql_2_result -- \N ALL 1 6 \N \N \N @@ -59,3 +64,4 @@ PhysicalResultSink 2020-01-04T00:00 ALL 1 6 \N \N b 2020-01-04T00:00 ALL 1 6 \N \N b 2020-01-04T00:00 ALL 1 7 \N \N \N + diff --git a/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out b/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out index adc172f81d6..dfe9a28c4bb 100644 --- a/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out +++ b/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out @@ -264,7 +264,9 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ----PhysicalProject[a + random(), a + random() + 0, abs(a + random()), sum(a + random() + 0), sum(a + random())] ------PhysicalQuickSort[MERGE_SORT] --------PhysicalQuickSort[LOCAL_SORT] -----------PhysicalProject[(a + random() + 1.0) AS `(a + random() + 1.0)`, a + random() + 0 AS `a + random() + 0`, a + random() AS `a + random()`, abs(a + random()) AS `abs(a + random())`, sum(a + random() + 0) AS `sum(a + random() + 0)`, sum(a + random()) AS `sum(a + random())`] -------------filter((.a + random() + 0 > 0.01)) ---------------PhysicalCteConsumer ( cteId=CTEId#0 ) +----------PhysicalProject[(a + random() + 1.0) AS `(a + random() + 1.0)`, a + random(), a + random() + 0, abs(a + random()) AS `abs(a + random())`, sum(a + random() + 0), sum(a + random())] +------------PhysicalUnion +--------------PhysicalEmptyRelation +--------------filter((.a + random() + 0 > 0.01)) +----------------PhysicalCteConsumer ( cteId=CTEId#0 ) diff --git a/regression-test/suites/nereids_p0/cte/test_cbo_cte_inline_prune.groovy b/regression-test/suites/nereids_p0/cte/test_cbo_cte_inline_prune.groovy deleted file mode 100644 index ffd4f2acae4..00000000000 --- a/regression-test/suites/nereids_p0/cte/test_cbo_cte_inline_prune.groovy +++ /dev/null @@ -1,113 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -suite("test_cbo_cte_inline_prune") { - sql "DROP TABLE IF EXISTS cte_cbo_inline_tbl" - sql """ - CREATE TABLE cte_cbo_inline_tbl ( - id INT, - val INT - ) ENGINE=OLAP - DUPLICATE KEY(id) - DISTRIBUTED BY HASH(id) BUCKETS 1 - PROPERTIES ("replication_num" = "1") - """ - sql "INSERT INTO cte_cbo_inline_tbl VALUES (1, 10), (2, 20), (3, 30)" - - sql "DROP TABLE IF EXISTS cte_cbo_empty_array_tbl" - sql """ - CREATE TABLE cte_cbo_empty_array_tbl ( - id INT, - vals ARRAY<INT> - ) ENGINE=OLAP - DUPLICATE KEY(id) - DISTRIBUTED BY HASH(id) BUCKETS 1 - PROPERTIES ("replication_num" = "1") - """ - - sql "SET cte_inline_mode=1" - sql "SET inline_cte_referenced_threshold=1" - - explain { - sql "SELECT count(*) FROM cte_cbo_empty_array_tbl" - contains("VEMPTYSET") - } - - explain { - sql """ - shape plan - WITH cte_base AS ( - SELECT id, val, 1 AS tag FROM cte_cbo_inline_tbl - ) - SELECT * FROM cte_base WHERE tag = 2 - UNION ALL - SELECT * FROM cte_base WHERE tag = 3 - """ - contains("PhysicalEmptyRelation") - notContains("PhysicalCteProducer") - } - - explain { - sql """ - shape plan - WITH cte_base AS ( - SELECT id, val, 1 AS tag FROM cte_cbo_inline_tbl - ), - cte_keep AS ( - SELECT id, val FROM cte_base WHERE tag = 1 - ), - cte_drop AS ( - SELECT id, val FROM cte_base WHERE tag = 2 - ) - SELECT * FROM cte_keep - UNION ALL - SELECT * FROM cte_keep - UNION ALL - SELECT * FROM cte_drop WHERE 1 = 0 - """ - multiContains("PhysicalCteProducer", 0) - } - - sql "SET cte_inline_mode=0" - explain { - sql """ - shape plan - WITH cte_base AS ( - SELECT id, val, 1 AS tag FROM cte_cbo_inline_tbl - ), - cte_keep AS ( - SELECT id, val FROM cte_base WHERE tag = 1 - ), - cte_drop AS ( - SELECT id, val FROM cte_base WHERE tag = 2 - ), - cte_outer AS ( - SELECT * FROM cte_keep - UNION ALL - SELECT * FROM cte_drop WHERE 1 = 0 - ) - SELECT * FROM cte_outer - UNION ALL - SELECT * FROM cte_outer - """ - // cte_outer is still referenced twice and remains materialized, but - // eliminating cte_drop makes cte_base have only one live consumer. - // The fixpoint check must revisit the kept outer CTE anchor and inline - // cte_base; otherwise two producers would remain. - multiContains("PhysicalCteProducer", 1) - } -} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
