diff --git a/doc/src/sgml/ref/alter_type.sgml b/doc/src/sgml/ref/alter_type.sgml index c4f9edd399..6f16da6242 100644 --- a/doc/src/sgml/ref/alter_type.sgml +++ b/doc/src/sgml/ref/alter_type.sgml @@ -1,5 +1,5 @@ @@ -24,6 +24,7 @@ PostgreSQL documentation +ALTER TYPE name RENAME TO new_name ALTER TYPE name OWNER TO new_owner ALTER TYPE name SET SCHEMA new_schema @@ -34,8 +35,6 @@ ALTER TYPE name SET SCHEMA ALTER TYPE changes the definition of an existing type. - The only currently available capabilities are changing the owner and schema - of a type. @@ -65,6 +64,15 @@ ALTER TYPE name SET SCHEMA + + new_name + + + The new name for the type. + + + + new_owner @@ -91,7 +99,14 @@ ALTER TYPE name SET SCHEMA Examples - To change the owner of the user-defined type email + To rename a data type: + +ALTER TYPE electronic_mail RENAME TO email; + + + + + To change the owner of the type email to joe: ALTER TYPE email OWNER TO joe; @@ -99,7 +114,7 @@ ALTER TYPE email OWNER TO joe; - To change the schema of the user-defined type email + To change the schema of the type email to customers: ALTER TYPE email SET SCHEMA customers; diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 780d5134d9..a654f19dbb 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.115 2008/01/01 19:45:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.116 2008/03/19 18:38:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 8cf833a921..63acefa527 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.27 2008/02/07 21:07:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.28 2008/03/19 18:38:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 027fe51eca..bd7786a918 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.242 2008/02/07 17:09:51 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.243 2008/03/19 18:38:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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); diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 9528b58c56..982588e04a 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.113 2008/01/01 19:45:49 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.114 2008/03/19 18:38:30 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -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. */ diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 4688bc7977..6d4df81a8a 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.607 2008/02/15 22:17:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.608 2008/03/19 18:38:30 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -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; } diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index fbd8f0d564..df3887b1dc 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.290 2008/03/14 17:25:58 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.291 2008/03/19 18:38:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 7ece0af78c..961f35e589 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.191 2008/01/01 19:45:57 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.192 2008/03/19 18:38:30 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -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); diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index e9c965439c..700c1bd42e 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.37 2008/01/30 19:46:48 tgl Exp $ + * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.38 2008/03/19 18:38:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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); diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h index 71d0ceefa8..ce807b56d0 100644 --- a/src/include/commands/typecmds.h +++ b/src/include/commands/typecmds.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.22 2008/01/01 19:45:57 momjian Exp $ + * $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.23 2008/03/19 18:38:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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);