Skip to content

Commit b703b7d

Browse files
committed
Invalidate partitions of table being attached/detached
Failing to do that, any direct inserts/updates of those partitions would fail to enforce the correct constraint, that is, one that considers the new partition constraint of their parent table. Backpatch to 10. Reported by: Hou Zhijie <houzj.fnst@fujitsu.com> Author: Amit Langote <amitlangote09@gmail.com> Author: Álvaro Herrera <alvherre@alvh.no-ip.org> Reviewed-by: Nitin Jadhav <nitinjadhavpostgres@gmail.com> Reviewed-by: Pavel Borisov <pashkin.elfe@gmail.com> Discussion: https://postgr.es/m/OS3PR01MB5718DA1C4609A25186D1FBF194089%40OS3PR01MB5718.jpnprd01.prod.outlook.com
1 parent 506aa1f commit b703b7d

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

src/backend/commands/tablecmds.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15330,6 +15330,22 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1533015330

1533115331
ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
1533215332

15333+
/*
15334+
* If the partition we just attached is partitioned itself, invalidate
15335+
* relcache for all descendent partitions too to ensure that their
15336+
* rd_partcheck expression trees are rebuilt; partitions already locked
15337+
* at the beginning of this function.
15338+
*/
15339+
if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15340+
{
15341+
ListCell *l;
15342+
15343+
foreach(l, attachrel_children)
15344+
{
15345+
CacheInvalidateRelcacheByRelid(lfirst_oid(l));
15346+
}
15347+
}
15348+
1533315349
/* keep our lock until commit */
1533415350
heap_close(attachrel, NoLock);
1533515351

@@ -15879,6 +15895,25 @@ ATExecDetachPartition(Relation rel, RangeVar *name)
1587915895
*/
1588015896
CacheInvalidateRelcache(rel);
1588115897

15898+
/*
15899+
* If the partition we just detached is partitioned itself, invalidate
15900+
* relcache for all descendent partitions too to ensure that their
15901+
* rd_partcheck expression trees are rebuilt; must lock partitions
15902+
* before doing so, using the same lockmode as what partRel has been
15903+
* locked with by the caller.
15904+
*/
15905+
if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15906+
{
15907+
List *children;
15908+
15909+
children = find_all_inheritors(RelationGetRelid(partRel),
15910+
AccessExclusiveLock, NULL);
15911+
foreach(cell, children)
15912+
{
15913+
CacheInvalidateRelcacheByRelid(lfirst_oid(cell));
15914+
}
15915+
}
15916+
1588215917
ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
1588315918

1588415919
/* keep our lock until commit */

src/test/regress/expected/alter_table.out

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4305,3 +4305,23 @@ select indexrelid::regclass, indisclustered from pg_index
43054305
(2 rows)
43064306

43074307
drop table alttype_cluster;
4308+
--
4309+
-- Check that attaching or detaching a partitioned partition correctly leads
4310+
-- to its partitions' constraint being updated to reflect the parent's
4311+
-- newly added/removed constraint
4312+
create table target_parted (a int, b int) partition by list (a);
4313+
create table attach_parted (a int, b int) partition by list (b);
4314+
create table attach_parted_part1 partition of attach_parted for values in (1);
4315+
-- insert a row directly into the leaf partition so that its partition
4316+
-- constraint is built and stored in the relcache
4317+
insert into attach_parted_part1 values (1, 1);
4318+
-- the following better invalidate the partition constraint of the leaf
4319+
-- partition too...
4320+
alter table target_parted attach partition attach_parted for values in (1);
4321+
-- ...such that the following insert fails
4322+
insert into attach_parted_part1 values (2, 1);
4323+
ERROR: new row for relation "attach_parted_part1" violates partition constraint
4324+
DETAIL: Failing row contains (2, 1).
4325+
-- ...and doesn't when the partition is detached along with its own partition
4326+
alter table target_parted detach partition attach_parted;
4327+
insert into attach_parted_part1 values (2, 1);

src/test/regress/sql/alter_table.sql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,3 +2860,22 @@ select indexrelid::regclass, indisclustered from pg_index
28602860
where indrelid = 'alttype_cluster'::regclass
28612861
order by indexrelid::regclass::text;
28622862
drop table alttype_cluster;
2863+
2864+
--
2865+
-- Check that attaching or detaching a partitioned partition correctly leads
2866+
-- to its partitions' constraint being updated to reflect the parent's
2867+
-- newly added/removed constraint
2868+
create table target_parted (a int, b int) partition by list (a);
2869+
create table attach_parted (a int, b int) partition by list (b);
2870+
create table attach_parted_part1 partition of attach_parted for values in (1);
2871+
-- insert a row directly into the leaf partition so that its partition
2872+
-- constraint is built and stored in the relcache
2873+
insert into attach_parted_part1 values (1, 1);
2874+
-- the following better invalidate the partition constraint of the leaf
2875+
-- partition too...
2876+
alter table target_parted attach partition attach_parted for values in (1);
2877+
-- ...such that the following insert fails
2878+
insert into attach_parted_part1 values (2, 1);
2879+
-- ...and doesn't when the partition is detached along with its own partition
2880+
alter table target_parted detach partition attach_parted;
2881+
insert into attach_parted_part1 values (2, 1);

0 commit comments

Comments
 (0)