[fix](nereids)group by expr may be bound twice in bind agg slot (#28771)

This commit is contained in:
starocean999
2023-12-25 11:23:44 +08:00
committed by GitHub
parent c53611dcb3
commit 48f8f8f2ad
2 changed files with 41 additions and 8 deletions

View File

@ -292,10 +292,22 @@ public class BindExpression implements AnalysisRuleFactory {
if (alias.child().anyMatch(expr -> expr instanceof AggregateFunction)) {
continue;
}
// NOTICE: must use unbound expressions, because we will bind them in binding group by expr.
childOutputsToExpr.putIfAbsent(alias.getName(), agg.getOutputExpressions().get(i).child(0));
/*
Alias(x) has been bound by binding agg's output
we add x to childOutputsToExpr, so when binding group by exprs later, we can use x directly
and won't bind it again
select
p_cycle_time / (select max(p_cycle_time) from log_event_8) as 'x',
count(distinct case_id) as 'y'
from
log_event_8
group by
x
*/
childOutputsToExpr.putIfAbsent(alias.getName(), output.get(i).child(0));
}
Set<Expression> boundedGroupByExpressions = Sets.newHashSet();
List<Expression> replacedGroupBy = agg.getGroupByExpressions().stream()
.map(groupBy -> {
if (groupBy instanceof UnboundSlot) {
@ -303,7 +315,9 @@ public class BindExpression implements AnalysisRuleFactory {
if (unboundSlot.getNameParts().size() == 1) {
String name = unboundSlot.getNameParts().get(0);
if (childOutputsToExpr.containsKey(name)) {
return childOutputsToExpr.get(name);
Expression expression = childOutputsToExpr.get(name);
boundedGroupByExpressions.add(expression);
return expression;
}
}
}
@ -336,16 +350,24 @@ public class BindExpression implements AnalysisRuleFactory {
List<Expression> groupBy = replacedGroupBy.stream()
.map(expression -> {
Expression e = binder.bind(expression);
if (e instanceof UnboundSlot) {
return childBinder.bind(e);
if (boundedGroupByExpressions.contains(expression)) {
// expr has been bound by binding agg's output
return expression;
} else {
// bind slot for unbound exprs
Expression e = binder.bind(expression);
if (e instanceof UnboundSlot) {
return childBinder.bind(e);
}
return e;
}
return e;
})
.collect(Collectors.toList());
groupBy.forEach(expression -> checkBoundExceptLambda(expression, ctx.root));
groupBy = groupBy.stream()
.map(expr -> bindFunction(expr, ctx.root, ctx.cascadesContext))
// bind function for unbound exprs or return old expr if it's bound by binding agg's output
.map(expr -> boundedGroupByExpressions.contains(expr) ? expr
: bindFunction(expr, ctx.root, ctx.cascadesContext))
.collect(ImmutableList.toImmutableList());
checkIfOutputAliasNameDuplicatedForGroupBy(groupBy, output);
return agg.withGroupByAndOutput(groupBy, output);