diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml
index c3039c8167..3af65accea 100644
--- a/doc/src/sgml/ref/alter_table.sgml
+++ b/doc/src/sgml/ref/alter_table.sgml
@@ -907,7 +907,8 @@ ALTER TABLE [ IF EXISTS ] name
and TABLESPACE> actions never recurse to descendant tables;
that is, they always act as though ONLY> were specified.
Adding a constraint can recurse only for CHECK> constraints,
- and is required to do so for such constraints.
+ and is required to do so for such constraints, except those that are
+ explicitely marked NO INHERIT>.
@@ -1013,7 +1014,7 @@ ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
To add a check constraint only to a table and not to its children:
-ALTER TABLE ONLY distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
+ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK NO INHERIT (char_length(zipcode) = 5);
(The check constraint will not be inherited by future children, either.)
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index bb93214210..4da6eea758 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -47,7 +47,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
[ CONSTRAINT constraint_name ]
{ NOT NULL |
NULL |
- CHECK ( expression ) |
+ CHECK [ NO INHERIT ] ( expression ) |
DEFAULT default_expr |
UNIQUE index_parameters |
PRIMARY KEY index_parameters |
@@ -58,7 +58,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
and table_constraint is:
[ CONSTRAINT constraint_name ]
-{ CHECK ( expression ) |
+{ CHECK [ NO INHERIT ] ( expression ) |
UNIQUE ( column_name [, ... ] ) index_parameters |
PRIMARY KEY ( column_name [, ... ] ) index_parameters |
EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ] |
@@ -299,7 +299,8 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
contain identically-named CHECK> constraints, these
constraints must all have the same check expression, or an error will be
reported. Constraints having the same name and expression will
- be merged into one copy. Notice that an unnamed CHECK>
+ be merged into one copy. A constraint marked NO INHERIT> in a
+ parent will not be considered. Notice that an unnamed CHECK>
constraint in the new table will never be merged, since a unique name
will always be chosen for it.
@@ -415,7 +416,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
- CHECK ( expression )
+ CHECK [ NO INHERIT ] ( expression )
The CHECK> clause specifies an expression producing a
@@ -434,6 +435,11 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
subqueries nor refer to variables other than columns of the
current row.
+
+
+ A constraint marked with NO INHERIT> will not propagate to
+ children tables.
+
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 8bd5a9296e..d029a25c11 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -92,10 +92,12 @@ static Oid AddNewRelationType(const char *typeName,
Oid new_array_type);
static void RelationRemoveInheritance(Oid relid);
static void StoreRelCheck(Relation rel, char *ccname, Node *expr,
- bool is_validated, bool is_local, int inhcount, bool is_only);
+ bool is_validated, bool is_local, int inhcount,
+ bool is_no_inherit);
static void StoreConstraints(Relation rel, List *cooked_constraints);
static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
- bool allow_merge, bool is_local, bool is_only);
+ bool allow_merge, bool is_local,
+ bool is_no_inherit);
static void SetRelationNumChecks(Relation rel, int numchecks);
static Node *cookConstraint(ParseState *pstate,
Node *raw_constraint,
@@ -1868,7 +1870,8 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr)
*/
static void
StoreRelCheck(Relation rel, char *ccname, Node *expr,
- bool is_validated, bool is_local, int inhcount, bool is_only)
+ bool is_validated, bool is_local, int inhcount,
+ bool is_no_inherit)
{
char *ccbin;
char *ccsrc;
@@ -1952,7 +1955,7 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
ccsrc, /* Source form of check constraint */
is_local, /* conislocal */
inhcount, /* coninhcount */
- is_only); /* conisonly */
+ is_no_inherit); /* connoinherit */
pfree(ccbin);
pfree(ccsrc);
@@ -1993,7 +1996,7 @@ StoreConstraints(Relation rel, List *cooked_constraints)
break;
case CONSTR_CHECK:
StoreRelCheck(rel, con->name, con->expr, !con->skip_validation,
- con->is_local, con->inhcount, con->is_only);
+ con->is_local, con->inhcount, con->is_no_inherit);
numchecks++;
break;
default:
@@ -2036,8 +2039,7 @@ AddRelationNewConstraints(Relation rel,
List *newColDefaults,
List *newConstraints,
bool allow_merge,
- bool is_local,
- bool is_only)
+ bool is_local)
{
List *cookedConstraints = NIL;
TupleDesc tupleDesc;
@@ -2110,7 +2112,7 @@ AddRelationNewConstraints(Relation rel,
cooked->skip_validation = false;
cooked->is_local = is_local;
cooked->inhcount = is_local ? 0 : 1;
- cooked->is_only = is_only;
+ cooked->is_no_inherit = false;
cookedConstraints = lappend(cookedConstraints, cooked);
}
@@ -2178,7 +2180,8 @@ AddRelationNewConstraints(Relation rel,
* what ATAddCheckConstraint wants.)
*/
if (MergeWithExistingConstraint(rel, ccname, expr,
- allow_merge, is_local, is_only))
+ allow_merge, is_local,
+ cdef->is_no_inherit))
continue;
}
else
@@ -2225,7 +2228,7 @@ AddRelationNewConstraints(Relation rel,
* OK, store it.
*/
StoreRelCheck(rel, ccname, expr, !cdef->skip_validation, is_local,
- is_local ? 0 : 1, is_only);
+ is_local ? 0 : 1, cdef->is_no_inherit);
numchecks++;
@@ -2237,7 +2240,7 @@ AddRelationNewConstraints(Relation rel,
cooked->skip_validation = cdef->skip_validation;
cooked->is_local = is_local;
cooked->inhcount = is_local ? 0 : 1;
- cooked->is_only = is_only;
+ cooked->is_no_inherit = cdef->is_no_inherit;
cookedConstraints = lappend(cookedConstraints, cooked);
}
@@ -2266,7 +2269,7 @@ AddRelationNewConstraints(Relation rel,
static bool
MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
bool allow_merge, bool is_local,
- bool is_only)
+ bool is_no_inherit)
{
bool found;
Relation conDesc;
@@ -2322,8 +2325,8 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
tup = heap_copytuple(tup);
con = (Form_pg_constraint) GETSTRUCT(tup);
- /* If the constraint is "only" then cannot merge */
- if (con->conisonly)
+ /* If the constraint is "no inherit" then cannot merge */
+ if (con->connoinherit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
@@ -2333,10 +2336,10 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
con->conislocal = true;
else
con->coninhcount++;
- if (is_only)
+ if (is_no_inherit)
{
Assert(is_local);
- con->conisonly = true;
+ con->connoinherit = true;
}
/* OK to update the tuple */
ereport(NOTICE,
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 3fd0e60457..998379c8af 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1156,7 +1156,7 @@ index_constraint_create(Relation heapRelation,
NULL,
true, /* islocal */
0, /* inhcount */
- false); /* isonly */
+ false); /* noinherit */
/*
* Register the index as internally dependent on the constraint.
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index bf174b6a46..dca5d09ee6 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -67,7 +67,7 @@ CreateConstraintEntry(const char *constraintName,
const char *conSrc,
bool conIsLocal,
int conInhCount,
- bool conIsOnly)
+ bool conNoInherit)
{
Relation conDesc;
Oid conOid;
@@ -170,7 +170,7 @@ CreateConstraintEntry(const char *constraintName,
values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
- values[Anum_pg_constraint_conisonly - 1] = BoolGetDatum(conIsOnly);
+ values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
if (conkeyArray)
values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index a4a36045df..3f0945b57d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -601,7 +601,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
cooked->skip_validation = false;
cooked->is_local = true; /* not used for defaults */
cooked->inhcount = 0; /* ditto */
- cooked->is_only = false;
+ cooked->is_no_inherit = false;
cookedDefaults = lappend(cookedDefaults, cooked);
descriptor->attrs[attnum - 1]->atthasdef = true;
}
@@ -661,7 +661,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
*/
if (rawDefaults || stmt->constraints)
AddRelationNewConstraints(rel, rawDefaults, stmt->constraints,
- true, true, false);
+ true, true);
/*
* Clean up. We keep lock on new relation (although it shouldn't be
@@ -1655,7 +1655,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
Node *expr;
/* ignore if the constraint is non-inheritable */
- if (check[i].cconly)
+ if (check[i].ccnoinherit)
continue;
/* adjust varattnos of ccbin here */
@@ -1676,7 +1676,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
cooked->skip_validation = false;
cooked->is_local = false;
cooked->inhcount = 1;
- cooked->is_only = false;
+ cooked->is_no_inherit = false;
constraints = lappend(constraints, cooked);
}
}
@@ -2399,7 +2399,7 @@ rename_constraint_internal(Oid myrelid,
constraintOid);
con = (Form_pg_constraint) GETSTRUCT(tuple);
- if (myrelid && con->contype == CONSTRAINT_CHECK && !con->conisonly)
+ if (myrelid && con->contype == CONSTRAINT_CHECK && !con->connoinherit)
{
if (recurse)
{
@@ -4573,7 +4573,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
* This function is intended for CREATE TABLE, so it processes a
* _list_ of defaults, but we just do one.
*/
- AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true, false);
+ AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true);
/* Make the additional catalog changes visible */
CommandCounterIncrement();
@@ -5015,7 +5015,7 @@ ATExecColumnDefault(Relation rel, const char *colName,
* This function is intended for CREATE TABLE, so it processes a
* _list_ of defaults, but we just do one.
*/
- AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true, false);
+ AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true);
}
}
@@ -5680,16 +5680,11 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
* omitted from the returned list, which is what we want: we do not need
* to do any validation work. That can only happen at child tables,
* though, since we disallow merging at the top level.
- *
- * Note: we set is_only based on the recurse flag which is false when
- * interpretInhOption() of our statement returns false all the way up
- * in AlterTable and gets passed all the way down to here.
*/
newcons = AddRelationNewConstraints(rel, NIL,
list_make1(copyObject(constr)),
- recursing, /* allow_merge */
- !recursing, /* is_local */
- !recurse && !recursing); /* is_only */
+ recursing, /* allow_merge */
+ !recursing); /* is_local */
/* Add each to-be-validated constraint to Phase 3's queue */
foreach(lcon, newcons)
@@ -5730,9 +5725,9 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
return;
/*
- * Adding an ONLY constraint? No need to find our children
+ * Adding a NO INHERIT constraint? No need to find our children
*/
- if (!recurse && !recursing)
+ if (constr->is_no_inherit)
return;
/*
@@ -5742,6 +5737,16 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
*/
children = find_inheritance_children(RelationGetRelid(rel), lockmode);
+ /*
+ * Check if ONLY was specified with ALTER TABLE. If so, allow the
+ * contraint creation only if there are no children currently. Error out
+ * otherwise.
+ */
+ if (!recurse && children != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("constraint must be added to child tables too")));
+
foreach(child, children)
{
Oid childrelid = lfirst_oid(child);
@@ -6127,7 +6132,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
NULL,
true, /* islocal */
0, /* inhcount */
- false); /* isonly */
+ false); /* isnoinherit */
/*
* Create the triggers that will enforce the constraint.
@@ -6998,8 +7003,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
ScanKeyData key;
HeapTuple tuple;
bool found = false;
- bool is_check_constraint = false;
- bool is_only_constraint = false;
+ bool is_no_inherit_constraint = false;
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
@@ -7033,15 +7037,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
constrName, RelationGetRelationName(rel))));
- /* Right now only CHECK constraints can be inherited */
- if (con->contype == CONSTRAINT_CHECK)
- is_check_constraint = true;
-
- if (con->conisonly)
- {
- Assert(is_check_constraint);
- is_only_constraint = true;
- }
+ is_no_inherit_constraint = con->connoinherit;
/*
* Perform the actual constraint deletion
@@ -7084,7 +7080,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
* routines, we have to do this one level of recursion at a time; we can't
* use find_all_inheritors to do it in one pass.
*/
- if (is_check_constraint && !is_only_constraint)
+ if (!is_no_inherit_constraint)
children = find_inheritance_children(RelationGetRelid(rel), lockmode);
else
children = NIL;
@@ -9250,8 +9246,8 @@ 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)
+ /* if the parent's constraint is marked NO INHERIT, it's not inherited */
+ if (parent_con->connoinherit)
continue;
/* Search for a child constraint matching this one */
@@ -9281,8 +9277,8 @@ 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)
+ /* If the constraint is "no inherit" then cannot merge */
+ if (child_con->connoinherit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"",
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index a98d1b884e..1218d033d1 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -459,7 +459,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
NULL,
true, /* islocal */
0, /* inhcount */
- false); /* isonly */
+ false); /* isnoinherit */
}
/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index fc396c5d30..0db60b161b 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2340,6 +2340,7 @@ _copyConstraint(const Constraint *from)
COPY_SCALAR_FIELD(deferrable);
COPY_SCALAR_FIELD(initdeferred);
COPY_LOCATION_FIELD(location);
+ COPY_SCALAR_FIELD(is_no_inherit);
COPY_NODE_FIELD(raw_expr);
COPY_STRING_FIELD(cooked_expr);
COPY_NODE_FIELD(keys);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index b0460970d5..9d588feac2 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2198,6 +2198,7 @@ _equalConstraint(const Constraint *a, const Constraint *b)
COMPARE_SCALAR_FIELD(deferrable);
COMPARE_SCALAR_FIELD(initdeferred);
COMPARE_LOCATION_FIELD(location);
+ COMPARE_SCALAR_FIELD(is_no_inherit);
COMPARE_NODE_FIELD(raw_expr);
COMPARE_STRING_FIELD(cooked_expr);
COMPARE_NODE_FIELD(keys);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index dbed70b21d..e690194b74 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2607,6 +2607,7 @@ _outConstraint(StringInfo str, const Constraint *node)
case CONSTR_CHECK:
appendStringInfo(str, "CHECK");
+ WRITE_BOOL_FIELD(is_no_inherit);
WRITE_NODE_FIELD(raw_expr);
WRITE_STRING_FIELD(cooked_expr);
break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ae1658a4ff..a289d4bd14 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -420,7 +420,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
%type character
%type extract_arg
%type opt_charset
-%type opt_varying opt_timezone
+%type opt_varying opt_timezone opt_no_inherit
%type Iconst SignedIconst
%type Sconst comment_text notify_payload
@@ -2685,12 +2685,13 @@ ColConstraintElem:
n->indexspace = $4;
$$ = (Node *)n;
}
- | CHECK '(' a_expr ')'
+ | CHECK opt_no_inherit '(' a_expr ')'
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_CHECK;
n->location = @1;
- n->raw_expr = $3;
+ n->is_no_inherit = $2;
+ n->raw_expr = $4;
n->cooked_expr = NULL;
$$ = (Node *)n;
}
@@ -2810,14 +2811,15 @@ TableConstraint:
;
ConstraintElem:
- CHECK '(' a_expr ')' ConstraintAttributeSpec
+ CHECK opt_no_inherit '(' a_expr ')' ConstraintAttributeSpec
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_CHECK;
n->location = @1;
- n->raw_expr = $3;
+ n->is_no_inherit = $2;
+ n->raw_expr = $4;
n->cooked_expr = NULL;
- processCASbits($5, @5, "CHECK",
+ processCASbits($6, @6, "CHECK",
NULL, NULL, &n->skip_validation,
yyscanner);
n->initially_valid = !n->skip_validation;
@@ -2920,6 +2922,10 @@ ConstraintElem:
}
;
+opt_no_inherit: NO INHERIT { $$ = TRUE; }
+ | /* EMPTY */ { $$ = FALSE; }
+ ;
+
opt_column_list:
'(' columnList ')' { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 64ba8ec891..3beed37dd2 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -1332,7 +1332,10 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
prettyFlags, 0);
/*
- * Now emit the constraint definition. There are cases where
+ * Now emit the constraint definition, adding NO INHERIT if
+ * necessary.
+ *
+ * There are cases where
* the constraint expression will be fully parenthesized and
* we don't need the outer parens ... but there are other
* cases where we do need 'em. Be conservative for now.
@@ -1340,7 +1343,9 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
* Note that simply checking for leading '(' and trailing ')'
* would NOT be good enough, consider "(x > 0) AND (y > 0)".
*/
- appendStringInfo(&buf, "CHECK (%s)", consrc);
+ appendStringInfo(&buf, "CHECK %s(%s)",
+ conForm->connoinherit ? "NO INHERIT " : "",
+ consrc);
break;
}
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 9cadb3f21a..7f0e20ec17 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3262,7 +3262,7 @@ CheckConstraintFetch(Relation relation)
RelationGetRelationName(relation));
check[found].ccvalid = conform->convalidated;
- check[found].cconly = conform->conisonly;
+ check[found].ccnoinherit = conform->connoinherit;
check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
NameStr(conform->conname));
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index db56910691..58fa92935b 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -5960,13 +5960,12 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
if (fout->remoteVersion >= 90200)
{
/*
- * conisonly and convalidated are new in 9.2 (actually, the latter
- * is there in 9.1, but it wasn't ever false for check constraints
- * until 9.2).
+ * convalidated is new in 9.2 (actually, it is there in 9.1,
+ * but it wasn't ever false for check constraints until 9.2).
*/
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
- "conislocal, convalidated, conisonly "
+ "conislocal, convalidated "
"FROM pg_catalog.pg_constraint "
"WHERE conrelid = '%u'::pg_catalog.oid "
" AND contype = 'c' "
@@ -5975,10 +5974,10 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
}
else if (fout->remoteVersion >= 80400)
{
+ /* conislocal is new in 8.4 */
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
- "conislocal, true AS convalidated, "
- "false as conisonly "
+ "conislocal, true AS convalidated "
"FROM pg_catalog.pg_constraint "
"WHERE conrelid = '%u'::pg_catalog.oid "
" AND contype = 'c' "
@@ -5989,8 +5988,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
{
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_catalog.pg_constraint "
"WHERE conrelid = '%u'::pg_catalog.oid "
" AND contype = 'c' "
@@ -6002,8 +6000,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
/* no pg_get_constraintdef, must use consrc */
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
"'CHECK (' || consrc || ')' AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_catalog.pg_constraint "
"WHERE conrelid = '%u'::pg_catalog.oid "
" AND contype = 'c' "
@@ -6016,8 +6013,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
"rcname AS conname, "
"'CHECK (' || rcsrc || ')' AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_relcheck "
"WHERE rcrelid = '%u'::oid "
"ORDER BY rcname",
@@ -6028,8 +6024,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
appendPQExpBuffer(q, "SELECT tableoid, oid, "
"rcname AS conname, "
"'CHECK (' || rcsrc || ')' AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_relcheck "
"WHERE rcrelid = '%u'::oid "
"ORDER BY rcname",
@@ -6042,8 +6037,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
"(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
"oid, rcname AS conname, "
"'CHECK (' || rcsrc || ')' AS consrc, "
- "true AS conislocal, true AS convalidated, "
- "false as conisonly "
+ "true AS conislocal, true AS convalidated "
"FROM pg_relcheck "
"WHERE rcrelid = '%u'::oid "
"ORDER BY rcname",
@@ -6068,7 +6062,6 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
for (j = 0; j < numConstrs; j++)
{
bool validated = PQgetvalue(res, j, 5)[0] == 't';
- bool isonly = PQgetvalue(res, j, 6)[0] == 't';
constrs[j].dobj.objType = DO_CONSTRAINT;
constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
@@ -6085,14 +6078,12 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
constrs[j].condeferrable = false;
constrs[j].condeferred = false;
constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
- constrs[j].conisonly = isonly;
/*
* An unvalidated constraint needs to be dumped separately, so
* that potentially-violating existing data is loaded before
- * the constraint. An ONLY constraint needs to be dumped
- * separately too.
+ * the constraint.
*/
- constrs[j].separate = !validated || isonly;
+ constrs[j].separate = !validated;
constrs[j].dobj.dump = tbinfo->dobj.dump;
@@ -13048,9 +13039,9 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
/* Ignore if not to be dumped separately */
if (coninfo->separate)
{
- /* add ONLY if we do not want it to propagate to children */
- appendPQExpBuffer(q, "ALTER TABLE %s %s\n",
- coninfo->conisonly ? "ONLY" : "", fmtId(tbinfo->dobj.name));
+ /* not ONLY since we want it to propagate to children */
+ appendPQExpBuffer(q, "ALTER TABLE %s\n",
+ fmtId(tbinfo->dobj.name));
appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
fmtId(coninfo->dobj.name),
coninfo->condef);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index fba69532ab..5d6125c425 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -370,7 +370,6 @@ typedef struct _constraintInfo
bool condeferrable; /* TRUE if constraint is DEFERRABLE */
bool condeferred; /* TRUE if constraint is INITIALLY DEFERRED */
bool conislocal; /* TRUE if constraint has local definition */
- bool conisonly; /* TRUE if constraint is non-inheritable */
bool separate; /* TRUE if must dump as separate item */
} ConstraintInfo;
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 844a2912bb..ffaaf4049f 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -1786,20 +1786,13 @@ describeOneTableDetails(const char *schemaname,
/* print table (and column) check constraints */
if (tableinfo.checks)
{
- char *is_only;
-
- if (pset.sversion >= 90200)
- is_only = "r.conisonly";
- else
- is_only = "false AS conisonly";
-
printfPQExpBuffer(&buf,
- "SELECT r.conname, %s, "
+ "SELECT r.conname, "
"pg_catalog.pg_get_constraintdef(r.oid, true)\n"
"FROM pg_catalog.pg_constraint r\n"
- "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
- "ORDER BY 2 DESC, 1;",
- is_only, oid);
+ "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
+ "ORDER BY 1;",
+ oid);
result = PSQLexec(buf.data, false);
if (!result)
goto error_return;
@@ -1812,10 +1805,9 @@ describeOneTableDetails(const char *schemaname,
for (i = 0; i < tuples; i++)
{
/* untranslated contraint name and def */
- printfPQExpBuffer(&buf, " \"%s\"%s%s",
+ printfPQExpBuffer(&buf, " \"%s\" %s",
PQgetvalue(result, i, 0),
- (strcmp(PQgetvalue(result, i, 1), "t") == 0) ? " (ONLY) ":" ",
- PQgetvalue(result, i, 2));
+ PQgetvalue(result, i, 1));
printTableAddFooter(&cont, buf.data);
}
diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h
index 0df47a03e2..953e146d5e 100644
--- a/src/include/access/tupdesc.h
+++ b/src/include/access/tupdesc.h
@@ -30,7 +30,7 @@ typedef struct constrCheck
char *ccname;
char *ccbin; /* nodeToString representation of expr */
bool ccvalid;
- bool cconly; /* this is a non-inheritable constraint */
+ bool ccnoinherit; /* this is a non-inheritable constraint */
} ConstrCheck;
/* This structure contains constraints of a tuple */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index a43491503a..88383f1e77 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201204141
+#define CATALOG_VERSION_NO 201204201
#endif
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 2055382096..c0deab73ae 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -33,7 +33,8 @@ typedef struct CookedConstraint
bool skip_validation; /* skip validation? (only for CHECK) */
bool is_local; /* constraint has local (non-inherited) def */
int inhcount; /* number of times constraint is inherited */
- bool is_only; /* constraint has local def and cannot be inherited */
+ bool is_no_inherit; /* constraint has local def and cannot be
+ * inherited */
} CookedConstraint;
extern Relation heap_create(const char *relname,
@@ -92,8 +93,7 @@ extern List *AddRelationNewConstraints(Relation rel,
List *newColDefaults,
List *newConstraints,
bool allow_merge,
- bool is_local,
- bool is_only);
+ bool is_local);
extern void StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr);
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 22d65951bd..3a77124b00 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -89,7 +89,7 @@ CATALOG(pg_constraint,2606)
int4 coninhcount;
/* Has a local definition and cannot be inherited */
- bool conisonly;
+ bool connoinherit;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/*
@@ -166,7 +166,7 @@ typedef FormData_pg_constraint *Form_pg_constraint;
#define Anum_pg_constraint_confmatchtype 13
#define Anum_pg_constraint_conislocal 14
#define Anum_pg_constraint_coninhcount 15
-#define Anum_pg_constraint_conisonly 16
+#define Anum_pg_constraint_connoinherit 16
#define Anum_pg_constraint_conkey 17
#define Anum_pg_constraint_confkey 18
#define Anum_pg_constraint_conpfeqop 19
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index aaa950db26..13b95e11aa 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1528,6 +1528,7 @@ typedef struct Constraint
int location; /* token location, or -1 if unknown */
/* Fields used for constraints with expressions (CHECK and DEFAULT): */
+ bool is_no_inherit; /* is constraint non-inheritable? */
Node *raw_expr; /* expr, as untransformed parse tree */
char *cooked_expr; /* expr, as nodeToString representation */
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index eba0493089..890a51fd9e 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -235,7 +235,7 @@ Check constraints:
"con1foo" CHECK (a > 0)
Inherits: constraint_rename_test
-ALTER TABLE ONLY constraint_rename_test ADD CONSTRAINT con2 CHECK (b > 0);
+ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK NO INHERIT (b > 0);
ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con2 TO con2foo; -- ok
ALTER TABLE constraint_rename_test RENAME CONSTRAINT con2foo TO con2bar; -- ok
\d constraint_rename_test
@@ -246,8 +246,8 @@ Table "public.constraint_rename_test"
b | integer |
c | integer |
Check constraints:
- "con2bar" (ONLY) CHECK (b > 0)
"con1foo" CHECK (a > 0)
+ "con2bar" CHECK NO INHERIT (b > 0)
Number of child tables: 1 (Use \d+ to list them.)
\d constraint_rename_test2
@@ -275,8 +275,8 @@ Table "public.constraint_rename_test"
Indexes:
"con3foo" PRIMARY KEY, btree (a)
Check constraints:
- "con2bar" (ONLY) CHECK (b > 0)
"con1foo" CHECK (a > 0)
+ "con2bar" CHECK NO INHERIT (b > 0)
Number of child tables: 1 (Use \d+ to list them.)
\d constraint_rename_test2
@@ -643,7 +643,7 @@ drop table atacc1;
create table atacc1 (test int);
create table atacc2 (test2 int) inherits (atacc1);
-- ok:
-alter table only atacc1 add constraint foo check (test>0);
+alter table atacc1 add constraint foo check no inherit (test>0);
-- check constraint is not there on child
insert into atacc2 (test) values (-3);
-- check constraint is there on parent
@@ -652,7 +652,7 @@ ERROR: new row for relation "atacc1" violates check constraint "foo"
DETAIL: Failing row contains (-3).
insert into atacc1 (test) values (3);
-- fail, violating row:
-alter table only atacc2 add constraint foo check (test>0);
+alter table atacc2 add constraint foo check no inherit (test>0);
ERROR: check constraint "foo" is violated by some row
drop table atacc2;
drop table atacc1;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 92a64c8dba..6613fea84a 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -598,17 +598,17 @@ select * from d;
-- Test non-inheritable parent constraints
create table p1(ff1 int);
-alter table only p1 add constraint p1chk check (ff1 > 0);
+alter table p1 add constraint p1chk check no inherit (ff1 > 0);
alter table p1 add constraint p2chk check (ff1 > 10);
--- conisonly should be true for ONLY constraint
-select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.conisonly from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname = 'p1' order by 1,2;
- relname | conname | contype | conislocal | coninhcount | conisonly
----------+---------+---------+------------+-------------+-----------
+-- connoinherit should be true for NO INHERIT constraint
+select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.connoinherit from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname = 'p1' order by 1,2;
+ relname | conname | contype | conislocal | coninhcount | connoinherit
+---------+---------+---------+------------+-------------+--------------
p1 | p1chk | c | t | 0 | t
p1 | p2chk | c | t | 0 | f
(2 rows)
--- Test that child does not inherit ONLY constraints
+-- Test that child does not inherit NO INHERIT constraints
create table c1 () inherits (p1);
\d p1
Table "public.p1"
@@ -616,7 +616,7 @@ create table c1 () inherits (p1);
--------+---------+-----------
ff1 | integer |
Check constraints:
- "p1chk" (ONLY) CHECK (ff1 > 0)
+ "p1chk" CHECK NO INHERIT (ff1 > 0)
"p2chk" CHECK (ff1 > 10)
Number of child tables: 1 (Use \d+ to list them.)
diff --git a/src/test/regress/input/constraints.source b/src/test/regress/input/constraints.source
index b84d51e9e5..37d06b0127 100644
--- a/src/test/regress/input/constraints.source
+++ b/src/test/regress/input/constraints.source
@@ -143,6 +143,34 @@ SELECT * FROM INSERT_CHILD;
DROP TABLE INSERT_CHILD;
+--
+-- Check NO INHERIT type of constraints and inheritance
+--
+
+CREATE TABLE ATACC1 (TEST INT
+ CHECK NO INHERIT (TEST > 0));
+
+CREATE TABLE ATACC2 (TEST2 INT) INHERITS (ATACC1);
+-- check constraint is not there on child
+INSERT INTO ATACC2 (TEST) VALUES (-3);
+-- check constraint is there on parent
+INSERT INTO ATACC1 (TEST) VALUES (-3);
+DROP TABLE ATACC1 CASCADE;
+
+CREATE TABLE ATACC1 (TEST INT, TEST2 INT
+ CHECK (TEST > 0), CHECK NO INHERIT (TEST2 > 10));
+
+CREATE TABLE ATACC2 () INHERITS (ATACC1);
+-- check constraint is there on child
+INSERT INTO ATACC2 (TEST) VALUES (-3);
+-- check constraint is there on parent
+INSERT INTO ATACC1 (TEST) VALUES (-3);
+-- check constraint is not there on child
+INSERT INTO ATACC2 (TEST2) VALUES (3);
+-- check constraint is there on parent
+INSERT INTO ATACC1 (TEST2) VALUES (3);
+DROP TABLE ATACC1 CASCADE;
+
--
-- Check constraints on INSERT INTO
--
diff --git a/src/test/regress/output/constraints.source b/src/test/regress/output/constraints.source
index 3e02e8dbd4..f37c9b1369 100644
--- a/src/test/regress/output/constraints.source
+++ b/src/test/regress/output/constraints.source
@@ -228,6 +228,39 @@ SELECT * FROM INSERT_CHILD;
DROP TABLE INSERT_CHILD;
--
+-- Check NO INHERIT type of constraints and inheritance
+--
+CREATE TABLE ATACC1 (TEST INT
+ CHECK NO INHERIT (TEST > 0));
+CREATE TABLE ATACC2 (TEST2 INT) INHERITS (ATACC1);
+-- check constraint is not there on child
+INSERT INTO ATACC2 (TEST) VALUES (-3);
+-- check constraint is there on parent
+INSERT INTO ATACC1 (TEST) VALUES (-3);
+ERROR: new row for relation "atacc1" violates check constraint "atacc1_test_check"
+DETAIL: Failing row contains (-3).
+DROP TABLE ATACC1 CASCADE;
+NOTICE: drop cascades to table atacc2
+CREATE TABLE ATACC1 (TEST INT, TEST2 INT
+ CHECK (TEST > 0), CHECK NO INHERIT (TEST2 > 10));
+CREATE TABLE ATACC2 () INHERITS (ATACC1);
+-- check constraint is there on child
+INSERT INTO ATACC2 (TEST) VALUES (-3);
+ERROR: new row for relation "atacc2" violates check constraint "atacc1_test_check"
+DETAIL: Failing row contains (-3, null).
+-- check constraint is there on parent
+INSERT INTO ATACC1 (TEST) VALUES (-3);
+ERROR: new row for relation "atacc1" violates check constraint "atacc1_test_check"
+DETAIL: Failing row contains (-3, null).
+-- check constraint is not there on child
+INSERT INTO ATACC2 (TEST2) VALUES (3);
+-- check constraint is there on parent
+INSERT INTO ATACC1 (TEST2) VALUES (3);
+ERROR: new row for relation "atacc1" violates check constraint "atacc1_test2_check"
+DETAIL: Failing row contains (null, 3).
+DROP TABLE ATACC1 CASCADE;
+NOTICE: drop cascades to table atacc2
+--
-- Check constraints on INSERT INTO
--
DELETE FROM INSERT_TBL;
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 50c58d23e1..5c03123b4e 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -218,7 +218,7 @@ ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- fa
ALTER TABLE constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- ok
\d constraint_rename_test
\d constraint_rename_test2
-ALTER TABLE ONLY constraint_rename_test ADD CONSTRAINT con2 CHECK (b > 0);
+ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK NO INHERIT (b > 0);
ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con2 TO con2foo; -- ok
ALTER TABLE constraint_rename_test RENAME CONSTRAINT con2foo TO con2bar; -- ok
\d constraint_rename_test
@@ -500,14 +500,14 @@ drop table atacc1;
create table atacc1 (test int);
create table atacc2 (test2 int) inherits (atacc1);
-- ok:
-alter table only atacc1 add constraint foo check (test>0);
+alter table atacc1 add constraint foo check no inherit (test>0);
-- check constraint is not there on child
insert into atacc2 (test) values (-3);
-- check constraint is there on parent
insert into atacc1 (test) values (-3);
insert into atacc1 (test) values (3);
-- fail, violating row:
-alter table only atacc2 add constraint foo check (test>0);
+alter table atacc2 add constraint foo check no inherit (test>0);
drop table atacc2;
drop table atacc1;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index 43f910f24a..6e6921aa9c 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -140,12 +140,12 @@ select * from d;
-- Test non-inheritable parent constraints
create table p1(ff1 int);
-alter table only p1 add constraint p1chk check (ff1 > 0);
+alter table p1 add constraint p1chk check no inherit (ff1 > 0);
alter table p1 add constraint p2chk check (ff1 > 10);
--- conisonly should be true for ONLY constraint
-select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.conisonly from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname = 'p1' order by 1,2;
+-- connoinherit should be true for NO INHERIT constraint
+select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.connoinherit from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname = 'p1' order by 1,2;
--- Test that child does not inherit ONLY constraints
+-- Test that child does not inherit NO INHERIT constraints
create table c1 () inherits (p1);
\d p1
\d c1