Skip to content

Commit 8b26be8

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 a207b85 commit 8b26be8

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
@@ -16341,6 +16341,22 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1634116341

1634216342
ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
1634316343

16344+
/*
16345+
* If the partition we just attached is partitioned itself, invalidate
16346+
* relcache for all descendent partitions too to ensure that their
16347+
* rd_partcheck expression trees are rebuilt; partitions already locked
16348+
* at the beginning of this function.
16349+
*/
16350+
if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16351+
{
16352+
ListCell *l;
16353+
16354+
foreach(l, attachrel_children)
16355+
{
16356+
CacheInvalidateRelcacheByRelid(lfirst_oid(l));
16357+
}
16358+
}
16359+
1634416360
/* keep our lock until commit */
1634516361
table_close(attachrel, NoLock);
1634616362

@@ -16917,6 +16933,25 @@ ATExecDetachPartition(Relation rel, RangeVar *name)
1691716933
*/
1691816934
CacheInvalidateRelcache(rel);
1691916935

16936+
/*
16937+
* If the partition we just detached is partitioned itself, invalidate
16938+
* relcache for all descendent partitions too to ensure that their
16939+
* rd_partcheck expression trees are rebuilt; must lock partitions
16940+
* before doing so, using the same lockmode as what partRel has been
16941+
* locked with by the caller.
16942+
*/
16943+
if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16944+
{
16945+
List *children;
16946+
16947+
children = find_all_inheritors(RelationGetRelid(partRel),
16948+
AccessExclusiveLock, NULL);
16949+
foreach(cell, children)
16950+
{
16951+
CacheInvalidateRelcacheByRelid(lfirst_oid(cell));
16952+
}
16953+
}
16954+
1692016955
ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
1692116956

1692216957
/* 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
@@ -4279,3 +4279,23 @@ select indexrelid::regclass, indisclustered from pg_index
42794279
(2 rows)
42804280

42814281
drop table alttype_cluster;
4282+
--
4283+
-- Check that attaching or detaching a partitioned partition correctly leads
4284+
-- to its partitions' constraint being updated to reflect the parent's
4285+
-- newly added/removed constraint
4286+
create table target_parted (a int, b int) partition by list (a);
4287+
create table attach_parted (a int, b int) partition by list (b);
4288+
create table attach_parted_part1 partition of attach_parted for values in (1);
4289+
-- insert a row directly into the leaf partition so that its partition
4290+
-- constraint is built and stored in the relcache
4291+
insert into attach_parted_part1 values (1, 1);
4292+
-- the following better invalidate the partition constraint of the leaf
4293+
-- partition too...
4294+
alter table target_parted attach partition attach_parted for values in (1);
4295+
-- ...such that the following insert fails
4296+
insert into attach_parted_part1 values (2, 1);
4297+
ERROR: new row for relation "attach_parted_part1" violates partition constraint
4298+
DETAIL: Failing row contains (2, 1).
4299+
-- ...and doesn't when the partition is detached along with its own partition
4300+
alter table target_parted detach partition attach_parted;
4301+
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
@@ -2872,3 +2872,22 @@ select indexrelid::regclass, indisclustered from pg_index
28722872
where indrelid = 'alttype_cluster'::regclass
28732873
order by indexrelid::regclass::text;
28742874
drop table alttype_cluster;
2875+
2876+
--
2877+
-- Check that attaching or detaching a partitioned partition correctly leads
2878+
-- to its partitions' constraint being updated to reflect the parent's
2879+
-- newly added/removed constraint
2880+
create table target_parted (a int, b int) partition by list (a);
2881+
create table attach_parted (a int, b int) partition by list (b);
2882+
create table attach_parted_part1 partition of attach_parted for values in (1);
2883+
-- insert a row directly into the leaf partition so that its partition
2884+
-- constraint is built and stored in the relcache
2885+
insert into attach_parted_part1 values (1, 1);
2886+
-- the following better invalidate the partition constraint of the leaf
2887+
-- partition too...
2888+
alter table target_parted attach partition attach_parted for values in (1);
2889+
-- ...such that the following insert fails
2890+
insert into attach_parted_part1 values (2, 1);
2891+
-- ...and doesn't when the partition is detached along with its own partition
2892+
alter table target_parted detach partition attach_parted;
2893+
insert into attach_parted_part1 values (2, 1);

0 commit comments

Comments
 (0)