8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
15
15
#include "postgres.h"
16
16
17
17
#include "access/heapam.h"
18
+ #include "access/xact.h"
18
19
#include "catalog/dependency.h"
19
20
#include "catalog/indexing.h"
20
21
#include "catalog/pg_namespace.h"
26
27
#include "utils/acl.h"
27
28
#include "utils/builtins.h"
28
29
#include "utils/fmgroids.h"
30
+ #include "utils/lsyscache.h"
29
31
#include "utils/syscache.h"
30
32
31
33
@@ -551,30 +553,35 @@ GenerateTypeDependencies(Oid typeNamespace,
551
553
552
554
/*
553
555
* TypeRename
554
- * This renames a type
556
+ * This renames a type, as well as any associated array type.
555
557
*
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 .
559
561
*/
560
562
void
561
- TypeRename (const char * oldTypeName , Oid typeNamespace ,
562
- const char * newTypeName )
563
+ TypeRename (Oid typeOid , const char * newTypeName , Oid typeNamespace )
563
564
{
564
565
Relation pg_type_desc ;
565
566
HeapTuple tuple ;
567
+ Form_pg_type typ ;
568
+ Oid arrayOid ;
566
569
567
570
pg_type_desc = heap_open (TypeRelationId , RowExclusiveLock );
568
571
569
- tuple = SearchSysCacheCopy (TYPENAMENSP ,
570
- CStringGetDatum (oldTypeName ),
571
- ObjectIdGetDatum (typeNamespace ),
572
- 0 , 0 );
572
+ tuple = SearchSysCacheCopy (TYPEOID ,
573
+ ObjectIdGetDatum (typeOid ),
574
+ 0 , 0 , 0 );
573
575
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 );
577
581
582
+ arrayOid = typ -> typarray ;
583
+
584
+ /* Just to give a more friendly error than unique-index violation */
578
585
if (SearchSysCacheExists (TYPENAMENSP ,
579
586
CStringGetDatum (newTypeName ),
580
587
ObjectIdGetDatum (typeNamespace ),
@@ -583,7 +590,8 @@ TypeRename(const char *oldTypeName, Oid typeNamespace,
583
590
(errcode (ERRCODE_DUPLICATE_OBJECT ),
584
591
errmsg ("type \"%s\" already exists" , newTypeName )));
585
592
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 );
587
595
588
596
simple_heap_update (pg_type_desc , & tuple -> t_self , tuple );
589
597
@@ -592,11 +600,20 @@ TypeRename(const char *oldTypeName, Oid typeNamespace,
592
600
593
601
heap_freetuple (tuple );
594
602
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
+ }
595
612
}
596
613
597
614
598
615
/*
599
- * makeArrayTypeName(typeName)
616
+ * makeArrayTypeName
600
617
* - given a base type name, make an array type name for it
601
618
*
602
619
* the caller is responsible for pfreeing the result
@@ -638,3 +655,66 @@ makeArrayTypeName(const char *typeName, Oid typeNamespace)
638
655
639
656
return arr ;
640
657
}
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