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

dataroaring 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 a5e4e1c7018 [fix](nereids) Fix not in aggregate's output err after 
eliminate by uniform when group sets exist (#56942)
a5e4e1c7018 is described below

commit a5e4e1c70186dcd3da0fa832e48bd180dbedfa53
Author: seawinde <[email protected]>
AuthorDate: Thu Nov 6 09:27:33 2025 +0800

    [fix](nereids) Fix not in aggregate's output err after eliminate by uniform 
when group sets exist (#56942)
    
    Fix not in aggregate's output err after eliminate by uniform when group
    sets exist
    
    if query as following, would cause `ERROR 1105 (HY000): errCode = 2,
    detailMessage = GROUPING_PREFIX_event_name_group not in aggregate's
    output`
    
    the pr fix this
    
    ```sql
    SELECT
      CASE WHEN GROUPING(event_date) = 1 THEN '(TOTAL)' ELSE CAST(event_date AS 
VARCHAR) END AS event_date,
      user_id,
      MAX(conversion_level) AS conversion_level,
      CASE WHEN GROUPING(event_name_group) = 1 THEN '(TOTAL)' ELSE 
event_name_group END AS event_name_group
    FROM
      (
        SELECT
          src.event_date,
          src.user_id,
          WINDOW_FUNNEL(
            3600 * 24 * 1,
            'default',
            src.event_time,
            src.event_name = 'shop_buy',
            src.event_name = 'shop_buy'
          ) AS conversion_level,
          src.event_name_group
        FROM
          (
            SELECT
              CAST(etb.`@dt` AS DATE) AS event_date,
              etb.`@event_name` AS event_name,
              etb.`@event_time` AS event_time,
              etb.`@event_name` AS event_name_group,
              etb.`@user_id` AS user_id
            FROM
              `test_event` AS etb
            WHERE
              etb.`@dt` between '2025-09-03 02:00:00' AND '2025-09-10 01:59:59'
              AND etb.`@event_name` = 'shop_buy'
              AND etb.`@user_id` IS NOT NULL
              AND etb.`@user_id` > '0'
          ) AS src
        GROUP BY
          src.event_date,
          src.user_id,
          src.event_name_group
      ) AS fwt
    GROUP BY
      GROUPING SETS (
        (user_id),
        (user_id, event_date),
        (user_id, event_name_group),
        (user_id, event_date, event_name_group)
      );
    ```
    
    ### What problem does this PR solve?
    
    Issue Number: close #xxx
    
    Related PR: #43391
    
    Problem Summary:
    
    ### Release note
    
    None
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [ ] Unit Test
        - [ ] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [ ] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 .../rules/expression/ExpressionRuleType.java       |  1 +
 .../rewrite/EliminateGroupByKeyByUniform.java      |  6 ++
 .../nereids/rules/rewrite/ExprIdRewriter.java      | 59 +++++++++++---
 .../trees/expressions/VirtualSlotReference.java    |  7 ++
 .../trees/plans/logical/LogicalAggregate.java      |  6 ++
 .../eliminate_group_by_key_by_uniform.groovy       | 95 ++++++++++++++++++++++
 6 files changed, 161 insertions(+), 13 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
index 5a5daeb7143..f0d1b93ed12 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
@@ -34,6 +34,7 @@ public enum ExpressionRuleType {
     DIGITAL_MASKING_CONVERT,
     DISTINCT_PREDICATES,
     EXPR_ID_REWRITE_REPLACE,
+    VIRTUAL_EXPR_ID_REWRITE_REPLACE,
     EXTRACT_COMMON_FACTOR,
     FOLD_CONSTANT_ON_BE,
     FOLD_CONSTANT_ON_FE,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByKeyByUniform.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByKeyByUniform.java
index c210c8cca6e..9928b2d8276 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByKeyByUniform.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByKeyByUniform.java
@@ -32,6 +32,7 @@ import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
 import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
 import org.apache.doris.nereids.trees.plans.logical.LogicalLimit;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+import org.apache.doris.nereids.trees.plans.logical.LogicalRepeat;
 import org.apache.doris.nereids.trees.plans.visitor.CustomRewriter;
 import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter;
 import org.apache.doris.nereids.util.Utils;
@@ -79,6 +80,11 @@ public class EliminateGroupByKeyByUniform extends 
DefaultPlanRewriter<Map<ExprId
     public Plan visitLogicalAggregate(LogicalAggregate<? extends Plan> 
aggregate, Map<ExprId, ExprId> replaceMap) {
         aggregate = visitChildren(this, aggregate, replaceMap);
         aggregate = (LogicalAggregate<? extends Plan>) 
exprIdReplacer.rewriteExpr(aggregate, replaceMap);
+        if (aggregate.getSourceRepeat().isPresent()) {
+            LogicalRepeat<?> sourceRepeat = (LogicalRepeat<?>) 
exprIdReplacer.rewriteExpr(
+                    aggregate.getSourceRepeat().get(), replaceMap);
+            aggregate = aggregate.withSourceRepeat(sourceRepeat);
+        }
 
         if (aggregate.getGroupByExpressions().isEmpty() || 
aggregate.getSourceRepeat().isPresent()) {
             return aggregate;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ExprIdRewriter.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ExprIdRewriter.java
index 615d3cc6c2e..d3c0343a8c3 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ExprIdRewriter.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ExprIdRewriter.java
@@ -29,12 +29,16 @@ import org.apache.doris.nereids.trees.expressions.ExprId;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.expressions.VirtualSlotReference;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.GroupingScalarFunction;
+import 
org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionRewriter;
 import org.apache.doris.nereids.trees.plans.Plan;
 
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 /** replace SlotReference ExprId in logical plans */
 public class ExprIdRewriter extends ExpressionRewrite {
@@ -75,18 +79,10 @@ public class ExprIdRewriter extends ExpressionRewrite {
      * SlotReference:a#0 -> a#3, a#1 -> a#7
      * */
     public static class ReplaceRule implements ExpressionPatternRuleFactory {
-        private final Map<ExprId, ExprId> replaceMap;
-
-        public ReplaceRule(Map<ExprId, ExprId> replaceMap) {
-            this.replaceMap = replaceMap;
-        }
-
-        @Override
-        public List<ExpressionPatternMatcher<? extends Expression>> 
buildRules() {
-            return ImmutableList.of(
-                    matchesType(SlotReference.class).thenApply(ctx -> {
-                        Slot slot = ctx.expr;
-
+        private static final DefaultExpressionRewriter<Map<ExprId, ExprId>> 
SLOT_REPLACER =
+                new DefaultExpressionRewriter<Map<ExprId, ExprId>>() {
+                    @Override
+                    public Expression visitSlotReference(SlotReference slot, 
Map<ExprId, ExprId> replaceMap) {
                         ExprId newId = replaceMap.get(slot.getExprId());
                         if (newId == null) {
                             return slot;
@@ -100,7 +96,44 @@ public class ExprIdRewriter extends ExpressionRewrite {
                                 lastId = newId;
                             }
                         }
-                    }).toRule(ExpressionRuleType.EXPR_ID_REWRITE_REPLACE)
+                    }
+                };
+        private final Map<ExprId, ExprId> replaceMap;
+
+        public ReplaceRule(Map<ExprId, ExprId> replaceMap) {
+            this.replaceMap = replaceMap;
+        }
+
+        @Override
+        public List<ExpressionPatternMatcher<? extends Expression>> 
buildRules() {
+            return ImmutableList.of(
+                    matchesType(SlotReference.class).thenApply(ctx -> {
+                        Slot slot = ctx.expr;
+                        return slot.accept(SLOT_REPLACER, replaceMap);
+                    }).toRule(ExpressionRuleType.EXPR_ID_REWRITE_REPLACE),
+                    matchesType(VirtualSlotReference.class).thenApply(ctx -> {
+                        VirtualSlotReference virtualSlot = ctx.expr;
+                        return virtualSlot.accept(new 
DefaultExpressionRewriter<Map<ExprId, ExprId>>() {
+                            @Override
+                            public Expression 
visitVirtualReference(VirtualSlotReference virtualSlot,
+                                    Map<ExprId, ExprId> replaceMap) {
+                                Optional<GroupingScalarFunction> 
originExpression = virtualSlot.getOriginExpression();
+                                if (!originExpression.isPresent()) {
+                                    return virtualSlot;
+                                }
+                                GroupingScalarFunction groupingScalarFunction 
= originExpression.get();
+                                GroupingScalarFunction rewrittenFunction =
+                                        (GroupingScalarFunction) 
groupingScalarFunction.accept(
+                                                SLOT_REPLACER, replaceMap);
+                                if 
(!rewrittenFunction.children().equals(groupingScalarFunction.children())) {
+                                    return 
virtualSlot.withOriginExpressionAndComputeLongValueMethod(
+                                            Optional.of(rewrittenFunction),
+                                            
rewrittenFunction::computeVirtualSlotValue);
+                                }
+                                return virtualSlot;
+                            }
+                        }, replaceMap);
+                    
}).toRule(ExpressionRuleType.VIRTUAL_EXPR_ID_REWRITE_REPLACE)
             );
         }
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/VirtualSlotReference.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/VirtualSlotReference.java
index 42be6210459..bac559f407d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/VirtualSlotReference.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/VirtualSlotReference.java
@@ -156,6 +156,13 @@ public class VirtualSlotReference extends SlotReference 
implements SlotNotFromCh
                 originExpression, computeLongValueMethod);
     }
 
+    public VirtualSlotReference withOriginExpressionAndComputeLongValueMethod(
+            Optional<GroupingScalarFunction> originExpression,
+            Function<GroupingSetShapes, List<Long>> computeLongValueMethod) {
+        return new VirtualSlotReference(exprId, name.get(), dataType, 
nullable, qualifier,
+                originExpression, computeLongValueMethod);
+    }
+
     @Override
     public Slot withIndexInSql(Pair<Integer, Integer> index) {
         return this;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
index 4e43631c95a..7401dbbaea7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
@@ -387,6 +387,12 @@ public class LogicalAggregate<CHILD_TYPE extends Plan>
                 sourceRepeat, Optional.empty(), Optional.empty(), child());
     }
 
+    public LogicalAggregate<Plan> withSourceRepeat(LogicalRepeat<?> 
sourceRepeat) {
+        return new LogicalAggregate<>(groupByExpressions, outputExpressions, 
normalized, ordinalIsResolved,
+                generated, hasPushed, withInProjection, 
Optional.ofNullable(sourceRepeat),
+                Optional.empty(), Optional.empty(), child());
+    }
+
     private boolean isUniqueGroupByUnique(NamedExpression namedExpression) {
         if (namedExpression.children().size() != 1) {
             return false;
diff --git 
a/regression-test/suites/nereids_rules_p0/eliminate_gby_key/eliminate_group_by_key_by_uniform.groovy
 
b/regression-test/suites/nereids_rules_p0/eliminate_gby_key/eliminate_group_by_key_by_uniform.groovy
index c5652e76d37..4b5b63ead8f 100644
--- 
a/regression-test/suites/nereids_rules_p0/eliminate_gby_key/eliminate_group_by_key_by_uniform.groovy
+++ 
b/regression-test/suites/nereids_rules_p0/eliminate_gby_key/eliminate_group_by_key_by_uniform.groovy
@@ -237,4 +237,99 @@ suite("eliminate_group_by_key_by_uniform") {
     qt_to_limit_join_project_shape "explain shape plan select 1 as c1 from 
test1 t1 inner join (select * from test2 where b=105)  t2 on t1.a=t2.a group by 
c1 order by 1;"
     qt_to_limit_project_uniform_shape "explain shape plan select 1 as c1 from 
eli_gbk_by_uniform_t group by c1"
     qt_to_limit_multi_group_by_shape "explain shape plan select 2 as c1 from 
eli_gbk_by_uniform_t where a=1 group by c1,a"
+
+    // test when has repeat above agg
+    // disable CONSTANT_PROPAGATION rules to test eliminate aggregate by 
uniform
+    sql """set disable_nereids_rules = 'CONSTANT_PROPAGATION';"""
+
+
+    sql """drop table if exists test_event"""
+    sql """
+    CREATE TABLE `test_event` (
+    `@dt` DATETIME NOT NULL COMMENT '',
+    `@event_name` VARCHAR(255) NOT NULL COMMENT '',
+    `@user_id` VARCHAR(100) NOT NULL COMMENT '',
+    `@event_time` DATETIME NOT NULL COMMENT '',
+    `@event_property_1` VARCHAR(255) NULL
+     )
+     ENGINE=OLAP
+     DUPLICATE KEY(`@dt`, `@event_name`, `@user_id`)
+     COMMENT ''
+     PARTITION BY RANGE(`@dt`)
+     (
+         PARTITION p202509 VALUES [('2025-09-01 00:00:00'), ('2025-10-05 
00:00:00'))
+     )
+     DISTRIBUTED BY HASH(`@user_id`) BUCKETS 10
+     PROPERTIES (
+         "replication_num" = "1",
+         "dynamic_partition.enable" = "true",
+         "dynamic_partition.time_unit" = "MONTH",
+         "dynamic_partition.start" = "-2147483648",
+         "dynamic_partition.end" = "3",
+         "dynamic_partition.prefix" = "p",
+         "dynamic_partition.buckets" = "10"
+     );
+    """
+
+    sql """
+    INSERT INTO `test_event` (`@dt`, `@event_name`, `@user_id`, `@event_time`, 
`@event_property_1`)
+    VALUES
+    ('2025-09-03 10:00:00', 'shop_buy', 'user_A', '2025-09-03 10:00:00', 
'prop_A1'),
+    ('2025-09-03 10:01:00', 'shop_buy', 'user_A', '2025-09-03 10:01:00', 
'prop_A2'),
+    ('2025-09-04 15:30:00', 'shop_buy', 'user_A', '2025-09-04 15:30:00', 
'prop_A3'),
+    ('2025-09-05 08:00:00', 'shop_buy', 'user_B', '2025-09-05 08:00:00', 
'prop_B1'),
+    ('2025-09-05 08:05:00', 'shop_buy', 'user_B', '2025-09-05 08:05:00', 
'prop_B2'),
+    ('2025-09-09 23:59:59', 'shop_buy', 'user_C', '2025-09-09 23:59:59', 
'prop_C1'),
+    ('2025-10-01 00:00:00', 'shop_buy', 'user_D', '2025-10-01 00:00:00', 
'prop_D1');
+    """
+
+    sql """
+    SELECT
+  CASE WHEN GROUPING(event_date) = 1 THEN '(TOTAL)' ELSE CAST(event_date AS 
VARCHAR) END AS event_date,
+  user_id,
+  MAX(conversion_level) AS conversion_level,
+  CASE WHEN GROUPING(event_name_group) = 1 THEN '(TOTAL)' ELSE 
event_name_group END AS event_name_group
+FROM
+  (
+    SELECT
+      src.event_date,
+      src.user_id,
+      WINDOW_FUNNEL(
+        3600 * 24 * 1,
+        'default',
+        src.event_time,
+        src.event_name = 'shop_buy',
+        src.event_name = 'shop_buy'
+      ) AS conversion_level,
+      src.event_name_group
+    FROM
+      (
+        SELECT
+          CAST(etb.`@dt` AS DATE) AS event_date,
+          etb.`@event_name` AS event_name,
+          etb.`@event_time` AS event_time,
+          etb.`@event_name` AS event_name_group,
+          etb.`@user_id` AS user_id
+        FROM
+          `test_event` AS etb
+        WHERE
+          etb.`@dt` between '2025-09-03 02:00:00' AND '2025-09-10 01:59:59'
+          AND etb.`@event_name` = 'shop_buy'
+          AND etb.`@user_id` IS NOT NULL
+          AND etb.`@user_id` > '0'
+      ) AS src
+    GROUP BY
+      src.event_date,
+      src.user_id,
+      src.event_name_group
+  ) AS fwt
+GROUP BY
+  GROUPING SETS (
+    (user_id),
+    (user_id, event_date),
+    (user_id, event_name_group),
+    (user_id, event_date, event_name_group)
+  );
+
+    """
 }
\ No newline at end of file


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

Reply via email to