<para>
There must also be matching child-table constraints for all
- <literal>CHECK</literal> constraints of the parent. Currently
+ <literal>CHECK</literal> constraints of the parent, except those
+ marked non-inheritable (that is, created with <literal>ALTER TABLE ONLY</literal>)
+ in the parent, which are ignored; all child-table constraints matched
+ must not be marked non-inheritable.
+ Currently
<literal>UNIQUE</literal>, <literal>PRIMARY KEY</literal>, and
<literal>FOREIGN KEY</literal> constraints are not considered, but
this might change in the future.
*
* Returns TRUE if merged (constraint is a duplicate), or FALSE if it's
* got a so-far-unique name, or throws error if conflict.
+ *
+ * XXX See MergeConstraintsIntoExisting too if you change this code.
*/
static bool
MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("constraint \"%s\" for relation \"%s\" already exists",
ccname, RelationGetRelationName(rel))));
- /* OK to update the tuple */
- ereport(NOTICE,
- (errmsg("merging constraint \"%s\" with inherited definition",
- ccname)));
+
tup = heap_copytuple(tup);
con = (Form_pg_constraint) GETSTRUCT(tup);
+
+ /* If the constraint is "only" then cannot merge */
+ if (con->conisonly)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
+ ccname, RelationGetRelationName(rel))));
+
if (is_local)
con->conislocal = true;
else
Assert(is_local);
con->conisonly = true;
}
+ /* OK to update the tuple */
+ ereport(NOTICE,
+ (errmsg("merging constraint \"%s\" with inherited definition",
+ ccname)));
simple_heap_update(conDesc, &tup->t_self, tup);
CatalogUpdateIndexes(conDesc, tup);
break;
* 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)
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,
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.)