This is an automated email from the ASF dual-hosted git repository.

huajianlan pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.0 by this push:
     new bd7446244dd [fix](Nereids) fix bind having aggregate failed again 
(#33148)
bd7446244dd is described below

commit bd7446244ddc521ef67faa4bd502fdf6f0a61338
Author: 924060929 <[email protected]>
AuthorDate: Tue Apr 2 21:58:15 2024 +0800

    [fix](Nereids) fix bind having aggregate failed again (#33148)
    
    cherry from #32490 and #32687
---
 .../nereids/rules/analysis/BindExpression.java     | 83 ++++++++++++++++++----
 .../doris/nereids/rules/analysis/SlotBinder.java   | 11 +++
 .../data/nereids_syntax_p0/bind_priority.out       | 23 ++++++
 .../suites/nereids_syntax_p0/bind_priority.groovy  | 80 +++++++++++++++++++++
 4 files changed, 185 insertions(+), 12 deletions(-)

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 aa44674cf98..e0f0d1baa78 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
@@ -497,21 +497,75 @@ public class BindExpression implements 
AnalysisRuleFactory {
                         }
                     }
                     List<Slot> groupBySlots = groupBySlotsBuilder.build();
+                    SlotBinder bindByGroupBy = new 
SlotBinder(toScope(ctx.cascadesContext, groupBySlots),
+                            ctx.cascadesContext, false, false, true
+                    );
+                    Scope aggOuputScope = toScope(ctx.cascadesContext, 
childPlan.getOutput());
+                    SlotBinder bindByAggOutput = new SlotBinder(
+                            aggOuputScope,
+                            ctx.cascadesContext, false, true, true
+                    );
+                    SlotBinder bindByAggChild = new SlotBinder(
+                            toScope(ctx.cascadesContext, 
childPlan.child().getOutput()),
+                            ctx.cascadesContext, false, true, true
+                    );
+
+                    SubExprAnalyzer bindSlot = new SubExprAnalyzer(
+                            aggOuputScope, ctx.cascadesContext) {
+                        private boolean currentIsInAggregateFunction;
+
+                        @Override
+                        public Expression visitAggregateFunction(
+                                AggregateFunction aggregateFunction, 
CascadesContext context) {
+                            if (!currentIsInAggregateFunction) {
+                                currentIsInAggregateFunction = true;
+                                try {
+                                    return 
super.visitAggregateFunction(aggregateFunction, context);
+                                } finally {
+                                    currentIsInAggregateFunction = false;
+                                }
+                            } else {
+                                return 
super.visitAggregateFunction(aggregateFunction, context);
+                            }
+                        }
 
-                    Set<Expression> boundConjuncts = 
having.getConjuncts().stream()
-                            .map(expr -> {
-                                if (hasAggregateFunction(expr, 
functionRegistry)) {
-                                    expr = bindSlot(expr, childPlan.child(), 
ctx.cascadesContext, false);
-                                } else {
-                                    expr = new 
SlotBinder(toScope(ctx.cascadesContext, groupBySlots),
-                                            ctx.cascadesContext, false, false
-                                    ).bind(expr);
+                        @Override
+                        public Expression visitUnboundFunction(
+                                UnboundFunction unboundFunction, 
CascadesContext context) {
+                            if (!currentIsInAggregateFunction
+                                    && isAggregateFunction(unboundFunction, 
functionRegistry)) {
+                                currentIsInAggregateFunction = true;
+                                try {
+                                    return 
super.visitUnboundFunction(unboundFunction, context);
+                                } finally {
+                                    currentIsInAggregateFunction = false;
+                                }
+                            } else {
+                                return 
super.visitUnboundFunction(unboundFunction, context);
+                            }
+                        }
 
-                                    expr = bindSlot(expr, childPlan, 
ctx.cascadesContext, false);
-                                    expr = bindSlot(expr, 
childPlan.children(), ctx.cascadesContext, false);
+                        @Override
+                        public Expression visitUnboundSlot(UnboundSlot 
unboundSlot, CascadesContext context) {
+                            if (currentIsInAggregateFunction) {
+                                // bind by agg child
+                                return bindSlot(unboundSlot, 
childPlan.child(), ctx.cascadesContext, false);
+                            } else {
+                                Expression expr = 
bindByGroupBy.bind(unboundSlot);
+                                if (expr instanceof SlotReference) {
+                                    return expr;
                                 }
-                                return expr;
-                            })
+                                expr = bindByAggOutput.bind(expr);
+                                if (expr instanceof SlotReference) {
+                                    return expr;
+                                }
+                                return bindByAggChild.bind(expr);
+                            }
+                        }
+                    };
+
+                    Set<Expression> boundConjuncts = 
having.getConjuncts().stream()
+                            .map(slot -> slot.accept(bindSlot, null))
                             .map(expr -> bindFunction(expr, ctx.root, 
ctx.cascadesContext))
                             .map(expr -> 
TypeCoercionUtils.castIfNotSameType(expr, BooleanType.INSTANCE))
                             .collect(Collectors.toSet());
@@ -847,6 +901,11 @@ public class BindExpression implements AnalysisRuleFactory 
{
         return expression;
     }
 
+    private boolean isAggregateFunction(UnboundFunction unboundFunction, 
FunctionRegistry functionRegistry) {
+        return functionRegistry.isAggregateFunction(
+                unboundFunction.getDbName(), unboundFunction.getName());
+    }
+
     private boolean hasAggregateFunction(Expression expression, 
FunctionRegistry functionRegistry) {
         return expression.anyMatch(expr -> {
             if (expr instanceof AggregateFunction) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SlotBinder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SlotBinder.java
index 99d55423689..e1cbb7760c4 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SlotBinder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SlotBinder.java
@@ -69,6 +69,7 @@ public class SlotBinder extends SubExprAnalyzer {
      */
     private final boolean enableExactMatch;
     private final boolean bindSlotInOuterScope;
+    private final boolean findFirst;
 
     public SlotBinder(Scope scope, CascadesContext cascadesContext) {
         this(scope, cascadesContext, true, true);
@@ -76,9 +77,16 @@ public class SlotBinder extends SubExprAnalyzer {
 
     public SlotBinder(Scope scope, CascadesContext cascadesContext,
             boolean enableExactMatch, boolean bindSlotInOuterScope) {
+        this(scope, cascadesContext, enableExactMatch, bindSlotInOuterScope, 
false);
+    }
+
+    public SlotBinder(Scope scope, CascadesContext cascadesContext,
+            boolean enableExactMatch, boolean bindSlotInOuterScope,
+            boolean findFirst) {
         super(scope, cascadesContext);
         this.enableExactMatch = enableExactMatch;
         this.bindSlotInOuterScope = bindSlotInOuterScope;
+        this.findFirst = findFirst;
     }
 
     public Expression bind(Expression expression) {
@@ -169,6 +177,9 @@ public class SlotBinder extends SubExprAnalyzer {
                         return exactMatch.get(0);
                     }
                 }
+                if (findFirst) {
+                    return bounded.get(0);
+                }
                 throw new AnalysisException(String.format("%s is ambiguous: 
%s.",
                         unboundSlot.toSql(),
                         bounded.stream()
diff --git a/regression-test/data/nereids_syntax_p0/bind_priority.out 
b/regression-test/data/nereids_syntax_p0/bind_priority.out
index b3bc666c23d..32619942eed 100644
--- a/regression-test/data/nereids_syntax_p0/bind_priority.out
+++ b/regression-test/data/nereids_syntax_p0/bind_priority.out
@@ -61,3 +61,26 @@ all  2
 -- !having_bind_child5 --
 2      11
 
+-- !having_bind_agg_fun --
+
+-- !having_bind_agg_fun --
+2      4
+3      3
+
+-- !having_bind_group_by --
+7      3
+
+-- !having_bind_group_by --
+7      3
+
+-- !having_bind_group_by --
+7      3
+
+-- !having_bind_group_by --
+4      5       3
+
+-- !having_bind_group_by --
+1      2
+
+-- !having_bind_group_by --
+2      1
diff --git a/regression-test/suites/nereids_syntax_p0/bind_priority.groovy 
b/regression-test/suites/nereids_syntax_p0/bind_priority.groovy
index 0e02f01a18b..c60cce38678 100644
--- a/regression-test/suites/nereids_syntax_p0/bind_priority.groovy
+++ b/regression-test/suites/nereids_syntax_p0/bind_priority.groovy
@@ -229,5 +229,85 @@ suite("bind_priority") {
             group by id
             having sum(age + 1) = 11 -- bind age from s
             """
+
+
+
+
+        sql "drop table if exists test_bind_having_slots2"
+        sql """create table test_bind_having_slots2
+                (id int)
+                distributed by hash(id)
+                properties('replication_num'='1');
+                """
+        sql "insert into test_bind_having_slots2 values(1), (2), (3), (2);"
+
+        order_qt_having_bind_agg_fun """
+               select id, abs(sum(id)) as id
+                from test_bind_having_slots2
+                group by id
+                having sum(id) + id  >= 7
+                """
+
+        order_qt_having_bind_agg_fun """
+               select id, abs(sum(id)) as id
+                from test_bind_having_slots2
+                group by id
+                having sum(id) + id  >= 6
+                """
+
+
+
+
+
+        sql "drop table if exists test_bind_having_slots3"
+
+        sql """CREATE TABLE `test_bind_having_slots3`(pk int, pk2 int)
+                    DUPLICATE KEY(`pk`)
+                    DISTRIBUTED BY HASH(`pk`) BUCKETS 10
+                    properties('replication_num'='1');
+                    """
+        sql "insert into test_bind_having_slots3 values(1, 1), (2, 2), (2, 2), 
(3, 3), (3, 3), (3, 3);"
+
+        order_qt_having_bind_group_by """
+                SELECT pk + 6 as ps, COUNT(pk )  *  3 as pk
+                FROM test_bind_having_slots3  tbl_alias1
+                GROUP by pk
+                HAVING  pk = 1
+                """
+
+        order_qt_having_bind_group_by """
+                SELECT pk + 6 as pk, COUNT(pk )  *  3 as pk
+                FROM test_bind_having_slots3  tbl_alias1
+                GROUP by pk + 6
+                HAVING  pk = 7
+                """
+
+        order_qt_having_bind_group_by """
+                SELECT pk + 6, COUNT(pk )  *  3 as pk
+                FROM test_bind_having_slots3  tbl_alias1
+                GROUP by pk + 6
+                HAVING  pk = 3
+                """
+
+        order_qt_having_bind_group_by """
+                select pk + 1 as pk, pk + 2 as pk, count(*)
+                from test_bind_having_slots3
+                group by pk + 1, pk + 2
+                having pk = 4;
+                """
+
+        order_qt_having_bind_group_by """
+                select count(*) pk, pk + 1 as pk
+                from test_bind_having_slots3
+                group by pk + 1, pk + 2
+                having pk = 1;
+                """
+
+        order_qt_having_bind_group_by """
+                select pk + 1 as pk, count(*) pk
+                from test_bind_having_slots3
+                group by pk + 1, pk + 2
+                having pk = 2;
+                """
     }()
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to