Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5c854e7

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 55b5686 commit 5c854e7

File tree

3 files changed

+106
-7
lines changed

3 files changed

+106
-7
lines changed

contrib/postgres_fdw/expected/postgres_fdw.out

+66
Original file line numberDiff line numberDiff line change
@@ -10734,6 +10734,72 @@ SELECT * FROM result_tbl ORDER BY a;
1073410734
(12 rows)
1073510735

1073610736
DELETE FROM result_tbl;
10737+
-- Disable async execution if we use gating Result nodes for pseudoconstant
10738+
-- quals
10739+
EXPLAIN (VERBOSE, COSTS OFF)
10740+
SELECT * FROM async_pt WHERE CURRENT_USER = SESSION_USER;
10741+
QUERY PLAN
10742+
----------------------------------------------------------------
10743+
Append
10744+
-> Result
10745+
Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
10746+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10747+
-> Foreign Scan on public.async_p1 async_pt_1
10748+
Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
10749+
Remote SQL: SELECT a, b, c FROM public.base_tbl1
10750+
-> Result
10751+
Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
10752+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10753+
-> Foreign Scan on public.async_p2 async_pt_2
10754+
Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
10755+
Remote SQL: SELECT a, b, c FROM public.base_tbl2
10756+
-> Result
10757+
Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
10758+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10759+
-> Seq Scan on public.async_p3 async_pt_3
10760+
Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
10761+
(18 rows)
10762+
10763+
EXPLAIN (VERBOSE, COSTS OFF)
10764+
(SELECT * FROM async_p1 WHERE CURRENT_USER = SESSION_USER)
10765+
UNION ALL
10766+
(SELECT * FROM async_p2 WHERE CURRENT_USER = SESSION_USER);
10767+
QUERY PLAN
10768+
----------------------------------------------------------------
10769+
Append
10770+
-> Result
10771+
Output: async_p1.a, async_p1.b, async_p1.c
10772+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10773+
-> Foreign Scan on public.async_p1
10774+
Output: async_p1.a, async_p1.b, async_p1.c
10775+
Remote SQL: SELECT a, b, c FROM public.base_tbl1
10776+
-> Result
10777+
Output: async_p2.a, async_p2.b, async_p2.c
10778+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10779+
-> Foreign Scan on public.async_p2
10780+
Output: async_p2.a, async_p2.b, async_p2.c
10781+
Remote SQL: SELECT a, b, c FROM public.base_tbl2
10782+
(13 rows)
10783+
10784+
EXPLAIN (VERBOSE, COSTS OFF)
10785+
SELECT * FROM ((SELECT * FROM async_p1 WHERE b < 10) UNION ALL (SELECT * FROM async_p2 WHERE b < 10)) s WHERE CURRENT_USER = SESSION_USER;
10786+
QUERY PLAN
10787+
---------------------------------------------------------------------------------
10788+
Append
10789+
-> Result
10790+
Output: async_p1.a, async_p1.b, async_p1.c
10791+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10792+
-> Foreign Scan on public.async_p1
10793+
Output: async_p1.a, async_p1.b, async_p1.c
10794+
Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((b < 10))
10795+
-> Result
10796+
Output: async_p2.a, async_p2.b, async_p2.c
10797+
One-Time Filter: (CURRENT_USER = SESSION_USER)
10798+
-> Foreign Scan on public.async_p2
10799+
Output: async_p2.a, async_p2.b, async_p2.c
10800+
Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((b < 10))
10801+
(13 rows)
10802+
1073710803
-- Test that pending requests are processed properly
1073810804
SET enable_mergejoin TO false;
1073910805
SET enable_hashjoin TO false;

contrib/postgres_fdw/sql/postgres_fdw.sql

+13
Original file line numberDiff line numberDiff line change
@@ -3410,6 +3410,19 @@ UNION ALL
34103410
SELECT * FROM result_tbl ORDER BY a;
34113411
DELETE FROM result_tbl;
34123412

3413+
-- Disable async execution if we use gating Result nodes for pseudoconstant
3414+
-- quals
3415+
EXPLAIN (VERBOSE, COSTS OFF)
3416+
SELECT * FROM async_pt WHERE CURRENT_USER = SESSION_USER;
3417+
3418+
EXPLAIN (VERBOSE, COSTS OFF)
3419+
(SELECT * FROM async_p1 WHERE CURRENT_USER = SESSION_USER)
3420+
UNION ALL
3421+
(SELECT * FROM async_p2 WHERE CURRENT_USER = SESSION_USER);
3422+
3423+
EXPLAIN (VERBOSE, COSTS OFF)
3424+
SELECT * FROM ((SELECT * FROM async_p1 WHERE b < 10) UNION ALL (SELECT * FROM async_p2 WHERE b < 10)) s WHERE CURRENT_USER = SESSION_USER;
3425+
34133426
-- Test that pending requests are processed properly
34143427
SET enable_mergejoin TO false;
34153428
SET enable_hashjoin TO false;

src/backend/optimizer/plan/createplan.c

+27-7
Original file line numberDiff line numberDiff line change
@@ -1112,9 +1112,9 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path)
11121112

11131113
/*
11141114
* mark_async_capable_plan
1115-
* Check whether a given Path node is async-capable, and if so, mark the
1116-
* Plan node created from it as such and return true, otherwise return
1117-
* false.
1115+
* Check whether the Plan node created from a Path node is async-capable,
1116+
* and if so, mark the Plan node as such and return true, otherwise
1117+
* return false.
11181118
*/
11191119
static bool
11201120
mark_async_capable_plan(Plan *plan, Path *path)
@@ -1125,6 +1125,13 @@ mark_async_capable_plan(Plan *plan, Path *path)
11251125
{
11261126
SubqueryScan *scan_plan = (SubqueryScan *) plan;
11271127

1128+
/*
1129+
* If the generated plan node includes a gating Result node,
1130+
* we can't execute it asynchronously.
1131+
*/
1132+
if (IsA(plan, Result))
1133+
return false;
1134+
11281135
/*
11291136
* If a SubqueryScan node atop of an async-capable plan node
11301137
* is deletable, consider it as async-capable.
@@ -1139,6 +1146,13 @@ mark_async_capable_plan(Plan *plan, Path *path)
11391146
{
11401147
FdwRoutine *fdwroutine = path->parent->fdwroutine;
11411148

1149+
/*
1150+
* If the generated plan node includes a gating Result node,
1151+
* we can't execute it asynchronously.
1152+
*/
1153+
if (IsA(plan, Result))
1154+
return false;
1155+
11421156
Assert(fdwroutine != NULL);
11431157
if (fdwroutine->IsForeignPathAsyncCapable != NULL &&
11441158
fdwroutine->IsForeignPathAsyncCapable((ForeignPath *) path))
@@ -1148,11 +1162,17 @@ mark_async_capable_plan(Plan *plan, Path *path)
11481162
case T_ProjectionPath:
11491163

11501164
/*
1151-
* If the generated plan node doesn't include a Result node,
1152-
* consider it as async-capable if the subpath is async-capable.
1165+
* If the generated plan node includes a Result node for
1166+
* the projection, we can't execute it asynchronously.
1167+
*/
1168+
if (IsA(plan, Result))
1169+
return false;
1170+
1171+
/*
1172+
* create_projection_plan() would have pulled up the subplan, so
1173+
* check the capability using the subpath.
11531174
*/
1154-
if (!IsA(plan, Result) &&
1155-
mark_async_capable_plan(plan,
1175+
if (mark_async_capable_plan(plan,
11561176
((ProjectionPath *) path)->subpath))
11571177
return true;
11581178
return false;

0 commit comments

Comments
 (0)