This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.1 by this push:
new d82a5c6372e branch-3.1: [fix](nereids) Fix not in aggregate's output
err after eliminate by uniform when group sets exist #56942 (#57885)
d82a5c6372e is described below
commit d82a5c6372e051eadd0db9bfa2d5047730d663a1
Author: seawinde <[email protected]>
AuthorDate: Wed Nov 12 14:08:56 2025 +0800
branch-3.1: [fix](nereids) Fix not in aggregate's output err after
eliminate by uniform when group sets exist #56942 (#57885)
picked from #56942
---
.../rewrite/EliminateGroupByKeyByUniform.java | 6 ++
.../nereids/rules/rewrite/ExprIdRewriter.java | 53 +++++++++++--
.../trees/expressions/VirtualSlotReference.java | 7 ++
.../trees/plans/logical/LogicalAggregate.java | 6 ++
.../eliminate_group_by_key_by_uniform.groovy | 92 ++++++++++++++++++++++
5 files changed, 157 insertions(+), 7 deletions(-)
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 d5b33dc5488..15435a08504 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.Plan;
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;
@@ -81,6 +82,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 5e065fa3724..a6dc37f990e 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
@@ -28,12 +28,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 {
@@ -74,6 +78,25 @@ public class ExprIdRewriter extends ExpressionRewrite {
* SlotReference:a#0 -> a#3, a#1 -> a#7
* */
public static class ReplaceRule implements ExpressionPatternRuleFactory {
+ 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;
+ }
+ ExprId lastId = newId;
+ while (true) {
+ newId = replaceMap.get(lastId);
+ if (newId == null) {
+ return slot.withExprId(lastId);
+ } else {
+ lastId = newId;
+ }
+ }
+ }
+ };
private final Map<ExprId, ExprId> replaceMap;
public ReplaceRule(Map<ExprId, ExprId> replaceMap) {
@@ -85,14 +108,30 @@ public class ExprIdRewriter extends ExpressionRewrite {
return ImmutableList.of(
matchesType(SlotReference.class).thenApply(ctx -> {
Slot slot = ctx.expr;
- if (replaceMap.containsKey(slot.getExprId())) {
- ExprId newId = replaceMap.get(slot.getExprId());
- while (replaceMap.containsKey(newId)) {
- newId = replaceMap.get(newId);
+ return slot.accept(SLOT_REPLACER, replaceMap);
+ }),
+ 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;
}
- return slot.withExprId(newId);
- }
- return slot;
+ }, replaceMap);
})
);
}
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 9bc7fbfd5e1..e59025442da 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
@@ -311,6 +311,12 @@ public class LogicalAggregate<CHILD_TYPE extends Plan>
hasPushed, sourceRepeat, Optional.empty(), Optional.empty(),
normalizedChild);
}
+ public LogicalAggregate<Plan> withSourceRepeat(LogicalRepeat<?>
sourceRepeat) {
+ return new LogicalAggregate<>(groupByExpressions, outputExpressions,
normalized, ordinalIsResolved,
+ generated, hasPushed, 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 b7e2dccaa77..d3fd6a4c293 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,96 @@ 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;"
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
+
+ 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]