Support ALTER TYPE RENAME. Petr Jelinek
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 19 Mar 2008 18:38:30 +0000 (18:38 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 19 Mar 2008 18:38:30 +0000 (18:38 +0000)
doc/src/sgml/ref/alter_type.sgml
src/backend/catalog/pg_type.c
src/backend/commands/alter.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/parser/gram.y
src/backend/tcop/utility.c
src/include/catalog/pg_type.h
src/include/commands/tablecmds.h
src/include/commands/typecmds.h

index 96e5ea267dbe735e0a15a6f57cf5c6af3f10613d..5a69707dd2f4c2d33ea077308049169a2950305b 100644 (file)
@@ -24,6 +24,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
   <synopsis>
+ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
 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>
   </synopsis>
@@ -34,8 +35,6 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replace
 
   <para>
    <command>ALTER TYPE</command> changes the definition of an existing type.
-   The only currently available capabilities are changing the owner and schema
-   of a type.
   </para>
 
   <para>
@@ -65,6 +64,15 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replace
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><replaceable class="PARAMETER">new_name</replaceable></term>
+      <listitem>
+       <para>
+        The new name for the type.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><replaceable class="PARAMETER">new_owner</replaceable></term>
       <listitem>
@@ -91,7 +99,14 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replace
   <title>Examples</title>
 
   <para> 
-   To change the owner of the user-defined type <literal>email</literal>
+   To rename a data type:
+   <programlisting>
+ALTER TYPE electronic_mail RENAME TO email;
+   </programlisting>
+  </para>
+
+  <para> 
+   To change the owner of the type <literal>email</literal>
    to <literal>joe</literal>:
    <programlisting>
 ALTER TYPE email OWNER TO joe;
@@ -99,7 +114,7 @@ ALTER TYPE email OWNER TO joe;
   </para>
 
   <para>
-   To change the schema of the user-defined type <literal>email</literal>
+   To change the schema of the type <literal>email</literal>
    to <literal>customers</literal>:
    <programlisting>
 ALTER TYPE email SET SCHEMA customers;
index be459ac7ce86e46d142662d11c393c82f8bfb56d..386abb9c59160bbd5258e137f1be63f00c44b3aa 100644 (file)
@@ -552,15 +552,16 @@ GenerateTypeDependencies(Oid typeNamespace,
 }
 
 /*
- * TypeRename
+ * RenameTypeInternal
  *             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.
+ * Caller must have already checked privileges.
+ *
+ * Currently this is used for renaming table rowtypes and for
+ * ALTER TYPE RENAME TO command.
  */
 void
-TypeRename(Oid typeOid, const char *newTypeName, Oid typeNamespace)
+RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
 {
        Relation        pg_type_desc;
        HeapTuple       tuple;
@@ -606,7 +607,7 @@ TypeRename(Oid typeOid, const char *newTypeName, Oid typeNamespace)
        {
                char       *arrname = makeArrayTypeName(newTypeName, typeNamespace);
 
-               TypeRename(arrayOid, arrname, typeNamespace);
+               RenameTypeInternal(arrayOid, arrname, typeNamespace);
                pfree(arrname);
        }
 }
@@ -706,7 +707,7 @@ moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
        newname = makeArrayTypeName(typeName, typeNamespace);
 
        /* Apply the rename */
-       TypeRename(typeOid, newname, typeNamespace);
+       RenameTypeInternal(typeOid, newname, typeNamespace);
 
        /*
         * We must bump the command counter so that any subsequent use of
index 3074ad585ecc1781d4a3e9018fcb7b143053c5ba..35d55037398040bb1a8479017287e3a54a8b81f7 100644 (file)
@@ -117,7 +117,7 @@ ExecRenameStmt(RenameStmt *stmt)
                                                                aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                                                                                        get_namespace_name(namespaceId));
 
-                                                       renamerel(relid, stmt->newname, stmt->renameType);
+                                                       RenameRelation(relid, stmt->newname, stmt->renameType);
                                                        break;
                                                }
                                        case OBJECT_COLUMN:
@@ -154,6 +154,10 @@ ExecRenameStmt(RenameStmt *stmt)
                        RenameTSConfiguration(stmt->object, stmt->newname);
                        break;
 
+               case OBJECT_TYPE:
+                       RenameType(stmt->object, stmt->newname);
+                       break;
+
                default:
                        elog(ERROR, "unrecognized rename stmt type: %d",
                                 (int) stmt->renameType);
index 886b7924bc9286a27fb486bff916aa426a9bc298..ee5ad8bf8743bf44b4f7415f219978f1f9edee17 100644 (file)
@@ -1612,26 +1612,18 @@ renameatt(Oid myrelid,
        relation_close(targetrelation, NoLock);         /* close rel but keep lock */
 }
 
+
 /*
- *             renamerel               - change the name of a relation
+ * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW RENAME
  *
- *             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.
+ * Caller has already done permissions checks.
  */
 void
-renamerel(Oid myrelid, const char *newrelname, ObjectType reltype)
+RenameRelation(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 view,
@@ -1639,20 +1631,13 @@ renamerel(Oid myrelid, const char *newrelname, ObjectType reltype)
         */
        targetrelation = relation_open(myrelid, AccessExclusiveLock);
 
-       oldrelname = pstrdup(RelationGetRelationName(targetrelation));
        namespaceId = RelationGetNamespace(targetrelation);
-
-       if (!allowSystemTableMods && IsSystemRelation(targetrelation))
-               ereport(ERROR,
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                errmsg("permission denied: \"%s\" is a system catalog",
-                                               RelationGetRelationName(targetrelation))));
+       relkind = targetrelation->rd_rel->relkind;
 
        /*
         * For compatibility with prior releases, we don't complain if ALTER TABLE
         * or ALTER INDEX is used to rename a sequence or view.
         */
-       relkind = targetrelation->rd_rel->relkind;
        if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE)
                ereport(ERROR,
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -1665,7 +1650,48 @@ renamerel(Oid myrelid, const char *newrelname, ObjectType reltype)
                                 errmsg("\"%s\" is not a view",
                                                RelationGetRelationName(targetrelation))));
 
-       relhastriggers = (targetrelation->rd_rel->reltriggers > 0);
+       /*
+        * 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 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.
@@ -1703,12 +1729,13 @@ renamerel(Oid myrelid, const char *newrelname, ObjectType reltype)
         * Also rename the associated type, if any.
         */
        if (OidIsValid(targetrelation->rd_rel->reltype))
-               TypeRename(targetrelation->rd_rel->reltype, newrelname, namespaceId);
+               RenameTypeInternal(targetrelation->rd_rel->reltype,
+                                                  newrelname, namespaceId);
 
        /*
         * Also rename the associated constraint, if any.
         */
-       if (relkind == RELKIND_INDEX)
+       if (targetrelation->rd_rel->relkind == RELKIND_INDEX)
        {
                Oid                     constraintId = get_index_constraint(myrelid);
 
index a1394d8286a0863e37c095c3524ec06e521e0647..abbf78a3d9f889b0db4ba8e42bfaab980e4705a4 100644 (file)
@@ -2339,6 +2339,76 @@ GetDomainConstraints(Oid typeOid)
        return result;
 }
 
+
+/*
+ * 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, NULL);
+
+       /* 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",
+                                               format_type_be(typeOid)),
+                                errhint("Use ALTER TABLE instead.")));
+
+       /* 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 we need to rename associated pg_class entry 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);
+}
+
 /*
  * Change the owner of a type.
  */
index 0205ef5f32f789d4581cf9d8f395cf0a3b625cd7..a75557a28e9203057166ac3e89da91b1bb662f75 100644 (file)
@@ -4734,6 +4734,14 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
                                        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 c49574cd34a01c0b9b88736cdd5046301f91b7f1..a481d2eb4949c1294e9b37d0326496bab20ac456 100644 (file)
@@ -1613,6 +1613,9 @@ CreateCommandTag(Node *parsetree)
                                case OBJECT_TSCONFIGURATION:
                                        tag = "ALTER TEXT SEARCH CONFIGURATION";
                                        break;
+                               case OBJECT_TYPE:
+                                       tag = "ALTER TYPE";
+                                       break;
                                default:
                                        tag = "???";
                                        break;
index ddaf74d21cb0e3b3c4e71d5855d6efc020c495f5..a4e9e8a9296c6874923b9aec56644265be05a0d6 100644 (file)
@@ -682,7 +682,7 @@ extern void GenerateTypeDependencies(Oid typeNamespace,
                                                 Node *defaultExpr,
                                                 bool rebuild);
 
-extern void TypeRename(Oid typeOid, const char *newTypeName,
+extern void RenameTypeInternal(Oid typeOid, const char *newTypeName,
                   Oid typeNamespace);
 
 extern char *makeArrayTypeName(const char *typeName, Oid typeNamespace);
index df32ee7cdce2c311a0645d51297bfd65f96a4062..d89a35615c0fffb12f715eccd064bb719a2c14f9 100644 (file)
@@ -44,10 +44,14 @@ extern void renameatt(Oid myrelid,
                  bool recurse,
                  bool recursing);
 
-extern void renamerel(Oid myrelid,
+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 a2224d277386ef6ea5fd34e843f81e152515c07e..eae69bf4f2ef2a0c096cecbd76b71c5f2479bf44 100644 (file)
@@ -35,6 +35,7 @@ extern void AlterDomainDropConstraint(List *names, const char *constrName,
 
 extern List *GetDomainConstraints(Oid typeOid);
 
+extern void RenameType(List *names, const char *newTypeName);
 extern void AlterTypeOwner(List *names, Oid newOwnerId);
 extern void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
                                           bool hasDependEntry);