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

Generated by: LCOV version 1.14