Thread: ALTER TYPE RENAME

ALTER TYPE RENAME

From
Petr Jelinek
Date:
Hi,
I noticed we don't have ALTER TYPE foo RENAME TO bar command which would
be handy for me especially for enum types.
So I wrote this little patch (including very brief doc) which adds above
syntax. It basically just does some checks and calls existing TypeRename
function which is used for renaming table rowtype now.
I hope I haven't missed anything, but I am unsure about two things.
First, this patch allows renaming base types which I don't know if it's
desired. And second we might want to throw error when renaming rowtype
(there is check in AlterTypeOwner for this but not in AlterTypeNamespace
so I don't know).

--
Regards
Petr Jelinek (PJMODOS)

Index: doc/src/sgml/ref/alter_type.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/alter_type.sgml,v
retrieving revision 1.4
diff -c -r1.4 alter_type.sgml
*** doc/src/sgml/ref/alter_type.sgml    16 Sep 2006 00:30:16 -0000    1.4
--- doc/src/sgml/ref/alter_type.sgml    29 Sep 2007 05:43:14 -0000
***************
*** 26,31 ****
--- 26,32 ----
    <synopsis>
  ALTER TYPE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable
class="PARAMETER">new_owner</replaceable> 
  ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable
class="PARAMETER">new_schema</replaceable>
+ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable
class="PARAMETER">new_name</replaceable>
    </synopsis>
   </refsynopsisdiv>

***************
*** 83,88 ****
--- 84,98 ----
        </listitem>
       </varlistentry>

+      <varlistentry>
+       <term><replaceable class="PARAMETER">new_name</replaceable></term>
+       <listitem>
+        <para>
+         The new name for the type.
+        </para>
+       </listitem>
+      </varlistentry>
+
      </variablelist>
     </para>
    </refsect1>
Index: src/backend/commands/alter.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/alter.c,v
retrieving revision 1.25
diff -c -r1.25 alter.c
*** src/backend/commands/alter.c    21 Aug 2007 01:11:14 -0000    1.25
--- src/backend/commands/alter.c    29 Sep 2007 05:12:31 -0000
***************
*** 154,159 ****
--- 154,164 ----
              RenameTSConfiguration(stmt->object, stmt->newname);
              break;

+         case OBJECT_TYPE:
+         case OBJECT_DOMAIN:
+             RenameType(stmt->object, stmt->newname);
+             break;
+
          default:
              elog(ERROR, "unrecognized rename stmt type: %d",
                   (int) stmt->renameType);
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.107
diff -c -r1.107 typecmds.c
*** src/backend/commands/typecmds.c    4 Sep 2007 16:41:42 -0000    1.107
--- src/backend/commands/typecmds.c    29 Sep 2007 05:11:22 -0000
***************
*** 2514,2519 ****
--- 2514,2567 ----
  }

  /*
+  * Execute ALTER TYPE RENAME
+  */
+ void
+ RenameType(List *names, const char *newTypeName)
+ {
+     TypeName   *typename;
+     Oid            typeOid;
+     Relation    rel;
+     HeapTuple    tup;
+     Form_pg_type typTup;
+
+     /* Make a TypeName so we can use standard type lookup machinery */
+     typename = makeTypeNameFromNameList(names);
+     typeOid = typenameTypeId(NULL, typename);
+
+     /* Look up the type in the type table */
+     rel = heap_open(TypeRelationId, RowExclusiveLock);
+
+     tup = SearchSysCacheCopy(TYPEOID,
+                              ObjectIdGetDatum(typeOid),
+                              0, 0, 0);
+     if (!HeapTupleIsValid(tup))
+         elog(ERROR, "cache lookup failed for type %u", typeOid);
+     typTup = (Form_pg_type) GETSTRUCT(tup);
+
+     /* check permissions on type */
+     if (!pg_type_ownercheck(typeOid, GetUserId()))
+         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
+                        format_type_be(typeOid));
+
+     /* don't allow direct alteration of array types */
+     if (OidIsValid(typTup->typelem) &&
+         get_array_type(typTup->typelem) == typeOid)
+         ereport(ERROR,
+                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                  errmsg("cannot alter array type %s",
+                         format_type_be(typeOid)),
+                  errhint("You can alter type %s, which will alter the array type as well.",
+                          format_type_be(typTup->typelem))));
+
+     /* and do the work */
+     TypeRename(typeOid, newTypeName, typTup->typnamespace);
+
+     /* Clean up */
+     heap_close(rel, RowExclusiveLock);
+ }
+
+ /*
   * Move specified type to new namespace.
   *
   * Caller must have already checked privileges.
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.603
diff -c -r2.603 gram.y
*** src/backend/parser/gram.y    24 Sep 2007 01:29:28 -0000    2.603
--- src/backend/parser/gram.y    29 Sep 2007 05:13:21 -0000
***************
*** 4748,4753 ****
--- 4748,4761 ----
                      n->newname = $8;
                      $$ = (Node *)n;
                  }
+             | ALTER TYPE_P any_name RENAME TO name
+                 {
+                     RenameStmt *n = makeNode(RenameStmt);
+                     n->renameType = OBJECT_TYPE;
+                     n->object = $3;
+                     n->newname = $6;
+                     $$ = (Node *)n;
+                 }
          ;

  opt_column: COLUMN                                    { $$ = COLUMN; }
Index: src/include/commands/typecmds.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/typecmds.h,v
retrieving revision 1.19
diff -c -r1.19 typecmds.h
*** src/include/commands/typecmds.h    11 May 2007 17:57:14 -0000    1.19
--- src/include/commands/typecmds.h    29 Sep 2007 05:11:57 -0000
***************
*** 43,46 ****
--- 43,48 ----
                                         bool isImplicitArray,
                                         bool errorOnTableType);

+ extern void RenameType(List *names, const char *newTypeName);
+
  #endif   /* TYPECMDS_H */

Re: ALTER TYPE RENAME

From
Tom Lane
Date:
Petr Jelinek <pjmodos@pjmodos.net> writes:
> I noticed we don't have ALTER TYPE foo RENAME TO bar command which would
> be handy for me especially for enum types.
> So I wrote this little patch (including very brief doc) which adds above
> syntax. It basically just does some checks and calls existing TypeRename
> function which is used for renaming table rowtype now.
> I hope I haven't missed anything, but I am unsure about two things.
> First, this patch allows renaming base types which I don't know if it's
> desired. And second we might want to throw error when renaming rowtype
> (there is check in AlterTypeOwner for this but not in AlterTypeNamespace
> so I don't know).

Hm, it's definitely a bug/oversight that AlterTypeNamespace doesn't make
a similar test for that.  I think you should have to use ALTER TABLE to
muck with a table's rowtype.  Your patch as proposed would allow people
to get into a state where a table's rowtype is named differently than
the table, which is a horrid idea.  (For one thing, a dump/restore would
fail to preserve such a state.)

As for the patch at hand, I think it's very poor style to have functions
named both RenameType and TypeRename, with no obvious indication of
which does what.  The newly added function should be RenameType, since
that parallels the other callees of ExecRenameStmt, but I'd be inclined
to rename the existing function to RenameTypeInternal, as contemplated
in its header comment.  (BTW, your patch omits to fix its header
comment, which is rendered an outright lie by the patch.)

            regards, tom lane

Re: ALTER TYPE RENAME

From
Tom Lane
Date:
I wrote:
> Hm, it's definitely a bug/oversight that AlterTypeNamespace doesn't make
> a similar test for that.

On closer look, there *is* such a test, but it's down inside
AlterTypeNamespaceInternal.

            regards, tom lane

Re: ALTER TYPE RENAME

From
Tom Lane
Date:
BTW, another issue this brings up is whether we should reject

regression=# create type footyp as (f2 int);
CREATE TYPE
regression=# alter table footyp rename to foobar;
ALTER TABLE

Currently, since there's no ALTER TYPE RENAME command, this is useful
functionality and I wouldn't want to forbid it.  But if we provide
ALTER TYPE RENAME then consistency would suggest requiring people to
use that for composite types.

            regards, tom lane

Re: ALTER TYPE RENAME

From
Petr Jelinek
Date:
Tom Lane wrote:
> BTW, another issue this brings up is whether we should reject
>
> regression=# create type footyp as (f2 int);
> CREATE TYPE
> regression=# alter table footyp rename to foobar;
> ALTER TABLE
>
> Currently, since there's no ALTER TYPE RENAME command, this is useful
> functionality and I wouldn't want to forbid it.  But if we provide
> ALTER TYPE RENAME then consistency would suggest requiring people to
> use that for composite types.
>
I assume ALTER TYPE RENAME should rename associated relation too, then.

--
Regards
Petr Jelinek (PJMODOS)


Re: ALTER TYPE RENAME

From
Tom Lane
Date:
Petr Jelinek <pjmodos@pjmodos.net> writes:
> Tom Lane wrote:
>> Currently, since there's no ALTER TYPE RENAME command, this is useful
>> functionality and I wouldn't want to forbid it.  But if we provide
>> ALTER TYPE RENAME then consistency would suggest requiring people to
>> use that for composite types.
>>
> I assume ALTER TYPE RENAME should rename associated relation too, then.

Hm, I'm not entirely sure if you got the point or not.  For either
relations or composite types, there is both a pg_class entry and a
pg_type entry, and their names *must* stay in sync.  We could allow
people to rename both entries using either ALTER TABLE or ALTER TYPE,
but the general consensus seems to be that ALTER TYPE should be used
for composite types and ALTER TABLE for tables/views/etc.  The fact
that there's a pg_class entry for a composite type is really an
implementation detail that would best not be exposed to users, so
enforcing the use of the appropriate command seems reasonable to me.

            regards, tom lane

Re: ALTER TYPE RENAME

From
Petr Jelinek
Date:
Tom Lane wrote:
> Hm, I'm not entirely sure if you got the point or not.  For either
> relations or composite types, there is both a pg_class entry and a
> pg_type entry, and their names *must* stay in sync.  We could allow
> people to rename both entries using either ALTER TABLE or ALTER TYPE,
> but the general consensus seems to be that ALTER TYPE should be used
> for composite types and ALTER TABLE for tables/views/etc.  The fact
> that there's a pg_class entry for a composite type is really an
> implementation detail that would best not be exposed to users, so
> enforcing the use of the appropriate command seems reasonable to me.
>
>             regards, tom lane
>
Yes, that's exactly what I meant (my language skills are not best).

Anyway, I am sending second version of the patch. Changes are:
 - renamed TypeRename function to RenameTypeInternal and changed its
header comment
 - throw error when using ALTER TYPE to rename rowtype
 - split function renamerel to RenameRelation and RenameRelationInternal
where RenameRelation does permission checks and stuff and also checks if
it's not used for composite types and RenameRelationInternal  does the
actual rename. And I also did a little cleanup in those functions
(removed unused code and changed some hardcoded relkind types to globaly
predefined constants)
 - RenameType now calls RenameRelationInternal  for composite types
(which calls RenameTypeInternal automatically)

Any other comments ?

--
Regards
Petr Jelinek (PJMODOS)

Index: doc/src/sgml/ref/alter_type.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/alter_type.sgml,v
retrieving revision 1.4
diff -c -r1.4 alter_type.sgml
*** doc/src/sgml/ref/alter_type.sgml    16 Sep 2006 00:30:16 -0000    1.4
--- doc/src/sgml/ref/alter_type.sgml    29 Sep 2007 05:43:14 -0000
***************
*** 26,31 ****
--- 26,32 ----
    <synopsis>
  ALTER TYPE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable
class="PARAMETER">new_owner</replaceable> 
  ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable
class="PARAMETER">new_schema</replaceable>
+ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RNAME TO <replaceable
class="PARAMETER">new_name</replaceable>
    </synopsis>
   </refsynopsisdiv>

***************
*** 83,88 ****
--- 84,98 ----
        </listitem>
       </varlistentry>

+      <varlistentry>
+       <term><replaceable class="PARAMETER">new_name</replaceable></term>
+       <listitem>
+        <para>
+         The new name for the type.
+        </para>
+       </listitem>
+      </varlistentry>
+
      </variablelist>
     </para>
    </refsect1>
Index: src/backend/catalog/pg_type.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/pg_type.c,v
retrieving revision 1.113
diff -c -r1.113 pg_type.c
*** src/backend/catalog/pg_type.c    12 May 2007 00:54:59 -0000    1.113
--- src/backend/catalog/pg_type.c    30 Sep 2007 04:20:03 -0000
***************
*** 552,566 ****
  }

  /*
!  * TypeRename
   *        This renames a type, as well as any associated array type.
   *
!  * Note: this isn't intended to be a user-exposed function; it doesn't check
!  * permissions etc.  (Perhaps TypeRenameInternal would be a better name.)
!  * Currently this is only used for renaming table rowtypes.
   */
  void
! TypeRename(Oid typeOid, const char *newTypeName, Oid typeNamespace)
  {
      Relation    pg_type_desc;
      HeapTuple    tuple;
--- 552,567 ----
  }

  /*
!  * RenameTypeInternal
   *        This renames a type, as well as any associated array type.
   *
!  * Caller must have already checked privileges.
!  *
!  * Currently this is used for renaming table rowtypes and for
!  * ALTER TYPE RENAME TO command.
   */
  void
! RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
  {
      Relation    pg_type_desc;
      HeapTuple    tuple;
***************
*** 606,612 ****
      {
          char   *arrname = makeArrayTypeName(newTypeName, typeNamespace);

!         TypeRename(arrayOid, arrname, typeNamespace);
          pfree(arrname);
      }
  }
--- 607,613 ----
      {
          char   *arrname = makeArrayTypeName(newTypeName, typeNamespace);

!         RenameTypeInternal(arrayOid, arrname, typeNamespace);
          pfree(arrname);
      }
  }
***************
*** 706,712 ****
      newname = makeArrayTypeName(typeName, typeNamespace);

      /* Apply the rename */
!     TypeRename(typeOid, newname, typeNamespace);

      /*
       * We must bump the command counter so that any subsequent use of
--- 707,713 ----
      newname = makeArrayTypeName(typeName, typeNamespace);

      /* Apply the rename */
!     RenameTypeInternal(typeOid, newname, typeNamespace);

      /*
       * We must bump the command counter so that any subsequent use of
Index: src/backend/commands/alter.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/alter.c,v
retrieving revision 1.25
diff -c -r1.25 alter.c
*** src/backend/commands/alter.c    21 Aug 2007 01:11:14 -0000    1.25
--- src/backend/commands/alter.c    30 Sep 2007 03:53:05 -0000
***************
*** 117,123 ****
                                  aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                                              get_namespace_name(namespaceId));

!                             renamerel(relid, stmt->newname, stmt->renameType);
                              break;
                          }
                      case OBJECT_COLUMN:
--- 117,123 ----
                                  aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                                              get_namespace_name(namespaceId));

!                             RenameRelation(relid, stmt->newname, stmt->renameType);
                              break;
                          }
                      case OBJECT_COLUMN:
***************
*** 154,159 ****
--- 154,164 ----
              RenameTSConfiguration(stmt->object, stmt->newname);
              break;

+         case OBJECT_TYPE:
+         case OBJECT_DOMAIN:
+             RenameType(stmt->object, stmt->newname);
+             break;
+
          default:
              elog(ERROR, "unrecognized rename stmt type: %d",
                   (int) stmt->renameType);
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.233
diff -c -r1.233 tablecmds.c
*** src/backend/commands/tablecmds.c    29 Sep 2007 17:18:58 -0000    1.233
--- src/backend/commands/tablecmds.c    30 Sep 2007 03:55:31 -0000
***************
*** 1612,1637 ****
      relation_close(targetrelation, NoLock);        /* close rel but keep lock */
  }

  /*
!  *        renamerel        - change the name of a relation
!  *
!  *        XXX - When renaming sequences, we don't bother to modify the
!  *              sequence name that is stored within the sequence itself
!  *              (this would cause problems with MVCC). In the future,
!  *              the sequence name should probably be removed from the
!  *              sequence, AFAIK there's no need for it to be there.
   */
  void
! renamerel(Oid myrelid, const char *newrelname, ObjectType reltype)
  {
      Relation    targetrelation;
-     Relation    relrelation;    /* for RELATION relation */
-     HeapTuple    reltup;
-     Form_pg_class relform;
      Oid            namespaceId;
-     char       *oldrelname;
      char        relkind;
-     bool        relhastriggers;

      /*
       * Grab an exclusive lock on the target table, index, sequence or
--- 1612,1627 ----
      relation_close(targetrelation, NoLock);        /* close rel but keep lock */
  }

+
  /*
!  * Execute ALTER TABLE/VIEW/SEQUENCE RENAME
   */
  void
! RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype)
  {
      Relation    targetrelation;
      Oid            namespaceId;
      char        relkind;

      /*
       * Grab an exclusive lock on the target table, index, sequence or
***************
*** 1639,1645 ****
       */
      targetrelation = relation_open(myrelid, AccessExclusiveLock);

-     oldrelname = pstrdup(RelationGetRelationName(targetrelation));
      namespaceId = RelationGetNamespace(targetrelation);

      if (!allowSystemTableMods && IsSystemRelation(targetrelation))
--- 1629,1634 ----
***************
*** 1654,1672 ****
       * view.
       */
      relkind = targetrelation->rd_rel->relkind;
!     if (reltype == OBJECT_SEQUENCE && relkind != 'S')
          ereport(ERROR,
                  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                   errmsg("\"%s\" is not a sequence",
                          RelationGetRelationName(targetrelation))));

!     if (reltype == OBJECT_VIEW && relkind != 'v')
          ereport(ERROR,
                  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                   errmsg("\"%s\" is not a view",
                          RelationGetRelationName(targetrelation))));

!     relhastriggers = (targetrelation->rd_rel->reltriggers > 0);

      /*
       * Find relation's pg_class tuple, and make sure newrelname isn't in use.
--- 1643,1702 ----
       * view.
       */
      relkind = targetrelation->rd_rel->relkind;
!     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 != RELKIND_VIEW)
          ereport(ERROR,
                  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                   errmsg("\"%s\" is not a view",
                          RelationGetRelationName(targetrelation))));

!     /*
!      * Don't allow ALTER TABLE on composite types.
!      * We want people to use ALTER TYPE for that.
!      */
!     if (relkind == RELKIND_COMPOSITE_TYPE)
!         ereport(ERROR,
!                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
!                  errmsg("\"%s\" is a composite type",
!                         RelationGetRelationName(targetrelation)),
!                  errhint("Use ALTER TYPE RENAME TO instead.")));
!
!     /* Do the work */
!     RenameRelationInternal(myrelid, newrelname, namespaceId);
!
!     /*
!      * Close rel, but keep exclusive lock!
!      */
!     relation_close(targetrelation, NoLock);
! }
!
! /*
!  *        RenameRelationInternal - change the name of a relation
!  *
!  *        XXX - When renaming sequences, we don't bother to modify the
!  *              sequence name that is stored within the sequence itself
!  *              (this would cause problems with MVCC). In the future,
!  *              the sequence name should probably be removed from the
!  *              sequence, AFAIK there's no need for it to be there.
!  */
! void
! RenameRelationInternal(Oid myrelid, const char *newrelname, Oid namespaceId)
! {
!     Relation    targetrelation;
!     Relation    relrelation;    /* for RELATION relation */
!     HeapTuple    reltup;
!     Form_pg_class relform;
!
!     /*
!      * Grab an exclusive lock on the target table, index, sequence or
!      * view, which we will NOT release until end of transaction.
!      */
!     targetrelation = relation_open(myrelid, AccessExclusiveLock);

      /*
       * Find relation's pg_class tuple, and make sure newrelname isn't in use.
***************
*** 1704,1710 ****
       * Also rename the associated type, if any.
       */
      if (OidIsValid(targetrelation->rd_rel->reltype))
!         TypeRename(targetrelation->rd_rel->reltype, newrelname, namespaceId);

      /*
       * Close rel, but keep exclusive lock!
--- 1734,1740 ----
       * Also rename the associated type, if any.
       */
      if (OidIsValid(targetrelation->rd_rel->reltype))
!         RenameTypeInternal(targetrelation->rd_rel->reltype, newrelname, namespaceId);

      /*
       * Close rel, but keep exclusive lock!
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.108
diff -c -r1.108 typecmds.c
*** src/backend/commands/typecmds.c    29 Sep 2007 17:18:58 -0000    1.108
--- src/backend/commands/typecmds.c    30 Sep 2007 04:36:08 -0000
***************
*** 2654,2656 ****
--- 2654,2723 ----
      if (OidIsValid(arrayOid))
          AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);
  }
+
+
+ /*
+  * Execute ALTER TYPE RENAME
+  */
+ void
+ RenameType(List *names, const char *newTypeName)
+ {
+     TypeName   *typename;
+     Oid            typeOid;
+     Relation    rel;
+     HeapTuple    tup;
+     Form_pg_type typTup;
+
+     /* Make a TypeName so we can use standard type lookup machinery */
+     typename = makeTypeNameFromNameList(names);
+     typeOid = typenameTypeId(NULL, typename);
+
+     /* Look up the type in the type table */
+     rel = heap_open(TypeRelationId, RowExclusiveLock);
+
+     tup = SearchSysCacheCopy(TYPEOID,
+                              ObjectIdGetDatum(typeOid),
+                              0, 0, 0);
+     if (!HeapTupleIsValid(tup))
+         elog(ERROR, "cache lookup failed for type %u", typeOid);
+     typTup = (Form_pg_type) GETSTRUCT(tup);
+
+     /* check permissions on type */
+     if (!pg_type_ownercheck(typeOid, GetUserId()))
+         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
+                        format_type_be(typeOid));
+
+     /*
+      * If it's a composite type, we need to check that it really is a
+      * free-standing composite type, and not a table's rowtype. We
+      * want people to use ALTER TABLE not ALTER TYPE for that case.
+      */
+     if (typTup->typtype == TYPTYPE_COMPOSITE &&
+         get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
+         ereport(ERROR,
+                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                  errmsg("\"%s\" is a table's row type",
+                         TypeNameToString(typename))));
+
+     /* don't allow direct alteration of array types, either */
+     if (OidIsValid(typTup->typelem) &&
+         get_array_type(typTup->typelem) == typeOid)
+         ereport(ERROR,
+                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                  errmsg("cannot alter array type %s",
+                         format_type_be(typeOid)),
+                  errhint("You can alter type %s, which will alter the array type as well.",
+                          format_type_be(typTup->typelem))));
+
+     /*
+      * If type is composite type we need to rename associated relation too.
+      * RenameRelationInternal will call RenameTypeInternal automatically.
+      */
+     if (typTup->typtype == TYPTYPE_COMPOSITE)
+         RenameRelationInternal(typTup->typrelid, newTypeName, typTup->typnamespace);
+     else
+         RenameTypeInternal(typeOid, newTypeName, typTup->typnamespace);
+
+     /* Clean up */
+     heap_close(rel, RowExclusiveLock);
+ }
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.603
diff -c -r2.603 gram.y
*** src/backend/parser/gram.y    24 Sep 2007 01:29:28 -0000    2.603
--- src/backend/parser/gram.y    29 Sep 2007 05:13:21 -0000
***************
*** 4748,4753 ****
--- 4748,4761 ----
                      n->newname = $8;
                      $$ = (Node *)n;
                  }
+             | ALTER TYPE_P any_name RENAME TO name
+                 {
+                     RenameStmt *n = makeNode(RenameStmt);
+                     n->renameType = OBJECT_TYPE;
+                     n->object = $3;
+                     n->newname = $6;
+                     $$ = (Node *)n;
+                 }
          ;

  opt_column: COLUMN                                    { $$ = COLUMN; }
Index: src/include/catalog/pg_type.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_type.h,v
retrieving revision 1.188
diff -c -r1.188 pg_type.h
*** src/include/catalog/pg_type.h    3 Sep 2007 02:30:45 -0000    1.188
--- src/include/catalog/pg_type.h    29 Sep 2007 23:04:57 -0000
***************
*** 678,684 ****
                           Node *defaultExpr,
                           bool rebuild);

! extern void TypeRename(Oid typeOid, const char *newTypeName,
                         Oid typeNamespace);

  extern char *makeArrayTypeName(const char *typeName, Oid typeNamespace);
--- 678,684 ----
                           Node *defaultExpr,
                           bool rebuild);

! extern void RenameTypeInternal(Oid typeOid, const char *newTypeName,
                         Oid typeNamespace);

  extern char *makeArrayTypeName(const char *typeName, Oid typeNamespace);
Index: src/include/commands/tablecmds.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/tablecmds.h,v
retrieving revision 1.34
diff -c -r1.34 tablecmds.h
*** src/include/commands/tablecmds.h    3 Jul 2007 01:30:37 -0000    1.34
--- src/include/commands/tablecmds.h    30 Sep 2007 03:49:44 -0000
***************
*** 42,51 ****
            bool recurse,
            bool recursing);

! extern void renamerel(Oid myrelid,
            const char *newrelname,
            ObjectType reltype);

  extern void find_composite_type_dependencies(Oid typeOid,
                                               const char *origTblName,
                                               const char *origTypeName);
--- 42,55 ----
            bool recurse,
            bool recursing);

! extern void RenameRelation(Oid myrelid,
            const char *newrelname,
            ObjectType reltype);

+ extern void RenameRelationInternal(Oid myrelid,
+           const char *newrelname,
+           Oid namespaceId);
+
  extern void find_composite_type_dependencies(Oid typeOid,
                                               const char *origTblName,
                                               const char *origTypeName);
Index: src/include/commands/typecmds.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/typecmds.h,v
retrieving revision 1.19
diff -c -r1.19 typecmds.h
*** src/include/commands/typecmds.h    11 May 2007 17:57:14 -0000    1.19
--- src/include/commands/typecmds.h    29 Sep 2007 05:11:57 -0000
***************
*** 43,46 ****
--- 43,48 ----
                                         bool isImplicitArray,
                                         bool errorOnTableType);

+ extern void RenameType(List *names, const char *newTypeName);
+
  #endif   /* TYPECMDS_H */

Re: ALTER TYPE RENAME

From
Bruce Momjian
Date:
This has been saved for the 8.4 release:

    http://momjian.postgresql.org/cgi-bin/pgpatches_hold

---------------------------------------------------------------------------

Petr Jelinek wrote:
> Hi,
> I noticed we don't have ALTER TYPE foo RENAME TO bar command which would
> be handy for me especially for enum types.
> So I wrote this little patch (including very brief doc) which adds above
> syntax. It basically just does some checks and calls existing TypeRename
> function which is used for renaming table rowtype now.
> I hope I haven't missed anything, but I am unsure about two things.
> First, this patch allows renaming base types which I don't know if it's
> desired. And second we might want to throw error when renaming rowtype
> (there is check in AlterTypeOwner for this but not in AlterTypeNamespace
> so I don't know).
>
> --
> Regards
> Petr Jelinek (PJMODOS)
>

> Index: doc/src/sgml/ref/alter_type.sgml
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/alter_type.sgml,v
> retrieving revision 1.4
> diff -c -r1.4 alter_type.sgml
> *** doc/src/sgml/ref/alter_type.sgml    16 Sep 2006 00:30:16 -0000    1.4
> --- doc/src/sgml/ref/alter_type.sgml    29 Sep 2007 05:43:14 -0000
> ***************
> *** 26,31 ****
> --- 26,32 ----
>     <synopsis>
>   ALTER TYPE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable
class="PARAMETER">new_owner</replaceable> 
>   ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable
class="PARAMETER">new_schema</replaceable>
> + ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable
class="PARAMETER">new_name</replaceable>
>     </synopsis>
>    </refsynopsisdiv>
>
> ***************
> *** 83,88 ****
> --- 84,98 ----
>         </listitem>
>        </varlistentry>
>
> +      <varlistentry>
> +       <term><replaceable class="PARAMETER">new_name</replaceable></term>
> +       <listitem>
> +        <para>
> +         The new name for the type.
> +        </para>
> +       </listitem>
> +      </varlistentry>
> +
>       </variablelist>
>      </para>
>     </refsect1>
> Index: src/backend/commands/alter.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/commands/alter.c,v
> retrieving revision 1.25
> diff -c -r1.25 alter.c
> *** src/backend/commands/alter.c    21 Aug 2007 01:11:14 -0000    1.25
> --- src/backend/commands/alter.c    29 Sep 2007 05:12:31 -0000
> ***************
> *** 154,159 ****
> --- 154,164 ----
>               RenameTSConfiguration(stmt->object, stmt->newname);
>               break;
>
> +         case OBJECT_TYPE:
> +         case OBJECT_DOMAIN:
> +             RenameType(stmt->object, stmt->newname);
> +             break;
> +
>           default:
>               elog(ERROR, "unrecognized rename stmt type: %d",
>                    (int) stmt->renameType);
> Index: src/backend/commands/typecmds.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/commands/typecmds.c,v
> retrieving revision 1.107
> diff -c -r1.107 typecmds.c
> *** src/backend/commands/typecmds.c    4 Sep 2007 16:41:42 -0000    1.107
> --- src/backend/commands/typecmds.c    29 Sep 2007 05:11:22 -0000
> ***************
> *** 2514,2519 ****
> --- 2514,2567 ----
>   }
>
>   /*
> +  * Execute ALTER TYPE RENAME
> +  */
> + void
> + RenameType(List *names, const char *newTypeName)
> + {
> +     TypeName   *typename;
> +     Oid            typeOid;
> +     Relation    rel;
> +     HeapTuple    tup;
> +     Form_pg_type typTup;
> +
> +     /* Make a TypeName so we can use standard type lookup machinery */
> +     typename = makeTypeNameFromNameList(names);
> +     typeOid = typenameTypeId(NULL, typename);
> +
> +     /* Look up the type in the type table */
> +     rel = heap_open(TypeRelationId, RowExclusiveLock);
> +
> +     tup = SearchSysCacheCopy(TYPEOID,
> +                              ObjectIdGetDatum(typeOid),
> +                              0, 0, 0);
> +     if (!HeapTupleIsValid(tup))
> +         elog(ERROR, "cache lookup failed for type %u", typeOid);
> +     typTup = (Form_pg_type) GETSTRUCT(tup);
> +
> +     /* check permissions on type */
> +     if (!pg_type_ownercheck(typeOid, GetUserId()))
> +         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
> +                        format_type_be(typeOid));
> +
> +     /* don't allow direct alteration of array types */
> +     if (OidIsValid(typTup->typelem) &&
> +         get_array_type(typTup->typelem) == typeOid)
> +         ereport(ERROR,
> +                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
> +                  errmsg("cannot alter array type %s",
> +                         format_type_be(typeOid)),
> +                  errhint("You can alter type %s, which will alter the array type as well.",
> +                          format_type_be(typTup->typelem))));
> +
> +     /* and do the work */
> +     TypeRename(typeOid, newTypeName, typTup->typnamespace);
> +
> +     /* Clean up */
> +     heap_close(rel, RowExclusiveLock);
> + }
> +
> + /*
>    * Move specified type to new namespace.
>    *
>    * Caller must have already checked privileges.
> Index: src/backend/parser/gram.y
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
> retrieving revision 2.603
> diff -c -r2.603 gram.y
> *** src/backend/parser/gram.y    24 Sep 2007 01:29:28 -0000    2.603
> --- src/backend/parser/gram.y    29 Sep 2007 05:13:21 -0000
> ***************
> *** 4748,4753 ****
> --- 4748,4761 ----
>                       n->newname = $8;
>                       $$ = (Node *)n;
>                   }
> +             | ALTER TYPE_P any_name RENAME TO name
> +                 {
> +                     RenameStmt *n = makeNode(RenameStmt);
> +                     n->renameType = OBJECT_TYPE;
> +                     n->object = $3;
> +                     n->newname = $6;
> +                     $$ = (Node *)n;
> +                 }
>           ;
>
>   opt_column: COLUMN                                    { $$ = COLUMN; }
> Index: src/include/commands/typecmds.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/include/commands/typecmds.h,v
> retrieving revision 1.19
> diff -c -r1.19 typecmds.h
> *** src/include/commands/typecmds.h    11 May 2007 17:57:14 -0000    1.19
> --- src/include/commands/typecmds.h    29 Sep 2007 05:11:57 -0000
> ***************
> *** 43,46 ****
> --- 43,48 ----
>                                          bool isImplicitArray,
>                                          bool errorOnTableType);
>
> + extern void RenameType(List *names, const char *newTypeName);
> +
>   #endif   /* TYPECMDS_H */

>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: Don't 'kill -9' the postmaster

--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://postgres.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

Re: ALTER TYPE RENAME

From
Tom Lane
Date:
Petr Jelinek <pjmodos@pjmodos.net> writes:
> Anyway, I am sending second version of the patch.

Applied with minor corrections.

            regards, tom lane

Re: ALTER TYPE RENAME

From
Bruce Momjian
Date:
This has been applied by Tom.

---------------------------------------------------------------------------

Petr Jelinek wrote:
> Tom Lane wrote:
> > Hm, I'm not entirely sure if you got the point or not.  For either
> > relations or composite types, there is both a pg_class entry and a
> > pg_type entry, and their names *must* stay in sync.  We could allow
> > people to rename both entries using either ALTER TABLE or ALTER TYPE,
> > but the general consensus seems to be that ALTER TYPE should be used
> > for composite types and ALTER TABLE for tables/views/etc.  The fact
> > that there's a pg_class entry for a composite type is really an
> > implementation detail that would best not be exposed to users, so
> > enforcing the use of the appropriate command seems reasonable to me.
> >
> >             regards, tom lane
> >
> Yes, that's exactly what I meant (my language skills are not best).
>
> Anyway, I am sending second version of the patch. Changes are:
>  - renamed TypeRename function to RenameTypeInternal and changed its
> header comment
>  - throw error when using ALTER TYPE to rename rowtype
>  - split function renamerel to RenameRelation and RenameRelationInternal
> where RenameRelation does permission checks and stuff and also checks if
> it's not used for composite types and RenameRelationInternal  does the
> actual rename. And I also did a little cleanup in those functions
> (removed unused code and changed some hardcoded relkind types to globaly
> predefined constants)
>  - RenameType now calls RenameRelationInternal  for composite types
> (which calls RenameTypeInternal automatically)
>
> Any other comments ?
>
> --
> Regards
> Petr Jelinek (PJMODOS)
>

> Index: doc/src/sgml/ref/alter_type.sgml
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/alter_type.sgml,v
> retrieving revision 1.4
> diff -c -r1.4 alter_type.sgml
> *** doc/src/sgml/ref/alter_type.sgml    16 Sep 2006 00:30:16 -0000    1.4
> --- doc/src/sgml/ref/alter_type.sgml    29 Sep 2007 05:43:14 -0000
> ***************
> *** 26,31 ****
> --- 26,32 ----
>     <synopsis>
>   ALTER TYPE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable
class="PARAMETER">new_owner</replaceable> 
>   ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable
class="PARAMETER">new_schema</replaceable>
> + ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RNAME TO <replaceable
class="PARAMETER">new_name</replaceable>
>     </synopsis>
>    </refsynopsisdiv>
>
> ***************
> *** 83,88 ****
> --- 84,98 ----
>         </listitem>
>        </varlistentry>
>
> +      <varlistentry>
> +       <term><replaceable class="PARAMETER">new_name</replaceable></term>
> +       <listitem>
> +        <para>
> +         The new name for the type.
> +        </para>
> +       </listitem>
> +      </varlistentry>
> +
>       </variablelist>
>      </para>
>     </refsect1>
> Index: src/backend/catalog/pg_type.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/catalog/pg_type.c,v
> retrieving revision 1.113
> diff -c -r1.113 pg_type.c
> *** src/backend/catalog/pg_type.c    12 May 2007 00:54:59 -0000    1.113
> --- src/backend/catalog/pg_type.c    30 Sep 2007 04:20:03 -0000
> ***************
> *** 552,566 ****
>   }
>
>   /*
> !  * TypeRename
>    *        This renames a type, as well as any associated array type.
>    *
> !  * Note: this isn't intended to be a user-exposed function; it doesn't check
> !  * permissions etc.  (Perhaps TypeRenameInternal would be a better name.)
> !  * Currently this is only used for renaming table rowtypes.
>    */
>   void
> ! TypeRename(Oid typeOid, const char *newTypeName, Oid typeNamespace)
>   {
>       Relation    pg_type_desc;
>       HeapTuple    tuple;
> --- 552,567 ----
>   }
>
>   /*
> !  * RenameTypeInternal
>    *        This renames a type, as well as any associated array type.
>    *
> !  * Caller must have already checked privileges.
> !  *
> !  * Currently this is used for renaming table rowtypes and for
> !  * ALTER TYPE RENAME TO command.
>    */
>   void
> ! RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
>   {
>       Relation    pg_type_desc;
>       HeapTuple    tuple;
> ***************
> *** 606,612 ****
>       {
>           char   *arrname = makeArrayTypeName(newTypeName, typeNamespace);
>
> !         TypeRename(arrayOid, arrname, typeNamespace);
>           pfree(arrname);
>       }
>   }
> --- 607,613 ----
>       {
>           char   *arrname = makeArrayTypeName(newTypeName, typeNamespace);
>
> !         RenameTypeInternal(arrayOid, arrname, typeNamespace);
>           pfree(arrname);
>       }
>   }
> ***************
> *** 706,712 ****
>       newname = makeArrayTypeName(typeName, typeNamespace);
>
>       /* Apply the rename */
> !     TypeRename(typeOid, newname, typeNamespace);
>
>       /*
>        * We must bump the command counter so that any subsequent use of
> --- 707,713 ----
>       newname = makeArrayTypeName(typeName, typeNamespace);
>
>       /* Apply the rename */
> !     RenameTypeInternal(typeOid, newname, typeNamespace);
>
>       /*
>        * We must bump the command counter so that any subsequent use of
> Index: src/backend/commands/alter.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/commands/alter.c,v
> retrieving revision 1.25
> diff -c -r1.25 alter.c
> *** src/backend/commands/alter.c    21 Aug 2007 01:11:14 -0000    1.25
> --- src/backend/commands/alter.c    30 Sep 2007 03:53:05 -0000
> ***************
> *** 117,123 ****
>                                   aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
>                                               get_namespace_name(namespaceId));
>
> !                             renamerel(relid, stmt->newname, stmt->renameType);
>                               break;
>                           }
>                       case OBJECT_COLUMN:
> --- 117,123 ----
>                                   aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
>                                               get_namespace_name(namespaceId));
>
> !                             RenameRelation(relid, stmt->newname, stmt->renameType);
>                               break;
>                           }
>                       case OBJECT_COLUMN:
> ***************
> *** 154,159 ****
> --- 154,164 ----
>               RenameTSConfiguration(stmt->object, stmt->newname);
>               break;
>
> +         case OBJECT_TYPE:
> +         case OBJECT_DOMAIN:
> +             RenameType(stmt->object, stmt->newname);
> +             break;
> +
>           default:
>               elog(ERROR, "unrecognized rename stmt type: %d",
>                    (int) stmt->renameType);
> Index: src/backend/commands/tablecmds.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/commands/tablecmds.c,v
> retrieving revision 1.233
> diff -c -r1.233 tablecmds.c
> *** src/backend/commands/tablecmds.c    29 Sep 2007 17:18:58 -0000    1.233
> --- src/backend/commands/tablecmds.c    30 Sep 2007 03:55:31 -0000
> ***************
> *** 1612,1637 ****
>       relation_close(targetrelation, NoLock);        /* close rel but keep lock */
>   }
>
>   /*
> !  *        renamerel        - change the name of a relation
> !  *
> !  *        XXX - When renaming sequences, we don't bother to modify the
> !  *              sequence name that is stored within the sequence itself
> !  *              (this would cause problems with MVCC). In the future,
> !  *              the sequence name should probably be removed from the
> !  *              sequence, AFAIK there's no need for it to be there.
>    */
>   void
> ! renamerel(Oid myrelid, const char *newrelname, ObjectType reltype)
>   {
>       Relation    targetrelation;
> -     Relation    relrelation;    /* for RELATION relation */
> -     HeapTuple    reltup;
> -     Form_pg_class relform;
>       Oid            namespaceId;
> -     char       *oldrelname;
>       char        relkind;
> -     bool        relhastriggers;
>
>       /*
>        * Grab an exclusive lock on the target table, index, sequence or
> --- 1612,1627 ----
>       relation_close(targetrelation, NoLock);        /* close rel but keep lock */
>   }
>
> +
>   /*
> !  * Execute ALTER TABLE/VIEW/SEQUENCE RENAME
>    */
>   void
> ! RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype)
>   {
>       Relation    targetrelation;
>       Oid            namespaceId;
>       char        relkind;
>
>       /*
>        * Grab an exclusive lock on the target table, index, sequence or
> ***************
> *** 1639,1645 ****
>        */
>       targetrelation = relation_open(myrelid, AccessExclusiveLock);
>
> -     oldrelname = pstrdup(RelationGetRelationName(targetrelation));
>       namespaceId = RelationGetNamespace(targetrelation);
>
>       if (!allowSystemTableMods && IsSystemRelation(targetrelation))
> --- 1629,1634 ----
> ***************
> *** 1654,1672 ****
>        * view.
>        */
>       relkind = targetrelation->rd_rel->relkind;
> !     if (reltype == OBJECT_SEQUENCE && relkind != 'S')
>           ereport(ERROR,
>                   (errcode(ERRCODE_WRONG_OBJECT_TYPE),
>                    errmsg("\"%s\" is not a sequence",
>                           RelationGetRelationName(targetrelation))));
>
> !     if (reltype == OBJECT_VIEW && relkind != 'v')
>           ereport(ERROR,
>                   (errcode(ERRCODE_WRONG_OBJECT_TYPE),
>                    errmsg("\"%s\" is not a view",
>                           RelationGetRelationName(targetrelation))));
>
> !     relhastriggers = (targetrelation->rd_rel->reltriggers > 0);
>
>       /*
>        * Find relation's pg_class tuple, and make sure newrelname isn't in use.
> --- 1643,1702 ----
>        * view.
>        */
>       relkind = targetrelation->rd_rel->relkind;
> !     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 != RELKIND_VIEW)
>           ereport(ERROR,
>                   (errcode(ERRCODE_WRONG_OBJECT_TYPE),
>                    errmsg("\"%s\" is not a view",
>                           RelationGetRelationName(targetrelation))));
>
> !     /*
> !      * Don't allow ALTER TABLE on composite types.
> !      * We want people to use ALTER TYPE for that.
> !      */
> !     if (relkind == RELKIND_COMPOSITE_TYPE)
> !         ereport(ERROR,
> !                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
> !                  errmsg("\"%s\" is a composite type",
> !                         RelationGetRelationName(targetrelation)),
> !                  errhint("Use ALTER TYPE RENAME TO instead.")));
> !
> !     /* Do the work */
> !     RenameRelationInternal(myrelid, newrelname, namespaceId);
> !
> !     /*
> !      * Close rel, but keep exclusive lock!
> !      */
> !     relation_close(targetrelation, NoLock);
> ! }
> !
> ! /*
> !  *        RenameRelationInternal - change the name of a relation
> !  *
> !  *        XXX - When renaming sequences, we don't bother to modify the
> !  *              sequence name that is stored within the sequence itself
> !  *              (this would cause problems with MVCC). In the future,
> !  *              the sequence name should probably be removed from the
> !  *              sequence, AFAIK there's no need for it to be there.
> !  */
> ! void
> ! RenameRelationInternal(Oid myrelid, const char *newrelname, Oid namespaceId)
> ! {
> !     Relation    targetrelation;
> !     Relation    relrelation;    /* for RELATION relation */
> !     HeapTuple    reltup;
> !     Form_pg_class relform;
> !
> !     /*
> !      * Grab an exclusive lock on the target table, index, sequence or
> !      * view, which we will NOT release until end of transaction.
> !      */
> !     targetrelation = relation_open(myrelid, AccessExclusiveLock);
>
>       /*
>        * Find relation's pg_class tuple, and make sure newrelname isn't in use.
> ***************
> *** 1704,1710 ****
>        * Also rename the associated type, if any.
>        */
>       if (OidIsValid(targetrelation->rd_rel->reltype))
> !         TypeRename(targetrelation->rd_rel->reltype, newrelname, namespaceId);
>
>       /*
>        * Close rel, but keep exclusive lock!
> --- 1734,1740 ----
>        * Also rename the associated type, if any.
>        */
>       if (OidIsValid(targetrelation->rd_rel->reltype))
> !         RenameTypeInternal(targetrelation->rd_rel->reltype, newrelname, namespaceId);
>
>       /*
>        * Close rel, but keep exclusive lock!
> Index: src/backend/commands/typecmds.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/commands/typecmds.c,v
> retrieving revision 1.108
> diff -c -r1.108 typecmds.c
> *** src/backend/commands/typecmds.c    29 Sep 2007 17:18:58 -0000    1.108
> --- src/backend/commands/typecmds.c    30 Sep 2007 04:36:08 -0000
> ***************
> *** 2654,2656 ****
> --- 2654,2723 ----
>       if (OidIsValid(arrayOid))
>           AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);
>   }
> +
> +
> + /*
> +  * Execute ALTER TYPE RENAME
> +  */
> + void
> + RenameType(List *names, const char *newTypeName)
> + {
> +     TypeName   *typename;
> +     Oid            typeOid;
> +     Relation    rel;
> +     HeapTuple    tup;
> +     Form_pg_type typTup;
> +
> +     /* Make a TypeName so we can use standard type lookup machinery */
> +     typename = makeTypeNameFromNameList(names);
> +     typeOid = typenameTypeId(NULL, typename);
> +
> +     /* Look up the type in the type table */
> +     rel = heap_open(TypeRelationId, RowExclusiveLock);
> +
> +     tup = SearchSysCacheCopy(TYPEOID,
> +                              ObjectIdGetDatum(typeOid),
> +                              0, 0, 0);
> +     if (!HeapTupleIsValid(tup))
> +         elog(ERROR, "cache lookup failed for type %u", typeOid);
> +     typTup = (Form_pg_type) GETSTRUCT(tup);
> +
> +     /* check permissions on type */
> +     if (!pg_type_ownercheck(typeOid, GetUserId()))
> +         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
> +                        format_type_be(typeOid));
> +
> +     /*
> +      * If it's a composite type, we need to check that it really is a
> +      * free-standing composite type, and not a table's rowtype. We
> +      * want people to use ALTER TABLE not ALTER TYPE for that case.
> +      */
> +     if (typTup->typtype == TYPTYPE_COMPOSITE &&
> +         get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
> +         ereport(ERROR,
> +                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
> +                  errmsg("\"%s\" is a table's row type",
> +                         TypeNameToString(typename))));
> +
> +     /* don't allow direct alteration of array types, either */
> +     if (OidIsValid(typTup->typelem) &&
> +         get_array_type(typTup->typelem) == typeOid)
> +         ereport(ERROR,
> +                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
> +                  errmsg("cannot alter array type %s",
> +                         format_type_be(typeOid)),
> +                  errhint("You can alter type %s, which will alter the array type as well.",
> +                          format_type_be(typTup->typelem))));
> +
> +     /*
> +      * If type is composite type we need to rename associated relation too.
> +      * RenameRelationInternal will call RenameTypeInternal automatically.
> +      */
> +     if (typTup->typtype == TYPTYPE_COMPOSITE)
> +         RenameRelationInternal(typTup->typrelid, newTypeName, typTup->typnamespace);
> +     else
> +         RenameTypeInternal(typeOid, newTypeName, typTup->typnamespace);
> +
> +     /* Clean up */
> +     heap_close(rel, RowExclusiveLock);
> + }
> Index: src/backend/parser/gram.y
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
> retrieving revision 2.603
> diff -c -r2.603 gram.y
> *** src/backend/parser/gram.y    24 Sep 2007 01:29:28 -0000    2.603
> --- src/backend/parser/gram.y    29 Sep 2007 05:13:21 -0000
> ***************
> *** 4748,4753 ****
> --- 4748,4761 ----
>                       n->newname = $8;
>                       $$ = (Node *)n;
>                   }
> +             | ALTER TYPE_P any_name RENAME TO name
> +                 {
> +                     RenameStmt *n = makeNode(RenameStmt);
> +                     n->renameType = OBJECT_TYPE;
> +                     n->object = $3;
> +                     n->newname = $6;
> +                     $$ = (Node *)n;
> +                 }
>           ;
>
>   opt_column: COLUMN                                    { $$ = COLUMN; }
> Index: src/include/catalog/pg_type.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_type.h,v
> retrieving revision 1.188
> diff -c -r1.188 pg_type.h
> *** src/include/catalog/pg_type.h    3 Sep 2007 02:30:45 -0000    1.188
> --- src/include/catalog/pg_type.h    29 Sep 2007 23:04:57 -0000
> ***************
> *** 678,684 ****
>                            Node *defaultExpr,
>                            bool rebuild);
>
> ! extern void TypeRename(Oid typeOid, const char *newTypeName,
>                          Oid typeNamespace);
>
>   extern char *makeArrayTypeName(const char *typeName, Oid typeNamespace);
> --- 678,684 ----
>                            Node *defaultExpr,
>                            bool rebuild);
>
> ! extern void RenameTypeInternal(Oid typeOid, const char *newTypeName,
>                          Oid typeNamespace);
>
>   extern char *makeArrayTypeName(const char *typeName, Oid typeNamespace);
> Index: src/include/commands/tablecmds.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/include/commands/tablecmds.h,v
> retrieving revision 1.34
> diff -c -r1.34 tablecmds.h
> *** src/include/commands/tablecmds.h    3 Jul 2007 01:30:37 -0000    1.34
> --- src/include/commands/tablecmds.h    30 Sep 2007 03:49:44 -0000
> ***************
> *** 42,51 ****
>             bool recurse,
>             bool recursing);
>
> ! extern void renamerel(Oid myrelid,
>             const char *newrelname,
>             ObjectType reltype);
>
>   extern void find_composite_type_dependencies(Oid typeOid,
>                                                const char *origTblName,
>                                                const char *origTypeName);
> --- 42,55 ----
>             bool recurse,
>             bool recursing);
>
> ! extern void RenameRelation(Oid myrelid,
>             const char *newrelname,
>             ObjectType reltype);
>
> + extern void RenameRelationInternal(Oid myrelid,
> +           const char *newrelname,
> +           Oid namespaceId);
> +
>   extern void find_composite_type_dependencies(Oid typeOid,
>                                                const char *origTblName,
>                                                const char *origTypeName);
> Index: src/include/commands/typecmds.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/include/commands/typecmds.h,v
> retrieving revision 1.19
> diff -c -r1.19 typecmds.h
> *** src/include/commands/typecmds.h    11 May 2007 17:57:14 -0000    1.19
> --- src/include/commands/typecmds.h    29 Sep 2007 05:11:57 -0000
> ***************
> *** 43,46 ****
> --- 43,48 ----
>                                          bool isImplicitArray,
>                                          bool errorOnTableType);
>
> + extern void RenameType(List *names, const char *newTypeName);
> +
>   #endif   /* TYPECMDS_H */

>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: Have you checked our extensive FAQ?
>
>                http://www.postgresql.org/docs/faq

--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://postgres.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +