This is an automated email from the ASF dual-hosted git repository. morrysnow pushed a commit to branch pick_3.1_59105 in repository https://gitbox.apache.org/repos/asf/doris.git
commit cc738779cdbd74d58efd0a1a8a560aad4dddc800 Author: morrySnow <[email protected]> AuthorDate: Thu Dec 18 10:30:20 2025 +0800 branch-3.1: [fix](rbo) use wrong child's output of set operation #59105 picked from #59105 --- .../rules/rewrite/EliminateEmptyRelation.java | 76 ++++++++++++---------- 1 file changed, 41 insertions(+), 35 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 44c042687a9..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 @@ -37,7 +37,6 @@ 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; @@ -83,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)); @@ -97,6 +103,7 @@ 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( @@ -107,28 +114,19 @@ public class EliminateEmptyRelation implements RewriteRuleFactory { } } 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; @@ -174,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)); @@ -183,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()); } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
