PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_enum.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_enum.c
4 * routines to support manipulation of the pg_enum relation
5 *
6 * Copyright (c) 2006-2026, 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"
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 */
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 */
64
65static void init_uncommitted_enum_types(void);
66static void init_uncommitted_enum_values(void);
67static bool EnumTypeUncommitted(Oid typ_id);
68static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems);
69static 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 */
83void
85{
87 Oid *oids;
88 int elemno,
89 num_elems;
90 ListCell *lc;
91 int slotCount = 0;
92 int nslots;
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 */
104 {
109 }
110
111 num_elems = list_length(vals);
112
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 */
123 oids = palloc_array(Oid, num_elems);
124
125 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 {
138 } while (new_oid & 1);
139 oids[elemno] = new_oid;
140 }
141
142 /* sort them, just in case OID counter wrapped from high to low */
143 qsort(oids, num_elems, sizeof(Oid), oid_cmp);
144
145 /* and make the entries */
147
148 /* allocate the slots to use and initialize them */
149 nslots = Min(num_elems,
151 slot = palloc_array(TupleTableSlot *, nslots);
152 for (int i = 0; i < nslots; i++)
155
156 elemno = 0;
157 foreach(lc, vals)
158 {
159 char *lab = strVal(lfirst(lc));
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 */
167 if (strlen(lab) > (NAMEDATALEN - 1))
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 */
178 foreach(lc2, vals)
179 {
180 /* Only need to compare lc to earlier entries */
181 if (lc2 == lc)
182 break;
183
184 if (strcmp(lab, strVal(lfirst(lc2))) == 0)
187 errmsg("enum label \"%s\" used more than once",
188 lab)));
189 }
190
191 /* OK, construct a tuple for this label */
193
194 memset(slot[slotCount]->tts_isnull, false,
195 slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
196
200
203
205 slotCount++;
206
207 /* if slots are full, insert a batch of tuples */
208 if (slotCount == nslots)
209 {
211 indstate);
212 slotCount = 0;
213 }
214
215 elemno++;
216 }
217
218 /* Insert any tuples left in the buffer */
219 if (slotCount > 0)
221 indstate);
222
223 /* clean up */
224 pfree(oids);
225 for (int i = 0; i < nslots; i++)
229}
230
231
232/*
233 * EnumValuesDelete
234 * Remove all the pg_enum entries for the specified enum type.
235 */
236void
263
264/*
265 * Initialize the uncommitted enum types table for this transaction.
266 */
267static void
269{
271
272 hash_ctl.keysize = sizeof(Oid);
273 hash_ctl.entrysize = sizeof(Oid);
275 uncommitted_enum_types = hash_create("Uncommitted enum types",
276 32,
277 &hash_ctl,
279}
280
281/*
282 * Initialize the uncommitted enum values table for this transaction.
283 */
284static void
286{
288
289 hash_ctl.keysize = sizeof(Oid);
290 hash_ctl.entrysize = sizeof(Oid);
292 uncommitted_enum_values = hash_create("Uncommitted enum values",
293 32,
294 &hash_ctl,
296}
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 */
304void
306 const char *newVal,
307 const char *neighbor,
308 bool newValIsAfter,
309 bool skipIfExists)
310{
312 Oid newOid;
314 bool nulls[Natts_pg_enum];
319 CatCList *list;
320 int nelems;
321 int i;
322
323 /* check length of new label is ok */
324 if (strlen(newVal) > (NAMEDATALEN - 1))
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 */
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 */
348 CStringGetDatum(newVal));
350 {
352 if (skipIfExists)
353 {
356 errmsg("enum label \"%s\" already exists, skipping",
357 newVal)));
358 return;
359 }
360 else
363 errmsg("enum label \"%s\" already exists",
364 newVal)));
365 }
366
368
369 /* If we have to renumber the existing members, we restart from here */
370restart:
371
372 /* Get the list of existing members of the enum */
375 nelems = list->n_members;
376
377 /* Sort the existing members by enumsortorder */
379 for (i = 0; i < nelems; i++)
380 existing[i] = &(list->members[i]->tuple);
381
382 qsort(existing, nelems, sizeof(HeapTuple), sort_order_cmp);
383
384 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 if (nelems > 0)
391 {
393
394 newelemorder = en->enumsortorder + 1;
395 }
396 else
397 newelemorder = 1;
398 }
399 else
400 {
401 /* BEFORE or AFTER was specified */
402 int nbr_index;
403 int other_nbr_index;
406
407 /* Locate the neighbor element */
408 for (nbr_index = 0; nbr_index < nelems; nbr_index++)
409 {
411
412 if (strcmp(NameStr(en->enumlabel), neighbor) == 0)
413 break;
414 }
415 if (nbr_index >= nelems)
418 errmsg("\"%s\" is not an existing enum label",
419 neighbor)));
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 if (newValIsAfter)
434 else
436
437 if (other_nbr_index < 0)
438 newelemorder = nbr_en->enumsortorder - 1;
439 else if (other_nbr_index >= nelems)
440 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
453 midpoint = (nbr_en->enumsortorder +
454 other_nbr_en->enumsortorder) / 2;
455
456 if (midpoint == nbr_en->enumsortorder ||
457 midpoint == other_nbr_en->enumsortorder)
458 {
460 /* Clean up and start over */
463 goto restart;
464 }
465
467 }
468 }
469
470 /* Get a new OID for the new label */
471 if (IsBinaryUpgrade)
472 {
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 */
483 if (neighbor != NULL)
486 errmsg("ALTER TYPE ADD BEFORE/AFTER is incompatible with binary upgrade")));
487
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 {
502 bool sorts_ok;
503
504 /* Get a new OID (different from all existing pg_enum tuples) */
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 */
514 sorts_ok = true;
515 for (i = 0; i < nelems; i++)
516 {
519 Oid exists_oid = exists_en->oid;
520
521 if (exists_oid & 1)
522 continue; /* ignore odd Oids */
523
524 if (exists_en->enumsortorder < newelemorder)
525 {
526 /* should sort before */
527 if (exists_oid >= newOid)
528 {
529 sorts_ok = false;
530 break;
531 }
532 }
533 else
534 {
535 /* should sort after */
536 if (exists_oid <= newOid)
537 {
538 sorts_ok = false;
539 break;
540 }
541 }
542 }
543
544 if (sorts_ok)
545 {
546 /* If it's even and sorts OK, we're done. */
547 if ((newOid & 1) == 0)
548 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 if (newOid & 1)
564 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 */
577
578 /* Create the new pg_enum entry */
579 memset(nulls, false, sizeof(nulls));
583 namestrcpy(&enumlabel, newVal);
588
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 */
604 return;
605
606 /* Set up the uncommitted values table if not already done in this tx */
609
610 /* Add the new value to the table */
612}
613
614
615/*
616 * RenameEnumLabel
617 * Rename a label in an enum set.
618 */
619void
621 const char *oldVal,
622 const char *newVal)
623{
627 CatCList *list;
628 int nelems;
630 bool found_new;
631 int i;
632
633 /* check length of new label is ok */
634 if (strlen(newVal) > (NAMEDATALEN - 1))
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 */
649
651
652 /* Get the list of existing members of the enum */
655 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 old_tup = NULL;
663 found_new = false;
664 for (i = 0; i < nelems; i++)
665 {
666 enum_tup = &(list->members[i]->tuple);
668 if (strcmp(NameStr(en->enumlabel), oldVal) == 0)
670 if (strcmp(NameStr(en->enumlabel), newVal) == 0)
671 found_new = true;
672 }
673 if (!old_tup)
676 errmsg("\"%s\" is not an existing enum label",
677 oldVal)));
678 if (found_new)
681 errmsg("enum label \"%s\" already exists",
682 newVal)));
683
684 /* OK, make a writable copy of old tuple */
687
689
690 /* Update the pg_enum entry */
691 namestrcpy(&en->enumlabel, newVal);
694
696}
697
698
699/*
700 * Test if the given type OID is in the table of uncommitted enum types.
701 */
702static bool
704{
705 bool found;
706
707 /* If we've made no uncommitted types table, it's not in the table */
709 return false;
710
711 /* Else, is it in the table? */
713 return found;
714}
715
716
717/*
718 * Test if the given enum value is in the table of uncommitted enum values.
719 */
720bool
722{
723 bool found;
724
725 /* If we've made no uncommitted values table, it's not in the table */
727 return false;
728
729 /* Else, is it in the table? */
731 return found;
732}
733
734
735/*
736 * Clean up enum stuff after end of top-level transaction.
737 */
738void
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 */
748}
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 */
773static void
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 for (i = nelems - 1; i >= 0; i--)
784 {
788
791
792 newsortorder = i + 1;
793 if (en->enumsortorder != newsortorder)
794 {
795 en->enumsortorder = newsortorder;
796
798 }
799
801 }
802
803 /* Make the updates visible */
805}
806
807
808/* qsort comparison function for tuples by sort order */
809static int
810sort_order_cmp(const void *p1, const void *p2)
811{
812 HeapTuple v1 = *((const HeapTuple *) p1);
813 HeapTuple v2 = *((const HeapTuple *) p2);
816
817 if (en1->enumsortorder < en2->enumsortorder)
818 return -1;
819 else if (en1->enumsortorder > en2->enumsortorder)
820 return 1;
821 else
822 return 0;
823}
824
825Size
827{
828 size_t entries = 0;
829
834
835 /* Add two for the terminators. */
836 return sizeof(Oid) * (entries + 2);
837}
838
839void
841{
842 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 */
849
850 /* Write out all the OIDs from the types hash table, if there is one. */
852 {
853 HASH_SEQ_STATUS status;
854 Oid *value;
855
857 while ((value = (Oid *) hash_seq_search(&status)))
858 *serialized++ = *value;
859 }
860
861 /* Write out the terminator. */
863
864 /* Write out all the OIDs from the values hash table, if there is one. */
866 {
867 HASH_SEQ_STATUS status;
868 Oid *value;
869
871 while ((value = (Oid *) hash_seq_search(&status)))
872 *serialized++ = *value;
873 }
874
875 /* Write out the terminator. */
877
878 /*
879 * Make sure the amount of space we actually used matches what was
880 * estimated.
881 */
882 Assert((char *) serialized == ((char *) space) + size);
883}
884
885void
887{
888 Oid *serialized = (Oid *) space;
889
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 */
899 {
900 /* Read all the types into a new hash table. */
902 do
903 {
906 } while (OidIsValid(*serialized));
907 }
908 serialized++;
910 {
911 /* Read all the values into a new hash table. */
913 do
914 {
917 } while (OidIsValid(*serialized));
918 }
919}
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define NameStr(name)
Definition c.h:765
#define Min(x, y)
Definition c.h:997
#define Assert(condition)
Definition c.h:873
float float4
Definition c.h:643
#define OidIsValid(objectId)
Definition c.h:788
size_t Size
Definition c.h:619
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:448
void ReleaseCatCacheList(CatCList *list)
Definition catcache.c:2114
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1415
int64 hash_get_num_entries(HTAB *hashp)
Definition dynahash.c:1336
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1380
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define NOTICE
Definition elog.h:35
#define ereport(elevel,...)
Definition elog.h:150
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
const TupleTableSlotOps TTSOpsHeapTuple
Definition execTuples.c:85
#define palloc_array(type, count)
Definition fe_memutils.h:76
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
bool IsBinaryUpgrade
Definition globals.c:121
HeapTuple heap_copytuple(HeapTuple tuple)
Definition heaptuple.c:778
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1435
@ HASH_FIND
Definition hsearch.h:113
@ HASH_ENTER
Definition hsearch.h:114
#define HASH_CONTEXT
Definition hsearch.h:102
#define HASH_ELEM
Definition hsearch.h:95
#define HASH_BLOBS
Definition hsearch.h:97
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition indexing.c:273
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition indexing.c:61
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition indexing.c:43
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
#define MAX_CATALOG_MULTI_INSERT_BYTES
Definition indexing.h:33
static struct @172 value
int i
Definition isn.c:77
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition lmgr.c:1008
#define ExclusiveLock
Definition lockdefs.h:42
#define RowExclusiveLock
Definition lockdefs.h:38
MemoryContext TopTransactionContext
Definition mcxt.c:171
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc0(Size size)
Definition mcxt.c:1417
void namestrcpy(Name name, const char *str)
Definition name.c:233
int oid_cmp(const void *p1, const void *p2)
Definition oid.c:258
#define NAMEDATALEN
void RestoreUncommittedEnums(void *space)
Definition pg_enum.c:886
static HTAB * uncommitted_enum_values
Definition pg_enum.c:63
void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal)
Definition pg_enum.c:620
Size EstimateUncommittedEnumsSpace(void)
Definition pg_enum.c:826
static void init_uncommitted_enum_types(void)
Definition pg_enum.c:268
bool EnumUncommitted(Oid enum_id)
Definition pg_enum.c:721
static void init_uncommitted_enum_values(void)
Definition pg_enum.c:285
void EnumValuesDelete(Oid enumTypeOid)
Definition pg_enum.c:237
void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists)
Definition pg_enum.c:305
void SerializeUncommittedEnums(void *space, Size size)
Definition pg_enum.c:840
Oid binary_upgrade_next_pg_enum_oid
Definition pg_enum.c:36
static HTAB * uncommitted_enum_types
Definition pg_enum.c:62
static int sort_order_cmp(const void *p1, const void *p2)
Definition pg_enum.c:810
void AtEOXact_Enum(void)
Definition pg_enum.c:739
static bool EnumTypeUncommitted(Oid typ_id)
Definition pg_enum.c:703
static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems)
Definition pg_enum.c:774
void EnumValuesCreate(Oid enumTypeOid, List *vals)
Definition pg_enum.c:84
FormData_pg_enum * Form_pg_enum
Definition pg_enum.h:44
FormData_pg_enum
Definition pg_enum.h:37
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#define qsort(a, b, c, d)
Definition port.h:495
static Datum Float4GetDatum(float4 X)
Definition postgres.h:478
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:403
uint64_t Datum
Definition postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition postgres.h:380
#define InvalidOid
unsigned int Oid
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:540
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define BTEqualStrategyNumber
Definition stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30
Size keysize
Definition hsearch.h:75
Definition pg_list.h:54
Datum * tts_values
Definition tuptable.h:124
Definition c.h:760
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition syscache.c:230
#define SearchSysCacheList1(cacheId, key1)
Definition syscache.h:127
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:457
#define strVal(v)
Definition value.h:82
int GetCurrentTransactionNestLevel(void)
Definition xact.c:930
void CommandCounterIncrement(void)
Definition xact.c:1101