diff --git a/src/backend/distributed/planner/distributed_planner.c b/src/backend/distributed/planner/distributed_planner.c index 6222d3ebf..dfd1cd5f6 100644 --- a/src/backend/distributed/planner/distributed_planner.c +++ b/src/backend/distributed/planner/distributed_planner.c @@ -266,19 +266,6 @@ distributed_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) * which we're unable to handle. Meanwhile we only optimize rewrites to Const. * So deoptimize non-Const LIMIT/OFFSET, standard_planner will handle it again later. */ - if (planContext.query->limitCount && - !IsA(planContext.query->limitCount, Const)) - { - planContext.query->limitCount = planContext.originalQuery->limitCount; - } - - if (planContext.query->limitOffset && - !IsA(planContext.query->limitOffset, Const)) - { - planContext.query->limitOffset = - planContext.originalQuery->limitOffset; - } - result = PlanDistributedStmt(&planContext, rteIdCounter); } else if ((result = TryToDelegateFunctionCall(&planContext)) == NULL) diff --git a/src/backend/distributed/planner/multi_logical_optimizer.c b/src/backend/distributed/planner/multi_logical_optimizer.c index 1343248c0..d23ab6439 100644 --- a/src/backend/distributed/planner/multi_logical_optimizer.c +++ b/src/backend/distributed/planner/multi_logical_optimizer.c @@ -1486,6 +1486,8 @@ MasterExtendedOpNode(MultiExtendedOp *originalOpNode, masterExtendedOpNode->sortClauseList = originalOpNode->sortClauseList; masterExtendedOpNode->distinctClause = originalOpNode->distinctClause; masterExtendedOpNode->hasDistinctOn = originalOpNode->hasDistinctOn; + masterExtendedOpNode->originalLimitCount = originalOpNode->originalLimitCount; + masterExtendedOpNode->originalLimitOffset = originalOpNode->originalLimitOffset; masterExtendedOpNode->limitCount = originalOpNode->limitCount; masterExtendedOpNode->limitOffset = originalOpNode->limitOffset; masterExtendedOpNode->havingQual = newHavingQual; @@ -2314,6 +2316,7 @@ WorkerExtendedOpNode(MultiExtendedOp *originalOpNode, workerExtendedOpNode->hasWindowFuncs = queryWindowClause.hasWindowFunctions; workerExtendedOpNode->windowClause = queryWindowClause.workerWindowClauseList; workerExtendedOpNode->sortClauseList = queryOrderByLimit.workerSortClauseList; + workerExtendedOpNode->originalLimitCount = queryOrderByLimit.workerLimitCount; workerExtendedOpNode->limitCount = queryOrderByLimit.workerLimitCount; return workerExtendedOpNode; diff --git a/src/backend/distributed/planner/multi_logical_planner.c b/src/backend/distributed/planner/multi_logical_planner.c index 4d30a11d3..9d2ce45de 100644 --- a/src/backend/distributed/planner/multi_logical_planner.c +++ b/src/backend/distributed/planner/multi_logical_planner.c @@ -157,7 +157,7 @@ MultiLogicalPlanCreate(Query *originalQuery, Query *queryTree, } else { - multiQueryNode = MultiNodeTree(queryTree); + multiQueryNode = MultiNodeTree(originalQuery, queryTree); } /* add a root node to serve as the permanent handle to the tree */ @@ -640,7 +640,7 @@ SubqueryEntryList(Query *queryTree) * group, and limit nodes if they appear in the original query tree. */ MultiNode * -MultiNodeTree(Query *queryTree) +MultiNodeTree(Query *originalQuery, Query *queryTree) { List *rangeTableList = queryTree->rtable; List *targetEntryList = queryTree->targetList; @@ -672,7 +672,7 @@ MultiNodeTree(Query *queryTree) * If we have a subquery, build a multi table node for the subquery and * add a collect node on top of the multi table node. */ - List *subqueryEntryList = SubqueryEntryList(queryTree); + List *subqueryEntryList = SubqueryEntryList(originalQuery); if (subqueryEntryList != NIL) { MultiCollect *subqueryCollectNode = CitusMakeNode(MultiCollect); @@ -715,7 +715,7 @@ MultiNodeTree(Query *queryTree) } /* recursively create child nested multitree */ - MultiNode *subqueryExtendedNode = MultiNodeTree(subqueryTree); + MultiNode *subqueryExtendedNode = MultiNodeTree(subqueryTree, subqueryTree); SetChild((MultiUnaryNode *) subqueryCollectNode, (MultiNode *) subqueryNode); SetChild((MultiUnaryNode *) subqueryNode, subqueryExtendedNode); @@ -769,7 +769,7 @@ MultiNodeTree(Query *queryTree) * distinguish between aggregates and expressions; and we address this later * in the logical optimizer. */ - MultiExtendedOp *extendedOpNode = MultiExtendedOpNode(queryTree, queryTree); + MultiExtendedOp *extendedOpNode = MultiExtendedOpNode(originalQuery, queryTree); SetChild((MultiUnaryNode *) extendedOpNode, currentTopNode); currentTopNode = (MultiNode *) extendedOpNode; @@ -1821,12 +1821,14 @@ MultiProjectNode(List *targetEntryList) /* Builds the extended operator node using fields from the given query tree. */ MultiExtendedOp * -MultiExtendedOpNode(Query *queryTree, Query *originalQuery) +MultiExtendedOpNode(Query *originalQuery, Query *queryTree) { MultiExtendedOp *extendedOpNode = CitusMakeNode(MultiExtendedOp); extendedOpNode->targetList = queryTree->targetList; extendedOpNode->groupClauseList = queryTree->groupClause; extendedOpNode->sortClauseList = queryTree->sortClause; + extendedOpNode->originalLimitCount = originalQuery->limitCount; + extendedOpNode->originalLimitOffset = originalQuery->limitOffset; extendedOpNode->limitCount = queryTree->limitCount; extendedOpNode->limitOffset = queryTree->limitOffset; extendedOpNode->havingQual = queryTree->havingQual; diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index 7f9b52060..e9111f51a 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -666,8 +666,8 @@ BuildJobQuery(MultiNode *multiNode, List *dependentJobList) { MultiExtendedOp *extendedOp = (MultiExtendedOp *) linitial(extendedOpNodeList); - limitCount = extendedOp->limitCount; - limitOffset = extendedOp->limitOffset; + limitCount = extendedOp->originalLimitCount; + limitOffset = extendedOp->originalLimitOffset; sortClauseList = extendedOp->sortClauseList; havingQual = extendedOp->havingQual; } @@ -814,8 +814,8 @@ BuildReduceQuery(MultiExtendedOp *extendedOpNode, List *dependentJobList) reduceQuery->jointree = joinTree; reduceQuery->sortClause = extendedOpNode->sortClauseList; reduceQuery->groupClause = extendedOpNode->groupClauseList; - reduceQuery->limitOffset = extendedOpNode->limitOffset; - reduceQuery->limitCount = extendedOpNode->limitCount; + reduceQuery->limitOffset = extendedOpNode->originalLimitOffset; + reduceQuery->limitCount = extendedOpNode->originalLimitCount; reduceQuery->havingQual = extendedOpNode->havingQual; reduceQuery->hasAggs = contain_aggs_of_level((Node *) targetList, 0); @@ -1551,8 +1551,8 @@ BuildSubqueryJobQuery(MultiNode *multiNode) { MultiExtendedOp *extendedOp = (MultiExtendedOp *) linitial(extendedOpNodeList); - limitCount = extendedOp->limitCount; - limitOffset = extendedOp->limitOffset; + limitCount = extendedOp->originalLimitCount; + limitOffset = extendedOp->originalLimitOffset; sortClauseList = extendedOp->sortClauseList; havingQual = extendedOp->havingQual; distinctClause = extendedOp->distinctClause; diff --git a/src/backend/distributed/planner/query_pushdown_planning.c b/src/backend/distributed/planner/query_pushdown_planning.c index cd21654d7..adc345abe 100644 --- a/src/backend/distributed/planner/query_pushdown_planning.c +++ b/src/backend/distributed/planner/query_pushdown_planning.c @@ -551,7 +551,7 @@ SubqueryMultiNodeTree(Query *originalQuery, Query *queryTree, } /* all checks have passed, safe to create the multi plan */ - multiQueryNode = MultiNodeTree(queryTree); + multiQueryNode = MultiNodeTree(originalQuery, queryTree); } Assert(multiQueryNode != NULL); @@ -1623,7 +1623,7 @@ SubqueryPushdownMultiNodeTree(Query *originalQuery) * distinguish between aggregates and expressions; and we address this later * in the logical optimizer. */ - MultiExtendedOp *extendedOpNode = MultiExtendedOpNode(queryTree, originalQuery); + MultiExtendedOp *extendedOpNode = MultiExtendedOpNode(originalQuery, queryTree); /* * Postgres standard planner converts having qual node to a list of and @@ -1665,6 +1665,10 @@ SubqueryPushdownMultiNodeTree(Query *originalQuery) * expression on the LIMIT and OFFSET clauses. Note that logical optimizer * expects those clauses to be already evaluated. */ + extendedOpNode->originalLimitCount = + PartiallyEvaluateExpression(extendedOpNode->originalLimitCount, NULL); + extendedOpNode->originalLimitOffset = + PartiallyEvaluateExpression(extendedOpNode->originalLimitOffset, NULL); extendedOpNode->limitCount = PartiallyEvaluateExpression(extendedOpNode->limitCount, NULL); extendedOpNode->limitOffset = diff --git a/src/include/distributed/multi_logical_planner.h b/src/include/distributed/multi_logical_planner.h index a5ec693f6..6b2b5b4bd 100644 --- a/src/include/distributed/multi_logical_planner.h +++ b/src/include/distributed/multi_logical_planner.h @@ -172,6 +172,8 @@ typedef struct MultiExtendedOp List *targetList; List *groupClauseList; List *sortClauseList; + Node *originalLimitCount; + Node *originalLimitOffset; Node *limitCount; Node *limitOffset; Node *havingQual; @@ -219,10 +221,10 @@ extern List * pull_var_clause_default(Node *node); extern bool OperatorImplementsEquality(Oid opno); extern DeferredErrorMessage * DeferErrorIfUnsupportedClause(List *clauseList); extern MultiProject * MultiProjectNode(List *targetEntryList); -extern MultiExtendedOp * MultiExtendedOpNode(Query *queryTree, Query *originalQuery); +extern MultiExtendedOp * MultiExtendedOpNode(Query *originalQuery, Query *queryTree); extern DeferredErrorMessage * DeferErrorIfUnsupportedSubqueryRepartition(Query * subqueryTree); -extern MultiNode * MultiNodeTree(Query *queryTree); +extern MultiNode * MultiNodeTree(Query *originalQuery, Query *queryTree); #endif /* MULTI_LOGICAL_PLANNER_H */