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-2025, 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 */
37typedef 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 */
57List *
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 */
81List *
82find_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;
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 */
254List *
255find_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 */
354bool
355has_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 */
376bool
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);
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 */
405bool
406typeInheritsFrom(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 ... */
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 */
507void
508StoreSingleInheritance(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 */
551bool
552DeleteInheritsTuple(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);
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)
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)
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 */
619bool
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);
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:151
int32_t int32
Definition: c.h:484
uint32 TransactionId
Definition: c.h:609
#define OidIsValid(objectId)
Definition: c.h:732
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
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:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
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
static TransactionId HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
Definition: htup_details.h:324
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
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:72
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:226
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:107
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 * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
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_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
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_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:58
void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
Definition: pg_inherits.c:508
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_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:475
uintptr_t Datum
Definition: postgres.h:69
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
tree ctl
Definition: radixtree.h:1838
#define RelationGetDescr(relation)
Definition: rel.h:538
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:1800
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:740
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:728
#define BTEqualStrategyNumber
Definition: stratnum.h:31
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:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:100
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