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

Generated by: LCOV version 1.13