LCOV - differential code coverage report
Current view: top level - src/backend/catalog - pg_enum.c (source / functions) Coverage Total Hit UNC UBC GNC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 92.1 % 266 245 21 5 240
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 14 14 1 13
Baseline: lcov-20250906-005545-baseline Branches: 72.0 % 168 121 4 43 8 113
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 100.0 % 5 5 5
(360..) days: 92.0 % 261 240 21 240
Function coverage date bins:
(360..) days: 100.0 % 14 14 1 13
Branch coverage date bins:
(1,7] days: 66.7 % 12 8 4 8
(360..) days: 72.4 % 156 113 43 113

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

Generated by: LCOV version 2.4-beta