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

Generated by: LCOV version 1.13