and <literal>TABLESPACE</> actions never recurse to descendant tables;
that is, they always act as though <literal>ONLY</> were specified.
Adding a constraint can recurse only for <literal>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 <literal>NO INHERIT</>.
</para>
<para>
<para>
To add a check constraint only to a table and not to its children:
<programlisting>
-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);
</programlisting>
(The check constraint will not be inherited by future children, either.)
</para>
[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
{ NOT NULL |
NULL |
- CHECK ( <replaceable class="PARAMETER">expression</replaceable> ) |
+ CHECK [ NO INHERIT ] ( <replaceable class="PARAMETER">expression</replaceable> ) |
DEFAULT <replaceable>default_expr</replaceable> |
UNIQUE <replaceable class="PARAMETER">index_parameters</replaceable> |
PRIMARY KEY <replaceable class="PARAMETER">index_parameters</replaceable> |
<phrase>and <replaceable class="PARAMETER">table_constraint</replaceable> is:</phrase>
[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
-{ CHECK ( <replaceable class="PARAMETER">expression</replaceable> ) |
+{ CHECK [ NO INHERIT ] ( <replaceable class="PARAMETER">expression</replaceable> ) |
UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] ( <replaceable class="parameter">exclude_element</replaceable> WITH <replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable class="parameter">predicate</replaceable> ) ] |
contain identically-named <literal>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 <literal>CHECK</>
+ be merged into one copy. A constraint marked <literal>NO INHERIT</> in a
+ parent will not be considered. Notice that an unnamed <literal>CHECK</>
constraint in the new table will never be merged, since a unique name
will always be chosen for it.
</para>
</varlistentry>
<varlistentry>
- <term><literal>CHECK ( <replaceable class="PARAMETER">expression</replaceable> )</literal></term>
+ <term><literal>CHECK [ NO INHERIT ] ( <replaceable class="PARAMETER">expression</replaceable> )</literal></term>
<listitem>
<para>
The <literal>CHECK</> clause specifies an expression producing a
subqueries nor refer to variables other than columns of the
current row.
</para>
+
+ <para>
+ A constraint marked with <literal>NO INHERIT</> will not propagate to
+ children tables.
+ </para>
</listitem>
</varlistentry>
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,
*/
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;
ccsrc, /* Source form of check constraint */
is_local, /* conislocal */
inhcount, /* coninhcount */
- is_only); /* conisonly */
+ is_no_inherit); /* connoinherit */
pfree(ccbin);
pfree(ccsrc);
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:
List *newColDefaults,
List *newConstraints,
bool allow_merge,
- bool is_local,
- bool is_only)
+ bool is_local)
{
List *cookedConstraints = NIL;
TupleDesc tupleDesc;
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);
}
* what ATAddCheckConstraint wants.)
*/
if (MergeWithExistingConstraint(rel, ccname, expr,
- allow_merge, is_local, is_only))
+ allow_merge, is_local,
+ cdef->is_no_inherit))
continue;
}
else
* 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++;
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);
}
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;
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\"",
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,
NULL,
true, /* islocal */
0, /* inhcount */
- false); /* isonly */
+ false); /* noinherit */
/*
* Register the index as internally dependent on the constraint.
const char *conSrc,
bool conIsLocal,
int conInhCount,
- bool conIsOnly)
+ bool conNoInherit)
{
Relation conDesc;
Oid conOid;
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);
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;
}
*/
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
Node *expr;
/* ignore if the constraint is non-inheritable */
- if (check[i].cconly)
+ if (check[i].ccnoinherit)
continue;
/* adjust varattnos of ccbin here */
cooked->skip_validation = false;
cooked->is_local = false;
cooked->inhcount = 1;
- cooked->is_only = false;
+ cooked->is_no_inherit = false;
constraints = lappend(constraints, cooked);
}
}
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)
{
* 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();
* 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);
}
}
* 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)
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;
/*
*/
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);
NULL,
true, /* islocal */
0, /* inhcount */
- false); /* isonly */
+ false); /* isnoinherit */
/*
* Create the triggers that will enforce the constraint.
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)
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
* 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;
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 */
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\"",
NULL,
true, /* islocal */
0, /* inhcount */
- false); /* isonly */
+ false); /* isnoinherit */
}
/*
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);
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);
case CONSTR_CHECK:
appendStringInfo(str, "CHECK");
+ WRITE_BOOL_FIELD(is_no_inherit);
WRITE_NODE_FIELD(raw_expr);
WRITE_STRING_FIELD(cooked_expr);
break;
%type <str> character
%type <str> extract_arg
%type <str> opt_charset
-%type <boolean> opt_varying opt_timezone
+%type <boolean> opt_varying opt_timezone opt_no_inherit
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
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;
}
;
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;
}
;
+opt_no_inherit: NO INHERIT { $$ = TRUE; }
+ | /* EMPTY */ { $$ = FALSE; }
+ ;
+
opt_column_list:
'(' columnList ')' { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
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.
* 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;
}
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));
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' "
}
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' "
{
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' "
/* 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' "
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",
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",
"(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",
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));
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;
/* 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);
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;
/* 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;
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);
}
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 */
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201204141
+#define CATALOG_VERSION_NO 201204201
#endif
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,
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);
int4 coninhcount;
/* Has a local definition and cannot be inherited */
- bool conisonly;
+ bool connoinherit;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/*
#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
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 */
"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
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
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
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
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;
-- 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"
--------+---------+-----------
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.)
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
--
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;
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
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;
-- 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