From 0df7717faa92ffc9d722495e2904767993b19d86 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 17 Jan 2008 18:56:54 +0000 Subject: [PATCH] Fix ALTER INDEX RENAME so that if the index belongs to a unique or primary key constraint, the constraint is renamed as well. This avoids inconsistent situations that could confuse pg_dump (not to mention humans). We might at some point provide ALTER TABLE RENAME CONSTRAINT as a more general solution, but there seems no reason not to allow doing it this way too. Per bug #3854 and related discussions. --- src/backend/catalog/pg_constraint.c | 64 ++++++++++++++++++++++++++++++++++++- src/backend/commands/tablecmds.c | 17 ++++++++-- src/include/catalog/pg_constraint.h | 3 +- 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index e62b3c8606..c25cfaab35 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.37 2008/01/01 19:45:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.38 2008/01/17 18:56:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -25,6 +25,7 @@ #include "utils/array.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/lsyscache.h" #include "utils/syscache.h" @@ -569,6 +570,67 @@ RemoveConstraintById(Oid conId) } /* + * RenameConstraintById + * Rename a constraint. + * + * Note: this isn't intended to be a user-exposed function; it doesn't check + * permissions etc. Currently this is only invoked when renaming an index + * that is associated with a constraint, but it's made a little more general + * than that with the expectation of someday having ALTER TABLE RENAME + * CONSTRAINT. + */ +void +RenameConstraintById(Oid conId, const char *newname) +{ + Relation conDesc; + HeapTuple tuple; + Form_pg_constraint con; + + conDesc = heap_open(ConstraintRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy(CONSTROID, + ObjectIdGetDatum(conId), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for constraint %u", conId); + con = (Form_pg_constraint) GETSTRUCT(tuple); + + /* + * We need to check whether the name is already in use --- note that + * there currently is not a unique index that would catch this. + */ + if (OidIsValid(con->conrelid) && + ConstraintNameIsUsed(CONSTRAINT_RELATION, + con->conrelid, + con->connamespace, + newname)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("constraint \"%s\" for relation \"%s\" already exists", + newname, get_rel_name(con->conrelid)))); + if (OidIsValid(con->contypid) && + ConstraintNameIsUsed(CONSTRAINT_DOMAIN, + con->contypid, + con->connamespace, + newname)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("constraint \"%s\" for domain \"%s\" already exists", + newname, format_type_be(con->contypid)))); + + /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ + namestrcpy(&(con->conname), newname); + + simple_heap_update(conDesc, &tuple->t_self, tuple); + + /* update the system catalog indexes */ + CatalogUpdateIndexes(conDesc, tuple); + + heap_freetuple(tuple); + heap_close(conDesc, RowExclusiveLock); +} + +/* * AlterConstraintNamespaces * Find any constraints belonging to the specified object, * and move them to the specified new namespace. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 301420c401..571990eef9 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.239 2008/01/02 23:34:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.240 2008/01/17 18:56:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1659,13 +1659,13 @@ renamerel(Oid myrelid, const char *newrelname, ObjectType reltype) * or ALTER INDEX is used to rename a sequence or view. */ relkind = targetrelation->rd_rel->relkind; - if (reltype == OBJECT_SEQUENCE && relkind != 'S') + if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a sequence", RelationGetRelationName(targetrelation)))); - if (reltype == OBJECT_VIEW && relkind != 'v') + if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a view", @@ -1712,6 +1712,17 @@ renamerel(Oid myrelid, const char *newrelname, ObjectType reltype) TypeRename(targetrelation->rd_rel->reltype, newrelname, namespaceId); /* + * Also rename the associated constraint, if any. + */ + if (relkind == RELKIND_INDEX) + { + Oid constraintId = get_index_constraint(myrelid); + + if (OidIsValid(constraintId)) + RenameConstraintById(constraintId, newrelname); + } + + /* * Close rel, but keep exclusive lock! */ relation_close(targetrelation, NoLock); diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index 3b01787a7e..4c0fd51d34 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.26 2008/01/01 19:45:56 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.27 2008/01/17 18:56:54 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -201,6 +201,7 @@ extern Oid CreateConstraintEntry(const char *constraintName, const char *conSrc); extern void RemoveConstraintById(Oid conId); +extern void RenameConstraintById(Oid conId, const char *newname); extern bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, Oid objNamespace, const char *conname); -- 2.11.0