1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-24 00:23:06 +03:00

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
This commit is contained in:
Alvaro Herrera
2022-10-07 19:37:48 +02:00
parent 3edc71ec04
commit 614a406b4f
4 changed files with 161 additions and 1 deletions

View File

@@ -985,8 +985,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)
@@ -1011,6 +1015,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;