Skip to content

Commit a784859

Browse files
author
Etsuro Fujita
committed
Prevent asynchronous execution of direct foreign-table modifications.
Commits 27e1f14 and 86dc900, which were independently discussed, cause a crash when executing an inherited foreign UPDATE/DELETE query with asynchronous execution enabled, where children of an Append node that is the direct/indirect child of the ModifyTable node are rewritten so as to modify foreign tables directly by postgresPlanDirectModify(); as in that case the direct modifications are executed asynchronously, which is not currently supported by asynchronous execution. Fix by disabling asynchronous execution of the direct modifications in that function. Author: Etsuro Fujita Reviewed-by: Amit Langote Discussion: https://postgr.es/m/CAPmGK158e9sJOfuWxfn%2B0ynrspXQU3JhNjSCbaoeSzMvnga%2Bbw%40mail.gmail.com
1 parent 5a73a9e commit a784859

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

contrib/postgres_fdw/expected/postgres_fdw.out

+55
Original file line numberDiff line numberDiff line change
@@ -10154,6 +10154,61 @@ DROP TABLE base_tbl3;
1015410154
DROP TABLE base_tbl4;
1015510155
RESET enable_mergejoin;
1015610156
RESET enable_hashjoin;
10157+
-- Test that UPDATE/DELETE with inherited target works with async_capable enabled
10158+
EXPLAIN (VERBOSE, COSTS OFF)
10159+
UPDATE async_pt SET c = c || c WHERE b = 0 RETURNING *;
10160+
QUERY PLAN
10161+
----------------------------------------------------------------------------------------------------------
10162+
Update on public.async_pt
10163+
Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
10164+
Foreign Update on public.async_p1 async_pt_1
10165+
Foreign Update on public.async_p2 async_pt_2
10166+
Update on public.async_p3 async_pt_3
10167+
-> Append
10168+
-> Foreign Update on public.async_p1 async_pt_1
10169+
Remote SQL: UPDATE public.base_tbl1 SET c = (c || c) WHERE ((b = 0)) RETURNING a, b, c
10170+
-> Foreign Update on public.async_p2 async_pt_2
10171+
Remote SQL: UPDATE public.base_tbl2 SET c = (c || c) WHERE ((b = 0)) RETURNING a, b, c
10172+
-> Seq Scan on public.async_p3 async_pt_3
10173+
Output: (async_pt_3.c || async_pt_3.c), async_pt_3.tableoid, async_pt_3.ctid, NULL::record
10174+
Filter: (async_pt_3.b = 0)
10175+
(13 rows)
10176+
10177+
UPDATE async_pt SET c = c || c WHERE b = 0 RETURNING *;
10178+
a | b | c
10179+
------+---+----------
10180+
1000 | 0 | 00000000
10181+
2000 | 0 | 00000000
10182+
3000 | 0 | 00000000
10183+
(3 rows)
10184+
10185+
EXPLAIN (VERBOSE, COSTS OFF)
10186+
DELETE FROM async_pt WHERE b = 0 RETURNING *;
10187+
QUERY PLAN
10188+
------------------------------------------------------------------------------------------
10189+
Delete on public.async_pt
10190+
Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
10191+
Foreign Delete on public.async_p1 async_pt_1
10192+
Foreign Delete on public.async_p2 async_pt_2
10193+
Delete on public.async_p3 async_pt_3
10194+
-> Append
10195+
-> Foreign Delete on public.async_p1 async_pt_1
10196+
Remote SQL: DELETE FROM public.base_tbl1 WHERE ((b = 0)) RETURNING a, b, c
10197+
-> Foreign Delete on public.async_p2 async_pt_2
10198+
Remote SQL: DELETE FROM public.base_tbl2 WHERE ((b = 0)) RETURNING a, b, c
10199+
-> Seq Scan on public.async_p3 async_pt_3
10200+
Output: async_pt_3.tableoid, async_pt_3.ctid
10201+
Filter: (async_pt_3.b = 0)
10202+
(13 rows)
10203+
10204+
DELETE FROM async_pt WHERE b = 0 RETURNING *;
10205+
a | b | c
10206+
------+---+----------
10207+
1000 | 0 | 00000000
10208+
2000 | 0 | 00000000
10209+
3000 | 0 | 00000000
10210+
(3 rows)
10211+
1015710212
-- Check EXPLAIN ANALYZE for a query that scans empty partitions asynchronously
1015810213
DELETE FROM async_p1;
1015910214
DELETE FROM async_p2;

contrib/postgres_fdw/postgres_fdw.c

+7
Original file line numberDiff line numberDiff line change
@@ -2530,6 +2530,13 @@ postgresPlanDirectModify(PlannerInfo *root,
25302530
rebuild_fdw_scan_tlist(fscan, returningList);
25312531
}
25322532

2533+
/*
2534+
* Finally, unset the async-capable flag if it is set, as we currently
2535+
* don't support asynchronous execution of direct modifications.
2536+
*/
2537+
if (fscan->scan.plan.async_capable)
2538+
fscan->scan.plan.async_capable = false;
2539+
25332540
table_close(rel, NoLock);
25342541
return true;
25352542
}

contrib/postgres_fdw/sql/postgres_fdw.sql

+8
Original file line numberDiff line numberDiff line change
@@ -3237,6 +3237,14 @@ DROP TABLE base_tbl4;
32373237
RESET enable_mergejoin;
32383238
RESET enable_hashjoin;
32393239

3240+
-- Test that UPDATE/DELETE with inherited target works with async_capable enabled
3241+
EXPLAIN (VERBOSE, COSTS OFF)
3242+
UPDATE async_pt SET c = c || c WHERE b = 0 RETURNING *;
3243+
UPDATE async_pt SET c = c || c WHERE b = 0 RETURNING *;
3244+
EXPLAIN (VERBOSE, COSTS OFF)
3245+
DELETE FROM async_pt WHERE b = 0 RETURNING *;
3246+
DELETE FROM async_pt WHERE b = 0 RETURNING *;
3247+
32403248
-- Check EXPLAIN ANALYZE for a query that scans empty partitions asynchronously
32413249
DELETE FROM async_p1;
32423250
DELETE FROM async_p2;

0 commit comments

Comments
 (0)