PostgreSQL Source Code  git master
pg_inherits.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_inherits.c
4  * routines to support manipulation of the pg_inherits relation
5  *
6  * Note: currently, this module mostly contains inquiry functions; actual
7  * creation and deletion of pg_inherits entries is mostly done in tablecmds.c.
8  * Perhaps someday that code should be moved here, but it'd have to be
9  * disentangled from other stuff such as pg_depend updates.
10  *
11  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
12  * Portions Copyright (c) 1994, Regents of the University of California
13  *
14  *
15  * IDENTIFICATION
16  * src/backend/catalog/pg_inherits.c
17  *
18  *-------------------------------------------------------------------------
19  */
20 #include "postgres.h"
21 
22 #include "access/genam.h"
23 #include "access/htup_details.h"
24 #include "access/table.h"
25 #include "catalog/indexing.h"
26 #include "catalog/pg_inherits.h"
27 #include "parser/parse_type.h"
28 #include "storage/lmgr.h"
29 #include "utils/builtins.h"
30 #include "utils/fmgroids.h"
31 #include "utils/memutils.h"
32 #include "utils/snapmgr.h"
33 #include "utils/syscache.h"
34 
35 /*
36  * Entry of a hash table used in find_all_inheritors. See below.
37  */
38 typedef struct SeenRelsEntry
39 {
40  Oid rel_id; /* relation oid */
41  int list_index; /* its position in output list(s) */
43 
44 /*
45  * find_inheritance_children
46  *
47  * Returns a list containing the OIDs of all relations which
48  * inherit *directly* from the relation with OID 'parentrelId'.
49  *
50  * The specified lock type is acquired on each child relation (but not on the
51  * given rel; caller should already have locked it). If lockmode is NoLock
52  * then no locks are acquired, but caller must beware of race conditions
53  * against possible DROPs of child relations.
54  *
55  * Partitions marked as being detached are omitted; see
56  * find_inheritance_children_extended for details.
57  */
58 List *
59 find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
60 {
61  return find_inheritance_children_extended(parentrelId, true, lockmode,
62  NULL, NULL);
63 }
64 
65 /*
66  * find_inheritance_children_extended
67  *
68  * As find_inheritance_children, with more options regarding detached
69  * partitions.
70  *
71  * If a partition's pg_inherits row is marked "detach pending",
72  * *detached_exist (if not null) is set true.
73  *
74  * If omit_detached is true and there is an active snapshot (not the same as
75  * the catalog snapshot used to scan pg_inherits!) and a pg_inherits tuple
76  * marked "detach pending" is visible to that snapshot, then that partition is
77  * omitted from the output list. This makes partitions invisible depending on
78  * whether the transaction that marked those partitions as detached appears
79  * committed to the active snapshot. In addition, *detached_xmin (if not null)
80  * is set to the xmin of the row of the detached partition.
81  */
82 List *
83 find_inheritance_children_extended(Oid parentrelId, bool omit_detached,
84  LOCKMODE lockmode, bool *detached_exist,
85  TransactionId *detached_xmin)
86 {
87  List *list = NIL;
88  Relation relation;
89  SysScanDesc scan;
90  ScanKeyData key[1];
91  HeapTuple inheritsTuple;
92  Oid inhrelid;
93  Oid *oidarr;
94  int maxoids,
95  numoids,
96  i;
97 
98  /*
99  * Can skip the scan if pg_class shows the relation has never had a
100  * subclass.
101  */
102  if (!has_subclass(parentrelId))
103  return NIL;
104 
105  /*
106  * Scan pg_inherits and build a working array of subclass OIDs.
107  */
108  maxoids = 32;
109  oidarr = (Oid *) palloc(maxoids * sizeof(Oid));
110  numoids = 0;
111 
112  relation = table_open(InheritsRelationId, AccessShareLock);
113 
114  ScanKeyInit(&key[0],
115  Anum_pg_inherits_inhparent,
116  BTEqualStrategyNumber, F_OIDEQ,
117  ObjectIdGetDatum(parentrelId));
118 
119  scan = systable_beginscan(relation, InheritsParentIndexId, true,
120  NULL, 1, key);
121 
122  while ((inheritsTuple = systable_getnext(scan)) != NULL)
123  {
124  /*
125  * Cope with partitions concurrently being detached. When we see a
126  * partition marked "detach pending", we omit it from the returned set
127  * of visible partitions if caller requested that and the tuple's xmin
128  * does not appear in progress to the active snapshot. (If there's no
129  * active snapshot set, that means we're not running a user query, so
130  * it's OK to always include detached partitions in that case; if the
131  * xmin is still running to the active snapshot, then the partition
132  * has not been detached yet and so we include it.)
133  *
134  * The reason for this hack is that we want to avoid seeing the
135  * partition as alive in RI queries during REPEATABLE READ or
136  * SERIALIZABLE transactions: such queries use a different snapshot
137  * than the one used by regular (user) queries.
138  */
139  if (((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhdetachpending)
140  {
141  if (detached_exist)
142  *detached_exist = true;
143 
144  if (omit_detached && ActiveSnapshotSet())
145  {
146  TransactionId xmin;
147  Snapshot snap;
148 
149  xmin = HeapTupleHeaderGetXmin(inheritsTuple->t_data);
150  snap = GetActiveSnapshot();
151 
152  if (!XidInMVCCSnapshot(xmin, snap))
153  {
154  if (detached_xmin)
155  {
156  /*
157  * Two detached partitions should not occur (see
158  * checks in MarkInheritDetached), but if they do,
159  * track the newer of the two. Make sure to warn the
160  * user, so that they can clean up. Since this is
161  * just a cross-check against potentially corrupt
162  * catalogs, we don't make it a full-fledged error
163  * message.
164  */
165  if (*detached_xmin != InvalidTransactionId)
166  {
167  elog(WARNING, "more than one partition pending detach found for table with OID %u",
168  parentrelId);
169  if (TransactionIdFollows(xmin, *detached_xmin))
170  *detached_xmin = xmin;
171  }
172  else
173  *detached_xmin = xmin;
174  }
175 
176  /* Don't add the partition to the output list */
177  continue;
178  }
179  }
180  }
181 
182  inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
183  if (numoids >= maxoids)
184  {
185  maxoids *= 2;
186  oidarr = (Oid *) repalloc(oidarr, maxoids * sizeof(Oid));
187  }
188  oidarr[numoids++] = inhrelid;
189  }
190 
191  systable_endscan(scan);
192 
193  table_close(relation, AccessShareLock);
194 
195  /*
196  * If we found more than one child, sort them by OID. This ensures
197  * reasonably consistent behavior regardless of the vagaries of an
198  * indexscan. This is important since we need to be sure all backends
199  * lock children in the same order to avoid needless deadlocks.
200  */
201  if (numoids > 1)
202  qsort(oidarr, numoids, sizeof(Oid), oid_cmp);
203 
204  /*
205  * Acquire locks and build the result list.
206  */
207  for (i = 0; i < numoids; i++)
208  {
209  inhrelid = oidarr[i];
210 
211  if (lockmode != NoLock)
212  {
213  /* Get the lock to synchronize against concurrent drop */
214  LockRelationOid(inhrelid, lockmode);
215 
216  /*
217  * Now that we have the lock, double-check to see if the relation
218  * really exists or not. If not, assume it was dropped while we
219  * waited to acquire lock, and ignore it.
220  */
222  {
223  /* Release useless lock */
224  UnlockRelationOid(inhrelid, lockmode);
225  /* And ignore this relation */
226  continue;
227  }
228  }
229 
230  list = lappend_oid(list, inhrelid);
231  }
232 
233  pfree(oidarr);
234 
235  return list;
236 }
237 
238 
239 /*
240  * find_all_inheritors -
241  * Returns a list of relation OIDs including the given rel plus
242  * all relations that inherit from it, directly or indirectly.
243  * Optionally, it also returns the number of parents found for
244  * each such relation within the inheritance tree rooted at the
245  * given rel.
246  *
247  * The specified lock type is acquired on all child relations (but not on the
248  * given rel; caller should already have locked it). If lockmode is NoLock
249  * then no locks are acquired, but caller must beware of race conditions
250  * against possible DROPs of child relations.
251  *
252  * NB - No current callers of this routine are interested in children being
253  * concurrently detached, so there's no provision to include them.
254  */
255 List *
256 find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
257 {
258  /* hash table for O(1) rel_oid -> rel_numparents cell lookup */
259  HTAB *seen_rels;
260  HASHCTL ctl;
261  List *rels_list,
262  *rel_numparents;
263  ListCell *l;
264 
265  ctl.keysize = sizeof(Oid);
266  ctl.entrysize = sizeof(SeenRelsEntry);
268 
269  seen_rels = hash_create("find_all_inheritors temporary table",
270  32, /* start small and extend */
271  &ctl,
273 
274  /*
275  * We build a list starting with the given rel and adding all direct and
276  * indirect children. We can use a single list as both the record of
277  * already-found rels and the agenda of rels yet to be scanned for more
278  * children. This is a bit tricky but works because the foreach() macro
279  * doesn't fetch the next list element until the bottom of the loop. Note
280  * that we can't keep pointers into the output lists; but an index is
281  * sufficient.
282  */
283  rels_list = list_make1_oid(parentrelId);
284  rel_numparents = list_make1_int(0);
285 
286  foreach(l, rels_list)
287  {
288  Oid currentrel = lfirst_oid(l);
289  List *currentchildren;
290  ListCell *lc;
291 
292  /* Get the direct children of this rel */
293  currentchildren = find_inheritance_children(currentrel, lockmode);
294 
295  /*
296  * Add to the queue only those children not already seen. This avoids
297  * making duplicate entries in case of multiple inheritance paths from
298  * the same parent. (It'll also keep us from getting into an infinite
299  * loop, though theoretically there can't be any cycles in the
300  * inheritance graph anyway.)
301  */
302  foreach(lc, currentchildren)
303  {
304  Oid child_oid = lfirst_oid(lc);
305  bool found;
306  SeenRelsEntry *hash_entry;
307 
308  hash_entry = hash_search(seen_rels, &child_oid, HASH_ENTER, &found);
309  if (found)
310  {
311  /* if the rel is already there, bump number-of-parents counter */
312  ListCell *numparents_cell;
313 
314  numparents_cell = list_nth_cell(rel_numparents,
315  hash_entry->list_index);
316  lfirst_int(numparents_cell)++;
317  }
318  else
319  {
320  /* if it's not there, add it. expect 1 parent, initially. */
321  hash_entry->list_index = list_length(rels_list);
322  rels_list = lappend_oid(rels_list, child_oid);
323  rel_numparents = lappend_int(rel_numparents, 1);
324  }
325  }
326  }
327 
328  if (numparents)
329  *numparents = rel_numparents;
330  else
331  list_free(rel_numparents);
332 
333  hash_destroy(seen_rels);
334 
335  return rels_list;
336 }
337 
338 
339 /*
340  * has_subclass - does this relation have any children?
341  *
342  * In the current implementation, has_subclass returns whether a
343  * particular class *might* have a subclass. It will not return the
344  * correct result if a class had a subclass which was later dropped.
345  * This is because relhassubclass in pg_class is not updated immediately
346  * when a subclass is dropped, primarily because of concurrency concerns.
347  *
348  * Currently has_subclass is only used as an efficiency hack to skip
349  * unnecessary inheritance searches, so this is OK. Note that ANALYZE
350  * on a childless table will clean up the obsolete relhassubclass flag.
351  *
352  * Although this doesn't actually touch pg_inherits, it seems reasonable
353  * to keep it here since it's normally used with the other routines here.
354  */
355 bool
356 has_subclass(Oid relationId)
357 {
358  HeapTuple tuple;
359  bool result;
360 
361  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationId));
362  if (!HeapTupleIsValid(tuple))
363  elog(ERROR, "cache lookup failed for relation %u", relationId);
364 
365  result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
366  ReleaseSysCache(tuple);
367  return result;
368 }
369 
370 /*
371  * has_superclass - does this relation inherit from another?
372  *
373  * Unlike has_subclass, this can be relied on to give an accurate answer.
374  * However, the caller must hold a lock on the given relation so that it
375  * can't be concurrently added to or removed from an inheritance hierarchy.
376  */
377 bool
378 has_superclass(Oid relationId)
379 {
380  Relation catalog;
381  SysScanDesc scan;
382  ScanKeyData skey;
383  bool result;
384 
385  catalog = table_open(InheritsRelationId, AccessShareLock);
386  ScanKeyInit(&skey, Anum_pg_inherits_inhrelid, BTEqualStrategyNumber,
387  F_OIDEQ, ObjectIdGetDatum(relationId));
388  scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
389  NULL, 1, &skey);
390  result = HeapTupleIsValid(systable_getnext(scan));
391  systable_endscan(scan);
392  table_close(catalog, AccessShareLock);
393 
394  return result;
395 }
396 
397 /*
398  * Given two type OIDs, determine whether the first is a complex type
399  * (class type) that inherits from the second.
400  *
401  * This essentially asks whether the first type is guaranteed to be coercible
402  * to the second. Therefore, we allow the first type to be a domain over a
403  * complex type that inherits from the second; that creates no difficulties.
404  * But the second type cannot be a domain.
405  */
406 bool
407 typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
408 {
409  bool result = false;
410  Oid subclassRelid;
411  Oid superclassRelid;
412  Relation inhrel;
413  List *visited,
414  *queue;
415  ListCell *queue_item;
416 
417  /* We need to work with the associated relation OIDs */
418  subclassRelid = typeOrDomainTypeRelid(subclassTypeId);
419  if (subclassRelid == InvalidOid)
420  return false; /* not a complex type or domain over one */
421  superclassRelid = typeidTypeRelid(superclassTypeId);
422  if (superclassRelid == InvalidOid)
423  return false; /* not a complex type */
424 
425  /* No point in searching if the superclass has no subclasses */
426  if (!has_subclass(superclassRelid))
427  return false;
428 
429  /*
430  * Begin the search at the relation itself, so add its relid to the queue.
431  */
432  queue = list_make1_oid(subclassRelid);
433  visited = NIL;
434 
435  inhrel = table_open(InheritsRelationId, AccessShareLock);
436 
437  /*
438  * Use queue to do a breadth-first traversal of the inheritance graph from
439  * the relid supplied up to the root. Notice that we append to the queue
440  * inside the loop --- this is okay because the foreach() macro doesn't
441  * advance queue_item until the next loop iteration begins.
442  */
443  foreach(queue_item, queue)
444  {
445  Oid this_relid = lfirst_oid(queue_item);
446  ScanKeyData skey;
447  SysScanDesc inhscan;
448  HeapTuple inhtup;
449 
450  /*
451  * If we've seen this relid already, skip it. This avoids extra work
452  * in multiple-inheritance scenarios, and also protects us from an
453  * infinite loop in case there is a cycle in pg_inherits (though
454  * theoretically that shouldn't happen).
455  */
456  if (list_member_oid(visited, this_relid))
457  continue;
458 
459  /*
460  * Okay, this is a not-yet-seen relid. Add it to the list of
461  * already-visited OIDs, then find all the types this relid inherits
462  * from and add them to the queue.
463  */
464  visited = lappend_oid(visited, this_relid);
465 
466  ScanKeyInit(&skey,
467  Anum_pg_inherits_inhrelid,
468  BTEqualStrategyNumber, F_OIDEQ,
469  ObjectIdGetDatum(this_relid));
470 
471  inhscan = systable_beginscan(inhrel, InheritsRelidSeqnoIndexId, true,
472  NULL, 1, &skey);
473 
474  while ((inhtup = systable_getnext(inhscan)) != NULL)
475  {
477  Oid inhparent = inh->inhparent;
478 
479  /* If this is the target superclass, we're done */
480  if (inhparent == superclassRelid)
481  {
482  result = true;
483  break;
484  }
485 
486  /* Else add to queue */
487  queue = lappend_oid(queue, inhparent);
488  }
489 
490  systable_endscan(inhscan);
491 
492  if (result)
493  break;
494  }
495 
496  /* clean up ... */
497  table_close(inhrel, AccessShareLock);
498 
499  list_free(visited);
500  list_free(queue);
501 
502  return result;
503 }
504 
505 /*
506  * Create a single pg_inherits row with the given data
507  */
508 void
509 StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
510 {
511  Datum values[Natts_pg_inherits];
512  bool nulls[Natts_pg_inherits];
513  HeapTuple tuple;
514  Relation inhRelation;
515 
516  inhRelation = table_open(InheritsRelationId, RowExclusiveLock);
517 
518  /*
519  * Make the pg_inherits entry
520  */
521  values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(relationId);
522  values[Anum_pg_inherits_inhparent - 1] = ObjectIdGetDatum(parentOid);
523  values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(seqNumber);
524  values[Anum_pg_inherits_inhdetachpending - 1] = BoolGetDatum(false);
525 
526  memset(nulls, 0, sizeof(nulls));
527 
528  tuple = heap_form_tuple(RelationGetDescr(inhRelation), values, nulls);
529 
530  CatalogTupleInsert(inhRelation, tuple);
531 
532  heap_freetuple(tuple);
533 
534  table_close(inhRelation, RowExclusiveLock);
535 }
536 
537 /*
538  * DeleteInheritsTuple
539  *
540  * Delete pg_inherits tuples with the given inhrelid. inhparent may be given
541  * as InvalidOid, in which case all tuples matching inhrelid are deleted;
542  * otherwise only delete tuples with the specified inhparent.
543  *
544  * expect_detach_pending is the expected state of the inhdetachpending flag.
545  * If the catalog row does not match that state, an error is raised.
546  *
547  * childname is the partition name, if a table; pass NULL for regular
548  * inheritance or when working with other relation kinds.
549  *
550  * Returns whether at least one row was deleted.
551  */
552 bool
553 DeleteInheritsTuple(Oid inhrelid, Oid inhparent, bool expect_detach_pending,
554  const char *childname)
555 {
556  bool found = false;
557  Relation catalogRelation;
559  SysScanDesc scan;
560  HeapTuple inheritsTuple;
561 
562  /*
563  * Find pg_inherits entries by inhrelid.
564  */
565  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
566  ScanKeyInit(&key,
567  Anum_pg_inherits_inhrelid,
568  BTEqualStrategyNumber, F_OIDEQ,
569  ObjectIdGetDatum(inhrelid));
570  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
571  true, NULL, 1, &key);
572 
573  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
574  {
575  Oid parent;
576 
577  /* Compare inhparent if it was given, and do the actual deletion. */
578  parent = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent;
579  if (!OidIsValid(inhparent) || parent == inhparent)
580  {
581  bool detach_pending;
582 
583  detach_pending =
584  ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhdetachpending;
585 
586  /*
587  * Raise error depending on state. This should only happen for
588  * partitions, but we have no way to cross-check.
589  */
590  if (detach_pending && !expect_detach_pending)
591  ereport(ERROR,
592  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
593  errmsg("cannot detach partition \"%s\"",
594  childname ? childname : "unknown relation"),
595  errdetail("The partition is being detached concurrently or has an unfinished detach."),
596  errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation.")));
597  if (!detach_pending && expect_detach_pending)
598  ereport(ERROR,
599  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
600  errmsg("cannot complete detaching partition \"%s\"",
601  childname ? childname : "unknown relation"),
602  errdetail("There's no pending concurrent detach.")));
603 
604  CatalogTupleDelete(catalogRelation, &inheritsTuple->t_self);
605  found = true;
606  }
607  }
608 
609  /* Done */
610  systable_endscan(scan);
611  table_close(catalogRelation, RowExclusiveLock);
612 
613  return found;
614 }
615 
616 /*
617  * Return whether the pg_inherits tuple for a partition has the "detach
618  * pending" flag set.
619  */
620 bool
622 {
623  Relation catalogRelation;
625  SysScanDesc scan;
626  HeapTuple inheritsTuple;
627 
628  /* We don't have a good way to verify it is in fact a partition */
629 
630  /*
631  * Find the pg_inherits entry by inhrelid. (There should only be one.)
632  */
633  catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
634  ScanKeyInit(&key,
635  Anum_pg_inherits_inhrelid,
636  BTEqualStrategyNumber, F_OIDEQ,
637  ObjectIdGetDatum(partoid));
638  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId,
639  true, NULL, 1, &key);
640 
641  while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
642  {
643  bool detached;
644 
645  detached =
646  ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhdetachpending;
647 
648  /* Done */
649  systable_endscan(scan);
650  table_close(catalogRelation, RowExclusiveLock);
651 
652  return detached;
653  }
654 
655  elog(ERROR, "relation %u is not a partition", partoid);
656  return false; /* keep compiler quiet */
657 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
signed int int32
Definition: c.h:483
uint32 TransactionId
Definition: c.h:641
#define OidIsValid(objectId)
Definition: c.h:764
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:863
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
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
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 HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:309
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
int i
Definition: isn.c:73
List * lappend_int(List *list, int datum)
Definition: list.c:356
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
void list_free(List *list)
Definition: list.c:1545
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:721
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:228
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
void pfree(void *pointer)
Definition: mcxt.c:1456
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1476
void * palloc(Size size)
Definition: mcxt.c:1226
int oid_cmp(const void *p1, const void *p2)
Definition: oid.c:257
Oid typeOrDomainTypeRelid(Oid type_id)
Definition: parse_type.c:689
Oid typeidTypeRelid(Oid type_id)
Definition: parse_type.c:668
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
List * find_inheritance_children_extended(Oid parentrelId, bool omit_detached, LOCKMODE lockmode, bool *detached_exist, TransactionId *detached_xmin)
Definition: pg_inherits.c:83
bool has_subclass(Oid relationId)
Definition: pg_inherits.c:356
bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent, bool expect_detach_pending, const char *childname)
Definition: pg_inherits.c:553
struct SeenRelsEntry SeenRelsEntry
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
Definition: pg_inherits.c:509
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:59
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:378
bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
Definition: pg_inherits.c:407
bool PartitionHasPendingDetach(Oid partoid)
Definition: pg_inherits.c:621
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:45
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define list_make1_oid(x1)
Definition: pg_list.h:242
static ListCell * list_nth_cell(const List *list, int n)
Definition: pg_list.h:277
#define list_make1_int(x1)
Definition: pg_list.h:227
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define qsort(a, b, c, d)
Definition: port.h:445
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:530
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
Definition: snapmgr.c:1862
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:789
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:777
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:220
ItemPointerData t_self
Definition: htup.h:65
HeapTupleHeader t_data
Definition: htup.h:68
Definition: pg_list.h:54
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
@ RELOID
Definition: syscache.h:89
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:191
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:314
#define InvalidTransactionId
Definition: transam.h:31