diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2019-01-18 14:49:40 -0300 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2019-01-18 14:57:49 -0300 |
commit | 4dff8935fbab64aef38470424cc57dbda9efa1cf (patch) | |
tree | 30945215314c799aff9a25573a3fda6a6e4c906d /src/backend/commands/tablecmds.c | |
parent | fca6cabed17c4960224408d44e3d384b560b78f5 (diff) | |
download | postgresql-4dff8935fbab64aef38470424cc57dbda9efa1cf.tar.gz postgresql-4dff8935fbab64aef38470424cc57dbda9efa1cf.zip |
Fix creation of duplicate foreign keys on partitions
When creating a foreign key in a partitioned table, if some partitions
already have equivalent constraints, we wastefully create duplicates of
the constraints instead of attaching to the existing ones. That's
inconsistent with the de-duplication that is applied when a table is
attached as a partition. To fix, reuse the FK-cloning code instead of
having a separate code path.
Backpatch to Postgres 11. This is a subtle behavior change, but surely
a welcome one since there's no use in having duplicate foreign keys.
Discovered by Álvaro Herrera while thinking about a different problem
reported by Jesper Pedersen (bug #15587).
Author: Álvaro Herrera
Discussion: https://postgr.es/m/201901151935.zfadrzvyof4k@alvherre.pgsql
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index b1b7fe11ac0..9893c352170 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -7751,30 +7751,49 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, if (recurse && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { PartitionDesc partdesc; + Relation pg_constraint; + List *cloned = NIL; + ListCell *cell; + pg_constraint = heap_open(ConstraintRelationId, RowExclusiveLock); partdesc = RelationGetPartitionDesc(rel); for (i = 0; i < partdesc->nparts; i++) { Oid partitionId = partdesc->oids[i]; Relation partition = heap_open(partitionId, lockmode); - AlteredTableInfo *childtab; - ObjectAddress childAddr; CheckTableNotInUse(partition, "ALTER TABLE"); - /* Find or create work queue entry for this table */ + CloneFkReferencing(pg_constraint, rel, partition, + list_make1_oid(constrOid), + &cloned); + + heap_close(partition, NoLock); + } + heap_close(pg_constraint, RowExclusiveLock); + + foreach(cell, cloned) + { + ClonedConstraint *cc = (ClonedConstraint *) lfirst(cell); + Relation partition = heap_open(cc->relid, lockmode); + AlteredTableInfo *childtab; + NewConstraint *newcon; + + /* Find or create work queue entry for this partition */ childtab = ATGetQueueEntry(wqueue, partition); - childAddr = - ATAddForeignKeyConstraint(wqueue, childtab, partition, - fkconstraint, constrOid, - recurse, true, lockmode); + newcon = (NewConstraint *) palloc0(sizeof(NewConstraint)); + newcon->name = cc->constraint->conname; + newcon->contype = CONSTR_FOREIGN; + newcon->refrelid = cc->refrelid; + newcon->refindid = cc->conindid; + newcon->conid = cc->conid; + newcon->qual = (Node *) fkconstraint; - /* Record this constraint as dependent on the parent one */ - recordDependencyOn(&childAddr, &address, DEPENDENCY_INTERNAL_AUTO); + childtab->constraints = lappend(childtab->constraints, newcon); - heap_close(partition, NoLock); + heap_close(partition, lockmode); } } |