Re: ALTER TYPE RENAME

From: Bruce Momjian <bruce(at)momjian(dot)us>
To: Petr Jelinek <pjmodos(at)pjmodos(dot)net>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, pgsql-patches(at)postgresql(dot)org
Subject: Re: ALTER TYPE RENAME
Date: 2008-03-19 18:42:59
Message-ID: 200803191842.m2JIgxn07947@momjian.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-patches


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(at)momjian(dot)us> http://momjian.us
EnterpriseDB http://postgres.enterprisedb.com

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

In response to

Browse pgsql-patches by date

  From Date Subject
Next Message Tom Lane 2008-03-20 00:10:47 Re: Text <-> C string
Previous Message Tom Lane 2008-03-19 18:39:11 Re: ALTER TYPE RENAME