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