From 416fe76c1b8095a14e1b2d39315ad32242cf9629 Mon Sep 17 00:00:00 2001 From: amitlan Date: Fri, 27 Aug 2021 15:40:57 +0900 Subject: [PATCH v3] Invalidate partitions of table being attached/detached MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Reported by: Hou Zhijie Author: Álvaro Herrera, Amit Langote Discussion: https://postgr.es/m/OS3PR01MB5718DA1C4609A25186D1FBF194089%40OS3PR01MB5718.jpnprd01.prod.outlook.com --- src/backend/commands/tablecmds.c | 38 +++++++++++++++++++++++ src/test/regress/expected/alter_table.out | 21 +++++++++++++ src/test/regress/sql/alter_table.sql | 21 +++++++++++++ 3 files changed, 80 insertions(+) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index dbee6ae199..1b50654c59 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -17460,6 +17460,24 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd, ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel)); + /* + * If the partition we just attached is partitioned itself, invalidate + * relcache for all descendent partitions too to ensure that their + * rd_partcheck expression trees are rebuilt; partitions already locked + * at the beginning of this function. + */ + if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + ListCell *l; + + foreach(l, attachrel_children) + { + Oid partOid = lfirst_oid(l); + + CacheInvalidateRelcacheByRelid(partOid); + } + } + /* keep our lock until commit */ table_close(attachrel, NoLock); @@ -18150,6 +18168,26 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, * included in its partition descriptor. */ CacheInvalidateRelcache(rel); + + /* + * If the partition we just detached is partitioned itself, invalidate + * relcache for all descendent partitions too to ensure that their + * rd_partcheck expression trees are rebuilt; must lock partitions + * before doing so. + */ + if (partRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + List *partRel_children = + find_all_inheritors(RelationGetRelid(partRel), + AccessExclusiveLock, NULL); + + foreach(cell, partRel_children) + { + Oid partOid = lfirst_oid(cell); + + CacheInvalidateRelcacheByRelid(partOid); + } + } } /* diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 4bee0c1173..a4dd7b7410 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -4489,3 +4489,24 @@ select indexrelid::regclass, indisclustered from pg_index (2 rows) drop table alttype_cluster; +-- +-- Check that attaching or detaching a partitioned partition correctly leads +-- to its partitions' constraint being updated to reflect the parent's +-- newly added/removed constraint +-- Report: https://postgr.es/m/OS3PR01MB5718DA1C4609A25186D1FBF194089%40OS3PR01MB5718.jpnprd01.prod.outlook.com +create table target_parted (a int, b int) partition by list (a); +create table attach_parted (a int, b int) partition by list (b); +create table attach_parted_part1 partition of attach_parted for values in (1); +-- insert a row directly into the leaf partition so that its partition +-- constraint is built and stored in the relcache +insert into attach_parted_part1 values (1, 1); +-- the following better invalidate the partition constraint of the leaf +-- partition too... +alter table target_parted attach partition attach_parted for values in (1); +-- ...such that the following insert fails +insert into attach_parted_part1 values (2, 1); +ERROR: new row for relation "attach_parted_part1" violates partition constraint +DETAIL: Failing row contains (2, 1). +-- and the following too, in the reverse direction +alter table target_parted detach partition attach_parted; +insert into attach_parted_part1 values (2, 1); diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index dc0200adcb..ac4ad7c00d 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2940,3 +2940,24 @@ select indexrelid::regclass, indisclustered from pg_index where indrelid = 'alttype_cluster'::regclass order by indexrelid::regclass::text; drop table alttype_cluster; + +-- +-- Check that attaching or detaching a partitioned partition correctly leads +-- to its partitions' constraint being updated to reflect the parent's +-- newly added/removed constraint +-- Report: https://postgr.es/m/OS3PR01MB5718DA1C4609A25186D1FBF194089%40OS3PR01MB5718.jpnprd01.prod.outlook.com + +create table target_parted (a int, b int) partition by list (a); +create table attach_parted (a int, b int) partition by list (b); +create table attach_parted_part1 partition of attach_parted for values in (1); +-- insert a row directly into the leaf partition so that its partition +-- constraint is built and stored in the relcache +insert into attach_parted_part1 values (1, 1); +-- the following better invalidate the partition constraint of the leaf +-- partition too... +alter table target_parted attach partition attach_parted for values in (1); +-- ...such that the following insert fails +insert into attach_parted_part1 values (2, 1); +-- and the following too, in the reverse direction +alter table target_parted detach partition attach_parted; +insert into attach_parted_part1 values (2, 1); -- 2.24.1