PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pg_inherits.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "catalog/indexing.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_inherits_fn.h"
#include "parser/parse_type.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
#include "utils/memutils.h"
Include dependency graph for pg_inherits.c:

Go to the source code of this file.

Data Structures

struct  SeenRelsEntry
 

Typedefs

typedef struct SeenRelsEntry SeenRelsEntry
 

Functions

Listfind_inheritance_children (Oid parentrelId, LOCKMODE lockmode)
 
Listfind_all_inheritors (Oid parentrelId, LOCKMODE lockmode, List **numparents)
 
bool has_subclass (Oid relationId)
 
bool typeInheritsFrom (Oid subclassTypeId, Oid superclassTypeId)
 

Typedef Documentation

Function Documentation

List* find_all_inheritors ( Oid  parentrelId,
LOCKMODE  lockmode,
List **  numparents 
)

Definition at line 167 of file pg_inherits.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), CurrentMemoryContext, HASHCTL::entrysize, find_inheritance_children(), HASH_BLOBS, HASH_CONTEXT, hash_create(), hash_destroy(), HASH_ELEM, HASH_ENTER, hash_search(), HASHCTL::hcxt, HASHCTL::keysize, lappend_int(), lappend_oid(), lfirst_int, lfirst_oid, list_free(), list_make1_int, list_make1_oid, SeenRelsEntry::numparents_cell, and List::tail.

Referenced by acquire_inherited_sample_rows(), ATExecAddInherit(), ATExecAttachPartition(), ATExecValidateConstraint(), ATPrepAlterColumnType(), ATSimpleRecursion(), ExecuteTruncate(), expand_inherited_rtentry(), get_rel_oids(), OpenTableList(), rename_constraint_internal(), renameatt_internal(), and sepgsql_dml_privileges().

168 {
169  /* hash table for O(1) rel_oid -> rel_numparents cell lookup */
170  HTAB *seen_rels;
171  HASHCTL ctl;
172  MemoryContext new_ctx;
173  List *rels_list,
174  *rel_numparents;
175  ListCell *l;
176 
177  /*
178  * We need a separate memory context for a hash table. This is because
179  * hash table is used only in this procedure. To free a memory we need to
180  * call hash_destroy which is just a wrapper around MemoryContextDelete.
181  */
183  "FindAllInheritorsSeenRelsContext",
185 
186  memset(&ctl, 0, sizeof(ctl));
187  ctl.keysize = sizeof(Oid);
188  ctl.entrysize = sizeof(SeenRelsEntry);
189  ctl.hcxt = new_ctx;
190 
191  seen_rels = hash_create(
192  "find_all_inheritors temporary table",
193  32, /* start small and extend */
194  &ctl, HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
195 
196  /*
197  * We build a list starting with the given rel and adding all direct and
198  * indirect children. We can use a single list as both the record of
199  * already-found rels and the agenda of rels yet to be scanned for more
200  * children. This is a bit tricky but works because the foreach() macro
201  * doesn't fetch the next list element until the bottom of the loop.
202  */
203  rels_list = list_make1_oid(parentrelId);
204  rel_numparents = list_make1_int(0);
205 
206  foreach(l, rels_list)
207  {
208  Oid currentrel = lfirst_oid(l);
209  List *currentchildren;
210  ListCell *lc;
211 
212  /* Get the direct children of this rel */
213  currentchildren = find_inheritance_children(currentrel, lockmode);
214 
215  /*
216  * Add to the queue only those children not already seen. This avoids
217  * making duplicate entries in case of multiple inheritance paths from
218  * the same parent. (It'll also keep us from getting into an infinite
219  * loop, though theoretically there can't be any cycles in the
220  * inheritance graph anyway.)
221  */
222  foreach(lc, currentchildren)
223  {
224  Oid child_oid = lfirst_oid(lc);
225  bool found;
226  SeenRelsEntry *hash_entry;
227 
228  hash_entry = hash_search(seen_rels, &child_oid, HASH_ENTER, &found);
229  if (found)
230  {
231  /* if the rel is already there, bump number-of-parents counter */
232  lfirst_int(hash_entry->numparents_cell)++;
233  }
234  else
235  {
236  /* if it's not there, add it. expect 1 parent, initially. */
237  rels_list = lappend_oid(rels_list, child_oid);
238  rel_numparents = lappend_int(rel_numparents, 1);
239  hash_entry->numparents_cell = rel_numparents->tail;
240  }
241  }
242  }
243 
244  if (numparents)
245  *numparents = rel_numparents;
246  else
247  list_free(rel_numparents);
248 
249  hash_destroy(seen_rels);
250 
251  return rels_list;
252 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:793
#define HASH_CONTEXT
Definition: hsearch.h:93
#define HASH_ELEM
Definition: hsearch.h:87
MemoryContext hcxt
Definition: hsearch.h:78
Size entrysize
Definition: hsearch.h:73
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
ListCell * numparents_cell
Definition: pg_inherits.c:42
Definition: dynahash.c:193
#define lfirst_int(lc)
Definition: pg_list.h:107
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define list_make1_int(x1)
Definition: pg_list.h:145
List * lappend_int(List *list, int datum)
Definition: list.c:146
struct SeenRelsEntry SeenRelsEntry
#define HASH_BLOBS
Definition: hsearch.h:88
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:301
#define list_make1_oid(x1)
Definition: pg_list.h:151
Size keysize
Definition: hsearch.h:72
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:57
void list_free(List *list)
Definition: list.c:1133
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108
ListCell * tail
Definition: pg_list.h:50
List* find_inheritance_children ( Oid  parentrelId,
LOCKMODE  lockmode 
)

Definition at line 57 of file pg_inherits.c.

References AccessShareLock, Anum_pg_inherits_inhparent, BTEqualStrategyNumber, GETSTRUCT, has_subclass(), heap_close, heap_open(), i, InheritsParentIndexId, InheritsRelationId, lappend_oid(), sort-test::list, LockRelationOid(), NIL, NoLock, NULL, ObjectIdGetDatum, oid_cmp(), palloc(), pfree(), qsort, RELOID, repalloc(), ScanKeyInit(), SearchSysCacheExists1, systable_beginscan(), systable_endscan(), systable_getnext(), and UnlockRelationOid().

Referenced by ATAddCheckConstraint(), ATExecAddColumn(), ATExecDropColumn(), ATExecDropConstraint(), ATPrepAlterColumnType(), find_all_inheritors(), LockTableRecurse(), RelationBuildPartitionDesc(), rename_constraint_internal(), and renameatt_internal().

58 {
59  List *list = NIL;
60  Relation relation;
61  SysScanDesc scan;
62  ScanKeyData key[1];
63  HeapTuple inheritsTuple;
64  Oid inhrelid;
65  Oid *oidarr;
66  int maxoids,
67  numoids,
68  i;
69 
70  /*
71  * Can skip the scan if pg_class shows the relation has never had a
72  * subclass.
73  */
74  if (!has_subclass(parentrelId))
75  return NIL;
76 
77  /*
78  * Scan pg_inherits and build a working array of subclass OIDs.
79  */
80  maxoids = 32;
81  oidarr = (Oid *) palloc(maxoids * sizeof(Oid));
82  numoids = 0;
83 
85 
86  ScanKeyInit(&key[0],
88  BTEqualStrategyNumber, F_OIDEQ,
89  ObjectIdGetDatum(parentrelId));
90 
91  scan = systable_beginscan(relation, InheritsParentIndexId, true,
92  NULL, 1, key);
93 
94  while ((inheritsTuple = systable_getnext(scan)) != NULL)
95  {
96  inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
97  if (numoids >= maxoids)
98  {
99  maxoids *= 2;
100  oidarr = (Oid *) repalloc(oidarr, maxoids * sizeof(Oid));
101  }
102  oidarr[numoids++] = inhrelid;
103  }
104 
105  systable_endscan(scan);
106 
107  heap_close(relation, AccessShareLock);
108 
109  /*
110  * If we found more than one child, sort them by OID. This ensures
111  * reasonably consistent behavior regardless of the vagaries of an
112  * indexscan. This is important since we need to be sure all backends
113  * lock children in the same order to avoid needless deadlocks.
114  */
115  if (numoids > 1)
116  qsort(oidarr, numoids, sizeof(Oid), oid_cmp);
117 
118  /*
119  * Acquire locks and build the result list.
120  */
121  for (i = 0; i < numoids; i++)
122  {
123  inhrelid = oidarr[i];
124 
125  if (lockmode != NoLock)
126  {
127  /* Get the lock to synchronize against concurrent drop */
128  LockRelationOid(inhrelid, lockmode);
129 
130  /*
131  * Now that we have the lock, double-check to see if the relation
132  * really exists or not. If not, assume it was dropped while we
133  * waited to acquire lock, and ignore it.
134  */
136  {
137  /* Release useless lock */
138  UnlockRelationOid(inhrelid, lockmode);
139  /* And ignore this relation */
140  continue;
141  }
142  }
143 
144  list = lappend_oid(list, inhrelid);
145  }
146 
147  pfree(oidarr);
148 
149  return list;
150 }
#define NIL
Definition: pg_list.h:69
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:170
void pfree(void *pointer)
Definition: mcxt.c:950
bool has_subclass(Oid relationId)
Definition: pg_inherits.c:272
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define NoLock
Definition: lockdefs.h:34
#define Anum_pg_inherits_inhparent
Definition: pg_inherits.h:51
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define InheritsParentIndexId
Definition: indexing.h:169
#define NULL
Definition: c.h:229
int oid_cmp(const void *p1, const void *p2)
Definition: oid.c:336
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:43
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:963
#define InheritsRelationId
Definition: pg_inherits.h:29
tuple list
Definition: sort-test.py:11
void * palloc(Size size)
Definition: mcxt.c:849
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define qsort(a, b, c, d)
Definition: port.h:440
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool has_subclass ( Oid  relationId)

Definition at line 272 of file pg_inherits.c.

References elog, ERROR, GETSTRUCT, HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RELOID, result, and SearchSysCache1.

Referenced by expand_inherited_rtentry(), find_inheritance_children(), and typeInheritsFrom().

273 {
274  HeapTuple tuple;
275  bool result;
276 
277  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationId));
278  if (!HeapTupleIsValid(tuple))
279  elog(ERROR, "cache lookup failed for relation %u", relationId);
280 
281  result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
282  ReleaseSysCache(tuple);
283  return result;
284 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
return result
Definition: formatting.c:1618
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define elog
Definition: elog.h:219
bool typeInheritsFrom ( Oid  subclassTypeId,
Oid  superclassTypeId 
)

Definition at line 292 of file pg_inherits.c.

References AccessShareLock, Anum_pg_inherits_inhrelid, BTEqualStrategyNumber, GETSTRUCT, has_subclass(), heap_close, heap_open(), InheritsRelationId, InheritsRelidSeqnoIndexId, InvalidOid, lappend_oid(), lfirst_oid, list_free(), list_make1_oid, list_member_oid(), NIL, NULL, ObjectIdGetDatum, result, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), and typeidTypeRelid().

Referenced by can_coerce_type(), and coerce_type().

293 {
294  bool result = false;
295  Oid subclassRelid;
296  Oid superclassRelid;
297  Relation inhrel;
298  List *visited,
299  *queue;
300  ListCell *queue_item;
301 
302  /* We need to work with the associated relation OIDs */
303  subclassRelid = typeidTypeRelid(subclassTypeId);
304  if (subclassRelid == InvalidOid)
305  return false; /* not a complex type */
306  superclassRelid = typeidTypeRelid(superclassTypeId);
307  if (superclassRelid == InvalidOid)
308  return false; /* not a complex type */
309 
310  /* No point in searching if the superclass has no subclasses */
311  if (!has_subclass(superclassRelid))
312  return false;
313 
314  /*
315  * Begin the search at the relation itself, so add its relid to the queue.
316  */
317  queue = list_make1_oid(subclassRelid);
318  visited = NIL;
319 
321 
322  /*
323  * Use queue to do a breadth-first traversal of the inheritance graph from
324  * the relid supplied up to the root. Notice that we append to the queue
325  * inside the loop --- this is okay because the foreach() macro doesn't
326  * advance queue_item until the next loop iteration begins.
327  */
328  foreach(queue_item, queue)
329  {
330  Oid this_relid = lfirst_oid(queue_item);
331  ScanKeyData skey;
332  SysScanDesc inhscan;
333  HeapTuple inhtup;
334 
335  /*
336  * If we've seen this relid already, skip it. This avoids extra work
337  * in multiple-inheritance scenarios, and also protects us from an
338  * infinite loop in case there is a cycle in pg_inherits (though
339  * theoretically that shouldn't happen).
340  */
341  if (list_member_oid(visited, this_relid))
342  continue;
343 
344  /*
345  * Okay, this is a not-yet-seen relid. Add it to the list of
346  * already-visited OIDs, then find all the types this relid inherits
347  * from and add them to the queue.
348  */
349  visited = lappend_oid(visited, this_relid);
350 
351  ScanKeyInit(&skey,
353  BTEqualStrategyNumber, F_OIDEQ,
354  ObjectIdGetDatum(this_relid));
355 
356  inhscan = systable_beginscan(inhrel, InheritsRelidSeqnoIndexId, true,
357  NULL, 1, &skey);
358 
359  while ((inhtup = systable_getnext(inhscan)) != NULL)
360  {
362  Oid inhparent = inh->inhparent;
363 
364  /* If this is the target superclass, we're done */
365  if (inhparent == superclassRelid)
366  {
367  result = true;
368  break;
369  }
370 
371  /* Else add to queue */
372  queue = lappend_oid(queue, inhparent);
373  }
374 
375  systable_endscan(inhscan);
376 
377  if (result)
378  break;
379  }
380 
381  /* clean up ... */
382  heap_close(inhrel, AccessShareLock);
383 
384  list_free(visited);
385  list_free(queue);
386 
387  return result;
388 }
#define NIL
Definition: pg_list.h:69
#define Anum_pg_inherits_inhrelid
Definition: pg_inherits.h:50
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define AccessShareLock
Definition: lockdefs.h:36
return result
Definition: formatting.c:1618
Oid typeidTypeRelid(Oid type_id)
Definition: parse_type.c:646
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
bool has_subclass(Oid relationId)
Definition: pg_inherits.c:272
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define list_make1_oid(x1)
Definition: pg_list.h:151
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define InvalidOid
Definition: postgres_ext.h:36
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define NULL
Definition: c.h:229
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:167
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:43
#define InheritsRelationId
Definition: pg_inherits.h:29
void list_free(List *list)
Definition: list.c:1133
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108