1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-16 06:01:02 +03:00

Disallow merging ONLY constraints in children tables

When creating a child table, or when attaching an existing table as
child of another, we must not allow inheritable constraints to be
merged with non-inheritable ones, because then grandchildren would not
properly get the constraint.  This would violate the grandparent's
expectations.

Bugs noted by Robert Haas.

Author: Nikhil Sontakke
This commit is contained in:
Alvaro Herrera
2012-01-16 19:19:42 -03:00
parent 1b9f774090
commit 3b11247aad
3 changed files with 37 additions and 10 deletions

View File

@ -8818,18 +8818,18 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
* Check constraints in child table match up with constraints in parent,
* and increment their coninhcount.
*
* Constraints that are marked ONLY in the parent are ignored.
*
* Called by ATExecAddInherit
*
* Currently all constraints in parent must be present in the child. One day we
* may consider adding new constraints like CREATE TABLE does. We may also want
* to allow an optional flag on parent table constraints indicating they are
* intended to ONLY apply to the master table, not to the children. That would
* make it possible to ensure no records are mistakenly inserted into the
* master in partitioned tables rather than the appropriate child.
* may consider adding new constraints like CREATE TABLE does.
*
* XXX This is O(N^2) which may be an issue with tables with hundreds of
* constraints. As long as tables have more like 10 constraints it shouldn't be
* a problem though. Even 100 constraints ought not be the end of the world.
*
* XXX See MergeWithExistingConstraint too if you change this code.
*/
static void
MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
@ -8862,6 +8862,10 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
if (parent_con->contype != CONSTRAINT_CHECK)
continue;
/* if the parent's constraint is marked ONLY, it's not inherited */
if (parent_con->conisonly)
continue;
/* Search for a child constraint matching this one */
ScanKeyInit(&child_key,
Anum_pg_constraint_conrelid,
@ -8889,6 +8893,14 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
RelationGetRelationName(child_rel),
NameStr(parent_con->conname))));
/* If the constraint is "only" then cannot merge */
if (child_con->conisonly)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
NameStr(child_con->conname),
RelationGetRelationName(child_rel))));
/*
* OK, bump the child constraint's inheritance count. (If we fail
* later on, this change will just roll back.)