LCOV - differential code coverage report
Current view: top level - src/backend/catalog - pg_enum.c (source / functions) Coverage Total Hit UNC UBC GIC GNC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 92.0 % 261 240 12 9 1 41 198 5 17
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 14 14 10 4 1
Baseline: 16@8cea358b128 Branches: 72.4 % 156 113 18 25 20 93
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 77.4 % 53 41 12 38 3
(240..) days: 95.7 % 208 199 9 1 3 195
Function coverage date bins:
[..60] days: 100.0 % 3 3 3
(240..) days: 100.0 % 11 11 7 4
Branch coverage date bins:
[..60] days: 52.6 % 38 20 18 20
(240..) days: 78.8 % 118 93 25 93

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * pg_enum.c
                                  4                 :                :  *    routines to support manipulation of the pg_enum relation
                                  5                 :                :  *
                                  6                 :                :  * Copyright (c) 2006-2024, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  *
                                  9                 :                :  * IDENTIFICATION
                                 10                 :                :  *    src/backend/catalog/pg_enum.c
                                 11                 :                :  *
                                 12                 :                :  *-------------------------------------------------------------------------
                                 13                 :                :  */
                                 14                 :                : #include "postgres.h"
                                 15                 :                : 
                                 16                 :                : #include "access/genam.h"
                                 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/indexing.h"
                                 23                 :                : #include "catalog/pg_enum.h"
                                 24                 :                : #include "catalog/pg_type.h"
                                 25                 :                : #include "miscadmin.h"
                                 26                 :                : #include "nodes/value.h"
                                 27                 :                : #include "storage/lmgr.h"
                                 28                 :                : #include "utils/builtins.h"
                                 29                 :                : #include "utils/catcache.h"
                                 30                 :                : #include "utils/fmgroids.h"
                                 31                 :                : #include "utils/hsearch.h"
                                 32                 :                : #include "utils/memutils.h"
                                 33                 :                : #include "utils/syscache.h"
                                 34                 :                : 
                                 35                 :                : /* Potentially set by pg_upgrade_support functions */
                                 36                 :                : Oid         binary_upgrade_next_pg_enum_oid = InvalidOid;
                                 37                 :                : 
                                 38                 :                : /*
                                 39                 :                :  * We keep two transaction-lifespan hash tables, one containing the OIDs
                                 40                 :                :  * of enum types made in the current transaction, and one containing the
                                 41                 :                :  * OIDs of enum values created during the current transaction by
                                 42                 :                :  * AddEnumLabel (but only if their enum type is not in the first hash).
                                 43                 :                :  *
                                 44                 :                :  * We disallow using enum values in the second hash until the transaction is
                                 45                 :                :  * committed; otherwise, they might get into indexes where we can't clean
                                 46                 :                :  * them up, and then if the transaction rolls back we have a broken index.
                                 47                 :                :  * (See comments for check_safe_enum_use() in enum.c.)  Values created by
                                 48                 :                :  * EnumValuesCreate are *not* entered into the table; we assume those are
                                 49                 :                :  * created during CREATE TYPE, so they can't go away unless the enum type
                                 50                 :                :  * itself does.
                                 51                 :                :  *
                                 52                 :                :  * The motivation for treating enum values as safe if their type OID is
                                 53                 :                :  * in the first hash is to allow CREATE TYPE AS ENUM; ALTER TYPE ADD VALUE;
                                 54                 :                :  * followed by a use of the value in the same transaction.  This pattern
                                 55                 :                :  * is really just as safe as creating the value during CREATE TYPE.
                                 56                 :                :  * We need to support this because pg_dump in binary upgrade mode produces
                                 57                 :                :  * commands like that.  But currently we only support it when the commands
                                 58                 :                :  * are at the outermost transaction level, which is as much as we need for
                                 59                 :                :  * pg_dump.  We could track subtransaction nesting of the commands to
                                 60                 :                :  * analyze things more precisely, but for now we don't bother.
                                 61                 :                :  */
                                 62                 :                : static HTAB *uncommitted_enum_types = NULL;
                                 63                 :                : static HTAB *uncommitted_enum_values = NULL;
                                 64                 :                : 
                                 65                 :                : static void init_uncommitted_enum_types(void);
                                 66                 :                : static void init_uncommitted_enum_values(void);
                                 67                 :                : static bool EnumTypeUncommitted(Oid typ_id);
                                 68                 :                : static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems);
                                 69                 :                : static int  sort_order_cmp(const void *p1, const void *p2);
                                 70                 :                : 
                                 71                 :                : 
                                 72                 :                : /*
                                 73                 :                :  * EnumValuesCreate
                                 74                 :                :  *      Create an entry in pg_enum for each of the supplied enum values.
                                 75                 :                :  *
                                 76                 :                :  * vals is a list of String values.
                                 77                 :                :  *
                                 78                 :                :  * We assume that this is called only by CREATE TYPE AS ENUM, and that it
                                 79                 :                :  * will be called even if the vals list is empty.  So we can enter the
                                 80                 :                :  * enum type's OID into uncommitted_enum_types here, rather than needing
                                 81                 :                :  * another entry point to do it.
                                 82                 :                :  */
                                 83                 :                : void
 4921 tgl@sss.pgh.pa.us          84                 :CBC         211 : EnumValuesCreate(Oid enumTypeOid, List *vals)
                                 85                 :                : {
                                 86                 :                :     Relation    pg_enum;
                                 87                 :                :     Oid        *oids;
                                 88                 :                :     int         elemno,
                                 89                 :                :                 num_elems;
                                 90                 :                :     ListCell   *lc;
  515 michael@paquier.xyz        91                 :            211 :     int         slotCount = 0;
                                 92                 :                :     int         nslots;
                                 93                 :                :     CatalogIndexState indstate;
                                 94                 :                :     TupleTableSlot **slot;
                                 95                 :                : 
                                 96                 :                :     /*
                                 97                 :                :      * Remember the type OID as being made in the current transaction, but not
                                 98                 :                :      * if we're in a subtransaction.  (We could remember the OID anyway, in
                                 99                 :                :      * case a subsequent ALTER ADD VALUE occurs at outer level.  But that
                                100                 :                :      * usage pattern seems unlikely enough that we'd probably just be wasting
                                101                 :                :      * hashtable maintenance effort.)
                                102                 :                :      */
   21 tgl@sss.pgh.pa.us         103         [ +  - ]:GNC         211 :     if (GetCurrentTransactionNestLevel() == 1)
                                104                 :                :     {
                                105         [ +  + ]:            211 :         if (uncommitted_enum_types == NULL)
                                106                 :            208 :             init_uncommitted_enum_types();
                                107                 :            211 :         (void) hash_search(uncommitted_enum_types, &enumTypeOid,
                                108                 :                :                            HASH_ENTER, NULL);
                                109                 :                :     }
                                110                 :                : 
 5225 bruce@momjian.us          111                 :CBC         211 :     num_elems = list_length(vals);
                                112                 :                : 
                                113                 :                :     /*
                                114                 :                :      * We do not bother to check the list of values for duplicates --- if you
                                115                 :                :      * have any, you'll get a less-than-friendly unique-index violation. It is
                                116                 :                :      * probably not worth trying harder.
                                117                 :                :      */
                                118                 :                : 
 1910 andres@anarazel.de        119                 :            211 :     pg_enum = table_open(EnumRelationId, RowExclusiveLock);
                                120                 :                : 
                                121                 :                :     /*
                                122                 :                :      * Allocate OIDs for the enum's members.
                                123                 :                :      *
                                124                 :                :      * While this method does not absolutely guarantee that we generate no
                                125                 :                :      * duplicate OIDs (since we haven't entered each oid into the table before
                                126                 :                :      * allocating the next), trouble could only occur if the OID counter wraps
                                127                 :                :      * all the way around before we finish. Which seems unlikely.
                                128                 :                :      */
 5225 bruce@momjian.us          129                 :            211 :     oids = (Oid *) palloc(num_elems * sizeof(Oid));
                                130                 :                : 
 4921 tgl@sss.pgh.pa.us         131         [ +  + ]:         125492 :     for (elemno = 0; elemno < num_elems; elemno++)
                                132                 :                :     {
                                133                 :                :         /*
                                134                 :                :          * We assign even-numbered OIDs to all the new enum labels.  This
                                135                 :                :          * tells the comparison functions the OIDs are in the correct sort
                                136                 :                :          * order and can be compared directly.
                                137                 :                :          */
                                138                 :                :         Oid         new_oid;
                                139                 :                : 
                                140                 :                :         do
                                141                 :                :         {
 1972 andres@anarazel.de        142                 :         250522 :             new_oid = GetNewOidWithIndex(pg_enum, EnumOidIndexId,
                                143                 :                :                                          Anum_pg_enum_oid);
 4921 tgl@sss.pgh.pa.us         144         [ +  + ]:         250522 :         } while (new_oid & 1);
                                145                 :         125281 :         oids[elemno] = new_oid;
                                146                 :                :     }
                                147                 :                : 
                                148                 :                :     /* sort them, just in case OID counter wrapped from high to low */
                                149                 :            211 :     qsort(oids, num_elems, sizeof(Oid), oid_cmp);
                                150                 :                : 
                                151                 :                :     /* and make the entries */
  515 michael@paquier.xyz       152                 :            211 :     indstate = CatalogOpenIndexes(pg_enum);
                                153                 :                : 
                                154                 :                :     /* allocate the slots to use and initialize them */
                                155         [ +  + ]:            211 :     nslots = Min(num_elems,
                                156                 :                :                  MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_enum));
                                157                 :            211 :     slot = palloc(sizeof(TupleTableSlot *) * nslots);
                                158         [ +  + ]:         108242 :     for (int i = 0; i < nslots; i++)
                                159                 :         108031 :         slot[i] = MakeSingleTupleTableSlot(RelationGetDescr(pg_enum),
                                160                 :                :                                            &TTSOpsHeapTuple);
                                161                 :                : 
 5225 bruce@momjian.us          162                 :            211 :     elemno = 0;
 6222 tgl@sss.pgh.pa.us         163   [ +  +  +  +  :         125492 :     foreach(lc, vals)
                                              +  + ]
                                164                 :                :     {
 5995 bruce@momjian.us          165                 :         125281 :         char       *lab = strVal(lfirst(lc));
  515 michael@paquier.xyz       166                 :         125281 :         Name        enumlabel = palloc0(NAMEDATALEN);
                                167                 :                : 
                                168                 :                :         /*
                                169                 :                :          * labels are stored in a name field, for easier syscache lookup, so
                                170                 :                :          * check the length to make sure it's within range.
                                171                 :                :          */
 6222 andrew@dunslane.net       172         [ -  + ]:         125281 :         if (strlen(lab) > (NAMEDATALEN - 1))
 6222 andrew@dunslane.net       173         [ #  # ]:UBC           0 :             ereport(ERROR,
                                174                 :                :                     (errcode(ERRCODE_INVALID_NAME),
                                175                 :                :                      errmsg("invalid enum label \"%s\"", lab),
                                176                 :                :                      errdetail("Labels must be %d bytes or less.",
                                177                 :                :                                NAMEDATALEN - 1)));
                                178                 :                : 
  515 michael@paquier.xyz       179                 :CBC      125281 :         ExecClearTuple(slot[slotCount]);
                                180                 :                : 
                                181                 :         125281 :         memset(slot[slotCount]->tts_isnull, false,
                                182                 :         125281 :                slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
                                183                 :                : 
                                184                 :         125281 :         slot[slotCount]->tts_values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(oids[elemno]);
                                185                 :         125281 :         slot[slotCount]->tts_values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
                                186                 :         125281 :         slot[slotCount]->tts_values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1);
                                187                 :                : 
                                188                 :         125281 :         namestrcpy(enumlabel, lab);
                                189                 :         125281 :         slot[slotCount]->tts_values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(enumlabel);
                                190                 :                : 
                                191                 :         125281 :         ExecStoreVirtualTuple(slot[slotCount]);
                                192                 :         125281 :         slotCount++;
                                193                 :                : 
                                194                 :                :         /* if slots are full, insert a batch of tuples */
                                195         [ +  + ]:         125281 :         if (slotCount == nslots)
                                196                 :                :         {
                                197                 :            207 :             CatalogTuplesMultiInsertWithInfo(pg_enum, slot, slotCount,
                                198                 :                :                                              indstate);
                                199                 :            207 :             slotCount = 0;
                                200                 :                :         }
                                201                 :                : 
 5225 bruce@momjian.us          202                 :         125281 :         elemno++;
                                203                 :                :     }
                                204                 :                : 
                                205                 :                :     /* Insert any tuples left in the buffer */
  515 michael@paquier.xyz       206         [ +  + ]:            211 :     if (slotCount > 0)
                                207                 :            125 :         CatalogTuplesMultiInsertWithInfo(pg_enum, slot, slotCount,
                                208                 :                :                                          indstate);
                                209                 :                : 
                                210                 :                :     /* clean up */
 6222 tgl@sss.pgh.pa.us         211                 :            211 :     pfree(oids);
  515 michael@paquier.xyz       212         [ +  + ]:         108242 :     for (int i = 0; i < nslots; i++)
                                213                 :         108031 :         ExecDropSingleTupleTableSlot(slot[i]);
                                214                 :            211 :     CatalogCloseIndexes(indstate);
 1910 andres@anarazel.de        215                 :            211 :     table_close(pg_enum, RowExclusiveLock);
 6222 tgl@sss.pgh.pa.us         216                 :            211 : }
                                217                 :                : 
                                218                 :                : 
                                219                 :                : /*
                                220                 :                :  * EnumValuesDelete
                                221                 :                :  *      Remove all the pg_enum entries for the specified enum type.
                                222                 :                :  */
                                223                 :                : void
                                224                 :            156 : EnumValuesDelete(Oid enumTypeOid)
                                225                 :                : {
                                226                 :                :     Relation    pg_enum;
                                227                 :                :     ScanKeyData key[1];
                                228                 :                :     SysScanDesc scan;
                                229                 :                :     HeapTuple   tup;
                                230                 :                : 
 1910 andres@anarazel.de        231                 :            156 :     pg_enum = table_open(EnumRelationId, RowExclusiveLock);
                                232                 :                : 
 6222 tgl@sss.pgh.pa.us         233                 :            156 :     ScanKeyInit(&key[0],
                                234                 :                :                 Anum_pg_enum_enumtypid,
                                235                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                                236                 :                :                 ObjectIdGetDatum(enumTypeOid));
                                237                 :                : 
                                238                 :            156 :     scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true,
                                239                 :                :                               NULL, 1, key);
                                240                 :                : 
                                241         [ +  + ]:         125258 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
                                242                 :                :     {
 2629                           243                 :         125102 :         CatalogTupleDelete(pg_enum, &tup->t_self);
                                244                 :                :     }
                                245                 :                : 
 6222                           246                 :            156 :     systable_endscan(scan);
                                247                 :                : 
 1910 andres@anarazel.de        248                 :            156 :     table_close(pg_enum, RowExclusiveLock);
 6222 tgl@sss.pgh.pa.us         249                 :            156 : }
                                250                 :                : 
                                251                 :                : /*
                                252                 :                :  * Initialize the uncommitted enum types table for this transaction.
                                253                 :                :  */
                                254                 :                : static void
   21 tgl@sss.pgh.pa.us         255                 :GNC         208 : init_uncommitted_enum_types(void)
                                256                 :                : {
                                257                 :                :     HASHCTL     hash_ctl;
                                258                 :                : 
   21 tgl@sss.pgh.pa.us         259                 :CBC         208 :     hash_ctl.keysize = sizeof(Oid);
                                260                 :            208 :     hash_ctl.entrysize = sizeof(Oid);
                                261                 :            208 :     hash_ctl.hcxt = TopTransactionContext;
   21 tgl@sss.pgh.pa.us         262                 :GNC         208 :     uncommitted_enum_types = hash_create("Uncommitted enum types",
                                263                 :                :                                          32,
                                264                 :                :                                          &hash_ctl,
                                265                 :                :                                          HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
                                266                 :            208 : }
                                267                 :                : 
                                268                 :                : /*
                                269                 :                :  * Initialize the uncommitted enum values table for this transaction.
                                270                 :                :  */
                                271                 :                : static void
                                272                 :            117 : init_uncommitted_enum_values(void)
                                273                 :                : {
                                274                 :                :     HASHCTL     hash_ctl;
                                275                 :                : 
 2014 tmunro@postgresql.or      276                 :            117 :     hash_ctl.keysize = sizeof(Oid);
                                277                 :            117 :     hash_ctl.entrysize = sizeof(Oid);
                                278                 :            117 :     hash_ctl.hcxt = TopTransactionContext;
   21 tgl@sss.pgh.pa.us         279                 :            117 :     uncommitted_enum_values = hash_create("Uncommitted enum values",
                                280                 :                :                                           32,
                                281                 :                :                                           &hash_ctl,
                                282                 :                :                                           HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
 2014 tmunro@postgresql.or      283                 :CBC         117 : }
                                284                 :                : 
                                285                 :                : /*
                                286                 :                :  * AddEnumLabel
                                287                 :                :  *      Add a new label to the enum set. By default it goes at
                                288                 :                :  *      the end, but the user can choose to place it before or
                                289                 :                :  *      after any existing set member.
                                290                 :                :  */
                                291                 :                : void
 4921 tgl@sss.pgh.pa.us         292                 :            185 : AddEnumLabel(Oid enumTypeOid,
                                293                 :                :              const char *newVal,
                                294                 :                :              const char *neighbor,
                                295                 :                :              bool newValIsAfter,
                                296                 :                :              bool skipIfExists)
                                297                 :                : {
                                298                 :                :     Relation    pg_enum;
                                299                 :                :     Oid         newOid;
                                300                 :                :     Datum       values[Natts_pg_enum];
                                301                 :                :     bool        nulls[Natts_pg_enum];
                                302                 :                :     NameData    enumlabel;
                                303                 :                :     HeapTuple   enum_tup;
                                304                 :                :     float4      newelemorder;
                                305                 :                :     HeapTuple  *existing;
                                306                 :                :     CatCList   *list;
                                307                 :                :     int         nelems;
                                308                 :                :     int         i;
                                309                 :                : 
                                310                 :                :     /* check length of new label is ok */
                                311         [ +  + ]:            185 :     if (strlen(newVal) > (NAMEDATALEN - 1))
                                312         [ +  - ]:              3 :         ereport(ERROR,
                                313                 :                :                 (errcode(ERRCODE_INVALID_NAME),
                                314                 :                :                  errmsg("invalid enum label \"%s\"", newVal),
                                315                 :                :                  errdetail("Labels must be %d bytes or less.",
                                316                 :                :                            NAMEDATALEN - 1)));
                                317                 :                : 
                                318                 :                :     /*
                                319                 :                :      * Acquire a lock on the enum type, which we won't release until commit.
                                320                 :                :      * This ensures that two backends aren't concurrently modifying the same
                                321                 :                :      * enum type.  Without that, we couldn't be sure to get a consistent view
                                322                 :                :      * of the enum members via the syscache.  Note that this does not block
                                323                 :                :      * other backends from inspecting the type; see comments for
                                324                 :                :      * RenumberEnumType.
                                325                 :                :      */
                                326                 :            182 :     LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock);
                                327                 :                : 
                                328                 :                :     /*
                                329                 :                :      * Check if label is already in use.  The unique index on pg_enum would
                                330                 :                :      * catch this anyway, but we prefer a friendlier error message, and
                                331                 :                :      * besides we need a check to support IF NOT EXISTS.
                                332                 :                :      */
 4222                           333                 :            182 :     enum_tup = SearchSysCache2(ENUMTYPOIDNAME,
                                334                 :                :                                ObjectIdGetDatum(enumTypeOid),
                                335                 :                :                                CStringGetDatum(newVal));
                                336         [ +  + ]:            182 :     if (HeapTupleIsValid(enum_tup))
                                337                 :                :     {
                                338                 :              6 :         ReleaseSysCache(enum_tup);
                                339         [ +  + ]:              6 :         if (skipIfExists)
                                340                 :                :         {
                                341         [ +  - ]:              3 :             ereport(NOTICE,
                                342                 :                :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
                                343                 :                :                      errmsg("enum label \"%s\" already exists, skipping",
                                344                 :                :                             newVal)));
      andrew@dunslane.net       345                 :             59 :             return;
                                346                 :                :         }
                                347                 :                :         else
      tgl@sss.pgh.pa.us         348         [ +  - ]:              3 :             ereport(ERROR,
                                349                 :                :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
                                350                 :                :                      errmsg("enum label \"%s\" already exists",
                                351                 :                :                             newVal)));
                                352                 :                :     }
                                353                 :                : 
 1910 andres@anarazel.de        354                 :            176 :     pg_enum = table_open(EnumRelationId, RowExclusiveLock);
                                355                 :                : 
                                356                 :                :     /* If we have to renumber the existing members, we restart from here */
 4921 tgl@sss.pgh.pa.us         357                 :            179 : restart:
                                358                 :                : 
                                359                 :                :     /* Get the list of existing members of the enum */
                                360                 :            179 :     list = SearchSysCacheList1(ENUMTYPOIDNAME,
                                361                 :                :                                ObjectIdGetDatum(enumTypeOid));
 4753 bruce@momjian.us          362                 :            179 :     nelems = list->n_members;
                                363                 :                : 
                                364                 :                :     /* Sort the existing members by enumsortorder */
 4921 tgl@sss.pgh.pa.us         365                 :            179 :     existing = (HeapTuple *) palloc(nelems * sizeof(HeapTuple));
                                366         [ +  + ]:           2440 :     for (i = 0; i < nelems; i++)
                                367                 :           2261 :         existing[i] = &(list->members[i]->tuple);
                                368                 :                : 
                                369                 :            179 :     qsort(existing, nelems, sizeof(HeapTuple), sort_order_cmp);
                                370                 :                : 
                                371         [ +  + ]:            179 :     if (neighbor == NULL)
                                372                 :                :     {
                                373                 :                :         /*
                                374                 :                :          * Put the new label at the end of the list. No change to existing
                                375                 :                :          * tuples is required.
                                376                 :                :          */
                                377         [ +  + ]:             68 :         if (nelems > 0)
                                378                 :                :         {
                                379                 :             64 :             Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nelems - 1]);
                                380                 :                : 
                                381                 :             64 :             newelemorder = en->enumsortorder + 1;
                                382                 :                :         }
                                383                 :                :         else
                                384                 :              4 :             newelemorder = 1;
                                385                 :                :     }
                                386                 :                :     else
                                387                 :                :     {
                                388                 :                :         /* BEFORE or AFTER was specified */
                                389                 :                :         int         nbr_index;
                                390                 :                :         int         other_nbr_index;
                                391                 :                :         Form_pg_enum nbr_en;
                                392                 :                :         Form_pg_enum other_nbr_en;
                                393                 :                : 
                                394                 :                :         /* Locate the neighbor element */
                                395         [ +  + ]:           1643 :         for (nbr_index = 0; nbr_index < nelems; nbr_index++)
                                396                 :                :         {
                                397                 :           1640 :             Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]);
                                398                 :                : 
                                399         [ +  + ]:           1640 :             if (strcmp(NameStr(en->enumlabel), neighbor) == 0)
                                400                 :            108 :                 break;
                                401                 :                :         }
                                402         [ +  + ]:            111 :         if (nbr_index >= nelems)
                                403         [ +  - ]:              3 :             ereport(ERROR,
                                404                 :                :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                405                 :                :                      errmsg("\"%s\" is not an existing enum label",
                                406                 :                :                             neighbor)));
                                407                 :            108 :         nbr_en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]);
                                408                 :                : 
                                409                 :                :         /*
                                410                 :                :          * Attempt to assign an appropriate enumsortorder value: one less than
                                411                 :                :          * the smallest member, one more than the largest member, or halfway
                                412                 :                :          * between two existing members.
                                413                 :                :          *
                                414                 :                :          * In the "halfway" case, because of the finite precision of float4,
                                415                 :                :          * we might compute a value that's actually equal to one or the other
                                416                 :                :          * of its neighbors.  In that case we renumber the existing members
                                417                 :                :          * and try again.
                                418                 :                :          */
                                419         [ +  + ]:            108 :         if (newValIsAfter)
                                420                 :              8 :             other_nbr_index = nbr_index + 1;
                                421                 :                :         else
                                422                 :            100 :             other_nbr_index = nbr_index - 1;
                                423                 :                : 
                                424         [ +  + ]:            108 :         if (other_nbr_index < 0)
                                425                 :              4 :             newelemorder = nbr_en->enumsortorder - 1;
                                426         [ +  + ]:            104 :         else if (other_nbr_index >= nelems)
                                427                 :              4 :             newelemorder = nbr_en->enumsortorder + 1;
                                428                 :                :         else
                                429                 :                :         {
                                430                 :                :             /*
                                431                 :                :              * The midpoint value computed here has to be rounded to float4
                                432                 :                :              * precision, else our equality comparisons against the adjacent
                                433                 :                :              * values are meaningless.  The most portable way of forcing that
                                434                 :                :              * to happen with non-C-standard-compliant compilers is to store
                                435                 :                :              * it into a volatile variable.
                                436                 :                :              */
                                437                 :                :             volatile float4 midpoint;
                                438                 :                : 
 2783                           439                 :            100 :             other_nbr_en = (Form_pg_enum) GETSTRUCT(existing[other_nbr_index]);
                                440                 :            100 :             midpoint = (nbr_en->enumsortorder +
                                441                 :            100 :                         other_nbr_en->enumsortorder) / 2;
                                442                 :                : 
                                443         [ +  + ]:            100 :             if (midpoint == nbr_en->enumsortorder ||
                                444         [ -  + ]:             97 :                 midpoint == other_nbr_en->enumsortorder)
                                445                 :                :             {
 4921                           446                 :              3 :                 RenumberEnumType(pg_enum, existing, nelems);
                                447                 :                :                 /* Clean up and start over */
                                448                 :              3 :                 pfree(existing);
                                449                 :              3 :                 ReleaseCatCacheList(list);
                                450                 :              3 :                 goto restart;
                                451                 :                :             }
                                452                 :                : 
 2783                           453                 :             97 :             newelemorder = midpoint;
                                454                 :                :         }
                                455                 :                :     }
                                456                 :                : 
                                457                 :                :     /* Get a new OID for the new label */
 3520 bruce@momjian.us          458         [ +  + ]:            173 :     if (IsBinaryUpgrade)
                                459                 :                :     {
                                460         [ -  + ]:             50 :         if (!OidIsValid(binary_upgrade_next_pg_enum_oid))
 3520 bruce@momjian.us          461         [ #  # ]:UBC           0 :             ereport(ERROR,
                                462                 :                :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                463                 :                :                      errmsg("pg_enum OID value not set when in binary upgrade mode")));
                                464                 :                : 
                                465                 :                :         /*
                                466                 :                :          * Use binary-upgrade override for pg_enum.oid, if supplied. During
                                467                 :                :          * binary upgrade, all pg_enum.oid's are set this way so they are
                                468                 :                :          * guaranteed to be consistent.
                                469                 :                :          */
 4921 tgl@sss.pgh.pa.us         470         [ -  + ]:CBC          50 :         if (neighbor != NULL)
 4921 tgl@sss.pgh.pa.us         471         [ #  # ]:UBC           0 :             ereport(ERROR,
                                472                 :                :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                473                 :                :                      errmsg("ALTER TYPE ADD BEFORE/AFTER is incompatible with binary upgrade")));
                                474                 :                : 
 4921 tgl@sss.pgh.pa.us         475                 :CBC          50 :         newOid = binary_upgrade_next_pg_enum_oid;
                                476                 :             50 :         binary_upgrade_next_pg_enum_oid = InvalidOid;
                                477                 :                :     }
                                478                 :                :     else
                                479                 :                :     {
                                480                 :                :         /*
                                481                 :                :          * Normal case: we need to allocate a new Oid for the value.
                                482                 :                :          *
                                483                 :                :          * We want to give the new element an even-numbered Oid if it's safe,
                                484                 :                :          * which is to say it compares correctly to all pre-existing even
                                485                 :                :          * numbered Oids in the enum.  Otherwise, we must give it an odd Oid.
                                486                 :                :          */
                                487                 :                :         for (;;)
                                488                 :             82 :         {
                                489                 :                :             bool        sorts_ok;
                                490                 :                : 
                                491                 :                :             /* Get a new OID (different from all existing pg_enum tuples) */
 1972 andres@anarazel.de        492                 :            205 :             newOid = GetNewOidWithIndex(pg_enum, EnumOidIndexId,
                                493                 :                :                                         Anum_pg_enum_oid);
                                494                 :                : 
                                495                 :                :             /*
                                496                 :                :              * Detect whether it sorts correctly relative to existing
                                497                 :                :              * even-numbered labels of the enum.  We can ignore existing
                                498                 :                :              * labels with odd Oids, since a comparison involving one of those
                                499                 :                :              * will not take the fast path anyway.
                                500                 :                :              */
 4921 tgl@sss.pgh.pa.us         501                 :            205 :             sorts_ok = true;
                                502         [ +  + ]:           2824 :             for (i = 0; i < nelems; i++)
                                503                 :                :             {
                                504                 :           2788 :                 HeapTuple   exists_tup = existing[i];
                                505                 :           2788 :                 Form_pg_enum exists_en = (Form_pg_enum) GETSTRUCT(exists_tup);
 1972 andres@anarazel.de        506                 :           2788 :                 Oid         exists_oid = exists_en->oid;
                                507                 :                : 
 4921 tgl@sss.pgh.pa.us         508         [ +  + ]:           2788 :                 if (exists_oid & 1)
                                509                 :           2351 :                     continue;   /* ignore odd Oids */
                                510                 :                : 
                                511         [ +  + ]:            437 :                 if (exists_en->enumsortorder < newelemorder)
                                512                 :                :                 {
                                513                 :                :                     /* should sort before */
                                514         [ -  + ]:            268 :                     if (exists_oid >= newOid)
                                515                 :                :                     {
 4921 tgl@sss.pgh.pa.us         516                 :UBC           0 :                         sorts_ok = false;
                                517                 :              0 :                         break;
                                518                 :                :                     }
                                519                 :                :                 }
                                520                 :                :                 else
                                521                 :                :                 {
                                522                 :                :                     /* should sort after */
 4921 tgl@sss.pgh.pa.us         523         [ +  - ]:CBC         169 :                     if (exists_oid <= newOid)
                                524                 :                :                     {
                                525                 :            169 :                         sorts_ok = false;
                                526                 :            169 :                         break;
                                527                 :                :                     }
                                528                 :                :                 }
                                529                 :                :             }
                                530                 :                : 
                                531         [ +  + ]:            205 :             if (sorts_ok)
                                532                 :                :             {
                                533                 :                :                 /* If it's even and sorts OK, we're done. */
                                534         [ +  + ]:             36 :                 if ((newOid & 1) == 0)
                                535                 :             22 :                     break;
                                536                 :                : 
                                537                 :                :                 /*
                                538                 :                :                  * If it's odd, and sorts OK, loop back to get another OID and
                                539                 :                :                  * try again.  Probably, the next available even OID will sort
                                540                 :                :                  * correctly too, so it's worth trying.
                                541                 :                :                  */
                                542                 :                :             }
                                543                 :                :             else
                                544                 :                :             {
                                545                 :                :                 /*
                                546                 :                :                  * If it's odd, and does not sort correctly, we're done.
                                547                 :                :                  * (Probably, the next available even OID would sort
                                548                 :                :                  * incorrectly too, so no point in trying again.)
                                549                 :                :                  */
                                550         [ +  + ]:            169 :                 if (newOid & 1)
                                551                 :            101 :                     break;
                                552                 :                : 
                                553                 :                :                 /*
                                554                 :                :                  * If it's even, and does not sort correctly, loop back to get
                                555                 :                :                  * another OID and try again.  (We *must* reject this case.)
                                556                 :                :                  */
                                557                 :                :             }
                                558                 :                :         }
                                559                 :                :     }
                                560                 :                : 
                                561                 :                :     /* Done with info about existing members */
                                562                 :            173 :     pfree(existing);
                                563                 :            173 :     ReleaseCatCacheList(list);
                                564                 :                : 
                                565                 :                :     /* Create the new pg_enum entry */
                                566                 :            173 :     memset(nulls, false, sizeof(nulls));
 1972 andres@anarazel.de        567                 :            173 :     values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(newOid);
 4921 tgl@sss.pgh.pa.us         568                 :            173 :     values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
                                569                 :            173 :     values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(newelemorder);
                                570                 :            173 :     namestrcpy(&enumlabel, newVal);
                                571                 :            173 :     values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
                                572                 :            173 :     enum_tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls);
 2630 alvherre@alvh.no-ip.      573                 :            173 :     CatalogTupleInsert(pg_enum, enum_tup);
 4921 tgl@sss.pgh.pa.us         574                 :            173 :     heap_freetuple(enum_tup);
                                575                 :                : 
 1910 andres@anarazel.de        576                 :            173 :     table_close(pg_enum, RowExclusiveLock);
                                577                 :                : 
                                578                 :                :     /*
                                579                 :                :      * If the enum type itself is uncommitted, we need not enter the new enum
                                580                 :                :      * value into uncommitted_enum_values, because the type won't survive if
                                581                 :                :      * the value doesn't.  (This is basically the same reasoning as for values
                                582                 :                :      * made directly by CREATE TYPE AS ENUM.)  However, apply this rule only
                                583                 :                :      * when we are not inside a subtransaction; if we're more deeply nested
                                584                 :                :      * than the CREATE TYPE then the conclusion doesn't hold.  We could expend
                                585                 :                :      * more effort to track the subtransaction level of CREATE TYPE, but for
                                586                 :                :      * now we're only concerned about making the world safe for pg_dump in
                                587                 :                :      * binary upgrade mode, and that won't use subtransactions.
                                588                 :                :      */
   21 tgl@sss.pgh.pa.us         589   [ +  -  +  + ]:GNC         346 :     if (GetCurrentTransactionNestLevel() == 1 &&
                                590                 :            173 :         EnumTypeUncommitted(enumTypeOid))
                                591                 :             56 :         return;
                                592                 :                : 
                                593                 :                :     /* Set up the uncommitted values table if not already done in this tx */
                                594         [ +  - ]:            117 :     if (uncommitted_enum_values == NULL)
                                595                 :            117 :         init_uncommitted_enum_values();
                                596                 :                : 
                                597                 :                :     /* Add the new value to the table */
                                598                 :            117 :     (void) hash_search(uncommitted_enum_values, &newOid, HASH_ENTER, NULL);
                                599                 :                : }
                                600                 :                : 
                                601                 :                : 
                                602                 :                : /*
                                603                 :                :  * RenameEnumLabel
                                604                 :                :  *      Rename a label in an enum set.
                                605                 :                :  */
                                606                 :                : void
 2776 tgl@sss.pgh.pa.us         607                 :CBC          12 : RenameEnumLabel(Oid enumTypeOid,
                                608                 :                :                 const char *oldVal,
                                609                 :                :                 const char *newVal)
                                610                 :                : {
                                611                 :                :     Relation    pg_enum;
                                612                 :                :     HeapTuple   enum_tup;
                                613                 :                :     Form_pg_enum en;
                                614                 :                :     CatCList   *list;
                                615                 :                :     int         nelems;
                                616                 :                :     HeapTuple   old_tup;
                                617                 :                :     bool        found_new;
                                618                 :                :     int         i;
                                619                 :                : 
                                620                 :                :     /* check length of new label is ok */
                                621         [ -  + ]:             12 :     if (strlen(newVal) > (NAMEDATALEN - 1))
 2776 tgl@sss.pgh.pa.us         622         [ #  # ]:UBC           0 :         ereport(ERROR,
                                623                 :                :                 (errcode(ERRCODE_INVALID_NAME),
                                624                 :                :                  errmsg("invalid enum label \"%s\"", newVal),
                                625                 :                :                  errdetail("Labels must be %d bytes or less.",
                                626                 :                :                            NAMEDATALEN - 1)));
                                627                 :                : 
                                628                 :                :     /*
                                629                 :                :      * Acquire a lock on the enum type, which we won't release until commit.
                                630                 :                :      * This ensures that two backends aren't concurrently modifying the same
                                631                 :                :      * enum type.  Since we are not changing the type's sort order, this is
                                632                 :                :      * probably not really necessary, but there seems no reason not to take
                                633                 :                :      * the lock to be sure.
                                634                 :                :      */
 2776 tgl@sss.pgh.pa.us         635                 :CBC          12 :     LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock);
                                636                 :                : 
 1910 andres@anarazel.de        637                 :             12 :     pg_enum = table_open(EnumRelationId, RowExclusiveLock);
                                638                 :                : 
                                639                 :                :     /* Get the list of existing members of the enum */
 2776 tgl@sss.pgh.pa.us         640                 :             12 :     list = SearchSysCacheList1(ENUMTYPOIDNAME,
                                641                 :                :                                ObjectIdGetDatum(enumTypeOid));
                                642                 :             12 :     nelems = list->n_members;
                                643                 :                : 
                                644                 :                :     /*
                                645                 :                :      * Locate the element to rename and check if the new label is already in
                                646                 :                :      * use.  (The unique index on pg_enum would catch that anyway, but we
                                647                 :                :      * prefer a friendlier error message.)
                                648                 :                :      */
                                649                 :             12 :     old_tup = NULL;
                                650                 :             12 :     found_new = false;
                                651         [ +  + ]:             72 :     for (i = 0; i < nelems; i++)
                                652                 :                :     {
                                653                 :             60 :         enum_tup = &(list->members[i]->tuple);
                                654                 :             60 :         en = (Form_pg_enum) GETSTRUCT(enum_tup);
                                655         [ +  + ]:             60 :         if (strcmp(NameStr(en->enumlabel), oldVal) == 0)
                                656                 :              9 :             old_tup = enum_tup;
                                657         [ +  + ]:             60 :         if (strcmp(NameStr(en->enumlabel), newVal) == 0)
                                658                 :              6 :             found_new = true;
                                659                 :                :     }
                                660         [ +  + ]:             12 :     if (!old_tup)
                                661         [ +  - ]:              3 :         ereport(ERROR,
                                662                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                663                 :                :                  errmsg("\"%s\" is not an existing enum label",
                                664                 :                :                         oldVal)));
                                665         [ +  + ]:              9 :     if (found_new)
                                666         [ +  - ]:              3 :         ereport(ERROR,
                                667                 :                :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
                                668                 :                :                  errmsg("enum label \"%s\" already exists",
                                669                 :                :                         newVal)));
                                670                 :                : 
                                671                 :                :     /* OK, make a writable copy of old tuple */
                                672                 :              6 :     enum_tup = heap_copytuple(old_tup);
                                673                 :              6 :     en = (Form_pg_enum) GETSTRUCT(enum_tup);
                                674                 :                : 
                                675                 :              6 :     ReleaseCatCacheList(list);
                                676                 :                : 
                                677                 :                :     /* Update the pg_enum entry */
                                678                 :              6 :     namestrcpy(&en->enumlabel, newVal);
 2630 alvherre@alvh.no-ip.      679                 :              6 :     CatalogTupleUpdate(pg_enum, &enum_tup->t_self, enum_tup);
 2776 tgl@sss.pgh.pa.us         680                 :              6 :     heap_freetuple(enum_tup);
                                681                 :                : 
 1910 andres@anarazel.de        682                 :              6 :     table_close(pg_enum, RowExclusiveLock);
 2776 tgl@sss.pgh.pa.us         683                 :              6 : }
                                684                 :                : 
                                685                 :                : 
                                686                 :                : /*
                                687                 :                :  * Test if the given type OID is in the table of uncommitted enum types.
                                688                 :                :  */
                                689                 :                : static bool
   21 tgl@sss.pgh.pa.us         690                 :GNC         173 : EnumTypeUncommitted(Oid typ_id)
                                691                 :                : {
                                692                 :                :     bool        found;
                                693                 :                : 
                                694                 :                :     /* If we've made no uncommitted types table, it's not in the table */
                                695         [ +  + ]:            173 :     if (uncommitted_enum_types == NULL)
                                696                 :            117 :         return false;
                                697                 :                : 
                                698                 :                :     /* Else, is it in the table? */
                                699                 :             56 :     (void) hash_search(uncommitted_enum_types, &typ_id, HASH_FIND, &found);
                                700                 :             56 :     return found;
                                701                 :                : }
                                702                 :                : 
                                703                 :                : 
                                704                 :                : /*
                                705                 :                :  * Test if the given enum value is in the table of uncommitted enum values.
                                706                 :                :  */
                                707                 :                : bool
 1195 tmunro@postgresql.or      708                 :CBC          45 : EnumUncommitted(Oid enum_id)
                                709                 :                : {
                                710                 :                :     bool        found;
                                711                 :                : 
                                712                 :                :     /* If we've made no uncommitted values table, it's not in the table */
   21 tgl@sss.pgh.pa.us         713         [ +  + ]:GNC          45 :     if (uncommitted_enum_values == NULL)
 2014 tmunro@postgresql.or      714                 :CBC          33 :         return false;
                                715                 :                : 
                                716                 :                :     /* Else, is it in the table? */
   21 tgl@sss.pgh.pa.us         717                 :GNC          12 :     (void) hash_search(uncommitted_enum_values, &enum_id, HASH_FIND, &found);
 2014 tmunro@postgresql.or      718                 :CBC          12 :     return found;
                                719                 :                : }
                                720                 :                : 
                                721                 :                : 
                                722                 :                : /*
                                723                 :                :  * Clean up enum stuff after end of top-level transaction.
                                724                 :                :  */
                                725                 :                : void
                                726                 :         431446 : AtEOXact_Enum(void)
                                727                 :                : {
                                728                 :                :     /*
                                729                 :                :      * Reset the uncommitted tables, as all our tuples are now committed. The
                                730                 :                :      * memory will go away automatically when TopTransactionContext is freed;
                                731                 :                :      * it's sufficient to clear our pointers.
                                732                 :                :      */
   21 tgl@sss.pgh.pa.us         733                 :GNC      431446 :     uncommitted_enum_types = NULL;
                                734                 :         431446 :     uncommitted_enum_values = NULL;
 2014 tmunro@postgresql.or      735                 :CBC      431446 : }
                                736                 :                : 
                                737                 :                : 
                                738                 :                : /*
                                739                 :                :  * RenumberEnumType
                                740                 :                :  *      Renumber existing enum elements to have sort positions 1..n.
                                741                 :                :  *
                                742                 :                :  * We avoid doing this unless absolutely necessary; in most installations
                                743                 :                :  * it will never happen.  The reason is that updating existing pg_enum
                                744                 :                :  * entries creates hazards for other backends that are concurrently reading
                                745                 :                :  * pg_enum.  Although system catalog scans now use MVCC semantics, the
                                746                 :                :  * syscache machinery might read different pg_enum entries under different
                                747                 :                :  * snapshots, so some other backend might get confused about the proper
                                748                 :                :  * ordering if a concurrent renumbering occurs.
                                749                 :                :  *
                                750                 :                :  * We therefore make the following choices:
                                751                 :                :  *
                                752                 :                :  * 1. Any code that is interested in the enumsortorder values MUST read
                                753                 :                :  * all the relevant pg_enum entries with a single MVCC snapshot, or else
                                754                 :                :  * acquire lock on the enum type to prevent concurrent execution of
                                755                 :                :  * AddEnumLabel().
                                756                 :                :  *
                                757                 :                :  * 2. Code that is not examining enumsortorder can use a syscache
                                758                 :                :  * (for example, enum_in and enum_out do so).
                                759                 :                :  */
                                760                 :                : static void
 4921 tgl@sss.pgh.pa.us         761                 :              3 : RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems)
                                762                 :                : {
                                763                 :                :     int         i;
                                764                 :                : 
                                765                 :                :     /*
                                766                 :                :      * We should only need to increase existing elements' enumsortorders,
                                767                 :                :      * never decrease them.  Therefore, work from the end backwards, to avoid
                                768                 :                :      * unwanted uniqueness violations.
                                769                 :                :      */
                                770         [ +  + ]:             78 :     for (i = nelems - 1; i >= 0; i--)
                                771                 :                :     {
                                772                 :                :         HeapTuple   newtup;
                                773                 :                :         Form_pg_enum en;
                                774                 :                :         float4      newsortorder;
                                775                 :                : 
                                776                 :             75 :         newtup = heap_copytuple(existing[i]);
                                777                 :             75 :         en = (Form_pg_enum) GETSTRUCT(newtup);
                                778                 :                : 
                                779                 :             75 :         newsortorder = i + 1;
                                780         [ +  + ]:             75 :         if (en->enumsortorder != newsortorder)
                                781                 :                :         {
                                782                 :             72 :             en->enumsortorder = newsortorder;
                                783                 :                : 
 2630 alvherre@alvh.no-ip.      784                 :             72 :             CatalogTupleUpdate(pg_enum, &newtup->t_self, newtup);
                                785                 :                :         }
                                786                 :                : 
 4921 tgl@sss.pgh.pa.us         787                 :             75 :         heap_freetuple(newtup);
                                788                 :                :     }
                                789                 :                : 
                                790                 :                :     /* Make the updates visible */
                                791                 :              3 :     CommandCounterIncrement();
                                792                 :              3 : }
                                793                 :                : 
                                794                 :                : 
                                795                 :                : /* qsort comparison function for tuples by sort order */
                                796                 :                : static int
                                797                 :           8821 : sort_order_cmp(const void *p1, const void *p2)
                                798                 :                : {
 4753 bruce@momjian.us          799                 :           8821 :     HeapTuple   v1 = *((const HeapTuple *) p1);
                                800                 :           8821 :     HeapTuple   v2 = *((const HeapTuple *) p2);
                                801                 :           8821 :     Form_pg_enum en1 = (Form_pg_enum) GETSTRUCT(v1);
                                802                 :           8821 :     Form_pg_enum en2 = (Form_pg_enum) GETSTRUCT(v2);
                                803                 :                : 
 4921 tgl@sss.pgh.pa.us         804         [ +  + ]:           8821 :     if (en1->enumsortorder < en2->enumsortorder)
                                805                 :           3735 :         return -1;
                                806         [ +  - ]:           5086 :     else if (en1->enumsortorder > en2->enumsortorder)
                                807                 :           5086 :         return 1;
                                808                 :                :     else
 4921 tgl@sss.pgh.pa.us         809                 :UBC           0 :         return 0;
                                810                 :                : }
                                811                 :                : 
                                812                 :                : Size
 1195 tmunro@postgresql.or      813                 :CBC         828 : EstimateUncommittedEnumsSpace(void)
                                814                 :                : {
   21 tgl@sss.pgh.pa.us         815                 :GNC         828 :     size_t      entries = 0;
                                816                 :                : 
                                817         [ -  + ]:            828 :     if (uncommitted_enum_types)
   21 tgl@sss.pgh.pa.us         818                 :UNC           0 :         entries += hash_get_num_entries(uncommitted_enum_types);
   21 tgl@sss.pgh.pa.us         819         [ -  + ]:GNC         828 :     if (uncommitted_enum_values)
   21 tgl@sss.pgh.pa.us         820                 :UNC           0 :         entries += hash_get_num_entries(uncommitted_enum_values);
                                821                 :                : 
                                822                 :                :     /* Add two for the terminators. */
   21 tgl@sss.pgh.pa.us         823                 :GNC         828 :     return sizeof(Oid) * (entries + 2);
                                824                 :                : }
                                825                 :                : 
                                826                 :                : void
 1195 tmunro@postgresql.or      827                 :CBC         414 : SerializeUncommittedEnums(void *space, Size size)
                                828                 :                : {
 2014                           829                 :            414 :     Oid        *serialized = (Oid *) space;
                                830                 :                : 
                                831                 :                :     /*
                                832                 :                :      * Make sure the hash tables haven't changed in size since the caller
                                833                 :                :      * reserved the space.
                                834                 :                :      */
 1195                           835         [ -  + ]:            414 :     Assert(size == EstimateUncommittedEnumsSpace());
                                836                 :                : 
                                837                 :                :     /* Write out all the OIDs from the types hash table, if there is one. */
   21 tgl@sss.pgh.pa.us         838         [ -  + ]:GNC         414 :     if (uncommitted_enum_types)
                                839                 :                :     {
                                840                 :                :         HASH_SEQ_STATUS status;
                                841                 :                :         Oid        *value;
                                842                 :                : 
   21 tgl@sss.pgh.pa.us         843                 :UNC           0 :         hash_seq_init(&status, uncommitted_enum_types);
 2014 tmunro@postgresql.or      844         [ #  # ]:UBC           0 :         while ((value = (Oid *) hash_seq_search(&status)))
                                845                 :              0 :             *serialized++ = *value;
                                846                 :                :     }
                                847                 :                : 
                                848                 :                :     /* Write out the terminator. */
   21 tgl@sss.pgh.pa.us         849                 :GNC         414 :     *serialized++ = InvalidOid;
                                850                 :                : 
                                851                 :                :     /* Write out all the OIDs from the values hash table, if there is one. */
                                852         [ -  + ]:            414 :     if (uncommitted_enum_values)
                                853                 :                :     {
                                854                 :                :         HASH_SEQ_STATUS status;
                                855                 :                :         Oid        *value;
                                856                 :                : 
   21 tgl@sss.pgh.pa.us         857                 :UNC           0 :         hash_seq_init(&status, uncommitted_enum_values);
                                858         [ #  # ]:              0 :         while ((value = (Oid *) hash_seq_search(&status)))
                                859                 :              0 :             *serialized++ = *value;
                                860                 :                :     }
                                861                 :                : 
                                862                 :                :     /* Write out the terminator. */
   21 tgl@sss.pgh.pa.us         863                 :GNC         414 :     *serialized++ = InvalidOid;
                                864                 :                : 
                                865                 :                :     /*
                                866                 :                :      * Make sure the amount of space we actually used matches what was
                                867                 :                :      * estimated.
                                868                 :                :      */
                                869         [ -  + ]:            414 :     Assert((char *) serialized == ((char *) space) + size);
 2014 tmunro@postgresql.or      870                 :CBC         414 : }
                                871                 :                : 
                                872                 :                : void
 1195                           873                 :           1322 : RestoreUncommittedEnums(void *space)
                                874                 :                : {
 2014                           875                 :           1322 :     Oid        *serialized = (Oid *) space;
                                876                 :                : 
   21 tgl@sss.pgh.pa.us         877         [ -  + ]:GNC        1322 :     Assert(!uncommitted_enum_types);
                                878         [ -  + ]:           1322 :     Assert(!uncommitted_enum_values);
                                879                 :                : 
                                880                 :                :     /*
                                881                 :                :      * If either list is empty then don't even bother to create that hash
                                882                 :                :      * table.  This is the common case, since most transactions don't create
                                883                 :                :      * or alter enums.
                                884                 :                :      */
                                885         [ -  + ]:           1322 :     if (OidIsValid(*serialized))
                                886                 :                :     {
                                887                 :                :         /* Read all the types into a new hash table. */
   21 tgl@sss.pgh.pa.us         888                 :UNC           0 :         init_uncommitted_enum_types();
                                889                 :                :         do
                                890                 :                :         {
                                891                 :              0 :             (void) hash_search(uncommitted_enum_types, serialized++,
                                892                 :                :                                HASH_ENTER, NULL);
                                893         [ #  # ]:              0 :         } while (OidIsValid(*serialized));
                                894                 :                :     }
   21 tgl@sss.pgh.pa.us         895                 :GNC        1322 :     serialized++;
                                896         [ -  + ]:           1322 :     if (OidIsValid(*serialized))
                                897                 :                :     {
                                898                 :                :         /* Read all the values into a new hash table. */
   21 tgl@sss.pgh.pa.us         899                 :UNC           0 :         init_uncommitted_enum_values();
                                900                 :                :         do
                                901                 :                :         {
                                902                 :              0 :             (void) hash_search(uncommitted_enum_values, serialized++,
                                903                 :                :                                HASH_ENTER, NULL);
                                904         [ #  # ]:              0 :         } while (OidIsValid(*serialized));
                                905                 :                :     }
 2014 tmunro@postgresql.or      906                 :GIC        1322 : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622