[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:
morrySnow
2023-10-25 18:52:14 +08:00
committed by GitHub
parent e8f479882d
commit 01d5901356
4 changed files with 87 additions and 16 deletions

View File

@ -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.
*/

View File

@ -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());