Header And Logo

PostgreSQL
| The world's most advanced open source database.

pg_type.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pg_type.c
00004  *    routines to support manipulation of the pg_type relation
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/catalog/pg_type.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include "access/heapam.h"
00018 #include "access/htup_details.h"
00019 #include "access/xact.h"
00020 #include "catalog/dependency.h"
00021 #include "catalog/indexing.h"
00022 #include "catalog/objectaccess.h"
00023 #include "catalog/pg_collation.h"
00024 #include "catalog/pg_namespace.h"
00025 #include "catalog/pg_proc.h"
00026 #include "catalog/pg_type.h"
00027 #include "catalog/pg_type_fn.h"
00028 #include "commands/typecmds.h"
00029 #include "miscadmin.h"
00030 #include "parser/scansup.h"
00031 #include "utils/acl.h"
00032 #include "utils/builtins.h"
00033 #include "utils/fmgroids.h"
00034 #include "utils/lsyscache.h"
00035 #include "utils/rel.h"
00036 #include "utils/syscache.h"
00037 
00038 /* Potentially set by contrib/pg_upgrade_support functions */
00039 Oid         binary_upgrade_next_pg_type_oid = InvalidOid;
00040 
00041 /* ----------------------------------------------------------------
00042  *      TypeShellMake
00043  *
00044  *      This procedure inserts a "shell" tuple into the pg_type relation.
00045  *      The type tuple inserted has valid but dummy values, and its
00046  *      "typisdefined" field is false indicating it's not really defined.
00047  *
00048  *      This is used so that a tuple exists in the catalogs.  The I/O
00049  *      functions for the type will link to this tuple.  When the full
00050  *      CREATE TYPE command is issued, the bogus values will be replaced
00051  *      with correct ones, and "typisdefined" will be set to true.
00052  * ----------------------------------------------------------------
00053  */
00054 Oid
00055 TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
00056 {
00057     Relation    pg_type_desc;
00058     TupleDesc   tupDesc;
00059     int         i;
00060     HeapTuple   tup;
00061     Datum       values[Natts_pg_type];
00062     bool        nulls[Natts_pg_type];
00063     Oid         typoid;
00064     NameData    name;
00065 
00066     Assert(PointerIsValid(typeName));
00067 
00068     /*
00069      * open pg_type
00070      */
00071     pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
00072     tupDesc = pg_type_desc->rd_att;
00073 
00074     /*
00075      * initialize our *nulls and *values arrays
00076      */
00077     for (i = 0; i < Natts_pg_type; ++i)
00078     {
00079         nulls[i] = false;
00080         values[i] = (Datum) NULL;       /* redundant, but safe */
00081     }
00082 
00083     /*
00084      * initialize *values with the type name and dummy values
00085      *
00086      * The representational details are the same as int4 ... it doesn't really
00087      * matter what they are so long as they are consistent.  Also note that we
00088      * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
00089      * mistaken for a usable type.
00090      */
00091     namestrcpy(&name, typeName);
00092     values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
00093     values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
00094     values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
00095     values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
00096     values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
00097     values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
00098     values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
00099     values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
00100     values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
00101     values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
00102     values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
00103     values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
00104     values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
00105     values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
00106     values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
00107     values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
00108     values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
00109     values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
00110     values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
00111     values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
00112     values[Anum_pg_type_typalign - 1] = CharGetDatum('i');
00113     values[Anum_pg_type_typstorage - 1] = CharGetDatum('p');
00114     values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
00115     values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
00116     values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
00117     values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
00118     values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
00119     nulls[Anum_pg_type_typdefaultbin - 1] = true;
00120     nulls[Anum_pg_type_typdefault - 1] = true;
00121     nulls[Anum_pg_type_typacl - 1] = true;
00122 
00123     /*
00124      * create a new type tuple
00125      */
00126     tup = heap_form_tuple(tupDesc, values, nulls);
00127 
00128     /* Use binary-upgrade override for pg_type.oid, if supplied. */
00129     if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_pg_type_oid))
00130     {
00131         HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
00132         binary_upgrade_next_pg_type_oid = InvalidOid;
00133     }
00134 
00135     /*
00136      * insert the tuple in the relation and get the tuple's oid.
00137      */
00138     typoid = simple_heap_insert(pg_type_desc, tup);
00139 
00140     CatalogUpdateIndexes(pg_type_desc, tup);
00141 
00142     /*
00143      * Create dependencies.  We can/must skip this in bootstrap mode.
00144      */
00145     if (!IsBootstrapProcessingMode())
00146         GenerateTypeDependencies(typeNamespace,
00147                                  typoid,
00148                                  InvalidOid,
00149                                  0,
00150                                  ownerId,
00151                                  F_SHELL_IN,
00152                                  F_SHELL_OUT,
00153                                  InvalidOid,
00154                                  InvalidOid,
00155                                  InvalidOid,
00156                                  InvalidOid,
00157                                  InvalidOid,
00158                                  InvalidOid,
00159                                  false,
00160                                  InvalidOid,
00161                                  InvalidOid,
00162                                  NULL,
00163                                  false);
00164 
00165     /* Post creation hook for new shell type */
00166     InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
00167 
00168     /*
00169      * clean up and return the type-oid
00170      */
00171     heap_freetuple(tup);
00172     heap_close(pg_type_desc, RowExclusiveLock);
00173 
00174     return typoid;
00175 }
00176 
00177 /* ----------------------------------------------------------------
00178  *      TypeCreate
00179  *
00180  *      This does all the necessary work needed to define a new type.
00181  *
00182  *      Returns the OID assigned to the new type.  If newTypeOid is
00183  *      zero (the normal case), a new OID is created; otherwise we
00184  *      use exactly that OID.
00185  * ----------------------------------------------------------------
00186  */
00187 Oid
00188 TypeCreate(Oid newTypeOid,
00189            const char *typeName,
00190            Oid typeNamespace,
00191            Oid relationOid,     /* only for relation rowtypes */
00192            char relationKind,   /* ditto */
00193            Oid ownerId,
00194            int16 internalSize,
00195            char typeType,
00196            char typeCategory,
00197            bool typePreferred,
00198            char typDelim,
00199            Oid inputProcedure,
00200            Oid outputProcedure,
00201            Oid receiveProcedure,
00202            Oid sendProcedure,
00203            Oid typmodinProcedure,
00204            Oid typmodoutProcedure,
00205            Oid analyzeProcedure,
00206            Oid elementType,
00207            bool isImplicitArray,
00208            Oid arrayType,
00209            Oid baseType,
00210            const char *defaultTypeValue,        /* human readable rep */
00211            char *defaultTypeBin,    /* cooked rep */
00212            bool passedByValue,
00213            char alignment,
00214            char storage,
00215            int32 typeMod,
00216            int32 typNDims,      /* Array dimensions for baseType */
00217            bool typeNotNull,
00218            Oid typeCollation)
00219 {
00220     Relation    pg_type_desc;
00221     Oid         typeObjectId;
00222     bool        rebuildDeps = false;
00223     HeapTuple   tup;
00224     bool        nulls[Natts_pg_type];
00225     bool        replaces[Natts_pg_type];
00226     Datum       values[Natts_pg_type];
00227     NameData    name;
00228     int         i;
00229     Acl        *typacl = NULL;
00230 
00231     /*
00232      * We assume that the caller validated the arguments individually, but did
00233      * not check for bad combinations.
00234      *
00235      * Validate size specifications: either positive (fixed-length) or -1
00236      * (varlena) or -2 (cstring).
00237      */
00238     if (!(internalSize > 0 ||
00239           internalSize == -1 ||
00240           internalSize == -2))
00241         ereport(ERROR,
00242                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00243                  errmsg("invalid type internal size %d",
00244                         internalSize)));
00245 
00246     if (passedByValue)
00247     {
00248         /*
00249          * Pass-by-value types must have a fixed length that is one of the
00250          * values supported by fetch_att() and store_att_byval(); and the
00251          * alignment had better agree, too.  All this code must match
00252          * access/tupmacs.h!
00253          */
00254         if (internalSize == (int16) sizeof(char))
00255         {
00256             if (alignment != 'c')
00257                 ereport(ERROR,
00258                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00259                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
00260                                 alignment, internalSize)));
00261         }
00262         else if (internalSize == (int16) sizeof(int16))
00263         {
00264             if (alignment != 's')
00265                 ereport(ERROR,
00266                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00267                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
00268                                 alignment, internalSize)));
00269         }
00270         else if (internalSize == (int16) sizeof(int32))
00271         {
00272             if (alignment != 'i')
00273                 ereport(ERROR,
00274                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00275                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
00276                                 alignment, internalSize)));
00277         }
00278 #if SIZEOF_DATUM == 8
00279         else if (internalSize == (int16) sizeof(Datum))
00280         {
00281             if (alignment != 'd')
00282                 ereport(ERROR,
00283                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00284                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
00285                                 alignment, internalSize)));
00286         }
00287 #endif
00288         else
00289             ereport(ERROR,
00290                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00291                errmsg("internal size %d is invalid for passed-by-value type",
00292                       internalSize)));
00293     }
00294     else
00295     {
00296         /* varlena types must have int align or better */
00297         if (internalSize == -1 && !(alignment == 'i' || alignment == 'd'))
00298             ereport(ERROR,
00299                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00300                errmsg("alignment \"%c\" is invalid for variable-length type",
00301                       alignment)));
00302         /* cstring must have char alignment */
00303         if (internalSize == -2 && !(alignment == 'c'))
00304             ereport(ERROR,
00305                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00306                errmsg("alignment \"%c\" is invalid for variable-length type",
00307                       alignment)));
00308     }
00309 
00310     /* Only varlena types can be toasted */
00311     if (storage != 'p' && internalSize != -1)
00312         ereport(ERROR,
00313                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00314                  errmsg("fixed-size types must have storage PLAIN")));
00315 
00316     /*
00317      * initialize arrays needed for heap_form_tuple or heap_modify_tuple
00318      */
00319     for (i = 0; i < Natts_pg_type; ++i)
00320     {
00321         nulls[i] = false;
00322         replaces[i] = true;
00323         values[i] = (Datum) 0;
00324     }
00325 
00326     /*
00327      * insert data values
00328      */
00329     namestrcpy(&name, typeName);
00330     values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
00331     values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
00332     values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
00333     values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
00334     values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
00335     values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
00336     values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
00337     values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
00338     values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
00339     values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
00340     values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
00341     values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
00342     values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
00343     values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
00344     values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
00345     values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
00346     values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
00347     values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
00348     values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
00349     values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
00350     values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
00351     values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
00352     values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
00353     values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
00354     values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
00355     values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
00356     values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
00357 
00358     /*
00359      * initialize the default binary value for this type.  Check for nulls of
00360      * course.
00361      */
00362     if (defaultTypeBin)
00363         values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
00364     else
00365         nulls[Anum_pg_type_typdefaultbin - 1] = true;
00366 
00367     /*
00368      * initialize the default value for this type.
00369      */
00370     if (defaultTypeValue)
00371         values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
00372     else
00373         nulls[Anum_pg_type_typdefault - 1] = true;
00374 
00375     typacl = get_user_default_acl(ACL_OBJECT_TYPE, ownerId,
00376                                   typeNamespace);
00377     if (typacl != NULL)
00378         values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
00379     else
00380         nulls[Anum_pg_type_typacl - 1] = true;
00381 
00382     /*
00383      * open pg_type and prepare to insert or update a row.
00384      *
00385      * NOTE: updating will not work correctly in bootstrap mode; but we don't
00386      * expect to be overwriting any shell types in bootstrap mode.
00387      */
00388     pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
00389 
00390     tup = SearchSysCacheCopy2(TYPENAMENSP,
00391                               CStringGetDatum(typeName),
00392                               ObjectIdGetDatum(typeNamespace));
00393     if (HeapTupleIsValid(tup))
00394     {
00395         /*
00396          * check that the type is not already defined.  It may exist as a
00397          * shell type, however.
00398          */
00399         if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
00400             ereport(ERROR,
00401                     (errcode(ERRCODE_DUPLICATE_OBJECT),
00402                      errmsg("type \"%s\" already exists", typeName)));
00403 
00404         /*
00405          * shell type must have been created by same owner
00406          */
00407         if (((Form_pg_type) GETSTRUCT(tup))->typowner != ownerId)
00408             aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);
00409 
00410         /* trouble if caller wanted to force the OID */
00411         if (OidIsValid(newTypeOid))
00412             elog(ERROR, "cannot assign new OID to existing shell type");
00413 
00414         /*
00415          * Okay to update existing shell type tuple
00416          */
00417         tup = heap_modify_tuple(tup,
00418                                 RelationGetDescr(pg_type_desc),
00419                                 values,
00420                                 nulls,
00421                                 replaces);
00422 
00423         simple_heap_update(pg_type_desc, &tup->t_self, tup);
00424 
00425         typeObjectId = HeapTupleGetOid(tup);
00426 
00427         rebuildDeps = true;     /* get rid of shell type's dependencies */
00428     }
00429     else
00430     {
00431         tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
00432                               values,
00433                               nulls);
00434 
00435         /* Force the OID if requested by caller */
00436         if (OidIsValid(newTypeOid))
00437             HeapTupleSetOid(tup, newTypeOid);
00438         /* Use binary-upgrade override for pg_type.oid, if supplied. */
00439         else if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_pg_type_oid))
00440         {
00441             HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
00442             binary_upgrade_next_pg_type_oid = InvalidOid;
00443         }
00444         /* else allow system to assign oid */
00445 
00446         typeObjectId = simple_heap_insert(pg_type_desc, tup);
00447     }
00448 
00449     /* Update indexes */
00450     CatalogUpdateIndexes(pg_type_desc, tup);
00451 
00452     /*
00453      * Create dependencies.  We can/must skip this in bootstrap mode.
00454      */
00455     if (!IsBootstrapProcessingMode())
00456         GenerateTypeDependencies(typeNamespace,
00457                                  typeObjectId,
00458                                  relationOid,
00459                                  relationKind,
00460                                  ownerId,
00461                                  inputProcedure,
00462                                  outputProcedure,
00463                                  receiveProcedure,
00464                                  sendProcedure,
00465                                  typmodinProcedure,
00466                                  typmodoutProcedure,
00467                                  analyzeProcedure,
00468                                  elementType,
00469                                  isImplicitArray,
00470                                  baseType,
00471                                  typeCollation,
00472                                  (defaultTypeBin ?
00473                                   stringToNode(defaultTypeBin) :
00474                                   NULL),
00475                                  rebuildDeps);
00476 
00477     /* Post creation hook for new type */
00478     InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
00479 
00480     /*
00481      * finish up
00482      */
00483     heap_close(pg_type_desc, RowExclusiveLock);
00484 
00485     return typeObjectId;
00486 }
00487 
00488 /*
00489  * GenerateTypeDependencies: build the dependencies needed for a type
00490  *
00491  * If rebuild is true, we remove existing dependencies and rebuild them
00492  * from scratch.  This is needed for ALTER TYPE, and also when replacing
00493  * a shell type.  We don't remove an existing extension dependency, though.
00494  * (That means an extension can't absorb a shell type created in another
00495  * extension, nor ALTER a type created by another extension.  Also, if it
00496  * replaces a free-standing shell type or ALTERs a free-standing type,
00497  * that type will become a member of the extension.)
00498  */
00499 void
00500 GenerateTypeDependencies(Oid typeNamespace,
00501                          Oid typeObjectId,
00502                          Oid relationOid,       /* only for relation rowtypes */
00503                          char relationKind,     /* ditto */
00504                          Oid owner,
00505                          Oid inputProcedure,
00506                          Oid outputProcedure,
00507                          Oid receiveProcedure,
00508                          Oid sendProcedure,
00509                          Oid typmodinProcedure,
00510                          Oid typmodoutProcedure,
00511                          Oid analyzeProcedure,
00512                          Oid elementType,
00513                          bool isImplicitArray,
00514                          Oid baseType,
00515                          Oid typeCollation,
00516                          Node *defaultExpr,
00517                          bool rebuild)
00518 {
00519     ObjectAddress myself,
00520                 referenced;
00521 
00522     /* If rebuild, first flush old dependencies, except extension deps */
00523     if (rebuild)
00524     {
00525         deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
00526         deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
00527     }
00528 
00529     myself.classId = TypeRelationId;
00530     myself.objectId = typeObjectId;
00531     myself.objectSubId = 0;
00532 
00533     /*
00534      * Make dependencies on namespace, owner, extension.
00535      *
00536      * For a relation rowtype (that's not a composite type), we should skip
00537      * these because we'll depend on them indirectly through the pg_class
00538      * entry.  Likewise, skip for implicit arrays since we'll depend on them
00539      * through the element type.
00540      */
00541     if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) &&
00542         !isImplicitArray)
00543     {
00544         referenced.classId = NamespaceRelationId;
00545         referenced.objectId = typeNamespace;
00546         referenced.objectSubId = 0;
00547         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00548 
00549         recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
00550 
00551         recordDependencyOnCurrentExtension(&myself, rebuild);
00552     }
00553 
00554     /* Normal dependencies on the I/O functions */
00555     if (OidIsValid(inputProcedure))
00556     {
00557         referenced.classId = ProcedureRelationId;
00558         referenced.objectId = inputProcedure;
00559         referenced.objectSubId = 0;
00560         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00561     }
00562 
00563     if (OidIsValid(outputProcedure))
00564     {
00565         referenced.classId = ProcedureRelationId;
00566         referenced.objectId = outputProcedure;
00567         referenced.objectSubId = 0;
00568         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00569     }
00570 
00571     if (OidIsValid(receiveProcedure))
00572     {
00573         referenced.classId = ProcedureRelationId;
00574         referenced.objectId = receiveProcedure;
00575         referenced.objectSubId = 0;
00576         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00577     }
00578 
00579     if (OidIsValid(sendProcedure))
00580     {
00581         referenced.classId = ProcedureRelationId;
00582         referenced.objectId = sendProcedure;
00583         referenced.objectSubId = 0;
00584         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00585     }
00586 
00587     if (OidIsValid(typmodinProcedure))
00588     {
00589         referenced.classId = ProcedureRelationId;
00590         referenced.objectId = typmodinProcedure;
00591         referenced.objectSubId = 0;
00592         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00593     }
00594 
00595     if (OidIsValid(typmodoutProcedure))
00596     {
00597         referenced.classId = ProcedureRelationId;
00598         referenced.objectId = typmodoutProcedure;
00599         referenced.objectSubId = 0;
00600         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00601     }
00602 
00603     if (OidIsValid(analyzeProcedure))
00604     {
00605         referenced.classId = ProcedureRelationId;
00606         referenced.objectId = analyzeProcedure;
00607         referenced.objectSubId = 0;
00608         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00609     }
00610 
00611     /*
00612      * If the type is a rowtype for a relation, mark it as internally
00613      * dependent on the relation, *unless* it is a stand-alone composite type
00614      * relation. For the latter case, we have to reverse the dependency.
00615      *
00616      * In the former case, this allows the type to be auto-dropped when the
00617      * relation is, and not otherwise. And in the latter, of course we get the
00618      * opposite effect.
00619      */
00620     if (OidIsValid(relationOid))
00621     {
00622         referenced.classId = RelationRelationId;
00623         referenced.objectId = relationOid;
00624         referenced.objectSubId = 0;
00625 
00626         if (relationKind != RELKIND_COMPOSITE_TYPE)
00627             recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
00628         else
00629             recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
00630     }
00631 
00632     /*
00633      * If the type is an implicitly-created array type, mark it as internally
00634      * dependent on the element type.  Otherwise, if it has an element type,
00635      * the dependency is a normal one.
00636      */
00637     if (OidIsValid(elementType))
00638     {
00639         referenced.classId = TypeRelationId;
00640         referenced.objectId = elementType;
00641         referenced.objectSubId = 0;
00642         recordDependencyOn(&myself, &referenced,
00643                   isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
00644     }
00645 
00646     /* Normal dependency from a domain to its base type. */
00647     if (OidIsValid(baseType))
00648     {
00649         referenced.classId = TypeRelationId;
00650         referenced.objectId = baseType;
00651         referenced.objectSubId = 0;
00652         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00653     }
00654 
00655     /* Normal dependency from a domain to its collation. */
00656     /* We know the default collation is pinned, so don't bother recording it */
00657     if (OidIsValid(typeCollation) && typeCollation != DEFAULT_COLLATION_OID)
00658     {
00659         referenced.classId = CollationRelationId;
00660         referenced.objectId = typeCollation;
00661         referenced.objectSubId = 0;
00662         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00663     }
00664 
00665     /* Normal dependency on the default expression. */
00666     if (defaultExpr)
00667         recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
00668 }
00669 
00670 /*
00671  * RenameTypeInternal
00672  *      This renames a type, as well as any associated array type.
00673  *
00674  * Caller must have already checked privileges.
00675  *
00676  * Currently this is used for renaming table rowtypes and for
00677  * ALTER TYPE RENAME TO command.
00678  */
00679 void
00680 RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
00681 {
00682     Relation    pg_type_desc;
00683     HeapTuple   tuple;
00684     Form_pg_type typ;
00685     Oid         arrayOid;
00686 
00687     pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
00688 
00689     tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
00690     if (!HeapTupleIsValid(tuple))
00691         elog(ERROR, "cache lookup failed for type %u", typeOid);
00692     typ = (Form_pg_type) GETSTRUCT(tuple);
00693 
00694     /* We are not supposed to be changing schemas here */
00695     Assert(typeNamespace == typ->typnamespace);
00696 
00697     arrayOid = typ->typarray;
00698 
00699     /* Just to give a more friendly error than unique-index violation */
00700     if (SearchSysCacheExists2(TYPENAMENSP,
00701                               CStringGetDatum(newTypeName),
00702                               ObjectIdGetDatum(typeNamespace)))
00703         ereport(ERROR,
00704                 (errcode(ERRCODE_DUPLICATE_OBJECT),
00705                  errmsg("type \"%s\" already exists", newTypeName)));
00706 
00707     /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
00708     namestrcpy(&(typ->typname), newTypeName);
00709 
00710     simple_heap_update(pg_type_desc, &tuple->t_self, tuple);
00711 
00712     /* update the system catalog indexes */
00713     CatalogUpdateIndexes(pg_type_desc, tuple);
00714 
00715     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
00716 
00717     heap_freetuple(tuple);
00718     heap_close(pg_type_desc, RowExclusiveLock);
00719 
00720     /* If the type has an array type, recurse to handle that */
00721     if (OidIsValid(arrayOid))
00722     {
00723         char       *arrname = makeArrayTypeName(newTypeName, typeNamespace);
00724 
00725         RenameTypeInternal(arrayOid, arrname, typeNamespace);
00726         pfree(arrname);
00727     }
00728 }
00729 
00730 
00731 /*
00732  * makeArrayTypeName
00733  *    - given a base type name, make an array type name for it
00734  *
00735  * the caller is responsible for pfreeing the result
00736  */
00737 char *
00738 makeArrayTypeName(const char *typeName, Oid typeNamespace)
00739 {
00740     char       *arr = (char *) palloc(NAMEDATALEN);
00741     int         namelen = strlen(typeName);
00742     Relation    pg_type_desc;
00743     int         i;
00744 
00745     /*
00746      * The idea is to prepend underscores as needed until we make a name that
00747      * doesn't collide with anything...
00748      */
00749     pg_type_desc = heap_open(TypeRelationId, AccessShareLock);
00750 
00751     for (i = 1; i < NAMEDATALEN - 1; i++)
00752     {
00753         arr[i - 1] = '_';
00754         if (i + namelen < NAMEDATALEN)
00755             strcpy(arr + i, typeName);
00756         else
00757         {
00758             memcpy(arr + i, typeName, NAMEDATALEN - i);
00759             truncate_identifier(arr, NAMEDATALEN, false);
00760         }
00761         if (!SearchSysCacheExists2(TYPENAMENSP,
00762                                    CStringGetDatum(arr),
00763                                    ObjectIdGetDatum(typeNamespace)))
00764             break;
00765     }
00766 
00767     heap_close(pg_type_desc, AccessShareLock);
00768 
00769     if (i >= NAMEDATALEN - 1)
00770         ereport(ERROR,
00771                 (errcode(ERRCODE_DUPLICATE_OBJECT),
00772                  errmsg("could not form array type name for type \"%s\"",
00773                         typeName)));
00774 
00775     return arr;
00776 }
00777 
00778 
00779 /*
00780  * moveArrayTypeName
00781  *    - try to reassign an array type name that the user wants to use.
00782  *
00783  * The given type name has been discovered to already exist (with the given
00784  * OID).  If it is an autogenerated array type, change the array type's name
00785  * to not conflict.  This allows the user to create type "foo" followed by
00786  * type "_foo" without problems.  (Of course, there are race conditions if
00787  * two backends try to create similarly-named types concurrently, but the
00788  * worst that can happen is an unnecessary failure --- anything we do here
00789  * will be rolled back if the type creation fails due to conflicting names.)
00790  *
00791  * Note that this must be called *before* calling makeArrayTypeName to
00792  * determine the new type's own array type name; else the latter will
00793  * certainly pick the same name.
00794  *
00795  * Returns TRUE if successfully moved the type, FALSE if not.
00796  *
00797  * We also return TRUE if the given type is a shell type.  In this case
00798  * the type has not been renamed out of the way, but nonetheless it can
00799  * be expected that TypeCreate will succeed.  This behavior is convenient
00800  * for most callers --- those that need to distinguish the shell-type case
00801  * must do their own typisdefined test.
00802  */
00803 bool
00804 moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
00805 {
00806     Oid         elemOid;
00807     char       *newname;
00808 
00809     /* We need do nothing if it's a shell type. */
00810     if (!get_typisdefined(typeOid))
00811         return true;
00812 
00813     /* Can't change it if it's not an autogenerated array type. */
00814     elemOid = get_element_type(typeOid);
00815     if (!OidIsValid(elemOid) ||
00816         get_array_type(elemOid) != typeOid)
00817         return false;
00818 
00819     /*
00820      * OK, use makeArrayTypeName to pick an unused modification of the name.
00821      * Note that since makeArrayTypeName is an iterative process, this will
00822      * produce a name that it might have produced the first time, had the
00823      * conflicting type we are about to create already existed.
00824      */
00825     newname = makeArrayTypeName(typeName, typeNamespace);
00826 
00827     /* Apply the rename */
00828     RenameTypeInternal(typeOid, newname, typeNamespace);
00829 
00830     /*
00831      * We must bump the command counter so that any subsequent use of
00832      * makeArrayTypeName sees what we just did and doesn't pick the same name.
00833      */
00834     CommandCounterIncrement();
00835 
00836     pfree(newname);
00837 
00838     return true;
00839 }