This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.0 by this push:
new 41e95bd0089 branch-4.0: [fix](rbo) use wrong child's output of set
operation #59105 (#59131)
41e95bd0089 is described below
commit 41e95bd008912ccdaeb0ca56d5e0cd4c7c0295f6
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Dec 18 17:59:37 2025 +0800
branch-4.0: [fix](rbo) use wrong child's output of set operation #59105
(#59131)
Cherry-picked from #59105
Co-authored-by: morrySnow <[email protected]>
---
.../rules/rewrite/EliminateEmptyRelation.java | 94 ++++++++++------------
.../data/empty_relation/eliminate_empty.out | 17 ++--
.../infer_predicate/pull_up_predicate_set_op.out | 4 +-
3 files changed, 50 insertions(+), 65 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateEmptyRelation.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateEmptyRelation.java
index e62716b2879..55e79e4742e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateEmptyRelation.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateEmptyRelation.java
@@ -23,7 +23,6 @@ import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.UnaryNode;
import org.apache.doris.nereids.trees.expressions.Alias;
import org.apache.doris.nereids.trees.expressions.ExprId;
-import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
@@ -34,12 +33,10 @@ import
org.apache.doris.nereids.trees.plans.algebra.SetOperation;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
-import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import org.apache.doris.qe.ConnectContext;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
import java.util.List;
import java.util.Optional;
@@ -85,13 +82,20 @@ public class EliminateEmptyRelation implements
RewriteRuleFactory {
}).toRule(RuleType.ELIMINATE_AGG_ON_EMPTYRELATION),
// after BuildAggForUnion rule, union may have more than 2
children.
logicalUnion(multi()).then(union -> {
- if (union.children().isEmpty()) {
- // example: select * from (select 1,2 union select 3, 4) T;
- // the children size is 0. (1,2) and (3,4) are stored in
union.constantExprsList
+ boolean needProcess = union.arity() == 1;
+ for (int i = 0; i < union.arity(); i++) {
+ if (union.child(i) instanceof EmptyRelation) {
+ needProcess = true;
+ break;
+ }
+ }
+ if (!needProcess) {
return null;
}
- ImmutableList.Builder<Plan> nonEmptyChildrenBuilder =
ImmutableList.builder();
- ImmutableList.Builder<List<SlotReference>>
nonEmptyOutputsBuilder = ImmutableList.builder();
+ ImmutableList.Builder<Plan> nonEmptyChildrenBuilder
+ = ImmutableList.builderWithExpectedSize(union.arity());
+ ImmutableList.Builder<List<SlotReference>>
nonEmptyOutputsBuilder
+ = ImmutableList.builderWithExpectedSize(union.arity());
for (int i = 0; i < union.arity(); i++) {
if (!(union.child(i) instanceof EmptyRelation)) {
nonEmptyChildrenBuilder.add(union.child(i));
@@ -99,54 +103,30 @@ public class EliminateEmptyRelation implements
RewriteRuleFactory {
}
}
List<Plan> nonEmptyChildren = nonEmptyChildrenBuilder.build();
+ List<List<SlotReference>> nonEmptyOutputs =
nonEmptyOutputsBuilder.build();
if (nonEmptyChildren.isEmpty()) {
if (union.getConstantExprsList().isEmpty()) {
return new LogicalEmptyRelation(
ConnectContext.get().getStatementContext().getNextRelationId(),
union.getOutput());
- } else if (union.getConstantExprsList().size() == 1) {
- List<NamedExpression> constantExprs =
union.getConstantExprsList().get(0);
- ImmutableList.Builder<NamedExpression>
newOneRowRelationOutput
- =
ImmutableList.builderWithExpectedSize(constantExprs.size());
- for (int i = 0; i < constantExprs.size(); i++) {
- NamedExpression setOutput =
union.getOutput().get(i);
- NamedExpression constantExpr =
constantExprs.get(i);
- Expression realConstantExpr = constantExpr
instanceof Alias
- ? ((Alias) constantExpr).child() :
constantExpr;
- Alias oneRowRelationOutput = new Alias(
- setOutput.getExprId(), realConstantExpr,
setOutput.getName());
- newOneRowRelationOutput.add(oneRowRelationOutput);
- }
- return new LogicalOneRowRelation(
-
ConnectContext.get().getStatementContext().getNextRelationId(),
- newOneRowRelationOutput.build());
} else {
return
union.withChildrenAndTheirOutputs(ImmutableList.of(), ImmutableList.of());
}
} else if (nonEmptyChildren.size() == 1) {
if (union.getConstantExprsList().isEmpty()) {
- Plan child = nonEmptyChildren.get(0);
+ ImmutableList.Builder<NamedExpression> projectsBuilder
= ImmutableList.builder();
List<Slot> unionOutput = union.getOutput();
- int childIdx =
union.children().indexOf(nonEmptyChildren.get(0));
- if (childIdx >= 0) {
- List<SlotReference> childOutput =
union.getRegularChildOutput(childIdx);
- List<NamedExpression> projects =
Lists.newArrayList();
- for (int i = 0; i < unionOutput.size(); i++) {
- ExprId id = unionOutput.get(i).getExprId();
- Alias alias = new Alias(id,
childOutput.get(i), unionOutput.get(i).getName());
- projects.add(alias);
- }
-
- return new LogicalProject<>(projects, child);
- } else {
- // should not hit here.
- return null;
+ for (int i = 0; i < unionOutput.size(); i++) {
+ ExprId id = unionOutput.get(i).getExprId();
+ Alias alias = new Alias(id,
nonEmptyOutputs.get(0).get(i), unionOutput.get(i).getName());
+ projectsBuilder.add(alias);
}
+ return new LogicalProject<>(projectsBuilder.build(),
nonEmptyChildren.get(0));
}
}
if (union.children().size() != nonEmptyChildren.size()) {
- return union.withChildrenAndTheirOutputs(nonEmptyChildren,
nonEmptyOutputsBuilder.build());
+ return union.withChildrenAndTheirOutputs(nonEmptyChildren,
nonEmptyOutputs);
} else {
// no empty relation child, do not change union
return null;
@@ -192,8 +172,20 @@ public class EliminateEmptyRelation implements
RewriteRuleFactory {
ConnectContext.get().getStatementContext().getNextRelationId(),
except.getOutput());
} else {
- ImmutableList.Builder<Plan> nonEmptyChildrenBuilder =
ImmutableList.builder();
- ImmutableList.Builder<List<SlotReference>>
nonEmptyOutputsBuilder = ImmutableList.builder();
+ boolean needProcess = false;
+ for (int i = 1; i < except.arity(); i++) {
+ if (except.child(i) instanceof EmptyRelation) {
+ needProcess = true;
+ break;
+ }
+ }
+ if (!needProcess) {
+ return null;
+ }
+ ImmutableList.Builder<Plan> nonEmptyChildrenBuilder
+ =
ImmutableList.builderWithExpectedSize(except.arity());
+ ImmutableList.Builder<List<SlotReference>>
nonEmptyOutputsBuilder
+ =
ImmutableList.builderWithExpectedSize(except.arity());
for (int i = 0; i < except.arity(); i++) {
if (!(except.child(i) instanceof EmptyRelation)) {
nonEmptyChildrenBuilder.add(except.child(i));
@@ -201,31 +193,27 @@ public class EliminateEmptyRelation implements
RewriteRuleFactory {
}
}
List<Plan> nonEmptyChildren =
nonEmptyChildrenBuilder.build();
+ List<List<SlotReference>> nonEmptyOutputs =
nonEmptyOutputsBuilder.build();
if (nonEmptyChildren.size() == 1) {
// the first child is not empty, others are all empty
// case 1. FIRST except(distinct) empty = >
project(AGG(FIRST))
// case 2. FIRST except(all) empty = > project(FIRST)
Plan projectChild;
if (except.getQualifier() ==
SetOperation.Qualifier.DISTINCT) {
- List<NamedExpression> firstOutputNamedExpressions
= first.getOutput()
- .stream().map(slot -> (NamedExpression)
slot)
- .collect(ImmutableList.toImmutableList());
- projectChild = new
LogicalAggregate<>(ImmutableList.copyOf(firstOutputNamedExpressions),
- firstOutputNamedExpressions, true,
Optional.empty(), first);
+ projectChild = new LogicalAggregate<>((List)
nonEmptyOutputs.get(0),
+ (List) nonEmptyOutputs.get(0), true,
Optional.empty(), first);
} else {
projectChild = first;
}
List<Slot> exceptOutput = except.getOutput();
- List<Slot> projectInputSlots =
projectChild.getOutput();
- List<NamedExpression> projects = Lists.newArrayList();
+ List<SlotReference> projectInputSlots =
nonEmptyOutputs.get(0);
+ ImmutableList.Builder<NamedExpression> projectsBuilder
= ImmutableList.builder();
for (int i = 0; i < exceptOutput.size(); i++) {
ExprId id = exceptOutput.get(i).getExprId();
Alias alias = new Alias(id,
projectInputSlots.get(i), exceptOutput.get(i).getName());
- projects.add(alias);
+ projectsBuilder.add(alias);
}
- return new LogicalProject<>(projects, projectChild);
- } else if (nonEmptyChildren.size() ==
except.children().size()) {
- return null;
+ return new LogicalProject<>(projectsBuilder.build(),
projectChild);
} else {
return
except.withChildrenAndTheirOutputs(nonEmptyChildren,
nonEmptyOutputsBuilder.build());
}
diff --git a/regression-test/data/empty_relation/eliminate_empty.out
b/regression-test/data/empty_relation/eliminate_empty.out
index 804cbb486bd..5379d0775a6 100644
--- a/regression-test/data/empty_relation/eliminate_empty.out
+++ b/regression-test/data/empty_relation/eliminate_empty.out
@@ -142,22 +142,19 @@ PhysicalResultSink
-- !union_to_onerow_1_shape --
PhysicalResultSink
---PhysicalDistribute[DistributionSpecGather]
-----hashAgg[GLOBAL]
-------PhysicalDistribute[DistributionSpecHash]
---------hashAgg[LOCAL]
-----------PhysicalOneRowRelation
+--PhysicalLimit[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------PhysicalProject
+--------PhysicalUnion
-- !union_to_onerow_2 --
1 2
-- !union_to_onerow_2_shape --
PhysicalResultSink
---PhysicalDistribute[DistributionSpecGather]
-----hashAgg[GLOBAL]
-------PhysicalDistribute[DistributionSpecHash]
---------hashAgg[LOCAL]
-----------PhysicalOneRowRelation
+--PhysicalLimit[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------PhysicalUnion
-- !prune_partition1 --
PhysicalResultSink
diff --git
a/regression-test/data/nereids_rules_p0/infer_predicate/pull_up_predicate_set_op.out
b/regression-test/data/nereids_rules_p0/infer_predicate/pull_up_predicate_set_op.out
index a7ac6765f62..24759dc8576 100644
---
a/regression-test/data/nereids_rules_p0/infer_predicate/pull_up_predicate_set_op.out
+++
b/regression-test/data/nereids_rules_p0/infer_predicate/pull_up_predicate_set_op.out
@@ -139,8 +139,8 @@ PhysicalResultSink
-- !union_all_const_empty_relation --
PhysicalResultSink
---hashJoin[INNER_JOIN] hashCondition=((t3.a = expr_cast(a as INT)) and (t3.b =
t.b)) otherCondition=()
-----PhysicalOneRowRelation
+--NestedLoopJoin[INNER_JOIN]
+----PhysicalUnion
----filter((t3.a = 2) and (t3.b = 'dd'))
------PhysicalOlapScan[test_pull_up_predicate_set_op3]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]