diff options
author | Etsuro Fujita <efujita@postgresql.org> | 2022-04-28 15:15:02 +0900 |
---|---|---|
committer | Etsuro Fujita <efujita@postgresql.org> | 2022-04-28 15:15:02 +0900 |
commit | ebb79024152348227250404fd06c35c56cbc672e (patch) | |
tree | 6ab524a7552088e45ec561c6483447136c3e9ab1 | |
parent | 71f394667c824257ddf6e8359cba746e621a2d16 (diff) | |
download | postgresql-ebb79024152348227250404fd06c35c56cbc672e.tar.gz |
Disable asynchronous execution if using gating Result nodes.
mark_async_capable_plan(), which is called from create_append_plan() to
determine whether subplans are async-capable, failed to take into
account that the given subplan created from a given subpath might
include a gating Result node if the subpath is a SubqueryScanPath or
ForeignPath, causing a segmentation fault there when the subplan created
from a SubqueryScanPath includes the Result node, or causing
ExecAsyncRequest() to throw an error about an unrecognized node type
when the subplan created from a ForeignPath includes the Result node,
because in the latter case the Result node was unintentionally
considered as async-capable, but we don't currently support executing
Result nodes asynchronously. Fix by modifying mark_async_capable_plan()
to disable asynchronous execution in such cases. Also, adjust code in
the ProjectionPath case in mark_async_capable_plan(), for consistency
with other cases, and adjust/improve comments there.
is_async_capable_path() added in commit 27e1f1456, which was rewritten
to mark_async_capable_plan() in a later commit, has the same issue,
causing the error at execution mentioned above, so back-patch to v14
where the aforesaid commit went in.
Per report from Justin Pryzby.
Etsuro Fujita, reviewed by Zhihong Yu and Justin Pryzby.
Discussion: https://postgr.es/m/20220408124338.GK24419%40telsasoft.com
-rw-r--r-- | contrib/postgres_fdw/expected/postgres_fdw.out | 26 | ||||
-rw-r--r-- | contrib/postgres_fdw/sql/postgres_fdw.sql | 5 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 19 |
3 files changed, 44 insertions, 6 deletions
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 8bcc18eca6..fa9674d1ef 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -10424,6 +10424,32 @@ DROP TABLE local_tbl; DROP INDEX base_tbl1_idx; DROP INDEX base_tbl2_idx; DROP INDEX async_p3_idx; +-- Disable async execution if we use gating Result nodes for pseudoconstant +-- quals +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM async_pt WHERE CURRENT_USER = SESSION_USER; + QUERY PLAN +---------------------------------------------------------------- + Append + -> Result + Output: async_pt_1.a, async_pt_1.b, async_pt_1.c + One-Time Filter: (CURRENT_USER = SESSION_USER) + -> Foreign Scan on public.async_p1 async_pt_1 + Output: async_pt_1.a, async_pt_1.b, async_pt_1.c + Remote SQL: SELECT a, b, c FROM public.base_tbl1 + -> Result + Output: async_pt_2.a, async_pt_2.b, async_pt_2.c + One-Time Filter: (CURRENT_USER = SESSION_USER) + -> Foreign Scan on public.async_p2 async_pt_2 + Output: async_pt_2.a, async_pt_2.b, async_pt_2.c + Remote SQL: SELECT a, b, c FROM public.base_tbl2 + -> Result + Output: async_pt_3.a, async_pt_3.b, async_pt_3.c + One-Time Filter: (CURRENT_USER = SESSION_USER) + -> Seq Scan on public.async_p3 async_pt_3 + Output: async_pt_3.a, async_pt_3.b, async_pt_3.c +(18 rows) + -- Test that pending requests are processed properly SET enable_mergejoin TO false; SET enable_hashjoin TO false; diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 855c7ea70e..89de85c03e 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -3317,6 +3317,11 @@ DROP INDEX base_tbl1_idx; DROP INDEX base_tbl2_idx; DROP INDEX async_p3_idx; +-- Disable async execution if we use gating Result nodes for pseudoconstant +-- quals +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM async_pt WHERE CURRENT_USER = SESSION_USER; + -- Test that pending requests are processed properly SET enable_mergejoin TO false; SET enable_hashjoin TO false; diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index a2101fb3fc..0ed858f305 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -82,7 +82,7 @@ static List *get_gating_quals(PlannerInfo *root, List *quals); static Plan *create_gating_plan(PlannerInfo *root, Path *path, Plan *plan, List *gating_quals); static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path); -static bool is_async_capable_path(Path *path); +static bool is_async_capable_plan(Plan *plan, Path *path); static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags); static Plan *create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, @@ -1109,11 +1109,11 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path) } /* - * is_async_capable_path - * Check whether a given Path node is async-capable. + * is_async_capable_plan + * Check whether the Plan node created from a Path node is async-capable. */ static bool -is_async_capable_path(Path *path) +is_async_capable_plan(Plan *plan, Path *path) { switch (nodeTag(path)) { @@ -1121,6 +1121,13 @@ is_async_capable_path(Path *path) { FdwRoutine *fdwroutine = path->parent->fdwroutine; + /* + * If the generated plan node includes a gating Result node, + * we can't execute it asynchronously. + */ + if (IsA(plan, Result)) + return false; + Assert(fdwroutine != NULL); if (fdwroutine->IsForeignPathAsyncCapable != NULL && fdwroutine->IsForeignPathAsyncCapable((ForeignPath *) path)) @@ -1295,8 +1302,8 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) subplans = lappend(subplans, subplan); - /* Check to see if subplan can be executed asynchronously */ - if (consider_async && is_async_capable_path(subpath)) + /* If needed, check to see if subplan can be executed asynchronously */ + if (consider_async && is_async_capable_plan(subplan, subpath)) { subplan->async_capable = true; ++nasyncplans; |