diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2012-11-05 13:36:16 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2012-11-05 13:36:16 -0500 |
commit | 5ed6546cf75623ba426942a3b71659a66cf7ed68 (patch) | |
tree | 2ee9770c6996159fdf12de5e4913e3d8b1c8d982 /src/backend/commands/tablecmds.c | |
parent | 4bb106ef4f6924312a67768571292c6f247122de (diff) | |
download | postgresql-5ed6546cf75623ba426942a3b71659a66cf7ed68.tar.gz postgresql-5ed6546cf75623ba426942a3b71659a66cf7ed68.zip |
Fix handling of inherited check constraints in ALTER COLUMN TYPE.
This case got broken in 8.4 by the addition of an error check that
complains if ALTER TABLE ONLY is used on a table that has children.
We do use ONLY for this situation, but it's okay because the necessary
recursion occurs at a higher level. So we need to have a separate
flag to suppress recursion without making the error check.
Reported and patched by Pavan Deolasee, with some editorial adjustments by
me. Back-patch to 8.4, since this is a regression of functionality that
worked in earlier branches.
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 1bd9bef3e72..f88bf793e57 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -335,13 +335,15 @@ static void ATExecAddIndex(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode); static void ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, - Constraint *newConstraint, bool recurse, LOCKMODE lockmode); + Constraint *newConstraint, bool recurse, bool is_readd, + LOCKMODE lockmode); static void ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode); static void ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, - bool recurse, bool recursing, LOCKMODE lockmode); + bool recurse, bool recursing, bool is_readd, + LOCKMODE lockmode); static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, LOCKMODE lockmode); static void ATExecDropConstraint(Relation rel, const char *constrName, @@ -2758,6 +2760,7 @@ AlterTableGetLockLevel(List *cmds) case AT_ColumnDefault: case AT_ProcessedConstraint: /* becomes AT_AddConstraint */ case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */ + case AT_ReAddConstraint: /* becomes AT_AddConstraint */ case AT_EnableTrig: case AT_EnableAlwaysTrig: case AT_EnableReplicaTrig: @@ -3249,11 +3252,15 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, break; case AT_AddConstraint: /* ADD CONSTRAINT */ ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def, - false, lockmode); + false, false, lockmode); break; case AT_AddConstraintRecurse: /* ADD CONSTRAINT with recursion */ ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def, - true, lockmode); + true, false, lockmode); + break; + case AT_ReAddConstraint: /* Re-add pre-existing check constraint */ + ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def, + false, true, lockmode); break; case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */ ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def, lockmode); @@ -5500,7 +5507,8 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, */ static void ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, - Constraint *newConstraint, bool recurse, LOCKMODE lockmode) + Constraint *newConstraint, bool recurse, bool is_readd, + LOCKMODE lockmode) { Assert(IsA(newConstraint, Constraint)); @@ -5513,7 +5521,8 @@ ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, { case CONSTR_CHECK: ATAddCheckConstraint(wqueue, tab, rel, - newConstraint, recurse, false, lockmode); + newConstraint, recurse, false, is_readd, + lockmode); break; case CONSTR_FOREIGN: @@ -5565,11 +5574,18 @@ 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 void ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, - LOCKMODE lockmode) + bool is_readd, LOCKMODE lockmode) { List *newcons; ListCell *lcon; @@ -5634,9 +5650,11 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, return; /* - * Adding a NO INHERIT constraint? No need to find our children + * 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) + if (constr->is_no_inherit || is_readd) return; /* @@ -5671,7 +5689,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, /* Recurse to child */ ATAddCheckConstraint(wqueue, childtab, childrel, - constr, recurse, true, lockmode); + constr, recurse, true, is_readd, lockmode); heap_close(childrel, NoLock); } @@ -7862,6 +7880,10 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, /* * Attach each generated command to the proper place in the work queue. * Note this could result in creation of entirely new work-queue entries. + * + * Also note that we have to tweak the command subtypes, because it turns + * out that re-creation of indexes and constraints has to act a bit + * differently from initial creation. */ foreach(list_item, querytree_list) { @@ -7919,6 +7941,7 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, if (con->contype == CONSTR_FOREIGN && !rewrite && !tab->rewrite) TryReuseForeignKey(oldId, con); + cmd->subtype = AT_ReAddConstraint; tab->subcmds[AT_PASS_OLD_CONSTR] = lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd); break; |