PostgreSQL Source Code  git master
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, on pg_enum using btree(oid oid_ops))
 
 DECLARE_UNIQUE_INDEX (pg_enum_typid_label_index, 3503, EnumTypIdLabelIndexId, on pg_enum using btree(enumtypid oid_ops, enumlabel name_ops))
 
 DECLARE_UNIQUE_INDEX (pg_enum_typid_sortorder_index, 3534, EnumTypIdSortOrderIndexId, on pg_enum using btree(enumtypid oid_ops, enumsortorder float4_ops))
 
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 237 of file pg_enum.c.

242 {
243  Relation pg_enum;
244  Oid newOid;
245  Datum values[Natts_pg_enum];
246  bool nulls[Natts_pg_enum];
247  NameData enumlabel;
248  HeapTuple enum_tup;
249  float4 newelemorder;
250  HeapTuple *existing;
251  CatCList *list;
252  int nelems;
253  int i;
254 
255  /* check length of new label is ok */
256  if (strlen(newVal) > (NAMEDATALEN - 1))
257  ereport(ERROR,
258  (errcode(ERRCODE_INVALID_NAME),
259  errmsg("invalid enum label \"%s\"", newVal),
260  errdetail("Labels must be %d bytes or less.",
261  NAMEDATALEN - 1)));
262 
263  /*
264  * Acquire a lock on the enum type, which we won't release until commit.
265  * This ensures that two backends aren't concurrently modifying the same
266  * enum type. Without that, we couldn't be sure to get a consistent view
267  * of the enum members via the syscache. Note that this does not block
268  * other backends from inspecting the type; see comments for
269  * RenumberEnumType.
270  */
271  LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock);
272 
273  /*
274  * Check if label is already in use. The unique index on pg_enum would
275  * catch this anyway, but we prefer a friendlier error message, and
276  * besides we need a check to support IF NOT EXISTS.
277  */
278  enum_tup = SearchSysCache2(ENUMTYPOIDNAME,
279  ObjectIdGetDatum(enumTypeOid),
280  CStringGetDatum(newVal));
281  if (HeapTupleIsValid(enum_tup))
282  {
283  ReleaseSysCache(enum_tup);
284  if (skipIfExists)
285  {
286  ereport(NOTICE,
288  errmsg("enum label \"%s\" already exists, skipping",
289  newVal)));
290  return;
291  }
292  else
293  ereport(ERROR,
295  errmsg("enum label \"%s\" already exists",
296  newVal)));
297  }
298 
299  pg_enum = table_open(EnumRelationId, RowExclusiveLock);
300 
301  /* If we have to renumber the existing members, we restart from here */
302 restart:
303 
304  /* Get the list of existing members of the enum */
306  ObjectIdGetDatum(enumTypeOid));
307  nelems = list->n_members;
308 
309  /* Sort the existing members by enumsortorder */
310  existing = (HeapTuple *) palloc(nelems * sizeof(HeapTuple));
311  for (i = 0; i < nelems; i++)
312  existing[i] = &(list->members[i]->tuple);
313 
314  qsort(existing, nelems, sizeof(HeapTuple), sort_order_cmp);
315 
316  if (neighbor == NULL)
317  {
318  /*
319  * Put the new label at the end of the list. No change to existing
320  * tuples is required.
321  */
322  if (nelems > 0)
323  {
324  Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nelems - 1]);
325 
326  newelemorder = en->enumsortorder + 1;
327  }
328  else
329  newelemorder = 1;
330  }
331  else
332  {
333  /* BEFORE or AFTER was specified */
334  int nbr_index;
335  int other_nbr_index;
336  Form_pg_enum nbr_en;
337  Form_pg_enum other_nbr_en;
338 
339  /* Locate the neighbor element */
340  for (nbr_index = 0; nbr_index < nelems; nbr_index++)
341  {
342  Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]);
343 
344  if (strcmp(NameStr(en->enumlabel), neighbor) == 0)
345  break;
346  }
347  if (nbr_index >= nelems)
348  ereport(ERROR,
349  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
350  errmsg("\"%s\" is not an existing enum label",
351  neighbor)));
352  nbr_en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]);
353 
354  /*
355  * Attempt to assign an appropriate enumsortorder value: one less than
356  * the smallest member, one more than the largest member, or halfway
357  * between two existing members.
358  *
359  * In the "halfway" case, because of the finite precision of float4,
360  * we might compute a value that's actually equal to one or the other
361  * of its neighbors. In that case we renumber the existing members
362  * and try again.
363  */
364  if (newValIsAfter)
365  other_nbr_index = nbr_index + 1;
366  else
367  other_nbr_index = nbr_index - 1;
368 
369  if (other_nbr_index < 0)
370  newelemorder = nbr_en->enumsortorder - 1;
371  else if (other_nbr_index >= nelems)
372  newelemorder = nbr_en->enumsortorder + 1;
373  else
374  {
375  /*
376  * The midpoint value computed here has to be rounded to float4
377  * precision, else our equality comparisons against the adjacent
378  * values are meaningless. The most portable way of forcing that
379  * to happen with non-C-standard-compliant compilers is to store
380  * it into a volatile variable.
381  */
382  volatile float4 midpoint;
383 
384  other_nbr_en = (Form_pg_enum) GETSTRUCT(existing[other_nbr_index]);
385  midpoint = (nbr_en->enumsortorder +
386  other_nbr_en->enumsortorder) / 2;
387 
388  if (midpoint == nbr_en->enumsortorder ||
389  midpoint == other_nbr_en->enumsortorder)
390  {
391  RenumberEnumType(pg_enum, existing, nelems);
392  /* Clean up and start over */
393  pfree(existing);
395  goto restart;
396  }
397 
398  newelemorder = midpoint;
399  }
400  }
401 
402  /* Get a new OID for the new label */
403  if (IsBinaryUpgrade)
404  {
406  ereport(ERROR,
407  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
408  errmsg("pg_enum OID value not set when in binary upgrade mode")));
409 
410  /*
411  * Use binary-upgrade override for pg_enum.oid, if supplied. During
412  * binary upgrade, all pg_enum.oid's are set this way so they are
413  * guaranteed to be consistent.
414  */
415  if (neighbor != NULL)
416  ereport(ERROR,
417  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
418  errmsg("ALTER TYPE ADD BEFORE/AFTER is incompatible with binary upgrade")));
419 
422  }
423  else
424  {
425  /*
426  * Normal case: we need to allocate a new Oid for the value.
427  *
428  * We want to give the new element an even-numbered Oid if it's safe,
429  * which is to say it compares correctly to all pre-existing even
430  * numbered Oids in the enum. Otherwise, we must give it an odd Oid.
431  */
432  for (;;)
433  {
434  bool sorts_ok;
435 
436  /* Get a new OID (different from all existing pg_enum tuples) */
437  newOid = GetNewOidWithIndex(pg_enum, EnumOidIndexId,
438  Anum_pg_enum_oid);
439 
440  /*
441  * Detect whether it sorts correctly relative to existing
442  * even-numbered labels of the enum. We can ignore existing
443  * labels with odd Oids, since a comparison involving one of those
444  * will not take the fast path anyway.
445  */
446  sorts_ok = true;
447  for (i = 0; i < nelems; i++)
448  {
449  HeapTuple exists_tup = existing[i];
450  Form_pg_enum exists_en = (Form_pg_enum) GETSTRUCT(exists_tup);
451  Oid exists_oid = exists_en->oid;
452 
453  if (exists_oid & 1)
454  continue; /* ignore odd Oids */
455 
456  if (exists_en->enumsortorder < newelemorder)
457  {
458  /* should sort before */
459  if (exists_oid >= newOid)
460  {
461  sorts_ok = false;
462  break;
463  }
464  }
465  else
466  {
467  /* should sort after */
468  if (exists_oid <= newOid)
469  {
470  sorts_ok = false;
471  break;
472  }
473  }
474  }
475 
476  if (sorts_ok)
477  {
478  /* If it's even and sorts OK, we're done. */
479  if ((newOid & 1) == 0)
480  break;
481 
482  /*
483  * If it's odd, and sorts OK, loop back to get another OID and
484  * try again. Probably, the next available even OID will sort
485  * correctly too, so it's worth trying.
486  */
487  }
488  else
489  {
490  /*
491  * If it's odd, and does not sort correctly, we're done.
492  * (Probably, the next available even OID would sort
493  * incorrectly too, so no point in trying again.)
494  */
495  if (newOid & 1)
496  break;
497 
498  /*
499  * If it's even, and does not sort correctly, loop back to get
500  * another OID and try again. (We *must* reject this case.)
501  */
502  }
503  }
504  }
505 
506  /* Done with info about existing members */
507  pfree(existing);
509 
510  /* Create the new pg_enum entry */
511  memset(nulls, false, sizeof(nulls));
512  values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(newOid);
513  values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
514  values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(newelemorder);
515  namestrcpy(&enumlabel, newVal);
516  values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
517  enum_tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls);
518  CatalogTupleInsert(pg_enum, enum_tup);
519  heap_freetuple(enum_tup);
520 
521  table_close(pg_enum, RowExclusiveLock);
522 
523  /* Set up the uncommitted enum table if not already done in this tx */
524  if (uncommitted_enums == NULL)
526 
527  /* Add the new value to the table */
528  (void) hash_search(uncommitted_enums, &newOid, HASH_ENTER, NULL);
529 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define NameStr(name)
Definition: c.h:730
float float4
Definition: c.h:613
#define OidIsValid(objectId)
Definition: c.h:759
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:393
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1776
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
bool IsBinaryUpgrade
Definition: globals.c:114
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
@ 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:221
int i
Definition: isn.c:73
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1005
#define ExclusiveLock
Definition: lockdefs.h:42
#define RowExclusiveLock
Definition: lockdefs.h:38
void pfree(void *pointer)
Definition: mcxt.c:1436
void * palloc(Size size)
Definition: mcxt.c:1210
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define NAMEDATALEN
static HTAB * uncommitted_enums
Definition: pg_enum.c:48
static void init_uncommitted_enums(void)
Definition: pg_enum.c:217
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:708
static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems)
Definition: pg_enum.c:672
FormData_pg_enum * Form_pg_enum
Definition: pg_enum.h:44
#define qsort(a, b, c, d)
Definition: port.h:445
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:527
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Definition: c.h:725
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:865
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:828
@ ENUMTYPOIDNAME
Definition: syscache.h:58
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:215
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References binary_upgrade_next_pg_enum_oid, CatalogTupleInsert(), CStringGetDatum(), ENUMTYPOIDNAME, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, ExclusiveLock, Float4GetDatum(), GetNewOidWithIndex(), GETSTRUCT, HASH_ENTER, hash_search(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, init_uncommitted_enums(), 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_enums, and values.

Referenced by AlterEnum().

◆ AtEOXact_Enum()

void AtEOXact_Enum ( void  )

Definition at line 638 of file pg_enum.c.

639 {
640  /*
641  * Reset the uncommitted table, as all our enum values are now committed.
642  * The memory will go away automatically when TopTransactionContext is
643  * freed; it's sufficient to clear our pointer.
644  */
645  uncommitted_enums = NULL;
646 }

References uncommitted_enums.

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  ,
on pg_enum using   btreeenumtypid oid_ops, enumlabel name_ops 
)

◆ DECLARE_UNIQUE_INDEX() [2/2]

DECLARE_UNIQUE_INDEX ( pg_enum_typid_sortorder_index  ,
3534  ,
EnumTypIdSortOrderIndexId  ,
on pg_enum using   btreeenumtypid oid_ops, enumsortorder float4_ops 
)

◆ DECLARE_UNIQUE_INDEX_PKEY()

DECLARE_UNIQUE_INDEX_PKEY ( pg_enum_oid_index  ,
3502  ,
EnumOidIndexId  ,
on pg_enum using   btreeoid oid_ops 
)

◆ EnumUncommitted()

bool EnumUncommitted ( Oid  enum_id)

Definition at line 620 of file pg_enum.c.

621 {
622  bool found;
623 
624  /* If we've made no uncommitted table, all values are safe */
625  if (uncommitted_enums == NULL)
626  return false;
627 
628  /* Else, is it in the table? */
629  (void) hash_search(uncommitted_enums, &enum_id, HASH_FIND, &found);
630  return found;
631 }
@ HASH_FIND
Definition: hsearch.h:113

References HASH_FIND, hash_search(), and uncommitted_enums.

Referenced by check_safe_enum_use().

◆ EnumValuesCreate()

void EnumValuesCreate ( Oid  enumTypeOid,
List vals 
)

Definition at line 61 of file pg_enum.c.

62 {
63  Relation pg_enum;
64  Oid *oids;
65  int elemno,
66  num_elems;
67  ListCell *lc;
68  int slotCount = 0;
69  int nslots;
70  CatalogIndexState indstate;
71  TupleTableSlot **slot;
72 
73  num_elems = list_length(vals);
74 
75  /*
76  * We do not bother to check the list of values for duplicates --- if you
77  * have any, you'll get a less-than-friendly unique-index violation. It is
78  * probably not worth trying harder.
79  */
80 
81  pg_enum = table_open(EnumRelationId, RowExclusiveLock);
82 
83  /*
84  * Allocate OIDs for the enum's members.
85  *
86  * While this method does not absolutely guarantee that we generate no
87  * duplicate OIDs (since we haven't entered each oid into the table before
88  * allocating the next), trouble could only occur if the OID counter wraps
89  * all the way around before we finish. Which seems unlikely.
90  */
91  oids = (Oid *) palloc(num_elems * sizeof(Oid));
92 
93  for (elemno = 0; elemno < num_elems; elemno++)
94  {
95  /*
96  * We assign even-numbered OIDs to all the new enum labels. This
97  * tells the comparison functions the OIDs are in the correct sort
98  * order and can be compared directly.
99  */
100  Oid new_oid;
101 
102  do
103  {
104  new_oid = GetNewOidWithIndex(pg_enum, EnumOidIndexId,
105  Anum_pg_enum_oid);
106  } while (new_oid & 1);
107  oids[elemno] = new_oid;
108  }
109 
110  /* sort them, just in case OID counter wrapped from high to low */
111  qsort(oids, num_elems, sizeof(Oid), oid_cmp);
112 
113  /* and make the entries */
114  indstate = CatalogOpenIndexes(pg_enum);
115 
116  /* allocate the slots to use and initialize them */
117  nslots = Min(num_elems,
119  slot = palloc(sizeof(TupleTableSlot *) * nslots);
120  for (int i = 0; i < nslots; i++)
122  &TTSOpsHeapTuple);
123 
124  elemno = 0;
125  foreach(lc, vals)
126  {
127  char *lab = strVal(lfirst(lc));
128  Name enumlabel = palloc0(NAMEDATALEN);
129 
130  /*
131  * labels are stored in a name field, for easier syscache lookup, so
132  * check the length to make sure it's within range.
133  */
134  if (strlen(lab) > (NAMEDATALEN - 1))
135  ereport(ERROR,
136  (errcode(ERRCODE_INVALID_NAME),
137  errmsg("invalid enum label \"%s\"", lab),
138  errdetail("Labels must be %d bytes or less.",
139  NAMEDATALEN - 1)));
140 
141  ExecClearTuple(slot[slotCount]);
142 
143  memset(slot[slotCount]->tts_isnull, false,
144  slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
145 
146  slot[slotCount]->tts_values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(oids[elemno]);
147  slot[slotCount]->tts_values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
148  slot[slotCount]->tts_values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1);
149 
150  namestrcpy(enumlabel, lab);
151  slot[slotCount]->tts_values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(enumlabel);
152 
153  ExecStoreVirtualTuple(slot[slotCount]);
154  slotCount++;
155 
156  /* if slots are full, insert a batch of tuples */
157  if (slotCount == nslots)
158  {
159  CatalogTuplesMultiInsertWithInfo(pg_enum, slot, slotCount,
160  indstate);
161  slotCount = 0;
162  }
163 
164  elemno++;
165  }
166 
167  /* Insert any tuples left in the buffer */
168  if (slotCount > 0)
169  CatalogTuplesMultiInsertWithInfo(pg_enum, slot, slotCount,
170  indstate);
171 
172  /* clean up */
173  pfree(oids);
174  for (int i = 0; i < nslots; i++)
176  CatalogCloseIndexes(indstate);
177  table_close(pg_enum, RowExclusiveLock);
178 }
#define Min(x, y)
Definition: c.h:988
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1552
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:84
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1238
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:261
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:1241
int oid_cmp(const void *p1, const void *p2)
Definition: oid.c:257
#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:126
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:433
#define strVal(v)
Definition: value.h:82

References CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTuplesMultiInsertWithInfo(), ereport, errcode(), errdetail(), errmsg(), ERROR, ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecStoreVirtualTuple(), Float4GetDatum(), FormData_pg_enum, GetNewOidWithIndex(), i, 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, and TTSOpsHeapTuple.

Referenced by DefineEnum().

◆ EnumValuesDelete()

void EnumValuesDelete ( Oid  enumTypeOid)

Definition at line 186 of file pg_enum.c.

187 {
188  Relation pg_enum;
189  ScanKeyData key[1];
190  SysScanDesc scan;
191  HeapTuple tup;
192 
193  pg_enum = table_open(EnumRelationId, RowExclusiveLock);
194 
195  ScanKeyInit(&key[0],
196  Anum_pg_enum_enumtypid,
197  BTEqualStrategyNumber, F_OIDEQ,
198  ObjectIdGetDatum(enumTypeOid));
199 
200  scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true,
201  NULL, 1, key);
202 
203  while (HeapTupleIsValid(tup = systable_getnext(scan)))
204  {
205  CatalogTupleDelete(pg_enum, &tup->t_self);
206  }
207 
208  systable_endscan(scan);
209 
210  table_close(pg_enum, RowExclusiveLock);
211 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
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:350
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 724 of file pg_enum.c.

725 {
726  size_t entries;
727 
728  if (uncommitted_enums)
730  else
731  entries = 0;
732 
733  /* Add one for the terminator. */
734  return sizeof(Oid) * (entries + 1);
735 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1377

References hash_get_num_entries(), and uncommitted_enums.

Referenced by InitializeParallelDSM(), and SerializeUncommittedEnums().

◆ RenameEnumLabel()

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

Definition at line 537 of file pg_enum.c.

540 {
541  Relation pg_enum;
542  HeapTuple enum_tup;
543  Form_pg_enum en;
544  CatCList *list;
545  int nelems;
546  HeapTuple old_tup;
547  bool found_new;
548  int i;
549 
550  /* check length of new label is ok */
551  if (strlen(newVal) > (NAMEDATALEN - 1))
552  ereport(ERROR,
553  (errcode(ERRCODE_INVALID_NAME),
554  errmsg("invalid enum label \"%s\"", newVal),
555  errdetail("Labels must be %d bytes or less.",
556  NAMEDATALEN - 1)));
557 
558  /*
559  * Acquire a lock on the enum type, which we won't release until commit.
560  * This ensures that two backends aren't concurrently modifying the same
561  * enum type. Since we are not changing the type's sort order, this is
562  * probably not really necessary, but there seems no reason not to take
563  * the lock to be sure.
564  */
565  LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock);
566 
567  pg_enum = table_open(EnumRelationId, RowExclusiveLock);
568 
569  /* Get the list of existing members of the enum */
571  ObjectIdGetDatum(enumTypeOid));
572  nelems = list->n_members;
573 
574  /*
575  * Locate the element to rename and check if the new label is already in
576  * use. (The unique index on pg_enum would catch that anyway, but we
577  * prefer a friendlier error message.)
578  */
579  old_tup = NULL;
580  found_new = false;
581  for (i = 0; i < nelems; i++)
582  {
583  enum_tup = &(list->members[i]->tuple);
584  en = (Form_pg_enum) GETSTRUCT(enum_tup);
585  if (strcmp(NameStr(en->enumlabel), oldVal) == 0)
586  old_tup = enum_tup;
587  if (strcmp(NameStr(en->enumlabel), newVal) == 0)
588  found_new = true;
589  }
590  if (!old_tup)
591  ereport(ERROR,
592  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
593  errmsg("\"%s\" is not an existing enum label",
594  oldVal)));
595  if (found_new)
596  ereport(ERROR,
598  errmsg("enum label \"%s\" already exists",
599  newVal)));
600 
601  /* OK, make a writable copy of old tuple */
602  enum_tup = heap_copytuple(old_tup);
603  en = (Form_pg_enum) GETSTRUCT(enum_tup);
604 
606 
607  /* Update the pg_enum entry */
608  namestrcpy(&en->enumlabel, newVal);
609  CatalogTupleUpdate(pg_enum, &enum_tup->t_self, enum_tup);
610  heap_freetuple(enum_tup);
611 
612  table_close(pg_enum, RowExclusiveLock);
613 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301

References CatalogTupleUpdate(), ENUMTYPOIDNAME, 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 770 of file pg_enum.c.

771 {
772  Oid *serialized = (Oid *) space;
773 
775 
776  /*
777  * As a special case, if the list is empty then don't even bother to
778  * create the hash table. This is the usual case, since enum alteration
779  * is expected to be rare.
780  */
781  if (!OidIsValid(*serialized))
782  return;
783 
784  /* Read all the values into a new hash table. */
786  do
787  {
788  hash_search(uncommitted_enums, serialized++, HASH_ENTER, NULL);
789  } while (OidIsValid(*serialized));
790 }
Assert(fmt[strlen(fmt) - 1] !='\n')

References Assert(), HASH_ENTER, hash_search(), init_uncommitted_enums(), OidIsValid, and uncommitted_enums.

Referenced by ParallelWorkerMain().

◆ SerializeUncommittedEnums()

void SerializeUncommittedEnums ( void *  space,
Size  size 
)

Definition at line 738 of file pg_enum.c.

739 {
740  Oid *serialized = (Oid *) space;
741 
742  /*
743  * Make sure the hash table hasn't changed in size since the caller
744  * reserved the space.
745  */
747 
748  /* Write out all the values from the hash table, if there is one. */
749  if (uncommitted_enums)
750  {
752  Oid *value;
753 
755  while ((value = (Oid *) hash_seq_search(&status)))
756  *serialized++ = *value;
757  }
758 
759  /* Write out the terminator. */
760  *serialized = InvalidOid;
761 
762  /*
763  * Make sure the amount of space we actually used matches what was
764  * estimated.
765  */
766  Assert((char *) (serialized + 1) == ((char *) space) + size);
767 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
static struct @143 value
Size EstimateUncommittedEnumsSpace(void)
Definition: pg_enum.c:724
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224

References Assert(), EstimateUncommittedEnumsSpace(), hash_seq_init(), hash_seq_search(), InvalidOid, status(), uncommitted_enums, 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().