Skip to content

Commit d36bdc4

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 d1a6a08 commit d36bdc4

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

src/backend/commands/tablecmds.c

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

1399213992
ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
1399313993

13994+
/*
13995+
* If the partition we just attached is partitioned itself, invalidate
13996+
* relcache for all descendent partitions too to ensure that their
13997+
* rd_partcheck expression trees are rebuilt; partitions already locked
13998+
* at the beginning of this function.
13999+
*/
14000+
if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14001+
{
14002+
ListCell *l;
14003+
14004+
foreach(l, attachrel_children)
14005+
{
14006+
CacheInvalidateRelcacheByRelid(lfirst_oid(l));
14007+
}
14008+
}
14009+
1399414010
/* keep our lock until commit */
1399514011
heap_close(attachrel, NoLock);
1399614012

@@ -14054,6 +14070,26 @@ ATExecDetachPartition(Relation rel, RangeVar *name)
1405414070
*/
1405514071
CacheInvalidateRelcache(rel);
1405614072

14073+
/*
14074+
* If the partition we just detached is partitioned itself, invalidate
14075+
* relcache for all descendent partitions too to ensure that their
14076+
* rd_partcheck expression trees are rebuilt; must lock partitions
14077+
* before doing so, using the same lockmode as what partRel has been
14078+
* locked with by the caller.
14079+
*/
14080+
if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14081+
{
14082+
List *children;
14083+
ListCell *cell;
14084+
14085+
children = find_all_inheritors(RelationGetRelid(partRel),
14086+
AccessExclusiveLock, NULL);
14087+
foreach(cell, children)
14088+
{
14089+
CacheInvalidateRelcacheByRelid(lfirst_oid(cell));
14090+
}
14091+
}
14092+
1405714093
ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
1405814094

1405914095
/* 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
@@ -3856,3 +3856,23 @@ select indexrelid::regclass, indisclustered from pg_index
38563856
(2 rows)
38573857

38583858
drop table alttype_cluster;
3859+
--
3860+
-- Check that attaching or detaching a partitioned partition correctly leads
3861+
-- to its partitions' constraint being updated to reflect the parent's
3862+
-- newly added/removed constraint
3863+
create table target_parted (a int, b int) partition by list (a);
3864+
create table attach_parted (a int, b int) partition by list (b);
3865+
create table attach_parted_part1 partition of attach_parted for values in (1);
3866+
-- insert a row directly into the leaf partition so that its partition
3867+
-- constraint is built and stored in the relcache
3868+
insert into attach_parted_part1 values (1, 1);
3869+
-- the following better invalidate the partition constraint of the leaf
3870+
-- partition too...
3871+
alter table target_parted attach partition attach_parted for values in (1);
3872+
-- ...such that the following insert fails
3873+
insert into attach_parted_part1 values (2, 1);
3874+
ERROR: new row for relation "attach_parted_part1" violates partition constraint
3875+
DETAIL: Failing row contains (2, 1).
3876+
-- ...and doesn't when the partition is detached along with its own partition
3877+
alter table target_parted detach partition attach_parted;
3878+
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
@@ -2510,3 +2510,22 @@ select indexrelid::regclass, indisclustered from pg_index
25102510
where indrelid = 'alttype_cluster'::regclass
25112511
order by indexrelid::regclass::text;
25122512
drop table alttype_cluster;
2513+
2514+
--
2515+
-- Check that attaching or detaching a partitioned partition correctly leads
2516+
-- to its partitions' constraint being updated to reflect the parent's
2517+
-- newly added/removed constraint
2518+
create table target_parted (a int, b int) partition by list (a);
2519+
create table attach_parted (a int, b int) partition by list (b);
2520+
create table attach_parted_part1 partition of attach_parted for values in (1);
2521+
-- insert a row directly into the leaf partition so that its partition
2522+
-- constraint is built and stored in the relcache
2523+
insert into attach_parted_part1 values (1, 1);
2524+
-- the following better invalidate the partition constraint of the leaf
2525+
-- partition too...
2526+
alter table target_parted attach partition attach_parted for values in (1);
2527+
-- ...such that the following insert fails
2528+
insert into attach_parted_part1 values (2, 1);
2529+
-- ...and doesn't when the partition is detached along with its own partition
2530+
alter table target_parted detach partition attach_parted;
2531+
insert into attach_parted_part1 values (2, 1);

0 commit comments

Comments
 (0)