LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_type.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 263 281 93.6 %
Date: 2025-09-01 10:17:37 Functions: 7 7 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-2025, 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         242 : 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(PointerIsValid(typeName));
      70             : 
      71             :     /*
      72             :      * open pg_type
      73             :      */
      74         242 :     pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
      75         242 :     tupDesc = pg_type_desc->rd_att;
      76             : 
      77             :     /*
      78             :      * initialize our *nulls and *values arrays
      79             :      */
      80        7986 :     for (i = 0; i < Natts_pg_type; ++i)
      81             :     {
      82        7744 :         nulls[i] = false;
      83        7744 :         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         242 :     namestrcpy(&name, typeName);
      95         242 :     values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
      96         242 :     values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
      97         242 :     values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
      98         242 :     values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
      99         242 :     values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
     100         242 :     values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
     101         242 :     values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
     102         242 :     values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
     103         242 :     values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
     104         242 :     values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
     105         242 :     values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
     106         242 :     values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(InvalidOid);
     107         242 :     values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
     108         242 :     values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
     109         242 :     values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
     110         242 :     values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
     111         242 :     values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
     112         242 :     values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
     113         242 :     values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
     114         242 :     values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
     115         242 :     values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
     116         242 :     values[Anum_pg_type_typalign - 1] = CharGetDatum(TYPALIGN_INT);
     117         242 :     values[Anum_pg_type_typstorage - 1] = CharGetDatum(TYPSTORAGE_PLAIN);
     118         242 :     values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
     119         242 :     values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
     120         242 :     values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
     121         242 :     values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
     122         242 :     values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
     123         242 :     nulls[Anum_pg_type_typdefaultbin - 1] = true;
     124         242 :     nulls[Anum_pg_type_typdefault - 1] = true;
     125         242 :     nulls[Anum_pg_type_typacl - 1] = true;
     126             : 
     127             :     /* Use binary-upgrade override for pg_type.oid? */
     128         242 :     if (IsBinaryUpgrade)
     129             :     {
     130          16 :         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          16 :         typoid = binary_upgrade_next_pg_type_oid;
     136          16 :         binary_upgrade_next_pg_type_oid = InvalidOid;
     137             :     }
     138             :     else
     139             :     {
     140         226 :         typoid = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
     141             :                                     Anum_pg_type_oid);
     142             :     }
     143             : 
     144         242 :     values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid);
     145             : 
     146             :     /*
     147             :      * create a new type tuple
     148             :      */
     149         242 :     tup = heap_form_tuple(tupDesc, values, nulls);
     150             : 
     151             :     /*
     152             :      * insert the tuple in the relation and get the tuple's oid.
     153             :      */
     154         242 :     CatalogTupleInsert(pg_type_desc, tup);
     155             : 
     156             :     /*
     157             :      * Create dependencies.  We can/must skip this in bootstrap mode.
     158             :      */
     159         242 :     if (!IsBootstrapProcessingMode())
     160         242 :         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         242 :     InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
     172             : 
     173         242 :     ObjectAddressSet(address, TypeRelationId, typoid);
     174             : 
     175             :     /*
     176             :      * clean up and return the type-oid
     177             :      */
     178         242 :     heap_freetuple(tup);
     179         242 :     table_close(pg_type_desc, RowExclusiveLock);
     180             : 
     181         242 :     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      141128 : 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      141128 :     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      141128 :     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      141128 :     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        1086 :         if (internalSize == (int16) sizeof(char))
     265             :         {
     266          12 :             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        1074 :         else if (internalSize == (int16) sizeof(int16))
     273             :         {
     274           4 :             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        1070 :         else if (internalSize == (int16) sizeof(int32))
     281             :         {
     282         926 :             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         144 :         else if (internalSize == (int16) sizeof(int64))
     289             :         {
     290         144 :             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      140042 :         if (internalSize == -1 &&
     306      136908 :             !(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      140042 :         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      141128 :     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       70574 :     isDependentType = isImplicitArray ||
     334      279946 :         typeType == TYPTYPE_MULTIRANGE ||
     335       68244 :         (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE);
     336             : 
     337             :     /*
     338             :      * initialize arrays needed for heap_form_tuple or heap_modify_tuple
     339             :      */
     340     4657224 :     for (i = 0; i < Natts_pg_type; ++i)
     341             :     {
     342     4516096 :         nulls[i] = false;
     343     4516096 :         replaces[i] = true;
     344     4516096 :         values[i] = (Datum) 0;
     345             :     }
     346             : 
     347             :     /*
     348             :      * insert data values
     349             :      */
     350      141128 :     namestrcpy(&name, typeName);
     351      141128 :     values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
     352      141128 :     values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
     353      141128 :     values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
     354      141128 :     values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
     355      141128 :     values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
     356      141128 :     values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
     357      141128 :     values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
     358      141128 :     values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
     359      141128 :     values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
     360      141128 :     values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
     361      141128 :     values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
     362      141128 :     values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(subscriptProcedure);
     363      141128 :     values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
     364      141128 :     values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
     365      141128 :     values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
     366      141128 :     values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
     367      141128 :     values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
     368      141128 :     values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
     369      141128 :     values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
     370      141128 :     values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
     371      141128 :     values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
     372      141128 :     values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
     373      141128 :     values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
     374      141128 :     values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
     375      141128 :     values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
     376      141128 :     values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
     377      141128 :     values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
     378      141128 :     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      141128 :     if (defaultTypeBin)
     385         162 :         values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
     386             :     else
     387      140966 :         nulls[Anum_pg_type_typdefaultbin - 1] = true;
     388             : 
     389             :     /*
     390             :      * initialize the default value for this type.
     391             :      */
     392      141128 :     if (defaultTypeValue)
     393         180 :         values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
     394             :     else
     395      140948 :         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      141128 :     if (isDependentType)
     401      134468 :         typacl = NULL;
     402             :     else
     403        6660 :         typacl = get_user_default_acl(OBJECT_TYPE, ownerId,
     404             :                                       typeNamespace);
     405      141128 :     if (typacl != NULL)
     406           6 :         values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
     407             :     else
     408      141122 :         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      141128 :     pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
     417             : 
     418      141128 :     tup = SearchSysCacheCopy2(TYPENAMENSP,
     419             :                               CStringGetDatum(typeName),
     420             :                               ObjectIdGetDatum(typeNamespace));
     421      141128 :     if (HeapTupleIsValid(tup))
     422             :     {
     423         218 :         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         218 :         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         218 :         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         218 :         if (OidIsValid(newTypeOid))
     442           0 :             elog(ERROR, "cannot assign new OID to existing shell type");
     443             : 
     444         218 :         replaces[Anum_pg_type_oid - 1] = false;
     445             : 
     446             :         /*
     447             :          * Okay to update existing shell type tuple
     448             :          */
     449         218 :         tup = heap_modify_tuple(tup,
     450             :                                 RelationGetDescr(pg_type_desc),
     451             :                                 values,
     452             :                                 nulls,
     453             :                                 replaces);
     454             : 
     455         218 :         CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup);
     456             : 
     457         218 :         typeObjectId = typform->oid;
     458             : 
     459         218 :         rebuildDeps = true;     /* get rid of shell type's dependencies */
     460             :     }
     461             :     else
     462             :     {
     463             :         /* Force the OID if requested by caller */
     464      140910 :         if (OidIsValid(newTypeOid))
     465       71214 :             typeObjectId = newTypeOid;
     466             :         /* Use binary-upgrade override for pg_type.oid, if supplied. */
     467       69696 :         else if (IsBinaryUpgrade)
     468             :         {
     469        1708 :             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        1708 :             typeObjectId = binary_upgrade_next_pg_type_oid;
     475        1708 :             binary_upgrade_next_pg_type_oid = InvalidOid;
     476             :         }
     477             :         else
     478             :         {
     479       67988 :             typeObjectId = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
     480             :                                               Anum_pg_type_oid);
     481             :         }
     482             : 
     483      140910 :         values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typeObjectId);
     484             : 
     485      140910 :         tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
     486             :                               values, nulls);
     487             : 
     488      140910 :         CatalogTupleInsert(pg_type_desc, tup);
     489             :     }
     490             : 
     491             :     /*
     492             :      * Create dependencies.  We can/must skip this in bootstrap mode.
     493             :      */
     494      141128 :     if (!IsBootstrapProcessingMode())
     495      129290 :         GenerateTypeDependencies(tup,
     496             :                                  pg_type_desc,
     497             :                                  (defaultTypeBin ?
     498         162 :                                   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      141126 :     InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
     509             : 
     510      141126 :     ObjectAddressSet(address, TypeRelationId, typeObjectId);
     511             : 
     512             :     /*
     513             :      * finish up
     514             :      */
     515      141126 :     table_close(pg_type_desc, RowExclusiveLock);
     516             : 
     517      141126 :     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      129450 : 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      129450 :     Form_pg_type typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
     566      129450 :     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      129450 :     if (defaultExpr == NULL)
     575             :     {
     576      129280 :         datum = heap_getattr(typeTuple, Anum_pg_type_typdefaultbin,
     577             :                              RelationGetDescr(typeCatalog), &isNull);
     578      129280 :         if (!isNull)
     579           0 :             defaultExpr = stringToNode(TextDatumGetCString(datum));
     580             :     }
     581             :     /* Extract typacl if caller didn't pass it */
     582      129450 :     if (typacl == NULL)
     583             :     {
     584      129444 :         datum = heap_getattr(typeTuple, Anum_pg_type_typacl,
     585             :                              RelationGetDescr(typeCatalog), &isNull);
     586      129444 :         if (!isNull)
     587           0 :             typacl = DatumGetAclPCopy(datum);
     588             :     }
     589             : 
     590             :     /* If rebuild, first flush old dependencies, except extension deps */
     591      129450 :     if (rebuild)
     592             :     {
     593         298 :         deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
     594         298 :         deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
     595             :     }
     596             : 
     597      129450 :     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      129450 :     addrs_normal = new_object_addresses();
     610             : 
     611      129450 :     if (!isDependentType || typeForm->typtype == TYPTYPE_MULTIRANGE)
     612             :     {
     613        7136 :         ObjectAddressSet(referenced, NamespaceRelationId,
     614             :                          typeForm->typnamespace);
     615        7136 :         add_exact_object_address(&referenced, addrs_normal);
     616             :     }
     617             : 
     618      129450 :     if (!isDependentType)
     619             :     {
     620        6976 :         recordDependencyOnOwner(TypeRelationId, typeObjectId,
     621             :                                 typeForm->typowner);
     622             : 
     623        6976 :         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      129450 :     if (makeExtensionDep)
     635      129370 :         recordDependencyOnCurrentExtension(&myself, rebuild);
     636             : 
     637             :     /* Normal dependencies on the I/O and support functions */
     638      129448 :     if (OidIsValid(typeForm->typinput))
     639             :     {
     640      129448 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typinput);
     641      129448 :         add_exact_object_address(&referenced, addrs_normal);
     642             :     }
     643             : 
     644      129448 :     if (OidIsValid(typeForm->typoutput))
     645             :     {
     646      129448 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typoutput);
     647      129448 :         add_exact_object_address(&referenced, addrs_normal);
     648             :     }
     649             : 
     650      129448 :     if (OidIsValid(typeForm->typreceive))
     651             :     {
     652      129002 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typreceive);
     653      129002 :         add_exact_object_address(&referenced, addrs_normal);
     654             :     }
     655             : 
     656      129448 :     if (OidIsValid(typeForm->typsend))
     657             :     {
     658      128990 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsend);
     659      128990 :         add_exact_object_address(&referenced, addrs_normal);
     660             :     }
     661             : 
     662      129448 :     if (OidIsValid(typeForm->typmodin))
     663             :     {
     664          28 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodin);
     665          28 :         add_exact_object_address(&referenced, addrs_normal);
     666             :     }
     667             : 
     668      129448 :     if (OidIsValid(typeForm->typmodout))
     669             :     {
     670          28 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodout);
     671          28 :         add_exact_object_address(&referenced, addrs_normal);
     672             :     }
     673             : 
     674      129448 :     if (OidIsValid(typeForm->typanalyze))
     675             :     {
     676       65056 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typanalyze);
     677       65056 :         add_exact_object_address(&referenced, addrs_normal);
     678             :     }
     679             : 
     680      129448 :     if (OidIsValid(typeForm->typsubscript))
     681             :     {
     682       64588 :         ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsubscript);
     683       64588 :         add_exact_object_address(&referenced, addrs_normal);
     684             :     }
     685             : 
     686             :     /* Normal dependency from a domain to its base type. */
     687      129448 :     if (OidIsValid(typeForm->typbasetype))
     688             :     {
     689        1364 :         ObjectAddressSet(referenced, TypeRelationId, typeForm->typbasetype);
     690        1364 :         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      129448 :     if (OidIsValid(typeForm->typcollation) &&
     698        1040 :         typeForm->typcollation != DEFAULT_COLLATION_OID)
     699             :     {
     700         616 :         ObjectAddressSet(referenced, CollationRelationId, typeForm->typcollation);
     701         616 :         add_exact_object_address(&referenced, addrs_normal);
     702             :     }
     703             : 
     704      129448 :     record_object_address_dependencies(&myself, addrs_normal, DEPENDENCY_NORMAL);
     705      129448 :     free_object_addresses(addrs_normal);
     706             : 
     707             :     /* Normal dependency on the default expression. */
     708      129448 :     if (defaultExpr)
     709         170 :         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      129448 :     if (OidIsValid(typeForm->typrelid))
     721             :     {
     722       62244 :         ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid);
     723             : 
     724       62244 :         if (relationKind != RELKIND_COMPOSITE_TYPE)
     725       57754 :             recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
     726             :         else
     727        4490 :             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      129448 :     if (OidIsValid(typeForm->typelem))
     736             :     {
     737       64568 :         ObjectAddressSet(referenced, TypeRelationId, typeForm->typelem);
     738       64568 :         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      129448 : }
     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         332 : 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         332 :     pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
     772             : 
     773         332 :     tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
     774         332 :     if (!HeapTupleIsValid(tuple))
     775           0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
     776         332 :     typ = (Form_pg_type) GETSTRUCT(tuple);
     777             : 
     778             :     /* We are not supposed to be changing schemas here */
     779             :     Assert(typeNamespace == typ->typnamespace);
     780             : 
     781         332 :     arrayOid = typ->typarray;
     782             : 
     783             :     /* Check for a conflicting type name. */
     784         332 :     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         332 :     if (OidIsValid(oldTypeOid))
     796             :     {
     797          24 :         if (get_typisdefined(oldTypeOid) &&
     798          12 :             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         332 :     namestrcpy(&(typ->typname), newTypeName);
     808             : 
     809         332 :     CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
     810             : 
     811         332 :     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
     812             : 
     813         332 :     heap_freetuple(tuple);
     814         332 :     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         332 :     if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
     822             :     {
     823         150 :         char       *arrname = makeArrayTypeName(newTypeName, typeNamespace);
     824             : 
     825         150 :         RenameTypeInternal(arrayOid, arrname, typeNamespace);
     826         150 :         pfree(arrname);
     827             :     }
     828         332 : }
     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       70730 : makeArrayTypeName(const char *typeName, Oid typeNamespace)
     839             : {
     840             :     char       *arr_name;
     841       70730 :     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       70730 :     arr_name = makeObjectName("", typeName, NULL);
     860             : 
     861             :     for (;;)
     862             :     {
     863       70750 :         if (!SearchSysCacheExists2(TYPENAMENSP,
     864             :                                    CStringGetDatum(arr_name),
     865             :                                    ObjectIdGetDatum(typeNamespace)))
     866       70730 :             break;
     867             : 
     868             :         /* That attempt conflicted.  Prepare a new name with some digits. */
     869          20 :         pfree(arr_name);
     870          20 :         snprintf(suffix, sizeof(suffix), "%d", ++pass);
     871          20 :         arr_name = makeObjectName("", typeName, suffix);
     872             :     }
     873             : 
     874       70730 :     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          40 : 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          40 :     if (!get_typisdefined(typeOid))
     910           2 :         return true;
     911             : 
     912             :     /* Can't change it if it's not an autogenerated array type. */
     913          38 :     elemOid = get_element_type(typeOid);
     914          64 :     if (!OidIsValid(elemOid) ||
     915          26 :         get_array_type(elemOid) != typeOid)
     916          12 :         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          26 :     newname = makeArrayTypeName(typeName, typeNamespace);
     925             : 
     926             :     /* Apply the rename */
     927          26 :     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          26 :     CommandCounterIncrement();
     934             : 
     935          26 :     pfree(newname);
     936             : 
     937          26 :     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         142 : makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace)
     949             : {
     950             :     char       *buf;
     951             :     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         142 :     rangestr = strstr(rangeTypeName, "range");
     958         142 :     if (rangestr)
     959             :     {
     960         124 :         char       *prefix = pnstrdup(rangeTypeName, rangestr - rangeTypeName);
     961             : 
     962         124 :         buf = psprintf("%s%s%s", prefix, "multi", rangestr);
     963             :     }
     964             :     else
     965          18 :         buf = psprintf("%s_multirange", pnstrdup(rangeTypeName, NAMEDATALEN - 12));
     966             : 
     967             :     /* clip it at NAMEDATALEN-1 bytes */
     968         142 :     buf[pg_mbcliplen(buf, strlen(buf), NAMEDATALEN - 1)] = '\0';
     969             : 
     970         142 :     if (SearchSysCacheExists2(TYPENAMENSP,
     971             :                               CStringGetDatum(buf),
     972             :                               ObjectIdGetDatum(typeNamespace)))
     973          12 :         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         130 :     return pstrdup(buf);
     980             : }

Generated by: LCOV version 1.16