diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index a04ad6e99e6..aecb6dfa72b 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -1208,12 +1208,25 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context) /* * Really we should not see SubLink during a max_interesting == restricted - * scan, but if we do, return true. + * scan, but if we do, return true. Also, we can't push sub-select + * containing LIMIT/OFFSET to workers as that can change the results + * depending on what is beneath LIMIT node. So, consider that case as + * parallel-unsafe. */ else if (IsA(node, SubLink)) { + Query *subquery; + SubLink *sublink = (SubLink *) node; + if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context)) return true; + + subquery = castNode(Query, sublink->subselect); + if (subquery->limitOffset || subquery->limitCount) + { + context->max_hazard = PROPARALLEL_UNSAFE; + return true; + } } /* @@ -1274,6 +1287,7 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context) else if (IsA(node, Query)) { Query *query = (Query *) node; + ListCell *rt; /* SELECT FOR UPDATE/SHARE must be treated as unsafe */ if (query->rowMarks != NULL) @@ -1282,6 +1296,27 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context) return true; } + /* + * We can't push sub-select containing LIMIT/OFFSET to workers as that + * can change the results depending on what is beneath LIMIT node. + * So, consider that case as parallel-unsafe. + */ + foreach(rt, query->rtable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); + + if (rte->rtekind == RTE_SUBQUERY) + { + Query *subquery = castNode(Query, rte->subquery); + + if (subquery->limitOffset || subquery->limitCount) + { + context->max_hazard = PROPARALLEL_UNSAFE; + return true; + } + } + } + /* Recurse into subselects */ return query_tree_walker(query, max_parallel_hazard_walker,