@ -8,13 +8,14 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / catalog / pg_type . c , v 1.112 2007 / 05 / 11 17 : 57 : 12 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / catalog / pg_type . c , v 1.113 2007 / 05 / 12 00 : 54 : 59 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
# include "postgres.h"
# include "access/heapam.h"
# include "access/xact.h"
# include "catalog/dependency.h"
# include "catalog/indexing.h"
# include "catalog/pg_namespace.h"
@ -26,6 +27,7 @@
# include "utils/acl.h"
# include "utils/builtins.h"
# include "utils/fmgroids.h"
# include "utils/lsyscache.h"
# include "utils/syscache.h"
@ -551,30 +553,35 @@ GenerateTypeDependencies(Oid typeNamespace,
/*
* TypeRename
* This renames a type
* This renames a type , as well as any associated array type .
*
* Note : any associated array type is * not * renamed ; caller must make
* another call to handle that case . Currently this is only used for
* renaming types associated with tables , for which there are no array s.
* 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 rowtype s.
*/
void
TypeRename ( const char * oldTypeName , Oid typeNamespace ,
const char * newTypeName )
TypeRename ( Oid typeOid , const char * newTypeName , Oid typeNamespace )
{
Relation pg_type_desc ;
HeapTuple tuple ;
Form_pg_type typ ;
Oid arrayOid ;
pg_type_desc = heap_open ( TypeRelationId , RowExclusiveLock ) ;
tuple = SearchSysCacheCopy ( TYPENAMENSP ,
CStringGetDatum ( oldTypeName ) ,
ObjectIdGetDatum ( typeNamespace ) ,
0 , 0 ) ;
tuple = SearchSysCacheCopy ( TYPEOID ,
ObjectIdGetDatum ( typeOid ) ,
0 , 0 , 0 ) ;
if ( ! HeapTupleIsValid ( tuple ) )
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " type \" %s \" does not exist " , oldTypeName ) ) ) ;
elog ( ERROR , " cache lookup failed for type %u " , typeOid ) ;
typ = ( Form_pg_type ) GETSTRUCT ( tuple ) ;
/* We are not supposed to be changing schemas here */
Assert ( typeNamespace = = typ - > typnamespace ) ;
arrayOid = typ - > typarray ;
/* Just to give a more friendly error than unique-index violation */
if ( SearchSysCacheExists ( TYPENAMENSP ,
CStringGetDatum ( newTypeName ) ,
ObjectIdGetDatum ( typeNamespace ) ,
@ -583,7 +590,8 @@ TypeRename(const char *oldTypeName, Oid typeNamespace,
( errcode ( ERRCODE_DUPLICATE_OBJECT ) ,
errmsg ( " type \" %s \" already exists " , newTypeName ) ) ) ;
namestrcpy ( & ( ( ( Form_pg_type ) GETSTRUCT ( tuple ) ) - > typname ) , newTypeName ) ;
/* OK, do the rename --- tuple is a copy, so OK to scribble on it */
namestrcpy ( & ( typ - > typname ) , newTypeName ) ;
simple_heap_update ( pg_type_desc , & tuple - > t_self , tuple ) ;
@ -592,11 +600,20 @@ TypeRename(const char *oldTypeName, Oid typeNamespace,
heap_freetuple ( tuple ) ;
heap_close ( pg_type_desc , RowExclusiveLock ) ;
/* If the type has an array type, recurse to handle that */
if ( OidIsValid ( arrayOid ) )
{
char * arrname = makeArrayTypeName ( newTypeName , typeNamespace ) ;
TypeRename ( arrayOid , arrname , typeNamespace ) ;
pfree ( arrname ) ;
}
}
/*
* makeArrayTypeName ( typeName )
* makeArrayTypeName
* - given a base type name , make an array type name for it
*
* the caller is responsible for pfreeing the result
@ -638,3 +655,66 @@ makeArrayTypeName(const char *typeName, Oid typeNamespace)
return arr ;
}
/*
* moveArrayTypeName
* - try to reassign an array type name that the user wants to use .
*
* The given type name has been discovered to already exist ( with the given
* OID ) . If it is an autogenerated array type , change the array type ' s name
* to not conflict . This allows the user to create type " foo " followed by
* type " _foo " without problems . ( Of course , there are race conditions if
* two backends try to create similarly - named types concurrently , but the
* worst that can happen is an unnecessary failure - - - anything we do here
* will be rolled back if the type creation fails due to conflicting names . )
*
* Note that this must be called * before * calling makeArrayTypeName to
* determine the new type ' s own array type name ; else the latter will
* certainly pick the same name .
*
* Returns TRUE if successfully moved the type , FALSE if not .
*
* We also return TRUE if the given type is a shell type . In this case
* the type has not been renamed out of the way , but nonetheless it can
* be expected that TypeCreate will succeed . This behavior is convenient
* for most callers - - - those that need to distinguish the shell - type case
* must do their own typisdefined test .
*/
bool
moveArrayTypeName ( Oid typeOid , const char * typeName , Oid typeNamespace )
{
Oid elemOid ;
char * newname ;
/* We need do nothing if it's a shell type. */
if ( ! get_typisdefined ( typeOid ) )
return true ;
/* Can't change it if it's not an autogenerated array type. */
elemOid = get_element_type ( typeOid ) ;
if ( ! OidIsValid ( elemOid ) | |
get_array_type ( elemOid ) ! = typeOid )
return false ;
/*
* OK , use makeArrayTypeName to pick an unused modification of the
* name . Note that since makeArrayTypeName is an iterative process ,
* this will produce a name that it might have produced the first time ,
* had the conflicting type we are about to create already existed .
*/
newname = makeArrayTypeName ( typeName , typeNamespace ) ;
/* Apply the rename */
TypeRename ( typeOid , newname , typeNamespace ) ;
/*
* We must bump the command counter so that any subsequent use of
* makeArrayTypeName sees what we just did and doesn ' t pick the same name .
*/
CommandCounterIncrement ( ) ;
pfree ( newname ) ;
return true ;
}