diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-01-25 15:42:03 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-01-25 15:43:05 -0500 |
commit | 88452d5ba6b3e8ad49133ac1a660ce0725710f8c (patch) | |
tree | 75762e7ac491b55eff6357e4b432fddce4169ab2 /src/backend/commands/tablecmds.c | |
parent | 966d4f52c258aba8187d61fdc1e10b80d560f07c (diff) | |
download | postgresql-88452d5ba6b3e8ad49133ac1a660ce0725710f8c.tar.gz postgresql-88452d5ba6b3e8ad49133ac1a660ce0725710f8c.zip |
Implement ALTER TABLE ADD UNIQUE/PRIMARY KEY USING INDEX.
This feature allows a unique or pkey constraint to be created using an
already-existing unique index. While the constraint isn't very
functionally different from the bare index, it's nice to be able to do that
for documentation purposes. The main advantage over just issuing a plain
ALTER TABLE ADD UNIQUE/PRIMARY KEY is that the index can be created with
CREATE INDEX CONCURRENTLY, so that there is not a long interval where the
table is locked against updates.
On the way, refactor some of the code in DefineIndex() and index_create()
so that we don't have to pass through those functions in order to create
the index constraint's catalog entries. Also, in parse_utilcmd.c, pass
around the ParseState pointer in struct CreateStmtContext to save on
notation, and add error location pointers to some error reports that didn't
have one before.
Gurjeet Singh, reviewed by Steve Singer and Tom Lane
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index a9bb8351bc1..6726ca97331 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -319,6 +319,8 @@ static void ATExecAddIndex(AlteredTableInfo *tab, Relation rel, static void ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *newConstraint, bool recurse, LOCKMODE lockmode); +static void ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, + IndexStmt *stmt, LOCKMODE lockmode); static void ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, @@ -2594,6 +2596,7 @@ AlterTableGetLockLevel(List *cmds) case AT_DisableTrigAll: case AT_DisableTrigUser: case AT_AddIndex: /* from ADD CONSTRAINT */ + case AT_AddIndexConstraint: cmd_lockmode = ShareRowExclusiveLock; break; @@ -2811,6 +2814,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, cmd->subtype = AT_AddConstraintRecurse; pass = AT_PASS_ADD_CONSTR; break; + case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */ + ATSimplePermissions(rel, ATT_TABLE); + /* This command never recurses */ + /* No command-specific prep needed */ + pass = AT_PASS_ADD_CONSTR; + break; case AT_DropConstraint: /* DROP CONSTRAINT */ ATSimplePermissions(rel, ATT_TABLE); /* Recursion occurs during execution phase */ @@ -3042,6 +3051,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def, true, lockmode); break; + case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */ + ATExecAddIndexConstraint(tab, rel, (IndexStmt *) cmd->def, lockmode); + break; case AT_DropConstraint: /* DROP CONSTRAINT */ ATExecDropConstraint(rel, cmd->name, cmd->behavior, false, false, @@ -5010,6 +5022,76 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel, } /* + * ALTER TABLE ADD CONSTRAINT USING INDEX + */ +static void +ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, + IndexStmt *stmt, LOCKMODE lockmode) +{ + Oid index_oid = stmt->indexOid; + Relation indexRel; + char *indexName; + IndexInfo *indexInfo; + char *constraintName; + char constraintType; + + Assert(IsA(stmt, IndexStmt)); + Assert(OidIsValid(index_oid)); + Assert(stmt->isconstraint); + + indexRel = index_open(index_oid, AccessShareLock); + + indexName = pstrdup(RelationGetRelationName(indexRel)); + + indexInfo = BuildIndexInfo(indexRel); + + /* this should have been checked at parse time */ + if (!indexInfo->ii_Unique) + elog(ERROR, "index \"%s\" is not unique", indexName); + + /* + * Determine name to assign to constraint. We require a constraint to + * have the same name as the underlying index; therefore, use the index's + * existing name as the default constraint name, and if the user explicitly + * gives some other name for the constraint, rename the index to match. + */ + constraintName = stmt->idxname; + if (constraintName == NULL) + constraintName = indexName; + else if (strcmp(constraintName, indexName) != 0) + { + ereport(NOTICE, + (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"", + indexName, constraintName))); + RenameRelation(index_oid, constraintName, OBJECT_INDEX); + } + + /* Extra checks needed if making primary key */ + if (stmt->primary) + index_check_primary_key(rel, indexInfo, true); + + /* Note we currently don't support EXCLUSION constraints here */ + if (stmt->primary) + constraintType = CONSTRAINT_PRIMARY; + else + constraintType = CONSTRAINT_UNIQUE; + + /* Create the catalog entries for the constraint */ + index_constraint_create(rel, + index_oid, + indexInfo, + constraintName, + constraintType, + stmt->deferrable, + stmt->initdeferred, + stmt->primary, + true, + allowSystemTableMods); + + index_close(indexRel, NoLock); +} + +/* * ALTER TABLE ADD CONSTRAINT */ static void |