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

Generated by: LCOV version 2.0-1