Skip to content

Commit f3baaf2

Browse files
author
Etsuro Fujita
committed
Fix rescanning of async-aware Append nodes.
In cases where run-time pruning isn't required, the synchronous and asynchronous subplans for an async-aware Append node determined using classify_matching_subplans() should be re-used when rescanning the node, but the previous code re-determined them using that function repeatedly each time when rescanning the node, leading to incorrect results in a normal build and an Assert failure in an Assert-enabled build as that function doesn't assume that it's called repeatedly in such cases. Fix the code as mentioned above. My oversight in commit 27e1f14. While at it, initialize async-related pointers/variables to NULL/zero explicitly in ExecInitAppend() and ExecReScanAppend(), just to be sure. (The variables would have been set to zero before we get to the latter function, but let's do so.) Reviewed-by: Kyotaro Horiguchi Discussion: https://postgr.es/m/CAPmGK16Q4B2_KY%2BJH7rb7wQbw54AUprp7TMekGTd2T1B62yysQ%40mail.gmail.com
1 parent a65e9f3 commit f3baaf2

File tree

3 files changed

+76
-5
lines changed

3 files changed

+76
-5
lines changed

contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9973,6 +9973,48 @@ SELECT * FROM join_tbl ORDER BY a1;
99739973

99749974
DELETE FROM join_tbl;
99759975
RESET enable_partitionwise_join;
9976+
-- Test rescan of an async Append node with do_exec_prune=false
9977+
SET enable_hashjoin TO false;
9978+
EXPLAIN (VERBOSE, COSTS OFF)
9979+
INSERT INTO join_tbl SELECT * FROM async_p1 t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
9980+
QUERY PLAN
9981+
----------------------------------------------------------------------------------------
9982+
Insert on public.join_tbl
9983+
-> Nested Loop
9984+
Output: t1.a, t1.b, t1.c, t2.a, t2.b, t2.c
9985+
Join Filter: ((t1.a = t2.a) AND (t1.b = t2.b))
9986+
-> Foreign Scan on public.async_p1 t1
9987+
Output: t1.a, t1.b, t1.c
9988+
Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE (((b % 100) = 0))
9989+
-> Append
9990+
-> Async Foreign Scan on public.async_p1 t2_1
9991+
Output: t2_1.a, t2_1.b, t2_1.c
9992+
Remote SQL: SELECT a, b, c FROM public.base_tbl1
9993+
-> Async Foreign Scan on public.async_p2 t2_2
9994+
Output: t2_2.a, t2_2.b, t2_2.c
9995+
Remote SQL: SELECT a, b, c FROM public.base_tbl2
9996+
-> Seq Scan on public.async_p3 t2_3
9997+
Output: t2_3.a, t2_3.b, t2_3.c
9998+
(16 rows)
9999+
10000+
INSERT INTO join_tbl SELECT * FROM async_p1 t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
10001+
SELECT * FROM join_tbl ORDER BY a1;
10002+
a1 | b1 | c1 | a2 | b2 | c2
10003+
------+-----+------+------+-----+------
10004+
1000 | 0 | 0000 | 1000 | 0 | 0000
10005+
1100 | 100 | 0100 | 1100 | 100 | 0100
10006+
1200 | 200 | 0200 | 1200 | 200 | 0200
10007+
1300 | 300 | 0300 | 1300 | 300 | 0300
10008+
1400 | 400 | 0400 | 1400 | 400 | 0400
10009+
1500 | 500 | 0500 | 1500 | 500 | 0500
10010+
1600 | 600 | 0600 | 1600 | 600 | 0600
10011+
1700 | 700 | 0700 | 1700 | 700 | 0700
10012+
1800 | 800 | 0800 | 1800 | 800 | 0800
10013+
1900 | 900 | 0900 | 1900 | 900 | 0900
10014+
(10 rows)
10015+
10016+
DELETE FROM join_tbl;
10017+
RESET enable_hashjoin;
997610018
-- Test interaction of async execution with plan-time partition pruning
997710019
EXPLAIN (VERBOSE, COSTS OFF)
997810020
SELECT * FROM async_pt WHERE a < 3000;

contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3157,6 +3157,18 @@ DELETE FROM join_tbl;
31573157

31583158
RESET enable_partitionwise_join;
31593159

3160+
-- Test rescan of an async Append node with do_exec_prune=false
3161+
SET enable_hashjoin TO false;
3162+
3163+
EXPLAIN (VERBOSE, COSTS OFF)
3164+
INSERT INTO join_tbl SELECT * FROM async_p1 t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
3165+
INSERT INTO join_tbl SELECT * FROM async_p1 t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
3166+
3167+
SELECT * FROM join_tbl ORDER BY a1;
3168+
DELETE FROM join_tbl;
3169+
3170+
RESET enable_hashjoin;
3171+
31603172
-- Test interaction of async execution with plan-time partition pruning
31613173
EXPLAIN (VERBOSE, COSTS OFF)
31623174
SELECT * FROM async_pt WHERE a < 3000;

src/backend/executor/nodeAppend.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,12 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
240240
appendstate->as_asyncplans = asyncplans;
241241
appendstate->as_nasyncplans = nasyncplans;
242242
appendstate->as_asyncrequests = NULL;
243-
appendstate->as_asyncresults = (TupleTableSlot **)
244-
palloc0(nasyncplans * sizeof(TupleTableSlot *));
243+
appendstate->as_asyncresults = NULL;
244+
appendstate->as_nasyncresults = 0;
245+
appendstate->as_nasyncremain = 0;
245246
appendstate->as_needrequest = NULL;
246247
appendstate->as_eventset = NULL;
248+
appendstate->as_valid_asyncplans = NULL;
247249

248250
if (nasyncplans > 0)
249251
{
@@ -265,6 +267,12 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
265267

266268
appendstate->as_asyncrequests[i] = areq;
267269
}
270+
271+
appendstate->as_asyncresults = (TupleTableSlot **)
272+
palloc0(nasyncplans * sizeof(TupleTableSlot *));
273+
274+
if (appendstate->as_valid_subplans != NULL)
275+
classify_matching_subplans(appendstate);
268276
}
269277

270278
/*
@@ -459,6 +467,8 @@ ExecReScanAppend(AppendState *node)
459467
areq->result = NULL;
460468
}
461469

470+
node->as_nasyncresults = 0;
471+
node->as_nasyncremain = 0;
462472
bms_free(node->as_needrequest);
463473
node->as_needrequest = NULL;
464474
}
@@ -861,15 +871,24 @@ ExecAppendAsyncBegin(AppendState *node)
861871
/* Backward scan is not supported by async-aware Appends. */
862872
Assert(ScanDirectionIsForward(node->ps.state->es_direction));
863873

874+
/* We should never be called when there are no subplans */
875+
Assert(node->as_nplans > 0);
876+
864877
/* We should never be called when there are no async subplans. */
865878
Assert(node->as_nasyncplans > 0);
866879

867880
/* If we've yet to determine the valid subplans then do so now. */
868881
if (node->as_valid_subplans == NULL)
882+
{
869883
node->as_valid_subplans =
870884
ExecFindMatchingSubPlans(node->as_prune_state);
871885

872-
classify_matching_subplans(node);
886+
classify_matching_subplans(node);
887+
}
888+
889+
/* Initialize state variables. */
890+
node->as_syncdone = bms_is_empty(node->as_valid_subplans);
891+
node->as_nasyncremain = bms_num_members(node->as_valid_asyncplans);
873892

874893
/* Nothing to do if there are no valid async subplans. */
875894
if (node->as_nasyncremain == 0)
@@ -1148,9 +1167,7 @@ classify_matching_subplans(AppendState *node)
11481167
/* Adjust the valid subplans to contain sync subplans only. */
11491168
node->as_valid_subplans = bms_del_members(node->as_valid_subplans,
11501169
valid_asyncplans);
1151-
node->as_syncdone = bms_is_empty(node->as_valid_subplans);
11521170

11531171
/* Save valid async subplans. */
11541172
node->as_valid_asyncplans = valid_asyncplans;
1155-
node->as_nasyncremain = bms_num_members(valid_asyncplans);
11561173
}

0 commit comments

Comments
 (0)