summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorAlvaro Herrera2022-10-07 17:37:48 +0000
committerAlvaro Herrera2022-10-07 17:37:48 +0000
commit7d520e68ea1e38a9f7ad1d04bd5f95d53eef6cd4 (patch)
tree4b1f85bda88879e16cf953537930740a6ab76b2c /src/backend
parent92941f26435ce3910bb9320fd92bda1e3dd4c6b5 (diff)
Fix self-referencing foreign keys with partitioned tables
There are a number of bugs in this area. Two of them are fixed here, namely: 1. get_relation_idx_constraint_oid does not restrict the type of constraint that's returned, so with sufficient bad luck it can return the OID of a foreign key constraint. This has the effect that a primary key in a partition can end up as a child of a foreign key, which makes no sense (it needs to be the child of the equivalent primary key.) Change the API contract so that only index-backed constraints are returned, mimicking get_constraint_index(). 2. Both CloneFkReferenced and CloneFkReferencing clone a self-referencing foreign key, so the partition ends up with a duplicate foreign key. Change the former function to ignore such constraints. Add some tests to verify that things are better now. (However, these new tests show some additional misbehavior that will be fixed later -- namely that there's a constraint marked NOT VALID.) Backpatch to 12, where these constraints are possible at all. Author: Jehan-Guillaume de Rorthais <jgdr@dalibo.com> Discussion: https://postgr.es/m/20220603154232.1715b14c@karst
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/pg_constraint.c13
-rw-r--r--src/backend/commands/tablecmds.c13
2 files changed, 25 insertions, 1 deletions
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 90932be8310..c54c18d62bc 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -973,8 +973,12 @@ get_relation_constraint_attnos(Oid relid, const char *conname,
}
/*
- * Return the OID of the constraint associated with the given index in the
+ * Return the OID of the constraint enforced by the given index in the
* given relation; or InvalidOid if no such index is catalogued.
+ *
+ * Much like get_constraint_index, this function is concerned only with the
+ * one constraint that "owns" the given index. Therefore, constraints of
+ * types other than unique, primary-key, and exclusion are ignored.
*/
Oid
get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
@@ -999,6 +1003,13 @@ get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
Form_pg_constraint constrForm;
constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
+
+ /* See above */
+ if (constrForm->contype != CONSTRAINT_PRIMARY &&
+ constrForm->contype != CONSTRAINT_UNIQUE &&
+ constrForm->contype != CONSTRAINT_EXCLUSION)
+ continue;
+
if (constrForm->conindid == indexId)
{
constraintId = constrForm->oid;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3df5c5681f3..4d67176b64b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -9356,6 +9356,8 @@ CloneForeignKeyConstraints(List **wqueue, Relation parentRel,
* clone those constraints to the given partition. This is to be called
* when the partition is being created or attached.
*
+ * This ignores self-referencing FKs; those are handled by CloneFkReferencing.
+ *
* This recurses to partitions, if the relation being attached is partitioned.
* Recursion is done by calling addFkRecurseReferenced.
*/
@@ -9432,6 +9434,17 @@ CloneFkReferenced(Relation parentRel, Relation partitionRel)
}
/*
+ * Don't clone self-referencing foreign keys, which can be in the
+ * partitioned table or in the partition-to-be.
+ */
+ if (constrForm->conrelid == RelationGetRelid(parentRel) ||
+ constrForm->conrelid == RelationGetRelid(partitionRel))
+ {
+ ReleaseSysCache(tuple);
+ continue;
+ }
+
+ /*
* Because we're only expanding the key space at the referenced side,
* we don't need to prevent any operation in the referencing table, so
* AccessShareLock suffices (assumes that dropping the constraint