Skip to content

Commit ebb7902

Browse files
author
Etsuro Fujita
committed
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 27e1f14, 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
1 parent 71f3946 commit ebb7902

File tree

3 files changed

+44
-6
lines changed

3 files changed

+44
-6
lines changed

contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10424,6 +10424,32 @@ DROP TABLE local_tbl;
1042410424
DROP INDEX base_tbl1_idx;
1042510425
DROP INDEX base_tbl2_idx;
1042610426
DROP INDEX async_p3_idx;
10427+
-- Disable async execution if we use gating Result nodes for pseudoconstant
10428+
-- quals
10429+
EXPLAIN (VERBOSE, COSTS OFF)
10430+
SELECT * FROM async_pt WHERE CURRENT_USER = SESSION_USER;
10431+
QUERY PLAN
10432+
----------------------------------------------------------------
10433+
Append
10434+
-> Result
10435+
Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
10436+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10437+
-> Foreign Scan on public.async_p1 async_pt_1
10438+
Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
10439+
Remote SQL: SELECT a, b, c FROM public.base_tbl1
10440+
-> Result
10441+
Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
10442+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10443+
-> Foreign Scan on public.async_p2 async_pt_2
10444+
Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
10445+
Remote SQL: SELECT a, b, c FROM public.base_tbl2
10446+
-> Result
10447+
Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
10448+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10449+
-> Seq Scan on public.async_p3 async_pt_3
10450+
Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
10451+
(18 rows)
10452+
1042710453
-- Test that pending requests are processed properly
1042810454
SET enable_mergejoin TO false;
1042910455
SET enable_hashjoin TO false;

contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3317,6 +3317,11 @@ DROP INDEX base_tbl1_idx;
33173317
DROP INDEX base_tbl2_idx;
33183318
DROP INDEX async_p3_idx;
33193319

3320+
-- Disable async execution if we use gating Result nodes for pseudoconstant
3321+
-- quals
3322+
EXPLAIN (VERBOSE, COSTS OFF)
3323+
SELECT * FROM async_pt WHERE CURRENT_USER = SESSION_USER;
3324+
33203325
-- Test that pending requests are processed properly
33213326
SET enable_mergejoin TO false;
33223327
SET enable_hashjoin TO false;

src/backend/optimizer/plan/createplan.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ static List *get_gating_quals(PlannerInfo *root, List *quals);
8282
static Plan *create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
8383
List *gating_quals);
8484
static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path);
85-
static bool is_async_capable_path(Path *path);
85+
static bool is_async_capable_plan(Plan *plan, Path *path);
8686
static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path,
8787
int flags);
8888
static Plan *create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path,
@@ -1109,18 +1109,25 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path)
11091109
}
11101110

11111111
/*
1112-
* is_async_capable_path
1113-
* Check whether a given Path node is async-capable.
1112+
* is_async_capable_plan
1113+
* Check whether the Plan node created from a Path node is async-capable.
11141114
*/
11151115
static bool
1116-
is_async_capable_path(Path *path)
1116+
is_async_capable_plan(Plan *plan, Path *path)
11171117
{
11181118
switch (nodeTag(path))
11191119
{
11201120
case T_ForeignPath:
11211121
{
11221122
FdwRoutine *fdwroutine = path->parent->fdwroutine;
11231123

1124+
/*
1125+
* If the generated plan node includes a gating Result node,
1126+
* we can't execute it asynchronously.
1127+
*/
1128+
if (IsA(plan, Result))
1129+
return false;
1130+
11241131
Assert(fdwroutine != NULL);
11251132
if (fdwroutine->IsForeignPathAsyncCapable != NULL &&
11261133
fdwroutine->IsForeignPathAsyncCapable((ForeignPath *) path))
@@ -1295,8 +1302,8 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags)
12951302

12961303
subplans = lappend(subplans, subplan);
12971304

1298-
/* Check to see if subplan can be executed asynchronously */
1299-
if (consider_async && is_async_capable_path(subpath))
1305+
/* If needed, check to see if subplan can be executed asynchronously */
1306+
if (consider_async && is_async_capable_plan(subplan, subpath))
13001307
{
13011308
subplan->async_capable = true;
13021309
++nasyncplans;

0 commit comments

Comments
 (0)