From 35a65c5e1182e4cf274d9cef07be757cc719f9df Mon Sep 17 00:00:00 2001 From: stdpain Date: Fri, 3 Jan 2025 13:56:35 +0800 Subject: [PATCH 1/2] [BugFix] Fix wrong plan when apply offset limit in PushDown Project limit Signed-off-by: stdpain --- .../transformation/PushDownProjectLimitRule.java | 5 +++++ .../java/com/starrocks/sql/plan/LimitTest.java | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/PushDownProjectLimitRule.java b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/PushDownProjectLimitRule.java index 9d50db92d061b..cb8572abd971d 100644 --- a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/PushDownProjectLimitRule.java +++ b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/PushDownProjectLimitRule.java @@ -54,6 +54,11 @@ public boolean check(OptExpression input, OptimizerContext context) { @Override public List transform(OptExpression project, OptimizerContext context) { LogicalLimitOperator limit = (LogicalLimitOperator) project.getInputs().get(0).getOp(); + if (project.getOp().hasLimit() && limit.hasOffset()) { + long projectLimit = project.getOp().getLimit(); + project.getOp().setLimit(limit.getOffset() + limit.getLimit()); + limit.setLimit(Math.min(projectLimit, limit.getLimit())); + } return Lists.newArrayList(OptExpression.create(limit, OptExpression.create(project.getOp(), project.getInputs().get(0).getInputs()))); } diff --git a/fe/fe-core/src/test/java/com/starrocks/sql/plan/LimitTest.java b/fe/fe-core/src/test/java/com/starrocks/sql/plan/LimitTest.java index 0846a1fb078ff..2e135ccd1f371 100644 --- a/fe/fe-core/src/test/java/com/starrocks/sql/plan/LimitTest.java +++ b/fe/fe-core/src/test/java/com/starrocks/sql/plan/LimitTest.java @@ -655,6 +655,22 @@ public void testOffsetWithSubTopN() throws Exception { " limit: 400"); } + @Test + public void testPushDownLimitToTopN() throws Exception { + connectContext.getSessionVariable().setOptimizerExecuteTimeout(3000000); + String sql; + String plan; + sql = "select c0 from (select * from ( select v1 c0, v2 c1 from t0 order by c0 asc limit 1000, 600 ) l " + + "union all select 0 as c0, '0' as c1 ) b limit 100;"; + plan = getFragmentPlan(sql); + assertContains(plan, " 2:TOP-N\n" + + " | order by: 1: v1 ASC\n" + + " | offset: 0\n" + + " | limit: 1100\n" + + " | \n" + + " 1:OlapScanNode"); + } + @Test public void testUnionLimit() throws Exception { String queryStr = "select 1 from (select 4, 3 from t0 union all select 2, 3 ) as a limit 3"; From 48349ec759f85cb387c5dce6839a495b72bd97ba Mon Sep 17 00:00:00 2001 From: stdpain Date: Fri, 3 Jan 2025 14:23:37 +0800 Subject: [PATCH 2/2] fix comments Signed-off-by: stdpain --- .../rule/transformation/PushDownProjectLimitRule.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/PushDownProjectLimitRule.java b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/PushDownProjectLimitRule.java index cb8572abd971d..31df09cbb576c 100644 --- a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/PushDownProjectLimitRule.java +++ b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/PushDownProjectLimitRule.java @@ -18,6 +18,7 @@ import com.google.common.collect.Lists; import com.starrocks.sql.optimizer.OptExpression; import com.starrocks.sql.optimizer.OptimizerContext; +import com.starrocks.sql.optimizer.operator.Operator; import com.starrocks.sql.optimizer.operator.OperatorType; import com.starrocks.sql.optimizer.operator.logical.LogicalLimitOperator; import com.starrocks.sql.optimizer.operator.pattern.Pattern; @@ -54,10 +55,9 @@ public boolean check(OptExpression input, OptimizerContext context) { @Override public List transform(OptExpression project, OptimizerContext context) { LogicalLimitOperator limit = (LogicalLimitOperator) project.getInputs().get(0).getOp(); + // clear the project limit when limit has offset if (project.getOp().hasLimit() && limit.hasOffset()) { - long projectLimit = project.getOp().getLimit(); - project.getOp().setLimit(limit.getOffset() + limit.getLimit()); - limit.setLimit(Math.min(projectLimit, limit.getLimit())); + project.getOp().setLimit(Operator.DEFAULT_LIMIT); } return Lists.newArrayList(OptExpression.create(limit, OptExpression.create(project.getOp(), project.getInputs().get(0).getInputs())));