LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_type.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 243 269 90.3 %
Date: 2017-09-29 13:40:31 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_type.c
       4             :  *    routines to support manipulation of the pg_type relation
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/catalog/pg_type.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "access/heapam.h"
      18             : #include "access/htup_details.h"
      19             : #include "access/xact.h"
      20             : #include "catalog/binary_upgrade.h"
      21             : #include "catalog/dependency.h"
      22             : #include "catalog/indexing.h"
      23             : #include "catalog/objectaccess.h"
      24             : #include "catalog/pg_collation.h"
      25             : #include "catalog/pg_namespace.h"
      26             : #include "catalog/pg_proc.h"
      27             : #include "catalog/pg_type.h"
      28             : #include "catalog/pg_type_fn.h"
      29             : #include "commands/typecmds.h"
      30             : #include "miscadmin.h"
      31             : #include "parser/scansup.h"
      32             : #include "utils/acl.h"
      33             : #include "utils/builtins.h"
      34             : #include "utils/fmgroids.h"
      35             : #include "utils/lsyscache.h"
      36             : #include "utils/rel.h"
      37             : #include "utils/syscache.h"
      38             : 
      39             : /* Potentially set by pg_upgrade_support functions */
      40             : Oid         binary_upgrade_next_pg_type_oid = InvalidOid;
      41             : 
      42             : /* ----------------------------------------------------------------
      43             :  *      TypeShellMake
      44             :  *
      45             :  *      This procedure inserts a "shell" tuple into the pg_type relation.
      46             :  *      The type tuple inserted has valid but dummy values, and its
      47             :  *      "typisdefined" field is false indicating it's not really defined.
      48             :  *
      49             :  *      This is used so that a tuple exists in the catalogs.  The I/O
      50             :  *      functions for the type will link to this tuple.  When the full
      51             :  *      CREATE TYPE command is issued, the bogus values will be replaced
      52             :  *      with correct ones, and "typisdefined" will be set to true.
      53             :  * ----------------------------------------------------------------
      54             :  */
      55             : ObjectAddress
      56          21 : TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
      57             : {
      58             :     Relation    pg_type_desc;
      59             :     TupleDesc   tupDesc;
      60             :     int         i;
      61             :     HeapTuple   tup;
      62             :     Datum       values[Natts_pg_type];
      63             :     bool        nulls[Natts_pg_type];
      64             :     Oid         typoid;
      65             :     NameData    name;
      66             :     ObjectAddress address;
      67             : 
      68          21 :     Assert(PointerIsValid(typeName));
      69             : 
      70             :     /*
      71             :      * open pg_type
      72             :      */
      73          21 :     pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
      74          21 :     tupDesc = pg_type_desc->rd_att;
      75             : 
      76             :     /*
      77             :      * initialize our *nulls and *values arrays
      78             :      */
      79         651 :     for (i = 0; i < Natts_pg_type; ++i)
      80             :     {
      81         630 :         nulls[i] = false;
      82         630 :         values[i] = (Datum) NULL;   /* redundant, but safe */
      83             :     }
      84             : 
      85             :     /*
      86             :      * initialize *values with the type name and dummy values
      87             :      *
      88             :      * The representational details are the same as int4 ... it doesn't really
      89             :      * matter what they are so long as they are consistent.  Also note that we
      90             :      * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
      91             :      * mistaken for a usable type.
      92             :      */
      93          21 :     namestrcpy(&name, typeName);
      94          21 :     values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
      95          21 :     values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
      96          21 :     values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
      97          21 :     values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
      98          21 :     values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
      99          21 :     values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
     100          21 :     values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
     101          21 :     values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
     102          21 :     values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
     103          21 :     values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
     104          21 :     values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
     105          21 :     values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
     106          21 :     values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
     107          21 :     values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
     108          21 :     values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
     109          21 :     values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
     110          21 :     values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
     111          21 :     values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
     112          21 :     values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
     113          21 :     values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
     114          21 :     values[Anum_pg_type_typalign - 1] = CharGetDatum('i');
     115          21 :     values[Anum_pg_type_typstorage - 1] = CharGetDatum('p');
     116          21 :     values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
     117          21 :     values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
     118          21 :     values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
     119          21 :     values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
     120          21 :     values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
     121          21 :     nulls[Anum_pg_type_typdefaultbin - 1] = true;
     122          21 :     nulls[Anum_pg_type_typdefault - 1] = true;
     123          21 :     nulls[Anum_pg_type_typacl - 1] = true;
     124             : 
     125             :     /*
     126             :      * create a new type tuple
     127             :      */
     128          21 :     tup = heap_form_tuple(tupDesc, values, nulls);
     129             : 
     130             :     /* Use binary-upgrade override for pg_type.oid? */
     131          21 :     if (IsBinaryUpgrade)
     132             :     {
     133           0 :         if (!OidIsValid(binary_upgrade_next_pg_type_oid))
     134           0 :             ereport(ERROR,
     135             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     136             :                      errmsg("pg_type OID value not set when in binary upgrade mode")));
     137             : 
     138           0 :         HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
     139           0 :         binary_upgrade_next_pg_type_oid = InvalidOid;
     140             :     }
     141             : 
     142             :     /*
     143             :      * insert the tuple in the relation and get the tuple's oid.
     144             :      */
     145          21 :     typoid = CatalogTupleInsert(pg_type_desc, tup);
     146             : 
     147             :     /*
     148             :      * Create dependencies.  We can/must skip this in bootstrap mode.
     149             :      */
     150          21 :     if (!IsBootstrapProcessingMode())
     151          21 :         GenerateTypeDependencies(typeNamespace,
     152             :                                  typoid,
     153             :                                  InvalidOid,
     154             :                                  0,
     155             :                                  ownerId,
     156             :                                  F_SHELL_IN,
     157             :                                  F_SHELL_OUT,
     158             :                                  InvalidOid,
     159             :                                  InvalidOid,
     160             :                                  InvalidOid,
     161             :                                  InvalidOid,
     162             :                                  InvalidOid,
     163             :                                  InvalidOid,
     164             :                                  false,
     165             :                                  InvalidOid,
     166             :                                  InvalidOid,
     167             :                                  NULL,
     168             :                                  false);
     169             : 
     170             :     /* Post creation hook for new shell type */
     171          21 :     InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
     172             : 
     173          21 :     ObjectAddressSet(address, TypeRelationId, typoid);
     174             : 
     175             :     /*
     176             :      * clean up and return the type-oid
     177             :      */
     178          21 :     heap_freetuple(tup);
     179          21 :     heap_close(pg_type_desc, RowExclusiveLock);
     180             : 
     181          21 :     return address;
     182             : }
     183             : 
     184             : /* ----------------------------------------------------------------
     185             :  *      TypeCreate
     186             :  *
     187             :  *      This does all the necessary work needed to define a new type.
     188             :  *
     189             :  *      Returns the ObjectAddress assigned to the new type.
     190             :  *      If newTypeOid is zero (the normal case), a new OID is created;
     191             :  *      otherwise we use exactly that OID.
     192             :  * ----------------------------------------------------------------
     193             :  */
     194             : ObjectAddress
     195        5104 : TypeCreate(Oid newTypeOid,
     196             :            const char *typeName,
     197             :            Oid typeNamespace,
     198             :            Oid relationOid,     /* only for relation rowtypes */
     199             :            char relationKind,   /* ditto */
     200             :            Oid ownerId,
     201             :            int16 internalSize,
     202             :            char typeType,
     203             :            char typeCategory,
     204             :            bool typePreferred,
     205             :            char typDelim,
     206             :            Oid inputProcedure,
     207             :            Oid outputProcedure,
     208             :            Oid receiveProcedure,
     209             :            Oid sendProcedure,
     210             :            Oid typmodinProcedure,
     211             :            Oid typmodoutProcedure,
     212             :            Oid analyzeProcedure,
     213             :            Oid elementType,
     214             :            bool isImplicitArray,
     215             :            Oid arrayType,
     216             :            Oid baseType,
     217             :            const char *defaultTypeValue,    /* human readable rep */
     218             :            char *defaultTypeBin,    /* cooked rep */
     219             :            bool passedByValue,
     220             :            char alignment,
     221             :            char storage,
     222             :            int32 typeMod,
     223             :            int32 typNDims,      /* Array dimensions for baseType */
     224             :            bool typeNotNull,
     225             :            Oid typeCollation)
     226             : {
     227             :     Relation    pg_type_desc;
     228             :     Oid         typeObjectId;
     229        5104 :     bool        rebuildDeps = false;
     230             :     HeapTuple   tup;
     231             :     bool        nulls[Natts_pg_type];
     232             :     bool        replaces[Natts_pg_type];
     233             :     Datum       values[Natts_pg_type];
     234             :     NameData    name;
     235             :     int         i;
     236        5104 :     Acl        *typacl = NULL;
     237             :     ObjectAddress address;
     238             : 
     239             :     /*
     240             :      * We assume that the caller validated the arguments individually, but did
     241             :      * not check for bad combinations.
     242             :      *
     243             :      * Validate size specifications: either positive (fixed-length) or -1
     244             :      * (varlena) or -2 (cstring).
     245             :      */
     246        5104 :     if (!(internalSize > 0 ||
     247             :           internalSize == -1 ||
     248             :           internalSize == -2))
     249           0 :         ereport(ERROR,
     250             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     251             :                  errmsg("invalid type internal size %d",
     252             :                         internalSize)));
     253             : 
     254        5104 :     if (passedByValue)
     255             :     {
     256             :         /*
     257             :          * Pass-by-value types must have a fixed length that is one of the
     258             :          * values supported by fetch_att() and store_att_byval(); and the
     259             :          * alignment had better agree, too.  All this code must match
     260             :          * access/tupmacs.h!
     261             :          */
     262          51 :         if (internalSize == (int16) sizeof(char))
     263             :         {
     264           1 :             if (alignment != 'c')
     265           0 :                 ereport(ERROR,
     266             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     267             :                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
     268             :                                 alignment, internalSize)));
     269             :         }
     270          50 :         else if (internalSize == (int16) sizeof(int16))
     271             :         {
     272           0 :             if (alignment != 's')
     273           0 :                 ereport(ERROR,
     274             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     275             :                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
     276             :                                 alignment, internalSize)));
     277             :         }
     278          50 :         else if (internalSize == (int16) sizeof(int32))
     279             :         {
     280          50 :             if (alignment != 'i')
     281           0 :                 ereport(ERROR,
     282             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     283             :                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
     284             :                                 alignment, internalSize)));
     285             :         }
     286             : #if SIZEOF_DATUM == 8
     287             :         else if (internalSize == (int16) sizeof(Datum))
     288             :         {
     289             :             if (alignment != 'd')
     290             :                 ereport(ERROR,
     291             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     292             :                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
     293             :                                 alignment, internalSize)));
     294             :         }
     295             : #endif
     296             :         else
     297           0 :             ereport(ERROR,
     298             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     299             :                      errmsg("internal size %d is invalid for passed-by-value type",
     300             :                             internalSize)));
     301             :     }
     302             :     else
     303             :     {
     304             :         /* varlena types must have int align or better */
     305        5053 :         if (internalSize == -1 && !(alignment == 'i' || alignment == 'd'))
     306           0 :             ereport(ERROR,
     307             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     308             :                      errmsg("alignment \"%c\" is invalid for variable-length type",
     309             :                             alignment)));
     310             :         /* cstring must have char alignment */
     311        5053 :         if (internalSize == -2 && !(alignment == 'c'))
     312           0 :             ereport(ERROR,
     313             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     314             :                      errmsg("alignment \"%c\" is invalid for variable-length type",
     315             :                             alignment)));
     316             :     }
     317             : 
     318             :     /* Only varlena types can be toasted */
     319        5104 :     if (storage != 'p' && internalSize != -1)
     320           0 :         ereport(ERROR,
     321             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     322             :                  errmsg("fixed-size types must have storage PLAIN")));
     323             : 
     324             :     /*
     325             :      * initialize arrays needed for heap_form_tuple or heap_modify_tuple
     326             :      */
     327      158224 :     for (i = 0; i < Natts_pg_type; ++i)
     328             :     {
     329      153120 :         nulls[i] = false;
     330      153120 :         replaces[i] = true;
     331      153120 :         values[i] = (Datum) 0;
     332             :     }
     333             : 
     334             :     /*
     335             :      * insert data values
     336             :      */
     337        5104 :     namestrcpy(&name, typeName);
     338        5104 :     values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
     339        5104 :     values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
     340        5104 :     values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
     341        5104 :     values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
     342        5104 :     values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
     343        5104 :     values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
     344        5104 :     values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
     345        5104 :     values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
     346        5104 :     values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
     347        5104 :     values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
     348        5104 :     values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
     349        5104 :     values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
     350        5104 :     values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
     351        5104 :     values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
     352        5104 :     values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
     353        5104 :     values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
     354        5104 :     values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
     355        5104 :     values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
     356        5104 :     values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
     357        5104 :     values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
     358        5104 :     values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
     359        5104 :     values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
     360        5104 :     values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
     361        5104 :     values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
     362        5104 :     values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
     363        5104 :     values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
     364        5104 :     values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
     365             : 
     366             :     /*
     367             :      * initialize the default binary value for this type.  Check for nulls of
     368             :      * course.
     369             :      */
     370        5104 :     if (defaultTypeBin)
     371           7 :         values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
     372             :     else
     373        5097 :         nulls[Anum_pg_type_typdefaultbin - 1] = true;
     374             : 
     375             :     /*
     376             :      * initialize the default value for this type.
     377             :      */
     378        5104 :     if (defaultTypeValue)
     379           9 :         values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
     380             :     else
     381        5095 :         nulls[Anum_pg_type_typdefault - 1] = true;
     382             : 
     383        5104 :     typacl = get_user_default_acl(ACL_OBJECT_TYPE, ownerId,
     384             :                                   typeNamespace);
     385        5104 :     if (typacl != NULL)
     386           3 :         values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
     387             :     else
     388        5101 :         nulls[Anum_pg_type_typacl - 1] = true;
     389             : 
     390             :     /*
     391             :      * open pg_type and prepare to insert or update a row.
     392             :      *
     393             :      * NOTE: updating will not work correctly in bootstrap mode; but we don't
     394             :      * expect to be overwriting any shell types in bootstrap mode.
     395             :      */
     396        5104 :     pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
     397             : 
     398        5104 :     tup = SearchSysCacheCopy2(TYPENAMENSP,
     399             :                               CStringGetDatum(typeName),
     400             :                               ObjectIdGetDatum(typeNamespace));
     401        5104 :     if (HeapTupleIsValid(tup))
     402             :     {
     403             :         /*
     404             :          * check that the type is not already defined.  It may exist as a
     405             :          * shell type, however.
     406             :          */
     407          17 :         if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
     408           0 :             ereport(ERROR,
     409             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
     410             :                      errmsg("type \"%s\" already exists", typeName)));
     411             : 
     412             :         /*
     413             :          * shell type must have been created by same owner
     414             :          */
     415          17 :         if (((Form_pg_type) GETSTRUCT(tup))->typowner != ownerId)
     416           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);
     417             : 
     418             :         /* trouble if caller wanted to force the OID */
     419          17 :         if (OidIsValid(newTypeOid))
     420           0 :             elog(ERROR, "cannot assign new OID to existing shell type");
     421             : 
     422             :         /*
     423             :          * Okay to update existing shell type tuple
     424             :          */
     425          17 :         tup = heap_modify_tuple(tup,
     426             :                                 RelationGetDescr(pg_type_desc),
     427             :                                 values,
     428             :                                 nulls,
     429             :                                 replaces);
     430             : 
     431          17 :         CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup);
     432             : 
     433          17 :         typeObjectId = HeapTupleGetOid(tup);
     434             : 
     435          17 :         rebuildDeps = true;     /* get rid of shell type's dependencies */
     436             :     }
     437             :     else
     438             :     {
     439        5087 :         tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
     440             :                               values,
     441             :                               nulls);
     442             : 
     443             :         /* Force the OID if requested by caller */
     444        5087 :         if (OidIsValid(newTypeOid))
     445        2012 :             HeapTupleSetOid(tup, newTypeOid);
     446             :         /* Use binary-upgrade override for pg_type.oid, if supplied. */
     447        3075 :         else if (IsBinaryUpgrade)
     448             :         {
     449           0 :             if (!OidIsValid(binary_upgrade_next_pg_type_oid))
     450           0 :                 ereport(ERROR,
     451             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     452             :                          errmsg("pg_type OID value not set when in binary upgrade mode")));
     453             : 
     454           0 :             HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
     455           0 :             binary_upgrade_next_pg_type_oid = InvalidOid;
     456             :         }
     457             :         /* else allow system to assign oid */
     458             : 
     459        5087 :         typeObjectId = CatalogTupleInsert(pg_type_desc, tup);
     460             :     }
     461             : 
     462             :     /*
     463             :      * Create dependencies.  We can/must skip this in bootstrap mode.
     464             :      */
     465        5104 :     if (!IsBootstrapProcessingMode())
     466        5034 :         GenerateTypeDependencies(typeNamespace,
     467             :                                  typeObjectId,
     468             :                                  relationOid,
     469             :                                  relationKind,
     470             :                                  ownerId,
     471             :                                  inputProcedure,
     472             :                                  outputProcedure,
     473             :                                  receiveProcedure,
     474             :                                  sendProcedure,
     475             :                                  typmodinProcedure,
     476             :                                  typmodoutProcedure,
     477             :                                  analyzeProcedure,
     478             :                                  elementType,
     479             :                                  isImplicitArray,
     480             :                                  baseType,
     481             :                                  typeCollation,
     482             :                                  (defaultTypeBin ?
     483             :                                   stringToNode(defaultTypeBin) :
     484             :                                   NULL),
     485             :                                  rebuildDeps);
     486             : 
     487             :     /* Post creation hook for new type */
     488        5104 :     InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
     489             : 
     490        5104 :     ObjectAddressSet(address, TypeRelationId, typeObjectId);
     491             : 
     492             :     /*
     493             :      * finish up
     494             :      */
     495        5104 :     heap_close(pg_type_desc, RowExclusiveLock);
     496             : 
     497        5104 :     return address;
     498             : }
     499             : 
     500             : /*
     501             :  * GenerateTypeDependencies: build the dependencies needed for a type
     502             :  *
     503             :  * If rebuild is true, we remove existing dependencies and rebuild them
     504             :  * from scratch.  This is needed for ALTER TYPE, and also when replacing
     505             :  * a shell type.  We don't remove an existing extension dependency, though.
     506             :  * (That means an extension can't absorb a shell type created in another
     507             :  * extension, nor ALTER a type created by another extension.  Also, if it
     508             :  * replaces a free-standing shell type or ALTERs a free-standing type,
     509             :  * that type will become a member of the extension.)
     510             :  */
     511             : void
     512        5057 : GenerateTypeDependencies(Oid typeNamespace,
     513             :                          Oid typeObjectId,
     514             :                          Oid relationOid,   /* only for relation rowtypes */
     515             :                          char relationKind, /* ditto */
     516             :                          Oid owner,
     517             :                          Oid inputProcedure,
     518             :                          Oid outputProcedure,
     519             :                          Oid receiveProcedure,
     520             :                          Oid sendProcedure,
     521             :                          Oid typmodinProcedure,
     522             :                          Oid typmodoutProcedure,
     523             :                          Oid analyzeProcedure,
     524             :                          Oid elementType,
     525             :                          bool isImplicitArray,
     526             :                          Oid baseType,
     527             :                          Oid typeCollation,
     528             :                          Node *defaultExpr,
     529             :                          bool rebuild)
     530             : {
     531             :     ObjectAddress myself,
     532             :                 referenced;
     533             : 
     534             :     /* If rebuild, first flush old dependencies, except extension deps */
     535        5057 :     if (rebuild)
     536             :     {
     537          19 :         deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
     538          19 :         deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
     539             :     }
     540             : 
     541        5057 :     myself.classId = TypeRelationId;
     542        5057 :     myself.objectId = typeObjectId;
     543        5057 :     myself.objectSubId = 0;
     544             : 
     545             :     /*
     546             :      * Make dependencies on namespace, owner, extension.
     547             :      *
     548             :      * For a relation rowtype (that's not a composite type), we should skip
     549             :      * these because we'll depend on them indirectly through the pg_class
     550             :      * entry.  Likewise, skip for implicit arrays since we'll depend on them
     551             :      * through the element type.
     552             :      */
     553        5057 :     if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) &&
     554             :         !isImplicitArray)
     555             :     {
     556         179 :         referenced.classId = NamespaceRelationId;
     557         179 :         referenced.objectId = typeNamespace;
     558         179 :         referenced.objectSubId = 0;
     559         179 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     560             : 
     561         179 :         recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
     562             : 
     563         179 :         recordDependencyOnCurrentExtension(&myself, rebuild);
     564             :     }
     565             : 
     566             :     /* Normal dependencies on the I/O functions */
     567        5057 :     if (OidIsValid(inputProcedure))
     568             :     {
     569        5057 :         referenced.classId = ProcedureRelationId;
     570        5057 :         referenced.objectId = inputProcedure;
     571        5057 :         referenced.objectSubId = 0;
     572        5057 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     573             :     }
     574             : 
     575        5057 :     if (OidIsValid(outputProcedure))
     576             :     {
     577        5057 :         referenced.classId = ProcedureRelationId;
     578        5057 :         referenced.objectId = outputProcedure;
     579        5057 :         referenced.objectSubId = 0;
     580        5057 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     581             :     }
     582             : 
     583        5057 :     if (OidIsValid(receiveProcedure))
     584             :     {
     585        5028 :         referenced.classId = ProcedureRelationId;
     586        5028 :         referenced.objectId = receiveProcedure;
     587        5028 :         referenced.objectSubId = 0;
     588        5028 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     589             :     }
     590             : 
     591        5057 :     if (OidIsValid(sendProcedure))
     592             :     {
     593        5028 :         referenced.classId = ProcedureRelationId;
     594        5028 :         referenced.objectId = sendProcedure;
     595        5028 :         referenced.objectSubId = 0;
     596        5028 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     597             :     }
     598             : 
     599        5057 :     if (OidIsValid(typmodinProcedure))
     600             :     {
     601           2 :         referenced.classId = ProcedureRelationId;
     602           2 :         referenced.objectId = typmodinProcedure;
     603           2 :         referenced.objectSubId = 0;
     604           2 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     605             :     }
     606             : 
     607        5057 :     if (OidIsValid(typmodoutProcedure))
     608             :     {
     609           2 :         referenced.classId = ProcedureRelationId;
     610           2 :         referenced.objectId = typmodoutProcedure;
     611           2 :         referenced.objectSubId = 0;
     612           2 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     613             :     }
     614             : 
     615        5057 :     if (OidIsValid(analyzeProcedure))
     616             :     {
     617        2033 :         referenced.classId = ProcedureRelationId;
     618        2033 :         referenced.objectId = analyzeProcedure;
     619        2033 :         referenced.objectSubId = 0;
     620        2033 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     621             :     }
     622             : 
     623             :     /*
     624             :      * If the type is a rowtype for a relation, mark it as internally
     625             :      * dependent on the relation, *unless* it is a stand-alone composite type
     626             :      * relation. For the latter case, we have to reverse the dependency.
     627             :      *
     628             :      * In the former case, this allows the type to be auto-dropped when the
     629             :      * relation is, and not otherwise. And in the latter, of course we get the
     630             :      * opposite effect.
     631             :      */
     632        5057 :     if (OidIsValid(relationOid))
     633             :     {
     634        2920 :         referenced.classId = RelationRelationId;
     635        2920 :         referenced.objectId = relationOid;
     636        2920 :         referenced.objectSubId = 0;
     637             : 
     638        2920 :         if (relationKind != RELKIND_COMPOSITE_TYPE)
     639        2871 :             recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
     640             :         else
     641          49 :             recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
     642             :     }
     643             : 
     644             :     /*
     645             :      * If the type is an implicitly-created array type, mark it as internally
     646             :      * dependent on the element type.  Otherwise, if it has an element type,
     647             :      * the dependency is a normal one.
     648             :      */
     649        5057 :     if (OidIsValid(elementType))
     650             :     {
     651        2008 :         referenced.classId = TypeRelationId;
     652        2008 :         referenced.objectId = elementType;
     653        2008 :         referenced.objectSubId = 0;
     654        2008 :         recordDependencyOn(&myself, &referenced,
     655             :                            isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
     656             :     }
     657             : 
     658             :     /* Normal dependency from a domain to its base type. */
     659        5057 :     if (OidIsValid(baseType))
     660             :     {
     661          77 :         referenced.classId = TypeRelationId;
     662          77 :         referenced.objectId = baseType;
     663          77 :         referenced.objectSubId = 0;
     664          77 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     665             :     }
     666             : 
     667             :     /* Normal dependency from a domain to its collation. */
     668             :     /* We know the default collation is pinned, so don't bother recording it */
     669        5057 :     if (OidIsValid(typeCollation) && typeCollation != DEFAULT_COLLATION_OID)
     670             :     {
     671           1 :         referenced.classId = CollationRelationId;
     672           1 :         referenced.objectId = typeCollation;
     673           1 :         referenced.objectSubId = 0;
     674           1 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     675             :     }
     676             : 
     677             :     /* Normal dependency on the default expression. */
     678        5057 :     if (defaultExpr)
     679           8 :         recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
     680        5057 : }
     681             : 
     682             : /*
     683             :  * RenameTypeInternal
     684             :  *      This renames a type, as well as any associated array type.
     685             :  *
     686             :  * Caller must have already checked privileges.
     687             :  *
     688             :  * Currently this is used for renaming table rowtypes and for
     689             :  * ALTER TYPE RENAME TO command.
     690             :  */
     691             : void
     692          80 : RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
     693             : {
     694             :     Relation    pg_type_desc;
     695             :     HeapTuple   tuple;
     696             :     Form_pg_type typ;
     697             :     Oid         arrayOid;
     698             :     Oid         oldTypeOid;
     699             : 
     700          80 :     pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
     701             : 
     702          80 :     tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
     703          80 :     if (!HeapTupleIsValid(tuple))
     704           0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
     705          80 :     typ = (Form_pg_type) GETSTRUCT(tuple);
     706             : 
     707             :     /* We are not supposed to be changing schemas here */
     708          80 :     Assert(typeNamespace == typ->typnamespace);
     709             : 
     710          80 :     arrayOid = typ->typarray;
     711             : 
     712             :     /* Check for a conflicting type name. */
     713          80 :     oldTypeOid = GetSysCacheOid2(TYPENAMENSP,
     714             :                                  CStringGetDatum(newTypeName),
     715             :                                  ObjectIdGetDatum(typeNamespace));
     716             : 
     717             :     /*
     718             :      * If there is one, see if it's an autogenerated array type, and if so
     719             :      * rename it out of the way.  (But we must skip that for a shell type
     720             :      * because moveArrayTypeName will do the wrong thing in that case.)
     721             :      * Otherwise, we can at least give a more friendly error than unique-index
     722             :      * violation.
     723             :      */
     724          80 :     if (OidIsValid(oldTypeOid))
     725             :     {
     726           4 :         if (get_typisdefined(oldTypeOid) &&
     727           2 :             moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
     728             :              /* successfully dodged the problem */ ;
     729             :         else
     730           0 :             ereport(ERROR,
     731             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
     732             :                      errmsg("type \"%s\" already exists", newTypeName)));
     733             :     }
     734             : 
     735             :     /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
     736          80 :     namestrcpy(&(typ->typname), newTypeName);
     737             : 
     738          80 :     CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
     739             : 
     740          80 :     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
     741             : 
     742          80 :     heap_freetuple(tuple);
     743          80 :     heap_close(pg_type_desc, RowExclusiveLock);
     744             : 
     745             :     /*
     746             :      * If the type has an array type, recurse to handle that.  But we don't
     747             :      * need to do anything more if we already renamed that array type above
     748             :      * (which would happen when, eg, renaming "foo" to "_foo").
     749             :      */
     750          80 :     if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
     751             :     {
     752          15 :         char       *arrname = makeArrayTypeName(newTypeName, typeNamespace);
     753             : 
     754          15 :         RenameTypeInternal(arrayOid, arrname, typeNamespace);
     755          15 :         pfree(arrname);
     756             :     }
     757          80 : }
     758             : 
     759             : 
     760             : /*
     761             :  * makeArrayTypeName
     762             :  *    - given a base type name, make an array type name for it
     763             :  *
     764             :  * the caller is responsible for pfreeing the result
     765             :  */
     766             : char *
     767        2025 : makeArrayTypeName(const char *typeName, Oid typeNamespace)
     768             : {
     769        2025 :     char       *arr = (char *) palloc(NAMEDATALEN);
     770        2025 :     int         namelen = strlen(typeName);
     771             :     Relation    pg_type_desc;
     772             :     int         i;
     773             : 
     774             :     /*
     775             :      * The idea is to prepend underscores as needed until we make a name that
     776             :      * doesn't collide with anything...
     777             :      */
     778        2025 :     pg_type_desc = heap_open(TypeRelationId, AccessShareLock);
     779             : 
     780        2027 :     for (i = 1; i < NAMEDATALEN - 1; i++)
     781             :     {
     782        2027 :         arr[i - 1] = '_';
     783        2027 :         if (i + namelen < NAMEDATALEN)
     784        2027 :             strcpy(arr + i, typeName);
     785             :         else
     786             :         {
     787           0 :             memcpy(arr + i, typeName, NAMEDATALEN - i);
     788           0 :             truncate_identifier(arr, NAMEDATALEN, false);
     789             :         }
     790        2027 :         if (!SearchSysCacheExists2(TYPENAMENSP,
     791             :                                    CStringGetDatum(arr),
     792             :                                    ObjectIdGetDatum(typeNamespace)))
     793        2025 :             break;
     794             :     }
     795             : 
     796        2025 :     heap_close(pg_type_desc, AccessShareLock);
     797             : 
     798        2025 :     if (i >= NAMEDATALEN - 1)
     799           0 :         ereport(ERROR,
     800             :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     801             :                  errmsg("could not form array type name for type \"%s\"",
     802             :                         typeName)));
     803             : 
     804        2025 :     return arr;
     805             : }
     806             : 
     807             : 
     808             : /*
     809             :  * moveArrayTypeName
     810             :  *    - try to reassign an array type name that the user wants to use.
     811             :  *
     812             :  * The given type name has been discovered to already exist (with the given
     813             :  * OID).  If it is an autogenerated array type, change the array type's name
     814             :  * to not conflict.  This allows the user to create type "foo" followed by
     815             :  * type "_foo" without problems.  (Of course, there are race conditions if
     816             :  * two backends try to create similarly-named types concurrently, but the
     817             :  * worst that can happen is an unnecessary failure --- anything we do here
     818             :  * will be rolled back if the type creation fails due to conflicting names.)
     819             :  *
     820             :  * Note that this must be called *before* calling makeArrayTypeName to
     821             :  * determine the new type's own array type name; else the latter will
     822             :  * certainly pick the same name.
     823             :  *
     824             :  * Returns TRUE if successfully moved the type, FALSE if not.
     825             :  *
     826             :  * We also return TRUE if the given type is a shell type.  In this case
     827             :  * the type has not been renamed out of the way, but nonetheless it can
     828             :  * be expected that TypeCreate will succeed.  This behavior is convenient
     829             :  * for most callers --- those that need to distinguish the shell-type case
     830             :  * must do their own typisdefined test.
     831             :  */
     832             : bool
     833           4 : moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
     834             : {
     835             :     Oid         elemOid;
     836             :     char       *newname;
     837             : 
     838             :     /* We need do nothing if it's a shell type. */
     839           4 :     if (!get_typisdefined(typeOid))
     840           0 :         return true;
     841             : 
     842             :     /* Can't change it if it's not an autogenerated array type. */
     843           4 :     elemOid = get_element_type(typeOid);
     844           7 :     if (!OidIsValid(elemOid) ||
     845           3 :         get_array_type(elemOid) != typeOid)
     846           1 :         return false;
     847             : 
     848             :     /*
     849             :      * OK, use makeArrayTypeName to pick an unused modification of the name.
     850             :      * Note that since makeArrayTypeName is an iterative process, this will
     851             :      * produce a name that it might have produced the first time, had the
     852             :      * conflicting type we are about to create already existed.
     853             :      */
     854           3 :     newname = makeArrayTypeName(typeName, typeNamespace);
     855             : 
     856             :     /* Apply the rename */
     857           3 :     RenameTypeInternal(typeOid, newname, typeNamespace);
     858             : 
     859             :     /*
     860             :      * We must bump the command counter so that any subsequent use of
     861             :      * makeArrayTypeName sees what we just did and doesn't pick the same name.
     862             :      */
     863           3 :     CommandCounterIncrement();
     864             : 
     865           3 :     pfree(newname);
     866             : 
     867           3 :     return true;
     868             : }

Generated by: LCOV version 1.11