This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.1 by this push:
new 9667573506d branch-4.1 [fix](eager-agg) push aggregation down through
filter (#62669) (#63536)
9667573506d is described below
commit 9667573506d76e70e06e6b7ced07afbde9a95dd7
Author: minghong <[email protected]>
AuthorDate: Thu Jun 4 11:20:12 2026 +0800
branch-4.1 [fix](eager-agg) push aggregation down through filter (#62669)
(#63536)
Issue Number: None
Related PR: None
push aggregation down through filter, if filter.child() is not Scan
None
- Test: Manual test
- Regression test case updated; out refreshed in working tree
- Behavior changed: Yes (eager agg can safely push through filter while
preserving filter-required slots)
- Does this need documentation: No
### What problem does this PR solve?
Issue Number: close #xxx
Related PR: #xxx
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 -->
---
.../eageraggregation/EagerAggRewriterTest.java | 111 +++++++++++----------
1 file changed, 56 insertions(+), 55 deletions(-)
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriterTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriterTest.java
index 397585e530e..799df7838d1 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriterTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriterTest.java
@@ -316,61 +316,6 @@ class EagerAggRewriterTest extends TestWithFeService
implements MemoPatternMatch
}
}
- @Test
- void testNotPushAggLiteralToNullableSideOfOuterJoin() {
- // sum(literal), min(literal), max(literal) aggregate over all
physical rows,
- // including null-extended rows from the outer join.
- // Pushing to the nullable side loses the contribution of unmatched
rows:
- // original: sum(2) on unmatched row = 2
- // pushed: sum(NULL) skips the row (wrong!)
- // So agg(literal) must NOT be pushed to the nullable side.
- connectContext.getSessionVariable().setEagerAggregationMode(1);
- connectContext.getSessionVariable().setDisableJoinReorder(true);
- try {
- // RIGHT JOIN: t1 is the nullable side (left side of RIGHT JOIN)
- // sum(2) should NOT be pushed to t1
- String sql = "select sum(2), t2.id2 from t1 right join t2"
- + " on t1.id1 = t2.id2 group by t2.id2";
- PlanChecker.from(connectContext)
- .analyze(sql)
- .rewrite()
- .nonMatch(logicalJoin(logicalAggregate(), any()))
- .printlnTree();
-
- // LEFT JOIN: t2 is the nullable side (right side of LEFT JOIN)
- // min(1) should NOT be pushed to t2
- sql = "select min(1), t1.id1 from t1 left join t2"
- + " on t1.id1 = t2.id2 group by t1.id1";
- PlanChecker.from(connectContext)
- .analyze(sql)
- .rewrite()
- .nonMatch(logicalJoin(any(), logicalAggregate()))
- .printlnTree();
-
- // RIGHT JOIN: max(3) should NOT be pushed to nullable left side
- sql = "select max(3), t2.id2 from t1 right join t2"
- + " on t1.id1 = t2.id2 group by t2.id2";
- PlanChecker.from(connectContext)
- .analyze(sql)
- .rewrite()
- .nonMatch(logicalJoin(logicalAggregate(), any()))
- .printlnTree();
-
- // Verify agg(nullable_side_col) is still safe to push (no
regression)
- // max(t1.name) references the left (nullable) side, so push is
allowed
- sql = "select max(t1.name), t2.id2 from t1 right join t2"
- + " on t1.id1 = t2.id2 group by t2.id2";
- PlanChecker.from(connectContext)
- .analyze(sql)
- .rewrite()
-
.matches(logicalAggregate(logicalProject(logicalJoin(logicalAggregate(),
any()))))
- .printlnTree();
- } finally {
- connectContext.getSessionVariable().setEagerAggregationMode(0);
- connectContext.getSessionVariable().setDisableJoinReorder(false);
- }
- }
-
@Test
void testUniqueFunctionFilterBlocksPushDownThroughFilter() {
connectContext.getSessionVariable().setEagerAggregationMode(1);
@@ -439,4 +384,60 @@ class EagerAggRewriterTest extends TestWithFeService
implements MemoPatternMatch
}
return null;
}
+
+ @Test
+ void testNotPushAggLiteralToNullableSideOfOuterJoin() {
+ // sum(literal), min(literal), max(literal) aggregate over all
physical rows,
+ // including null-extended rows from the outer join.
+ // Pushing to the nullable side loses the contribution of unmatched
rows:
+ // original: sum(2) on unmatched row = 2
+ // pushed: sum(NULL) skips the row (wrong!)
+ // So agg(literal) must NOT be pushed to the nullable side.
+ connectContext.getSessionVariable().setEagerAggregationMode(1);
+ connectContext.getSessionVariable().setDisableJoinReorder(true);
+ try {
+ // RIGHT JOIN: t1 is the nullable side (left side of RIGHT JOIN)
+ // sum(2) should NOT be pushed to t1
+ String sql = "select sum(2), t2.id2 from t1 right join t2"
+ + " on t1.id1 = t2.id2 group by t2.id2";
+ PlanChecker.from(connectContext)
+ .analyze(sql)
+ .rewrite()
+ .nonMatch(logicalJoin(logicalAggregate(), any()))
+ .printlnTree();
+
+ // LEFT JOIN: t2 is the nullable side (right side of LEFT JOIN)
+ // min(1) should NOT be pushed to t2
+ sql = "select min(1), t1.id1 from t1 left join t2"
+ + " on t1.id1 = t2.id2 group by t1.id1";
+ PlanChecker.from(connectContext)
+ .analyze(sql)
+ .rewrite()
+ .nonMatch(logicalJoin(any(), logicalAggregate()))
+ .printlnTree();
+
+ // RIGHT JOIN: max(3) should NOT be pushed to nullable left side
+ sql = "select max(3), t2.id2 from t1 right join t2"
+ + " on t1.id1 = t2.id2 group by t2.id2";
+ PlanChecker.from(connectContext)
+ .analyze(sql)
+ .rewrite()
+ .nonMatch(logicalJoin(logicalAggregate(), any()))
+ .printlnTree();
+
+ // Verify agg(nullable_side_col) is still safe to push (no
regression)
+ // max(t1.name) references the left (nullable) side, so push is
allowed
+ sql = "select max(t1.name), t2.id2 from t1 right join t2"
+ + " on t1.id1 = t2.id2 group by t2.id2";
+ PlanChecker.from(connectContext)
+ .analyze(sql)
+ .rewrite()
+
.matches(logicalAggregate(logicalProject(logicalJoin(logicalAggregate(),
any()))))
+ .printlnTree();
+ } finally {
+ connectContext.getSessionVariable().setEagerAggregationMode(0);
+ connectContext.getSessionVariable().setDisableJoinReorder(false);
+ }
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]