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

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


The following commit(s) were added to refs/heads/master by this push:
     new 2af831de33 [Fix](Nereids)fix group by binding error, resulting in 
incorrect results (#15328)
2af831de33 is described below

commit 2af831de335bd0ffc7d18d4b8d9bed43addd2b5b
Author: zhengshiJ <32082872+zhengs...@users.noreply.github.com>
AuthorDate: Wed Dec 28 10:42:21 2022 +0800

    [Fix](Nereids)fix group by binding error, resulting in incorrect results 
(#15328)
    
    Original: group by is bound to the outputExpression of the current node.
    
    Problem: When the name of the new reference of outputExpression is the same 
as the child's output column, the child's output column should be used for 
group by, but at this time, the new reference of the node's outputExpression 
will be used for group by, resulting in an error
    
    Now: Give priority to the child's output for group by binding. If the child 
does not have a corresponding column, use the outputExpression of this node for 
binding
---
 .../nereids/rules/analysis/BindSlotReference.java  | 23 ++++++++--
 .../nereids/rules/analysis/NormalizeRepeat.java    |  2 +-
 .../rules/rewrite/logical/NormalizeAggregate.java  |  3 +-
 .../nereids/trees/plans/GroupingSetsTest.java      | 49 ++++++++++++++++++++++
 .../data/nereids_syntax_p0/grouping_sets.out       | 34 +++++++++++++++
 .../suites/nereids_syntax_p0/grouping_sets.groovy  | 28 +++++++++++++
 6 files changed, 133 insertions(+), 6 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
index 3590d07483..d438db12ea 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
@@ -167,18 +167,26 @@ public class BindSlotReference implements 
AnalysisRuleFactory {
                     LogicalAggregate<GroupPlan> agg = ctx.root;
                     List<NamedExpression> output =
                             bind(agg.getOutputExpressions(), agg.children(), 
agg, ctx.cascadesContext);
+
+                    // The columns referenced in group by are first obtained 
from the child's output,
+                    // and then from the node's output
+                    Map<String, Expression> childOutputsToExpr = 
agg.child().getOutput().stream()
+                            .collect(Collectors.toMap(Slot::getName, 
Slot::toSlot, (oldExpr, newExpr) -> oldExpr));
                     Map<String, Expression> aliasNameToExpr = output.stream()
                             .filter(ne -> ne instanceof Alias)
                             .map(Alias.class::cast)
                             .collect(Collectors.toMap(Alias::getName, 
UnaryNode::child, (oldExpr, newExpr) -> oldExpr));
+                    aliasNameToExpr.entrySet().stream()
+                            .forEach(e -> 
childOutputsToExpr.putIfAbsent(e.getKey(), e.getValue()));
+
                     List<Expression> replacedGroupBy = 
agg.getGroupByExpressions().stream()
                             .map(groupBy -> {
                                 if (groupBy instanceof UnboundSlot) {
                                     UnboundSlot unboundSlot = (UnboundSlot) 
groupBy;
                                     if (unboundSlot.getNameParts().size() == 
1) {
                                         String name = 
unboundSlot.getNameParts().get(0);
-                                        if (aliasNameToExpr.containsKey(name)) 
{
-                                            return aliasNameToExpr.get(name);
+                                        if 
(childOutputsToExpr.containsKey(name)) {
+                                            return 
childOutputsToExpr.get(name);
                                         }
                                     }
                                 }
@@ -197,10 +205,17 @@ public class BindSlotReference implements 
AnalysisRuleFactory {
                     List<NamedExpression> output =
                             bind(repeat.getOutputExpressions(), 
repeat.children(), repeat, ctx.cascadesContext);
 
+                    // The columns referenced in group by are first obtained 
from the child's output,
+                    // and then from the node's output
+                    Map<String, Expression> childOutputsToExpr = 
repeat.child().getOutput().stream()
+                            .collect(Collectors.toMap(Slot::getName, 
Slot::toSlot, (oldExpr, newExpr) -> oldExpr));
                     Map<String, Expression> aliasNameToExpr = output.stream()
                             .filter(ne -> ne instanceof Alias)
                             .map(Alias.class::cast)
                             .collect(Collectors.toMap(Alias::getName, 
UnaryNode::child, (oldExpr, newExpr) -> oldExpr));
+                    aliasNameToExpr.entrySet().stream()
+                            .forEach(e -> 
childOutputsToExpr.putIfAbsent(e.getKey(), e.getValue()));
+
                     List<List<Expression>> replacedGroupingSets = 
repeat.getGroupingSets().stream()
                             .map(groupBy ->
                                 groupBy.stream().map(expr -> {
@@ -208,8 +223,8 @@ public class BindSlotReference implements 
AnalysisRuleFactory {
                                         UnboundSlot unboundSlot = 
(UnboundSlot) expr;
                                         if (unboundSlot.getNameParts().size() 
== 1) {
                                             String name = 
unboundSlot.getNameParts().get(0);
-                                            if 
(aliasNameToExpr.containsKey(name)) {
-                                                return 
aliasNameToExpr.get(name);
+                                            if 
(childOutputsToExpr.containsKey(name)) {
+                                                return 
childOutputsToExpr.get(name);
                                             }
                                         }
                                     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/NormalizeRepeat.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/NormalizeRepeat.java
index 8c62aab3d4..7818fe2bb7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/NormalizeRepeat.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/NormalizeRepeat.java
@@ -200,7 +200,7 @@ public class NormalizeRepeat extends OneAnalysisRuleFactory 
{
     }
 
     private Plan pushDownProject(Set<NamedExpression> pushedExprs, Plan 
originBottomPlan) {
-        if (!pushedExprs.equals(originBottomPlan.getOutputSet())) {
+        if (!pushedExprs.equals(originBottomPlan.getOutputSet()) && 
!pushedExprs.isEmpty()) {
             return new LogicalProject<>(ImmutableList.copyOf(pushedExprs), 
originBottomPlan);
         }
         return originBottomPlan;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/NormalizeAggregate.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/NormalizeAggregate.java
index d69cff4d58..b5a1ddc32b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/NormalizeAggregate.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/NormalizeAggregate.java
@@ -93,7 +93,8 @@ public class NormalizeAggregate extends OneRewriteRuleFactory 
implements Normali
                     
aggregateFunctionToSlotContext.pushDownToNamedExpression(normalizedAggregateFunctions);
 
             List<Slot> normalizedGroupBy =
-                    (List) 
groupByAndArgumentToSlotContext.normalizeToUseSlotRef(aggregate.getGroupByExpressions());
+                    (List) groupByAndArgumentToSlotContext
+                            
.normalizeToUseSlotRef(aggregate.getGroupByExpressions());
 
             // we can safely add all groupBy and aggregate functions to 
output, because we will
             // add a project on it, and the upper project can protect the 
scope of visible of slot
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/GroupingSetsTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/GroupingSetsTest.java
index cec372311e..a30364b116 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/GroupingSetsTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/GroupingSetsTest.java
@@ -183,4 +183,53 @@ public class GroupingSetsTest extends TestWithFeService {
         PlanChecker.from(connectContext)
                 .checkPlannerResult("select if(k1 = 1, 2, k1) k_if from t1");
     }
+
+    @Test
+    public void test1() {
+        PlanChecker.from(connectContext)
+                .checkPlannerResult("select coalesce(col1, 'all') as col1, 
count(*) as cnt from"
+                        + " (select null as col1 union all select 'a' as col1 
) t group by grouping sets ((col1),());");
+    }
+
+    @Test
+    public void test1_1() {
+        PlanChecker.from(connectContext)
+                .checkPlannerResult("select coalesce(col1, 'all') as col2, 
count(*) as cnt from"
+                        + " (select null as col1 union all select 'a' as col1 
) t group by grouping sets ((col1),());");
+    }
+
+    @Test
+    public void test1_2() {
+        PlanChecker.from(connectContext)
+                .checkPlannerResult("select coalesce(col1, 'all') as col2, 
count(*) as cnt from"
+                        + " (select null as col1 union all select 'a' as col1 
) t group by grouping sets ((col2),());");
+    }
+
+    @Test
+    public void test2() {
+        PlanChecker.from(connectContext)
+                .checkPlannerResult("select if(1 = null, 'all', 2) as col1, 
count(*) as cnt from"
+                        + " (select null as col1 union all select 'a' as col1 
) t group by grouping sets ((col1),());");
+    }
+
+    @Test
+    public void test2_1() {
+        PlanChecker.from(connectContext)
+                .checkPlannerResult("select if(col1 = null, 'all', 2) as col1, 
count(*) as cnt from"
+                        + " (select null as col1 union all select 'a' as col1 
) t group by grouping sets ((col1),());");
+    }
+
+    @Test
+    public void test2_2() {
+        PlanChecker.from(connectContext)
+                .checkPlannerResult("select if(col1 = null, 'all', 2) as col2, 
count(*) as cnt from"
+                        + " (select null as col1 union all select 'a' as col1 
) t group by grouping sets ((col1),());");
+    }
+
+    @Test
+    public void test2_3() {
+        PlanChecker.from(connectContext)
+                .checkPlannerResult("select if(col1 = null, 'all', 2) as col2, 
count(*) as cnt from"
+                        + " (select null as col1 union all select 'a' as col1 
) t group by grouping sets ((col2),());");
+    }
 }
diff --git a/regression-test/data/nereids_syntax_p0/grouping_sets.out 
b/regression-test/data/nereids_syntax_p0/grouping_sets.out
index 38b19938d0..6c18f54e2b 100644
--- a/regression-test/data/nereids_syntax_p0/grouping_sets.out
+++ b/regression-test/data/nereids_syntax_p0/grouping_sets.out
@@ -224,3 +224,37 @@
 3
 4
 
+-- !select1 --
+a      1
+all    1
+all    2
+
+-- !select2 --
+a      1
+all    1
+all    2
+
+-- !select3 --
+\N     2
+a      1
+all    1
+
+-- !select4 --
+2      1
+2      1
+2      2
+
+-- !select5 --
+2      1
+2      1
+2      2
+
+-- !select6 --
+2      1
+2      1
+2      2
+
+-- !select7 --
+2      1
+2      1
+2      2
diff --git a/regression-test/suites/nereids_syntax_p0/grouping_sets.groovy 
b/regression-test/suites/nereids_syntax_p0/grouping_sets.groovy
index 5218a4215c..8e6cc6e5c7 100644
--- a/regression-test/suites/nereids_syntax_p0/grouping_sets.groovy
+++ b/regression-test/suites/nereids_syntax_p0/grouping_sets.groovy
@@ -232,4 +232,32 @@ suite("test_nereids_grouping_sets") {
             ) T
         ) T2;
     """
+
+    order_qt_select1 """
+        select coalesce(col1, 'all') as col1, count(*) as cnt from (select 
null as col1 union all select 'a' as col1 ) t group by grouping sets 
((col1),());
+    """
+
+    order_qt_select2 """
+        select coalesce(col1, 'all') as col2, count(*) as cnt from (select 
null as col1 union all select 'a' as col1 ) t group by grouping sets 
((col1),());
+    """
+
+    order_qt_select3 """
+        select coalesce(col1, 'all') as col2, count(*) as cnt from (select 
null as col1 union all select 'a' as col1 ) t group by grouping sets 
((col2),());
+    """
+
+    order_qt_select4 """
+        select if(1 = null, 'all', 2) as col1, count(*) as cnt from (select 
null as col1 union all select 'a' as col1 ) t group by grouping sets 
((col1),());
+    """
+
+    order_qt_select5 """
+        select if(col1 = null, 'all', 2) as col1, count(*) as cnt from (select 
null as col1 union all select 'a' as col1 ) t group by grouping sets 
((col1),());
+    """
+
+    order_qt_select6 """
+        select if(1 = null, 'all', 2) as col2, count(*) as cnt from (select 
null as col1 union all select 'a' as col1 ) t group by grouping sets 
((col1),());
+    """
+
+    order_qt_select7 """
+        select if(col1 = null, 'all', 2) as col2, count(*) as cnt from (select 
null as col1 union all select 'a' as col1 ) t group by grouping sets 
((col1),());
+    """
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to