diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java index 0437f7cdcdac3f..83b0eb1ea7924e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java @@ -292,10 +292,22 @@ protected boolean condition(Rule rule, Plan plan) { 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 boundedGroupByExpressions = Sets.newHashSet(); List replacedGroupBy = agg.getGroupByExpressions().stream() .map(groupBy -> { if (groupBy instanceof UnboundSlot) { @@ -303,7 +315,9 @@ protected boolean condition(Rule rule, Plan plan) { 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 @@ protected boolean condition(Rule rule, Plan plan) { List 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); diff --git a/regression-test/suites/nereids_syntax_p0/analyze_agg.groovy b/regression-test/suites/nereids_syntax_p0/analyze_agg.groovy index 9f426e23e3d133..9a79df6bad524b 100644 --- a/regression-test/suites/nereids_syntax_p0/analyze_agg.groovy +++ b/regression-test/suites/nereids_syntax_p0/analyze_agg.groovy @@ -77,4 +77,15 @@ suite("analyze_agg") { // should not bind g /g in group by again, otherwise will throw exception sql "select g / g as nu, sum(c) from t2 group by nu" + sql """ + select + 1, + id / (select max(id) from t2) as 'x', + count(distinct c) as 'y' + from + t2 + group by + 1, + x + """ } \ No newline at end of file