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

Lines changed: 66 additions & 0 deletions
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

Lines changed: 13 additions & 0 deletions
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

Lines changed: 27 additions & 7 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy