Allow ALTER TABLE ... ALTER CONSTRAINT ... RENAME
authorBruce Momjian <bruce@momjian.us>
Sat, 11 Feb 2006 22:17:19 +0000 (22:17 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 11 Feb 2006 22:17:19 +0000 (22:17 +0000)
Joachim Wieland

12 files changed:
doc/src/sgml/ddl.sgml
doc/src/sgml/ref/alter_index.sgml
doc/src/sgml/ref/alter_table.sgml
src/backend/catalog/pg_constraint.c
src/backend/catalog/pg_depend.c
src/backend/commands/alter.c
src/backend/parser/gram.y
src/backend/tcop/utility.c
src/include/catalog/dependency.h
src/include/catalog/pg_constraint.h
src/test/regress/expected/alter_table.out
src/test/regress/sql/alter_table.sql

index 2342f8703caf83a8da160ade2d928da01503e1ab..f7e6671e606e80212c3e8b3309e73387069768a7 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.52 2006/02/04 23:03:19 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.53 2006/02/11 22:17:18 momjian Exp $ -->
 
 <chapter id="ddl">
  <title>Data Definition</title>
@@ -543,6 +543,10 @@ CREATE TABLE products (
     price numeric
 );
 </programlisting>
+   Since <productname>PostgreSQL</productname> implements a UNIQUE constraint by
+   means of an index, the above command will also create an index with the same
+   name as the constraint. If you later on change the name of one of those, the
+   name of the corresponding object will be changed automatically as well.
    </para>
 
    <indexterm>
index c212fd09f93f59b214522f1ef9de2f573dc834d0..b2df948d64cbabd568d3c2bc4c8c271d10dfafeb 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_index.sgml,v 1.6 2005/08/22 19:39:52 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_index.sgml,v 1.7 2006/02/11 22:17:18 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -107,6 +107,15 @@ ALTER INDEX <replaceable class="PARAMETER">name</replaceable> SET TABLESPACE <re
     of <command>ALTER TABLE</> that apply to indexes.
    </para>
 
+   <para>
+    Indexes are also used internally by constraints, namely by UNIQUE and
+    PRIMARY KEY constraints. If you rename an index that is used internally by
+    a constraint of that type, this constraint will implicitly be renamed as
+    well. On the other hand, if you rename such a constraint, it will
+    implicitly rename its corresponding index such that both objects always
+    have the same name.
+   </para>
+
    <para>
     There was formerly an <command>ALTER INDEX OWNER</> variant, but
     this is now ignored (with a warning).  An index cannot have an owner
index 58a4876f332c2c28d8abdec2a74353002b94f72f..9061fb4e2dfdd3aaf471708efba41fcb8b030c60 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.82 2005/12/08 21:35:36 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.83 2006/02/11 22:17:18 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -24,6 +24,8 @@ ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [ * ]
     <replaceable class="PARAMETER">action</replaceable> [, ... ]
 ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [ * ]
     RENAME [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> TO <replaceable class="PARAMETER">new_column</replaceable>
+ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [ * ]
+    ALTER CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> RENAME TO <replaceable class="PARAMETER">new_constraint_name</replaceable>
 ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
     RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
 ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
@@ -169,6 +171,18 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><literal>ALTER CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> RENAME TO <replaceable class="PARAMETER">new_constraint_name</replaceable></literal></term>
+    <listitem>
+     <para>
+      This form renames a constraint that is defined on the table. Note that if
+      a constraint is using an index internally (<literal>UNIQUE</> or
+      <literal>PRIMARY KEY</> constraints), the corresponding index will be
+      renamed as well.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><literal>ADD <replaceable class="PARAMETER">table_constraint</replaceable></literal></term>
     <listitem>
index 60013c4d27acc4ac5bb59721b8378710d6ad32c0..6e89d6832c2c74ea0d9e7ae4ddb86c6b9336dd2b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.28 2005/11/22 18:17:08 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.29 2006/02/11 22:17:18 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -664,3 +664,191 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 
    heap_close(conRel, RowExclusiveLock);
 }
+
+
+/*
+ * RenameConstraint
+ *     Rename a single constraint record
+ *     conId: The OID of the constraint to rename
+ *     newName: The new name of the constraint
+ *     implicitRename: is this an implicit rename? If so, we will issue
+ *                     a notice about the implicit rename
+ *     cmdName: the command that triggered the rename for the "implicitly
+ *              renames" notice message
+ */
+void
+RenameConstraint(Oid conId, const char* newName,
+                bool implicitRename, const char* cmdName)
+{
+   Relation            conRel;
+   ScanKeyData         key[1];
+   SysScanDesc         scan;
+   HeapTuple           tup;
+   NameData            newNameData;
+   Relation            rel;
+   Oid                 relId;
+   Oid                 nspOid;
+   Form_pg_constraint  conform;
+
+   /* before reading the tuple, lock the table it constraints in
+    * AccessExclusiveLock mode. Otherwise, if we read it before locking this
+    * table, the tuple might be changed by another transaction and our copy
+    * would be out of date
+    */
+   relId = GetConstraintRelationId(conId);
+   if (!OidIsValid(relId))
+   {
+       ereport(ERROR,
+               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                errmsg("constraint with OID %d does not exist", conId)));
+   }
+
+   rel = relation_open(relId, AccessExclusiveLock);
+   nspOid = get_rel_namespace(relId);
+
+   conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
+
+   ScanKeyInit(&key[0],
+               ObjectIdAttributeNumber,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(conId));
+
+   scan = systable_beginscan(conRel, ConstraintOidIndexId, true,
+                             SnapshotNow, 1, key);
+   if (!HeapTupleIsValid((tup = systable_getnext(scan))))
+   {
+       ereport(ERROR,
+               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                errmsg("constraint with OID %d does not exist", conId)));
+   }
+
+   conform = (Form_pg_constraint) GETSTRUCT(tup);
+
+   if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
+                            conform->conrelid,
+                            get_rel_namespace(conform->conrelid),
+                            newName))
+   {
+       ereport(ERROR,
+               (errcode(ERRCODE_DUPLICATE_OBJECT),
+                errmsg("constraint \"%s\" for relation \"%s\" already exists",
+                       newName,
+                       RelationGetRelationName(rel))));
+   }
+   tup = heap_copytuple(tup);
+   conform = (Form_pg_constraint) GETSTRUCT(tup);
+
+   if (implicitRename && cmdName)
+   {
+       ereport(NOTICE,
+               (errmsg("%s will implicitly rename constraint "
+                       "\"%s\" to \"%s\" on table \"%s.%s\"",
+                   cmdName,
+                   NameStr(conform->conname),
+                   newName,
+                   get_namespace_name(nspOid),
+                   RelationGetRelationName(rel))));
+   }
+
+   namestrcpy(&newNameData, newName);
+   conform->conname = newNameData;
+
+   simple_heap_update(conRel, &tup->t_self, tup);
+   CatalogUpdateIndexes(conRel, tup);
+   heap_freetuple(tup);
+
+   systable_endscan(scan);
+   heap_close(conRel, RowExclusiveLock);
+
+   /* close relation but hold lock until end of transaction */
+   relation_close(rel, NoLock);
+}
+
+
+/* GetRelationConstraintOid
+ *
+ * Get the contraint OID by the relation Id of the relation it constraints and
+ * this relations' name. We need this function in order to rename a constraint.
+ * This is done via "ALTER TABLE ... ALTER CONSTRAINT name" and the parser
+ * gives us the relation this constraint is defined on as well as the
+ * constraint's name.
+ *
+ * The function returns:
+ *
+ *  - the unique OID of the constraint if the constraint could be found
+ *  - the invalid OID if the constraint was not found
+ *
+ */
+Oid GetRelationConstraintOid(Oid relId, const char* name)
+{
+   Relation        conRel;
+   ScanKeyData     key[1];
+   SysScanDesc     scan;
+   HeapTuple       tup;
+   Oid             conId = InvalidOid;
+
+   /* we don't change data, so an AccessShareLock is enough */
+   conRel = heap_open(ConstraintRelationId, AccessShareLock);
+
+   ScanKeyInit(&key[0],
+               Anum_pg_constraint_conrelid,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(relId));
+
+   scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
+                             SnapshotNow, 1, key);
+
+   while (HeapTupleIsValid((tup = systable_getnext(scan))))
+   {
+       Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
+       if (pg_strcasecmp(name, NameStr(con->conname)) == 0)
+       {
+           conId = HeapTupleGetOid(tup);
+           Assert(OidIsValid(conId));
+       }
+   }
+
+   systable_endscan(scan);
+   heap_close(conRel, AccessShareLock);
+
+   return conId;
+}
+
+
+/* GetConstraintRelationId
+ *
+ * Gets the OID of the relation where the constraint is defined on or the
+ * invalid OID if the constraint cannot be found.
+ */
+Oid GetConstraintRelationId(Oid conId)
+{
+   Relation        conRel;
+   ScanKeyData     key[1];
+   SysScanDesc     scan;
+   HeapTuple       tup;
+   Oid             relId = InvalidOid;
+
+   /* we don't change data, so an AccessShareLock is enough */
+   conRel = heap_open(ConstraintRelationId, AccessShareLock);
+
+   ScanKeyInit(&key[0],
+               ObjectIdAttributeNumber,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(conId));
+
+   scan = systable_beginscan(conRel, ConstraintOidIndexId, true,
+                             SnapshotNow, 1, key);
+
+   if (HeapTupleIsValid((tup = systable_getnext(scan))))
+   {
+       Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
+       relId = con->conrelid;
+       Assert(OidIsValid(relId));
+   }
+
+   systable_endscan(scan);
+   heap_close(conRel, AccessShareLock);
+
+   return relId;
+}
+
index 28118ecc38e4bfdeeebf6268fb9f4d73cceb1274..0915ef5c827961d1bba9084ef3aa69b195c721cb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.17 2005/11/22 18:17:08 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.18 2006/02/11 22:17:18 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -361,3 +361,102 @@ isObjectPinned(const ObjectAddress *object, Relation rel)
 
    return ret;
 }
+
+List* getReferencingOids(Oid refClassId, Oid refObjId, Oid refObjSubId,
+                        Oid classId, DependencyType deptype)
+{
+   ScanKeyData     key[3];
+   SysScanDesc     scan;
+   HeapTuple       tup;
+   Relation        depRel;
+   List           *list = NIL;
+
+   depRel = heap_open(DependRelationId, AccessShareLock);
+
+   ScanKeyInit(&key[0],
+               Anum_pg_depend_refclassid,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(refClassId));
+
+   ScanKeyInit(&key[1],
+               Anum_pg_depend_refobjid,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(refObjId));
+
+   ScanKeyInit(&key[2],
+               Anum_pg_depend_refobjsubid,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(refObjSubId));
+
+   scan = systable_beginscan(depRel, DependReferenceIndexId, true,
+                             SnapshotNow, 3, key);
+
+   while (HeapTupleIsValid(tup = systable_getnext(scan)))
+   {
+       Form_pg_depend  depForm = (Form_pg_depend) GETSTRUCT(tup);
+
+       /* check if the class id is what we want */
+       if (depForm->classid != classId)
+           continue;
+
+       /* check if the DependencyType is what we want */
+       if (depForm->deptype != deptype)
+           continue;
+
+       /* if we are still here, we have found a match */
+       list = lcons_oid(depForm->objid, list);
+       break;
+   }
+   systable_endscan(scan);
+
+   heap_close(depRel, AccessShareLock);
+   return list;
+}
+
+
+List* getDependentOids(Oid classId, Oid objId,
+                      Oid refClassId, DependencyType deptype)
+{
+   ScanKeyData     key[2];
+   SysScanDesc     scan;
+   HeapTuple       tup;
+   Relation        depRel;
+   List           *list = NIL;
+
+   depRel = heap_open(DependRelationId, AccessShareLock);
+
+   ScanKeyInit(&key[0],
+               Anum_pg_depend_classid,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(classId));
+
+   ScanKeyInit(&key[1],
+               Anum_pg_depend_objid,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(objId));
+
+   scan = systable_beginscan(depRel, DependDependerIndexId, true,
+                             SnapshotNow, 2, key);
+
+   while (HeapTupleIsValid(tup = systable_getnext(scan)))
+   {
+       Form_pg_depend  depForm = (Form_pg_depend) GETSTRUCT(tup);
+
+       /* check if the DependencyType is what we want */
+       if (depForm->deptype != deptype)
+           continue;
+
+       /* check if the referenced class id is what we want */
+       if (depForm->refclassid != refClassId)
+           continue;
+
+       /* if we are still here, we have found a match */
+       list = lcons_oid(depForm->refobjid, list);
+       break;
+   }
+   systable_endscan(scan);
+
+   heap_close(depRel, AccessShareLock);
+   return list;
+}
+
index 102dafb8a2a60bfb581b381e28113a4d4b8608e5..1a120a93882b9f04551091169d6bad699ae83261 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.15 2005/10/15 02:49:14 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.16 2006/02/11 22:17:18 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "access/htup.h"
 #include "catalog/catalog.h"
+#include "catalog/dependency.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_class.h"
+#include "catalog/pg_constraint.h"
 #include "commands/alter.h"
 #include "commands/conversioncmds.h"
 #include "commands/dbcommands.h"
@@ -88,6 +90,7 @@ ExecRenameStmt(RenameStmt *stmt)
        case OBJECT_INDEX:
        case OBJECT_COLUMN:
        case OBJECT_TRIGGER:
+       case OBJECT_CONSTRAINT:
            {
                Oid         relid;
 
@@ -109,12 +112,38 @@ ExecRenameStmt(RenameStmt *stmt)
                            AclResult   aclresult;
 
                            aclresult = pg_namespace_aclcheck(namespaceId,
-                                                             GetUserId(),
-                                                             ACL_CREATE);
+                                                   GetUserId(), ACL_CREATE);
                            if (aclresult != ACLCHECK_OK)
                                aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                                            get_namespace_name(namespaceId));
 
+                           /*
+                            *  Do NOT refer to stmt->renameType here because
+                            *  you can also rename an index with ALTER TABLE
+                            */
+                           if (get_rel_relkind(relid) == RELKIND_INDEX)
+                           {
+                               /* see if we depend on a constraint */
+                               List* depOids = getDependentOids(
+                                               RelationRelationId, relid,
+                                               ConstraintRelationId,
+                                               DEPENDENCY_INTERNAL);
+
+                               /* there should only be one constraint */
+                               Assert(list_length(depOids) <= 1);
+                               if (list_length(depOids) == 1)
+                               {
+                                       Oid conRelId = linitial_oid(depOids);
+                                       /*
+                                        *  Apply the same name to the
+                                        *  constraint and tell it that this
+                                        *  is an implicit rename triggered
+                                        *  by an "ALTER INDEX" command.
+                                        */
+                                       RenameConstraint(conRelId,
+                                           stmt->newname, true, "ALTER INDEX");
+                               }
+                           }
                            renamerel(relid, stmt->newname);
                            break;
                        }
@@ -130,6 +159,52 @@ ExecRenameStmt(RenameStmt *stmt)
                                   stmt->subname,       /* old att name */
                                   stmt->newname);      /* new att name */
                        break;
+                   case OBJECT_CONSTRAINT:
+                       /* XXX could do extra function renameconstr() - but I
+                        * don't know where it should go */
+                       /* renameconstr(relid,
+                                    stmt->subname,
+                                    stmt->newname); */
+                       {
+                           List        *depRelOids;
+                           ListCell    *l;
+                           Oid conId =
+                                   GetRelationConstraintOid(relid,
+                                                            stmt->subname);
+                           if (!OidIsValid(conId)) {
+                               ereport(ERROR,
+                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                        errmsg("constraint with name \"%s\" "
+                                               "does not exist",
+                                               stmt->subname)));
+                           }
+                           RenameConstraint(conId, stmt->newname,
+                                            false, NULL);
+                           depRelOids = getReferencingOids(
+                                           ConstraintRelationId, conId, 0,
+                                           RelationRelationId,
+                                           DEPENDENCY_INTERNAL);
+                           foreach(l, depRelOids)
+                           {
+                               Oid     depRelOid;
+                               Oid     nspOid;
+                               depRelOid = lfirst_oid(l);
+                               nspOid = get_rel_namespace(depRelOid);
+                               if (get_rel_relkind(depRelOid) == RELKIND_INDEX)
+                               {
+                                   ereport(NOTICE,
+                                           (errmsg("ALTER TABLE / CONSTRAINT will implicitly rename index "
+                                                   "\"%s\" to \"%s\" on table \"%s.%s\"",
+                                               get_rel_name(depRelOid),
+                                               stmt->newname,
+                                               get_namespace_name(nspOid),
+                                               get_rel_name(relid))));
+                                   renamerel(depRelOid, stmt->newname);
+                               }
+                           }
+                       }
+                       break;
+
                    default:
                         /* can't happen */ ;
                }
index 8c21c421587c3c0e7c19b041ab076c2b2dd1cee9..19270bcbda6d4e4674490f7a5e6dc764b37d81bd 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.526 2006/02/04 19:06:46 adunstan Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.527 2006/02/11 22:17:18 momjian Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -4096,6 +4096,15 @@ RenameStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' RENAME TO name
                    n->newname = $8;
                    $$ = (Node *)n;
                }
+           | ALTER TABLE relation_expr ALTER CONSTRAINT name RENAME TO name
+               {
+                   RenameStmt *n = makeNode(RenameStmt);
+                   n->renameType = OBJECT_CONSTRAINT;
+                   n->relation = $3;
+                   n->subname = $6;
+                   n->newname = $9;
+                   $$ = (Node *)n;
+               }
            | ALTER TRIGGER name ON relation_expr RENAME TO name
                {
                    RenameStmt *n = makeNode(RenameStmt);
index 85b81fd14b53f3fbda01b19508c72b00247d3b18..05c943f38bb1672d3d33a868c2ee0f5cf4f5ef5f 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.250 2005/11/29 01:25:49 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.251 2006/02/11 22:17:19 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1406,6 +1406,7 @@ CreateCommandTag(Node *parsetree)
                case OBJECT_SCHEMA:
                    tag = "ALTER SCHEMA";
                    break;
+               case OBJECT_CONSTRAINT:
                case OBJECT_COLUMN:
                case OBJECT_TABLE:
                    tag = "ALTER TABLE";
index c91406390b015f96fecdc1a551856e967320d6ce..c78556f9e8dc5995043ac143aa899bdee2f225c8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.18 2005/11/21 12:49:32 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.19 2006/02/11 22:17:19 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -179,6 +179,12 @@ extern long changeDependencyFor(Oid classId, Oid objectId,
 
 extern bool objectIsInternalDependency(Oid classId, Oid objectId);
 
+extern List* getDependentOids(Oid classId, Oid objId,
+                             Oid refClassId, DependencyType deptype);
+
+extern List* getReferencingOids(Oid refClassId, Oid refObjId, Oid refObjSubId,
+                               Oid classId, DependencyType deptype);
+
 /* in pg_shdepend.c */
 
 extern void recordSharedDependencyOn(ObjectAddress *depender,
index e87dd88b6a255c7e489c83ff724b1e97dfa0a833..6f1312e46bbffe55b28167d677850a3bfd6313f8 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.19 2005/11/22 18:17:30 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.20 2006/02/11 22:17:19 momjian Exp $
  *
  * NOTES
  *   the genbki.sh script reads this file and generates .bki
@@ -187,4 +187,10 @@ extern char *GetConstraintNameForTrigger(Oid triggerId);
 extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
                          Oid newNspId, bool isType);
 
+extern void RenameConstraint(Oid conId, const char* newName,
+                            bool implicitRename, const char* cmdName);
+
+extern Oid GetRelationConstraintOid(Oid relId, const char* name);
+extern Oid GetConstraintRelationId(Oid conId);
+
 #endif   /* PG_CONSTRAINT_H */
index 02723d62ecc7153ac411cc5a5c0841309e44dc66..ae05d4a68628ad294f74a65298ee34b1762eb500 100644 (file)
@@ -159,6 +159,10 @@ CREATE TABLE tmp3 (a int, b int);
 CREATE TABLE tmp4 (a int, b int, unique(a,b));
 NOTICE:  CREATE TABLE / UNIQUE will create implicit index "tmp4_a_key" for table "tmp4"
 CREATE TABLE tmp5 (a int, b int);
+-- creates implicit index tmp6_a_key
+CREATE TABLE tmp6 (a int, b int, unique(a));
+NOTICE:  CREATE TABLE / UNIQUE will create implicit index "tmp6_a_key" for table "tmp6"
+CREATE INDEX tmp6_b_key ON tmp6(b);
 -- Insert rows into tmp2 (pktable)
 INSERT INTO tmp2 values (1);
 INSERT INTO tmp2 values (2);
@@ -186,6 +190,22 @@ ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match
 -- tmp4 is a,b
 ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full;
 ERROR:  there is no unique constraint matching given keys for referenced table "tmp4"
+-- check if constraint and index name stay in sync if we rename one or the other
+-- fail here
+ALTER TABLE tmp6 ALTER CONSTRAINT tmp6_a_key RENAME TO tmp6_b_key;
+NOTICE:  ALTER TABLE / CONSTRAINT will implicitly rename index "tmp6_a_key" to "tmp6_b_key" on table "public.tmp6"
+ERROR:  relation "tmp6_b_key" already exists
+-- succeed
+ALTER TABLE tmp6 ALTER CONSTRAINT tmp6_a_key RENAME TO tmp6_c_key;
+NOTICE:  ALTER TABLE / CONSTRAINT will implicitly rename index "tmp6_a_key" to "tmp6_c_key" on table "public.tmp6"
+-- Now rename the index (this fails)
+ALTER INDEX tmp6_c_key RENAME TO tmp6_b_key;
+NOTICE:  ALTER INDEX will implicitly rename constraint "tmp6_c_key" to "tmp6_b_key" on table "public.tmp6"
+ERROR:  relation "tmp6_b_key" already exists
+-- this succeeds and uses ALTER TABLE syntax to rename an INDEX
+ALTER TABLE tmp6_c_key RENAME TO tmp6_a_key;
+NOTICE:  ALTER INDEX will implicitly rename constraint "tmp6_c_key" to "tmp6_a_key" on table "public.tmp6"
+DROP TABLE tmp6;
 DROP TABLE tmp5;
 DROP TABLE tmp4;
 DROP TABLE tmp3;
index 8690f61dbedae317c49b4767ff8d27aeb2c817cf..b0400051c0b9abe162c11c158f659be223c02f06 100644 (file)
@@ -196,6 +196,10 @@ CREATE TABLE tmp4 (a int, b int, unique(a,b));
 
 CREATE TABLE tmp5 (a int, b int);
 
+-- creates implicit index tmp6_a_key
+CREATE TABLE tmp6 (a int, b int, unique(a));
+CREATE INDEX tmp6_b_key ON tmp6(b);
+
 -- Insert rows into tmp2 (pktable)
 INSERT INTO tmp2 values (1);
 INSERT INTO tmp2 values (2);
@@ -227,6 +231,21 @@ ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match
 
 ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full;
 
+-- check if constraint and index name stay in sync if we rename one or the other
+-- fail here
+ALTER TABLE tmp6 ALTER CONSTRAINT tmp6_a_key RENAME TO tmp6_b_key;
+
+-- succeed
+ALTER TABLE tmp6 ALTER CONSTRAINT tmp6_a_key RENAME TO tmp6_c_key;
+
+-- Now rename the index (this fails)
+ALTER INDEX tmp6_c_key RENAME TO tmp6_b_key;
+
+-- this succeeds and uses ALTER TABLE syntax to rename an INDEX
+ALTER TABLE tmp6_c_key RENAME TO tmp6_a_key;
+
+DROP TABLE tmp6;
+
 DROP TABLE tmp5;
 
 DROP TABLE tmp4;