Skip to content

Commit 927f453

Browse files
committed
Fix tuple routing to initialize batching only for inserts
A cross-partition update on a partitioned table is implemented as a delete followed by an insert. With foreign partitions, this was however causing issues, because the FDW and core may disagree on when to enable batching. postgres_fdw was only allowing batching for plain inserts (CMD_INSERT) while core was trying to batch the insert component of the cross-partition update. Fix by restricting core to apply batching only to plain CMD_INSERT queries. It's possible to allow batching for cross-partition updates, but that will require more extensive changes, so better to leave that for a separate patch. Author: Amit Langote Reviewed-by: Tomas Vondra, Takayuki Tsunakawa Discussion: https://postgr.es/m/20200628151002.7x5laxwpgvkyiu3q@development
1 parent c15283f commit 927f453

File tree

4 files changed

+53
-5
lines changed

4 files changed

+53
-5
lines changed

contrib/postgres_fdw/expected/postgres_fdw.out

+22-1
Original file line numberDiff line numberDiff line change
@@ -9414,5 +9414,26 @@ SELECT COUNT(*) FROM batch_table;
94149414
66
94159415
(1 row)
94169416

9417+
-- Check that enabling batched inserts doesn't interfere with cross-partition
9418+
-- updates
9419+
CREATE TABLE batch_cp_upd_test (a int) PARTITION BY LIST (a);
9420+
CREATE TABLE batch_cp_upd_test1 (LIKE batch_cp_upd_test);
9421+
CREATE FOREIGN TABLE batch_cp_upd_test1_f
9422+
PARTITION OF batch_cp_upd_test
9423+
FOR VALUES IN (1)
9424+
SERVER loopback
9425+
OPTIONS (table_name 'batch_cp_upd_test1', batch_size '10');
9426+
CREATE TABLE batch_cp_up_test1 PARTITION OF batch_cp_upd_test
9427+
FOR VALUES IN (2);
9428+
INSERT INTO batch_cp_upd_test VALUES (1), (2);
9429+
-- The following moves a row from the local partition to the foreign one
9430+
UPDATE batch_cp_upd_test t SET a = 1 FROM (VALUES (1), (2)) s(a) WHERE t.a = s.a;
9431+
SELECT tableoid::regclass, * FROM batch_cp_upd_test;
9432+
tableoid | a
9433+
----------------------+---
9434+
batch_cp_upd_test1_f | 1
9435+
batch_cp_upd_test1_f | 1
9436+
(2 rows)
9437+
94179438
-- Clean up
9418-
DROP TABLE batch_table CASCADE;
9439+
DROP TABLE batch_table, batch_cp_upd_test CASCADE;

contrib/postgres_fdw/postgres_fdw.c

+11-2
Original file line numberDiff line numberDiff line change
@@ -1934,17 +1934,26 @@ static int
19341934
postgresGetForeignModifyBatchSize(ResultRelInfo *resultRelInfo)
19351935
{
19361936
int batch_size;
1937+
PgFdwModifyState *fmstate = resultRelInfo->ri_FdwState ?
1938+
(PgFdwModifyState *) resultRelInfo->ri_FdwState :
1939+
NULL;
19371940

19381941
/* should be called only once */
19391942
Assert(resultRelInfo->ri_BatchSize == 0);
19401943

1944+
/*
1945+
* Should never get called when the insert is being performed as part of
1946+
* a row movement operation.
1947+
*/
1948+
Assert(fmstate == NULL || fmstate->aux_fmstate == NULL);
1949+
19411950
/*
19421951
* In EXPLAIN without ANALYZE, ri_fdwstate is NULL, so we have to lookup
19431952
* the option directly in server/table options. Otherwise just use the
19441953
* value we determined earlier.
19451954
*/
1946-
if (resultRelInfo->ri_FdwState)
1947-
batch_size = ((PgFdwModifyState *) resultRelInfo->ri_FdwState)->batch_size;
1955+
if (fmstate)
1956+
batch_size = fmstate->batch_size;
19481957
else
19491958
batch_size = get_batch_size_option(resultRelInfo->ri_RelationDesc);
19501959

contrib/postgres_fdw/sql/postgres_fdw.sql

+18-1
Original file line numberDiff line numberDiff line change
@@ -2909,5 +2909,22 @@ CREATE TABLE batch_table_p2
29092909
INSERT INTO batch_table SELECT * FROM generate_series(1, 66) i;
29102910
SELECT COUNT(*) FROM batch_table;
29112911

2912+
-- Check that enabling batched inserts doesn't interfere with cross-partition
2913+
-- updates
2914+
CREATE TABLE batch_cp_upd_test (a int) PARTITION BY LIST (a);
2915+
CREATE TABLE batch_cp_upd_test1 (LIKE batch_cp_upd_test);
2916+
CREATE FOREIGN TABLE batch_cp_upd_test1_f
2917+
PARTITION OF batch_cp_upd_test
2918+
FOR VALUES IN (1)
2919+
SERVER loopback
2920+
OPTIONS (table_name 'batch_cp_upd_test1', batch_size '10');
2921+
CREATE TABLE batch_cp_up_test1 PARTITION OF batch_cp_upd_test
2922+
FOR VALUES IN (2);
2923+
INSERT INTO batch_cp_upd_test VALUES (1), (2);
2924+
2925+
-- The following moves a row from the local partition to the foreign one
2926+
UPDATE batch_cp_upd_test t SET a = 1 FROM (VALUES (1), (2)) s(a) WHERE t.a = s.a;
2927+
SELECT tableoid::regclass, * FROM batch_cp_upd_test;
2928+
29122929
-- Clean up
2913-
DROP TABLE batch_table CASCADE;
2930+
DROP TABLE batch_table, batch_cp_upd_test CASCADE;

src/backend/executor/execPartition.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,8 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
10001000
*
10011001
* If the FDW does not support batching, we set the batch size to 1.
10021002
*/
1003-
if (partRelInfo->ri_FdwRoutine != NULL &&
1003+
if (mtstate->operation == CMD_INSERT &&
1004+
partRelInfo->ri_FdwRoutine != NULL &&
10041005
partRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
10051006
partRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
10061007
partRelInfo->ri_BatchSize =

0 commit comments

Comments
 (0)