This is an automated email from the ASF dual-hosted git repository.
huajianlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new deef491e01 [fix](Nereids) refactor CTE and EliminateAliasNode and fix
the bug that CTE reuse relationId (#14534)
deef491e01 is described below
commit deef491e0104746b3cc7bcfd6ca50481b960531a
Author: 924060929 <[email protected]>
AuthorDate: Fri Nov 25 10:54:53 2022 +0800
[fix](Nereids) refactor CTE and EliminateAliasNode and fix the bug that CTE
reuse relationId (#14534)
This pr contribute:
- support explain CTE;
- refine CTE, fix the bug: reuse the same analyzed plan which
LogicalOlapScan has the same relationId;
- change EliminateAliasNode to LogicalSubQueryAliasToLogicalProject and
move to the top of rewrite stage, so we can simply observe the analyzed plan by
the LogicalSubQueryAlias with alias;
- job traverse left child first, so the ExprId growth from left child to
right child.
---
.../antlr4/org/apache/doris/nereids/DorisParser.g4 | 9 +-
.../org/apache/doris/nereids/CascadesContext.java | 18 ++-
.../org/apache/doris/nereids/StatementContext.java | 17 ---
.../doris/nereids/analyzer/NereidsAnalyzer.java | 2 -
... AdjustApplyFromCorrelateToUnCorrelateJob.java} | 4 +-
.../nereids/jobs/batch/FinalizeAnalyzeJob.java | 40 ------
.../jobs/batch/NereidsRewriteJobExecutor.java | 9 +-
.../nereids/jobs/cascades/OptimizeGroupJob.java | 14 +-
.../nereids/jobs/rewrite/RewriteBottomUpJob.java | 5 +-
.../nereids/jobs/rewrite/RewriteTopDownJob.java | 5 +-
.../java/org/apache/doris/nereids/memo/Memo.java | 5 +
.../doris/nereids/parser/LogicalPlanBuilder.java | 85 ++++++------
.../doris/nereids/pattern/MatchingContext.java | 3 +
.../org/apache/doris/nereids/rules/RuleType.java | 9 +-
.../nereids/rules/analysis/AnalyzeSubquery.java | 32 ++---
.../doris/nereids/rules/analysis/BindRelation.java | 13 +-
.../nereids/rules/analysis/BindSlotReference.java | 2 +-
.../doris/nereids/rules/analysis/CTEContext.java | 77 ++++++++---
.../nereids/rules/analysis/EliminateAliasNode.java | 66 ---------
.../LogicalSubQueryAliasToLogicalProject.java | 43 ++++++
.../doris/nereids/rules/analysis/RegisterCTE.java | 107 ++++-----------
.../doris/nereids/trees/expressions/Slot.java | 4 +
.../nereids/trees/expressions/SlotReference.java | 5 +
.../nereids/trees/plans/logical/LogicalCTE.java | 12 +-
.../trees/plans/logical/LogicalSubQueryAlias.java | 34 +++--
.../trees/plans/physical/PhysicalLimit.java | 3 +-
.../java/org/apache/doris/qe/StmtExecutor.java | 2 -
.../rules/analysis/AnalyzeSubQueryTest.java | 24 +++-
.../rules/analysis/AnalyzeWhereSubqueryTest.java | 62 ++++++---
.../nereids/rules/analysis/RegisterCTETest.java | 149 ++++++++++++---------
.../nereids/rules/mv/SelectRollupIndexTest.java | 4 +
.../PushdownExpressionsInHashConditionTest.java | 78 ++++++-----
.../doris/nereids/trees/expressions/ViewTest.java | 6 +-
regression-test/data/nereids_syntax_p0/cte.out | 12 +-
34 files changed, 504 insertions(+), 456 deletions(-)
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
index 7a16b52f39..8a6627edda 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -49,9 +49,12 @@ singleStatement
;
statement
- : cte? query
#statementDefault
- | (EXPLAIN planType? | DESC | DESCRIBE)
- level=(VERBOSE | GRAPH | PLAN)? query
#explain
+ : explain? cte? query #statementDefault
+ ;
+
+explain
+ : (EXPLAIN planType? | DESC | DESCRIBE)
+ level=(VERBOSE | GRAPH | PLAN)?
;
planType
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/CascadesContext.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/CascadesContext.java
index 9aca1d2f8b..a2b97e6880 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/CascadesContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/CascadesContext.java
@@ -32,6 +32,7 @@ import org.apache.doris.nereids.properties.PhysicalProperties;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleFactory;
import org.apache.doris.nereids.rules.RuleSet;
+import org.apache.doris.nereids.rules.analysis.CTEContext;
import org.apache.doris.nereids.rules.analysis.Scope;
import org.apache.doris.nereids.trees.expressions.SubqueryExpr;
import org.apache.doris.nereids.trees.plans.Plan;
@@ -50,6 +51,8 @@ import java.util.Optional;
public class CascadesContext {
private final Memo memo;
private final StatementContext statementContext;
+
+ private CTEContext cteContext;
private RuleSet ruleSet;
private JobPool jobPool;
private final JobScheduler jobScheduler;
@@ -58,13 +61,17 @@ public class CascadesContext {
private final Map<SubqueryExpr, Boolean> subqueryExprIsAnalyzed;
private final RuntimeFilterContext runtimeFilterContext;
+ public CascadesContext(Memo memo, StatementContext statementContext) {
+ this(memo, statementContext, new CTEContext());
+ }
+
/**
* Constructor of OptimizerContext.
*
* @param memo {@link Memo} reference
* @param statementContext {@link StatementContext} reference
*/
- public CascadesContext(Memo memo, StatementContext statementContext) {
+ public CascadesContext(Memo memo, StatementContext statementContext,
CTEContext cteContext) {
this.memo = memo;
this.statementContext = statementContext;
this.ruleSet = new RuleSet();
@@ -73,6 +80,7 @@ public class CascadesContext {
this.currentJobContext = new JobContext(this, PhysicalProperties.ANY,
Double.MAX_VALUE);
this.subqueryExprIsAnalyzed = new HashMap<>();
this.runtimeFilterContext = new
RuntimeFilterContext(getConnectContext().getSessionVariable());
+ this.cteContext = cteContext;
}
public static CascadesContext newContext(StatementContext
statementContext, Plan initPlan) {
@@ -176,6 +184,14 @@ public class CascadesContext {
return execute(new RewriteTopDownJob(memo.getRoot(), rules,
currentJobContext));
}
+ public CTEContext getCteContext() {
+ return cteContext;
+ }
+
+ public void setCteContext(CTEContext cteContext) {
+ this.cteContext = cteContext;
+ }
+
private CascadesContext execute(Job job) {
pushJob(job);
jobScheduler.executeJobPool(this);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java
index 8b04dc8f06..ca7e13d6b5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java
@@ -19,7 +19,6 @@ package org.apache.doris.nereids;
import org.apache.doris.analysis.StatementBase;
import org.apache.doris.common.IdGenerator;
-import org.apache.doris.nereids.rules.analysis.CTEContext;
import org.apache.doris.nereids.trees.expressions.ExprId;
import org.apache.doris.nereids.trees.plans.RelationId;
import org.apache.doris.qe.ConnectContext;
@@ -40,21 +39,13 @@ public class StatementContext {
private StatementBase parsedStatement;
- private CTEContext cteContext;
-
public StatementContext() {
this.connectContext = ConnectContext.get();
- this.cteContext = new CTEContext();
}
public StatementContext(ConnectContext connectContext, OriginStatement
originStatement) {
- this(connectContext, originStatement, new CTEContext());
- }
-
- public StatementContext(ConnectContext connectContext, OriginStatement
originStatement, CTEContext cteContext) {
this.connectContext = connectContext;
this.originStatement = originStatement;
- this.cteContext = cteContext;
}
public void setConnectContext(ConnectContext connectContext) {
@@ -85,14 +76,6 @@ public class StatementContext {
return relationIdGenerator.getNextId();
}
- public CTEContext getCteContext() {
- return cteContext;
- }
-
- public void setCteContext(CTEContext cteContext) {
- this.cteContext = cteContext;
- }
-
public void setParsedStatement(StatementBase parsedStatement) {
this.parsedStatement = parsedStatement;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/NereidsAnalyzer.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/NereidsAnalyzer.java
index 75bcfc8117..120eb635a7 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/NereidsAnalyzer.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/NereidsAnalyzer.java
@@ -21,7 +21,6 @@ import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.jobs.batch.AnalyzeRulesJob;
import org.apache.doris.nereids.jobs.batch.AnalyzeSubqueryRulesJob;
import org.apache.doris.nereids.jobs.batch.CheckAnalysisJob;
-import org.apache.doris.nereids.jobs.batch.FinalizeAnalyzeJob;
import org.apache.doris.nereids.jobs.batch.TypeCoercionJob;
import org.apache.doris.nereids.rules.analysis.Scope;
@@ -52,7 +51,6 @@ public class NereidsAnalyzer {
new AnalyzeRulesJob(cascadesContext, outerScope).execute();
new AnalyzeSubqueryRulesJob(cascadesContext).execute();
new TypeCoercionJob(cascadesContext).execute();
- new FinalizeAnalyzeJob(cascadesContext).execute();
// check whether analyze result is meaningful
new CheckAnalysisJob(cascadesContext).execute();
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AdjustApplyFromCorrelatToUnCorrelatJob.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AdjustApplyFromCorrelateToUnCorrelateJob.java
similarity index 92%
rename from
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AdjustApplyFromCorrelatToUnCorrelatJob.java
rename to
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AdjustApplyFromCorrelateToUnCorrelateJob.java
index c61bb007cf..e4c9f057d4 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AdjustApplyFromCorrelatToUnCorrelatJob.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AdjustApplyFromCorrelateToUnCorrelateJob.java
@@ -33,11 +33,11 @@ import com.google.common.collect.ImmutableList;
* For the project and filter on AGG, try to adjust them to apply.
* For the project and filter under AGG, bring the filter under AGG and merge
it with agg.
*/
-public class AdjustApplyFromCorrelatToUnCorrelatJob extends BatchRulesJob {
+public class AdjustApplyFromCorrelateToUnCorrelateJob extends BatchRulesJob {
/**
* Constructor.
*/
- public AdjustApplyFromCorrelatToUnCorrelatJob(CascadesContext
cascadesContext) {
+ public AdjustApplyFromCorrelateToUnCorrelateJob(CascadesContext
cascadesContext) {
super(cascadesContext);
rulesJob.addAll(ImmutableList.of(
topDownBatch(ImmutableList.of(
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/FinalizeAnalyzeJob.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/FinalizeAnalyzeJob.java
deleted file mode 100644
index 4430bfa86f..0000000000
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/FinalizeAnalyzeJob.java
+++ /dev/null
@@ -1,40 +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.
-
-package org.apache.doris.nereids.jobs.batch;
-
-import org.apache.doris.nereids.CascadesContext;
-import org.apache.doris.nereids.rules.analysis.EliminateAliasNode;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Job to eliminate the logical node of sub query and alias
- */
-public class FinalizeAnalyzeJob extends BatchRulesJob {
-
- /**
- * constructor
- * @param cascadesContext ctx
- */
- public FinalizeAnalyzeJob(CascadesContext cascadesContext) {
- super(cascadesContext);
- rulesJob.addAll(ImmutableList.of(
- bottomUpBatch(ImmutableList.of(new EliminateAliasNode()))
- ));
- }
-}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriteJobExecutor.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriteJobExecutor.java
index 32fc226e5d..4f99e4c660 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriteJobExecutor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriteJobExecutor.java
@@ -21,6 +21,7 @@ import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.jobs.Job;
import org.apache.doris.nereids.rules.RuleSet;
import org.apache.doris.nereids.rules.analysis.CheckAfterRewrite;
+import
org.apache.doris.nereids.rules.analysis.LogicalSubQueryAliasToLogicalProject;
import
org.apache.doris.nereids.rules.expression.rewrite.ExpressionNormalization;
import
org.apache.doris.nereids.rules.expression.rewrite.ExpressionOptimization;
import org.apache.doris.nereids.rules.mv.SelectMaterializedIndexWithAggregate;
@@ -33,6 +34,7 @@ import
org.apache.doris.nereids.rules.rewrite.logical.ExtractSingleTableExpressi
import org.apache.doris.nereids.rules.rewrite.logical.FindHashConditionForJoin;
import org.apache.doris.nereids.rules.rewrite.logical.InferPredicates;
import org.apache.doris.nereids.rules.rewrite.logical.LimitPushDown;
+import org.apache.doris.nereids.rules.rewrite.logical.MergeProjects;
import org.apache.doris.nereids.rules.rewrite.logical.NormalizeAggregate;
import org.apache.doris.nereids.rules.rewrite.logical.PruneOlapScanPartition;
import org.apache.doris.nereids.rules.rewrite.logical.PushFilterInsideJoin;
@@ -53,6 +55,11 @@ public class NereidsRewriteJobExecutor extends BatchRulesJob
{
public NereidsRewriteJobExecutor(CascadesContext cascadesContext) {
super(cascadesContext);
ImmutableList<Job> jobs = new ImmutableList.Builder<Job>()
+ // MergeProjects depends on this rule
+ .add(bottomUpBatch(ImmutableList.of(new
LogicalSubQueryAliasToLogicalProject())))
+ // AdjustApplyFromCorrelateToUnCorrelateJob and
ConvertApplyToJoinJob
+ // and SelectMaterializedIndexWithAggregate depends on this
rule
+ .add(topDownBatch(ImmutableList.of(new MergeProjects())))
/*
* Subquery unnesting.
* 1. Adjust the plan in correlated logicalApply
@@ -60,7 +67,7 @@ public class NereidsRewriteJobExecutor extends BatchRulesJob {
* 2. Convert logicalApply to a logicalJoin.
* TODO: group these rules to make sure the result plan is
what we expected.
*/
- .addAll(new
AdjustApplyFromCorrelatToUnCorrelatJob(cascadesContext).rulesJob)
+ .addAll(new
AdjustApplyFromCorrelateToUnCorrelateJob(cascadesContext).rulesJob)
.addAll(new ConvertApplyToJoinJob(cascadesContext).rulesJob)
.add(topDownBatch(ImmutableList.of(new
ExpressionNormalization(cascadesContext.getConnectContext()))))
.add(topDownBatch(ImmutableList.of(new
ExpressionOptimization())))
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
index 618e405b8f..8395adfebe 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
@@ -23,6 +23,8 @@ import org.apache.doris.nereids.jobs.JobType;
import org.apache.doris.nereids.memo.Group;
import org.apache.doris.nereids.memo.GroupExpression;
+import java.util.List;
+
/**
* Job to optimize {@link Group} in {@link org.apache.doris.nereids.memo.Memo}.
*/
@@ -41,12 +43,16 @@ public class OptimizeGroupJob extends Job {
return;
}
if (!group.isExplored()) {
- for (GroupExpression logicalGroupExpression :
group.getLogicalExpressions()) {
- context.getCascadesContext().pushJob(new
OptimizeGroupExpressionJob(logicalGroupExpression, context));
+ List<GroupExpression> logicalExpressions =
group.getLogicalExpressions();
+ for (int i = logicalExpressions.size() - 1; i >= 0; i--) {
+ context.getCascadesContext().pushJob(
+ new
OptimizeGroupExpressionJob(logicalExpressions.get(i), context));
}
}
- for (GroupExpression physicalGroupExpression :
group.getPhysicalExpressions()) {
- context.getCascadesContext().pushJob(new
CostAndEnforcerJob(physicalGroupExpression, context));
+
+ List<GroupExpression> physicalExpressions =
group.getPhysicalExpressions();
+ for (int i = physicalExpressions.size() - 1; i >= 0; i--) {
+ context.getCascadesContext().pushJob(new
CostAndEnforcerJob(physicalExpressions.get(i), context));
}
group.setExplored(true);
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
index bc7f9cfe32..a7041fc8bb 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
@@ -65,8 +65,9 @@ public class RewriteBottomUpJob extends Job {
GroupExpression logicalExpression = group.getLogicalExpression();
if (!childrenOptimized) {
pushJob(new RewriteBottomUpJob(group, rules, context, true));
- for (Group childGroup : logicalExpression.children()) {
- pushJob(new RewriteBottomUpJob(childGroup, rules, context,
false));
+ List<Group> children = logicalExpression.children();
+ for (int i = children.size() - 1; i >= 0; i--) {
+ pushJob(new RewriteBottomUpJob(children.get(i), rules,
context, false));
}
return;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
index 8eb0654ad1..8164baf25d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
@@ -95,8 +95,9 @@ public class RewriteTopDownJob extends Job {
}
}
- for (Group childGroup : group.getLogicalExpression().children()) {
- pushJob(new RewriteTopDownJob(childGroup, rules, context));
+ List<Group> children = group.getLogicalExpression().children();
+ for (int i = children.size() - 1; i >= 0; i--) {
+ pushJob(new RewriteTopDownJob(children.get(i), rules, context));
}
}
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
index 31a5dee6a4..d98ef76b9b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
@@ -21,6 +21,7 @@ import org.apache.doris.common.IdGenerator;
import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.StatementContext;
import org.apache.doris.nereids.properties.LogicalProperties;
+import org.apache.doris.nereids.rules.analysis.CTEContext;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.GroupPlan;
import org.apache.doris.nereids.trees.plans.Plan;
@@ -174,6 +175,10 @@ public class Memo {
return new CascadesContext(this, statementContext);
}
+ public CascadesContext newCascadesContext(StatementContext
statementContext, CTEContext cteContext) {
+ return new CascadesContext(this, statementContext, cteContext);
+ }
+
/**
* init memo by a first plan.
* @param plan first plan
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index cf197fce84..9d5cc39569 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -139,7 +139,6 @@ import
org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
-import org.apache.doris.nereids.trees.plans.commands.Command;
import org.apache.doris.nereids.trees.plans.commands.ExplainCommand;
import
org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
@@ -212,8 +211,9 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
@Override
public LogicalPlan visitStatementDefault(StatementDefaultContext ctx) {
- LogicalPlan plan = visitQuery(ctx.query());
- return ctx.cte() == null ? plan : withCte(ctx.cte(), plan);
+ LogicalPlan plan = plan(ctx.query());
+ plan = withCte(plan, ctx.cte());
+ return withExplain(plan, ctx.explain());
}
/**
@@ -242,8 +242,11 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
/**
* process CTE and store the results in a logical plan node LogicalCTE
*/
- public LogicalPlan withCte(CteContext ctx, LogicalPlan plan) {
- return new LogicalCTE<>(visit(ctx.aliasQuery(),
LogicalSubQueryAlias.class), plan);
+ public LogicalPlan withCte(LogicalPlan plan, CteContext ctx) {
+ if (ctx == null) {
+ return plan;
+ }
+ return new LogicalCTE<>((List) visit(ctx.aliasQuery(),
LogicalSubQueryAlias.class), plan);
}
/**
@@ -263,29 +266,6 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
});
}
- @Override
- public Command visitExplain(ExplainContext ctx) {
- return ParserUtils.withOrigin(ctx, () -> {
- LogicalPlan logicalPlan = plan(ctx.query());
- ExplainLevel explainLevel = ExplainLevel.NORMAL;
-
- if (ctx.planType() != null) {
- if (ctx.level == null ||
!ctx.level.getText().equalsIgnoreCase("plan")) {
- throw new ParseException("Only explain plan can use plan
type: " + ctx.planType().getText(), ctx);
- }
- }
-
- if (ctx.level != null) {
- if (!ctx.level.getText().equalsIgnoreCase("plan")) {
- explainLevel =
ExplainLevel.valueOf(ctx.level.getText().toUpperCase(Locale.ROOT));
- } else {
- explainLevel = parseExplainPlanType(ctx.planType());
- }
- }
- return new ExplainCommand(explainLevel, logicalPlan);
- });
- }
-
@Override
public LogicalPlan visitQuery(QueryContext ctx) {
return ParserUtils.withOrigin(ctx, () -> {
@@ -298,18 +278,22 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
@Override
public LogicalPlan
visitRegularQuerySpecification(RegularQuerySpecificationContext ctx) {
return ParserUtils.withOrigin(ctx, () -> {
+ SelectClauseContext selectCtx = ctx.selectClause();
+ LogicalPlan selectPlan;
if (ctx.fromClause() == null) {
- return withOneRowRelation(ctx.selectClause());
+ selectPlan = withOneRowRelation(selectCtx);
+ } else {
+ LogicalPlan relation = visitFromClause(ctx.fromClause());
+ selectPlan = withSelectQuerySpecification(
+ ctx, relation,
+ selectCtx,
+ Optional.ofNullable(ctx.whereClause()),
+ Optional.ofNullable(ctx.aggClause()),
+ Optional.ofNullable(ctx.havingClause())
+ );
}
- LogicalPlan relation = visitFromClause(ctx.fromClause());
- return withSelectQuerySpecification(
- ctx, relation,
- ctx.selectClause(),
- Optional.ofNullable(ctx.whereClause()),
- Optional.ofNullable(ctx.aggClause()),
- Optional.ofNullable(ctx.havingClause())
- );
+ return withSelectHint(selectPlan, selectCtx.selectHint());
});
}
@@ -866,6 +850,30 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
return typedVisit(ctx);
}
+ private LogicalPlan withExplain(LogicalPlan inputPlan, ExplainContext ctx)
{
+ if (ctx == null) {
+ return inputPlan;
+ }
+ return ParserUtils.withOrigin(ctx, () -> {
+ ExplainLevel explainLevel = ExplainLevel.NORMAL;
+
+ if (ctx.planType() != null) {
+ if (ctx.level == null ||
!ctx.level.getText().equalsIgnoreCase("plan")) {
+ throw new ParseException("Only explain plan can use plan
type: " + ctx.planType().getText(), ctx);
+ }
+ }
+
+ if (ctx.level != null) {
+ if (!ctx.level.getText().equalsIgnoreCase("plan")) {
+ explainLevel =
ExplainLevel.valueOf(ctx.level.getText().toUpperCase(Locale.ROOT));
+ } else {
+ explainLevel = parseExplainPlanType(ctx.planType());
+ }
+ }
+ return new ExplainCommand(explainLevel, inputPlan);
+ });
+ }
+
private LogicalPlan withQueryOrganization(LogicalPlan inputPlan,
QueryOrganizationContext ctx) {
Optional<SortClauseContext> sortClauseContext =
Optional.ofNullable(ctx.sortClause());
Optional<LimitClauseContext> limitClauseContext =
Optional.ofNullable(ctx.limitClause());
@@ -929,8 +937,7 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
LogicalPlan aggregate = withAggregate(filter, selectClause,
aggClause);
// TODO: replace and process having at this position
LogicalPlan having = withHaving(aggregate, havingClause);
- LogicalPlan projection = withProjection(having, selectClause,
aggClause);
- return withSelectHint(projection, selectClause.selectHint());
+ return withProjection(having, selectClause, aggClause);
});
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/MatchingContext.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/MatchingContext.java
index a1ba46cdb7..de9205d2f8 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/MatchingContext.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/MatchingContext.java
@@ -19,6 +19,7 @@ package org.apache.doris.nereids.pattern;
import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.StatementContext;
+import org.apache.doris.nereids.rules.analysis.CTEContext;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.qe.ConnectContext;
@@ -31,6 +32,7 @@ public class MatchingContext<TYPE extends Plan> {
public final CascadesContext cascadesContext;
public final StatementContext statementContext;
public final ConnectContext connectContext;
+ public final CTEContext cteContext;
/**
* the MatchingContext is the param pass through the MatchedAction.
@@ -45,5 +47,6 @@ public class MatchingContext<TYPE extends Plan> {
this.cascadesContext = cascadesContext;
this.statementContext = cascadesContext.getStatementContext();
this.connectContext = cascadesContext.getConnectContext();
+ this.cteContext = cascadesContext.getCteContext();
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
index 2f75b14e35..54132bc9df 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
@@ -77,14 +77,7 @@ public enum RuleType {
AGGREGATE_DISASSEMBLE(RuleTypeClass.REWRITE),
COLUMN_PRUNE_PROJECTION(RuleTypeClass.REWRITE),
ELIMINATE_UNNECESSARY_PROJECT(RuleTypeClass.REWRITE),
- ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE),
-
- PROJECT_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE),
- FILTER_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE),
- JOIN_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE),
- JOIN_LEFT_CHILD_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE),
- JOIN_RIGHT_CHILD_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE),
- AGGREGATE_ELIMINATE_ALIAS_NODE(RuleTypeClass.REWRITE),
+ LOGICAL_SUB_QUERY_ALIAS_TO_LOGICAL_PROJECT(RuleTypeClass.REWRITE),
// subquery analyze
ANALYZE_FILTER_SUBQUERY(RuleTypeClass.REWRITE),
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubquery.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubquery.java
index cbffb53611..4293c5962d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubquery.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubquery.java
@@ -50,23 +50,23 @@ public class AnalyzeSubquery implements AnalysisRuleFactory
{
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
- RuleType.ANALYZE_FILTER_SUBQUERY.build(
- logicalFilter().thenApply(ctx -> {
- LogicalFilter filter = ctx.root;
- Set<SubqueryExpr> subqueryExprs =
filter.getPredicates()
- .collect(SubqueryExpr.class::isInstance);
- if (subqueryExprs.isEmpty()) {
- return filter;
- }
+ RuleType.ANALYZE_FILTER_SUBQUERY.build(
+ logicalFilter().thenApply(ctx -> {
+ LogicalFilter filter = ctx.root;
+ Set<SubqueryExpr> subqueryExprs = filter.getPredicates()
+ .collect(SubqueryExpr.class::isInstance);
+ if (subqueryExprs.isEmpty()) {
+ return filter;
+ }
- // first step: Replace the subquery of predicate
in LogicalFilter
- // second step: Replace subquery with LogicalApply
- return new LogicalFilter<>(new
ReplaceSubquery().replace(filter.getPredicates()),
- analyzedSubquery(
- subqueryExprs, (LogicalPlan)
filter.child(), ctx.cascadesContext
- ));
- })
- )
+ // first step: Replace the subquery of predicate in
LogicalFilter
+ // second step: Replace subquery with LogicalApply
+ return new LogicalFilter<>(new
ReplaceSubquery().replace(filter.getPredicates()),
+ analyzedSubquery(
+ subqueryExprs, (LogicalPlan) filter.child(),
ctx.cascadesContext
+ ));
+ })
+ )
);
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java
index 72f4ca3fa0..fd1337e191 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java
@@ -37,6 +37,7 @@ import org.apache.doris.qe.ConnectContext;
import com.google.common.collect.ImmutableList;
import java.util.List;
+import java.util.Optional;
/**
* Rule to bind relations in query plan.
@@ -76,9 +77,15 @@ public class BindRelation extends OneAnalysisRuleFactory {
private LogicalPlan bindWithCurrentDb(CascadesContext cascadesContext,
String tableName) {
// check if it is a CTE's name
- CTEContext cteContext =
cascadesContext.getStatementContext().getCteContext();
- if (cteContext.containsCTE(tableName)) {
- return new LogicalSubQueryAlias<>(tableName,
cteContext.getAnalyzedCTEPlan(tableName));
+ CTEContext cteContext = cascadesContext.getCteContext();
+ Optional<LogicalPlan> analyzedCte =
cteContext.getAnalyzedCTE(tableName);
+ if (analyzedCte.isPresent()) {
+ LogicalPlan ctePlan = analyzedCte.get();
+ if (ctePlan instanceof LogicalSubQueryAlias
+ && ((LogicalSubQueryAlias<?>)
ctePlan).getAlias().equals(tableName)) {
+ return ctePlan;
+ }
+ return new LogicalSubQueryAlias<>(tableName, ctePlan);
}
String dbName = cascadesContext.getConnectContext().getDatabase();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
index df0302b778..e7b445ba62 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
@@ -556,7 +556,7 @@ public class BindSlotReference implements
AnalysisRuleFactory {
private AnalyzedResult analyzeSubquery(SubqueryExpr expr) {
CascadesContext subqueryContext = new Memo(expr.getQueryPlan())
-
.newCascadesContext((cascadesContext.getStatementContext()));
+
.newCascadesContext((cascadesContext.getStatementContext()),
cascadesContext.getCteContext());
Scope subqueryScope = genScopeWithSubquery(expr);
subqueryContext
.newAnalyzer(Optional.of(subqueryScope))
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CTEContext.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CTEContext.java
index da73da93ab..7bddf9d57b 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CTEContext.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CTEContext.java
@@ -17,48 +17,89 @@
package org.apache.doris.nereids.rules.analysis;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias;
+
+import com.google.common.collect.ImmutableMap;
-import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import javax.annotation.Nullable;
/**
* Context used for CTE analysis and register
*/
public class CTEContext {
+ private Map<String, CTEContext> cteContextMap;
- // store CTE name and both initial and analyzed LogicalPlan of with query;
- // The initial LogicalPlan is used to inline a CTE if it is referenced by
another CTE,
- // and the analyzed LogicalPlan will be if it is referenced by the main
query.
- private Map<String, LogicalPlan> initialCtePlans;
- private Map<String, LogicalPlan> analyzedCtePlans;
+ private String name;
+ private LogicalSubQueryAlias<Plan> parsedPlan;
+ // this cache only use once
+ private LogicalPlan analyzedPlanCacheOnce;
+ private Function<Plan, LogicalPlan> analyzePlanBuilder;
+ /* build head CTEContext */
public CTEContext() {
- initialCtePlans = new HashMap<>();
- analyzedCtePlans = new HashMap<>();
+ this(null, null);
+ }
+
+ /** CTEContext */
+ public CTEContext(@Nullable LogicalSubQueryAlias<Plan> parsedPlan,
@Nullable CTEContext previousCteContext) {
+ if ((parsedPlan == null && previousCteContext != null) || (parsedPlan
!= null && previousCteContext == null)) {
+ throw new AnalysisException("Only first CteContext can contains
null cte plan or previousCteContext");
+ }
+ this.parsedPlan = parsedPlan;
+ this.name = parsedPlan == null ? null : parsedPlan.getAlias();
+ this.cteContextMap = previousCteContext == null
+ ? ImmutableMap.of()
+ : ImmutableMap.<String, CTEContext>builder()
+ .putAll(previousCteContext.cteContextMap)
+ .put(name, this)
+ .build();
+ }
+
+ public void setAnalyzedPlanCacheOnce(LogicalPlan analyzedPlan) {
+ this.analyzedPlanCacheOnce = analyzedPlan;
+ }
+
+ public void setAnalyzePlanBuilder(Function<Plan, LogicalPlan>
analyzePlanBuilder) {
+ this.analyzePlanBuilder = analyzePlanBuilder;
}
/**
* check if cteName can be found in current order
*/
public boolean containsCTE(String cteName) {
- return initialCtePlans.containsKey(cteName);
+ return findCTEContext(cteName).isPresent();
}
- public LogicalPlan getInitialCTEPlan(String cteName) {
- return initialCtePlans.get(cteName);
+ public Optional<LogicalSubQueryAlias<Plan>> getParsedCtePlan(String
cteName) {
+ return findCTEContext(cteName).map(cte -> cte.parsedPlan);
}
- public LogicalPlan getAnalyzedCTEPlan(String cteName) {
- return analyzedCtePlans.get(cteName);
+ /** getAnalyzedCTE */
+ public Optional<LogicalPlan> getAnalyzedCTE(String cteName) {
+ return findCTEContext(cteName).map(CTEContext::doAnalyzeCTE);
}
- public void putInitialPlan(String cteName, LogicalPlan plan) {
- initialCtePlans.put(cteName, plan);
+ /** findCTEContext */
+ public Optional<CTEContext> findCTEContext(String cteName) {
+ CTEContext cteContext = cteContextMap.get(cteName);
+ return Optional.ofNullable(cteContext);
}
- public void putAnalyzedPlan(String cteName, LogicalPlan plan) {
- analyzedCtePlans.put(cteName, plan);
+ private LogicalPlan doAnalyzeCTE() {
+ // we always analyze a cte as least once, if the cte only use once, we
can return analyzedPlanCacheOnce.
+ // but if the cte use more then once, we should return difference
analyzed plan to generate difference
+ // relation id, so the relation will not conflict in the memo.
+ if (analyzedPlanCacheOnce != null) {
+ LogicalPlan analyzedPlan = analyzedPlanCacheOnce;
+ analyzedPlanCacheOnce = null;
+ return analyzedPlan;
+ }
+ return analyzePlanBuilder.apply(parsedPlan);
}
-
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateAliasNode.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateAliasNode.java
deleted file mode 100644
index 0691d42e4a..0000000000
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateAliasNode.java
+++ /dev/null
@@ -1,66 +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.
-
-package org.apache.doris.nereids.rules.analysis;
-
-import org.apache.doris.nereids.rules.Rule;
-import org.apache.doris.nereids.rules.RuleType;
-
-import com.google.common.collect.ImmutableList;
-
-import java.util.List;
-
-/**
- * Eliminate the logical sub query and alias node after analyze and before
rewrite
- * If we match the alias node and return its child node, in the execute() of
the job
- * <p>
- * TODO: refactor group merge strategy to support the feature above
- */
-public class EliminateAliasNode implements AnalysisRuleFactory {
- @Override
- public List<Rule> buildRules() {
- return ImmutableList.of(
- RuleType.PROJECT_ELIMINATE_ALIAS_NODE.build(
- logicalProject(logicalSubQueryAlias())
- .then(project ->
project.withChildren(ImmutableList.of(project.child().child())))
- ),
- RuleType.FILTER_ELIMINATE_ALIAS_NODE.build(
- logicalFilter(logicalSubQueryAlias())
- .then(filter ->
filter.withChildren(ImmutableList.of(filter.child().child())))
- ),
- RuleType.AGGREGATE_ELIMINATE_ALIAS_NODE.build(
- aggregate(logicalSubQueryAlias())
- .then(agg ->
agg.withChildren(ImmutableList.of(agg.child().child())))
- ),
- RuleType.JOIN_ELIMINATE_ALIAS_NODE.build(
- logicalJoin(logicalSubQueryAlias(),
logicalSubQueryAlias())
- .then(join -> join.withChildren(
- ImmutableList.of(join.left().child(),
join.right().child())))
- ),
- RuleType.JOIN_LEFT_CHILD_ELIMINATE_ALIAS_NODE.build(
- logicalJoin(logicalSubQueryAlias(), group())
- .then(join -> join.withChildren(
- ImmutableList.of(join.left().child(),
join.right())))
- ),
- RuleType.JOIN_RIGHT_CHILD_ELIMINATE_ALIAS_NODE.build(
- logicalJoin(group(), logicalSubQueryAlias())
- .then(join -> join.withChildren(
- ImmutableList.of(join.left(),
join.right().child())))
- )
- );
- }
-}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/LogicalSubQueryAliasToLogicalProject.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/LogicalSubQueryAliasToLogicalProject.java
new file mode 100644
index 0000000000..2f39a493e2
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/LogicalSubQueryAliasToLogicalProject.java
@@ -0,0 +1,43 @@
+// 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.
+
+package org.apache.doris.nereids.rules.analysis;
+
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+
+import java.util.List;
+
+/**
+ * Eliminate the logical sub query and alias node after analyze and before
rewrite
+ * If we match the alias node and return its child node, in the execute() of
the job
+ * <p>
+ * TODO: refactor group merge strategy to support the feature above
+ */
+public class LogicalSubQueryAliasToLogicalProject extends
OneAnalysisRuleFactory {
+ @Override
+ public Rule build() {
+ return RuleType.LOGICAL_SUB_QUERY_ALIAS_TO_LOGICAL_PROJECT.build(
+ logicalSubQueryAlias().then(alias -> {
+ List<Slot> output = alias.getOutput();
+ return new LogicalProject<>((List) output, alias.child());
+ })
+ );
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/RegisterCTE.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/RegisterCTE.java
index ac11a32022..39e5701e0c 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/RegisterCTE.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/RegisterCTE.java
@@ -18,30 +18,23 @@
package org.apache.doris.nereids.rules.analysis;
import org.apache.doris.nereids.CascadesContext;
-import org.apache.doris.nereids.StatementContext;
-import org.apache.doris.nereids.analyzer.UnboundAlias;
-import org.apache.doris.nereids.analyzer.UnboundRelation;
-import org.apache.doris.nereids.analyzer.UnboundSlot;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.memo.Memo;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
-import org.apache.doris.nereids.trees.expressions.Alias;
-import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.GroupPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalCTE;
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.LogicalSubQueryAlias;
-import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter;
+
+import com.google.common.collect.ImmutableList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
+import java.util.function.Function;
/**
* Register CTE, includes checking columnAliases, checking CTE name, analyzing
each CTE and store the
@@ -55,78 +48,50 @@ public class RegisterCTE extends OneAnalysisRuleFactory {
public Rule build() {
return logicalCTE().thenApply(ctx -> {
LogicalCTE<GroupPlan> logicalCTE = ctx.root;
- register(logicalCTE.getAliasQueries(), ctx.statementContext);
- return (LogicalPlan) logicalCTE.child();
+ register(logicalCTE.getAliasQueries(), ctx.cascadesContext);
+ return logicalCTE.child();
}).toRule(RuleType.REGISTER_CTE);
}
/**
* register and store CTEs in CTEContext
*/
- private void register(List<LogicalSubQueryAlias> aliasQueryList,
StatementContext statementContext) {
- CTEContext cteContext = statementContext.getCteContext();
-
- for (LogicalSubQueryAlias<LogicalPlan> aliasQuery : aliasQueryList) {
+ private void register(List<LogicalSubQueryAlias<Plan>> aliasQueryList,
CascadesContext cascadesContext) {
+ CTEContext cteCtx = cascadesContext.getCteContext();
+ for (LogicalSubQueryAlias<Plan> aliasQuery : aliasQueryList) {
String cteName = aliasQuery.getAlias();
- if (cteContext.containsCTE(cteName)) {
+ if (cteCtx.containsCTE(cteName)) {
throw new AnalysisException("CTE name [" + cteName + "] cannot
be used more than once.");
}
- // inline CTE's initialPlan if it is referenced by another CTE
- LogicalPlan plan = aliasQuery.child();
- plan = (LogicalPlan) new CTEVisitor().inlineCTE(cteContext, plan);
- cteContext.putInitialPlan(cteName, plan);
+ // we should use a chain to ensure visible of cte
+ CTEContext localCteContext = cteCtx;
- // analyze CTE's initialPlan
- CascadesContext cascadesContext = new
Memo(plan).newCascadesContext(statementContext);
- cascadesContext.newAnalyzer().analyze();
- LogicalPlan analyzedPlan = (LogicalPlan)
cascadesContext.getMemo().copyOut(false);
+ Function<Plan, LogicalPlan> analyzeCte = parsePlan -> {
+ CascadesContext localCascadesContext = new Memo(parsePlan)
+
.newCascadesContext(cascadesContext.getStatementContext(), localCteContext);
+ localCascadesContext.newAnalyzer().analyze();
+ return (LogicalPlan)
localCascadesContext.getMemo().copyOut(false);
+ };
+ LogicalPlan analyzedCteBody = analyzeCte.apply(aliasQuery.child());
if (aliasQuery.getColumnAliases().isPresent()) {
- analyzedPlan = withColumnAliases(analyzedPlan, aliasQuery,
cteContext);
+ checkColumnAlias(aliasQuery, analyzedCteBody.getOutput());
}
- cteContext.putAnalyzedPlan(cteName, analyzedPlan);
- }
- }
-
- /**
- * deal with columnAliases of CTE
- */
- private LogicalPlan withColumnAliases(LogicalPlan analyzedPlan,
- LogicalSubQueryAlias<LogicalPlan>
aliasQuery, CTEContext cteContext) {
- List<Slot> outputSlots = analyzedPlan.getOutput();
- List<String> columnAliases = aliasQuery.getColumnAliases().get();
-
- checkColumnAlias(aliasQuery, outputSlots);
-
- // if this CTE has columnAlias, we should add an extra LogicalProject
to both its initialPlan and analyzedPlan,
- // which is used to store columnAlias
-
- // projects for initialPlan
- List<NamedExpression> unboundProjects = IntStream.range(0,
outputSlots.size())
- .mapToObj(i -> i >= columnAliases.size()
- ? new UnboundSlot(outputSlots.get(i).getName())
- : new UnboundAlias(new
UnboundSlot(outputSlots.get(i).getName()), columnAliases.get(i)))
- .collect(Collectors.toList());
+ cteCtx = new CTEContext(aliasQuery, localCteContext);
- String name = aliasQuery.getAlias();
- LogicalPlan initialPlan = cteContext.getInitialCTEPlan(name);
- cteContext.putInitialPlan(name, new LogicalProject<>(unboundProjects,
initialPlan));
-
- // projects for analyzedPlan
- List<NamedExpression> boundedProjects = IntStream.range(0,
outputSlots.size())
- .mapToObj(i -> i >= columnAliases.size()
- ? outputSlots.get(i)
- : new Alias(outputSlots.get(i), columnAliases.get(i)))
- .collect(Collectors.toList());
- return new LogicalProject<>(boundedProjects, analyzedPlan);
+ // now we can simply wrap aliasQuery for the first usage of this
cte
+
cteCtx.setAnalyzedPlanCacheOnce(aliasQuery.withChildren(ImmutableList.of(analyzedCteBody)));
+ cteCtx.setAnalyzePlanBuilder(analyzeCte);
+ }
+ cascadesContext.setCteContext(cteCtx);
}
/**
* check columnAliases' size and name
*/
- private void checkColumnAlias(LogicalSubQueryAlias<LogicalPlan>
aliasQuery, List<Slot> outputSlots) {
+ private void checkColumnAlias(LogicalSubQueryAlias<Plan> aliasQuery,
List<Slot> outputSlots) {
List<String> columnAlias = aliasQuery.getColumnAliases().get();
// if the size of columnAlias is smaller than outputSlots' size, we
will replace the corresponding number
// of front slots with columnAlias.
@@ -146,24 +111,4 @@ public class RegisterCTE extends OneAnalysisRuleFactory {
names.add(alias);
});
}
-
- private class CTEVisitor extends DefaultPlanRewriter<CTEContext> {
- @Override
- public LogicalPlan visitUnboundRelation(UnboundRelation
unboundRelation, CTEContext cteContext) {
- // confirm if it is a CTE
- if (unboundRelation.getNameParts().size() != 1) {
- return unboundRelation;
- }
- String name = unboundRelation.getTableName();
- if (cteContext.containsCTE(name)) {
- return new LogicalSubQueryAlias<>(name,
cteContext.getInitialCTEPlan(name));
- }
- return unboundRelation;
- }
-
- public Plan inlineCTE(CTEContext cteContext, LogicalPlan ctePlan) {
- return ctePlan.accept(this, cteContext);
- }
- }
-
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
index 8b54c637f4..3a3b498c51 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
@@ -38,4 +38,8 @@ public abstract class Slot extends NamedExpression implements
LeafExpression {
public Slot withQualifier(List<String> qualifiers) {
throw new RuntimeException("Do not implement");
}
+
+ public Slot withName(String name) {
+ throw new RuntimeException("Do not implement");
+ }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java
index b64852f880..ee5feed16d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java
@@ -182,6 +182,11 @@ public class SlotReference extends Slot {
return new SlotReference(exprId, name, dataType, nullable, qualifiers,
column);
}
+ @Override
+ public Slot withName(String name) {
+ return new SlotReference(exprId, name, dataType, nullable, qualifier,
column);
+ }
+
/** withCommonGroupingSetExpression */
public Slot withCommonGroupingSetExpression(boolean
isCommonGroupingSetExpression) {
if (!isCommonGroupingSetExpression) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCTE.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCTE.java
index c49533c662..0bdaa999f5 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCTE.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCTE.java
@@ -38,19 +38,19 @@ import java.util.Optional;
*/
public class LogicalCTE<CHILD_TYPE extends Plan> extends
LogicalUnary<CHILD_TYPE> {
- private final List<LogicalSubQueryAlias> aliasQueries;
+ private final List<LogicalSubQueryAlias<Plan>> aliasQueries;
- public LogicalCTE(List<LogicalSubQueryAlias> aliasQueries, CHILD_TYPE
child) {
+ public LogicalCTE(List<LogicalSubQueryAlias<Plan>> aliasQueries,
CHILD_TYPE child) {
this(aliasQueries, Optional.empty(), Optional.empty(), child);
}
- public LogicalCTE(List<LogicalSubQueryAlias> aliasQueries,
Optional<GroupExpression> groupExpression,
+ public LogicalCTE(List<LogicalSubQueryAlias<Plan>> aliasQueries,
Optional<GroupExpression> groupExpression,
Optional<LogicalProperties> logicalProperties,
CHILD_TYPE child) {
super(PlanType.LOGICAL_CTE, groupExpression, logicalProperties, child);
this.aliasQueries = aliasQueries;
}
- public List<LogicalSubQueryAlias> getAliasQueries() {
+ public List<LogicalSubQueryAlias<Plan>> getAliasQueries() {
return aliasQueries;
}
@@ -105,12 +105,12 @@ public class LogicalCTE<CHILD_TYPE extends Plan> extends
LogicalUnary<CHILD_TYPE
}
@Override
- public Plan withGroupExpression(Optional<GroupExpression> groupExpression)
{
+ public LogicalCTE<CHILD_TYPE>
withGroupExpression(Optional<GroupExpression> groupExpression) {
return new LogicalCTE<>(aliasQueries, groupExpression,
Optional.of(getLogicalProperties()), child());
}
@Override
- public Plan withLogicalProperties(Optional<LogicalProperties>
logicalProperties) {
+ public LogicalCTE<CHILD_TYPE>
withLogicalProperties(Optional<LogicalProperties> logicalProperties) {
return new LogicalCTE<>(aliasQueries, Optional.empty(),
logicalProperties, child());
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
index a9fe72f8d8..a02467a52f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
@@ -33,7 +33,6 @@ import org.apache.commons.lang.StringUtils;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.stream.Collectors;
/**
* The node of logical plan for sub query and alias
@@ -63,9 +62,26 @@ public class LogicalSubQueryAlias<CHILD_TYPE extends Plan>
extends LogicalUnary<
@Override
public List<Slot> computeOutput() {
- return child().getOutput().stream()
- .map(slot -> slot.withQualifier(ImmutableList.of(alias)))
- .collect(Collectors.toList());
+ List<Slot> childOutput = child().getOutput();
+ List<String> columnAliases = this.columnAliases.isPresent()
+ ? this.columnAliases.get()
+ : ImmutableList.of();
+ ImmutableList.Builder<Slot> currentOutput = ImmutableList.builder();
+ String qualifier = alias;
+ for (int i = 0; i < childOutput.size(); i++) {
+ Slot originSlot = childOutput.get(i);
+ String columnAlias;
+ if (i < columnAliases.size()) {
+ columnAlias = columnAliases.get(i);
+ } else {
+ columnAlias = originSlot.getName();
+ }
+ Slot qualified = originSlot
+ .withQualifier(ImmutableList.of(qualifier))
+ .withName(columnAlias);
+ currentOutput.add(qualified);
+ }
+ return currentOutput.build();
}
public String getAlias() {
@@ -107,14 +123,14 @@ public class LogicalSubQueryAlias<CHILD_TYPE extends
Plan> extends LogicalUnary<
}
@Override
- public Plan withChildren(List<Plan> children) {
+ public LogicalSubQueryAlias<Plan> withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 1);
- return new LogicalSubQueryAlias<>(alias, children.get(0));
+ return new LogicalSubQueryAlias<>(alias, columnAliases,
children.get(0));
}
@Override
public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
- return visitor.visitSubQueryAlias((LogicalSubQueryAlias<Plan>) this,
context);
+ return visitor.visitSubQueryAlias(this, context);
}
@Override
@@ -123,13 +139,13 @@ public class LogicalSubQueryAlias<CHILD_TYPE extends
Plan> extends LogicalUnary<
}
@Override
- public Plan withGroupExpression(Optional<GroupExpression> groupExpression)
{
+ public LogicalSubQueryAlias<CHILD_TYPE>
withGroupExpression(Optional<GroupExpression> groupExpression) {
return new LogicalSubQueryAlias<>(alias, columnAliases,
groupExpression,
Optional.of(getLogicalProperties()), child());
}
@Override
- public Plan withLogicalProperties(Optional<LogicalProperties>
logicalProperties) {
+ public LogicalSubQueryAlias<CHILD_TYPE>
withLogicalProperties(Optional<LogicalProperties> logicalProperties) {
return new LogicalSubQueryAlias<>(alias, columnAliases,
Optional.empty(),
logicalProperties, child());
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLimit.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLimit.java
index c6a3baba0e..e5bdb40dd2 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLimit.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLimit.java
@@ -142,7 +142,8 @@ public class PhysicalLimit<CHILD_TYPE extends Plan> extends
PhysicalUnary<CHILD_
public String toString() {
return Utils.toSqlString("PhysicalLimit",
"limit", limit,
- "offset", offset
+ "offset", offset,
+ "stats", statsDeriveResult
);
}
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
index cd8df03f24..9980f06086 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
@@ -93,7 +93,6 @@ import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.nereids.NereidsPlanner;
import org.apache.doris.nereids.StatementContext;
import org.apache.doris.nereids.glue.LogicalPlanAdapter;
-import org.apache.doris.nereids.rules.analysis.CTEContext;
import org.apache.doris.planner.OlapScanNode;
import org.apache.doris.planner.OriginalPlanner;
import org.apache.doris.planner.Planner;
@@ -214,7 +213,6 @@ public class StmtExecutor implements ProfileWriter {
this.statementContext.setConnectContext(ctx);
this.statementContext.setOriginStatement(originStmt);
this.statementContext.setParsedStatement(parsedStmt);
- this.statementContext.setCteContext(new CTEContext());
} else {
this.statementContext = new StatementContext(ctx, originStmt);
this.statementContext.setParsedStatement(parsedStmt);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubQueryTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubQueryTest.java
index e0a07abc2b..8d15f83607 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubQueryTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubQueryTest.java
@@ -105,11 +105,15 @@ public class AnalyzeSubQueryTest extends
TestWithFeService implements PatternMat
public void testCaseSubQuery() {
PlanChecker.from(connectContext)
.analyze(testSql.get(0))
- .applyTopDown(new EliminateAliasNode())
+ .applyTopDown(new LogicalSubQueryAliasToLogicalProject())
.matchesFromRoot(
logicalProject(
logicalProject(
- logicalOlapScan().when(o -> true)
+ logicalProject(
+ logicalProject(
+ logicalOlapScan().when(o -> true)
+ )
+ )
).when(FieldChecker.check("projects", ImmutableList.of(
new SlotReference(new ExprId(0), "id",
BigIntType.INSTANCE, true, ImmutableList.of("T")),
new SlotReference(new ExprId(1), "score",
BigIntType.INSTANCE, true, ImmutableList.of("T"))))
@@ -125,13 +129,19 @@ public class AnalyzeSubQueryTest extends
TestWithFeService implements PatternMat
public void testCaseMixed() {
PlanChecker.from(connectContext)
.analyze(testSql.get(1))
- .applyTopDown(new EliminateAliasNode())
+ .applyTopDown(new LogicalSubQueryAliasToLogicalProject())
.matchesFromRoot(
logicalProject(
logicalJoin(
- logicalOlapScan(),
logicalProject(
logicalOlapScan()
+ ),
+ logicalProject(
+ logicalProject(
+ logicalProject(
+ logicalOlapScan()
+ )
+ )
).when(FieldChecker.check("projects",
ImmutableList.of(
new SlotReference(new ExprId(0), "id",
BigIntType.INSTANCE, true, ImmutableList.of("TT2")),
new SlotReference(new ExprId(1), "score",
BigIntType.INSTANCE, true, ImmutableList.of("TT2"))))
@@ -156,12 +166,14 @@ public class AnalyzeSubQueryTest extends
TestWithFeService implements PatternMat
public void testCaseJoinSameTable() {
PlanChecker.from(connectContext)
.analyze(testSql.get(5))
- .applyTopDown(new EliminateAliasNode())
+ .applyTopDown(new LogicalSubQueryAliasToLogicalProject())
.matchesFromRoot(
logicalProject(
logicalJoin(
logicalOlapScan(),
- logicalOlapScan()
+ logicalProject(
+ logicalOlapScan()
+ )
)
.when(FieldChecker.check("joinType",
JoinType.INNER_JOIN))
.when(FieldChecker.check("otherJoinConjuncts",
ImmutableList.of(new EqualTo(
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/AnalyzeWhereSubqueryTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/AnalyzeWhereSubqueryTest.java
index 1059d9bd3c..6e59b9123d 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/AnalyzeWhereSubqueryTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/AnalyzeWhereSubqueryTest.java
@@ -30,6 +30,7 @@ import
org.apache.doris.nereids.rules.rewrite.logical.ApplyPullFilterOnAgg;
import
org.apache.doris.nereids.rules.rewrite.logical.ApplyPullFilterOnProjectUnderAgg;
import org.apache.doris.nereids.rules.rewrite.logical.ExistsApplyToJoin;
import org.apache.doris.nereids.rules.rewrite.logical.InApplyToJoin;
+import org.apache.doris.nereids.rules.rewrite.logical.MergeProjects;
import org.apache.doris.nereids.rules.rewrite.logical.PushApplyUnderFilter;
import org.apache.doris.nereids.rules.rewrite.logical.PushApplyUnderProject;
import org.apache.doris.nereids.rules.rewrite.logical.ScalarApplyToJoin;
@@ -369,27 +370,41 @@ public class AnalyzeWhereSubqueryTest extends
TestWithFeService implements Patte
// select * from t6 where t6.k1 < (select max(aa) from (select v1 as
aa from t7 where t6.k2=t7.v2) t2 )
PlanChecker.from(connectContext)
.analyze(sql10)
- .matches(
- logicalApply(
- any(),
- logicalAggregate(
- logicalProject(
+ .matchesFromRoot(
+ logicalProject(
+ logicalFilter(
+ logicalProject(
+ logicalApply(
+ any(),
+ logicalAggregate(
+ logicalSubQueryAlias(
+ logicalProject(
logicalFilter()
- ).when(FieldChecker.check("projects",
ImmutableList.of(
+ ).when(p ->
p.getProjects().equals(ImmutableList.of(
new Alias(new ExprId(7), new
SlotReference(new ExprId(5), "v1", BigIntType.INSTANCE,
true,
ImmutableList.of("default_cluster:test", "t7")), "aa")
+ )))
+ )
+ .when(a -> a.getAlias().equals("t2"))
+ .when(a ->
a.getOutput().equals(ImmutableList.of(
+ new SlotReference(new
ExprId(7), "aa", BigIntType.INSTANCE,
+ true,
ImmutableList.of("t2"))
)))
- ).when(FieldChecker.check("outputExpressions",
ImmutableList.of(
+ ).when(agg ->
agg.getOutputExpressions().equals(ImmutableList.of(
new Alias(new ExprId(8),
new Max(new SlotReference(new
ExprId(7), "aa", BigIntType.INSTANCE,
true,
ImmutableList.of("t2"))), "max(aa)")
- )))
-
.when(FieldChecker.check("groupByExpressions", ImmutableList.of()))
- ).when(FieldChecker.check("correlationSlot",
ImmutableList.of(
- new SlotReference(new ExprId(1), "k2",
BigIntType.INSTANCE, true,
-
ImmutableList.of("default_cluster:test", "t6")))))
+ )))
+ .when(agg ->
agg.getGroupByExpressions().equals(ImmutableList.of()))
+ )
+ .when(apply ->
apply.getCorrelationSlot().equals(ImmutableList.of(
+ new SlotReference(new ExprId(1), "k2",
BigIntType.INSTANCE, true,
+
ImmutableList.of("default_cluster:test", "t6")))))
+ )
+ )
+ )
);
}
@@ -397,6 +412,8 @@ public class AnalyzeWhereSubqueryTest extends
TestWithFeService implements Patte
public void testSql10AfterChangeProjectFilter() {
PlanChecker.from(connectContext)
.analyze(sql10)
+ .applyBottomUp(new LogicalSubQueryAliasToLogicalProject())
+ .applyTopDown(new MergeProjects())
.applyBottomUp(new ApplyPullFilterOnProjectUnderAgg())
.matches(
logicalApply(
@@ -427,6 +444,8 @@ public class AnalyzeWhereSubqueryTest extends
TestWithFeService implements Patte
public void testSql10AfterChangeAggFilter() {
PlanChecker.from(connectContext)
.analyze(sql10)
+ .applyBottomUp(new LogicalSubQueryAliasToLogicalProject())
+ .applyTopDown(new MergeProjects())
.applyBottomUp(new ApplyPullFilterOnProjectUnderAgg())
.applyBottomUp(new ApplyPullFilterOnAgg())
.matches(
@@ -448,9 +467,11 @@ public class AnalyzeWhereSubqueryTest extends
TestWithFeService implements Patte
}
@Test
- public void testSql10AfterScalarTOJoin() {
+ public void testSql10AfterScalarToJoin() {
PlanChecker.from(connectContext)
.analyze(sql10)
+ .applyBottomUp(new LogicalSubQueryAliasToLogicalProject())
+ .applyTopDown(new MergeProjects())
.applyBottomUp(new ApplyPullFilterOnProjectUnderAgg())
.applyBottomUp(new ApplyPullFilterOnAgg())
.applyBottomUp(new ScalarApplyToJoin())
@@ -460,13 +481,14 @@ public class AnalyzeWhereSubqueryTest extends
TestWithFeService implements Patte
logicalAggregate(
logicalProject()
)
- ).when(FieldChecker.check("joinType",
JoinType.LEFT_OUTER_JOIN))
- .when(FieldChecker.check("otherJoinConjuncts",
ImmutableList.of(
- new EqualTo(new SlotReference(new
ExprId(1), "k2", BigIntType.INSTANCE, true,
-
ImmutableList.of("default_cluster:test", "t6")),
- new SlotReference(new
ExprId(6), "v2", BigIntType.INSTANCE, true,
-
ImmutableList.of("default_cluster:test", "t7")))
- )))
+ )
+ .when(j ->
j.getJoinType().equals(JoinType.LEFT_OUTER_JOIN))
+ .when(j ->
j.getOtherJoinConjuncts().equals(ImmutableList.of(
+ new EqualTo(new SlotReference(new ExprId(1),
"k2", BigIntType.INSTANCE, true,
+
ImmutableList.of("default_cluster:test", "t6")),
+ new SlotReference(new ExprId(6), "v2",
BigIntType.INSTANCE, true,
+
ImmutableList.of("default_cluster:test", "t7")))
+ )))
);
}
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/RegisterCTETest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/RegisterCTETest.java
index d0d4692f93..ee9aa5b9e1 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/RegisterCTETest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/RegisterCTETest.java
@@ -20,8 +20,6 @@ package org.apache.doris.nereids.rules.analysis;
import org.apache.doris.common.NereidsException;
import org.apache.doris.nereids.NereidsPlanner;
import org.apache.doris.nereids.StatementContext;
-import org.apache.doris.nereids.analyzer.UnboundAlias;
-import org.apache.doris.nereids.analyzer.UnboundSlot;
import org.apache.doris.nereids.datasets.ssb.SSBUtils;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.glue.translator.PhysicalPlanTranslator;
@@ -37,7 +35,6 @@ import
org.apache.doris.nereids.rules.rewrite.logical.PushApplyUnderProject;
import org.apache.doris.nereids.trees.expressions.Alias;
import org.apache.doris.nereids.trees.expressions.EqualTo;
import org.apache.doris.nereids.trees.expressions.ExprId;
-import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.NamedExpressionUtil;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.expressions.functions.agg.Count;
@@ -60,7 +57,6 @@ import mockit.MockUp;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import java.util.ArrayList;
import java.util.List;
public class RegisterCTETest extends TestWithFeService implements
PatternMatchSupported {
@@ -111,7 +107,8 @@ public class RegisterCTETest extends TestWithFeService
implements PatternMatchSu
private CTEContext getCTEContextAfterRegisterCTE(String sql) {
return PlanChecker.from(connectContext)
.analyze(sql)
- .getCascadesContext().getStatementContext().getCteContext();
+ .getCascadesContext()
+ .getCteContext();
}
/*
********************************************************************************************
@@ -145,21 +142,17 @@ public class RegisterCTETest extends TestWithFeService
implements PatternMatchSu
Assertions.assertTrue(cteContext.containsCTE("cte1")
&& cteContext.containsCTE("cte2"));
-
- LogicalPlan cte2InitialPlan = cteContext.getInitialCTEPlan("cte2");
- PlanChecker.from(connectContext, cte2InitialPlan).matchesFromRoot(
- logicalProject(
- logicalFilter(
- logicalSubQueryAlias(
- logicalProject(
- logicalFilter(
- unboundRelation()
- )
+ LogicalPlan cte2parsedPlan = cteContext.getParsedCtePlan("cte2").get();
+ PlanChecker.from(connectContext, cte2parsedPlan)
+ .matchesFromRoot(
+ logicalSubQueryAlias(
+ logicalProject(
+ logicalFilter(
+ unboundRelation()
)
)
)
- )
- );
+ );
}
@Test
@@ -169,32 +162,31 @@ public class RegisterCTETest extends TestWithFeService
implements PatternMatchSu
Assertions.assertTrue(cteContext.containsCTE("cte1")
&& cteContext.containsCTE("cte2"));
- // check initial plan
- LogicalPlan cte1InitialPlan = cteContext.getInitialCTEPlan("cte1");
-
- List<NamedExpression> targetProjects = new ArrayList<>();
- targetProjects.add(new UnboundAlias(new UnboundSlot("s_suppkey"),
"skey"));
- targetProjects.add(new UnboundSlot("s_nation"));
-
- PlanChecker.from(connectContext, cte1InitialPlan)
- .matches(
- logicalProject(
- ).when(FieldChecker.check("projects", targetProjects))
- );
-
// check analyzed plan
- LogicalPlan cte1AnalyzedPlan = cteContext.getAnalyzedCTEPlan("cte1");
-
- targetProjects = new ArrayList<>();
- targetProjects.add(new Alias(new ExprId(7),
- new SlotReference(new ExprId(0), "s_suppkey",
VarcharType.INSTANCE,
- false, ImmutableList.of("defaulst_cluster:test", "supplier")),
"skey"));
- targetProjects.add(new SlotReference(new ExprId(4), "s_nation",
VarcharType.INSTANCE,
- false, ImmutableList.of("defaulst_cluster:test", "supplier")));
+ LogicalPlan cte1AnalyzedPlan = cteContext.getAnalyzedCTE("cte1").get();
+
PlanChecker.from(connectContext, cte1AnalyzedPlan)
- .matches(
- logicalProject(
- ).when(FieldChecker.check("projects", targetProjects))
+ .matchesFromRoot(
+ logicalSubQueryAlias(
+ logicalProject()
+ .when(p -> p.getProjects().size() == 2
+ &&
p.getProjects().get(0).getName().equals("s_suppkey")
+ && p.getProjects().get(0).getExprId().asInt()
== 14
+ &&
p.getProjects().get(0).getQualifier().equals(ImmutableList.of("default_cluster:test",
"supplier"))
+ &&
p.getProjects().get(1).getName().equals("s_nation")
+ && p.getProjects().get(1).getExprId().asInt()
== 18
+ &&
p.getProjects().get(1).getQualifier().equals(ImmutableList.of("default_cluster:test",
"supplier"))
+ )
+ )
+ .when(a -> a.getAlias().equals("cte1"))
+ .when(a -> a.getOutput().size() == 2
+ && a.getOutput().get(0).getName().equals("skey")
+ && a.getOutput().get(0).getExprId().asInt() == 14
+ &&
a.getOutput().get(0).getQualifier().equals(ImmutableList.of("cte1"))
+ &&
a.getOutput().get(1).getName().equals("s_nation")
+ && a.getOutput().get(1).getExprId().asInt() == 18
+ &&
a.getOutput().get(1).getQualifier().equals(ImmutableList.of("cte1"))
+ )
);
}
@@ -230,45 +222,52 @@ public class RegisterCTETest extends TestWithFeService
implements PatternMatchSu
@Test
public void testCTEWithAlias() {
- SlotReference skInCTE1 = new SlotReference(new ExprId(7), "sk",
IntegerType.INSTANCE,
+ SlotReference skInCTE1 = new SlotReference(new ExprId(15), "sk",
IntegerType.INSTANCE,
false, ImmutableList.of("cte1"));
- SlotReference skInCTE2 = new SlotReference(new ExprId(15), "sk",
IntegerType.INSTANCE,
+ SlotReference skInCTE2 = new SlotReference(new ExprId(7), "sk",
IntegerType.INSTANCE,
false, ImmutableList.of("cte2"));
- Alias skAlias = new Alias(new ExprId(7),
- new SlotReference(new ExprId(0), "s_suppkey",
IntegerType.INSTANCE,
- false, ImmutableList.of("default_cluster:test",
"supplier")), "sk");
+ Alias skAlias = new Alias(new ExprId(15),
+ new SlotReference(new ExprId(8), "sk", IntegerType.INSTANCE,
+ false, ImmutableList.of("default_cluster:test", "supplier")),
"sk");
+
PlanChecker.from(connectContext)
.analyze(sql4)
- .matches(
+ .matchesFromRoot(
logicalProject(
logicalJoin(
-
logicalProject().when(FieldChecker.check("projects",
ImmutableList.of(skAlias))),
-
logicalProject().when(FieldChecker.check("projects",
ImmutableList.of(skInCTE2)))
+ logicalSubQueryAlias(
+ logicalProject().when(p ->
p.getProjects().equals(ImmutableList.of(skAlias)))
+ ).when(a -> a.getAlias().equals("cte1")),
+ logicalSubQueryAlias(
+ logicalProject().when(p ->
p.getProjects().equals(ImmutableList.of(skInCTE2)))
+ ).when(a -> a.getAlias().equals("cte2"))
).when(FieldChecker.check("joinType",
JoinType.INNER_JOIN))
- .when(FieldChecker.check("otherJoinConjuncts",
ImmutableList.of(
- new EqualTo(skInCTE1, skInCTE2)
- )))
- ).when(FieldChecker.check("projects",
ImmutableList.of(skInCTE1, skInCTE2)))
+ .when(j ->
j.getOtherJoinConjuncts().equals(ImmutableList.of(new EqualTo(skInCTE1,
skInCTE2))))
+ ).when(p ->
p.getProjects().equals(ImmutableList.of(skInCTE1, skInCTE2)))
);
}
@Test
public void testCTEWithAnExistedTableOrViewName() {
- SlotReference suppkeyInV1 = new SlotReference(new ExprId(7),
"s_suppkey", IntegerType.INSTANCE,
+ SlotReference suppkeyInV1 = new SlotReference(new ExprId(0),
"s_suppkey", IntegerType.INSTANCE,
false, ImmutableList.of("V1"));
- SlotReference suppkeyInV2 = new SlotReference(new ExprId(7),
"s_suppkey", IntegerType.INSTANCE,
+ SlotReference suppkeyInV2 = new SlotReference(new ExprId(0),
"s_suppkey", IntegerType.INSTANCE,
false, ImmutableList.of("V2"));
- SlotReference suppkeyInSupplier = new SlotReference(new ExprId(7),
"s_suppkey", IntegerType.INSTANCE,
+ SlotReference suppkeyInSupplier = new SlotReference(new ExprId(0),
"s_suppkey", IntegerType.INSTANCE,
false, ImmutableList.of("default_cluster:test", "supplier"));
PlanChecker.from(connectContext)
.analyze(sql5)
- .matches(
+ .matchesFromRoot(
logicalProject(
- logicalProject(
- logicalProject()
- .when(FieldChecker.check("projects",
ImmutableList.of(suppkeyInSupplier)))
- ).when(FieldChecker.check("projects",
ImmutableList.of(suppkeyInV1)))
- ).when(FieldChecker.check("projects",
ImmutableList.of(suppkeyInV2)))
+ logicalSubQueryAlias(
+ logicalProject(
+ logicalSubQueryAlias(
+ logicalProject()
+ .when(p ->
p.getProjects().equals(ImmutableList.of(suppkeyInSupplier)))
+ ).when(a -> a.getAlias().equals("V1"))
+ ).when(p ->
p.getProjects().equals(ImmutableList.of(suppkeyInV1)))
+ ).when(a -> a.getAlias().equals("V2"))
+ ).when(p ->
p.getProjects().equals(ImmutableList.of(suppkeyInV2)))
);
}
@@ -337,4 +336,30 @@ public class RegisterCTETest extends TestWithFeService
implements PatternMatchSu
}, "Not throw expected exception.");
Assertions.assertTrue(exception.getMessage().contains("[cte1] cannot
be used more than once"));
}
+
+ @Test
+ public void testDifferenceRelationId() {
+ PlanChecker.from(connectContext)
+ .analyze("with s as (select * from supplier) select * from s
as s1, s as s2")
+ .matchesFromRoot(
+ logicalProject(
+ logicalJoin(
+ logicalSubQueryAlias(// as s1
+ logicalSubQueryAlias(// as s
+ logicalProject(// select * from supplier
+ logicalOlapScan().when(scan ->
scan.getId().asInt() == 0)
+ )
+ ).when(a -> a.getAlias().equals("s"))
+ ).when(a -> a.getAlias().equals("s1")),
+ logicalSubQueryAlias(
+ logicalSubQueryAlias(
+ logicalProject(
+ logicalOlapScan().when(scan ->
scan.getId().asInt() == 1)
+ )
+ ).when(a -> a.getAlias().equals("s"))
+ ).when(a -> a.getAlias().equals("s2"))
+ )
+ )
+ );
+ }
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/mv/SelectRollupIndexTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/mv/SelectRollupIndexTest.java
index 091d39013c..6eb5f30160 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/mv/SelectRollupIndexTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/mv/SelectRollupIndexTest.java
@@ -18,6 +18,8 @@
package org.apache.doris.nereids.rules.mv;
import org.apache.doris.common.FeConstants;
+import
org.apache.doris.nereids.rules.analysis.LogicalSubQueryAliasToLogicalProject;
+import org.apache.doris.nereids.rules.rewrite.logical.MergeProjects;
import org.apache.doris.nereids.trees.plans.PreAggStatus;
import org.apache.doris.nereids.util.PatternMatchSupported;
import org.apache.doris.nereids.util.PlanChecker;
@@ -182,6 +184,8 @@ class SelectRollupIndexTest extends
BaseMaterializedIndexSelectTest implements P
+ " where c3>0 group by c2";
PlanChecker.from(connectContext)
.analyze(sql)
+ .applyBottomUp(new LogicalSubQueryAliasToLogicalProject())
+ .applyTopDown(new MergeProjects())
.applyTopDown(new SelectMaterializedIndexWithAggregate())
.applyTopDown(new SelectMaterializedIndexWithoutAggregate())
.matches(logicalOlapScan().when(scan -> {
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownExpressionsInHashConditionTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownExpressionsInHashConditionTest.java
index f6735c4f4c..9b1c9b564a 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownExpressionsInHashConditionTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownExpressionsInHashConditionTest.java
@@ -106,21 +106,25 @@ public class PushdownExpressionsInHashConditionTest
extends TestWithFeService im
"SELECT * FROM (SELECT * FROM T1) X JOIN (SELECT *
FROM T2) Y ON X.ID + 1 = Y.ID + 2 AND X.ID + 1 > 2")
.applyTopDown(new FindHashConditionForJoin())
.applyTopDown(new PushdownExpressionsInHashCondition())
- .matches(
- logicalProject(
- logicalJoin(
- logicalProject(
- logicalProject(
- logicalOlapScan()
- )
- ),
- logicalProject(
- logicalProject(
- logicalOlapScan()
- )
- )
+ .matchesFromRoot(
+ logicalProject(
+ logicalJoin(
+ logicalProject(
+ logicalSubQueryAlias(
+ logicalProject(
+ logicalOlapScan()
+ )
+ )
+ ),
+ logicalProject(
+ logicalSubQueryAlias(
+ logicalProject(
+ logicalOlapScan()
+ )
)
+ )
)
+ )
);
}
@@ -131,19 +135,21 @@ public class PushdownExpressionsInHashConditionTest
extends TestWithFeService im
"SELECT * FROM T1 JOIN (SELECT ID, SUM(SCORE) SCORE
FROM T2 GROUP BY ID) T ON T1.ID + 1 = T.ID AND T.SCORE = T1.SCORE + 10")
.applyTopDown(new FindHashConditionForJoin())
.applyTopDown(new PushdownExpressionsInHashCondition())
- .matches(
- logicalProject(
- logicalJoin(
- logicalProject(
- logicalOlapScan()
- ),
- logicalProject(
- logicalAggregate(
- logicalOlapScan()
- )
- )
+ .matchesFromRoot(
+ logicalProject(
+ logicalJoin(
+ logicalProject(
+ logicalOlapScan()
+ ),
+ logicalProject(
+ logicalSubQueryAlias(
+ logicalAggregate(
+ logicalOlapScan()
+ )
)
+ )
)
+ )
);
}
@@ -154,21 +160,23 @@ public class PushdownExpressionsInHashConditionTest
extends TestWithFeService im
"SELECT * FROM T1 JOIN (SELECT ID, SUM(SCORE) SCORE
FROM T2 GROUP BY ID ORDER BY ID) T ON T1.ID + 1 = T.ID AND T.SCORE = T1.SCORE +
10")
.applyTopDown(new FindHashConditionForJoin())
.applyTopDown(new PushdownExpressionsInHashCondition())
- .matches(
- logicalProject(
- logicalJoin(
- logicalProject(
+ .matchesFromRoot(
+ logicalProject(
+ logicalJoin(
+ logicalProject(
+ logicalOlapScan()
+ ),
+ logicalProject(
+ logicalSubQueryAlias(
+ logicalSort(
+ logicalAggregate(
logicalOlapScan()
- ),
- logicalProject(
- logicalSort(
- logicalAggregate(
-
logicalOlapScan()
- )
- )
)
+ )
)
+ )
)
+ )
);
}
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ViewTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ViewTest.java
index d1c7fcb452..4a72965010 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ViewTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ViewTest.java
@@ -23,7 +23,7 @@ import
org.apache.doris.nereids.glue.translator.PhysicalPlanTranslator;
import org.apache.doris.nereids.glue.translator.PlanTranslatorContext;
import org.apache.doris.nereids.parser.NereidsParser;
import org.apache.doris.nereids.properties.PhysicalProperties;
-import org.apache.doris.nereids.rules.analysis.EliminateAliasNode;
+import
org.apache.doris.nereids.rules.analysis.LogicalSubQueryAliasToLogicalProject;
import org.apache.doris.nereids.rules.rewrite.logical.MergeProjects;
import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan;
import org.apache.doris.nereids.util.MemoTestUtils;
@@ -113,7 +113,7 @@ public class ViewTest extends TestWithFeService implements
PatternMatchSupported
public void testSimpleViewMergeProjects() {
PlanChecker.from(connectContext)
.analyze("SELECT * FROM V1")
- .applyTopDown(new EliminateAliasNode())
+ .applyTopDown(new LogicalSubQueryAliasToLogicalProject())
.applyTopDown(new MergeProjects())
.matchesFromRoot(
logicalProject(
@@ -140,7 +140,7 @@ public class ViewTest extends TestWithFeService implements
PatternMatchSupported
+ ") Y\n"
+ "ON X.ID1 = Y.ID3"
)
- .applyTopDown(new EliminateAliasNode())
+ .applyTopDown(new LogicalSubQueryAliasToLogicalProject())
.applyTopDown(new MergeProjects())
.matchesFromRoot(
logicalProject(
diff --git a/regression-test/data/nereids_syntax_p0/cte.out
b/regression-test/data/nereids_syntax_p0/cte.out
index 2aa6d04c5c..e9a1795428 100644
--- a/regression-test/data/nereids_syntax_p0/cte.out
+++ b/regression-test/data/nereids_syntax_p0/cte.out
@@ -1,13 +1,13 @@
-- This file is automatically generated. You should know what you did if you
want to edit this
-- !cte_1 --
15 15
-15 15
-15 15
-29 29
-29 29
+15 29
+15 9
+29 15
29 29
-9 9
-9 9
+29 9
+9 15
+9 29
9 9
-- !cte_2 --
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]