Change the rules for inherited CHECK constraints to be essentially the same
as those for inherited columns; that is, it's no longer allowed for a child table to not have a check constraint matching one that exists on a parent. This satisfies the principle of least surprise (rows selected from the parent will always appear to meet its check constraints) and eliminates some longstanding bogosity in pg_dump, which formerly had to guess about whether check constraints were really inherited or not. The implementation involves adding conislocal and coninhcount columns to pg_constraint (paralleling attislocal and attinhcount in pg_attribute) and refactoring various ALTER TABLE actions to be more like those for columns. Alex Hunsaker, Nikhil Sontakke, Tom Lane
This commit is contained in:
parent
f8df836ae3
commit
cd902b331d
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.165 2008/04/14 17:05:32 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.166 2008/05/09 23:32:03 tgl Exp $ -->
|
||||||
<!--
|
<!--
|
||||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||||
-->
|
-->
|
||||||
@ -1907,6 +1907,26 @@
|
|||||||
<entry>Foreign key match type</entry>
|
<entry>Foreign key match type</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>conislocal</structfield></entry>
|
||||||
|
<entry><type>bool</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>
|
||||||
|
This constraint is defined locally in the relation. Note that a
|
||||||
|
constraint can be locally defined and inherited simultaneously
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>coninhcount</structfield></entry>
|
||||||
|
<entry><type>int4</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>
|
||||||
|
The number of direct ancestors this constraint has. A constraint with
|
||||||
|
a nonzero number of ancestors cannot be dropped nor renamed
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>conkey</structfield></entry>
|
<entry><structfield>conkey</structfield></entry>
|
||||||
<entry><type>int2[]</type></entry>
|
<entry><type>int2[]</type></entry>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.81 2008/01/13 17:58:54 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.82 2008/05/09 23:32:03 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="ddl">
|
<chapter id="ddl">
|
||||||
<title>Data Definition</title>
|
<title>Data Definition</title>
|
||||||
@ -2107,7 +2107,8 @@ VALUES ('New York', NULL, NULL, 'NY');
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
A parent table cannot be dropped while any of its children remain. Neither
|
A parent table cannot be dropped while any of its children remain. Neither
|
||||||
can columns of child tables be dropped or altered if they are inherited
|
can columns or check constraints of child tables be dropped or altered
|
||||||
|
if they are inherited
|
||||||
from any parent tables. If you wish to remove a table and all of its
|
from any parent tables. If you wish to remove a table and all of its
|
||||||
descendants, one easy way is to drop the parent table with the
|
descendants, one easy way is to drop the parent table with the
|
||||||
<literal>CASCADE</literal> option.
|
<literal>CASCADE</literal> option.
|
||||||
@ -2117,7 +2118,7 @@ VALUES ('New York', NULL, NULL, 'NY');
|
|||||||
<xref linkend="sql-altertable" endterm="sql-altertable-title"> will
|
<xref linkend="sql-altertable" endterm="sql-altertable-title"> will
|
||||||
propagate any changes in column data definitions and check
|
propagate any changes in column data definitions and check
|
||||||
constraints down the inheritance hierarchy. Again, dropping
|
constraints down the inheritance hierarchy. Again, dropping
|
||||||
columns or constraints on parent tables is only possible when using
|
columns that are depended on by other tables is only possible when using
|
||||||
the <literal>CASCADE</literal> option. <command>ALTER
|
the <literal>CASCADE</literal> option. <command>ALTER
|
||||||
TABLE</command> follows the same rules for duplicate column merging
|
TABLE</command> follows the same rules for duplicate column merging
|
||||||
and rejection that apply during <command>CREATE TABLE</command>.
|
and rejection that apply during <command>CREATE TABLE</command>.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.98 2007/11/28 15:42:31 petere Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.99 2008/05/09 23:32:03 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -713,7 +713,8 @@ ALTER TABLE table ALTER COLUMN anycol TYPE anytype;
|
|||||||
The <literal>TRIGGER</>, <literal>CLUSTER</>, <literal>OWNER</>,
|
The <literal>TRIGGER</>, <literal>CLUSTER</>, <literal>OWNER</>,
|
||||||
and <literal>TABLESPACE</> actions never recurse to descendant tables;
|
and <literal>TABLESPACE</> actions never recurse to descendant tables;
|
||||||
that is, they always act as though <literal>ONLY</> were specified.
|
that is, they always act as though <literal>ONLY</> were specified.
|
||||||
Adding a constraint can recurse only for <literal>CHECK</> constraints.
|
Adding a constraint can recurse only for <literal>CHECK</> constraints,
|
||||||
|
and is required to do so for such constraints.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -804,7 +805,7 @@ ALTER TABLE distributors ALTER COLUMN street DROP NOT NULL;
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To add a check constraint to a table:
|
To add a check constraint to a table and all its children:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
|
ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
@ -817,6 +818,14 @@ ALTER TABLE distributors DROP CONSTRAINT zipchk;
|
|||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To remove a check constraint from a table only:
|
||||||
|
<programlisting>
|
||||||
|
ALTER TABLE ONLY distributors DROP CONSTRAINT zipchk;
|
||||||
|
</programlisting>
|
||||||
|
(The check constraint remains in place for any child tables.)
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To add a foreign key constraint to a table:
|
To add a foreign key constraint to a table:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.109 2007/07/17 05:02:00 neilc Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.110 2008/05/09 23:32:04 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -210,16 +210,25 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
|
|||||||
the new table. If the column name list of the new table
|
the new table. If the column name list of the new table
|
||||||
contains a column name that is also inherited, the data type must
|
contains a column name that is also inherited, the data type must
|
||||||
likewise match the inherited column(s), and the column
|
likewise match the inherited column(s), and the column
|
||||||
definitions are merged into one. However, inherited and new
|
definitions are merged into one. If the
|
||||||
column declarations of the same name need not specify identical
|
|
||||||
constraints: all constraints provided from any declaration are
|
|
||||||
merged together and all are applied to the new table. If the
|
|
||||||
new table explicitly specifies a default value for the column,
|
new table explicitly specifies a default value for the column,
|
||||||
this default overrides any defaults from inherited declarations
|
this default overrides any defaults from inherited declarations
|
||||||
of the column. Otherwise, any parents that specify default
|
of the column. Otherwise, any parents that specify default
|
||||||
values for the column must all specify the same default, or an
|
values for the column must all specify the same default, or an
|
||||||
error will be reported.
|
error will be reported.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<literal>CHECK</> constraints are merged in essentially the same way as
|
||||||
|
columns: if multiple parent tables and/or the new table definition
|
||||||
|
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</>
|
||||||
|
constraint in the new table will never be merged, since a unique name
|
||||||
|
will always be chosen for it.
|
||||||
|
</para>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<para>
|
<para>
|
||||||
<productname>PostgreSQL</> automatically allows the
|
<productname>PostgreSQL</> automatically allows the
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.122 2008/01/01 19:45:46 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.123 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* some of the executor utility code such as "ExecTypeFromTL" should be
|
* some of the executor utility code such as "ExecTypeFromTL" should be
|
||||||
@ -505,20 +505,18 @@ BuildDescForRelation(List *schema)
|
|||||||
AttrNumber attnum;
|
AttrNumber attnum;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
TupleDesc desc;
|
TupleDesc desc;
|
||||||
AttrDefault *attrdef = NULL;
|
bool has_not_null;
|
||||||
TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
|
|
||||||
char *attname;
|
char *attname;
|
||||||
Oid atttypid;
|
Oid atttypid;
|
||||||
int32 atttypmod;
|
int32 atttypmod;
|
||||||
int attdim;
|
int attdim;
|
||||||
int ndef = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* allocate a new tuple descriptor
|
* allocate a new tuple descriptor
|
||||||
*/
|
*/
|
||||||
natts = list_length(schema);
|
natts = list_length(schema);
|
||||||
desc = CreateTemplateTupleDesc(natts, false);
|
desc = CreateTemplateTupleDesc(natts, false);
|
||||||
constr->has_not_null = false;
|
has_not_null = false;
|
||||||
|
|
||||||
attnum = 0;
|
attnum = 0;
|
||||||
|
|
||||||
@ -547,52 +545,25 @@ BuildDescForRelation(List *schema)
|
|||||||
atttypid, atttypmod, attdim);
|
atttypid, atttypmod, attdim);
|
||||||
|
|
||||||
/* Fill in additional stuff not handled by TupleDescInitEntry */
|
/* Fill in additional stuff not handled by TupleDescInitEntry */
|
||||||
if (entry->is_not_null)
|
|
||||||
constr->has_not_null = true;
|
|
||||||
desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
|
desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
|
||||||
|
has_not_null |= entry->is_not_null;
|
||||||
/*
|
|
||||||
* Note we copy only pre-cooked default expressions. Digestion of raw
|
|
||||||
* ones is someone else's problem.
|
|
||||||
*/
|
|
||||||
if (entry->cooked_default != NULL)
|
|
||||||
{
|
|
||||||
if (attrdef == NULL)
|
|
||||||
attrdef = (AttrDefault *) palloc(natts * sizeof(AttrDefault));
|
|
||||||
attrdef[ndef].adnum = attnum;
|
|
||||||
attrdef[ndef].adbin = pstrdup(entry->cooked_default);
|
|
||||||
ndef++;
|
|
||||||
desc->attrs[attnum - 1]->atthasdef = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
desc->attrs[attnum - 1]->attislocal = entry->is_local;
|
desc->attrs[attnum - 1]->attislocal = entry->is_local;
|
||||||
desc->attrs[attnum - 1]->attinhcount = entry->inhcount;
|
desc->attrs[attnum - 1]->attinhcount = entry->inhcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constr->has_not_null || ndef > 0)
|
if (has_not_null)
|
||||||
{
|
{
|
||||||
desc->constr = constr;
|
TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
|
||||||
|
|
||||||
if (ndef > 0) /* DEFAULTs */
|
constr->has_not_null = true;
|
||||||
{
|
|
||||||
if (ndef < natts)
|
|
||||||
constr->defval = (AttrDefault *)
|
|
||||||
repalloc(attrdef, ndef * sizeof(AttrDefault));
|
|
||||||
else
|
|
||||||
constr->defval = attrdef;
|
|
||||||
constr->num_defval = ndef;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
constr->defval = NULL;
|
constr->defval = NULL;
|
||||||
constr->num_defval = 0;
|
constr->num_defval = 0;
|
||||||
}
|
|
||||||
constr->check = NULL;
|
constr->check = NULL;
|
||||||
constr->num_check = 0;
|
constr->num_check = 0;
|
||||||
|
desc->constr = constr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pfree(constr);
|
|
||||||
desc->constr = NULL;
|
desc->constr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.91 2008/01/01 19:45:48 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.92 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -206,6 +206,7 @@ Boot_CreateStmt:
|
|||||||
$6,
|
$6,
|
||||||
BOOTSTRAP_SUPERUSERID,
|
BOOTSTRAP_SUPERUSERID,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
|
NIL,
|
||||||
RELKIND_RELATION,
|
RELKIND_RELATION,
|
||||||
$3,
|
$3,
|
||||||
true,
|
true,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.332 2008/03/27 03:57:33 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.333 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -77,9 +77,15 @@ static Oid AddNewRelationType(const char *typeName,
|
|||||||
char new_rel_kind,
|
char new_rel_kind,
|
||||||
Oid new_array_type);
|
Oid new_array_type);
|
||||||
static void RelationRemoveInheritance(Oid relid);
|
static void RelationRemoveInheritance(Oid relid);
|
||||||
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
|
static void StoreRelCheck(Relation rel, char *ccname, Node *expr,
|
||||||
static void StoreConstraints(Relation rel, TupleDesc tupdesc);
|
bool is_local, int inhcount);
|
||||||
|
static void StoreConstraints(Relation rel, List *cooked_constraints);
|
||||||
|
static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
|
||||||
|
bool allow_merge, bool is_local);
|
||||||
static void SetRelationNumChecks(Relation rel, int numchecks);
|
static void SetRelationNumChecks(Relation rel, int numchecks);
|
||||||
|
static Node *cookConstraint(ParseState *pstate,
|
||||||
|
Node *raw_constraint,
|
||||||
|
char *relname);
|
||||||
static List *insert_ordered_unique_oid(List *list, Oid datum);
|
static List *insert_ordered_unique_oid(List *list, Oid datum);
|
||||||
|
|
||||||
|
|
||||||
@ -788,6 +794,7 @@ heap_create_with_catalog(const char *relname,
|
|||||||
Oid relid,
|
Oid relid,
|
||||||
Oid ownerid,
|
Oid ownerid,
|
||||||
TupleDesc tupdesc,
|
TupleDesc tupdesc,
|
||||||
|
List *cooked_constraints,
|
||||||
char relkind,
|
char relkind,
|
||||||
bool shared_relation,
|
bool shared_relation,
|
||||||
bool oidislocal,
|
bool oidislocal,
|
||||||
@ -1004,13 +1011,13 @@ heap_create_with_catalog(const char *relname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* store constraints and defaults passed in the tupdesc, if any.
|
* Store any supplied constraints and defaults.
|
||||||
*
|
*
|
||||||
* NB: this may do a CommandCounterIncrement and rebuild the relcache
|
* NB: this may do a CommandCounterIncrement and rebuild the relcache
|
||||||
* entry, so the relation must be valid and self-consistent at this point.
|
* entry, so the relation must be valid and self-consistent at this point.
|
||||||
* In particular, there are not yet constraints and defaults anywhere.
|
* In particular, there are not yet constraints and defaults anywhere.
|
||||||
*/
|
*/
|
||||||
StoreConstraints(new_rel_desc, tupdesc);
|
StoreConstraints(new_rel_desc, cooked_constraints);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's a special on-commit action, remember it
|
* If there's a special on-commit action, remember it
|
||||||
@ -1426,12 +1433,11 @@ heap_drop_with_catalog(Oid relid)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Store a default expression for column attnum of relation rel.
|
* Store a default expression for column attnum of relation rel.
|
||||||
* The expression must be presented as a nodeToString() string.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin)
|
StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr)
|
||||||
{
|
{
|
||||||
Node *expr;
|
char *adbin;
|
||||||
char *adsrc;
|
char *adsrc;
|
||||||
Relation adrel;
|
Relation adrel;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
@ -1445,12 +1451,12 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin)
|
|||||||
defobject;
|
defobject;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to construct source equivalent of given node-string.
|
* Flatten expression to string form for storage.
|
||||||
*/
|
*/
|
||||||
expr = stringToNode(adbin);
|
adbin = nodeToString(expr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* deparse it
|
* Also deparse it to form the mostly-obsolete adsrc field.
|
||||||
*/
|
*/
|
||||||
adsrc = deparse_expression(expr,
|
adsrc = deparse_expression(expr,
|
||||||
deparse_context_for(RelationGetRelationName(rel),
|
deparse_context_for(RelationGetRelationName(rel),
|
||||||
@ -1482,6 +1488,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin)
|
|||||||
pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
|
pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
|
||||||
pfree(DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1]));
|
pfree(DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1]));
|
||||||
heap_freetuple(tuple);
|
heap_freetuple(tuple);
|
||||||
|
pfree(adbin);
|
||||||
pfree(adsrc);
|
pfree(adsrc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1525,27 +1532,27 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Store a check-constraint expression for the given relation.
|
* Store a check-constraint expression for the given relation.
|
||||||
* The expression must be presented as a nodeToString() string.
|
|
||||||
*
|
*
|
||||||
* Caller is responsible for updating the count of constraints
|
* Caller is responsible for updating the count of constraints
|
||||||
* in the pg_class entry for the relation.
|
* in the pg_class entry for the relation.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
StoreRelCheck(Relation rel, char *ccname, char *ccbin)
|
StoreRelCheck(Relation rel, char *ccname, Node *expr,
|
||||||
|
bool is_local, int inhcount)
|
||||||
{
|
{
|
||||||
Node *expr;
|
char *ccbin;
|
||||||
char *ccsrc;
|
char *ccsrc;
|
||||||
List *varList;
|
List *varList;
|
||||||
int keycount;
|
int keycount;
|
||||||
int16 *attNos;
|
int16 *attNos;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert condition to an expression tree.
|
* Flatten expression to string form for storage.
|
||||||
*/
|
*/
|
||||||
expr = stringToNode(ccbin);
|
ccbin = nodeToString(expr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* deparse it
|
* Also deparse it to form the mostly-obsolete consrc field.
|
||||||
*/
|
*/
|
||||||
ccsrc = deparse_expression(expr,
|
ccsrc = deparse_expression(expr,
|
||||||
deparse_context_for(RelationGetRelationName(rel),
|
deparse_context_for(RelationGetRelationName(rel),
|
||||||
@ -1553,7 +1560,7 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
|
|||||||
false, false);
|
false, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find columns of rel that are used in ccbin
|
* Find columns of rel that are used in expr
|
||||||
*
|
*
|
||||||
* NB: pull_var_clause is okay here only because we don't allow subselects
|
* NB: pull_var_clause is okay here only because we don't allow subselects
|
||||||
* in check constraints; it would fail to examine the contents of
|
* in check constraints; it would fail to examine the contents of
|
||||||
@ -1608,26 +1615,29 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
|
|||||||
InvalidOid, /* no associated index */
|
InvalidOid, /* no associated index */
|
||||||
expr, /* Tree form check constraint */
|
expr, /* Tree form check constraint */
|
||||||
ccbin, /* Binary form check constraint */
|
ccbin, /* Binary form check constraint */
|
||||||
ccsrc); /* Source form check constraint */
|
ccsrc, /* Source form check constraint */
|
||||||
|
is_local, /* conislocal */
|
||||||
|
inhcount); /* coninhcount */
|
||||||
|
|
||||||
|
pfree(ccbin);
|
||||||
pfree(ccsrc);
|
pfree(ccsrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store defaults and constraints passed in via the tuple constraint struct.
|
* Store defaults and constraints (passed as a list of CookedConstraint).
|
||||||
*
|
*
|
||||||
* NOTE: only pre-cooked expressions will be passed this way, which is to
|
* NOTE: only pre-cooked expressions will be passed this way, which is to
|
||||||
* say expressions inherited from an existing relation. Newly parsed
|
* say expressions inherited from an existing relation. Newly parsed
|
||||||
* expressions can be added later, by direct calls to StoreAttrDefault
|
* expressions can be added later, by direct calls to StoreAttrDefault
|
||||||
* and StoreRelCheck (see AddRelationRawConstraints()).
|
* and StoreRelCheck (see AddRelationNewConstraints()).
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
StoreConstraints(Relation rel, TupleDesc tupdesc)
|
StoreConstraints(Relation rel, List *cooked_constraints)
|
||||||
{
|
{
|
||||||
TupleConstr *constr = tupdesc->constr;
|
int numchecks = 0;
|
||||||
int i;
|
ListCell *lc;
|
||||||
|
|
||||||
if (!constr)
|
if (!cooked_constraints)
|
||||||
return; /* nothing to do */
|
return; /* nothing to do */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1637,33 +1647,46 @@ StoreConstraints(Relation rel, TupleDesc tupdesc)
|
|||||||
*/
|
*/
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
for (i = 0; i < constr->num_defval; i++)
|
foreach(lc, cooked_constraints)
|
||||||
StoreAttrDefault(rel, constr->defval[i].adnum,
|
{
|
||||||
constr->defval[i].adbin);
|
CookedConstraint *con = (CookedConstraint *) lfirst(lc);
|
||||||
|
|
||||||
for (i = 0; i < constr->num_check; i++)
|
switch (con->contype)
|
||||||
StoreRelCheck(rel, constr->check[i].ccname,
|
{
|
||||||
constr->check[i].ccbin);
|
case CONSTR_DEFAULT:
|
||||||
|
StoreAttrDefault(rel, con->attnum, con->expr);
|
||||||
|
break;
|
||||||
|
case CONSTR_CHECK:
|
||||||
|
StoreRelCheck(rel, con->name, con->expr,
|
||||||
|
con->is_local, con->inhcount);
|
||||||
|
numchecks++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "unrecognized constraint type: %d",
|
||||||
|
(int) con->contype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (constr->num_check > 0)
|
if (numchecks > 0)
|
||||||
SetRelationNumChecks(rel, constr->num_check);
|
SetRelationNumChecks(rel, numchecks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AddRelationRawConstraints
|
* AddRelationNewConstraints
|
||||||
*
|
*
|
||||||
* Add raw (not-yet-transformed) column default expressions and/or constraint
|
* Add new column default expressions and/or constraint check expressions
|
||||||
* check expressions to an existing relation. This is defined to do both
|
* to an existing relation. This is defined to do both for efficiency in
|
||||||
* for efficiency in DefineRelation, but of course you can do just one or
|
* DefineRelation, but of course you can do just one or the other by passing
|
||||||
* the other by passing empty lists.
|
* empty lists.
|
||||||
*
|
*
|
||||||
* rel: relation to be modified
|
* rel: relation to be modified
|
||||||
* rawColDefaults: list of RawColumnDefault structures
|
* newColDefaults: list of RawColumnDefault structures
|
||||||
* rawConstraints: list of Constraint nodes
|
* newConstraints: list of Constraint nodes
|
||||||
|
* allow_merge: TRUE if check constraints may be merged with existing ones
|
||||||
|
* is_local: TRUE if definition is local, FALSE if it's inherited
|
||||||
*
|
*
|
||||||
* All entries in rawColDefaults will be processed. Entries in rawConstraints
|
* All entries in newColDefaults will be processed. Entries in newConstraints
|
||||||
* will be processed only if they are CONSTR_CHECK type and contain a "raw"
|
* will be processed only if they are CONSTR_CHECK type.
|
||||||
* expression.
|
|
||||||
*
|
*
|
||||||
* Returns a list of CookedConstraint nodes that shows the cooked form of
|
* Returns a list of CookedConstraint nodes that shows the cooked form of
|
||||||
* the default and constraint expressions added to the relation.
|
* the default and constraint expressions added to the relation.
|
||||||
@ -1674,9 +1697,11 @@ StoreConstraints(Relation rel, TupleDesc tupdesc)
|
|||||||
* tuples visible.
|
* tuples visible.
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
AddRelationRawConstraints(Relation rel,
|
AddRelationNewConstraints(Relation rel,
|
||||||
List *rawColDefaults,
|
List *newColDefaults,
|
||||||
List *rawConstraints)
|
List *newConstraints,
|
||||||
|
bool allow_merge,
|
||||||
|
bool is_local)
|
||||||
{
|
{
|
||||||
List *cookedConstraints = NIL;
|
List *cookedConstraints = NIL;
|
||||||
TupleDesc tupleDesc;
|
TupleDesc tupleDesc;
|
||||||
@ -1715,7 +1740,7 @@ AddRelationRawConstraints(Relation rel,
|
|||||||
/*
|
/*
|
||||||
* Process column default expressions.
|
* Process column default expressions.
|
||||||
*/
|
*/
|
||||||
foreach(cell, rawColDefaults)
|
foreach(cell, newColDefaults)
|
||||||
{
|
{
|
||||||
RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell);
|
RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell);
|
||||||
Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
|
Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
|
||||||
@ -1739,13 +1764,15 @@ AddRelationRawConstraints(Relation rel,
|
|||||||
(IsA(expr, Const) &&((Const *) expr)->constisnull))
|
(IsA(expr, Const) &&((Const *) expr)->constisnull))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
StoreAttrDefault(rel, colDef->attnum, nodeToString(expr));
|
StoreAttrDefault(rel, colDef->attnum, expr);
|
||||||
|
|
||||||
cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
|
cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
|
||||||
cooked->contype = CONSTR_DEFAULT;
|
cooked->contype = CONSTR_DEFAULT;
|
||||||
cooked->name = NULL;
|
cooked->name = NULL;
|
||||||
cooked->attnum = colDef->attnum;
|
cooked->attnum = colDef->attnum;
|
||||||
cooked->expr = expr;
|
cooked->expr = expr;
|
||||||
|
cooked->is_local = is_local;
|
||||||
|
cooked->inhcount = is_local ? 0 : 1;
|
||||||
cookedConstraints = lappend(cookedConstraints, cooked);
|
cookedConstraints = lappend(cookedConstraints, cooked);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1754,45 +1781,35 @@ AddRelationRawConstraints(Relation rel,
|
|||||||
*/
|
*/
|
||||||
numchecks = numoldchecks;
|
numchecks = numoldchecks;
|
||||||
checknames = NIL;
|
checknames = NIL;
|
||||||
foreach(cell, rawConstraints)
|
foreach(cell, newConstraints)
|
||||||
{
|
{
|
||||||
Constraint *cdef = (Constraint *) lfirst(cell);
|
Constraint *cdef = (Constraint *) lfirst(cell);
|
||||||
char *ccname;
|
char *ccname;
|
||||||
|
|
||||||
if (cdef->contype != CONSTR_CHECK || cdef->raw_expr == NULL)
|
if (cdef->contype != CONSTR_CHECK)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (cdef->raw_expr != NULL)
|
||||||
|
{
|
||||||
Assert(cdef->cooked_expr == NULL);
|
Assert(cdef->cooked_expr == NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transform raw parsetree to executable expression.
|
* Transform raw parsetree to executable expression, and verify
|
||||||
|
* it's valid as a CHECK constraint.
|
||||||
*/
|
*/
|
||||||
expr = transformExpr(pstate, cdef->raw_expr);
|
expr = cookConstraint(pstate, cdef->raw_expr,
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert(cdef->cooked_expr != NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure it yields a boolean result.
|
* Here, we assume the parser will only pass us valid CHECK
|
||||||
|
* expressions, so we do no particular checking.
|
||||||
*/
|
*/
|
||||||
expr = coerce_to_boolean(pstate, expr, "CHECK");
|
expr = stringToNode(cdef->cooked_expr);
|
||||||
|
}
|
||||||
/*
|
|
||||||
* Make sure no outside relations are referred to.
|
|
||||||
*/
|
|
||||||
if (list_length(pstate->p_rtable) != 1)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
||||||
errmsg("only table \"%s\" can be referenced in check constraint",
|
|
||||||
RelationGetRelationName(rel))));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* No subplans or aggregates, either...
|
|
||||||
*/
|
|
||||||
if (pstate->p_hasSubLinks)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("cannot use subquery in check constraint")));
|
|
||||||
if (pstate->p_hasAggs)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_GROUPING_ERROR),
|
|
||||||
errmsg("cannot use aggregate function in check constraint")));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check name uniqueness, or generate a name if none was given.
|
* Check name uniqueness, or generate a name if none was given.
|
||||||
@ -1802,15 +1819,6 @@ AddRelationRawConstraints(Relation rel,
|
|||||||
ListCell *cell2;
|
ListCell *cell2;
|
||||||
|
|
||||||
ccname = cdef->name;
|
ccname = cdef->name;
|
||||||
/* Check against pre-existing constraints */
|
|
||||||
if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
|
|
||||||
RelationGetRelid(rel),
|
|
||||||
RelationGetNamespace(rel),
|
|
||||||
ccname))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
||||||
errmsg("constraint \"%s\" for relation \"%s\" already exists",
|
|
||||||
ccname, RelationGetRelationName(rel))));
|
|
||||||
/* Check against other new constraints */
|
/* Check against other new constraints */
|
||||||
/* Needed because we don't do CommandCounterIncrement in loop */
|
/* Needed because we don't do CommandCounterIncrement in loop */
|
||||||
foreach(cell2, checknames)
|
foreach(cell2, checknames)
|
||||||
@ -1821,6 +1829,19 @@ AddRelationRawConstraints(Relation rel,
|
|||||||
errmsg("check constraint \"%s\" already exists",
|
errmsg("check constraint \"%s\" already exists",
|
||||||
ccname)));
|
ccname)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* save name for future checks */
|
||||||
|
checknames = lappend(checknames, ccname);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check against pre-existing constraints. If we are allowed
|
||||||
|
* to merge with an existing constraint, there's no more to
|
||||||
|
* do here. (We omit the duplicate constraint from the result,
|
||||||
|
* which is what ATAddCheckConstraint wants.)
|
||||||
|
*/
|
||||||
|
if (MergeWithExistingConstraint(rel, ccname, expr,
|
||||||
|
allow_merge, is_local))
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1855,15 +1876,15 @@ AddRelationRawConstraints(Relation rel,
|
|||||||
"check",
|
"check",
|
||||||
RelationGetNamespace(rel),
|
RelationGetNamespace(rel),
|
||||||
checknames);
|
checknames);
|
||||||
}
|
|
||||||
|
|
||||||
/* save name for future checks */
|
/* save name for future checks */
|
||||||
checknames = lappend(checknames, ccname);
|
checknames = lappend(checknames, ccname);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OK, store it.
|
* OK, store it.
|
||||||
*/
|
*/
|
||||||
StoreRelCheck(rel, ccname, nodeToString(expr));
|
StoreRelCheck(rel, ccname, expr, is_local, is_local ? 0 : 1);
|
||||||
|
|
||||||
numchecks++;
|
numchecks++;
|
||||||
|
|
||||||
@ -1872,6 +1893,8 @@ AddRelationRawConstraints(Relation rel,
|
|||||||
cooked->name = ccname;
|
cooked->name = ccname;
|
||||||
cooked->attnum = 0;
|
cooked->attnum = 0;
|
||||||
cooked->expr = expr;
|
cooked->expr = expr;
|
||||||
|
cooked->is_local = is_local;
|
||||||
|
cooked->inhcount = is_local ? 0 : 1;
|
||||||
cookedConstraints = lappend(cookedConstraints, cooked);
|
cookedConstraints = lappend(cookedConstraints, cooked);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1887,6 +1910,90 @@ AddRelationRawConstraints(Relation rel,
|
|||||||
return cookedConstraints;
|
return cookedConstraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for a pre-existing check constraint that conflicts with a proposed
|
||||||
|
* new one, and either adjust its conislocal/coninhcount settings or throw
|
||||||
|
* error as needed.
|
||||||
|
*
|
||||||
|
* Returns TRUE if merged (constraint is a duplicate), or FALSE if it's
|
||||||
|
* got a so-far-unique name, or throws error if conflict.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
|
||||||
|
bool allow_merge, bool is_local)
|
||||||
|
{
|
||||||
|
bool found;
|
||||||
|
Relation conDesc;
|
||||||
|
SysScanDesc conscan;
|
||||||
|
ScanKeyData skey[2];
|
||||||
|
HeapTuple tup;
|
||||||
|
|
||||||
|
/* Search for a pg_constraint entry with same name and relation */
|
||||||
|
conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
|
||||||
|
|
||||||
|
found = false;
|
||||||
|
|
||||||
|
ScanKeyInit(&skey[0],
|
||||||
|
Anum_pg_constraint_conname,
|
||||||
|
BTEqualStrategyNumber, F_NAMEEQ,
|
||||||
|
CStringGetDatum(ccname));
|
||||||
|
|
||||||
|
ScanKeyInit(&skey[1],
|
||||||
|
Anum_pg_constraint_connamespace,
|
||||||
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(RelationGetNamespace(rel)));
|
||||||
|
|
||||||
|
conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
|
||||||
|
SnapshotNow, 2, skey);
|
||||||
|
|
||||||
|
while (HeapTupleIsValid(tup = systable_getnext(conscan)))
|
||||||
|
{
|
||||||
|
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
|
||||||
|
|
||||||
|
if (con->conrelid == RelationGetRelid(rel))
|
||||||
|
{
|
||||||
|
/* Found it. Conflicts if not identical check constraint */
|
||||||
|
if (con->contype == CONSTRAINT_CHECK)
|
||||||
|
{
|
||||||
|
Datum val;
|
||||||
|
bool isnull;
|
||||||
|
|
||||||
|
val = fastgetattr(tup,
|
||||||
|
Anum_pg_constraint_conbin,
|
||||||
|
conDesc->rd_att, &isnull);
|
||||||
|
if (isnull)
|
||||||
|
elog(ERROR, "null conbin for rel %s",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
if (equal(expr, stringToNode(TextDatumGetCString(val))))
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (!found || !allow_merge)
|
||||||
|
ereport(ERROR,
|
||||||
|
(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 (is_local)
|
||||||
|
con->conislocal = true;
|
||||||
|
else
|
||||||
|
con->coninhcount++;
|
||||||
|
simple_heap_update(conDesc, &tup->t_self, tup);
|
||||||
|
CatalogUpdateIndexes(conDesc, tup);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
systable_endscan(conscan);
|
||||||
|
heap_close(conDesc, RowExclusiveLock);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the count of constraints in the relation's pg_class tuple.
|
* Update the count of constraints in the relation's pg_class tuple.
|
||||||
*
|
*
|
||||||
@ -2015,63 +2122,52 @@ cookDefault(ParseState *pstate,
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removes all constraints on a relation that match the given name.
|
* Take a raw CHECK constraint expression and convert it to a cooked format
|
||||||
|
* ready for storage.
|
||||||
*
|
*
|
||||||
* It is the responsibility of the calling function to acquire a suitable
|
* Parse state must be set up to recognize any vars that might appear
|
||||||
* lock on the relation.
|
* in the expression.
|
||||||
*
|
|
||||||
* Returns: The number of constraints removed.
|
|
||||||
*/
|
*/
|
||||||
int
|
static Node *
|
||||||
RemoveRelConstraints(Relation rel, const char *constrName,
|
cookConstraint(ParseState *pstate,
|
||||||
DropBehavior behavior)
|
Node *raw_constraint,
|
||||||
|
char *relname)
|
||||||
{
|
{
|
||||||
int ndeleted = 0;
|
Node *expr;
|
||||||
Relation conrel;
|
|
||||||
SysScanDesc conscan;
|
|
||||||
ScanKeyData key[1];
|
|
||||||
HeapTuple contup;
|
|
||||||
|
|
||||||
/* Grab an appropriate lock on the pg_constraint relation */
|
|
||||||
conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
|
|
||||||
|
|
||||||
/* Use the index to scan only constraints of the target relation */
|
|
||||||
ScanKeyInit(&key[0],
|
|
||||||
Anum_pg_constraint_conrelid,
|
|
||||||
BTEqualStrategyNumber, F_OIDEQ,
|
|
||||||
ObjectIdGetDatum(RelationGetRelid(rel)));
|
|
||||||
|
|
||||||
conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
|
|
||||||
SnapshotNow, 1, key);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan over the result set, removing any matching entries.
|
* Transform raw parsetree to executable expression.
|
||||||
*/
|
*/
|
||||||
while ((contup = systable_getnext(conscan)) != NULL)
|
expr = transformExpr(pstate, raw_constraint);
|
||||||
{
|
|
||||||
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
|
|
||||||
|
|
||||||
if (strcmp(NameStr(con->conname), constrName) == 0)
|
/*
|
||||||
{
|
* Make sure it yields a boolean result.
|
||||||
ObjectAddress conobj;
|
*/
|
||||||
|
expr = coerce_to_boolean(pstate, expr, "CHECK");
|
||||||
|
|
||||||
conobj.classId = ConstraintRelationId;
|
/*
|
||||||
conobj.objectId = HeapTupleGetOid(contup);
|
* Make sure no outside relations are referred to.
|
||||||
conobj.objectSubId = 0;
|
*/
|
||||||
|
if (list_length(pstate->p_rtable) != 1)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||||
|
errmsg("only table \"%s\" can be referenced in check constraint",
|
||||||
|
relname)));
|
||||||
|
|
||||||
performDeletion(&conobj, behavior);
|
/*
|
||||||
|
* No subplans or aggregates, either...
|
||||||
|
*/
|
||||||
|
if (pstate->p_hasSubLinks)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("cannot use subquery in check constraint")));
|
||||||
|
if (pstate->p_hasAggs)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_GROUPING_ERROR),
|
||||||
|
errmsg("cannot use aggregate function in check constraint")));
|
||||||
|
|
||||||
ndeleted++;
|
return expr;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clean up after the scan */
|
|
||||||
systable_endscan(conscan);
|
|
||||||
heap_close(conrel, RowExclusiveLock);
|
|
||||||
|
|
||||||
return ndeleted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.296 2008/03/26 21:10:37 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.297 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -716,7 +716,9 @@ index_create(Oid heapRelationId,
|
|||||||
InvalidOid, /* no associated index */
|
InvalidOid, /* no associated index */
|
||||||
NULL, /* no check constraint */
|
NULL, /* no check constraint */
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL,
|
||||||
|
true, /* islocal */
|
||||||
|
0); /* inhcount */
|
||||||
|
|
||||||
referenced.classId = ConstraintRelationId;
|
referenced.classId = ConstraintRelationId;
|
||||||
referenced.objectId = conOid;
|
referenced.objectId = conOid;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.40 2008/03/26 21:10:37 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.41 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -60,7 +60,9 @@ CreateConstraintEntry(const char *constraintName,
|
|||||||
Oid indexRelId,
|
Oid indexRelId,
|
||||||
Node *conExpr,
|
Node *conExpr,
|
||||||
const char *conBin,
|
const char *conBin,
|
||||||
const char *conSrc)
|
const char *conSrc,
|
||||||
|
bool conIsLocal,
|
||||||
|
int conInhCount)
|
||||||
{
|
{
|
||||||
Relation conDesc;
|
Relation conDesc;
|
||||||
Oid conOid;
|
Oid conOid;
|
||||||
@ -145,6 +147,8 @@ CreateConstraintEntry(const char *constraintName,
|
|||||||
values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
|
values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
|
||||||
values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
|
values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
|
||||||
values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
|
values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
|
||||||
|
values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
|
||||||
|
values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
|
||||||
|
|
||||||
if (conkeyArray)
|
if (conkeyArray)
|
||||||
values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
|
values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.9 2008/01/01 19:45:48 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.10 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -193,6 +193,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid)
|
|||||||
toastOid,
|
toastOid,
|
||||||
rel->rd_rel->relowner,
|
rel->rd_rel->relowner,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
|
NIL,
|
||||||
RELKIND_TOASTVALUE,
|
RELKIND_TOASTVALUE,
|
||||||
shared_relation,
|
shared_relation,
|
||||||
true,
|
true,
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.173 2008/04/13 19:18:14 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.174 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -639,9 +639,12 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to make a copy of the tuple descriptor, since
|
* Need to make a copy of the tuple descriptor, since
|
||||||
* heap_create_with_catalog modifies it.
|
* heap_create_with_catalog modifies it. Note that the NewHeap will
|
||||||
|
* not receive any of the defaults or constraints associated with the
|
||||||
|
* OldHeap; we don't need 'em, and there's no reason to spend cycles
|
||||||
|
* inserting them into the catalogs only to delete them.
|
||||||
*/
|
*/
|
||||||
tupdesc = CreateTupleDescCopyConstr(OldHeapDesc);
|
tupdesc = CreateTupleDescCopy(OldHeapDesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use options of the old heap for new heap.
|
* Use options of the old heap for new heap.
|
||||||
@ -662,6 +665,7 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
|
|||||||
InvalidOid,
|
InvalidOid,
|
||||||
OldHeap->rd_rel->relowner,
|
OldHeap->rd_rel->relowner,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
|
NIL,
|
||||||
OldHeap->rd_rel->relkind,
|
OldHeap->rd_rel->relkind,
|
||||||
OldHeap->rd_rel->relisshared,
|
OldHeap->rd_rel->relisshared,
|
||||||
true,
|
true,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.117 2008/03/27 03:57:33 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.118 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* The "DefineFoo" routines take the parse tree and pick out the
|
* The "DefineFoo" routines take the parse tree and pick out the
|
||||||
@ -2206,7 +2206,9 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
|
|||||||
InvalidOid,
|
InvalidOid,
|
||||||
expr, /* Tree form check constraint */
|
expr, /* Tree form check constraint */
|
||||||
ccbin, /* Binary form check constraint */
|
ccbin, /* Binary form check constraint */
|
||||||
ccsrc); /* Source form check constraint */
|
ccsrc, /* Source form check constraint */
|
||||||
|
true, /* is local */
|
||||||
|
0); /* inhcount */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the compiled constraint expression so the calling routine can
|
* Return the compiled constraint expression so the calling routine can
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.306 2008/04/21 03:49:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.307 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2626,7 +2626,7 @@ OpenIntoRel(QueryDesc *queryDesc)
|
|||||||
false);
|
false);
|
||||||
(void) heap_reloptions(RELKIND_RELATION, reloptions, true);
|
(void) heap_reloptions(RELKIND_RELATION, reloptions, true);
|
||||||
|
|
||||||
/* have to copy the actual tupdesc to get rid of any constraints */
|
/* Copy the tupdesc because heap_create_with_catalog modifies it */
|
||||||
tupdesc = CreateTupleDescCopy(queryDesc->tupDesc);
|
tupdesc = CreateTupleDescCopy(queryDesc->tupDesc);
|
||||||
|
|
||||||
/* Now we can actually create the new relation */
|
/* Now we can actually create the new relation */
|
||||||
@ -2636,6 +2636,7 @@ OpenIntoRel(QueryDesc *queryDesc)
|
|||||||
InvalidOid,
|
InvalidOid,
|
||||||
GetUserId(),
|
GetUserId(),
|
||||||
tupdesc,
|
tupdesc,
|
||||||
|
NIL,
|
||||||
RELKIND_RELATION,
|
RELKIND_RELATION,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.103 2008/03/27 03:57:33 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.104 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -62,8 +62,7 @@ static DumpableObject **oprinfoindex;
|
|||||||
|
|
||||||
static void flagInhTables(TableInfo *tbinfo, int numTables,
|
static void flagInhTables(TableInfo *tbinfo, int numTables,
|
||||||
InhInfo *inhinfo, int numInherits);
|
InhInfo *inhinfo, int numInherits);
|
||||||
static void flagInhAttrs(TableInfo *tbinfo, int numTables,
|
static void flagInhAttrs(TableInfo *tblinfo, int numTables);
|
||||||
InhInfo *inhinfo, int numInherits);
|
|
||||||
static DumpableObject **buildIndexArray(void *objArray, int numObjs,
|
static DumpableObject **buildIndexArray(void *objArray, int numObjs,
|
||||||
Size objSize);
|
Size objSize);
|
||||||
static int DOCatalogIdCompare(const void *p1, const void *p2);
|
static int DOCatalogIdCompare(const void *p1, const void *p2);
|
||||||
@ -191,7 +190,7 @@ getSchemaData(int *numTablesPtr)
|
|||||||
|
|
||||||
if (g_verbose)
|
if (g_verbose)
|
||||||
write_msg(NULL, "flagging inherited columns in subtables\n");
|
write_msg(NULL, "flagging inherited columns in subtables\n");
|
||||||
flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
|
flagInhAttrs(tblinfo, numTables);
|
||||||
|
|
||||||
if (g_verbose)
|
if (g_verbose)
|
||||||
write_msg(NULL, "reading indexes\n");
|
write_msg(NULL, "reading indexes\n");
|
||||||
@ -257,8 +256,7 @@ flagInhTables(TableInfo *tblinfo, int numTables,
|
|||||||
* modifies tblinfo
|
* modifies tblinfo
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
flagInhAttrs(TableInfo *tblinfo, int numTables,
|
flagInhAttrs(TableInfo *tblinfo, int numTables)
|
||||||
InhInfo *inhinfo, int numInherits)
|
|
||||||
{
|
{
|
||||||
int i,
|
int i,
|
||||||
j,
|
j,
|
||||||
@ -414,43 +412,6 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
|
|||||||
tbinfo->inhAttrs[j] = false;
|
tbinfo->inhAttrs[j] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for inherited CHECK constraints. We assume a constraint is
|
|
||||||
* inherited if its name matches the name of any constraint in the
|
|
||||||
* parent. Originally this code tried to compare the expression
|
|
||||||
* texts, but that can fail if the parent and child tables are in
|
|
||||||
* different schemas, because reverse-listing of function calls may
|
|
||||||
* produce different text (schema-qualified or not) depending on
|
|
||||||
* search path. We really need a more bulletproof way of detecting
|
|
||||||
* inherited constraints --- pg_constraint should record this
|
|
||||||
* explicitly!
|
|
||||||
*/
|
|
||||||
for (j = 0; j < tbinfo->ncheck; j++)
|
|
||||||
{
|
|
||||||
ConstraintInfo *constr;
|
|
||||||
|
|
||||||
constr = &(tbinfo->checkexprs[j]);
|
|
||||||
|
|
||||||
for (k = 0; k < numParents; k++)
|
|
||||||
{
|
|
||||||
int l;
|
|
||||||
|
|
||||||
parent = parents[k];
|
|
||||||
for (l = 0; l < parent->ncheck; l++)
|
|
||||||
{
|
|
||||||
ConstraintInfo *pconstr = &(parent->checkexprs[l]);
|
|
||||||
|
|
||||||
if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
|
|
||||||
{
|
|
||||||
constr->coninherited = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (constr->coninherited)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* by PostgreSQL
|
* by PostgreSQL
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.489 2008/05/03 23:32:32 adunstan Exp $
|
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.490 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -120,6 +120,7 @@ static void expand_table_name_patterns(SimpleStringList *patterns,
|
|||||||
SimpleOidList *oids);
|
SimpleOidList *oids);
|
||||||
static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
|
static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
|
||||||
static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
|
static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
|
||||||
|
static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
|
||||||
static void dumpComment(Archive *fout, const char *target,
|
static void dumpComment(Archive *fout, const char *target,
|
||||||
const char *namespace, const char *owner,
|
const char *namespace, const char *owner,
|
||||||
CatalogId catalogId, int subid, DumpId dumpId);
|
CatalogId catalogId, int subid, DumpId dumpId);
|
||||||
@ -645,6 +646,9 @@ main(int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
tblinfo = getSchemaData(&numTables);
|
tblinfo = getSchemaData(&numTables);
|
||||||
|
|
||||||
|
if (g_fout->remoteVersion < 80400)
|
||||||
|
guessConstraintInheritance(tblinfo, numTables);
|
||||||
|
|
||||||
if (!schemaOnly)
|
if (!schemaOnly)
|
||||||
getTableData(tblinfo, numTables, oids);
|
getTableData(tblinfo, numTables, oids);
|
||||||
|
|
||||||
@ -1383,6 +1387,81 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* guessConstraintInheritance:
|
||||||
|
* In pre-8.4 databases, we can't tell for certain which constraints
|
||||||
|
* are inherited. We assume a CHECK constraint is inherited if its name
|
||||||
|
* matches the name of any constraint in the parent. Originally this code
|
||||||
|
* tried to compare the expression texts, but that can fail for various
|
||||||
|
* reasons --- for example, if the parent and child tables are in different
|
||||||
|
* schemas, reverse-listing of function calls may produce different text
|
||||||
|
* (schema-qualified or not) depending on search path.
|
||||||
|
*
|
||||||
|
* In 8.4 and up we can rely on the conislocal field to decide which
|
||||||
|
* constraints must be dumped; much safer.
|
||||||
|
*
|
||||||
|
* This function assumes all conislocal flags were initialized to TRUE.
|
||||||
|
* It clears the flag on anything that seems to be inherited.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
guessConstraintInheritance(TableInfo *tblinfo, int numTables)
|
||||||
|
{
|
||||||
|
int i,
|
||||||
|
j,
|
||||||
|
k;
|
||||||
|
|
||||||
|
for (i = 0; i < numTables; i++)
|
||||||
|
{
|
||||||
|
TableInfo *tbinfo = &(tblinfo[i]);
|
||||||
|
int numParents;
|
||||||
|
TableInfo **parents;
|
||||||
|
TableInfo *parent;
|
||||||
|
|
||||||
|
/* Sequences and views never have parents */
|
||||||
|
if (tbinfo->relkind == RELKIND_SEQUENCE ||
|
||||||
|
tbinfo->relkind == RELKIND_VIEW)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Don't bother computing anything for non-target tables, either */
|
||||||
|
if (!tbinfo->dobj.dump)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
numParents = tbinfo->numParents;
|
||||||
|
parents = tbinfo->parents;
|
||||||
|
|
||||||
|
if (numParents == 0)
|
||||||
|
continue; /* nothing to see here, move along */
|
||||||
|
|
||||||
|
/* scan for inherited CHECK constraints */
|
||||||
|
for (j = 0; j < tbinfo->ncheck; j++)
|
||||||
|
{
|
||||||
|
ConstraintInfo *constr;
|
||||||
|
|
||||||
|
constr = &(tbinfo->checkexprs[j]);
|
||||||
|
|
||||||
|
for (k = 0; k < numParents; k++)
|
||||||
|
{
|
||||||
|
int l;
|
||||||
|
|
||||||
|
parent = parents[k];
|
||||||
|
for (l = 0; l < parent->ncheck; l++)
|
||||||
|
{
|
||||||
|
ConstraintInfo *pconstr = &(parent->checkexprs[l]);
|
||||||
|
|
||||||
|
if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
|
||||||
|
{
|
||||||
|
constr->conislocal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!constr->conislocal)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dumpDatabase:
|
* dumpDatabase:
|
||||||
* dump the database definition
|
* dump the database definition
|
||||||
@ -3522,7 +3601,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
|
|||||||
constrinfo[j].contype = contype;
|
constrinfo[j].contype = contype;
|
||||||
constrinfo[j].condef = NULL;
|
constrinfo[j].condef = NULL;
|
||||||
constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
|
constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
|
||||||
constrinfo[j].coninherited = false;
|
constrinfo[j].conislocal = true;
|
||||||
constrinfo[j].separate = true;
|
constrinfo[j].separate = true;
|
||||||
|
|
||||||
indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
|
indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
|
||||||
@ -3623,7 +3702,7 @@ getConstraints(TableInfo tblinfo[], int numTables)
|
|||||||
constrinfo[j].contype = 'f';
|
constrinfo[j].contype = 'f';
|
||||||
constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
|
constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
|
||||||
constrinfo[j].conindex = 0;
|
constrinfo[j].conindex = 0;
|
||||||
constrinfo[j].coninherited = false;
|
constrinfo[j].conislocal = true;
|
||||||
constrinfo[j].separate = true;
|
constrinfo[j].separate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3706,7 +3785,7 @@ getDomainConstraints(TypeInfo *tinfo)
|
|||||||
constrinfo[i].contype = 'c';
|
constrinfo[i].contype = 'c';
|
||||||
constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
|
constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
|
||||||
constrinfo[i].conindex = 0;
|
constrinfo[i].conindex = 0;
|
||||||
constrinfo[i].coninherited = false;
|
constrinfo[i].conislocal = true;
|
||||||
constrinfo[i].separate = false;
|
constrinfo[i].separate = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4586,10 +4665,22 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
tbinfo->dobj.name);
|
tbinfo->dobj.name);
|
||||||
|
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
if (g_fout->remoteVersion >= 70400)
|
if (g_fout->remoteVersion >= 80400)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
|
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
|
||||||
"pg_catalog.pg_get_constraintdef(oid) AS consrc "
|
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
|
||||||
|
"conislocal "
|
||||||
|
"FROM pg_catalog.pg_constraint "
|
||||||
|
"WHERE conrelid = '%u'::pg_catalog.oid "
|
||||||
|
" AND contype = 'c' "
|
||||||
|
"ORDER BY conname",
|
||||||
|
tbinfo->dobj.catId.oid);
|
||||||
|
}
|
||||||
|
else if (g_fout->remoteVersion >= 70400)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
|
||||||
|
"pg_catalog.pg_get_constraintdef(oid) AS consrc, "
|
||||||
|
"true as conislocal "
|
||||||
"FROM pg_catalog.pg_constraint "
|
"FROM pg_catalog.pg_constraint "
|
||||||
"WHERE conrelid = '%u'::pg_catalog.oid "
|
"WHERE conrelid = '%u'::pg_catalog.oid "
|
||||||
" AND contype = 'c' "
|
" AND contype = 'c' "
|
||||||
@ -4600,7 +4691,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
{
|
{
|
||||||
/* no pg_get_constraintdef, must use consrc */
|
/* no pg_get_constraintdef, must use consrc */
|
||||||
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
|
appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
|
||||||
"'CHECK (' || consrc || ')' AS consrc "
|
"'CHECK (' || consrc || ')' AS consrc, "
|
||||||
|
"true as conislocal "
|
||||||
"FROM pg_catalog.pg_constraint "
|
"FROM pg_catalog.pg_constraint "
|
||||||
"WHERE conrelid = '%u'::pg_catalog.oid "
|
"WHERE conrelid = '%u'::pg_catalog.oid "
|
||||||
" AND contype = 'c' "
|
" AND contype = 'c' "
|
||||||
@ -4612,7 +4704,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
/* 7.2 did not have OIDs in pg_relcheck */
|
/* 7.2 did not have OIDs in pg_relcheck */
|
||||||
appendPQExpBuffer(q, "SELECT tableoid, 0 as oid, "
|
appendPQExpBuffer(q, "SELECT tableoid, 0 as oid, "
|
||||||
"rcname AS conname, "
|
"rcname AS conname, "
|
||||||
"'CHECK (' || rcsrc || ')' AS consrc "
|
"'CHECK (' || rcsrc || ')' AS consrc, "
|
||||||
|
"true as conislocal "
|
||||||
"FROM pg_relcheck "
|
"FROM pg_relcheck "
|
||||||
"WHERE rcrelid = '%u'::oid "
|
"WHERE rcrelid = '%u'::oid "
|
||||||
"ORDER BY rcname",
|
"ORDER BY rcname",
|
||||||
@ -4622,7 +4715,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
{
|
{
|
||||||
appendPQExpBuffer(q, "SELECT tableoid, oid, "
|
appendPQExpBuffer(q, "SELECT tableoid, oid, "
|
||||||
"rcname AS conname, "
|
"rcname AS conname, "
|
||||||
"'CHECK (' || rcsrc || ')' AS consrc "
|
"'CHECK (' || rcsrc || ')' AS consrc, "
|
||||||
|
"true as conislocal "
|
||||||
"FROM pg_relcheck "
|
"FROM pg_relcheck "
|
||||||
"WHERE rcrelid = '%u'::oid "
|
"WHERE rcrelid = '%u'::oid "
|
||||||
"ORDER BY rcname",
|
"ORDER BY rcname",
|
||||||
@ -4634,7 +4728,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
appendPQExpBuffer(q, "SELECT "
|
appendPQExpBuffer(q, "SELECT "
|
||||||
"(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
|
"(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
|
||||||
"oid, rcname AS conname, "
|
"oid, rcname AS conname, "
|
||||||
"'CHECK (' || rcsrc || ')' AS consrc "
|
"'CHECK (' || rcsrc || ')' AS consrc, "
|
||||||
|
"true as conislocal "
|
||||||
"FROM pg_relcheck "
|
"FROM pg_relcheck "
|
||||||
"WHERE rcrelid = '%u'::oid "
|
"WHERE rcrelid = '%u'::oid "
|
||||||
"ORDER BY rcname",
|
"ORDER BY rcname",
|
||||||
@ -4668,7 +4763,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
constrs[j].contype = 'c';
|
constrs[j].contype = 'c';
|
||||||
constrs[j].condef = strdup(PQgetvalue(res, j, 3));
|
constrs[j].condef = strdup(PQgetvalue(res, j, 3));
|
||||||
constrs[j].conindex = 0;
|
constrs[j].conindex = 0;
|
||||||
constrs[j].coninherited = false;
|
constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
|
||||||
constrs[j].separate = false;
|
constrs[j].separate = false;
|
||||||
|
|
||||||
constrs[j].dobj.dump = tbinfo->dobj.dump;
|
constrs[j].dobj.dump = tbinfo->dobj.dump;
|
||||||
@ -4684,8 +4779,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If the constraint is inherited, this will be detected
|
* If the constraint is inherited, this will be detected
|
||||||
* later. We also detect later if the constraint must be
|
* later (in pre-8.4 databases). We also detect later if the
|
||||||
* split out from the table definition.
|
* constraint must be split out from the table definition.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
@ -8840,7 +8935,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
|||||||
{
|
{
|
||||||
ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
|
ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
|
||||||
|
|
||||||
if (constr->coninherited || constr->separate)
|
if (constr->separate || !constr->conislocal)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (actual_atts > 0)
|
if (actual_atts > 0)
|
||||||
@ -8955,7 +9050,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
|||||||
{
|
{
|
||||||
ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
|
ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
|
||||||
|
|
||||||
if (constr->coninherited || constr->separate)
|
if (constr->separate || !constr->conislocal)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dumpTableConstraintComment(fout, constr);
|
dumpTableConstraintComment(fout, constr);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.139 2008/01/01 19:45:55 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.140 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -353,7 +353,7 @@ typedef struct _constraintInfo
|
|||||||
char contype;
|
char contype;
|
||||||
char *condef; /* definition, if CHECK or FOREIGN KEY */
|
char *condef; /* definition, if CHECK or FOREIGN KEY */
|
||||||
DumpId conindex; /* identifies associated index if any */
|
DumpId conindex; /* identifies associated index if any */
|
||||||
bool coninherited; /* TRUE if appears to be inherited */
|
bool conislocal; /* TRUE if constraint has local definition */
|
||||||
bool separate; /* TRUE if must dump as separate item */
|
bool separate; /* TRUE if must dump as separate item */
|
||||||
} ConstraintInfo;
|
} ConstraintInfo;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.457 2008/05/08 08:58:59 mha Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.458 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200805081
|
#define CATALOG_VERSION_NO 200805091
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.87 2008/01/01 19:45:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.88 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -29,6 +29,8 @@ typedef struct CookedConstraint
|
|||||||
char *name; /* name, or NULL if none */
|
char *name; /* name, or NULL if none */
|
||||||
AttrNumber attnum; /* which attr (only for DEFAULT) */
|
AttrNumber attnum; /* which attr (only for DEFAULT) */
|
||||||
Node *expr; /* transformed default or check expr */
|
Node *expr; /* transformed default or check expr */
|
||||||
|
bool is_local; /* constraint has local (non-inherited) def */
|
||||||
|
int inhcount; /* number of times constraint is inherited */
|
||||||
} CookedConstraint;
|
} CookedConstraint;
|
||||||
|
|
||||||
extern Relation heap_create(const char *relname,
|
extern Relation heap_create(const char *relname,
|
||||||
@ -46,6 +48,7 @@ extern Oid heap_create_with_catalog(const char *relname,
|
|||||||
Oid relid,
|
Oid relid,
|
||||||
Oid ownerid,
|
Oid ownerid,
|
||||||
TupleDesc tupdesc,
|
TupleDesc tupdesc,
|
||||||
|
List *cooked_constraints,
|
||||||
char relkind,
|
char relkind,
|
||||||
bool shared_relation,
|
bool shared_relation,
|
||||||
bool oidislocal,
|
bool oidislocal,
|
||||||
@ -67,11 +70,13 @@ extern void InsertPgClassTuple(Relation pg_class_desc,
|
|||||||
Oid new_rel_oid,
|
Oid new_rel_oid,
|
||||||
Datum reloptions);
|
Datum reloptions);
|
||||||
|
|
||||||
extern List *AddRelationRawConstraints(Relation rel,
|
extern List *AddRelationNewConstraints(Relation rel,
|
||||||
List *rawColDefaults,
|
List *newColDefaults,
|
||||||
List *rawConstraints);
|
List *newConstraints,
|
||||||
|
bool allow_merge,
|
||||||
|
bool is_local);
|
||||||
|
|
||||||
extern void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin);
|
extern void StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr);
|
||||||
|
|
||||||
extern Node *cookDefault(ParseState *pstate,
|
extern Node *cookDefault(ParseState *pstate,
|
||||||
Node *raw_default,
|
Node *raw_default,
|
||||||
@ -79,9 +84,6 @@ extern Node *cookDefault(ParseState *pstate,
|
|||||||
int32 atttypmod,
|
int32 atttypmod,
|
||||||
char *attname);
|
char *attname);
|
||||||
|
|
||||||
extern int RemoveRelConstraints(Relation rel, const char *constrName,
|
|
||||||
DropBehavior behavior);
|
|
||||||
|
|
||||||
extern void DeleteRelationTuple(Oid relid);
|
extern void DeleteRelationTuple(Oid relid);
|
||||||
extern void DeleteAttributeTuples(Oid relid);
|
extern void DeleteAttributeTuples(Oid relid);
|
||||||
extern void RemoveAttributeById(Oid relid, AttrNumber attnum);
|
extern void RemoveAttributeById(Oid relid, AttrNumber attnum);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.28 2008/03/27 03:57:34 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.29 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -71,6 +71,12 @@ CATALOG(pg_constraint,2606)
|
|||||||
char confdeltype; /* foreign key's ON DELETE action */
|
char confdeltype; /* foreign key's ON DELETE action */
|
||||||
char confmatchtype; /* foreign key's match type */
|
char confmatchtype; /* foreign key's match type */
|
||||||
|
|
||||||
|
/* Has a local definition (hence, do not drop when coninhcount is 0) */
|
||||||
|
bool conislocal;
|
||||||
|
|
||||||
|
/* Number of times inherited from direct parent relation(s) */
|
||||||
|
int4 coninhcount;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VARIABLE LENGTH FIELDS start here. These fields may be NULL, too.
|
* VARIABLE LENGTH FIELDS start here. These fields may be NULL, too.
|
||||||
*/
|
*/
|
||||||
@ -125,7 +131,7 @@ typedef FormData_pg_constraint *Form_pg_constraint;
|
|||||||
* compiler constants for pg_constraint
|
* compiler constants for pg_constraint
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
#define Natts_pg_constraint 18
|
#define Natts_pg_constraint 20
|
||||||
#define Anum_pg_constraint_conname 1
|
#define Anum_pg_constraint_conname 1
|
||||||
#define Anum_pg_constraint_connamespace 2
|
#define Anum_pg_constraint_connamespace 2
|
||||||
#define Anum_pg_constraint_contype 3
|
#define Anum_pg_constraint_contype 3
|
||||||
@ -137,13 +143,15 @@ typedef FormData_pg_constraint *Form_pg_constraint;
|
|||||||
#define Anum_pg_constraint_confupdtype 9
|
#define Anum_pg_constraint_confupdtype 9
|
||||||
#define Anum_pg_constraint_confdeltype 10
|
#define Anum_pg_constraint_confdeltype 10
|
||||||
#define Anum_pg_constraint_confmatchtype 11
|
#define Anum_pg_constraint_confmatchtype 11
|
||||||
#define Anum_pg_constraint_conkey 12
|
#define Anum_pg_constraint_conislocal 12
|
||||||
#define Anum_pg_constraint_confkey 13
|
#define Anum_pg_constraint_coninhcount 13
|
||||||
#define Anum_pg_constraint_conpfeqop 14
|
#define Anum_pg_constraint_conkey 14
|
||||||
#define Anum_pg_constraint_conppeqop 15
|
#define Anum_pg_constraint_confkey 15
|
||||||
#define Anum_pg_constraint_conffeqop 16
|
#define Anum_pg_constraint_conpfeqop 16
|
||||||
#define Anum_pg_constraint_conbin 17
|
#define Anum_pg_constraint_conppeqop 17
|
||||||
#define Anum_pg_constraint_consrc 18
|
#define Anum_pg_constraint_conffeqop 18
|
||||||
|
#define Anum_pg_constraint_conbin 19
|
||||||
|
#define Anum_pg_constraint_consrc 20
|
||||||
|
|
||||||
|
|
||||||
/* Valid values for contype */
|
/* Valid values for contype */
|
||||||
@ -192,7 +200,9 @@ extern Oid CreateConstraintEntry(const char *constraintName,
|
|||||||
Oid indexRelId,
|
Oid indexRelId,
|
||||||
Node *conExpr,
|
Node *conExpr,
|
||||||
const char *conBin,
|
const char *conBin,
|
||||||
const char *conSrc);
|
const char *conSrc,
|
||||||
|
bool conIsLocal,
|
||||||
|
int conInhCount);
|
||||||
|
|
||||||
extern void RemoveConstraintById(Oid conId);
|
extern void RemoveConstraintById(Oid conId);
|
||||||
extern void RenameConstraintById(Oid conId, const char *newname);
|
extern void RenameConstraintById(Oid conId, const char *newname);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.364 2008/04/29 20:44:49 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.365 2008/05/09 23:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -892,11 +892,11 @@ typedef enum AlterTableType
|
|||||||
AT_AddIndex, /* add index */
|
AT_AddIndex, /* add index */
|
||||||
AT_ReAddIndex, /* internal to commands/tablecmds.c */
|
AT_ReAddIndex, /* internal to commands/tablecmds.c */
|
||||||
AT_AddConstraint, /* add constraint */
|
AT_AddConstraint, /* add constraint */
|
||||||
|
AT_AddConstraintRecurse, /* internal to commands/tablecmds.c */
|
||||||
AT_ProcessedConstraint, /* pre-processed add constraint (local in
|
AT_ProcessedConstraint, /* pre-processed add constraint (local in
|
||||||
* parser/parse_utilcmd.c) */
|
* parser/parse_utilcmd.c) */
|
||||||
AT_DropConstraint, /* drop constraint */
|
AT_DropConstraint, /* drop constraint */
|
||||||
AT_DropConstraintQuietly, /* drop constraint, no error/warning (local in
|
AT_DropConstraintRecurse, /* internal to commands/tablecmds.c */
|
||||||
* commands/tablecmds.c) */
|
|
||||||
AT_AlterColumnType, /* alter column type */
|
AT_AlterColumnType, /* alter column type */
|
||||||
AT_ChangeOwner, /* change owner */
|
AT_ChangeOwner, /* change owner */
|
||||||
AT_ClusterOn, /* CLUSTER ON */
|
AT_ClusterOn, /* CLUSTER ON */
|
||||||
|
@ -378,19 +378,21 @@ drop table atacc2 cascade;
|
|||||||
NOTICE: drop cascades to table atacc3
|
NOTICE: drop cascades to table atacc3
|
||||||
NOTICE: drop cascades to constraint foo on table atacc3
|
NOTICE: drop cascades to constraint foo on table atacc3
|
||||||
drop table atacc1;
|
drop table atacc1;
|
||||||
-- let's try only to add only to the parent
|
-- adding only to a parent is disallowed as of 8.4
|
||||||
create table atacc1 (test int);
|
create table atacc1 (test int);
|
||||||
create table atacc2 (test2 int);
|
create table atacc2 (test2 int) inherits (atacc1);
|
||||||
create table atacc3 (test3 int) inherits (atacc1, atacc2);
|
-- fail:
|
||||||
alter table only atacc2 add constraint foo check (test2>0);
|
alter table only atacc1 add constraint foo check (test>0);
|
||||||
-- fail and then succeed on atacc2
|
ERROR: constraint must be added to child tables too
|
||||||
insert into atacc2 (test2) values (-3);
|
-- ok:
|
||||||
|
alter table only atacc2 add constraint foo check (test>0);
|
||||||
|
-- check constraint not there on parent
|
||||||
|
insert into atacc1 (test) values (-3);
|
||||||
|
insert into atacc1 (test) values (3);
|
||||||
|
-- check constraint is there on child
|
||||||
|
insert into atacc2 (test) values (-3);
|
||||||
ERROR: new row for relation "atacc2" violates check constraint "foo"
|
ERROR: new row for relation "atacc2" violates check constraint "foo"
|
||||||
insert into atacc2 (test2) values (3);
|
insert into atacc2 (test) values (3);
|
||||||
-- both succeed on atacc3
|
|
||||||
insert into atacc3 (test2) values (-3);
|
|
||||||
insert into atacc3 (test2) values (3);
|
|
||||||
drop table atacc3;
|
|
||||||
drop table atacc2;
|
drop table atacc2;
|
||||||
drop table atacc1;
|
drop table atacc1;
|
||||||
-- test unique constraint adding
|
-- test unique constraint adding
|
||||||
@ -1230,7 +1232,7 @@ alter table p1 add column f2 text;
|
|||||||
NOTICE: merging definition of column "f2" for child "c1"
|
NOTICE: merging definition of column "f2" for child "c1"
|
||||||
insert into p1 values (1,2,'abc');
|
insert into p1 values (1,2,'abc');
|
||||||
insert into c1 values(11,'xyz',33,0); -- should fail
|
insert into c1 values(11,'xyz',33,0); -- should fail
|
||||||
ERROR: new row for relation "c1" violates check constraint "c1_a1_check"
|
ERROR: new row for relation "c1" violates check constraint "p1_a1_check"
|
||||||
insert into c1 values(11,'xyz',33,22);
|
insert into c1 values(11,'xyz',33,22);
|
||||||
select * from p1;
|
select * from p1;
|
||||||
f1 | a1 | f2
|
f1 | a1 | f2
|
||||||
@ -1249,7 +1251,7 @@ select * from p1;
|
|||||||
|
|
||||||
drop table p1 cascade;
|
drop table p1 cascade;
|
||||||
NOTICE: drop cascades to table c1
|
NOTICE: drop cascades to table c1
|
||||||
NOTICE: drop cascades to constraint c1_a1_check on table c1
|
NOTICE: drop cascades to constraint p1_a1_check on table c1
|
||||||
-- test that operations with a dropped column do not try to reference
|
-- test that operations with a dropped column do not try to reference
|
||||||
-- its datatype
|
-- its datatype
|
||||||
create domain mytype as text;
|
create domain mytype as text;
|
||||||
|
@ -692,3 +692,220 @@ drop function p2text(p2);
|
|||||||
drop table c1;
|
drop table c1;
|
||||||
drop table p2;
|
drop table p2;
|
||||||
drop table p1;
|
drop table p1;
|
||||||
|
CREATE TABLE ac (aa TEXT);
|
||||||
|
alter table ac add constraint ac_check check (aa is not null);
|
||||||
|
CREATE TABLE bc (bb TEXT) INHERITS (ac);
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+----------+---------+------------+-------------+------------------
|
||||||
|
ac | ac_check | c | t | 0 | (aa IS NOT NULL)
|
||||||
|
bc | ac_check | c | f | 1 | (aa IS NOT NULL)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
insert into ac (aa) values (NULL);
|
||||||
|
ERROR: new row for relation "ac" violates check constraint "ac_check"
|
||||||
|
insert into bc (aa) values (NULL);
|
||||||
|
ERROR: new row for relation "bc" violates check constraint "ac_check"
|
||||||
|
alter table bc drop constraint ac_check; -- fail, disallowed
|
||||||
|
ERROR: cannot drop inherited constraint "ac_check" of relation "bc"
|
||||||
|
alter table ac drop constraint ac_check;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+---------+---------+------------+-------------+--------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
-- try the unnamed-constraint case
|
||||||
|
alter table ac add check (aa is not null);
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+-------------+---------+------------+-------------+------------------
|
||||||
|
ac | ac_aa_check | c | t | 0 | (aa IS NOT NULL)
|
||||||
|
bc | ac_aa_check | c | f | 1 | (aa IS NOT NULL)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
insert into ac (aa) values (NULL);
|
||||||
|
ERROR: new row for relation "ac" violates check constraint "ac_aa_check"
|
||||||
|
insert into bc (aa) values (NULL);
|
||||||
|
ERROR: new row for relation "bc" violates check constraint "ac_aa_check"
|
||||||
|
alter table bc drop constraint ac_aa_check; -- fail, disallowed
|
||||||
|
ERROR: cannot drop inherited constraint "ac_aa_check" of relation "bc"
|
||||||
|
alter table ac drop constraint ac_aa_check;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+---------+---------+------------+-------------+--------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
alter table ac add constraint ac_check check (aa is not null);
|
||||||
|
alter table bc no inherit ac;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+----------+---------+------------+-------------+------------------
|
||||||
|
ac | ac_check | c | t | 0 | (aa IS NOT NULL)
|
||||||
|
bc | ac_check | c | t | 0 | (aa IS NOT NULL)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
alter table bc drop constraint ac_check;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+----------+---------+------------+-------------+------------------
|
||||||
|
ac | ac_check | c | t | 0 | (aa IS NOT NULL)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
alter table ac drop constraint ac_check;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+---------+---------+------------+-------------+--------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
drop table bc;
|
||||||
|
drop table ac;
|
||||||
|
create table ac (a int constraint check_a check (a <> 0));
|
||||||
|
create table bc (a int constraint check_a check (a <> 0), b int constraint check_b check (b <> 0)) inherits (ac);
|
||||||
|
NOTICE: merging column "a" with inherited definition
|
||||||
|
NOTICE: merging constraint "check_a" with inherited definition
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+---------+---------+------------+-------------+----------
|
||||||
|
ac | check_a | c | t | 0 | (a <> 0)
|
||||||
|
bc | check_a | c | t | 1 | (a <> 0)
|
||||||
|
bc | check_b | c | t | 0 | (b <> 0)
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
drop table bc;
|
||||||
|
drop table ac;
|
||||||
|
create table ac (a int constraint check_a check (a <> 0));
|
||||||
|
create table bc (b int constraint check_b check (b <> 0));
|
||||||
|
create table cc (c int constraint check_c check (c <> 0)) inherits (ac, bc);
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc', 'cc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+---------+---------+------------+-------------+----------
|
||||||
|
ac | check_a | c | t | 0 | (a <> 0)
|
||||||
|
bc | check_b | c | t | 0 | (b <> 0)
|
||||||
|
cc | check_a | c | f | 1 | (a <> 0)
|
||||||
|
cc | check_b | c | f | 1 | (b <> 0)
|
||||||
|
cc | check_c | c | t | 0 | (c <> 0)
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
alter table cc no inherit bc;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc', 'cc') order by 1,2;
|
||||||
|
relname | conname | contype | conislocal | coninhcount | consrc
|
||||||
|
---------+---------+---------+------------+-------------+----------
|
||||||
|
ac | check_a | c | t | 0 | (a <> 0)
|
||||||
|
bc | check_b | c | t | 0 | (b <> 0)
|
||||||
|
cc | check_a | c | f | 1 | (a <> 0)
|
||||||
|
cc | check_b | c | t | 0 | (b <> 0)
|
||||||
|
cc | check_c | c | t | 0 | (c <> 0)
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
drop table cc;
|
||||||
|
drop table bc;
|
||||||
|
drop table ac;
|
||||||
|
create table p1(f1 int);
|
||||||
|
create table p2(f2 int);
|
||||||
|
create table c1(f3 int) inherits(p1,p2);
|
||||||
|
insert into c1 values(1,-1,2);
|
||||||
|
alter table p2 add constraint cc check (f2>0); -- fail
|
||||||
|
ERROR: check constraint "cc" is violated by some row
|
||||||
|
alter table p2 add check (f2>0); -- check it without a name, too
|
||||||
|
ERROR: check constraint "p2_f2_check" is violated by some row
|
||||||
|
delete from c1;
|
||||||
|
insert into c1 values(1,1,2);
|
||||||
|
alter table p2 add check (f2>0);
|
||||||
|
insert into c1 values(1,-1,2); -- fail
|
||||||
|
ERROR: new row for relation "c1" violates check constraint "p2_f2_check"
|
||||||
|
create table c2(f3 int) inherits(p1,p2);
|
||||||
|
\d c2
|
||||||
|
Table "public.c2"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+---------+-----------
|
||||||
|
f1 | integer |
|
||||||
|
f2 | integer |
|
||||||
|
f3 | integer |
|
||||||
|
Check constraints:
|
||||||
|
"p2_f2_check" CHECK (f2 > 0)
|
||||||
|
Inherits: p1,
|
||||||
|
p2
|
||||||
|
|
||||||
|
create table c3 (f4 int) inherits(c1,c2);
|
||||||
|
NOTICE: merging multiple inherited definitions of column "f1"
|
||||||
|
NOTICE: merging multiple inherited definitions of column "f2"
|
||||||
|
NOTICE: merging multiple inherited definitions of column "f3"
|
||||||
|
\d c3
|
||||||
|
Table "public.c3"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+---------+-----------
|
||||||
|
f1 | integer |
|
||||||
|
f2 | integer |
|
||||||
|
f3 | integer |
|
||||||
|
f4 | integer |
|
||||||
|
Check constraints:
|
||||||
|
"p2_f2_check" CHECK (f2 > 0)
|
||||||
|
Inherits: c1,
|
||||||
|
c2
|
||||||
|
|
||||||
|
drop table p1 cascade;
|
||||||
|
NOTICE: drop cascades to table c2
|
||||||
|
NOTICE: drop cascades to table c3
|
||||||
|
NOTICE: drop cascades to constraint p2_f2_check on table c3
|
||||||
|
NOTICE: drop cascades to constraint p2_f2_check on table c2
|
||||||
|
NOTICE: drop cascades to table c1
|
||||||
|
NOTICE: drop cascades to constraint p2_f2_check on table c1
|
||||||
|
drop table p2 cascade;
|
||||||
|
create table pp1 (f1 int);
|
||||||
|
create table cc1 (f2 text, f3 int) inherits (pp1);
|
||||||
|
alter table pp1 add column a1 int check (a1 > 0);
|
||||||
|
\d cc1
|
||||||
|
Table "public.cc1"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+---------+-----------
|
||||||
|
f1 | integer |
|
||||||
|
f2 | text |
|
||||||
|
f3 | integer |
|
||||||
|
a1 | integer |
|
||||||
|
Check constraints:
|
||||||
|
"pp1_a1_check" CHECK (a1 > 0)
|
||||||
|
Inherits: pp1
|
||||||
|
|
||||||
|
create table cc2(f4 float) inherits(pp1,cc1);
|
||||||
|
NOTICE: merging multiple inherited definitions of column "f1"
|
||||||
|
NOTICE: merging multiple inherited definitions of column "a1"
|
||||||
|
\d cc2
|
||||||
|
Table "public.cc2"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+------------------+-----------
|
||||||
|
f1 | integer |
|
||||||
|
a1 | integer |
|
||||||
|
f2 | text |
|
||||||
|
f3 | integer |
|
||||||
|
f4 | double precision |
|
||||||
|
Check constraints:
|
||||||
|
"pp1_a1_check" CHECK (a1 > 0)
|
||||||
|
Inherits: pp1,
|
||||||
|
cc1
|
||||||
|
|
||||||
|
alter table pp1 add column a2 int check (a2 > 0);
|
||||||
|
NOTICE: merging definition of column "a2" for child "cc2"
|
||||||
|
NOTICE: merging constraint "pp1_a2_check" with inherited definition
|
||||||
|
\d cc2
|
||||||
|
Table "public.cc2"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+------------------+-----------
|
||||||
|
f1 | integer |
|
||||||
|
a1 | integer |
|
||||||
|
f2 | text |
|
||||||
|
f3 | integer |
|
||||||
|
f4 | double precision |
|
||||||
|
a2 | integer |
|
||||||
|
Check constraints:
|
||||||
|
"pp1_a1_check" CHECK (a1 > 0)
|
||||||
|
"pp1_a2_check" CHECK (a2 > 0)
|
||||||
|
Inherits: pp1,
|
||||||
|
cc1
|
||||||
|
|
||||||
|
drop table pp1 cascade;
|
||||||
|
NOTICE: drop cascades to table cc2
|
||||||
|
NOTICE: drop cascades to constraint pp1_a1_check on table cc2
|
||||||
|
NOTICE: drop cascades to constraint pp1_a2_check on table cc2
|
||||||
|
NOTICE: drop cascades to table cc1
|
||||||
|
NOTICE: drop cascades to constraint pp1_a1_check on table cc1
|
||||||
|
NOTICE: drop cascades to constraint pp1_a2_check on table cc1
|
||||||
|
@ -389,19 +389,20 @@ select test2 from atacc2;
|
|||||||
drop table atacc2 cascade;
|
drop table atacc2 cascade;
|
||||||
drop table atacc1;
|
drop table atacc1;
|
||||||
|
|
||||||
-- let's try only to add only to the parent
|
-- adding only to a parent is disallowed as of 8.4
|
||||||
|
|
||||||
create table atacc1 (test int);
|
create table atacc1 (test int);
|
||||||
create table atacc2 (test2 int);
|
create table atacc2 (test2 int) inherits (atacc1);
|
||||||
create table atacc3 (test3 int) inherits (atacc1, atacc2);
|
-- fail:
|
||||||
alter table only atacc2 add constraint foo check (test2>0);
|
alter table only atacc1 add constraint foo check (test>0);
|
||||||
-- fail and then succeed on atacc2
|
-- ok:
|
||||||
insert into atacc2 (test2) values (-3);
|
alter table only atacc2 add constraint foo check (test>0);
|
||||||
insert into atacc2 (test2) values (3);
|
-- check constraint not there on parent
|
||||||
-- both succeed on atacc3
|
insert into atacc1 (test) values (-3);
|
||||||
insert into atacc3 (test2) values (-3);
|
insert into atacc1 (test) values (3);
|
||||||
insert into atacc3 (test2) values (3);
|
-- check constraint is there on child
|
||||||
drop table atacc3;
|
insert into atacc2 (test) values (-3);
|
||||||
|
insert into atacc2 (test) values (3);
|
||||||
drop table atacc2;
|
drop table atacc2;
|
||||||
drop table atacc1;
|
drop table atacc1;
|
||||||
|
|
||||||
|
@ -196,3 +196,83 @@ drop function p2text(p2);
|
|||||||
drop table c1;
|
drop table c1;
|
||||||
drop table p2;
|
drop table p2;
|
||||||
drop table p1;
|
drop table p1;
|
||||||
|
|
||||||
|
CREATE TABLE ac (aa TEXT);
|
||||||
|
alter table ac add constraint ac_check check (aa is not null);
|
||||||
|
CREATE TABLE bc (bb TEXT) INHERITS (ac);
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
|
||||||
|
insert into ac (aa) values (NULL);
|
||||||
|
insert into bc (aa) values (NULL);
|
||||||
|
|
||||||
|
alter table bc drop constraint ac_check; -- fail, disallowed
|
||||||
|
alter table ac drop constraint ac_check;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
|
||||||
|
-- try the unnamed-constraint case
|
||||||
|
alter table ac add check (aa is not null);
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
|
||||||
|
insert into ac (aa) values (NULL);
|
||||||
|
insert into bc (aa) values (NULL);
|
||||||
|
|
||||||
|
alter table bc drop constraint ac_aa_check; -- fail, disallowed
|
||||||
|
alter table ac drop constraint ac_aa_check;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
|
||||||
|
alter table ac add constraint ac_check check (aa is not null);
|
||||||
|
alter table bc no inherit ac;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
alter table bc drop constraint ac_check;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
alter table ac drop constraint ac_check;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
|
||||||
|
drop table bc;
|
||||||
|
drop table ac;
|
||||||
|
|
||||||
|
create table ac (a int constraint check_a check (a <> 0));
|
||||||
|
create table bc (a int constraint check_a check (a <> 0), b int constraint check_b check (b <> 0)) inherits (ac);
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2;
|
||||||
|
|
||||||
|
drop table bc;
|
||||||
|
drop table ac;
|
||||||
|
|
||||||
|
create table ac (a int constraint check_a check (a <> 0));
|
||||||
|
create table bc (b int constraint check_b check (b <> 0));
|
||||||
|
create table cc (c int constraint check_c check (c <> 0)) inherits (ac, bc);
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc', 'cc') order by 1,2;
|
||||||
|
|
||||||
|
alter table cc no inherit bc;
|
||||||
|
select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc', 'cc') order by 1,2;
|
||||||
|
|
||||||
|
drop table cc;
|
||||||
|
drop table bc;
|
||||||
|
drop table ac;
|
||||||
|
|
||||||
|
create table p1(f1 int);
|
||||||
|
create table p2(f2 int);
|
||||||
|
create table c1(f3 int) inherits(p1,p2);
|
||||||
|
insert into c1 values(1,-1,2);
|
||||||
|
alter table p2 add constraint cc check (f2>0); -- fail
|
||||||
|
alter table p2 add check (f2>0); -- check it without a name, too
|
||||||
|
delete from c1;
|
||||||
|
insert into c1 values(1,1,2);
|
||||||
|
alter table p2 add check (f2>0);
|
||||||
|
insert into c1 values(1,-1,2); -- fail
|
||||||
|
create table c2(f3 int) inherits(p1,p2);
|
||||||
|
\d c2
|
||||||
|
create table c3 (f4 int) inherits(c1,c2);
|
||||||
|
\d c3
|
||||||
|
drop table p1 cascade;
|
||||||
|
drop table p2 cascade;
|
||||||
|
|
||||||
|
create table pp1 (f1 int);
|
||||||
|
create table cc1 (f2 text, f3 int) inherits (pp1);
|
||||||
|
alter table pp1 add column a1 int check (a1 > 0);
|
||||||
|
\d cc1
|
||||||
|
create table cc2(f4 float) inherits(pp1,cc1);
|
||||||
|
\d cc2
|
||||||
|
alter table pp1 add column a2 int check (a2 > 0);
|
||||||
|
\d cc2
|
||||||
|
drop table pp1 cascade;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user