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

Generated by: LCOV version 1.14