diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/RewriteJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/RewriteJob.java index 5ec029005b..e8d347000d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/RewriteJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/RewriteJob.java @@ -31,8 +31,9 @@ import org.apache.doris.nereids.rules.rewrite.logical.MergeConsecutiveProjects; import org.apache.doris.nereids.rules.rewrite.logical.NormalizeAggregate; import org.apache.doris.nereids.rules.rewrite.logical.PruneOlapScanPartition; import org.apache.doris.nereids.rules.rewrite.logical.PushPredicateThroughJoin; +import org.apache.doris.nereids.rules.rewrite.logical.PushdownFilterThroughProject; +import org.apache.doris.nereids.rules.rewrite.logical.PushdownProjectThroughLimit; import org.apache.doris.nereids.rules.rewrite.logical.ReorderJoin; -import org.apache.doris.nereids.rules.rewrite.logical.SwapFilterAndProject; import com.google.common.collect.ImmutableList; @@ -54,6 +55,7 @@ public class RewriteJob extends BatchRulesJob { * 1. Adjust the plan in correlated logicalApply * so that there are no correlated columns in the subquery. * 2. Convert logicalApply to a logicalJoin. + * TODO: group these rules to make sure the result plan is what we expected. */ .addAll(new AdjustApplyFromCorrelatToUnCorrelatJob(cascadesContext).rulesJob) .addAll(new ConvertApplyToJoinJob(cascadesContext).rulesJob) @@ -65,7 +67,8 @@ public class RewriteJob extends BatchRulesJob { .add(topDownBatch(ImmutableList.of(new NormalizeAggregate()))) .add(topDownBatch(ImmutableList.of(new ColumnPruning()))) .add(topDownBatch(ImmutableList.of(new AggregateDisassemble()))) - .add(topDownBatch(ImmutableList.of(new SwapFilterAndProject()))) + .add(topDownBatch(ImmutableList.of(new PushdownProjectThroughLimit()))) + .add(topDownBatch(ImmutableList.of(new PushdownFilterThroughProject()))) .add(bottomUpBatch(ImmutableList.of(new MergeConsecutiveProjects()))) .add(topDownBatch(ImmutableList.of(new MergeConsecutiveFilters()))) .add(bottomUpBatch(ImmutableList.of(new MergeConsecutiveLimits()))) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java index 31a028eb9e..78b2a42d33 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java @@ -105,6 +105,7 @@ public enum RuleType { OLAP_SCAN_PARTITION_PRUNE(RuleTypeClass.REWRITE), SWAP_FILTER_AND_PROJECT(RuleTypeClass.REWRITE), LOGICAL_LIMIT_TO_LOGICAL_EMPTY_RELATION_RULE(RuleTypeClass.REWRITE), + SWAP_LIMIT_PROJECT(RuleTypeClass.REWRITE), // exploration rules TEST_EXPLORATION(RuleTypeClass.EXPLORATION), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/SwapFilterAndProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownFilterThroughProject.java similarity index 96% rename from fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/SwapFilterAndProject.java rename to fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownFilterThroughProject.java index 7d6b0e46f7..aab04a0ac6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/SwapFilterAndProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownFilterThroughProject.java @@ -32,7 +32,7 @@ import org.apache.doris.nereids.util.ExpressionUtils; * output: * project(c+d as a, e as b) -> filter(c+d>2, e=0). */ -public class SwapFilterAndProject extends OneRewriteRuleFactory { +public class PushdownFilterThroughProject extends OneRewriteRuleFactory { @Override public Rule build() { return logicalFilter(logicalProject()).then(filter -> { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownProjectThroughLimit.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownProjectThroughLimit.java new file mode 100644 index 0000000000..230e5f2e98 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownProjectThroughLimit.java @@ -0,0 +1,59 @@ +// 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.logical; + +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; +import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory; +import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; +import org.apache.doris.nereids.trees.plans.logical.LogicalProject; + +/** + * Before: + * project + * │ + * ▼ + * limit + * │ + * ▼ + * plan node + * + * After: + * + * limit + * │ + * ▼ + * project + * │ + * ▼ + * plan node + */ +public class PushdownProjectThroughLimit extends OneRewriteRuleFactory { + + @Override + public Rule build() { + return logicalProject(logicalLimit(group())).thenApply(ctx -> { + LogicalProject> logicalProject = ctx.root; + LogicalLimit logicalLimit = logicalProject.child(); + return new LogicalLimit>(logicalLimit.getLimit(), + logicalLimit.getOffset(), new LogicalProject<>(logicalProject.getProjects(), + logicalLimit.child())); + }).toRule(RuleType.SWAP_LIMIT_PROJECT); + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownProjectThroughLimitTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownProjectThroughLimitTest.java new file mode 100644 index 0000000000..602f4c7251 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownProjectThroughLimitTest.java @@ -0,0 +1,49 @@ +// 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.logical; + +import org.apache.doris.nereids.CascadesContext; +import org.apache.doris.nereids.trees.expressions.SlotReference; +import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; +import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; +import org.apache.doris.nereids.trees.plans.logical.LogicalProject; +import org.apache.doris.nereids.types.IntegerType; + +import com.google.common.collect.ImmutableList; +import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class PushdownProjectThroughLimitTest { + + @Mocked + private CascadesContext cascadesContext; + + @Test + public void testPushdownProjectThroughLimit(@Mocked GroupPlan groupPlan) { + SlotReference slotRef = new SlotReference("col1", IntegerType.INSTANCE); + LogicalLimit logicalLimit = new LogicalLimit(1, 1, groupPlan); + LogicalProject logicalProject = new LogicalProject(ImmutableList.of(slotRef), logicalLimit); + PushdownProjectThroughLimit pushdownProjectThroughLimit = new PushdownProjectThroughLimit(); + LogicalPlan rewrittenPlan = + (LogicalPlan) pushdownProjectThroughLimit.build().transform(logicalProject, cascadesContext).get(0); + Assertions.assertTrue(rewrittenPlan instanceof LogicalLimit); + Assertions.assertTrue(rewrittenPlan.child(0) instanceof LogicalProject); + } +}