PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pg_enum.h File Reference
#include "catalog/genbki.h"
#include "catalog/pg_enum_d.h"
#include "nodes/pg_list.h"
Include dependency graph for pg_enum.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef FormData_pg_enumForm_pg_enum
 

Functions

 CATALOG (pg_enum, 3501, EnumRelationId)
 
 DECLARE_UNIQUE_INDEX_PKEY (pg_enum_oid_index, 3502, EnumOidIndexId, pg_enum, btree(oid oid_ops))
 
 DECLARE_UNIQUE_INDEX (pg_enum_typid_label_index, 3503, EnumTypIdLabelIndexId, pg_enum, btree(enumtypid oid_ops, enumlabel name_ops))
 
 DECLARE_UNIQUE_INDEX (pg_enum_typid_sortorder_index, 3534, EnumTypIdSortOrderIndexId, pg_enum, btree(enumtypid oid_ops, enumsortorder float4_ops))
 
 MAKE_SYSCACHE (ENUMOID, pg_enum_oid_index, 8)
 
 MAKE_SYSCACHE (ENUMTYPOIDNAME, pg_enum_typid_label_index, 8)
 
void EnumValuesCreate (Oid enumTypeOid, List *vals)
 
void EnumValuesDelete (Oid enumTypeOid)
 
void AddEnumLabel (Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists)
 
void RenameEnumLabel (Oid enumTypeOid, const char *oldVal, const char *newVal)
 
bool EnumUncommitted (Oid enum_id)
 
Size EstimateUncommittedEnumsSpace (void)
 
void SerializeUncommittedEnums (void *space, Size size)
 
void RestoreUncommittedEnums (void *space)
 
void AtEOXact_Enum (void)
 

Variables

 FormData_pg_enum
 

Typedef Documentation

◆ Form_pg_enum

Definition at line 44 of file pg_enum.h.

Function Documentation

◆ AddEnumLabel()

void AddEnumLabel ( Oid  enumTypeOid,
const char *  newVal,
const char *  neighbor,
bool  newValIsAfter,
bool  skipIfExists 
)

Definition at line 292 of file pg_enum.c.

297{
298 Relation pg_enum;
299 Oid newOid;
300 Datum values[Natts_pg_enum];
301 bool nulls[Natts_pg_enum];
302 NameData enumlabel;
303 HeapTuple enum_tup;
304 float4 newelemorder;
305 HeapTuple *existing;
306 CatCList *list;
307 int nelems;
308 int i;
309
310 /* check length of new label is ok */
311 if (strlen(newVal) > (NAMEDATALEN - 1))
313 (errcode(ERRCODE_INVALID_NAME),
314 errmsg("invalid enum label \"%s\"", newVal),
315 errdetail("Labels must be %d bytes or less.",
316 NAMEDATALEN - 1)));
317
318 /*
319 * Acquire a lock on the enum type, which we won't release until commit.
320 * This ensures that two backends aren't concurrently modifying the same
321 * enum type. Without that, we couldn't be sure to get a consistent view
322 * of the enum members via the syscache. Note that this does not block
323 * other backends from inspecting the type; see comments for
324 * RenumberEnumType.
325 */
326 LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock);
327
328 /*
329 * Check if label is already in use. The unique index on pg_enum would
330 * catch this anyway, but we prefer a friendlier error message, and
331 * besides we need a check to support IF NOT EXISTS.
332 */
333 enum_tup = SearchSysCache2(ENUMTYPOIDNAME,
334 ObjectIdGetDatum(enumTypeOid),
335 CStringGetDatum(newVal));
336 if (HeapTupleIsValid(enum_tup))
337 {
338 ReleaseSysCache(enum_tup);
339 if (skipIfExists)
340 {
343 errmsg("enum label \"%s\" already exists, skipping",
344 newVal)));
345 return;
346 }
347 else
350 errmsg("enum label \"%s\" already exists",
351 newVal)));
352 }
353
354 pg_enum = table_open(EnumRelationId, RowExclusiveLock);
355
356 /* If we have to renumber the existing members, we restart from here */
357restart:
358
359 /* Get the list of existing members of the enum */
360 list = SearchSysCacheList1(ENUMTYPOIDNAME,
361 ObjectIdGetDatum(enumTypeOid));
362 nelems = list->n_members;
363
364 /* Sort the existing members by enumsortorder */
365 existing = (HeapTuple *) palloc(nelems * sizeof(HeapTuple));
366 for (i = 0; i < nelems; i++)
367 existing[i] = &(list->members[i]->tuple);
368
369 qsort(existing, nelems, sizeof(HeapTuple), sort_order_cmp);
370
371 if (neighbor == NULL)
372 {
373 /*
374 * Put the new label at the end of the list. No change to existing
375 * tuples is required.
376 */
377 if (nelems > 0)
378 {
379 Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nelems - 1]);
380
381 newelemorder = en->enumsortorder + 1;
382 }
383 else
384 newelemorder = 1;
385 }
386 else
387 {
388 /* BEFORE or AFTER was specified */
389 int nbr_index;
390 int other_nbr_index;
391 Form_pg_enum nbr_en;
392 Form_pg_enum other_nbr_en;
393
394 /* Locate the neighbor element */
395 for (nbr_index = 0; nbr_index < nelems; nbr_index++)
396 {
397 Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]);
398
399 if (strcmp(NameStr(en->enumlabel), neighbor) == 0)
400 break;
401 }
402 if (nbr_index >= nelems)
404 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
405 errmsg("\"%s\" is not an existing enum label",
406 neighbor)));
407 nbr_en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]);
408
409 /*
410 * Attempt to assign an appropriate enumsortorder value: one less than
411 * the smallest member, one more than the largest member, or halfway
412 * between two existing members.
413 *
414 * In the "halfway" case, because of the finite precision of float4,
415 * we might compute a value that's actually equal to one or the other
416 * of its neighbors. In that case we renumber the existing members
417 * and try again.
418 */
419 if (newValIsAfter)
420 other_nbr_index = nbr_index + 1;
421 else
422 other_nbr_index = nbr_index - 1;
423
424 if (other_nbr_index < 0)
425 newelemorder = nbr_en->enumsortorder - 1;
426 else if (other_nbr_index >= nelems)
427 newelemorder = nbr_en->enumsortorder + 1;
428 else
429 {
430 /*
431 * The midpoint value computed here has to be rounded to float4
432 * precision, else our equality comparisons against the adjacent
433 * values are meaningless. The most portable way of forcing that
434 * to happen with non-C-standard-compliant compilers is to store
435 * it into a volatile variable.
436 */
437 volatile float4 midpoint;
438
439 other_nbr_en = (Form_pg_enum) GETSTRUCT(existing[other_nbr_index]);
440 midpoint = (nbr_en->enumsortorder +
441 other_nbr_en->enumsortorder) / 2;
442
443 if (midpoint == nbr_en->enumsortorder ||
444 midpoint == other_nbr_en->enumsortorder)
445 {
446 RenumberEnumType(pg_enum, existing, nelems);
447 /* Clean up and start over */
448 pfree(existing);
450 goto restart;
451 }
452
453 newelemorder = midpoint;
454 }
455 }
456
457 /* Get a new OID for the new label */
458 if (IsBinaryUpgrade)
459 {
462 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
463 errmsg("pg_enum OID value not set when in binary upgrade mode")));
464
465 /*
466 * Use binary-upgrade override for pg_enum.oid, if supplied. During
467 * binary upgrade, all pg_enum.oid's are set this way so they are
468 * guaranteed to be consistent.
469 */
470 if (neighbor != NULL)
472 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
473 errmsg("ALTER TYPE ADD BEFORE/AFTER is incompatible with binary upgrade")));
474
477 }
478 else
479 {
480 /*
481 * Normal case: we need to allocate a new Oid for the value.
482 *
483 * We want to give the new element an even-numbered Oid if it's safe,
484 * which is to say it compares correctly to all pre-existing even
485 * numbered Oids in the enum. Otherwise, we must give it an odd Oid.
486 */
487 for (;;)
488 {
489 bool sorts_ok;
490
491 /* Get a new OID (different from all existing pg_enum tuples) */
492 newOid = GetNewOidWithIndex(pg_enum, EnumOidIndexId,
493 Anum_pg_enum_oid);
494
495 /*
496 * Detect whether it sorts correctly relative to existing
497 * even-numbered labels of the enum. We can ignore existing
498 * labels with odd Oids, since a comparison involving one of those
499 * will not take the fast path anyway.
500 */
501 sorts_ok = true;
502 for (i = 0; i < nelems; i++)
503 {
504 HeapTuple exists_tup = existing[i];
505 Form_pg_enum exists_en = (Form_pg_enum) GETSTRUCT(exists_tup);
506 Oid exists_oid = exists_en->oid;
507
508 if (exists_oid & 1)
509 continue; /* ignore odd Oids */
510
511 if (exists_en->enumsortorder < newelemorder)
512 {
513 /* should sort before */
514 if (exists_oid >= newOid)
515 {
516 sorts_ok = false;
517 break;
518 }
519 }
520 else
521 {
522 /* should sort after */
523 if (exists_oid <= newOid)
524 {
525 sorts_ok = false;
526 break;
527 }
528 }
529 }
530
531 if (sorts_ok)
532 {
533 /* If it's even and sorts OK, we're done. */
534 if ((newOid & 1) == 0)
535 break;
536
537 /*
538 * If it's odd, and sorts OK, loop back to get another OID and
539 * try again. Probably, the next available even OID will sort
540 * correctly too, so it's worth trying.
541 */
542 }
543 else
544 {
545 /*
546 * If it's odd, and does not sort correctly, we're done.
547 * (Probably, the next available even OID would sort
548 * incorrectly too, so no point in trying again.)
549 */
550 if (newOid & 1)
551 break;
552
553 /*
554 * If it's even, and does not sort correctly, loop back to get
555 * another OID and try again. (We *must* reject this case.)
556 */
557 }
558 }
559 }
560
561 /* Done with info about existing members */
562 pfree(existing);
564
565 /* Create the new pg_enum entry */
566 memset(nulls, false, sizeof(nulls));
567 values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(newOid);
568 values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
569 values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(newelemorder);
570 namestrcpy(&enumlabel, newVal);
571 values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
572 enum_tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls);
573 CatalogTupleInsert(pg_enum, enum_tup);
574 heap_freetuple(enum_tup);
575
577
578 /*
579 * If the enum type itself is uncommitted, we need not enter the new enum
580 * value into uncommitted_enum_values, because the type won't survive if
581 * the value doesn't. (This is basically the same reasoning as for values
582 * made directly by CREATE TYPE AS ENUM.) However, apply this rule only
583 * when we are not inside a subtransaction; if we're more deeply nested
584 * than the CREATE TYPE then the conclusion doesn't hold. We could expend
585 * more effort to track the subtransaction level of CREATE TYPE, but for
586 * now we're only concerned about making the world safe for pg_dump in
587 * binary upgrade mode, and that won't use subtransactions.
588 */
590 EnumTypeUncommitted(enumTypeOid))
591 return;
592
593 /* Set up the uncommitted values table if not already done in this tx */
594 if (uncommitted_enum_values == NULL)
596
597 /* Add the new value to the table */
598 (void) hash_search(uncommitted_enum_values, &newOid, HASH_ENTER, NULL);
599}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define NameStr(name)
Definition: c.h:700
float float4
Definition: c.h:583
#define OidIsValid(objectId)
Definition: c.h:729
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1985
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
bool IsBinaryUpgrade
Definition: globals.c:120
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_ENTER
Definition: hsearch.h:114
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int i
Definition: isn.c:72
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:993
#define ExclusiveLock
Definition: lockdefs.h:42
#define RowExclusiveLock
Definition: lockdefs.h:38
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define NAMEDATALEN
static HTAB * uncommitted_enum_values
Definition: pg_enum.c:63
static void init_uncommitted_enum_values(void)
Definition: pg_enum.c:272
Oid binary_upgrade_next_pg_enum_oid
Definition: pg_enum.c:36
static int sort_order_cmp(const void *p1, const void *p2)
Definition: pg_enum.c:797
static bool EnumTypeUncommitted(Oid typ_id)
Definition: pg_enum.c:690
static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems)
Definition: pg_enum.c:761
FormData_pg_enum * Form_pg_enum
Definition: pg_enum.h:44
#define qsort(a, b, c, d)
Definition: port.h:447
static Datum Float4GetDatum(float4 X)
Definition: postgres.h:475
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:531
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
Definition: c.h:695
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232
#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
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:928

References binary_upgrade_next_pg_enum_oid, CatalogTupleInsert(), CStringGetDatum(), EnumTypeUncommitted(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, ExclusiveLock, Float4GetDatum(), GetCurrentTransactionNestLevel(), GetNewOidWithIndex(), GETSTRUCT, HASH_ENTER, hash_search(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, init_uncommitted_enum_values(), InvalidOid, IsBinaryUpgrade, sort-test::list, LockDatabaseObject(), NAMEDATALEN, NameGetDatum(), NameStr, namestrcpy(), NOTICE, ObjectIdGetDatum(), OidIsValid, palloc(), pfree(), qsort, RelationGetDescr, ReleaseCatCacheList(), ReleaseSysCache(), RenumberEnumType(), RowExclusiveLock, SearchSysCache2(), SearchSysCacheList1, sort_order_cmp(), table_close(), table_open(), uncommitted_enum_values, and values.

Referenced by AlterEnum().

◆ AtEOXact_Enum()

void AtEOXact_Enum ( void  )

Definition at line 726 of file pg_enum.c.

727{
728 /*
729 * Reset the uncommitted tables, as all our tuples are now committed. The
730 * memory will go away automatically when TopTransactionContext is freed;
731 * it's sufficient to clear our pointers.
732 */
735}
static HTAB * uncommitted_enum_types
Definition: pg_enum.c:62

References uncommitted_enum_types, and uncommitted_enum_values.

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

◆ CATALOG()

CATALOG ( pg_enum  ,
3501  ,
EnumRelationId   
)

Definition at line 31 of file pg_enum.h.

32{
33 Oid oid; /* oid */
34 Oid enumtypid BKI_LOOKUP(pg_type); /* OID of owning enum type */
35 float4 enumsortorder; /* sort position of this enum value */
36 NameData enumlabel; /* text representation of enum value */
#define BKI_LOOKUP(catalog)
Definition: genbki.h:46
FormData_pg_enum
Definition: pg_enum.h:37

References BKI_LOOKUP.

◆ DECLARE_UNIQUE_INDEX() [1/2]

DECLARE_UNIQUE_INDEX ( pg_enum_typid_label_index  ,
3503  ,
EnumTypIdLabelIndexId  ,
pg_enum  ,
btree(enumtypid oid_ops, enumlabel name_ops)   
)

◆ DECLARE_UNIQUE_INDEX() [2/2]

DECLARE_UNIQUE_INDEX ( pg_enum_typid_sortorder_index  ,
3534  ,
EnumTypIdSortOrderIndexId  ,
pg_enum  ,
btree(enumtypid oid_ops, enumsortorder float4_ops)   
)

◆ DECLARE_UNIQUE_INDEX_PKEY()

DECLARE_UNIQUE_INDEX_PKEY ( pg_enum_oid_index  ,
3502  ,
EnumOidIndexId  ,
pg_enum  ,
btree(oid oid_ops)   
)

◆ EnumUncommitted()

bool EnumUncommitted ( Oid  enum_id)

Definition at line 708 of file pg_enum.c.

709{
710 bool found;
711
712 /* If we've made no uncommitted values table, it's not in the table */
713 if (uncommitted_enum_values == NULL)
714 return false;
715
716 /* Else, is it in the table? */
717 (void) hash_search(uncommitted_enum_values, &enum_id, HASH_FIND, &found);
718 return found;
719}
@ HASH_FIND
Definition: hsearch.h:113

References HASH_FIND, hash_search(), and uncommitted_enum_values.

Referenced by check_safe_enum_use().

◆ EnumValuesCreate()

void EnumValuesCreate ( Oid  enumTypeOid,
List vals 
)

Definition at line 84 of file pg_enum.c.

85{
86 Relation pg_enum;
87 Oid *oids;
88 int elemno,
89 num_elems;
90 ListCell *lc;
91 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 */
104 {
105 if (uncommitted_enum_types == NULL)
107 (void) hash_search(uncommitted_enum_types, &enumTypeOid,
108 HASH_ENTER, NULL);
109 }
110
111 num_elems = list_length(vals);
112
113 /*
114 * We do not bother to check the list of values for duplicates --- if you
115 * have any, you'll get a less-than-friendly unique-index violation. It is
116 * probably not worth trying harder.
117 */
118
119 pg_enum = table_open(EnumRelationId, RowExclusiveLock);
120
121 /*
122 * Allocate OIDs for the enum's members.
123 *
124 * While this method does not absolutely guarantee that we generate no
125 * duplicate OIDs (since we haven't entered each oid into the table before
126 * allocating the next), trouble could only occur if the OID counter wraps
127 * all the way around before we finish. Which seems unlikely.
128 */
129 oids = (Oid *) palloc(num_elems * sizeof(Oid));
130
131 for (elemno = 0; elemno < num_elems; elemno++)
132 {
133 /*
134 * We assign even-numbered OIDs to all the new enum labels. This
135 * tells the comparison functions the OIDs are in the correct sort
136 * order and can be compared directly.
137 */
138 Oid new_oid;
139
140 do
141 {
142 new_oid = GetNewOidWithIndex(pg_enum, EnumOidIndexId,
143 Anum_pg_enum_oid);
144 } while (new_oid & 1);
145 oids[elemno] = new_oid;
146 }
147
148 /* sort them, just in case OID counter wrapped from high to low */
149 qsort(oids, num_elems, sizeof(Oid), oid_cmp);
150
151 /* and make the entries */
152 indstate = CatalogOpenIndexes(pg_enum);
153
154 /* allocate the slots to use and initialize them */
155 nslots = Min(num_elems,
157 slot = palloc(sizeof(TupleTableSlot *) * nslots);
158 for (int i = 0; i < nslots; i++)
161
162 elemno = 0;
163 foreach(lc, vals)
164 {
165 char *lab = strVal(lfirst(lc));
166 Name enumlabel = palloc0(NAMEDATALEN);
167
168 /*
169 * labels are stored in a name field, for easier syscache lookup, so
170 * check the length to make sure it's within range.
171 */
172 if (strlen(lab) > (NAMEDATALEN - 1))
174 (errcode(ERRCODE_INVALID_NAME),
175 errmsg("invalid enum label \"%s\"", lab),
176 errdetail("Labels must be %d bytes or less.",
177 NAMEDATALEN - 1)));
178
179 ExecClearTuple(slot[slotCount]);
180
181 memset(slot[slotCount]->tts_isnull, false,
182 slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
183
184 slot[slotCount]->tts_values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(oids[elemno]);
185 slot[slotCount]->tts_values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
186 slot[slotCount]->tts_values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1);
187
188 namestrcpy(enumlabel, lab);
189 slot[slotCount]->tts_values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(enumlabel);
190
191 ExecStoreVirtualTuple(slot[slotCount]);
192 slotCount++;
193
194 /* if slots are full, insert a batch of tuples */
195 if (slotCount == nslots)
196 {
197 CatalogTuplesMultiInsertWithInfo(pg_enum, slot, slotCount,
198 indstate);
199 slotCount = 0;
200 }
201
202 elemno++;
203 }
204
205 /* Insert any tuples left in the buffer */
206 if (slotCount > 0)
207 CatalogTuplesMultiInsertWithInfo(pg_enum, slot, slotCount,
208 indstate);
209
210 /* clean up */
211 pfree(oids);
212 for (int i = 0; i < nslots; i++)
214 CatalogCloseIndexes(indstate);
216}
#define Min(x, y)
Definition: c.h:958
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1425
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1441
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1739
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:273
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
#define MAX_CATALOG_MULTI_INSERT_BYTES
Definition: indexing.h:33
void * palloc0(Size size)
Definition: mcxt.c:1347
int oid_cmp(const void *p1, const void *p2)
Definition: oid.c:258
static void init_uncommitted_enum_types(void)
Definition: pg_enum.c:255
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
Datum * tts_values
Definition: tuptable.h:125
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
#define strVal(v)
Definition: value.h:82

References CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTuplesMultiInsertWithInfo(), ereport, errcode(), errdetail(), errmsg(), ERROR, ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecStoreVirtualTuple(), Float4GetDatum(), FormData_pg_enum, GetCurrentTransactionNestLevel(), GetNewOidWithIndex(), HASH_ENTER, hash_search(), i, init_uncommitted_enum_types(), lfirst, list_length(), MakeSingleTupleTableSlot(), MAX_CATALOG_MULTI_INSERT_BYTES, Min, NAMEDATALEN, NameGetDatum(), namestrcpy(), ObjectIdGetDatum(), oid_cmp(), palloc(), palloc0(), pfree(), qsort, RelationGetDescr, RowExclusiveLock, strVal, table_close(), table_open(), TupleTableSlot::tts_values, TTSOpsHeapTuple, and uncommitted_enum_types.

Referenced by DefineEnum().

◆ EnumValuesDelete()

void EnumValuesDelete ( Oid  enumTypeOid)

Definition at line 224 of file pg_enum.c.

225{
226 Relation pg_enum;
227 ScanKeyData key[1];
228 SysScanDesc scan;
229 HeapTuple tup;
230
231 pg_enum = table_open(EnumRelationId, RowExclusiveLock);
232
233 ScanKeyInit(&key[0],
234 Anum_pg_enum_enumtypid,
235 BTEqualStrategyNumber, F_OIDEQ,
236 ObjectIdGetDatum(enumTypeOid));
237
238 scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true,
239 NULL, 1, key);
240
241 while (HeapTupleIsValid(tup = systable_getnext(scan)))
242 {
243 CatalogTupleDelete(pg_enum, &tup->t_self);
244 }
245
246 systable_endscan(scan);
247
249}
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
ItemPointerData t_self
Definition: htup.h:65

References BTEqualStrategyNumber, CatalogTupleDelete(), HeapTupleIsValid, sort-test::key, ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by RemoveTypeById().

◆ EstimateUncommittedEnumsSpace()

Size EstimateUncommittedEnumsSpace ( void  )

Definition at line 813 of file pg_enum.c.

814{
815 size_t entries = 0;
816
821
822 /* Add two for the terminators. */
823 return sizeof(Oid) * (entries + 2);
824}
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1341

References hash_get_num_entries(), uncommitted_enum_types, and uncommitted_enum_values.

Referenced by InitializeParallelDSM(), and SerializeUncommittedEnums().

◆ MAKE_SYSCACHE() [1/2]

MAKE_SYSCACHE ( ENUMOID  ,
pg_enum_oid_index  ,
 
)

◆ MAKE_SYSCACHE() [2/2]

MAKE_SYSCACHE ( ENUMTYPOIDNAME  ,
pg_enum_typid_label_index  ,
 
)

◆ RenameEnumLabel()

void RenameEnumLabel ( Oid  enumTypeOid,
const char *  oldVal,
const char *  newVal 
)

Definition at line 607 of file pg_enum.c.

610{
611 Relation pg_enum;
612 HeapTuple enum_tup;
613 Form_pg_enum en;
614 CatCList *list;
615 int nelems;
616 HeapTuple old_tup;
617 bool found_new;
618 int i;
619
620 /* check length of new label is ok */
621 if (strlen(newVal) > (NAMEDATALEN - 1))
623 (errcode(ERRCODE_INVALID_NAME),
624 errmsg("invalid enum label \"%s\"", newVal),
625 errdetail("Labels must be %d bytes or less.",
626 NAMEDATALEN - 1)));
627
628 /*
629 * Acquire a lock on the enum type, which we won't release until commit.
630 * This ensures that two backends aren't concurrently modifying the same
631 * enum type. Since we are not changing the type's sort order, this is
632 * probably not really necessary, but there seems no reason not to take
633 * the lock to be sure.
634 */
635 LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock);
636
637 pg_enum = table_open(EnumRelationId, RowExclusiveLock);
638
639 /* Get the list of existing members of the enum */
640 list = SearchSysCacheList1(ENUMTYPOIDNAME,
641 ObjectIdGetDatum(enumTypeOid));
642 nelems = list->n_members;
643
644 /*
645 * Locate the element to rename and check if the new label is already in
646 * use. (The unique index on pg_enum would catch that anyway, but we
647 * prefer a friendlier error message.)
648 */
649 old_tup = NULL;
650 found_new = false;
651 for (i = 0; i < nelems; i++)
652 {
653 enum_tup = &(list->members[i]->tuple);
654 en = (Form_pg_enum) GETSTRUCT(enum_tup);
655 if (strcmp(NameStr(en->enumlabel), oldVal) == 0)
656 old_tup = enum_tup;
657 if (strcmp(NameStr(en->enumlabel), newVal) == 0)
658 found_new = true;
659 }
660 if (!old_tup)
662 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
663 errmsg("\"%s\" is not an existing enum label",
664 oldVal)));
665 if (found_new)
668 errmsg("enum label \"%s\" already exists",
669 newVal)));
670
671 /* OK, make a writable copy of old tuple */
672 enum_tup = heap_copytuple(old_tup);
673 en = (Form_pg_enum) GETSTRUCT(enum_tup);
674
676
677 /* Update the pg_enum entry */
678 namestrcpy(&en->enumlabel, newVal);
679 CatalogTupleUpdate(pg_enum, &enum_tup->t_self, enum_tup);
680 heap_freetuple(enum_tup);
681
683}
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313

References CatalogTupleUpdate(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, ExclusiveLock, GETSTRUCT, heap_copytuple(), heap_freetuple(), i, sort-test::list, LockDatabaseObject(), NAMEDATALEN, NameStr, namestrcpy(), ObjectIdGetDatum(), ReleaseCatCacheList(), RowExclusiveLock, SearchSysCacheList1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by AlterEnum().

◆ RestoreUncommittedEnums()

void RestoreUncommittedEnums ( void *  space)

Definition at line 873 of file pg_enum.c.

874{
875 Oid *serialized = (Oid *) space;
876
879
880 /*
881 * If either list is empty then don't even bother to create that hash
882 * table. This is the common case, since most transactions don't create
883 * or alter enums.
884 */
885 if (OidIsValid(*serialized))
886 {
887 /* Read all the types into a new hash table. */
889 do
890 {
891 (void) hash_search(uncommitted_enum_types, serialized++,
892 HASH_ENTER, NULL);
893 } while (OidIsValid(*serialized));
894 }
895 serialized++;
896 if (OidIsValid(*serialized))
897 {
898 /* Read all the values into a new hash table. */
900 do
901 {
902 (void) hash_search(uncommitted_enum_values, serialized++,
903 HASH_ENTER, NULL);
904 } while (OidIsValid(*serialized));
905 }
906}
#define Assert(condition)
Definition: c.h:812

References Assert, HASH_ENTER, hash_search(), init_uncommitted_enum_types(), init_uncommitted_enum_values(), OidIsValid, uncommitted_enum_types, and uncommitted_enum_values.

Referenced by ParallelWorkerMain().

◆ SerializeUncommittedEnums()

void SerializeUncommittedEnums ( void *  space,
Size  size 
)

Definition at line 827 of file pg_enum.c.

828{
829 Oid *serialized = (Oid *) space;
830
831 /*
832 * Make sure the hash tables haven't changed in size since the caller
833 * reserved the space.
834 */
836
837 /* Write out all the OIDs from the types hash table, if there is one. */
839 {
840 HASH_SEQ_STATUS status;
841 Oid *value;
842
844 while ((value = (Oid *) hash_seq_search(&status)))
845 *serialized++ = *value;
846 }
847
848 /* Write out the terminator. */
849 *serialized++ = InvalidOid;
850
851 /* Write out all the OIDs from the values hash table, if there is one. */
853 {
854 HASH_SEQ_STATUS status;
855 Oid *value;
856
858 while ((value = (Oid *) hash_seq_search(&status)))
859 *serialized++ = *value;
860 }
861
862 /* Write out the terminator. */
863 *serialized++ = InvalidOid;
864
865 /*
866 * Make sure the amount of space we actually used matches what was
867 * estimated.
868 */
869 Assert((char *) serialized == ((char *) space) + size);
870}
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1420
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
static struct @161 value
Size EstimateUncommittedEnumsSpace(void)
Definition: pg_enum.c:813
static pg_noinline void Size size
Definition: slab.c:607

References Assert, EstimateUncommittedEnumsSpace(), hash_seq_init(), hash_seq_search(), InvalidOid, size, uncommitted_enum_types, uncommitted_enum_values, and value.

Referenced by InitializeParallelDSM().

Variable Documentation

◆ FormData_pg_enum

FormData_pg_enum

Definition at line 37 of file pg_enum.h.

Referenced by EnumValuesCreate().