diff options
-rw-r--r-- | src/backend/access/heap/heapam.c | 11 | ||||
-rw-r--r-- | src/test/regress/expected/copy.out | 37 | ||||
-rw-r--r-- | src/test/regress/sql/copy.sql | 37 |
3 files changed, 85 insertions, 0 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 88a123d38a6..3c0895518fa 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -1792,6 +1792,17 @@ ReleaseBulkInsertStatePin(BulkInsertState bistate) if (bistate->current_buf != InvalidBuffer) ReleaseBuffer(bistate->current_buf); bistate->current_buf = InvalidBuffer; + + /* + * Despite the name, we also reset bulk relation extension + * state. Otherwise we can end up erroring out due to looking for free + * space in ->next_free of one partition, even though ->next_free was set + * when extending another partition. It's obviously also could be bad for + * efficiency to look at existing blocks at offsets from another + * partition, even if we don't error out. + */ + bistate->next_free = InvalidBlockNumber; + bistate->last_free = InvalidBlockNumber; } diff --git a/src/test/regress/expected/copy.out b/src/test/regress/expected/copy.out index a5912c13a8c..b48365ec981 100644 --- a/src/test/regress/expected/copy.out +++ b/src/test/regress/expected/copy.out @@ -257,3 +257,40 @@ ERROR: value too long for type character varying(5) \. invalid command \. drop table oversized_column_default; +-- +-- Create partitioned table that does not allow bulk insertions, to test bugs +-- related to the reuse of BulkInsertState across partitions (only done when +-- not using bulk insert). Switching between partitions often makes it more +-- likely to encounter these bugs, so we just switch on roughly every insert +-- by having an even/odd number partition and inserting evenly distributed +-- data. +-- +CREATE TABLE parted_si ( + id int not null, + data text not null, + -- prevent use of bulk insert by having a volatile function + rand float8 not null default random() +) +PARTITION BY LIST((id % 2)); +CREATE TABLE parted_si_p_even PARTITION OF parted_si FOR VALUES IN (0); +CREATE TABLE parted_si_p_odd PARTITION OF parted_si FOR VALUES IN (1); +-- Test that bulk relation extension handles reusing a single BulkInsertState +-- across partitions. Without the fix applied, this reliably reproduces +-- #18130 unless shared_buffers is extremely small (preventing any use use of +-- bulk relation extension). See +-- https://postgr.es/m/18130-7a86a7356a75209d%40postgresql.org +-- https://postgr.es/m/257696.1695670946%40sss.pgh.pa.us +\set filename :abs_srcdir '/data/desc.data' +COPY parted_si(id, data) FROM :'filename'; +-- An earlier bug (see commit b1ecb9b3fcf) could end up using a buffer from +-- the wrong partition. This test is *not* guaranteed to trigger that bug, but +-- does so when shared_buffers is small enough. To test if we encountered the +-- bug, check that the partition condition isn't violated. +SELECT tableoid::regclass, id % 2 = 0 is_even, count(*) from parted_si GROUP BY 1, 2 ORDER BY 1; + tableoid | is_even | count +------------------+---------+------- + parted_si_p_even | t | 5000 + parted_si_p_odd | f | 5000 +(2 rows) + +DROP TABLE parted_si; diff --git a/src/test/regress/sql/copy.sql b/src/test/regress/sql/copy.sql index 7fdb26d14f3..43d2e906dd9 100644 --- a/src/test/regress/sql/copy.sql +++ b/src/test/regress/sql/copy.sql @@ -283,3 +283,40 @@ copy oversized_column_default (col2) from stdin; copy oversized_column_default from stdin (default ''); \. drop table oversized_column_default; + + +-- +-- Create partitioned table that does not allow bulk insertions, to test bugs +-- related to the reuse of BulkInsertState across partitions (only done when +-- not using bulk insert). Switching between partitions often makes it more +-- likely to encounter these bugs, so we just switch on roughly every insert +-- by having an even/odd number partition and inserting evenly distributed +-- data. +-- +CREATE TABLE parted_si ( + id int not null, + data text not null, + -- prevent use of bulk insert by having a volatile function + rand float8 not null default random() +) +PARTITION BY LIST((id % 2)); + +CREATE TABLE parted_si_p_even PARTITION OF parted_si FOR VALUES IN (0); +CREATE TABLE parted_si_p_odd PARTITION OF parted_si FOR VALUES IN (1); + +-- Test that bulk relation extension handles reusing a single BulkInsertState +-- across partitions. Without the fix applied, this reliably reproduces +-- #18130 unless shared_buffers is extremely small (preventing any use use of +-- bulk relation extension). See +-- https://postgr.es/m/18130-7a86a7356a75209d%40postgresql.org +-- https://postgr.es/m/257696.1695670946%40sss.pgh.pa.us +\set filename :abs_srcdir '/data/desc.data' +COPY parted_si(id, data) FROM :'filename'; + +-- An earlier bug (see commit b1ecb9b3fcf) could end up using a buffer from +-- the wrong partition. This test is *not* guaranteed to trigger that bug, but +-- does so when shared_buffers is small enough. To test if we encountered the +-- bug, check that the partition condition isn't violated. +SELECT tableoid::regclass, id % 2 = 0 is_even, count(*) from parted_si GROUP BY 1, 2 ORDER BY 1; + +DROP TABLE parted_si; |