LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_type.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 93.6 % 281 263
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 7 7
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-2026, 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/defrem.h"
      30              : #include "commands/typecmds.h"
      31              : #include "mb/pg_wchar.h"
      32              : #include "miscadmin.h"
      33              : #include "utils/acl.h"
      34              : #include "utils/builtins.h"
      35              : #include "utils/fmgroids.h"
      36              : #include "utils/lsyscache.h"
      37              : #include "utils/rel.h"
      38              : #include "utils/syscache.h"
      39              : 
      40              : /* Potentially set by pg_upgrade_support functions */
      41              : Oid         binary_upgrade_next_pg_type_oid = InvalidOid;
      42              : 
      43              : /* ----------------------------------------------------------------
      44              :  *      TypeShellMake
      45              :  *
      46              :  *      This procedure inserts a "shell" tuple into the pg_type relation.
      47              :  *      The type tuple inserted has valid but dummy values, and its
      48              :  *      "typisdefined" field is false indicating it's not really defined.
      49              :  *
      50              :  *      This is used so that a tuple exists in the catalogs.  The I/O
      51              :  *      functions for the type will link to this tuple.  When the full
      52              :  *      CREATE TYPE command is issued, the bogus values will be replaced
      53              :  *      with correct ones, and "typisdefined" will be set to true.
      54              :  * ----------------------------------------------------------------
      55              :  */
      56              : ObjectAddress
      57          121 : TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
      58              : {
      59              :     Relation    pg_type_desc;
      60              :     TupleDesc   tupDesc;
      61              :     int         i;
      62              :     HeapTuple   tup;
      63              :     Datum       values[Natts_pg_type];
      64              :     bool        nulls[Natts_pg_type];
      65              :     Oid         typoid;
      66              :     NameData    name;
      67              :     ObjectAddress address;
      68              : 
      69              :     Assert(typeName);
      70              : 
      71              :     /*
      72              :      * open pg_type
      73              :      */
      74          121 :     pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
      75          121 :     tupDesc = pg_type_desc->rd_att;
      76              : 
      77              :     /*
      78              :      * initialize our *nulls and *values arrays
      79              :      */
      80         3993 :     for (i = 0; i < Natts_pg_type; ++i)
      81              :     {
      82         3872 :         nulls[i] = false;
      83         3872 :         values[i] = (Datum) 0;  /* redundant, but safe */
      84              :     }
      85              : 
      86              :     /*
      87              :      * initialize *values with the type name and dummy values
      88              :      *
      89              :      * The representational details are the same as int4 ... it doesn't really
      90              :      * matter what they are so long as they are consistent.  Also note that we
      91              :      * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
      92              :      * mistaken for a usable type.
      93              :      */
      94          121 :     namestrcpy(&name, typeName);
      95          121 :     values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
      96          121 :     values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
      97          121 :     values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
      98          121 :     values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
      99          121 :     values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
     100          121 :     values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
     101          121 :     values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
     102          121 :     values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
     103          121 :     values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
     104          121 :     values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
     105          121 :     values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
     106          121 :     values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(InvalidOid);
     107          121 :     values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
     108          121 :     values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
     109          121 :     values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
     110          121 :     values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
     111          121 :     values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
     112          121 :     values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
     113          121 :     values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
     114          121 :     values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
     115          121 :     values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
     116          121 :     values[Anum_pg_type_typalign - 1] = CharGetDatum(TYPALIGN_INT);
     117          121 :     values[Anum_pg_type_typstorage - 1] = CharGetDatum(TYPSTORAGE_PLAIN);
     118          121 :     values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
     119          121 :     values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
     120          121 :     values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
     121          121 :     values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
     122          121 :     values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
     123          121 :     nulls[Anum_pg_type_typdefaultbin - 1] = true;
     124          121 :     nulls[Anum_pg_type_typdefault - 1] = true;
     125          121 :     nulls[Anum_pg_type_typacl - 1] = true;
     126              : 
     127              :     /* Use binary-upgrade override for pg_type.oid? */
     128          121 :     if (IsBinaryUpgrade)
     129              :     {
     130            8 :         if (!OidIsValid(binary_upgrade_next_pg_type_oid))
     131            0 :             ereport(ERROR,
     132              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     133              :                      errmsg("pg_type OID value not set when in binary upgrade mode")));
     134              : 
     135            8 :         typoid = binary_upgrade_next_pg_type_oid;
     136            8 :         binary_upgrade_next_pg_type_oid = InvalidOid;
     137              :     }
     138              :     else
     139              :     {
     140          113 :         typoid = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
     141              :                                     Anum_pg_type_oid);
     142              :     }
     143              : 
     144          121 :     values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid);
     145              : 
     146              :     /*
     147              :      * create a new type tuple
     148              :      */
     149          121 :     tup = heap_form_tuple(tupDesc, values, nulls);
     150              : 
     151              :     /*
     152              :      * insert the tuple in the relation and get the tuple's oid.
     153              :      */
     154          121 :     CatalogTupleInsert(pg_type_desc, tup);
     155              : 
     156              :     /*
     157              :      * Create dependencies.  We can/must skip this in bootstrap mode.
     158              :      */
     159          121 :     if (!IsBootstrapProcessingMode())
     160          121 :         GenerateTypeDependencies(tup,
     161              :                                  pg_type_desc,
     162              :                                  NULL,
     163              :                                  NULL,
     164              :                                  0,
     165              :                                  false,
     166              :                                  false,
     167              :                                  true,  /* make extension dependency */
     168              :                                  false);
     169              : 
     170              :     /* Post creation hook for new shell type */
     171          121 :     InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
     172              : 
     173          121 :     ObjectAddressSet(address, TypeRelationId, typoid);
     174              : 
     175              :     /*
     176              :      * clean up and return the type-oid
     177              :      */
     178          121 :     heap_freetuple(tup);
     179          121 :     table_close(pg_type_desc, RowExclusiveLock);
     180              : 
     181          121 :     return address;
     182              : }
     183              : 
     184              : /* ----------------------------------------------------------------
     185              :  *      TypeCreate
     186              :  *
     187              :  *      This does all the necessary work needed to define a new type.
     188              :  *
     189              :  *      Returns the ObjectAddress assigned to the new type.
     190              :  *      If newTypeOid is zero (the normal case), a new OID is created;
     191              :  *      otherwise we use exactly that OID.
     192              :  * ----------------------------------------------------------------
     193              :  */
     194              : ObjectAddress
     195        74505 : TypeCreate(Oid newTypeOid,
     196              :            const char *typeName,
     197              :            Oid typeNamespace,
     198              :            Oid relationOid,     /* only for relation rowtypes */
     199              :            char relationKind,   /* ditto */
     200              :            Oid ownerId,
     201              :            int16 internalSize,
     202              :            char typeType,
     203              :            char typeCategory,
     204              :            bool typePreferred,
     205              :            char typDelim,
     206              :            Oid inputProcedure,
     207              :            Oid outputProcedure,
     208              :            Oid receiveProcedure,
     209              :            Oid sendProcedure,
     210              :            Oid typmodinProcedure,
     211              :            Oid typmodoutProcedure,
     212              :            Oid analyzeProcedure,
     213              :            Oid subscriptProcedure,
     214              :            Oid elementType,
     215              :            bool isImplicitArray,
     216              :            Oid arrayType,
     217              :            Oid baseType,
     218              :            const char *defaultTypeValue,    /* human-readable rep */
     219              :            char *defaultTypeBin,    /* cooked rep */
     220              :            bool passedByValue,
     221              :            char alignment,
     222              :            char storage,
     223              :            int32 typeMod,
     224              :            int32 typNDims,      /* Array dimensions for baseType */
     225              :            bool typeNotNull,
     226              :            Oid typeCollation)
     227              : {
     228              :     Relation    pg_type_desc;
     229              :     Oid         typeObjectId;
     230              :     bool        isDependentType;
     231        74505 :     bool        rebuildDeps = false;
     232              :     Acl        *typacl;
     233              :     HeapTuple   tup;
     234              :     bool        nulls[Natts_pg_type];
     235              :     bool        replaces[Natts_pg_type];
     236              :     Datum       values[Natts_pg_type];
     237              :     NameData    name;
     238              :     int         i;
     239              :     ObjectAddress address;
     240              : 
     241              :     /*
     242              :      * We assume that the caller validated the arguments individually, but did
     243              :      * not check for bad combinations.
     244              :      *
     245              :      * Validate size specifications: either positive (fixed-length) or -1
     246              :      * (varlena) or -2 (cstring).
     247              :      */
     248        74505 :     if (!(internalSize > 0 ||
     249              :           internalSize == -1 ||
     250              :           internalSize == -2))
     251            0 :         ereport(ERROR,
     252              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     253              :                  errmsg("invalid type internal size %d",
     254              :                         internalSize)));
     255              : 
     256        74505 :     if (passedByValue)
     257              :     {
     258              :         /*
     259              :          * Pass-by-value types must have a fixed length that is one of the
     260              :          * values supported by fetch_att() and store_att_byval(); and the
     261              :          * alignment had better agree, too.  All this code must match
     262              :          * access/tupmacs.h!
     263              :          */
     264          548 :         if (internalSize == (int16) sizeof(char))
     265              :         {
     266            6 :             if (alignment != TYPALIGN_CHAR)
     267            0 :                 ereport(ERROR,
     268              :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     269              :                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
     270              :                                 alignment, internalSize)));
     271              :         }
     272          542 :         else if (internalSize == (int16) sizeof(int16))
     273              :         {
     274            2 :             if (alignment != TYPALIGN_SHORT)
     275            0 :                 ereport(ERROR,
     276              :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     277              :                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
     278              :                                 alignment, internalSize)));
     279              :         }
     280          540 :         else if (internalSize == (int16) sizeof(int32))
     281              :         {
     282          467 :             if (alignment != TYPALIGN_INT)
     283            0 :                 ereport(ERROR,
     284              :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     285              :                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
     286              :                                 alignment, internalSize)));
     287              :         }
     288           73 :         else if (internalSize == (int16) sizeof(int64))
     289              :         {
     290           73 :             if (alignment != TYPALIGN_DOUBLE)
     291            0 :                 ereport(ERROR,
     292              :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     293              :                          errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
     294              :                                 alignment, internalSize)));
     295              :         }
     296              :         else
     297            0 :             ereport(ERROR,
     298              :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     299              :                      errmsg("internal size %d is invalid for passed-by-value type",
     300              :                             internalSize)));
     301              :     }
     302              :     else
     303              :     {
     304              :         /* varlena types must have int align or better */
     305        73957 :         if (internalSize == -1 &&
     306        72371 :             !(alignment == TYPALIGN_INT || alignment == TYPALIGN_DOUBLE))
     307            0 :             ereport(ERROR,
     308              :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     309              :                      errmsg("alignment \"%c\" is invalid for variable-length type",
     310              :                             alignment)));
     311              :         /* cstring must have char alignment */
     312        73957 :         if (internalSize == -2 && !(alignment == TYPALIGN_CHAR))
     313            0 :             ereport(ERROR,
     314              :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     315              :                      errmsg("alignment \"%c\" is invalid for variable-length type",
     316              :                             alignment)));
     317              :     }
     318              : 
     319              :     /* Only varlena types can be toasted */
     320        74505 :     if (storage != TYPSTORAGE_PLAIN && internalSize != -1)
     321            0 :         ereport(ERROR,
     322              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     323              :                  errmsg("fixed-size types must have storage PLAIN")));
     324              : 
     325              :     /*
     326              :      * This is a dependent type if it's an implicitly-created array type or
     327              :      * multirange type, or if it's a relation rowtype that's not a composite
     328              :      * type.  For such types we'll leave the ACL empty, and we'll skip
     329              :      * creating some dependency records because there will be a dependency
     330              :      * already through the depended-on type or relation.  (Caution: this is
     331              :      * closely intertwined with some behavior in GenerateTypeDependencies.)
     332              :      */
     333        37259 :     isDependentType = isImplicitArray ||
     334       147844 :         typeType == TYPTYPE_MULTIRANGE ||
     335        36080 :         (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE);
     336              : 
     337              :     /*
     338              :      * initialize arrays needed for heap_form_tuple or heap_modify_tuple
     339              :      */
     340      2458665 :     for (i = 0; i < Natts_pg_type; ++i)
     341              :     {
     342      2384160 :         nulls[i] = false;
     343      2384160 :         replaces[i] = true;
     344      2384160 :         values[i] = (Datum) 0;
     345              :     }
     346              : 
     347              :     /*
     348              :      * insert data values
     349              :      */
     350        74505 :     namestrcpy(&name, typeName);
     351        74505 :     values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
     352        74505 :     values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
     353        74505 :     values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
     354        74505 :     values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
     355        74505 :     values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
     356        74505 :     values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
     357        74505 :     values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
     358        74505 :     values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
     359        74505 :     values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
     360        74505 :     values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
     361        74505 :     values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
     362        74505 :     values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(subscriptProcedure);
     363        74505 :     values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
     364        74505 :     values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
     365        74505 :     values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
     366        74505 :     values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
     367        74505 :     values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
     368        74505 :     values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
     369        74505 :     values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
     370        74505 :     values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
     371        74505 :     values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
     372        74505 :     values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
     373        74505 :     values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
     374        74505 :     values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
     375        74505 :     values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
     376        74505 :     values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
     377        74505 :     values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
     378        74505 :     values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
     379              : 
     380              :     /*
     381              :      * initialize the default binary value for this type.  Check for nulls of
     382              :      * course.
     383              :      */
     384        74505 :     if (defaultTypeBin)
     385           82 :         values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
     386              :     else
     387        74423 :         nulls[Anum_pg_type_typdefaultbin - 1] = true;
     388              : 
     389              :     /*
     390              :      * initialize the default value for this type.
     391              :      */
     392        74505 :     if (defaultTypeValue)
     393           91 :         values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
     394              :     else
     395        74414 :         nulls[Anum_pg_type_typdefault - 1] = true;
     396              : 
     397              :     /*
     398              :      * Initialize the type's ACL, too.  But dependent types don't get one.
     399              :      */
     400        74505 :     if (isDependentType)
     401        71158 :         typacl = NULL;
     402              :     else
     403         3347 :         typacl = get_user_default_acl(OBJECT_TYPE, ownerId,
     404              :                                       typeNamespace);
     405        74505 :     if (typacl != NULL)
     406            3 :         values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
     407              :     else
     408        74502 :         nulls[Anum_pg_type_typacl - 1] = true;
     409              : 
     410              :     /*
     411              :      * open pg_type and prepare to insert or update a row.
     412              :      *
     413              :      * NOTE: updating will not work correctly in bootstrap mode; but we don't
     414              :      * expect to be overwriting any shell types in bootstrap mode.
     415              :      */
     416        74505 :     pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
     417              : 
     418        74505 :     tup = SearchSysCacheCopy2(TYPENAMENSP,
     419              :                               CStringGetDatum(typeName),
     420              :                               ObjectIdGetDatum(typeNamespace));
     421        74505 :     if (HeapTupleIsValid(tup))
     422              :     {
     423          109 :         Form_pg_type typform = (Form_pg_type) GETSTRUCT(tup);
     424              : 
     425              :         /*
     426              :          * check that the type is not already defined.  It may exist as a
     427              :          * shell type, however.
     428              :          */
     429          109 :         if (typform->typisdefined)
     430            0 :             ereport(ERROR,
     431              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
     432              :                      errmsg("type \"%s\" already exists", typeName)));
     433              : 
     434              :         /*
     435              :          * shell type must have been created by same owner
     436              :          */
     437          109 :         if (typform->typowner != ownerId)
     438            0 :             aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TYPE, typeName);
     439              : 
     440              :         /* trouble if caller wanted to force the OID */
     441          109 :         if (OidIsValid(newTypeOid))
     442            0 :             elog(ERROR, "cannot assign new OID to existing shell type");
     443              : 
     444          109 :         replaces[Anum_pg_type_oid - 1] = false;
     445              : 
     446              :         /*
     447              :          * Okay to update existing shell type tuple
     448              :          */
     449          109 :         tup = heap_modify_tuple(tup,
     450              :                                 RelationGetDescr(pg_type_desc),
     451              :                                 values,
     452              :                                 nulls,
     453              :                                 replaces);
     454              : 
     455          109 :         CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup);
     456              : 
     457          109 :         typeObjectId = typform->oid;
     458              : 
     459          109 :         rebuildDeps = true;     /* get rid of shell type's dependencies */
     460              :     }
     461              :     else
     462              :     {
     463              :         /* Force the OID if requested by caller */
     464        74396 :         if (OidIsValid(newTypeOid))
     465        37581 :             typeObjectId = newTypeOid;
     466              :         /* Use binary-upgrade override for pg_type.oid, if supplied. */
     467        36815 :         else if (IsBinaryUpgrade)
     468              :         {
     469          860 :             if (!OidIsValid(binary_upgrade_next_pg_type_oid))
     470            0 :                 ereport(ERROR,
     471              :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     472              :                          errmsg("pg_type OID value not set when in binary upgrade mode")));
     473              : 
     474          860 :             typeObjectId = binary_upgrade_next_pg_type_oid;
     475          860 :             binary_upgrade_next_pg_type_oid = InvalidOid;
     476              :         }
     477              :         else
     478              :         {
     479        35955 :             typeObjectId = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
     480              :                                               Anum_pg_type_oid);
     481              :         }
     482              : 
     483        74396 :         values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typeObjectId);
     484              : 
     485        74396 :         tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
     486              :                               values, nulls);
     487              : 
     488        74396 :         CatalogTupleInsert(pg_type_desc, tup);
     489              :     }
     490              : 
     491              :     /*
     492              :      * Create dependencies.  We can/must skip this in bootstrap mode.
     493              :      */
     494        74505 :     if (!IsBootstrapProcessingMode())
     495        68467 :         GenerateTypeDependencies(tup,
     496              :                                  pg_type_desc,
     497              :                                  (defaultTypeBin ?
     498           82 :                                   stringToNode(defaultTypeBin) :
     499              :                                   NULL),
     500              :                                  typacl,
     501              :                                  relationKind,
     502              :                                  isImplicitArray,
     503              :                                  isDependentType,
     504              :                                  true,  /* make extension dependency */
     505              :                                  rebuildDeps);
     506              : 
     507              :     /* Post creation hook for new type */
     508        74504 :     InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
     509              : 
     510        74504 :     ObjectAddressSet(address, TypeRelationId, typeObjectId);
     511              : 
     512              :     /*
     513              :      * finish up
     514              :      */
     515        74504 :     table_close(pg_type_desc, RowExclusiveLock);
     516              : 
     517        74504 :     return address;
     518              : }
     519              : 
     520              : /*
     521              :  * GenerateTypeDependencies: build the dependencies needed for a type
     522              :  *
     523              :  * Most of what this function needs to know about the type is passed as the
     524              :  * new pg_type row, typeTuple.  We make callers pass the pg_type Relation
     525              :  * as well, so that we have easy access to a tuple descriptor for the row.
     526              :  *
     527              :  * While this is able to extract the defaultExpr and typacl from the tuple,
     528              :  * doing so is relatively expensive, and callers may have those values at
     529              :  * hand already.  Pass those if handy, otherwise pass NULL.  (typacl is really
     530              :  * "Acl *", but we declare it "void *" to avoid including acl.h in pg_type.h.)
     531              :  *
     532              :  * relationKind and isImplicitArray are likewise somewhat expensive to deduce
     533              :  * from the tuple, so we make callers pass those (they're not optional).
     534              :  *
     535              :  * isDependentType is true if this is an implicit array, multirange, or
     536              :  * relation rowtype; that means it doesn't need its own dependencies on owner
     537              :  * etc.
     538              :  *
     539              :  * We make an extension-membership dependency if we're in an extension
     540              :  * script and makeExtensionDep is true.
     541              :  * makeExtensionDep should be true when creating a new type or replacing a
     542              :  * shell type, but not for ALTER TYPE on an existing type.  Passing false
     543              :  * causes the type's extension membership to be left alone.
     544              :  *
     545              :  * rebuild should be true if this is a pre-existing type.  We will remove
     546              :  * existing dependencies and rebuild them from scratch.  This is needed for
     547              :  * ALTER TYPE, and also when replacing a shell type.  We don't remove any
     548              :  * existing extension dependency, though; hence, if makeExtensionDep is also
     549              :  * true and we're in an extension script, an error will occur unless the
     550              :  * type already belongs to the current extension.  That's the behavior we
     551              :  * want when replacing a shell type, which is the only case where both flags
     552              :  * are true.
     553              :  */
     554              : void
     555        68546 : GenerateTypeDependencies(HeapTuple typeTuple,
     556              :                          Relation typeCatalog,
     557              :                          Node *defaultExpr,
     558              :                          void *typacl,
     559              :                          char relationKind, /* only for relation rowtypes */
     560              :                          bool isImplicitArray,
     561              :                          bool isDependentType,
     562              :                          bool makeExtensionDep,
     563              :                          bool rebuild)
     564              : {
     565        68546 :     Form_pg_type typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
     566        68546 :     Oid         typeObjectId = typeForm->oid;
     567              :     Datum       datum;
     568              :     bool        isNull;
     569              :     ObjectAddress myself,
     570              :                 referenced;
     571              :     ObjectAddresses *addrs_normal;
     572              : 
     573              :     /* Extract defaultExpr if caller didn't pass it */
     574        68546 :     if (defaultExpr == NULL)
     575              :     {
     576        68460 :         datum = heap_getattr(typeTuple, Anum_pg_type_typdefaultbin,
     577              :                              RelationGetDescr(typeCatalog), &isNull);
     578        68460 :         if (!isNull)
     579            0 :             defaultExpr = stringToNode(TextDatumGetCString(datum));
     580              :     }
     581              :     /* Extract typacl if caller didn't pass it */
     582        68546 :     if (typacl == NULL)
     583              :     {
     584        68543 :         datum = heap_getattr(typeTuple, Anum_pg_type_typacl,
     585              :                              RelationGetDescr(typeCatalog), &isNull);
     586        68543 :         if (!isNull)
     587            0 :             typacl = DatumGetAclPCopy(datum);
     588              :     }
     589              : 
     590              :     /* If rebuild, first flush old dependencies, except extension deps */
     591        68546 :     if (rebuild)
     592              :     {
     593          149 :         deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
     594          149 :         deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
     595              :     }
     596              : 
     597        68546 :     ObjectAddressSet(myself, TypeRelationId, typeObjectId);
     598              : 
     599              :     /*
     600              :      * Make dependencies on namespace, owner, ACL.
     601              :      *
     602              :      * Skip these for a dependent type, since it will have such dependencies
     603              :      * indirectly through its depended-on type or relation.  An exception is
     604              :      * that multiranges need their own namespace dependency, since we don't
     605              :      * force them to be in the same schema as their range type.
     606              :      */
     607              : 
     608              :     /* collects normal dependencies for bulk recording */
     609        68546 :     addrs_normal = new_object_addresses();
     610              : 
     611        68546 :     if (!isDependentType || typeForm->typtype == TYPTYPE_MULTIRANGE)
     612              :     {
     613         3585 :         ObjectAddressSet(referenced, NamespaceRelationId,
     614              :                          typeForm->typnamespace);
     615         3585 :         add_exact_object_address(&referenced, addrs_normal);
     616              :     }
     617              : 
     618        68546 :     if (!isDependentType)
     619              :     {
     620         3505 :         recordDependencyOnOwner(TypeRelationId, typeObjectId,
     621              :                                 typeForm->typowner);
     622              : 
     623         3505 :         recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0,
     624              :                                  typeForm->typowner, typacl);
     625              :     }
     626              : 
     627              :     /*
     628              :      * Make extension dependency if requested.
     629              :      *
     630              :      * We used to skip this for dependent types, but it seems better to record
     631              :      * their extension membership explicitly; otherwise code such as
     632              :      * postgres_fdw's shippability test will be fooled.
     633              :      */
     634        68546 :     if (makeExtensionDep)
     635        68506 :         recordDependencyOnCurrentExtension(&myself, rebuild);
     636              : 
     637              :     /* Normal dependencies on the I/O and support functions */
     638        68545 :     if (OidIsValid(typeForm->typinput))
     639              :     {
     640        68545 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typinput);
     641        68545 :         add_exact_object_address(&referenced, addrs_normal);
     642              :     }
     643              : 
     644        68545 :     if (OidIsValid(typeForm->typoutput))
     645              :     {
     646        68545 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typoutput);
     647        68545 :         add_exact_object_address(&referenced, addrs_normal);
     648              :     }
     649              : 
     650        68545 :     if (OidIsValid(typeForm->typreceive))
     651              :     {
     652        68322 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typreceive);
     653        68322 :         add_exact_object_address(&referenced, addrs_normal);
     654              :     }
     655              : 
     656        68545 :     if (OidIsValid(typeForm->typsend))
     657              :     {
     658        68316 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsend);
     659        68316 :         add_exact_object_address(&referenced, addrs_normal);
     660              :     }
     661              : 
     662        68545 :     if (OidIsValid(typeForm->typmodin))
     663              :     {
     664           14 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodin);
     665           14 :         add_exact_object_address(&referenced, addrs_normal);
     666              :     }
     667              : 
     668        68545 :     if (OidIsValid(typeForm->typmodout))
     669              :     {
     670           14 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodout);
     671           14 :         add_exact_object_address(&referenced, addrs_normal);
     672              :     }
     673              : 
     674        68545 :     if (OidIsValid(typeForm->typanalyze))
     675              :     {
     676        34437 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typanalyze);
     677        34437 :         add_exact_object_address(&referenced, addrs_normal);
     678              :     }
     679              : 
     680        68545 :     if (OidIsValid(typeForm->typsubscript))
     681              :     {
     682        34203 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsubscript);
     683        34203 :         add_exact_object_address(&referenced, addrs_normal);
     684              :     }
     685              : 
     686              :     /* Normal dependency from a domain to its base type. */
     687        68545 :     if (OidIsValid(typeForm->typbasetype))
     688              :     {
     689          693 :         ObjectAddressSet(referenced, TypeRelationId, typeForm->typbasetype);
     690          693 :         add_exact_object_address(&referenced, addrs_normal);
     691              :     }
     692              : 
     693              :     /*
     694              :      * Normal dependency from a domain to its collation.  We know the default
     695              :      * collation is pinned, so don't bother recording it.
     696              :      */
     697        68545 :     if (OidIsValid(typeForm->typcollation) &&
     698          538 :         typeForm->typcollation != DEFAULT_COLLATION_OID)
     699              :     {
     700          326 :         ObjectAddressSet(referenced, CollationRelationId, typeForm->typcollation);
     701          326 :         add_exact_object_address(&referenced, addrs_normal);
     702              :     }
     703              : 
     704        68545 :     record_object_address_dependencies(&myself, addrs_normal, DEPENDENCY_NORMAL);
     705        68545 :     free_object_addresses(addrs_normal);
     706              : 
     707              :     /* Normal dependency on the default expression. */
     708        68545 :     if (defaultExpr)
     709           86 :         recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
     710              : 
     711              :     /*
     712              :      * If the type is a rowtype for a relation, mark it as internally
     713              :      * dependent on the relation, *unless* it is a stand-alone composite type
     714              :      * relation. For the latter case, we have to reverse the dependency.
     715              :      *
     716              :      * In the former case, this allows the type to be auto-dropped when the
     717              :      * relation is, and not otherwise. And in the latter, of course we get the
     718              :      * opposite effect.
     719              :      */
     720        68545 :     if (OidIsValid(typeForm->typrelid))
     721              :     {
     722        33020 :         ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid);
     723              : 
     724        33020 :         if (relationKind != RELKIND_COMPOSITE_TYPE)
     725        30772 :             recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
     726              :         else
     727         2248 :             recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
     728              :     }
     729              : 
     730              :     /*
     731              :      * If the type is an implicitly-created array type, mark it as internally
     732              :      * dependent on the element type.  Otherwise, if it has an element type,
     733              :      * the dependency is a normal one.
     734              :      */
     735        68545 :     if (OidIsValid(typeForm->typelem))
     736              :     {
     737        34193 :         ObjectAddressSet(referenced, TypeRelationId, typeForm->typelem);
     738        34193 :         recordDependencyOn(&myself, &referenced,
     739              :                            isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
     740              :     }
     741              : 
     742              :     /*
     743              :      * Note: you might expect that we should record an internal dependency of
     744              :      * a multirange on its range type here, by analogy with the cases above.
     745              :      * But instead, that is done by RangeCreate(), which also handles
     746              :      * recording of other range-type-specific dependencies.  That's pretty
     747              :      * bogus.  It's okay for now, because there are no cases where we need to
     748              :      * regenerate the dependencies of a range or multirange type.  But someday
     749              :      * we might need to move that logic here to allow such regeneration.
     750              :      */
     751        68545 : }
     752              : 
     753              : /*
     754              :  * RenameTypeInternal
     755              :  *      This renames a type, as well as any associated array type.
     756              :  *
     757              :  * Caller must have already checked privileges.
     758              :  *
     759              :  * Currently this is used for renaming table rowtypes and for
     760              :  * ALTER TYPE RENAME TO command.
     761              :  */
     762              : void
     763          236 : RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
     764              : {
     765              :     Relation    pg_type_desc;
     766              :     HeapTuple   tuple;
     767              :     Form_pg_type typ;
     768              :     Oid         arrayOid;
     769              :     Oid         oldTypeOid;
     770              : 
     771          236 :     pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
     772              : 
     773          236 :     tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
     774          236 :     if (!HeapTupleIsValid(tuple))
     775            0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
     776          236 :     typ = (Form_pg_type) GETSTRUCT(tuple);
     777              : 
     778              :     /* We are not supposed to be changing schemas here */
     779              :     Assert(typeNamespace == typ->typnamespace);
     780              : 
     781          236 :     arrayOid = typ->typarray;
     782              : 
     783              :     /* Check for a conflicting type name. */
     784          236 :     oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
     785              :                                  CStringGetDatum(newTypeName),
     786              :                                  ObjectIdGetDatum(typeNamespace));
     787              : 
     788              :     /*
     789              :      * If there is one, see if it's an autogenerated array type, and if so
     790              :      * rename it out of the way.  (But we must skip that for a shell type
     791              :      * because moveArrayTypeName will do the wrong thing in that case.)
     792              :      * Otherwise, we can at least give a more friendly error than unique-index
     793              :      * violation.
     794              :      */
     795          236 :     if (OidIsValid(oldTypeOid))
     796              :     {
     797           12 :         if (get_typisdefined(oldTypeOid) &&
     798            6 :             moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
     799              :              /* successfully dodged the problem */ ;
     800              :         else
     801            0 :             ereport(ERROR,
     802              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
     803              :                      errmsg("type \"%s\" already exists", newTypeName)));
     804              :     }
     805              : 
     806              :     /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
     807          236 :     namestrcpy(&(typ->typname), newTypeName);
     808              : 
     809          236 :     CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
     810              : 
     811          236 :     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
     812              : 
     813          236 :     heap_freetuple(tuple);
     814          236 :     table_close(pg_type_desc, RowExclusiveLock);
     815              : 
     816              :     /*
     817              :      * If the type has an array type, recurse to handle that.  But we don't
     818              :      * need to do anything more if we already renamed that array type above
     819              :      * (which would happen when, eg, renaming "foo" to "_foo").
     820              :      */
     821          236 :     if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
     822              :     {
     823          110 :         char       *arrname = makeArrayTypeName(newTypeName, typeNamespace);
     824              : 
     825          110 :         RenameTypeInternal(arrayOid, arrname, typeNamespace);
     826          110 :         pfree(arrname);
     827              :     }
     828          236 : }
     829              : 
     830              : 
     831              : /*
     832              :  * makeArrayTypeName
     833              :  *    - given a base type name, make an array type name for it
     834              :  *
     835              :  * the caller is responsible for pfreeing the result
     836              :  */
     837              : char *
     838        37369 : makeArrayTypeName(const char *typeName, Oid typeNamespace)
     839              : {
     840              :     char       *arr_name;
     841        37369 :     int         pass = 0;
     842              :     char        suffix[NAMEDATALEN];
     843              : 
     844              :     /*
     845              :      * Per ancient Postgres tradition, array type names are made by prepending
     846              :      * an underscore to the base type name.  Much client code knows that
     847              :      * convention, so don't muck with it.  However, the tradition is less
     848              :      * clear about what to do in the corner cases where the resulting name is
     849              :      * too long or conflicts with an existing name.  Our current rules are (1)
     850              :      * truncate the base name on the right as needed, and (2) if there is a
     851              :      * conflict, append another underscore and some digits chosen to make it
     852              :      * unique.  This is similar to what ChooseRelationName() does.
     853              :      *
     854              :      * The actual name generation can be farmed out to makeObjectName() by
     855              :      * giving it an empty first name component.
     856              :      */
     857              : 
     858              :     /* First, try with no numeric suffix */
     859        37369 :     arr_name = makeObjectName("", typeName, NULL);
     860              : 
     861              :     for (;;)
     862              :     {
     863        37379 :         if (!SearchSysCacheExists2(TYPENAMENSP,
     864              :                                    CStringGetDatum(arr_name),
     865              :                                    ObjectIdGetDatum(typeNamespace)))
     866        37369 :             break;
     867              : 
     868              :         /* That attempt conflicted.  Prepare a new name with some digits. */
     869           10 :         pfree(arr_name);
     870           10 :         snprintf(suffix, sizeof(suffix), "%d", ++pass);
     871           10 :         arr_name = makeObjectName("", typeName, suffix);
     872              :     }
     873              : 
     874        37369 :     return arr_name;
     875              : }
     876              : 
     877              : 
     878              : /*
     879              :  * moveArrayTypeName
     880              :  *    - try to reassign an array type name that the user wants to use.
     881              :  *
     882              :  * The given type name has been discovered to already exist (with the given
     883              :  * OID).  If it is an autogenerated array type, change the array type's name
     884              :  * to not conflict.  This allows the user to create type "foo" followed by
     885              :  * type "_foo" without problems.  (Of course, there are race conditions if
     886              :  * two backends try to create similarly-named types concurrently, but the
     887              :  * worst that can happen is an unnecessary failure --- anything we do here
     888              :  * will be rolled back if the type creation fails due to conflicting names.)
     889              :  *
     890              :  * Note that this must be called *before* calling makeArrayTypeName to
     891              :  * determine the new type's own array type name; else the latter will
     892              :  * certainly pick the same name.
     893              :  *
     894              :  * Returns true if successfully moved the type, false if not.
     895              :  *
     896              :  * We also return true if the given type is a shell type.  In this case
     897              :  * the type has not been renamed out of the way, but nonetheless it can
     898              :  * be expected that TypeCreate will succeed.  This behavior is convenient
     899              :  * for most callers --- those that need to distinguish the shell-type case
     900              :  * must do their own typisdefined test.
     901              :  */
     902              : bool
     903           20 : moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
     904              : {
     905              :     Oid         elemOid;
     906              :     char       *newname;
     907              : 
     908              :     /* We need do nothing if it's a shell type. */
     909           20 :     if (!get_typisdefined(typeOid))
     910            1 :         return true;
     911              : 
     912              :     /* Can't change it if it's not an autogenerated array type. */
     913           19 :     elemOid = get_element_type(typeOid);
     914           32 :     if (!OidIsValid(elemOid) ||
     915           13 :         get_array_type(elemOid) != typeOid)
     916            6 :         return false;
     917              : 
     918              :     /*
     919              :      * OK, use makeArrayTypeName to pick an unused modification of the name.
     920              :      * Note that since makeArrayTypeName is an iterative process, this will
     921              :      * produce a name that it might have produced the first time, had the
     922              :      * conflicting type we are about to create already existed.
     923              :      */
     924           13 :     newname = makeArrayTypeName(typeName, typeNamespace);
     925              : 
     926              :     /* Apply the rename */
     927           13 :     RenameTypeInternal(typeOid, newname, typeNamespace);
     928              : 
     929              :     /*
     930              :      * We must bump the command counter so that any subsequent use of
     931              :      * makeArrayTypeName sees what we just did and doesn't pick the same name.
     932              :      */
     933           13 :     CommandCounterIncrement();
     934              : 
     935           13 :     pfree(newname);
     936              : 
     937           13 :     return true;
     938              : }
     939              : 
     940              : 
     941              : /*
     942              :  * makeMultirangeTypeName
     943              :  *    - given a range type name, make a multirange type name for it
     944              :  *
     945              :  * caller is responsible for pfreeing the result
     946              :  */
     947              : char *
     948           71 : makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace)
     949              : {
     950              :     char       *buf;
     951              :     const char *rangestr;
     952              : 
     953              :     /*
     954              :      * If the range type name contains "range" then change that to
     955              :      * "multirange". Otherwise add "_multirange" to the end.
     956              :      */
     957           71 :     rangestr = strstr(rangeTypeName, "range");
     958           71 :     if (rangestr)
     959              :     {
     960           62 :         char       *prefix = pnstrdup(rangeTypeName, rangestr - rangeTypeName);
     961              : 
     962           62 :         buf = psprintf("%s%s%s", prefix, "multi", rangestr);
     963              :     }
     964              :     else
     965            9 :         buf = psprintf("%s_multirange", pnstrdup(rangeTypeName, NAMEDATALEN - 12));
     966              : 
     967              :     /* clip it at NAMEDATALEN-1 bytes */
     968           71 :     buf[pg_mbcliplen(buf, strlen(buf), NAMEDATALEN - 1)] = '\0';
     969              : 
     970           71 :     if (SearchSysCacheExists2(TYPENAMENSP,
     971              :                               CStringGetDatum(buf),
     972              :                               ObjectIdGetDatum(typeNamespace)))
     973            6 :         ereport(ERROR,
     974              :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     975              :                  errmsg("type \"%s\" already exists", buf),
     976              :                  errdetail("Failed while creating a multirange type for type \"%s\".", rangeTypeName),
     977              :                  errhint("You can manually specify a multirange type name using the \"multirange_type_name\" attribute.")));
     978              : 
     979           65 :     return pstrdup(buf);
     980              : }
        

Generated by: LCOV version 2.0-1