PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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/heapam.h"
18 #include "access/htup_details.h"
19 #include "access/xact.h"
20 #include "catalog/binary_upgrade.h"
21 #include "catalog/catalog.h"
22 #include "catalog/indexing.h"
23 #include "catalog/pg_enum.h"
24 #include "catalog/pg_type.h"
25 #include "storage/lmgr.h"
26 #include "miscadmin.h"
27 #include "nodes/value.h"
28 #include "utils/builtins.h"
29 #include "utils/catcache.h"
30 #include "utils/fmgroids.h"
31 #include "utils/syscache.h"
32 #include "utils/tqual.h"
33 
34 
35 /* Potentially set by pg_upgrade_support functions */
37 
38 static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems);
39 static int sort_order_cmp(const void *p1, const void *p2);
40 
41 
42 /*
43  * EnumValuesCreate
44  * Create an entry in pg_enum for each of the supplied enum values.
45  *
46  * vals is a list of Value strings.
47  */
48 void
49 EnumValuesCreate(Oid enumTypeOid, List *vals)
50 {
51  Relation pg_enum;
52  NameData enumlabel;
53  Oid *oids;
54  int elemno,
55  num_elems;
57  bool nulls[Natts_pg_enum];
58  ListCell *lc;
59  HeapTuple tup;
60 
61  num_elems = list_length(vals);
62 
63  /*
64  * We do not bother to check the list of values for duplicates --- if you
65  * have any, you'll get a less-than-friendly unique-index violation. It is
66  * probably not worth trying harder.
67  */
68 
70 
71  /*
72  * Allocate OIDs for the enum's members.
73  *
74  * While this method does not absolutely guarantee that we generate no
75  * duplicate OIDs (since we haven't entered each oid into the table before
76  * allocating the next), trouble could only occur if the OID counter wraps
77  * all the way around before we finish. Which seems unlikely.
78  */
79  oids = (Oid *) palloc(num_elems * sizeof(Oid));
80 
81  for (elemno = 0; elemno < num_elems; elemno++)
82  {
83  /*
84  * We assign even-numbered OIDs to all the new enum labels. This
85  * tells the comparison functions the OIDs are in the correct sort
86  * order and can be compared directly.
87  */
88  Oid new_oid;
89 
90  do
91  {
92  new_oid = GetNewOid(pg_enum);
93  } while (new_oid & 1);
94  oids[elemno] = new_oid;
95  }
96 
97  /* sort them, just in case OID counter wrapped from high to low */
98  qsort(oids, num_elems, sizeof(Oid), oid_cmp);
99 
100  /* and make the entries */
101  memset(nulls, false, sizeof(nulls));
102 
103  elemno = 0;
104  foreach(lc, vals)
105  {
106  char *lab = strVal(lfirst(lc));
107 
108  /*
109  * labels are stored in a name field, for easier syscache lookup, so
110  * check the length to make sure it's within range.
111  */
112  if (strlen(lab) > (NAMEDATALEN - 1))
113  ereport(ERROR,
114  (errcode(ERRCODE_INVALID_NAME),
115  errmsg("invalid enum label \"%s\"", lab),
116  errdetail("Labels must be %d characters or less.",
117  NAMEDATALEN - 1)));
118 
119  values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
120  values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1);
121  namestrcpy(&enumlabel, lab);
122  values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
123 
124  tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls);
125  HeapTupleSetOid(tup, oids[elemno]);
126 
127  CatalogTupleInsert(pg_enum, tup);
128  heap_freetuple(tup);
129 
130  elemno++;
131  }
132 
133  /* clean up */
134  pfree(oids);
135  heap_close(pg_enum, RowExclusiveLock);
136 }
137 
138 
139 /*
140  * EnumValuesDelete
141  * Remove all the pg_enum entries for the specified enum type.
142  */
143 void
144 EnumValuesDelete(Oid enumTypeOid)
145 {
146  Relation pg_enum;
147  ScanKeyData key[1];
148  SysScanDesc scan;
149  HeapTuple tup;
150 
152 
153  ScanKeyInit(&key[0],
155  BTEqualStrategyNumber, F_OIDEQ,
156  ObjectIdGetDatum(enumTypeOid));
157 
158  scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true,
159  NULL, 1, key);
160 
161  while (HeapTupleIsValid(tup = systable_getnext(scan)))
162  {
163  CatalogTupleDelete(pg_enum, &tup->t_self);
164  }
165 
166  systable_endscan(scan);
167 
168  heap_close(pg_enum, RowExclusiveLock);
169 }
170 
171 
172 /*
173  * AddEnumLabel
174  * Add a new label to the enum set. By default it goes at
175  * the end, but the user can choose to place it before or
176  * after any existing set member.
177  */
178 void
179 AddEnumLabel(Oid enumTypeOid,
180  const char *newVal,
181  const char *neighbor,
182  bool newValIsAfter,
183  bool skipIfExists)
184 {
185  Relation pg_enum;
186  Oid newOid;
188  bool nulls[Natts_pg_enum];
189  NameData enumlabel;
190  HeapTuple enum_tup;
191  float4 newelemorder;
192  HeapTuple *existing;
193  CatCList *list;
194  int nelems;
195  int i;
196 
197  /* check length of new label is ok */
198  if (strlen(newVal) > (NAMEDATALEN - 1))
199  ereport(ERROR,
200  (errcode(ERRCODE_INVALID_NAME),
201  errmsg("invalid enum label \"%s\"", newVal),
202  errdetail("Labels must be %d characters or less.",
203  NAMEDATALEN - 1)));
204 
205  /*
206  * Acquire a lock on the enum type, which we won't release until commit.
207  * This ensures that two backends aren't concurrently modifying the same
208  * enum type. Without that, we couldn't be sure to get a consistent view
209  * of the enum members via the syscache. Note that this does not block
210  * other backends from inspecting the type; see comments for
211  * RenumberEnumType.
212  */
214 
215  /*
216  * Check if label is already in use. The unique index on pg_enum would
217  * catch this anyway, but we prefer a friendlier error message, and
218  * besides we need a check to support IF NOT EXISTS.
219  */
220  enum_tup = SearchSysCache2(ENUMTYPOIDNAME,
221  ObjectIdGetDatum(enumTypeOid),
222  CStringGetDatum(newVal));
223  if (HeapTupleIsValid(enum_tup))
224  {
225  ReleaseSysCache(enum_tup);
226  if (skipIfExists)
227  {
228  ereport(NOTICE,
230  errmsg("enum label \"%s\" already exists, skipping",
231  newVal)));
232  return;
233  }
234  else
235  ereport(ERROR,
237  errmsg("enum label \"%s\" already exists",
238  newVal)));
239  }
240 
242 
243  /* If we have to renumber the existing members, we restart from here */
244 restart:
245 
246  /* Get the list of existing members of the enum */
248  ObjectIdGetDatum(enumTypeOid));
249  nelems = list->n_members;
250 
251  /* Sort the existing members by enumsortorder */
252  existing = (HeapTuple *) palloc(nelems * sizeof(HeapTuple));
253  for (i = 0; i < nelems; i++)
254  existing[i] = &(list->members[i]->tuple);
255 
256  qsort(existing, nelems, sizeof(HeapTuple), sort_order_cmp);
257 
258  if (neighbor == NULL)
259  {
260  /*
261  * Put the new label at the end of the list. No change to existing
262  * tuples is required.
263  */
264  if (nelems > 0)
265  {
266  Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nelems - 1]);
267 
268  newelemorder = en->enumsortorder + 1;
269  }
270  else
271  newelemorder = 1;
272  }
273  else
274  {
275  /* BEFORE or AFTER was specified */
276  int nbr_index;
277  int other_nbr_index;
278  Form_pg_enum nbr_en;
279  Form_pg_enum other_nbr_en;
280 
281  /* Locate the neighbor element */
282  for (nbr_index = 0; nbr_index < nelems; nbr_index++)
283  {
284  Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]);
285 
286  if (strcmp(NameStr(en->enumlabel), neighbor) == 0)
287  break;
288  }
289  if (nbr_index >= nelems)
290  ereport(ERROR,
291  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
292  errmsg("\"%s\" is not an existing enum label",
293  neighbor)));
294  nbr_en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]);
295 
296  /*
297  * Attempt to assign an appropriate enumsortorder value: one less than
298  * the smallest member, one more than the largest member, or halfway
299  * between two existing members.
300  *
301  * In the "halfway" case, because of the finite precision of float4,
302  * we might compute a value that's actually equal to one or the other
303  * of its neighbors. In that case we renumber the existing members
304  * and try again.
305  */
306  if (newValIsAfter)
307  other_nbr_index = nbr_index + 1;
308  else
309  other_nbr_index = nbr_index - 1;
310 
311  if (other_nbr_index < 0)
312  newelemorder = nbr_en->enumsortorder - 1;
313  else if (other_nbr_index >= nelems)
314  newelemorder = nbr_en->enumsortorder + 1;
315  else
316  {
317  /*
318  * The midpoint value computed here has to be rounded to float4
319  * precision, else our equality comparisons against the adjacent
320  * values are meaningless. The most portable way of forcing that
321  * to happen with non-C-standard-compliant compilers is to store
322  * it into a volatile variable.
323  */
324  volatile float4 midpoint;
325 
326  other_nbr_en = (Form_pg_enum) GETSTRUCT(existing[other_nbr_index]);
327  midpoint = (nbr_en->enumsortorder +
328  other_nbr_en->enumsortorder) / 2;
329 
330  if (midpoint == nbr_en->enumsortorder ||
331  midpoint == other_nbr_en->enumsortorder)
332  {
333  RenumberEnumType(pg_enum, existing, nelems);
334  /* Clean up and start over */
335  pfree(existing);
336  ReleaseCatCacheList(list);
337  goto restart;
338  }
339 
340  newelemorder = midpoint;
341  }
342  }
343 
344  /* Get a new OID for the new label */
345  if (IsBinaryUpgrade)
346  {
348  ereport(ERROR,
349  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
350  errmsg("pg_enum OID value not set when in binary upgrade mode")));
351 
352  /*
353  * Use binary-upgrade override for pg_enum.oid, if supplied. During
354  * binary upgrade, all pg_enum.oid's are set this way so they are
355  * guaranteed to be consistent.
356  */
357  if (neighbor != NULL)
358  ereport(ERROR,
359  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
360  errmsg("ALTER TYPE ADD BEFORE/AFTER is incompatible with binary upgrade")));
361 
364  }
365  else
366  {
367  /*
368  * Normal case: we need to allocate a new Oid for the value.
369  *
370  * We want to give the new element an even-numbered Oid if it's safe,
371  * which is to say it compares correctly to all pre-existing even
372  * numbered Oids in the enum. Otherwise, we must give it an odd Oid.
373  */
374  for (;;)
375  {
376  bool sorts_ok;
377 
378  /* Get a new OID (different from all existing pg_enum tuples) */
379  newOid = GetNewOid(pg_enum);
380 
381  /*
382  * Detect whether it sorts correctly relative to existing
383  * even-numbered labels of the enum. We can ignore existing
384  * labels with odd Oids, since a comparison involving one of those
385  * will not take the fast path anyway.
386  */
387  sorts_ok = true;
388  for (i = 0; i < nelems; i++)
389  {
390  HeapTuple exists_tup = existing[i];
391  Form_pg_enum exists_en = (Form_pg_enum) GETSTRUCT(exists_tup);
392  Oid exists_oid = HeapTupleGetOid(exists_tup);
393 
394  if (exists_oid & 1)
395  continue; /* ignore odd Oids */
396 
397  if (exists_en->enumsortorder < newelemorder)
398  {
399  /* should sort before */
400  if (exists_oid >= newOid)
401  {
402  sorts_ok = false;
403  break;
404  }
405  }
406  else
407  {
408  /* should sort after */
409  if (exists_oid <= newOid)
410  {
411  sorts_ok = false;
412  break;
413  }
414  }
415  }
416 
417  if (sorts_ok)
418  {
419  /* If it's even and sorts OK, we're done. */
420  if ((newOid & 1) == 0)
421  break;
422 
423  /*
424  * If it's odd, and sorts OK, loop back to get another OID and
425  * try again. Probably, the next available even OID will sort
426  * correctly too, so it's worth trying.
427  */
428  }
429  else
430  {
431  /*
432  * If it's odd, and does not sort correctly, we're done.
433  * (Probably, the next available even OID would sort
434  * incorrectly too, so no point in trying again.)
435  */
436  if (newOid & 1)
437  break;
438 
439  /*
440  * If it's even, and does not sort correctly, loop back to get
441  * another OID and try again. (We *must* reject this case.)
442  */
443  }
444  }
445  }
446 
447  /* Done with info about existing members */
448  pfree(existing);
449  ReleaseCatCacheList(list);
450 
451  /* Create the new pg_enum entry */
452  memset(nulls, false, sizeof(nulls));
453  values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
454  values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(newelemorder);
455  namestrcpy(&enumlabel, newVal);
456  values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
457  enum_tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls);
458  HeapTupleSetOid(enum_tup, newOid);
459  CatalogTupleInsert(pg_enum, enum_tup);
460  heap_freetuple(enum_tup);
461 
462  heap_close(pg_enum, RowExclusiveLock);
463 }
464 
465 
466 /*
467  * RenameEnumLabel
468  * Rename a label in an enum set.
469  */
470 void
471 RenameEnumLabel(Oid enumTypeOid,
472  const char *oldVal,
473  const char *newVal)
474 {
475  Relation pg_enum;
476  HeapTuple enum_tup;
477  Form_pg_enum en;
478  CatCList *list;
479  int nelems;
480  HeapTuple old_tup;
481  bool found_new;
482  int i;
483 
484  /* check length of new label is ok */
485  if (strlen(newVal) > (NAMEDATALEN - 1))
486  ereport(ERROR,
487  (errcode(ERRCODE_INVALID_NAME),
488  errmsg("invalid enum label \"%s\"", newVal),
489  errdetail("Labels must be %d characters or less.",
490  NAMEDATALEN - 1)));
491 
492  /*
493  * Acquire a lock on the enum type, which we won't release until commit.
494  * This ensures that two backends aren't concurrently modifying the same
495  * enum type. Since we are not changing the type's sort order, this is
496  * probably not really necessary, but there seems no reason not to take
497  * the lock to be sure.
498  */
500 
502 
503  /* Get the list of existing members of the enum */
505  ObjectIdGetDatum(enumTypeOid));
506  nelems = list->n_members;
507 
508  /*
509  * Locate the element to rename and check if the new label is already in
510  * use. (The unique index on pg_enum would catch that anyway, but we
511  * prefer a friendlier error message.)
512  */
513  old_tup = NULL;
514  found_new = false;
515  for (i = 0; i < nelems; i++)
516  {
517  enum_tup = &(list->members[i]->tuple);
518  en = (Form_pg_enum) GETSTRUCT(enum_tup);
519  if (strcmp(NameStr(en->enumlabel), oldVal) == 0)
520  old_tup = enum_tup;
521  if (strcmp(NameStr(en->enumlabel), newVal) == 0)
522  found_new = true;
523  }
524  if (!old_tup)
525  ereport(ERROR,
526  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
527  errmsg("\"%s\" is not an existing enum label",
528  oldVal)));
529  if (found_new)
530  ereport(ERROR,
532  errmsg("enum label \"%s\" already exists",
533  newVal)));
534 
535  /* OK, make a writable copy of old tuple */
536  enum_tup = heap_copytuple(old_tup);
537  en = (Form_pg_enum) GETSTRUCT(enum_tup);
538 
539  ReleaseCatCacheList(list);
540 
541  /* Update the pg_enum entry */
542  namestrcpy(&en->enumlabel, newVal);
543  CatalogTupleUpdate(pg_enum, &enum_tup->t_self, enum_tup);
544  heap_freetuple(enum_tup);
545 
546  heap_close(pg_enum, RowExclusiveLock);
547 }
548 
549 
550 /*
551  * RenumberEnumType
552  * Renumber existing enum elements to have sort positions 1..n.
553  *
554  * We avoid doing this unless absolutely necessary; in most installations
555  * it will never happen. The reason is that updating existing pg_enum
556  * entries creates hazards for other backends that are concurrently reading
557  * pg_enum. Although system catalog scans now use MVCC semantics, the
558  * syscache machinery might read different pg_enum entries under different
559  * snapshots, so some other backend might get confused about the proper
560  * ordering if a concurrent renumbering occurs.
561  *
562  * We therefore make the following choices:
563  *
564  * 1. Any code that is interested in the enumsortorder values MUST read
565  * all the relevant pg_enum entries with a single MVCC snapshot, or else
566  * acquire lock on the enum type to prevent concurrent execution of
567  * AddEnumLabel().
568  *
569  * 2. Code that is not examining enumsortorder can use a syscache
570  * (for example, enum_in and enum_out do so).
571  */
572 static void
573 RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems)
574 {
575  int i;
576 
577  /*
578  * We should only need to increase existing elements' enumsortorders,
579  * never decrease them. Therefore, work from the end backwards, to avoid
580  * unwanted uniqueness violations.
581  */
582  for (i = nelems - 1; i >= 0; i--)
583  {
584  HeapTuple newtup;
585  Form_pg_enum en;
586  float4 newsortorder;
587 
588  newtup = heap_copytuple(existing[i]);
589  en = (Form_pg_enum) GETSTRUCT(newtup);
590 
591  newsortorder = i + 1;
592  if (en->enumsortorder != newsortorder)
593  {
594  en->enumsortorder = newsortorder;
595 
596  CatalogTupleUpdate(pg_enum, &newtup->t_self, newtup);
597  }
598 
599  heap_freetuple(newtup);
600  }
601 
602  /* Make the updates visible */
604 }
605 
606 
607 /* qsort comparison function for tuples by sort order */
608 static int
609 sort_order_cmp(const void *p1, const void *p2)
610 {
611  HeapTuple v1 = *((const HeapTuple *) p1);
612  HeapTuple v2 = *((const HeapTuple *) p2);
613  Form_pg_enum en1 = (Form_pg_enum) GETSTRUCT(v1);
614  Form_pg_enum en2 = (Form_pg_enum) GETSTRUCT(v2);
615 
616  if (en1->enumsortorder < en2->enumsortorder)
617  return -1;
618  else if (en1->enumsortorder > en2->enumsortorder)
619  return 1;
620  else
621  return 0;
622 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
static int sort_order_cmp(const void *p1, const void *p2)
Definition: pg_enum.c:609
#define NameGetDatum(X)
Definition: postgres.h:601
int n_members
Definition: catcache.h:154
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationGetDescr(relation)
Definition: rel.h:429
#define ExclusiveLock
Definition: lockdefs.h:44
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
void EnumValuesCreate(Oid enumTypeOid, List *vals)
Definition: pg_enum.c:49
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define heap_close(r, l)
Definition: heapam.h:97
#define Anum_pg_enum_enumlabel
Definition: pg_enum.h:55
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
#define EnumTypIdLabelIndexId
Definition: indexing.h:157
#define TypeRelationId
Definition: pg_type.h:34
int namestrcpy(Name name, const char *str)
Definition: name.c:217
#define OidIsValid(objectId)
Definition: c.h:538
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
bool IsBinaryUpgrade
Definition: globals.c:101
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1665
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:155
#define NAMEDATALEN
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
void pfree(void *pointer)
Definition: mcxt.c:950
#define Natts_pg_enum
Definition: pg_enum.h:52
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
#define EnumRelationId
Definition: pg_enum.h:32
Datum Float4GetDatum(float4 X)
Definition: fmgr.c:1803
ItemPointerData t_self
Definition: htup.h:65
void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists)
Definition: pg_enum.c:179
Definition: c.h:493
Oid binary_upgrade_next_pg_enum_oid
Definition: pg_enum.c:36
#define RowExclusiveLock
Definition: lockdefs.h:38
void EnumValuesDelete(Oid enumTypeOid)
Definition: pg_enum.c:144
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define CStringGetDatum(X)
Definition: postgres.h:584
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:830
FormData_pg_enum * Form_pg_enum
Definition: pg_enum.h:46
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:197
#define ereport(elevel, rest)
Definition: elog.h:122
void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal)
Definition: pg_enum.c:471
float float4
Definition: c.h:380
uintptr_t Datum
Definition: postgres.h:372
void CommandCounterIncrement(void)
Definition: xact.c:922
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Oid GetNewOid(Relation relation)
Definition: catalog.c:288
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems)
Definition: pg_enum.c:573
#define InvalidOid
Definition: postgres_ext.h:36
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
int oid_cmp(const void *p1, const void *p2)
Definition: oid.c:336
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
static int list_length(const List *l)
Definition: pg_list.h:89
static Datum values[MAXATTR]
Definition: bootstrap.c:163
#define Anum_pg_enum_enumtypid
Definition: pg_enum.h:53
tuple list
Definition: sort-test.py:11
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define Anum_pg_enum_enumsortorder
Definition: pg_enum.h:54
int i
#define NameStr(name)
Definition: c.h:499
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
HeapTupleData tuple
Definition: catcache.h:116
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
#define qsort(a, b, c, d)
Definition: port.h:440
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define SearchSysCache2(cacheId, key1, key2)
Definition: syscache.h:154