mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +03:00
Check parallel safety in generate_useful_gather_paths
Commit ebb7ae839d
ensured we ignore pathkeys with volatile expressions
when considering adding a sort below a Gather Merge. Turns out we need
to care about parallel safety of the pathkeys too, otherwise we might
try sorting e.g. on results of a correlated subquery (as demonstrated
by a report from Luis Roberto).
Initial investigation by Tom Lane, patch by James Coleman. Backpatch
to 13, where the code was instroduced (as part of Incremental Sort).
Reported-by: Luis Roberto
Author: James Coleman
Reviewed-by: Tomas Vondra
Backpatch-through: 13
Discussion: https://postgr.es/m/622580997.37108180.1604080457319.JavaMail.zimbra%40siscobra.com.br
Discussion: https://postgr.es/m/CAAaqYe8cK3g5CfLC4w7bs=hC0mSksZC=H5M8LSchj5e5OxpTAg@mail.gmail.com
This commit is contained in:
@ -2802,6 +2802,9 @@ generate_gather_paths(PlannerInfo *root, RelOptInfo *rel, bool override_rows)
|
||||
* This allows us to do incremental sort on top of an index scan under a gather
|
||||
* merge node, i.e. parallelized.
|
||||
*
|
||||
* If the require_parallel_safe is true, we also require the expressions to
|
||||
* be parallel safe (which allows pushing the sort below Gather Merge).
|
||||
*
|
||||
* XXX At the moment this can only ever return a list with a single element,
|
||||
* because it looks at query_pathkeys only. So we might return the pathkeys
|
||||
* directly, but it seems plausible we'll want to consider other orderings
|
||||
@ -2809,7 +2812,8 @@ generate_gather_paths(PlannerInfo *root, RelOptInfo *rel, bool override_rows)
|
||||
* merge joins.
|
||||
*/
|
||||
static List *
|
||||
get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel)
|
||||
get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel,
|
||||
bool require_parallel_safe)
|
||||
{
|
||||
List *useful_pathkeys_list = NIL;
|
||||
|
||||
@ -2839,8 +2843,11 @@ get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel)
|
||||
* meet criteria of EC membership in the current relation, we
|
||||
* enable not just an incremental sort on the entirety of
|
||||
* query_pathkeys but also incremental sort below a JOIN.
|
||||
*
|
||||
* If requested, ensure the expression is parallel safe too.
|
||||
*/
|
||||
if (!find_em_expr_usable_for_sorting_rel(pathkey_ec, rel))
|
||||
if (!find_em_expr_usable_for_sorting_rel(root, pathkey_ec, rel,
|
||||
require_parallel_safe))
|
||||
break;
|
||||
|
||||
npathkeys++;
|
||||
@ -2894,7 +2901,7 @@ generate_useful_gather_paths(PlannerInfo *root, RelOptInfo *rel, bool override_r
|
||||
generate_gather_paths(root, rel, override_rows);
|
||||
|
||||
/* consider incremental sort for interesting orderings */
|
||||
useful_pathkeys_list = get_useful_pathkeys_for_relation(root, rel);
|
||||
useful_pathkeys_list = get_useful_pathkeys_for_relation(root, rel, true);
|
||||
|
||||
/* used for explicit (full) sort paths */
|
||||
cheapest_partial_path = linitial(rel->partial_pathlist);
|
||||
|
@ -803,7 +803,8 @@ find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel)
|
||||
* applied in prepare_sort_from_pathkeys.
|
||||
*/
|
||||
Expr *
|
||||
find_em_expr_usable_for_sorting_rel(EquivalenceClass *ec, RelOptInfo *rel)
|
||||
find_em_expr_usable_for_sorting_rel(PlannerInfo *root, EquivalenceClass *ec,
|
||||
RelOptInfo *rel, bool require_parallel_safe)
|
||||
{
|
||||
ListCell *lc_em;
|
||||
|
||||
@ -833,6 +834,12 @@ find_em_expr_usable_for_sorting_rel(EquivalenceClass *ec, RelOptInfo *rel)
|
||||
if (!bms_is_subset(em->em_relids, rel->relids))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If requested, reject expressions that are not parallel-safe.
|
||||
*/
|
||||
if (require_parallel_safe && !is_parallel_safe(root, (Node *) em_expr))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* As long as the expression isn't volatile then
|
||||
* prepare_sort_from_pathkeys is able to generate a new target entry,
|
||||
|
Reference in New Issue
Block a user