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 b6d314c2bb3 branch-4.1 [fix](eager-agg) push aggregation down through
filter (#62669) (#63915)
b6d314c2bb3 is described below
commit b6d314c2bb35d290060ea3b444abf88f4f60590e
Author: minghong <[email protected]>
AuthorDate: Wed Jun 3 18:41:53 2026 +0800
branch-4.1 [fix](eager-agg) push aggregation down through filter (#62669)
(#63915)
pick #62669
### 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 -->
---
.../rewrite/eageraggregation/EagerAggRewriter.java | 70 ++++++----
.../eageraggregation/EagerAggRewriterTest.java | 128 +++++++++++++++++
.../data/nereids_p0/eager_agg/eager_agg.out | 73 ++++++++++
.../suites/nereids_p0/eager_agg/eager_agg.groovy | 152 +++++++++++++++++++++
4 files changed, 398 insertions(+), 25 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriter.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriter.java
index 87050b5bbdf..217854d6033 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriter.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriter.java
@@ -28,7 +28,6 @@ import
org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import
org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction;
-import org.apache.doris.nereids.trees.expressions.functions.agg.Count;
import org.apache.doris.nereids.trees.expressions.functions.scalar.If;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
@@ -54,6 +53,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* eager aggregation
@@ -133,34 +133,32 @@ public class EagerAggRewriter extends
DefaultPlanRewriter<PushDownAggContext> {
}
}
- // Do not push count(*)/count(literal)/count(preserved_side_col) to
the nullable side of outer joins.
- // count(*) counts all physical rows, including null-extended rows
from the outer join.
- // After pushdown to the nullable side, unmatched rows produce NULL
for the pre-aggregated count,
- // and ifnull(sum(NULL), 0) = 0, which loses the count of unmatched
rows.
- // However, count(nullable_side_col) is safe to push down because for
unmatched rows,
- // nullable_side_col IS NULL, so the original count is 0, matching
ifnull(sum(NULL), 0) = 0.
+ // Do not push agg(literal) or agg(preserved_side_col) to the nullable
side of outer joins.
+ // Aggregates like count(*), sum(2), min(1) etc. aggregate over all
physical rows,
+ // including null-extended rows from the outer join.
+ // After pushdown to the nullable side, unmatched rows produce NULL
for the pre-aggregated value,
+ // losing the contribution of those rows (e.g. sum(2) should add 2 per
unmatched row,
+ // but sum(NULL) skips them).
+ // However, agg(nullable_side_col) is safe to push down because for
unmatched rows,
+ // nullable_side_col IS NULL, and the aggregate naturally handles NULL
values correctly.
if (!join.getJoinType().isInnerJoin() &&
!join.getJoinType().isCrossJoin()) {
JoinType joinType = join.getJoinType();
+ boolean leftIsNullable = joinType.isRightOuterJoin() ||
joinType.isFullOuterJoin();
+ boolean rightIsNullable = joinType.isLeftOuterJoin() ||
joinType.isFullOuterJoin();
for (AggregateFunction aggFunc : context.getAggFunctions()) {
- if (aggFunc instanceof Count) {
- Set<Slot> countInputSlots = aggFunc.getInputSlots();
- // Determine which side is nullable
- boolean leftIsNullable = joinType.isRightOuterJoin() ||
joinType.isFullOuterJoin();
- boolean rightIsNullable = joinType.isLeftOuterJoin() ||
joinType.isFullOuterJoin();
- // Check if we're pushing to a nullable side without
referencing its columns
- if (toLeft && leftIsNullable) {
- boolean hasLeftInput = countInputSlots.stream()
- .anyMatch(slot ->
join.left().getOutputSet().contains(slot));
- if (!hasLeftInput) {
- toLeft = false;
- }
+ Set<Slot> inputSlots = aggFunc.getInputSlots();
+ if (toLeft && leftIsNullable) {
+ boolean hasLeftInput = inputSlots.stream()
+ .anyMatch(slot ->
join.left().getOutputSet().contains(slot));
+ if (!hasLeftInput) {
+ toLeft = false;
}
- if (toRight && rightIsNullable) {
- boolean hasRightInput = countInputSlots.stream()
- .anyMatch(slot ->
join.right().getOutputSet().contains(slot));
- if (!hasRightInput) {
- toRight = false;
- }
+ }
+ if (toRight && rightIsNullable) {
+ boolean hasRightInput = inputSlots.stream()
+ .anyMatch(slot ->
join.right().getOutputSet().contains(slot));
+ if (!hasRightInput) {
+ toRight = false;
}
}
}
@@ -505,6 +503,28 @@ public class EagerAggRewriter extends
DefaultPlanRewriter<PushDownAggContext> {
@Override
public Plan visitLogicalFilter(LogicalFilter<? extends Plan> filter,
PushDownAggContext context) {
+ if (filter.child() instanceof LogicalRelation) {
+ return genAggregate(filter, context);
+ }
+ if
(filter.getConjuncts().stream().anyMatch(Expression::containsUniqueFunction)) {
+ return genAggregate(filter, context);
+ }
+ List<SlotReference> filterInputSlots = filter.getInputSlots().stream()
+ .map(slot -> (SlotReference) slot)
+ .collect(Collectors.toList());
+ List<SlotReference> childGroupKeys = Stream.concat(
+ context.getGroupKeys().stream(),
+ filterInputSlots.stream())
+ .distinct()
+ .collect(Collectors.toList());
+ PushDownAggContext childContext =
context.withGroupKeys(childGroupKeys);
+ if (!childContext.isValid()) {
+ return genAggregate(filter, context);
+ }
+ Plan newChild = filter.child().accept(this, childContext);
+ if (newChild != filter.child()) {
+ return filter.withChildren(newChild);
+ }
return genAggregate(filter, context);
}
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 4b0561ccd0f..397585e530e 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
@@ -17,10 +17,14 @@
package org.apache.doris.nereids.rules.rewrite.eageraggregation;
+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.LogicalFilter;
import org.apache.doris.nereids.util.MemoPatternMatchSupported;
import org.apache.doris.nereids.util.PlanChecker;
import org.apache.doris.utframe.TestWithFeService;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class EagerAggRewriterTest extends TestWithFeService implements
MemoPatternMatchSupported {
@@ -311,4 +315,128 @@ class EagerAggRewriterTest extends TestWithFeService
implements MemoPatternMatch
connectContext.getSessionVariable().setDisableJoinReorder(false);
}
}
+
+ @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);
+ connectContext.getSessionVariable().setDisableJoinReorder(true);
+ try {
+ String sql = "select count(s.name1), t2.id2"
+ + " from (select * from (select id1, name as name1 from
t1) s1 where random() < 0.5) s"
+ + " join t2 on s.id1 = t2.id2 group by t2.id2";
+ Plan plan = PlanChecker.from(connectContext)
+ .analyze(sql)
+ .rewrite()
+ .getPlan();
+ Assertions.assertEquals(2, countPlans(plan,
LogicalAggregate.class), plan.treeString());
+ LogicalFilter<?> filter = findFirstPlan(plan, LogicalFilter.class);
+ Assertions.assertNotNull(filter, plan.treeString());
+ Assertions.assertFalse(containsPlan(filter.child(),
LogicalAggregate.class), plan.treeString());
+ } finally {
+ connectContext.getSessionVariable().setEagerAggregationMode(0);
+ connectContext.getSessionVariable().setDisableJoinReorder(false);
+ }
+ }
+
+ @Test
+ void testInvalidFilterContextFallsBackToCurrentFilter() {
+ connectContext.getSessionVariable().setEagerAggregationMode(1);
+ connectContext.getSessionVariable().setDisableJoinReorder(true);
+ try {
+ String sql = "select count(s.name1), t2.id2"
+ + " from (select * from (select id1, name as name1 from
t1) s1 where s1.name1 is not null) s"
+ + " join t2 on s.id1 = t2.id2 group by t2.id2";
+ Plan plan = PlanChecker.from(connectContext)
+ .analyze(sql)
+ .rewrite()
+ .getPlan();
+ Assertions.assertEquals(2, countPlans(plan,
LogicalAggregate.class), plan.treeString());
+ LogicalFilter<?> filter = findFirstPlan(plan, LogicalFilter.class);
+ Assertions.assertNotNull(filter, plan.treeString());
+ Assertions.assertFalse(containsPlan(filter.child(),
LogicalAggregate.class), plan.treeString());
+ } finally {
+ connectContext.getSessionVariable().setEagerAggregationMode(0);
+ connectContext.getSessionVariable().setDisableJoinReorder(false);
+ }
+ }
+
+ private int countPlans(Plan plan, Class<? extends Plan> clazz) {
+ int count = clazz.isInstance(plan) ? 1 : 0;
+ for (Plan child : plan.children()) {
+ count += countPlans(child, clazz);
+ }
+ return count;
+ }
+
+ private boolean containsPlan(Plan plan, Class<? extends Plan> clazz) {
+ return countPlans(plan, clazz) > 0;
+ }
+
+ private <T extends Plan> T findFirstPlan(Plan plan, Class<T> clazz) {
+ if (clazz.isInstance(plan)) {
+ return clazz.cast(plan);
+ }
+ for (Plan child : plan.children()) {
+ T matched = findFirstPlan(child, clazz);
+ if (matched != null) {
+ return matched;
+ }
+ }
+ return null;
+ }
}
diff --git a/regression-test/data/nereids_p0/eager_agg/eager_agg.out
b/regression-test/data/nereids_p0/eager_agg/eager_agg.out
index 731f2e9bd9e..85d8dcffd15 100644
--- a/regression-test/data/nereids_p0/eager_agg/eager_agg.out
+++ b/regression-test/data/nereids_p0/eager_agg/eager_agg.out
@@ -311,3 +311,76 @@ Used:
UnUsed:
SyntaxError: leading({ ss broadcast dt } broadcast ws) Msg:can not find table:
ws
+-- !check_sum_literal_right_join_not_push --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----hashAgg[LOCAL]
+------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((a.val = c.val) and (b.id2 =
c.id2)) otherCondition=()
+--------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((a.id = b.id))
otherCondition=()
+----------PhysicalOlapScan[eager_agg_t1]
+----------PhysicalOlapScan[eager_agg_t2]
+--------PhysicalOlapScan[eager_agg_t3]
+
+-- !check_sum_literal_left_join_not_push --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----hashAgg[LOCAL]
+------hashJoin[LEFT_OUTER_JOIN] hashCondition=((date_dim.d_date_sk =
store_sales.ss_sold_date_sk)) otherCondition=()
+--------hashAgg[GLOBAL]
+----------hashAgg[LOCAL]
+------------PhysicalOlapScan[store_sales]
+--------PhysicalOlapScan[date_dim]
+
+-- !check_min_literal_right_join_not_push --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----hashAgg[LOCAL]
+------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((a.val = c.val) and (b.id2 =
c.id2)) otherCondition=()
+--------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((a.id = b.id))
otherCondition=()
+----------PhysicalOlapScan[eager_agg_t1]
+----------PhysicalOlapScan[eager_agg_t2]
+--------PhysicalOlapScan[eager_agg_t3]
+
+-- !check_max_literal_left_join_not_push --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----hashAgg[LOCAL]
+------hashJoin[LEFT_OUTER_JOIN] hashCondition=((date_dim.d_date_sk =
store_sales.ss_sold_date_sk)) otherCondition=()
+--------hashAgg[GLOBAL]
+----------hashAgg[LOCAL]
+------------PhysicalOlapScan[store_sales]
+--------PhysicalOlapScan[date_dim]
+
+-- !sum_literal_right_join_eager_off --
+\N 4
+10 2
+
+-- !sum_literal_right_join_eager_on --
+\N 4
+10 2
+
+-- !min_literal_right_join_eager_on --
+\N 1
+10 1
+
+-- !max_literal_right_join_eager_on --
+\N 3
+10 3
+
+-- !check_filter_slots_preserved_pushdown --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----filter(OR[( not (id = 1)),id IS NULL])
+------hashJoin[LEFT_OUTER_JOIN] hashCondition=((a.id = b.id)) otherCondition=()
+--------hashAgg[GLOBAL]
+----------PhysicalOlapScan[eager_agg_filter_t1]
+--------PhysicalOlapScan[eager_agg_filter_t2]
+
+Hint log:
+Used: [broadcast]_1
+UnUsed:
+SyntaxError:
+
+-- !filter_slots_preserved_eager_on --
+2 20
+
diff --git a/regression-test/suites/nereids_p0/eager_agg/eager_agg.groovy
b/regression-test/suites/nereids_p0/eager_agg/eager_agg.groovy
index 4f9653829b3..5d738a962d6 100644
--- a/regression-test/suites/nereids_p0/eager_agg/eager_agg.groovy
+++ b/regression-test/suites/nereids_p0/eager_agg/eager_agg.groovy
@@ -411,4 +411,156 @@ suite("eager_agg") {
) t
group by d_year;
"""
+
+ //
=========================================================================
+ // Tests for agg(literal) on nullable side of outer joins
+ // sum(literal), min(literal), max(literal) should NOT be pushed to the
+ // nullable side of outer joins because unmatched rows lose their
contribution.
+ //
=========================================================================
+
+ sql """
+ drop table if exists eager_agg_t1;
+ drop table if exists eager_agg_t2;
+ drop table if exists eager_agg_t3;
+ drop table if exists eager_agg_filter_t1;
+ drop table if exists eager_agg_filter_t2;
+
+ CREATE TABLE eager_agg_t1 (
+ id INT NOT NULL,
+ val INT
+ ) DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ('replication_num' = '1');
+
+ CREATE TABLE eager_agg_t2 (
+ id INT NOT NULL,
+ id2 INT NOT NULL
+ ) DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ('replication_num' = '1');
+
+ CREATE TABLE eager_agg_t3 (
+ id2 INT NOT NULL,
+ val INT
+ ) DISTRIBUTED BY HASH(id2) BUCKETS 1
+ PROPERTIES ('replication_num' = '1');
+
+ CREATE TABLE eager_agg_filter_t1 (
+ id INT NOT NULL,
+ flag INT NOT NULL,
+ v INT NOT NULL
+ ) DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ('replication_num' = '1');
+
+ CREATE TABLE eager_agg_filter_t2 (
+ id INT NOT NULL
+ ) DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ('replication_num' = '1');
+
+ INSERT INTO eager_agg_t1 VALUES (1, 10);
+ INSERT INTO eager_agg_t2 VALUES (1, 100), (2, 200);
+ INSERT INTO eager_agg_t3 VALUES (100, 10), (200, 20), (300, 30);
+ INSERT INTO eager_agg_filter_t1 VALUES (1, 0, 10), (2, 1, 20);
+ INSERT INTO eager_agg_filter_t2 VALUES (1);
+ """
+
+ // sum(literal) should NOT be pushed below RIGHT JOIN to the nullable left
side
+ qt_check_sum_literal_right_join_not_push """
+ explain shape plan
+ select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/
+ a.val, sum(2) as s
+ from eager_agg_t1 as a
+ right join eager_agg_t2 as b on a.id = b.id
+ right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val
+ group by a.val;
+ """
+
+ // sum(literal) should NOT be pushed below LEFT JOIN to the nullable right
side
+ qt_check_sum_literal_left_join_not_push """
+ explain shape plan
+ select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/
+ ss_sales_price, sum(2) as s
+ from store_sales
+ left join date_dim on d_date_sk = ss_sold_date_sk
+ group by ss_sales_price;
+ """
+
+ // min(literal) should NOT be pushed to nullable side of RIGHT JOIN
+ qt_check_min_literal_right_join_not_push """
+ explain shape plan
+ select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/
+ a.val, min(1) as m
+ from eager_agg_t1 as a
+ right join eager_agg_t2 as b on a.id = b.id
+ right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val
+ group by a.val;
+ """
+
+ // max(literal) should NOT be pushed to nullable side of LEFT JOIN
+ qt_check_max_literal_left_join_not_push """
+ explain shape plan
+ select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/
+ ss_sales_price, max(3) as m
+ from store_sales
+ left join date_dim on d_date_sk = ss_sold_date_sk
+ group by ss_sales_price;
+ """
+
+ // Execution tests: verify eager agg produces correct results for outer
join + literal agg
+ order_qt_sum_literal_right_join_eager_off """
+ select /*+SET_VAR(eager_aggregation_mode=-1)*/ /*+ leading(a b c) */
+ a.val, sum(2) as s
+ from eager_agg_t1 as a
+ right join eager_agg_t2 as b on a.id = b.id
+ right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val
+ group by a.val
+ order by a.val;
+ """
+
+ order_qt_sum_literal_right_join_eager_on """
+ select /*+SET_VAR(eager_aggregation_mode=1)*/ /*+ leading(a b c) */
+ a.val, sum(2) as s
+ from eager_agg_t1 as a
+ right join eager_agg_t2 as b on a.id = b.id
+ right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val
+ group by a.val
+ order by a.val;
+ """
+
+ order_qt_min_literal_right_join_eager_on """
+ select /*+SET_VAR(eager_aggregation_mode=1)*/ /*+ leading(a b c) */
+ a.val, min(1) as m
+ from eager_agg_t1 as a
+ right join eager_agg_t2 as b on a.id = b.id
+ right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val
+ group by a.val
+ order by a.val;
+ """
+
+ order_qt_max_literal_right_join_eager_on """
+ select /*+SET_VAR(eager_aggregation_mode=1)*/ /*+ leading(a b c) */
+ a.val, max(3) as m
+ from eager_agg_t1 as a
+ right join eager_agg_t2 as b on a.id = b.id
+ right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val
+ group by a.val
+ order by a.val;
+ """
+
+ qt_check_filter_slots_preserved_pushdown """
+ explain shape plan
+ select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/
+ a.id, sum(a.v) as s
+ from eager_agg_filter_t1 as a
+ left join[broadcast] eager_agg_filter_t2 as b on a.id = b.id
+ where b.id <> 1 or b.id is null
+ group by a.id;
+ """
+
+ order_qt_filter_slots_preserved_eager_on """
+ select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/
+ a.id, sum(a.v) as s
+ from eager_agg_filter_t1 as a
+ left join[broadcast] eager_agg_filter_t2 as b on a.id = b.id
+ where b.id <> 1 or b.id is null
+ group by a.id;
+ """
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]