From 0df7717faa92ffc9d722495e2904767993b19d86 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
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 e62b3c86066..c25cfaab35b 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"
 
 
@@ -568,6 +569,67 @@ RemoveConstraintById(Oid conId)
 	heap_close(conDesc, RowExclusiveLock);
 }
 
+/*
+ * 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,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 301420c401d..571990eef9b 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",
@@ -1711,6 +1711,17 @@ renamerel(Oid myrelid, const char *newrelname, ObjectType reltype)
 	if (OidIsValid(targetrelation->rd_rel->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!
 	 */
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 3b01787a7ef..4c0fd51d346 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);
-- 
GitLab