[fix](Nereids) make agg output unchanged after normalized (#23499)

The normalizedAgg rule can change the output of agg.

For example:
```
select c1 as c, c1 from t having c1 > 0
```
The normalizedAgg rule will make a plan with output c, which can cause the having filter error

Therefore, the output exprId should be unchanged after normalized
This commit is contained in:
谢健
2023-08-29 15:01:26 +08:00
committed by GitHub
parent 993659cd0b
commit 598dc6960a
4 changed files with 45 additions and 20 deletions

View File

@ -33,6 +33,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@ -185,24 +186,6 @@ public class NormalizeAggregate extends OneRewriteRuleFactory implements Normali
bottomProjects.addAll(aggInputSlots);
// build group by exprs
List<Expression> normalizedGroupExprs = groupByToSlotContext.normalizeToUseSlotRef(groupingByExprs);
// build upper project, use two context to do pop up, because agg output maybe contain two part:
// group by keys and agg expressions
List<NamedExpression> upperProjects = groupByToSlotContext
.normalizeToUseSlotRefWithoutWindowFunction(aggregateOutput);
upperProjects = normalizedAggFuncsToSlotContext.normalizeToUseSlotRefWithoutWindowFunction(upperProjects);
// process Expression like Alias(SlotReference#0)#0
upperProjects = upperProjects.stream().map(e -> {
if (e instanceof Alias) {
Alias alias = (Alias) e;
if (alias.child() instanceof SlotReference) {
SlotReference slotReference = (SlotReference) alias.child();
if (slotReference.getExprId().equals(alias.getExprId())) {
return slotReference;
}
}
}
return e;
}).collect(Collectors.toList());
Plan bottomPlan;
if (!bottomProjects.isEmpty()) {
@ -211,11 +194,41 @@ public class NormalizeAggregate extends OneRewriteRuleFactory implements Normali
bottomPlan = aggregate.child();
}
List<NamedExpression> upperProjects = normalizeOutput(aggregateOutput,
groupByToSlotContext, normalizedAggFuncsToSlotContext);
return new LogicalProject<>(upperProjects,
aggregate.withNormalized(normalizedGroupExprs, normalizedAggOutput, bottomPlan));
}).toRule(RuleType.NORMALIZE_AGGREGATE);
}
private List<NamedExpression> normalizeOutput(List<NamedExpression> aggregateOutput,
NormalizeToSlotContext groupByToSlotContext, NormalizeToSlotContext normalizedAggFuncsToSlotContext) {
// build upper project, use two context to do pop up, because agg output maybe contain two part:
// group by keys and agg expressions
List<NamedExpression> upperProjects = groupByToSlotContext
.normalizeToUseSlotRefWithoutWindowFunction(aggregateOutput);
upperProjects = normalizedAggFuncsToSlotContext.normalizeToUseSlotRefWithoutWindowFunction(upperProjects);
Builder<NamedExpression> builder = new ImmutableList.Builder<>();
for (int i = 0; i < aggregateOutput.size(); i++) {
NamedExpression e = upperProjects.get(i);
// process Expression like Alias(SlotReference#0)#0
if (e instanceof Alias && e.child(0) instanceof SlotReference) {
SlotReference slotReference = (SlotReference) e.child(0);
if (slotReference.getExprId().equals(e.getExprId())) {
e = slotReference;
}
}
// Make the output ExprId unchanged
if (!e.getExprId().equals(aggregateOutput.get(i).getExprId())) {
e = new Alias(aggregateOutput.get(i).getExprId(), e, aggregateOutput.get(i).getName());
}
builder.add(e);
}
return builder.build();
}
private static class CollectNonWindowedAggFuncs extends DefaultExpressionVisitor<Void, List<AggregateFunction>> {
private static final CollectNonWindowedAggFuncs INSTANCE = new CollectNonWindowedAggFuncs();

View File

@ -91,7 +91,16 @@ public class CaseWhen extends Expression {
@Override
public String toString() {
return toSql();
StringBuilder output = new StringBuilder("CASE");
for (Expression child : children()) {
if (child instanceof WhenClause) {
output.append(child);
} else {
output.append(" ELSE ").append(child.toString());
}
}
output.append(" END");
return output.toString();
}
@Override

View File

@ -111,6 +111,6 @@ public class WhenClause extends Expression implements BinaryExpression, ExpectsI
@Override
public String toString() {
return toSql();
return " WHEN " + left().toString() + " THEN " + right().toString();
}
}