This is an automated email from the ASF dual-hosted git repository. dataroaring pushed a commit to branch branch-3.0 in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.0 by this push: new 785fb1a0d85 branch-3.0: [fix](nereids) project child output to union output in correct order after eliminate empty relation #49257 (#49463) 785fb1a0d85 is described below commit 785fb1a0d85129e20fb0449edd2983a544641cfe Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> AuthorDate: Thu Mar 27 17:44:26 2025 +0800 branch-3.0: [fix](nereids) project child output to union output in correct order after eliminate empty relation #49257 (#49463) Cherry-picked from #49257 Co-authored-by: minghong <zhoumingh...@selectdb.com> --- .../rules/rewrite/EliminateEmptyRelation.java | 22 ++- .../rules/rewrite/EliminateEmptyRelationTest.java | 92 +++++++++++ .../suites/empty_relation/eliminate_empty.groovy | 173 +++++++++++++++++++++ 3 files changed, 279 insertions(+), 8 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 c45d55bb8ef..44c042687a9 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 @@ -109,15 +109,21 @@ public class EliminateEmptyRelation implements RewriteRuleFactory { if (union.getConstantExprsList().isEmpty()) { Plan child = nonEmptyChildren.get(0); List<Slot> unionOutput = union.getOutput(); - List<Slot> childOutput = child.getOutput(); - 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); - } + 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); + return new LogicalProject<>(projects, child); + } else { + // should not hit here. + return null; + } } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateEmptyRelationTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateEmptyRelationTest.java new file mode 100644 index 00000000000..cf5752e63eb --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateEmptyRelationTest.java @@ -0,0 +1,92 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.rules.rewrite; + +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.plans.Plan; +import org.apache.doris.nereids.trees.plans.RelationId; +import org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier; +import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; +import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; +import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; +import org.apache.doris.nereids.trees.plans.logical.LogicalUnion; +import org.apache.doris.nereids.types.IntegerType; +import org.apache.doris.nereids.types.StringType; +import org.apache.doris.nereids.util.MemoPatternMatchSupported; +import org.apache.doris.nereids.util.MemoTestUtils; +import org.apache.doris.nereids.util.PlanChecker; +import org.apache.doris.nereids.util.PlanConstructor; + +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tests for {@link EliminateEmptyRelation}. + */ +class EliminateEmptyRelationTest implements MemoPatternMatchSupported { + private static final LogicalOlapScan scan1 = PlanConstructor.newLogicalOlapScan(0, "t1", 0); + + @Test + void testEliminateUnionEmptyChild() { + List<SlotReference> emptyOutput = new ArrayList<>(); + emptyOutput.add(new SlotReference("k", IntegerType.INSTANCE)); + emptyOutput.add(new SlotReference("v", StringType.INSTANCE)); + LogicalEmptyRelation emptyRelation = new LogicalEmptyRelation(new RelationId(1000), emptyOutput); + + List<Plan> children = new ArrayList<>(); + children.add(scan1); + children.add(emptyRelation); + + List<Slot> scan1Output = scan1.getOutput(); + + List<NamedExpression> unionOutput = new ArrayList<>(); + unionOutput.add(scan1Output.get(1)); + unionOutput.add(scan1Output.get(0)); + + List<List<SlotReference>> regularOutput = new ArrayList<>(); + regularOutput.add(Lists.newArrayList((SlotReference) scan1Output.get(1), (SlotReference) scan1Output.get(0))); + regularOutput.add(Lists.newArrayList(emptyOutput.get(1), emptyOutput.get(0))); + + List<List<NamedExpression>> constantExprsList = new ArrayList<>(); + LogicalPlan union = new LogicalUnion(Qualifier.ALL, unionOutput, regularOutput, constantExprsList, + false, children); + + PlanChecker checker = PlanChecker.from(MemoTestUtils.createConnectContext(), union) + .applyTopDown(new EliminateEmptyRelation()); + Plan plan = checker.getPlan(); + System.out.println(plan.treeString()); + /* + * LogicalProject[16] ( distinct=false, projects=[name#10003 AS `name`#10003, id#10002 AS `id`#10002] ) + * +--LogicalOlapScan ( qualified=db.t1, indexName=<index_not_selected>, selectedIndexId=-1, preAgg=UNSET, operativeCol=[] ) + */ + //make sure project matches output column to the correct child output column + checker.matches(logicalProject().when(project -> { + NamedExpression name = project.getProjects().get(0); + Assertions.assertEquals("name", name.getName()); + Assertions.assertInstanceOf(SlotReference.class, name.child(0)); + Assertions.assertEquals("name", name.child(0).getExpressionName()); + return true; + })); + } +} diff --git a/regression-test/suites/empty_relation/eliminate_empty.groovy b/regression-test/suites/empty_relation/eliminate_empty.groovy index afe0a1ce487..13893c4976e 100644 --- a/regression-test/suites/empty_relation/eliminate_empty.groovy +++ b/regression-test/suites/empty_relation/eliminate_empty.groovy @@ -320,4 +320,177 @@ suite("eliminate_empty") { sql """drop table if exists table_5_undef_partitions2_keys3""" sql """drop table if exists table_10_undef_partitions2_keys3""" } + + // union(A, empty) => A + sql """ + set disable_nereids_rules=''; + drop table if exists dwd_bill_fact_bill_standard_info; + drop table if exists ods_bill_fact_bill_jingdong_coupon; + CREATE TABLE `dwd_bill_fact_bill_standard_info` ( + `tenant_id` bigint NULL, + `event_day` date NULL, + `platform` varchar(60) NULL, + `trade_order_no` varchar(192) NULL, + `bill_order_no` varchar(150) NULL, + `item_type` varchar(256) NULL, + `fa_type` varchar(384) NULL, + `id` bigint NULL, + `bill_name` varchar(150) NULL, + `bill_platform` varchar(60) NULL, + `sub_bill_platform` varchar(20) NULL COMMENT '平台子类型 ', + `account_no` varchar(150) NULL, + `shop_id` bigint NULL, + `shop_name` varchar(150) NULL, + `business_year` int NULL, + `business_mouth` int NULL, + `import_date` datetime NULL, + `input_method` varchar(60) NULL, + `import_code` bigint NULL, + `import_name` varchar(60) NULL, + `original_order_no` varchar(150) NULL, + `refund_order_no` varchar(50) NULL COMMENT '退款单号 ', + `bill_type` varchar(60) NULL, + `fa_order_no` varchar(120) NULL, + `sub_fa_type` text NULL, + `time_of_expense` datetime NULL, + `refund_time` datetime NULL COMMENT '退款时间 ', + `fa_settlement_time` datetime NULL, + `goods_name` varchar(765) NULL, + `opt_pay_account` varchar(150) NULL, + `account_name` varchar(150) NULL, + `actual_amount` decimal(19,4) NULL, + `income_out_direction` tinyint NULL, + `balance` decimal(19,4) NULL, + `amount_unit` varchar(30) NULL, + `amount_field_name` varchar(128) NULL COMMENT '金额字段名称 ', + `currency_id` int NULL, + `currency` varchar(30) NULL, + `business_channel` varchar(120) NULL, + `document_type` varchar(30) NULL, + `remark` varchar(765) NULL, + `abstracts` varchar(765) NULL, + `sub_order_no` varchar(150) NULL, + `seq` tinyint NULL, + `original_id` bigint NULL, + `original_goods_id` bigint NULL, + `plat_spec_id` bigint NULL COMMENT '平台规格ID ', + `create_time` datetime NULL, + `update_time` datetime NULL, + `creator_id` bigint NULL, + `updater_id` bigint NULL, + `version_no` bigint NULL, + `is_delete_doris` tinyint NULL COMMENT 'doris删除标记' + ) ENGINE=OLAP + UNIQUE KEY(`tenant_id`, `event_day`, `platform`, `trade_order_no`, `bill_order_no`, `item_type`, `fa_type`) + DISTRIBUTED BY HASH(`platform`) BUCKETS 1 + properties("replication_num" = "1"); + + CREATE TABLE `ods_bill_fact_bill_jingdong_coupon` ( + `tenant_id` bigint NOT NULL COMMENT '商户号', + `event_day` date NOT NULL COMMENT '分区', + `shop_id` bigint NOT NULL COMMENT '商店id', + `bill_coupon_id` varchar(150) NOT NULL COMMENT '生成优惠券号', + `coupon_name` varchar(765) NULL COMMENT '优惠券名称', + `shop_name` varchar(765) NULL COMMENT '店铺名称', + `effect_date` varchar(150) NULL COMMENT '作用日期', + `coupon_type` varchar(150) NULL COMMENT '优惠券类型', + `coupon_batch_code` varchar(150) NULL, + `coupon_code` varchar(150) NULL COMMENT '优惠券码', + `sku_id` varchar(150) NULL, + `money` decimal(19,4) NULL COMMENT '优惠券金额', + `contribute_party` varchar(150) NULL COMMENT '承担方', + `occur_time` datetime NULL, + `billing_time` datetime NULL, + `fee_settlement_time` datetime NULL, + `fa_settlement_time` datetime NULL COMMENT '业务日期', + `settlement_status` varchar(150) NULL COMMENT '结算状态', + `account_id` varchar(150) NULL COMMENT '账户id', + `account_no` varchar(150) NULL COMMENT '账号', + `trade_order_no` varchar(150) NULL COMMENT '商品编号', + `create_time` datetime NULL COMMENT '创建时间', + `update_time` datetime NULL COMMENT '修改时间', + `creator_id` bigint NULL COMMENT '创建人', + `updater_id` bigint NULL COMMENT '分区', + `currency_id` int NULL COMMENT '分区', + `version_no` bigint NULL COMMENT '分区', + `is_delete_doris` tinyint NULL COMMENT 'doris删除标记', + `summary_number` varchar(150) NULL + ) ENGINE=OLAP + UNIQUE KEY(`tenant_id`, `event_day`, `shop_id`, `bill_coupon_id`) + COMMENT 'OLAP' + DISTRIBUTED BY HASH(`shop_id`) BUCKETS 1 + properties("replication_num" = "1"); + + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-10',-21911.4800); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-18',2592.5400); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-30',2218.4700); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-12',2940.4100); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-20',-25357.9600); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-24',-10754.1800); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-06',3089.6400); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-09',3066.7900); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-17',2271.7500); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-27',2290.4900); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-29',2363.7300); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-03',3664.7300); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-05',3014.6100); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-23',3175.2100); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-15',2622.6600); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-07',3444.7800); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-19',3348.2700); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-31',2003.6000); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-13',3981.9000); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-21',2850.0000); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-01',2543.0300); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-11',3671.9000); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-25',3303.3500); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-08',2510.0500); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-16',2869.5100); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-28',2405.4000); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-02',-65854.8900); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-04',3229.0900); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-14',1486.5400); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-22',3476.0100); + insert into dwd_bill_fact_bill_standard_info(tenant_id,shop_id,event_day,actual_amount) values(1548,102,'2025-01-26',2745.2200); + set parallel_pipeline_task_num=1; + """ + + sql """ + SELECT + sum(s.actual_amount) sum_amount, + sum(cnt) sum_no + FROM + ( + SELECT + tenant_id, + shop_id, + event_day, + sum(actual_amount) actual_amount, + count(*) cnt + FROM + dwd_bill_fact_bill_standard_info + group by + tenant_id, + shop_id, + event_day + union + all + select + tenant_id, + shop_id, + event_day, + sum(money) actual_amount, + count(*) cnt + from + ods_bill_fact_bill_jingdong_coupon + group by + tenant_id, + shop_id, + event_day + ) s + group by + s.tenant_id, + s.event_day, + s.shop_id; + """ } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org