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)
 
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 EnumBlacklisted (Oid enum_id)
 
Size EstimateEnumBlacklistSpace (void)
 
void SerializeEnumBlacklist (void *space, Size size)
 
void RestoreEnumBlacklist (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 208 of file pg_enum.c.

References binary_upgrade_next_pg_enum_oid, CatalogTupleInsert(), CStringGetDatum, EnumOidIndexId, 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_enum_blacklist(), InvalidOid, IsBinaryUpgrade, sort-test::list, LockDatabaseObject(), catclist::members, catclist::n_members, NAMEDATALEN, NameGetDatum, NameStr, namestrcpy(), NOTICE, ObjectIdGetDatum, OidIsValid, palloc(), pfree(), qsort, RelationGetDescr, ReleaseCatCacheList(), ReleaseSysCache(), RenumberEnumType(), RowExclusiveLock, SearchSysCache2(), SearchSysCacheList1, sort_order_cmp(), table_close(), table_open(), catctup::tuple, and values.

Referenced by AlterEnum().

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

◆ AtEOXact_Enum()

void AtEOXact_Enum ( void  )

Definition at line 609 of file pg_enum.c.

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

610 {
611  /*
612  * Reset the blacklist table, as all our enum values are now committed.
613  * The memory will go away automatically when TopTransactionContext is
614  * freed; it's sufficient to clear our pointer.
615  */
616  enum_blacklist = NULL;
617 }
static HTAB * enum_blacklist
Definition: pg_enum.c:47

◆ CATALOG()

CATALOG ( pg_enum  ,
3501  ,
EnumRelationId   
)

Definition at line 31 of file pg_enum.h.

32 {
33  Oid oid; /* oid */
34  Oid enumtypid; /* OID of owning enum type */
35  float4 enumsortorder; /* sort position of this enum value */
36  NameData enumlabel; /* text representation of enum value */
unsigned int Oid
Definition: postgres_ext.h:31
Definition: c.h:604
FormData_pg_enum
Definition: pg_enum.h:37
float float4
Definition: c.h:491

◆ EnumBlacklisted()

bool EnumBlacklisted ( Oid  enum_id)

Definition at line 591 of file pg_enum.c.

References HASH_FIND, and hash_search().

Referenced by check_safe_enum_use().

592 {
593  bool found;
594 
595  /* If we've made no blacklist table, all values are safe */
596  if (enum_blacklist == NULL)
597  return false;
598 
599  /* Else, is it in the table? */
600  (void) hash_search(enum_blacklist, &enum_id, HASH_FIND, &found);
601  return found;
602 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * enum_blacklist
Definition: pg_enum.c:47

◆ EnumValuesCreate()

void EnumValuesCreate ( Oid  enumTypeOid,
List vals 
)

Definition at line 60 of file pg_enum.c.

References CatalogTupleInsert(), EnumOidIndexId, ereport, errcode(), errdetail(), errmsg(), ERROR, Float4GetDatum(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), lfirst, list_length(), NAMEDATALEN, NameGetDatum, namestrcpy(), ObjectIdGetDatum, oid_cmp(), palloc(), pfree(), qsort, RelationGetDescr, RowExclusiveLock, strVal, table_close(), table_open(), and values.

Referenced by DefineEnum().

61 {
62  Relation pg_enum;
63  NameData enumlabel;
64  Oid *oids;
65  int elemno,
66  num_elems;
67  Datum values[Natts_pg_enum];
68  bool nulls[Natts_pg_enum];
69  ListCell *lc;
70  HeapTuple tup;
71 
72  num_elems = list_length(vals);
73 
74  /*
75  * We do not bother to check the list of values for duplicates --- if you
76  * have any, you'll get a less-than-friendly unique-index violation. It is
77  * probably not worth trying harder.
78  */
79 
80  pg_enum = table_open(EnumRelationId, RowExclusiveLock);
81 
82  /*
83  * Allocate OIDs for the enum's members.
84  *
85  * While this method does not absolutely guarantee that we generate no
86  * duplicate OIDs (since we haven't entered each oid into the table before
87  * allocating the next), trouble could only occur if the OID counter wraps
88  * all the way around before we finish. Which seems unlikely.
89  */
90  oids = (Oid *) palloc(num_elems * sizeof(Oid));
91 
92  for (elemno = 0; elemno < num_elems; elemno++)
93  {
94  /*
95  * We assign even-numbered OIDs to all the new enum labels. This
96  * tells the comparison functions the OIDs are in the correct sort
97  * order and can be compared directly.
98  */
99  Oid new_oid;
100 
101  do
102  {
103  new_oid = GetNewOidWithIndex(pg_enum, EnumOidIndexId,
104  Anum_pg_enum_oid);
105  } while (new_oid & 1);
106  oids[elemno] = new_oid;
107  }
108 
109  /* sort them, just in case OID counter wrapped from high to low */
110  qsort(oids, num_elems, sizeof(Oid), oid_cmp);
111 
112  /* and make the entries */
113  memset(nulls, false, sizeof(nulls));
114 
115  elemno = 0;
116  foreach(lc, vals)
117  {
118  char *lab = strVal(lfirst(lc));
119 
120  /*
121  * labels are stored in a name field, for easier syscache lookup, so
122  * check the length to make sure it's within range.
123  */
124  if (strlen(lab) > (NAMEDATALEN - 1))
125  ereport(ERROR,
126  (errcode(ERRCODE_INVALID_NAME),
127  errmsg("invalid enum label \"%s\"", lab),
128  errdetail("Labels must be %d characters or less.",
129  NAMEDATALEN - 1)));
130 
131  values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(oids[elemno]);
132  values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
133  values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1);
134  namestrcpy(&enumlabel, lab);
135  values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
136 
137  tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls);
138 
139  CatalogTupleInsert(pg_enum, tup);
140  heap_freetuple(tup);
141 
142  elemno++;
143  }
144 
145  /* clean up */
146  pfree(oids);
147  table_close(pg_enum, RowExclusiveLock);
148 }
static Datum Float4GetDatum(float4 X)
Definition: postgres.h:681
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:322
#define NameGetDatum(X)
Definition: postgres.h:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define RelationGetDescr(relation)
Definition: rel.h:449
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:608
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
#define NAMEDATALEN
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Definition: c.h:604
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:957
#define ereport(elevel, rest)
Definition: elog.h:141
uintptr_t Datum
Definition: postgres.h:367
#define EnumOidIndexId
Definition: indexing.h:159
#define lfirst(lc)
Definition: pg_list.h:190
int oid_cmp(const void *p1, const void *p2)
Definition: oid.c:336
static int list_length(const List *l)
Definition: pg_list.h:169
static Datum values[MAXATTR]
Definition: bootstrap.c:167
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define qsort(a, b, c, d)
Definition: port.h:492
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183

◆ EnumValuesDelete()

void EnumValuesDelete ( Oid  enumTypeOid)

Definition at line 156 of file pg_enum.c.

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

Referenced by RemoveTypeById().

157 {
158  Relation pg_enum;
159  ScanKeyData key[1];
160  SysScanDesc scan;
161  HeapTuple tup;
162 
163  pg_enum = table_open(EnumRelationId, RowExclusiveLock);
164 
165  ScanKeyInit(&key[0],
166  Anum_pg_enum_enumtypid,
167  BTEqualStrategyNumber, F_OIDEQ,
168  ObjectIdGetDatum(enumTypeOid));
169 
170  scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true,
171  NULL, 1, key);
172 
173  while (HeapTupleIsValid(tup = systable_getnext(scan)))
174  {
175  CatalogTupleDelete(pg_enum, &tup->t_self);
176  }
177 
178  systable_endscan(scan);
179 
180  table_close(pg_enum, RowExclusiveLock);
181 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
#define EnumTypIdLabelIndexId
Definition: indexing.h:161
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ EstimateEnumBlacklistSpace()

Size EstimateEnumBlacklistSpace ( void  )

Definition at line 695 of file pg_enum.c.

References hash_get_num_entries().

Referenced by InitializeParallelDSM(), and SerializeEnumBlacklist().

696 {
697  size_t entries;
698 
699  if (enum_blacklist)
701  else
702  entries = 0;
703 
704  /* Add one for the terminator. */
705  return sizeof(Oid) * (entries + 1);
706 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1335
unsigned int Oid
Definition: postgres_ext.h:31
static HTAB * enum_blacklist
Definition: pg_enum.c:47

◆ RenameEnumLabel()

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

Definition at line 508 of file pg_enum.c.

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

Referenced by AlterEnum().

511 {
512  Relation pg_enum;
513  HeapTuple enum_tup;
514  Form_pg_enum en;
515  CatCList *list;
516  int nelems;
517  HeapTuple old_tup;
518  bool found_new;
519  int i;
520 
521  /* check length of new label is ok */
522  if (strlen(newVal) > (NAMEDATALEN - 1))
523  ereport(ERROR,
524  (errcode(ERRCODE_INVALID_NAME),
525  errmsg("invalid enum label \"%s\"", newVal),
526  errdetail("Labels must be %d characters or less.",
527  NAMEDATALEN - 1)));
528 
529  /*
530  * Acquire a lock on the enum type, which we won't release until commit.
531  * This ensures that two backends aren't concurrently modifying the same
532  * enum type. Since we are not changing the type's sort order, this is
533  * probably not really necessary, but there seems no reason not to take
534  * the lock to be sure.
535  */
536  LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock);
537 
538  pg_enum = table_open(EnumRelationId, RowExclusiveLock);
539 
540  /* Get the list of existing members of the enum */
542  ObjectIdGetDatum(enumTypeOid));
543  nelems = list->n_members;
544 
545  /*
546  * Locate the element to rename and check if the new label is already in
547  * use. (The unique index on pg_enum would catch that anyway, but we
548  * prefer a friendlier error message.)
549  */
550  old_tup = NULL;
551  found_new = false;
552  for (i = 0; i < nelems; i++)
553  {
554  enum_tup = &(list->members[i]->tuple);
555  en = (Form_pg_enum) GETSTRUCT(enum_tup);
556  if (strcmp(NameStr(en->enumlabel), oldVal) == 0)
557  old_tup = enum_tup;
558  if (strcmp(NameStr(en->enumlabel), newVal) == 0)
559  found_new = true;
560  }
561  if (!old_tup)
562  ereport(ERROR,
563  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
564  errmsg("\"%s\" is not an existing enum label",
565  oldVal)));
566  if (found_new)
567  ereport(ERROR,
569  errmsg("enum label \"%s\" already exists",
570  newVal)));
571 
572  /* OK, make a writable copy of old tuple */
573  enum_tup = heap_copytuple(old_tup);
574  en = (Form_pg_enum) GETSTRUCT(enum_tup);
575 
576  ReleaseCatCacheList(list);
577 
578  /* Update the pg_enum entry */
579  namestrcpy(&en->enumlabel, newVal);
580  CatalogTupleUpdate(pg_enum, &enum_tup->t_self, enum_tup);
581  heap_freetuple(enum_tup);
582 
583  table_close(pg_enum, RowExclusiveLock);
584 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
int n_members
Definition: catcache.h:176
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define ExclusiveLock
Definition: lockdefs.h:44
int errcode(int sqlerrcode)
Definition: elog.c:608
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
int namestrcpy(Name name, const char *str)
Definition: name.c:250
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1782
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
#define NAMEDATALEN
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:957
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:961
FormData_pg_enum * Form_pg_enum
Definition: pg_enum.h:44
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:210
#define ereport(elevel, rest)
Definition: elog.h:141
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
#define NameStr(name)
Definition: c.h:610
HeapTupleData tuple
Definition: catcache.h:121
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ RestoreEnumBlacklist()

void RestoreEnumBlacklist ( void *  space)

Definition at line 741 of file pg_enum.c.

References Assert, HASH_ENTER, hash_search(), init_enum_blacklist(), and OidIsValid.

Referenced by ParallelWorkerMain().

742 {
743  Oid *serialized = (Oid *) space;
744 
746 
747  /*
748  * As a special case, if the list is empty then don't even bother to
749  * create the hash table. This is the usual case, since enum alteration
750  * is expected to be rare.
751  */
752  if (!OidIsValid(*serialized))
753  return;
754 
755  /* Read all the values into a new hash table. */
757  do
758  {
759  hash_search(enum_blacklist, serialized++, HASH_ENTER, NULL);
760  } while (OidIsValid(*serialized));
761 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:639
#define Assert(condition)
Definition: c.h:733
static HTAB * enum_blacklist
Definition: pg_enum.c:47
static void init_enum_blacklist(void)
Definition: pg_enum.c:187

◆ SerializeEnumBlacklist()

void SerializeEnumBlacklist ( void *  space,
Size  size 
)

Definition at line 709 of file pg_enum.c.

References Assert, EstimateEnumBlacklistSpace(), hash_seq_init(), hash_seq_search(), InvalidOid, status(), and value.

Referenced by InitializeParallelDSM().

710 {
711  Oid *serialized = (Oid *) space;
712 
713  /*
714  * Make sure the hash table hasn't changed in size since the caller
715  * reserved the space.
716  */
718 
719  /* Write out all the values from the hash table, if there is one. */
720  if (enum_blacklist)
721  {
723  Oid *value;
724 
725  hash_seq_init(&status, enum_blacklist);
726  while ((value = (Oid *) hash_seq_search(&status)))
727  *serialized++ = *value;
728  }
729 
730  /* Write out the terminator. */
731  *serialized = InvalidOid;
732 
733  /*
734  * Make sure the amount of space we actually used matches what was
735  * estimated.
736  */
737  Assert((char *) (serialized + 1) == ((char *) space) + size);
738 }
static struct @145 value
unsigned int Oid
Definition: postgres_ext.h:31
Size EstimateEnumBlacklistSpace(void)
Definition: pg_enum.c:695
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:733
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
static HTAB * enum_blacklist
Definition: pg_enum.c:47
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226

Variable Documentation

◆ FormData_pg_enum

FormData_pg_enum

Definition at line 37 of file pg_enum.h.