LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_type.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 93.6 % 281 263
Test Date: 2026-08-15 17:15:51 Functions: 100.0 % 7 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 69.1 % 194 134

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

Generated by: LCOV version 2.0-1