Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 3b11247

Browse files
committed
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
1 parent 1b9f774 commit 3b11247

File tree

3 files changed

+37
-10
lines changed

3 files changed

+37
-10
lines changed

doc/src/sgml/ref/alter_table.sgml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,11 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
482482

483483
<para>
484484
There must also be matching child-table constraints for all
485-
<literal>CHECK</literal> constraints of the parent. Currently
485+
<literal>CHECK</literal> constraints of the parent, except those
486+
marked non-inheritable (that is, created with <literal>ALTER TABLE ONLY</literal>)
487+
in the parent, which are ignored; all child-table constraints matched
488+
must not be marked non-inheritable.
489+
Currently
486490
<literal>UNIQUE</literal>, <literal>PRIMARY KEY</literal>, and
487491
<literal>FOREIGN KEY</literal> constraints are not considered, but
488492
this might change in the future.

src/backend/catalog/heap.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,6 +2251,8 @@ AddRelationNewConstraints(Relation rel,
22512251
*
22522252
* Returns TRUE if merged (constraint is a duplicate), or FALSE if it's
22532253
* got a so-far-unique name, or throws error if conflict.
2254+
*
2255+
* XXX See MergeConstraintsIntoExisting too if you change this code.
22542256
*/
22552257
static bool
22562258
MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
@@ -2307,12 +2309,17 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
23072309
(errcode(ERRCODE_DUPLICATE_OBJECT),
23082310
errmsg("constraint \"%s\" for relation \"%s\" already exists",
23092311
ccname, RelationGetRelationName(rel))));
2310-
/* OK to update the tuple */
2311-
ereport(NOTICE,
2312-
(errmsg("merging constraint \"%s\" with inherited definition",
2313-
ccname)));
2312+
23142313
tup = heap_copytuple(tup);
23152314
con = (Form_pg_constraint) GETSTRUCT(tup);
2315+
2316+
/* If the constraint is "only" then cannot merge */
2317+
if (con->conisonly)
2318+
ereport(ERROR,
2319+
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2320+
errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
2321+
ccname, RelationGetRelationName(rel))));
2322+
23162323
if (is_local)
23172324
con->conislocal = true;
23182325
else
@@ -2322,6 +2329,10 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
23222329
Assert(is_local);
23232330
con->conisonly = true;
23242331
}
2332+
/* OK to update the tuple */
2333+
ereport(NOTICE,
2334+
(errmsg("merging constraint \"%s\" with inherited definition",
2335+
ccname)));
23252336
simple_heap_update(conDesc, &tup->t_self, tup);
23262337
CatalogUpdateIndexes(conDesc, tup);
23272338
break;

src/backend/commands/tablecmds.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8818,18 +8818,18 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
88188818
* Check constraints in child table match up with constraints in parent,
88198819
* and increment their coninhcount.
88208820
*
8821+
* Constraints that are marked ONLY in the parent are ignored.
8822+
*
88218823
* Called by ATExecAddInherit
88228824
*
88238825
* Currently all constraints in parent must be present in the child. One day we
8824-
* may consider adding new constraints like CREATE TABLE does. We may also want
8825-
* to allow an optional flag on parent table constraints indicating they are
8826-
* intended to ONLY apply to the master table, not to the children. That would
8827-
* make it possible to ensure no records are mistakenly inserted into the
8828-
* master in partitioned tables rather than the appropriate child.
8826+
* may consider adding new constraints like CREATE TABLE does.
88298827
*
88308828
* XXX This is O(N^2) which may be an issue with tables with hundreds of
88318829
* constraints. As long as tables have more like 10 constraints it shouldn't be
88328830
* a problem though. Even 100 constraints ought not be the end of the world.
8831+
*
8832+
* XXX See MergeWithExistingConstraint too if you change this code.
88338833
*/
88348834
static void
88358835
MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
@@ -8862,6 +8862,10 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
88628862
if (parent_con->contype != CONSTRAINT_CHECK)
88638863
continue;
88648864

8865+
/* if the parent's constraint is marked ONLY, it's not inherited */
8866+
if (parent_con->conisonly)
8867+
continue;
8868+
88658869
/* Search for a child constraint matching this one */
88668870
ScanKeyInit(&child_key,
88678871
Anum_pg_constraint_conrelid,
@@ -8889,6 +8893,14 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
88898893
RelationGetRelationName(child_rel),
88908894
NameStr(parent_con->conname))));
88918895

8896+
/* If the constraint is "only" then cannot merge */
8897+
if (child_con->conisonly)
8898+
ereport(ERROR,
8899+
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
8900+
errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
8901+
NameStr(child_con->conname),
8902+
RelationGetRelationName(child_rel))));
8903+
88928904
/*
88938905
* OK, bump the child constraint's inheritance count. (If we fail
88948906
* later on, this change will just roll back.)

0 commit comments

Comments
 (0)