88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.112 2007/05/11 17:57:12 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.113 2007/05/12 00:54:59 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
1515#include "postgres.h"
1616
1717#include "access/heapam.h"
18+ #include "access/xact.h"
1819#include "catalog/dependency.h"
1920#include "catalog/indexing.h"
2021#include "catalog/pg_namespace.h"
2627#include "utils/acl.h"
2728#include "utils/builtins.h"
2829#include "utils/fmgroids.h"
30+ #include "utils/lsyscache.h"
2931#include "utils/syscache.h"
3032
3133
@@ -551,30 +553,35 @@ GenerateTypeDependencies(Oid typeNamespace,
551553
552554/*
553555 * TypeRename
554- * This renames a type
556+ * This renames a type, as well as any associated array type.
555557 *
556- * Note: any associated array type is *not* renamed; caller must make
557- * another call to handle that case . Currently this is only used for
558- * renaming types associated with tables, for which there are no arrays .
558+ * Note: this isn't intended to be a user-exposed function; it doesn't check
559+ * permissions etc . (Perhaps TypeRenameInternal would be a better name.)
560+ * Currently this is only used for renaming table rowtypes .
559561 */
560562void
561- TypeRename (const char * oldTypeName , Oid typeNamespace ,
562- const char * newTypeName )
563+ TypeRename (Oid typeOid , const char * newTypeName , Oid typeNamespace )
563564{
564565 Relation pg_type_desc ;
565566 HeapTuple tuple ;
567+ Form_pg_type typ ;
568+ Oid arrayOid ;
566569
567570 pg_type_desc = heap_open (TypeRelationId , RowExclusiveLock );
568571
569- tuple = SearchSysCacheCopy (TYPENAMENSP ,
570- CStringGetDatum (oldTypeName ),
571- ObjectIdGetDatum (typeNamespace ),
572- 0 , 0 );
572+ tuple = SearchSysCacheCopy (TYPEOID ,
573+ ObjectIdGetDatum (typeOid ),
574+ 0 , 0 , 0 );
573575 if (!HeapTupleIsValid (tuple ))
574- ereport (ERROR ,
575- (errcode (ERRCODE_UNDEFINED_OBJECT ),
576- errmsg ("type \"%s\" does not exist" , oldTypeName )));
576+ elog (ERROR , "cache lookup failed for type %u" , typeOid );
577+ typ = (Form_pg_type ) GETSTRUCT (tuple );
578+
579+ /* We are not supposed to be changing schemas here */
580+ Assert (typeNamespace == typ -> typnamespace );
577581
582+ arrayOid = typ -> typarray ;
583+
584+ /* Just to give a more friendly error than unique-index violation */
578585 if (SearchSysCacheExists (TYPENAMENSP ,
579586 CStringGetDatum (newTypeName ),
580587 ObjectIdGetDatum (typeNamespace ),
@@ -583,7 +590,8 @@ TypeRename(const char *oldTypeName, Oid typeNamespace,
583590 (errcode (ERRCODE_DUPLICATE_OBJECT ),
584591 errmsg ("type \"%s\" already exists" , newTypeName )));
585592
586- namestrcpy (& (((Form_pg_type ) GETSTRUCT (tuple ))-> typname ), newTypeName );
593+ /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
594+ namestrcpy (& (typ -> typname ), newTypeName );
587595
588596 simple_heap_update (pg_type_desc , & tuple -> t_self , tuple );
589597
@@ -592,11 +600,20 @@ TypeRename(const char *oldTypeName, Oid typeNamespace,
592600
593601 heap_freetuple (tuple );
594602 heap_close (pg_type_desc , RowExclusiveLock );
603+
604+ /* If the type has an array type, recurse to handle that */
605+ if (OidIsValid (arrayOid ))
606+ {
607+ char * arrname = makeArrayTypeName (newTypeName , typeNamespace );
608+
609+ TypeRename (arrayOid , arrname , typeNamespace );
610+ pfree (arrname );
611+ }
595612}
596613
597614
598615/*
599- * makeArrayTypeName(typeName)
616+ * makeArrayTypeName
600617 * - given a base type name, make an array type name for it
601618 *
602619 * the caller is responsible for pfreeing the result
@@ -638,3 +655,66 @@ makeArrayTypeName(const char *typeName, Oid typeNamespace)
638655
639656 return arr ;
640657}
658+
659+
660+ /*
661+ * moveArrayTypeName
662+ * - try to reassign an array type name that the user wants to use.
663+ *
664+ * The given type name has been discovered to already exist (with the given
665+ * OID). If it is an autogenerated array type, change the array type's name
666+ * to not conflict. This allows the user to create type "foo" followed by
667+ * type "_foo" without problems. (Of course, there are race conditions if
668+ * two backends try to create similarly-named types concurrently, but the
669+ * worst that can happen is an unnecessary failure --- anything we do here
670+ * will be rolled back if the type creation fails due to conflicting names.)
671+ *
672+ * Note that this must be called *before* calling makeArrayTypeName to
673+ * determine the new type's own array type name; else the latter will
674+ * certainly pick the same name.
675+ *
676+ * Returns TRUE if successfully moved the type, FALSE if not.
677+ *
678+ * We also return TRUE if the given type is a shell type. In this case
679+ * the type has not been renamed out of the way, but nonetheless it can
680+ * be expected that TypeCreate will succeed. This behavior is convenient
681+ * for most callers --- those that need to distinguish the shell-type case
682+ * must do their own typisdefined test.
683+ */
684+ bool
685+ moveArrayTypeName (Oid typeOid , const char * typeName , Oid typeNamespace )
686+ {
687+ Oid elemOid ;
688+ char * newname ;
689+
690+ /* We need do nothing if it's a shell type. */
691+ if (!get_typisdefined (typeOid ))
692+ return true;
693+
694+ /* Can't change it if it's not an autogenerated array type. */
695+ elemOid = get_element_type (typeOid );
696+ if (!OidIsValid (elemOid ) ||
697+ get_array_type (elemOid ) != typeOid )
698+ return false;
699+
700+ /*
701+ * OK, use makeArrayTypeName to pick an unused modification of the
702+ * name. Note that since makeArrayTypeName is an iterative process,
703+ * this will produce a name that it might have produced the first time,
704+ * had the conflicting type we are about to create already existed.
705+ */
706+ newname = makeArrayTypeName (typeName , typeNamespace );
707+
708+ /* Apply the rename */
709+ TypeRename (typeOid , newname , typeNamespace );
710+
711+ /*
712+ * We must bump the command counter so that any subsequent use of
713+ * makeArrayTypeName sees what we just did and doesn't pick the same name.
714+ */
715+ CommandCounterIncrement ();
716+
717+ pfree (newname );
718+
719+ return true;
720+ }
0 commit comments