diff options
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 040eb50078c..954266bc1c5 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -18779,6 +18779,7 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, HeapTuple tuple, newtuple; Relation trigrel = NULL; + List *fkoids = NIL; if (concurrent) { @@ -18799,6 +18800,27 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, fks = copyObject(RelationGetFKeyList(partRel)); if (fks != NIL) trigrel = table_open(TriggerRelationId, RowExclusiveLock); + + /* + * It's possible that the partition being detached has a foreign key that + * references a partitioned table. When that happens, there are multiple + * pg_constraint rows for the partition: one points to the partitioned + * table itself, while the others point to each of its partitions. Only + * the topmost one is to be considered here; the child constraints must be + * left alone, because conceptually those aren't coming from our parent + * partitioned table, but from this partition itself. + * + * We implement this by collecting all the constraint OIDs in a first scan + * of the FK array, and skipping in the loop below those constraints whose + * parents are listed here. + */ + foreach(cell, fks) + { + ForeignKeyCacheInfo *fk = (ForeignKeyCacheInfo *) lfirst(cell); + + fkoids = lappend_oid(fkoids, fk->conoid); + } + foreach(cell, fks) { ForeignKeyCacheInfo *fk = lfirst(cell); @@ -18812,9 +18834,13 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, elog(ERROR, "cache lookup failed for constraint %u", fk->conoid); conform = (Form_pg_constraint) GETSTRUCT(contup); - /* consider only the inherited foreign keys */ + /* + * Consider only inherited foreign keys, and only if their parents + * aren't in the list. + */ if (conform->contype != CONSTRAINT_FOREIGN || - !OidIsValid(conform->conparentid)) + !OidIsValid(conform->conparentid) || + list_member_oid(fkoids, conform->conparentid)) { ReleaseSysCache(contup); continue; |