diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2018-12-12 16:08:30 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2018-12-12 16:08:30 -0500 |
commit | 77d4d88afbaa37773d15578d89881fa175ec38e8 (patch) | |
tree | e7ad5b104a8707dd2330d47c215cabf57a401a44 /src/backend/optimizer/plan/createplan.c | |
parent | 0f7ec8d9c3aeb8964d3539561e5c8d4caef42bf6 (diff) | |
download | postgresql-77d4d88afbaa37773d15578d89881fa175ec38e8.tar.gz postgresql-77d4d88afbaa37773d15578d89881fa175ec38e8.zip |
Repair bogus EPQ plans generated for postgres_fdw foreign joins.
postgres_fdw's postgresGetForeignPlan() assumes without checking that the
outer_plan it's given for a join relation must have a NestLoop, MergeJoin,
or HashJoin node at the top. That's been wrong at least since commit
4bbf6edfb (which could cause insertion of a Sort node on top) and it seems
like a pretty unsafe thing to Just Assume even without that.
Through blind good fortune, this doesn't seem to have any worse
consequences today than strange EXPLAIN output, but it's clearly trouble
waiting to happen.
To fix, test the node type explicitly before touching Join-specific
fields, and avoid jamming the new tlist into a node type that can't
do projection. Export a new support function from createplan.c
to avoid building low-level knowledge about the latter into FDWs.
Back-patch to 9.6 where the faulty coding was added. Note that the
associated regression test cases don't show any changes before v11,
apparently because the tests back-patched with 4bbf6edfb don't actually
exercise the problem case before then (there's no top-level Sort
in those plans).
Discussion: https://postgr.es/m/8946.1544644803@sss.pgh.pa.us
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 50 |
1 files changed, 37 insertions, 13 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index da7a92081af..91cf78233d5 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1407,20 +1407,10 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path, int flags) } } + /* Use change_plan_targetlist in case we need to insert a Result node */ if (newitems || best_path->umethod == UNIQUE_PATH_SORT) - { - /* - * If the top plan node can't do projections and its existing target - * list isn't already what we need, we need to add a Result node to - * help it along. - */ - if (!is_projection_capable_plan(subplan) && - !tlist_same_exprs(newtlist, subplan->targetlist)) - subplan = inject_projection_plan(subplan, newtlist, - best_path->path.parallel_safe); - else - subplan->targetlist = newtlist; - } + subplan = change_plan_targetlist(subplan, newtlist, + best_path->path.parallel_safe); /* * Build control information showing which subplan output columns are to @@ -1763,6 +1753,40 @@ inject_projection_plan(Plan *subplan, List *tlist, bool parallel_safe) } /* + * change_plan_targetlist + * Externally available wrapper for inject_projection_plan. + * + * This is meant for use by FDW plan-generation functions, which might + * want to adjust the tlist computed by some subplan tree. In general, + * a Result node is needed to compute the new tlist, but we can optimize + * some cases. + * + * In most cases, tlist_parallel_safe can just be passed as the parallel_safe + * flag of the FDW's own Path node. + */ +Plan * +change_plan_targetlist(Plan *subplan, List *tlist, bool tlist_parallel_safe) +{ + /* + * If the top plan node can't do projections and its existing target list + * isn't already what we need, we need to add a Result node to help it + * along. + */ + if (!is_projection_capable_plan(subplan) && + !tlist_same_exprs(tlist, subplan->targetlist)) + subplan = inject_projection_plan(subplan, tlist, + subplan->parallel_safe && + tlist_parallel_safe); + else + { + /* Else we can just replace the plan node's tlist */ + subplan->targetlist = tlist; + subplan->parallel_safe &= tlist_parallel_safe; + } + return subplan; +} + +/* * create_sort_plan * * Create a Sort plan for 'best_path' and (recursively) plans |