[fix](Nereids) cte should support nested name reuse (#25858)
for example: ```sql with a as (with a as (select * from t) select * from a) select * from a; with a as (select * from t1), b as (with a as (select * from a) select * from a) select * from b; ```
This commit is contained in:
@ -60,7 +60,8 @@ public class CTEContext {
|
||||
: ImmutableMap.<String, CTEContext>builder()
|
||||
.putAll(previousCteContext.cteContextMap)
|
||||
.put(name, this)
|
||||
.build();
|
||||
// if inner name same with outer name, use inner name in this scope.
|
||||
.buildKeepingLast();
|
||||
this.cteId = cteId;
|
||||
}
|
||||
|
||||
@ -68,13 +69,6 @@ public class CTEContext {
|
||||
this.analyzedPlan = analyzedPlan;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if cteName can be found in current order
|
||||
*/
|
||||
public boolean containsCTE(String cteName) {
|
||||
return findCTEContext(cteName).isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get for CTE reuse.
|
||||
*/
|
||||
|
||||
@ -34,11 +34,13 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Register CTE, includes checking columnAliases, checking CTE name, analyzing each CTE and store the
|
||||
@ -53,6 +55,18 @@ public class AnalyzeCTE extends OneAnalysisRuleFactory {
|
||||
return logicalCTE().thenApply(ctx -> {
|
||||
LogicalCTE<Plan> logicalCTE = ctx.root;
|
||||
|
||||
// step 0. check duplicate cte name
|
||||
Set<String> uniqueAlias = Sets.newHashSet();
|
||||
List<String> aliases = logicalCTE.getAliasQueries().stream()
|
||||
.map(LogicalSubQueryAlias::getAlias)
|
||||
.collect(Collectors.toList());
|
||||
for (String alias : aliases) {
|
||||
if (uniqueAlias.contains(alias)) {
|
||||
throw new AnalysisException("CTE name [" + alias + "] cannot be used more than once.");
|
||||
}
|
||||
uniqueAlias.add(alias);
|
||||
}
|
||||
|
||||
// step 1. analyzed all cte plan
|
||||
Pair<CTEContext, List<LogicalCTEProducer<Plan>>> result = analyzeCte(logicalCTE, ctx.cascadesContext);
|
||||
CascadesContext outerCascadesCtx = CascadesContext.newContextWithCteContext(
|
||||
@ -76,17 +90,10 @@ public class AnalyzeCTE extends OneAnalysisRuleFactory {
|
||||
List<LogicalSubQueryAlias<Plan>> aliasQueries = logicalCTE.getAliasQueries();
|
||||
List<LogicalCTEProducer<Plan>> cteProducerPlans = new ArrayList<>();
|
||||
for (LogicalSubQueryAlias<Plan> aliasQuery : aliasQueries) {
|
||||
String cteName = aliasQuery.getAlias();
|
||||
if (outerCteCtx.containsCTE(cteName)) {
|
||||
throw new AnalysisException("CTE name [" + cteName + "] cannot be used more than once.");
|
||||
}
|
||||
|
||||
// we should use a chain to ensure visible of cte
|
||||
CTEContext innerCteCtx = outerCteCtx;
|
||||
|
||||
LogicalPlan parsedCtePlan = (LogicalPlan) aliasQuery.child();
|
||||
CascadesContext innerCascadesCtx = CascadesContext.newContextWithCteContext(
|
||||
cascadesContext, parsedCtePlan, innerCteCtx);
|
||||
cascadesContext, parsedCtePlan, outerCteCtx);
|
||||
innerCascadesCtx.newAnalyzer().analyze();
|
||||
LogicalPlan analyzedCtePlan = (LogicalPlan) innerCascadesCtx.getRewritePlan();
|
||||
checkColumnAlias(aliasQuery, analyzedCtePlan.getOutput());
|
||||
|
||||
Reference in New Issue
Block a user