mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
Fix handling of inherited check constraints in ALTER COLUMN TYPE (again).
The previous way of reconstructing check constraints was to do a separate "ALTER TABLE ONLY tab ADD CONSTRAINT" for each table in an inheritance hierarchy. However, that way has no hope of reconstructing the check constraints' own inheritance properties correctly, as pointed out in bug #13779 from Jan Dirk Zijlstra. What we should do instead is to do a regular "ALTER TABLE", allowing recursion, at the topmost table that has a particular constraint, and then suppress the work queue entries for inherited instances of the constraint. Annoyingly, we'd tried to fix this behavior before, in commit5ed6546cf
, but we failed to notice that it wasn't reconstructing the pg_constraint field values correctly. As long as I'm touching pg_get_constraintdef_worker anyway, tweak it to always schema-qualify the target table name; this seems like useful backup to the protections installed by commit5f173040
. In HEAD/9.5, get rid of get_constraint_relation_oids, which is now unused. (I could alternatively have modified it to also return conislocal, but that seemed like a pretty single-purpose API, so let's not pretend it has some other use.) It's unused in the back branches as well, but I left it in place just in case some third-party code has decided to use it. In HEAD/9.5, also rename pg_get_constraintdef_string to pg_get_constraintdef_command, as the previous name did nothing to explain what that entry point did differently from others (and its comment was equally useless). Again, that change doesn't seem like material for back-patching. I did a bit of re-pgindenting in tablecmds.c in HEAD/9.5, as well. Otherwise, back-patch to all supported branches.
This commit is contained in:
parent
6c878a7553
commit
074c5cfbfb
@ -754,25 +754,6 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
|
||||
heap_close(conRel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_constraint_relation_oids
|
||||
* Find the IDs of the relations to which a constraint refers.
|
||||
*/
|
||||
void
|
||||
get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Form_pg_constraint con;
|
||||
|
||||
tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraint_oid));
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for constraint %u", constraint_oid);
|
||||
con = (Form_pg_constraint) GETSTRUCT(tup);
|
||||
*conrelid = con->conrelid;
|
||||
*confrelid = con->confrelid;
|
||||
ReleaseSysCache(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_relation_constraint_oid
|
||||
* Find a constraint on the specified relation with the specified name.
|
||||
|
@ -328,9 +328,10 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recu
|
||||
bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode);
|
||||
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
|
||||
Relation rel, ColumnDef *colDef, bool isOid,
|
||||
bool recurse, bool recursing, bool if_not_exists, LOCKMODE lockmode);
|
||||
bool recurse, bool recursing,
|
||||
bool if_not_exists, LOCKMODE lockmode);
|
||||
static bool check_for_column_name_collision(Relation rel, const char *colname,
|
||||
bool if_not_exists);
|
||||
bool if_not_exists);
|
||||
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
|
||||
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
|
||||
static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
|
||||
@ -3457,11 +3458,13 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
case AT_AddColumnToView: /* add column via CREATE OR REPLACE
|
||||
* VIEW */
|
||||
address = ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
|
||||
false, false, false, false, lockmode);
|
||||
false, false, false,
|
||||
false, lockmode);
|
||||
break;
|
||||
case AT_AddColumnRecurse:
|
||||
address = ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
|
||||
false, true, false, cmd->missing_ok, lockmode);
|
||||
false, true, false,
|
||||
cmd->missing_ok, lockmode);
|
||||
break;
|
||||
case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
|
||||
address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
|
||||
@ -3516,7 +3519,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
* constraint */
|
||||
address =
|
||||
ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
|
||||
false, true, lockmode);
|
||||
true, true, lockmode);
|
||||
break;
|
||||
case AT_ReAddComment: /* Re-add existing comment */
|
||||
address = CommentObject((CommentStmt *) cmd->def);
|
||||
@ -3574,14 +3577,16 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
if (cmd->def != NULL)
|
||||
address =
|
||||
ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
|
||||
true, false, false, cmd->missing_ok, lockmode);
|
||||
true, false, false,
|
||||
cmd->missing_ok, lockmode);
|
||||
break;
|
||||
case AT_AddOidsRecurse: /* SET WITH OIDS */
|
||||
/* Use the ADD COLUMN code, unless prep decided to do nothing */
|
||||
if (cmd->def != NULL)
|
||||
address =
|
||||
ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
|
||||
true, true, false, cmd->missing_ok, lockmode);
|
||||
true, true, false,
|
||||
cmd->missing_ok, lockmode);
|
||||
break;
|
||||
case AT_DropOids: /* SET WITHOUT OIDS */
|
||||
|
||||
@ -4691,7 +4696,8 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
|
||||
static ObjectAddress
|
||||
ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
ColumnDef *colDef, bool isOid,
|
||||
bool recurse, bool recursing, bool if_not_exists, LOCKMODE lockmode)
|
||||
bool recurse, bool recursing,
|
||||
bool if_not_exists, LOCKMODE lockmode)
|
||||
{
|
||||
Oid myrelid = RelationGetRelid(rel);
|
||||
Relation pgclass,
|
||||
@ -6090,13 +6096,6 @@ ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
* AddRelationNewConstraints would normally assign different names to the
|
||||
* child constraints. To fix that, we must capture the name assigned at
|
||||
* the parent table and pass that down.
|
||||
*
|
||||
* When re-adding a previously existing constraint (during ALTER COLUMN TYPE),
|
||||
* we don't need to recurse here, because recursion will be carried out at a
|
||||
* higher level; the constraint name issue doesn't apply because the names
|
||||
* have already been assigned and are just being re-used. We need a separate
|
||||
* "is_readd" flag for that; just setting recurse=false would result in an
|
||||
* error if there are child tables.
|
||||
*/
|
||||
static ObjectAddress
|
||||
ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
@ -6125,7 +6124,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
*/
|
||||
newcons = AddRelationNewConstraints(rel, NIL,
|
||||
list_make1(copyObject(constr)),
|
||||
recursing, /* allow_merge */
|
||||
recursing | is_readd, /* allow_merge */
|
||||
!recursing, /* is_local */
|
||||
is_readd); /* is_internal */
|
||||
|
||||
@ -6174,10 +6173,8 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
|
||||
/*
|
||||
* If adding a NO INHERIT constraint, no need to find our children.
|
||||
* Likewise, in a re-add operation, we don't need to recurse (that will be
|
||||
* handled at higher levels).
|
||||
*/
|
||||
if (constr->is_no_inherit || is_readd)
|
||||
if (constr->is_no_inherit)
|
||||
return address;
|
||||
|
||||
/*
|
||||
@ -8209,7 +8206,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
||||
if (!list_member_oid(tab->changedConstraintOids,
|
||||
foundObject.objectId))
|
||||
{
|
||||
char *defstring = pg_get_constraintdef_string(foundObject.objectId);
|
||||
char *defstring = pg_get_constraintdef_command(foundObject.objectId);
|
||||
|
||||
/*
|
||||
* Put NORMAL dependencies at the front of the list and
|
||||
@ -8584,10 +8581,30 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
||||
def_item, tab->changedConstraintDefs)
|
||||
{
|
||||
Oid oldId = lfirst_oid(oid_item);
|
||||
HeapTuple tup;
|
||||
Form_pg_constraint con;
|
||||
Oid relid;
|
||||
Oid confrelid;
|
||||
bool conislocal;
|
||||
|
||||
tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for constraint %u", oldId);
|
||||
con = (Form_pg_constraint) GETSTRUCT(tup);
|
||||
relid = con->conrelid;
|
||||
confrelid = con->confrelid;
|
||||
conislocal = con->conislocal;
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
/*
|
||||
* If the constraint is inherited (only), we don't want to inject a
|
||||
* new definition here; it'll get recreated when ATAddCheckConstraint
|
||||
* recurses from adding the parent table's constraint. But we had to
|
||||
* carry the info this far so that we can drop the constraint below.
|
||||
*/
|
||||
if (!conislocal)
|
||||
continue;
|
||||
|
||||
get_constraint_relation_oids(oldId, &relid, &confrelid);
|
||||
ATPostAlterTypeParse(oldId, relid, confrelid,
|
||||
(char *) lfirst(def_item),
|
||||
wqueue, lockmode, tab->rewrite);
|
||||
@ -8761,7 +8778,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
|
||||
rel, con->conname);
|
||||
}
|
||||
else
|
||||
elog(ERROR, "unexpected statement type: %d",
|
||||
elog(ERROR, "unexpected statement subtype: %d",
|
||||
(int) cmd->subtype);
|
||||
}
|
||||
}
|
||||
@ -11272,9 +11289,9 @@ ATPrepChangePersistence(Relation rel, bool toLogged)
|
||||
if (foreignrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||
errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
|
||||
RelationGetRelationName(rel),
|
||||
RelationGetRelationName(foreignrel)),
|
||||
errmsg("could not change table \"%s\" to logged because it references unlogged table \"%s\"",
|
||||
RelationGetRelationName(rel),
|
||||
RelationGetRelationName(foreignrel)),
|
||||
errtableconstraint(rel, NameStr(con->conname))));
|
||||
}
|
||||
else
|
||||
@ -11282,9 +11299,9 @@ ATPrepChangePersistence(Relation rel, bool toLogged)
|
||||
if (foreignrel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||
errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
|
||||
RelationGetRelationName(rel),
|
||||
RelationGetRelationName(foreignrel)),
|
||||
errmsg("could not change table \"%s\" to unlogged because it references logged table \"%s\"",
|
||||
RelationGetRelationName(rel),
|
||||
RelationGetRelationName(foreignrel)),
|
||||
errtableconstraint(rel, NameStr(con->conname))));
|
||||
}
|
||||
|
||||
|
@ -433,6 +433,7 @@ static Node *processIndirection(Node *node, deparse_context *context,
|
||||
static void printSubscripts(ArrayRef *aref, deparse_context *context);
|
||||
static char *get_relation_name(Oid relid);
|
||||
static char *generate_relation_name(Oid relid, List *namespaces);
|
||||
static char *generate_qualified_relation_name(Oid relid);
|
||||
static char *generate_function_name(Oid funcid, int nargs,
|
||||
List *argnames, Oid *argtypes,
|
||||
bool has_variadic, bool *use_variadic_p,
|
||||
@ -1314,9 +1315,11 @@ pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
|
||||
prettyFlags)));
|
||||
}
|
||||
|
||||
/* Internal version that returns a palloc'd C string; no pretty-printing */
|
||||
/*
|
||||
* Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
|
||||
*/
|
||||
char *
|
||||
pg_get_constraintdef_string(Oid constraintId)
|
||||
pg_get_constraintdef_command(Oid constraintId)
|
||||
{
|
||||
return pg_get_constraintdef_worker(constraintId, true, 0);
|
||||
}
|
||||
@ -1363,10 +1366,16 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
|
||||
|
||||
initStringInfo(&buf);
|
||||
|
||||
if (fullCommand && OidIsValid(conForm->conrelid))
|
||||
if (fullCommand)
|
||||
{
|
||||
appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
|
||||
generate_relation_name(conForm->conrelid, NIL),
|
||||
/*
|
||||
* Currently, callers want ALTER TABLE (without ONLY) for CHECK
|
||||
* constraints, and other types of constraints don't inherit anyway so
|
||||
* it doesn't matter whether we say ONLY or not. Someday we might
|
||||
* need to let callers specify whether to put ONLY in the command.
|
||||
*/
|
||||
appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
|
||||
generate_qualified_relation_name(conForm->conrelid),
|
||||
quote_identifier(NameStr(conForm->conname)));
|
||||
}
|
||||
|
||||
@ -1890,28 +1899,9 @@ pg_get_serial_sequence(PG_FUNCTION_ARGS)
|
||||
|
||||
if (OidIsValid(sequenceId))
|
||||
{
|
||||
HeapTuple classtup;
|
||||
Form_pg_class classtuple;
|
||||
char *nspname;
|
||||
char *result;
|
||||
|
||||
/* Get the sequence's pg_class entry */
|
||||
classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(sequenceId));
|
||||
if (!HeapTupleIsValid(classtup))
|
||||
elog(ERROR, "cache lookup failed for relation %u", sequenceId);
|
||||
classtuple = (Form_pg_class) GETSTRUCT(classtup);
|
||||
|
||||
/* Get the namespace */
|
||||
nspname = get_namespace_name(classtuple->relnamespace);
|
||||
if (!nspname)
|
||||
elog(ERROR, "cache lookup failed for namespace %u",
|
||||
classtuple->relnamespace);
|
||||
|
||||
/* And construct the result string */
|
||||
result = quote_qualified_identifier(nspname,
|
||||
NameStr(classtuple->relname));
|
||||
|
||||
ReleaseSysCache(classtup);
|
||||
result = generate_qualified_relation_name(sequenceId);
|
||||
|
||||
PG_RETURN_TEXT_P(string_to_text(result));
|
||||
}
|
||||
@ -9577,6 +9567,39 @@ generate_relation_name(Oid relid, List *namespaces)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate_qualified_relation_name
|
||||
* Compute the name to display for a relation specified by OID
|
||||
*
|
||||
* As above, but unconditionally schema-qualify the name.
|
||||
*/
|
||||
static char *
|
||||
generate_qualified_relation_name(Oid relid)
|
||||
{
|
||||
HeapTuple tp;
|
||||
Form_pg_class reltup;
|
||||
char *relname;
|
||||
char *nspname;
|
||||
char *result;
|
||||
|
||||
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
||||
if (!HeapTupleIsValid(tp))
|
||||
elog(ERROR, "cache lookup failed for relation %u", relid);
|
||||
reltup = (Form_pg_class) GETSTRUCT(tp);
|
||||
relname = NameStr(reltup->relname);
|
||||
|
||||
nspname = get_namespace_name(reltup->relnamespace);
|
||||
if (!nspname)
|
||||
elog(ERROR, "cache lookup failed for namespace %u",
|
||||
reltup->relnamespace);
|
||||
|
||||
result = quote_qualified_identifier(nspname, relname);
|
||||
|
||||
ReleaseSysCache(tp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate_function_name
|
||||
* Compute the name to display for a function specified by OID,
|
||||
|
@ -247,7 +247,6 @@ extern char *ChooseConstraintName(const char *name1, const char *name2,
|
||||
|
||||
extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
|
||||
Oid newNspId, bool isType, ObjectAddresses *objsMoved);
|
||||
extern void get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid);
|
||||
extern Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok);
|
||||
extern Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok);
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
extern char *pg_get_indexdef_string(Oid indexrelid);
|
||||
extern char *pg_get_indexdef_columns(Oid indexrelid, bool pretty);
|
||||
|
||||
extern char *pg_get_constraintdef_string(Oid constraintId);
|
||||
extern char *pg_get_constraintdef_command(Oid constraintId);
|
||||
extern char *deparse_expression(Node *expr, List *dpcontext,
|
||||
bool forceprefix, bool showimplicit);
|
||||
extern List *deparse_context_for(const char *aliasname, Oid relid);
|
||||
|
@ -1810,16 +1810,125 @@ where oid = 'test_storage'::regclass;
|
||||
t
|
||||
(1 row)
|
||||
|
||||
-- ALTER TYPE with a check constraint and a child table (bug before Nov 2012)
|
||||
CREATE TABLE test_inh_check (a float check (a > 10.2));
|
||||
-- ALTER COLUMN TYPE with a check constraint and a child table (bug #13779)
|
||||
CREATE TABLE test_inh_check (a float check (a > 10.2), b float);
|
||||
CREATE TABLE test_inh_check_child() INHERITS(test_inh_check);
|
||||
\d test_inh_check
|
||||
Table "public.test_inh_check"
|
||||
Column | Type | Modifiers
|
||||
--------+------------------+-----------
|
||||
a | double precision |
|
||||
b | double precision |
|
||||
Check constraints:
|
||||
"test_inh_check_a_check" CHECK (a > 10.2::double precision)
|
||||
Number of child tables: 1 (Use \d+ to list them.)
|
||||
|
||||
\d test_inh_check_child
|
||||
Table "public.test_inh_check_child"
|
||||
Column | Type | Modifiers
|
||||
--------+------------------+-----------
|
||||
a | double precision |
|
||||
b | double precision |
|
||||
Check constraints:
|
||||
"test_inh_check_a_check" CHECK (a > 10.2::double precision)
|
||||
Inherits: test_inh_check
|
||||
|
||||
select relname, conname, coninhcount, conislocal, connoinherit
|
||||
from pg_constraint c, pg_class r
|
||||
where relname like 'test_inh_check%' and c.conrelid = r.oid
|
||||
order by 1, 2;
|
||||
relname | conname | coninhcount | conislocal | connoinherit
|
||||
----------------------+------------------------+-------------+------------+--------------
|
||||
test_inh_check | test_inh_check_a_check | 0 | t | f
|
||||
test_inh_check_child | test_inh_check_a_check | 1 | f | f
|
||||
(2 rows)
|
||||
|
||||
ALTER TABLE test_inh_check ALTER COLUMN a TYPE numeric;
|
||||
\d test_inh_check
|
||||
Table "public.test_inh_check"
|
||||
Column | Type | Modifiers
|
||||
--------+------------------+-----------
|
||||
a | numeric |
|
||||
b | double precision |
|
||||
Check constraints:
|
||||
"test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
|
||||
Number of child tables: 1 (Use \d+ to list them.)
|
||||
|
||||
\d test_inh_check_child
|
||||
Table "public.test_inh_check_child"
|
||||
Column | Type | Modifiers
|
||||
--------+------------------+-----------
|
||||
a | numeric |
|
||||
b | double precision |
|
||||
Check constraints:
|
||||
"test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
|
||||
Inherits: test_inh_check
|
||||
|
||||
select relname, conname, coninhcount, conislocal, connoinherit
|
||||
from pg_constraint c, pg_class r
|
||||
where relname like 'test_inh_check%' and c.conrelid = r.oid
|
||||
order by 1, 2;
|
||||
relname | conname | coninhcount | conislocal | connoinherit
|
||||
----------------------+------------------------+-------------+------------+--------------
|
||||
test_inh_check | test_inh_check_a_check | 0 | t | f
|
||||
test_inh_check_child | test_inh_check_a_check | 1 | f | f
|
||||
(2 rows)
|
||||
|
||||
-- also try noinherit, local, and local+inherited cases
|
||||
ALTER TABLE test_inh_check ADD CONSTRAINT bnoinherit CHECK (b > 100) NO INHERIT;
|
||||
ALTER TABLE test_inh_check_child ADD CONSTRAINT blocal CHECK (b < 1000);
|
||||
ALTER TABLE test_inh_check_child ADD CONSTRAINT bmerged CHECK (b > 1);
|
||||
ALTER TABLE test_inh_check ADD CONSTRAINT bmerged CHECK (b > 1);
|
||||
NOTICE: merging constraint "bmerged" with inherited definition
|
||||
\d test_inh_check
|
||||
Table "public.test_inh_check"
|
||||
Column | Type | Modifiers
|
||||
--------+------------------+-----------
|
||||
a | numeric |
|
||||
b | double precision |
|
||||
Check constraints:
|
||||
"bmerged" CHECK (b > 1::double precision)
|
||||
"bnoinherit" CHECK (b > 100::double precision) NO INHERIT
|
||||
"test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
|
||||
Number of child tables: 1 (Use \d+ to list them.)
|
||||
|
||||
\d test_inh_check_child
|
||||
Table "public.test_inh_check_child"
|
||||
Column | Type | Modifiers
|
||||
--------+------------------+-----------
|
||||
a | numeric |
|
||||
b | double precision |
|
||||
Check constraints:
|
||||
"blocal" CHECK (b < 1000::double precision)
|
||||
"bmerged" CHECK (b > 1::double precision)
|
||||
"test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
|
||||
Inherits: test_inh_check
|
||||
|
||||
select relname, conname, coninhcount, conislocal, connoinherit
|
||||
from pg_constraint c, pg_class r
|
||||
where relname like 'test_inh_check%' and c.conrelid = r.oid
|
||||
order by 1, 2;
|
||||
relname | conname | coninhcount | conislocal | connoinherit
|
||||
----------------------+------------------------+-------------+------------+--------------
|
||||
test_inh_check | bmerged | 0 | t | f
|
||||
test_inh_check | bnoinherit | 0 | t | t
|
||||
test_inh_check | test_inh_check_a_check | 0 | t | f
|
||||
test_inh_check_child | blocal | 0 | t | f
|
||||
test_inh_check_child | bmerged | 1 | t | f
|
||||
test_inh_check_child | test_inh_check_a_check | 1 | f | f
|
||||
(6 rows)
|
||||
|
||||
ALTER TABLE test_inh_check ALTER COLUMN b TYPE numeric;
|
||||
NOTICE: merging constraint "bmerged" with inherited definition
|
||||
\d test_inh_check
|
||||
Table "public.test_inh_check"
|
||||
Column | Type | Modifiers
|
||||
--------+---------+-----------
|
||||
a | numeric |
|
||||
b | numeric |
|
||||
Check constraints:
|
||||
"bmerged" CHECK (b::double precision > 1::double precision)
|
||||
"bnoinherit" CHECK (b::double precision > 100::double precision) NO INHERIT
|
||||
"test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
|
||||
Number of child tables: 1 (Use \d+ to list them.)
|
||||
|
||||
@ -1828,10 +1937,27 @@ Table "public.test_inh_check_child"
|
||||
Column | Type | Modifiers
|
||||
--------+---------+-----------
|
||||
a | numeric |
|
||||
b | numeric |
|
||||
Check constraints:
|
||||
"blocal" CHECK (b::double precision < 1000::double precision)
|
||||
"bmerged" CHECK (b::double precision > 1::double precision)
|
||||
"test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
|
||||
Inherits: test_inh_check
|
||||
|
||||
select relname, conname, coninhcount, conislocal, connoinherit
|
||||
from pg_constraint c, pg_class r
|
||||
where relname like 'test_inh_check%' and c.conrelid = r.oid
|
||||
order by 1, 2;
|
||||
relname | conname | coninhcount | conislocal | connoinherit
|
||||
----------------------+------------------------+-------------+------------+--------------
|
||||
test_inh_check | bmerged | 0 | t | f
|
||||
test_inh_check | bnoinherit | 0 | t | t
|
||||
test_inh_check | test_inh_check_a_check | 0 | t | f
|
||||
test_inh_check_child | blocal | 0 | t | f
|
||||
test_inh_check_child | bmerged | 1 | t | f
|
||||
test_inh_check_child | test_inh_check_a_check | 1 | f | f
|
||||
(6 rows)
|
||||
|
||||
-- check for rollback of ANALYZE corrupting table property flags (bug #11638)
|
||||
CREATE TABLE check_fk_presence_1 (id int PRIMARY KEY, t text);
|
||||
CREATE TABLE check_fk_presence_2 (id int REFERENCES check_fk_presence_1, t text);
|
||||
|
@ -1253,12 +1253,40 @@ select reltoastrelid <> 0 as has_toast_table
|
||||
from pg_class
|
||||
where oid = 'test_storage'::regclass;
|
||||
|
||||
-- ALTER TYPE with a check constraint and a child table (bug before Nov 2012)
|
||||
CREATE TABLE test_inh_check (a float check (a > 10.2));
|
||||
-- ALTER COLUMN TYPE with a check constraint and a child table (bug #13779)
|
||||
CREATE TABLE test_inh_check (a float check (a > 10.2), b float);
|
||||
CREATE TABLE test_inh_check_child() INHERITS(test_inh_check);
|
||||
\d test_inh_check
|
||||
\d test_inh_check_child
|
||||
select relname, conname, coninhcount, conislocal, connoinherit
|
||||
from pg_constraint c, pg_class r
|
||||
where relname like 'test_inh_check%' and c.conrelid = r.oid
|
||||
order by 1, 2;
|
||||
ALTER TABLE test_inh_check ALTER COLUMN a TYPE numeric;
|
||||
\d test_inh_check
|
||||
\d test_inh_check_child
|
||||
select relname, conname, coninhcount, conislocal, connoinherit
|
||||
from pg_constraint c, pg_class r
|
||||
where relname like 'test_inh_check%' and c.conrelid = r.oid
|
||||
order by 1, 2;
|
||||
-- also try noinherit, local, and local+inherited cases
|
||||
ALTER TABLE test_inh_check ADD CONSTRAINT bnoinherit CHECK (b > 100) NO INHERIT;
|
||||
ALTER TABLE test_inh_check_child ADD CONSTRAINT blocal CHECK (b < 1000);
|
||||
ALTER TABLE test_inh_check_child ADD CONSTRAINT bmerged CHECK (b > 1);
|
||||
ALTER TABLE test_inh_check ADD CONSTRAINT bmerged CHECK (b > 1);
|
||||
\d test_inh_check
|
||||
\d test_inh_check_child
|
||||
select relname, conname, coninhcount, conislocal, connoinherit
|
||||
from pg_constraint c, pg_class r
|
||||
where relname like 'test_inh_check%' and c.conrelid = r.oid
|
||||
order by 1, 2;
|
||||
ALTER TABLE test_inh_check ALTER COLUMN b TYPE numeric;
|
||||
\d test_inh_check
|
||||
\d test_inh_check_child
|
||||
select relname, conname, coninhcount, conislocal, connoinherit
|
||||
from pg_constraint c, pg_class r
|
||||
where relname like 'test_inh_check%' and c.conrelid = r.oid
|
||||
order by 1, 2;
|
||||
|
||||
-- check for rollback of ANALYZE corrupting table property flags (bug #11638)
|
||||
CREATE TABLE check_fk_presence_1 (id int PRIMARY KEY, t text);
|
||||
|
Loading…
Reference in New Issue
Block a user