aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r--src/backend/commands/tablecmds.c30
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;