PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pg_inherits_fn.h File Reference
#include "nodes/pg_list.h"
#include "storage/lock.h"
Include dependency graph for pg_inherits_fn.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

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

Function Documentation

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

Definition at line 159 of file pg_inherits.c.

References find_inheritance_children(), forboth, lappend_int(), lappend_oid(), lfirst_int, lfirst_oid, list_free(), list_make1_int, and list_make1_oid.

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

160 {
161  List *rels_list,
162  *rel_numparents;
163  ListCell *l;
164 
165  /*
166  * We build a list starting with the given rel and adding all direct and
167  * indirect children. We can use a single list as both the record of
168  * already-found rels and the agenda of rels yet to be scanned for more
169  * children. This is a bit tricky but works because the foreach() macro
170  * doesn't fetch the next list element until the bottom of the loop.
171  */
172  rels_list = list_make1_oid(parentrelId);
173  rel_numparents = list_make1_int(0);
174 
175  foreach(l, rels_list)
176  {
177  Oid currentrel = lfirst_oid(l);
178  List *currentchildren;
179  ListCell *lc;
180 
181  /* Get the direct children of this rel */
182  currentchildren = find_inheritance_children(currentrel, lockmode);
183 
184  /*
185  * Add to the queue only those children not already seen. This avoids
186  * making duplicate entries in case of multiple inheritance paths from
187  * the same parent. (It'll also keep us from getting into an infinite
188  * loop, though theoretically there can't be any cycles in the
189  * inheritance graph anyway.)
190  */
191  foreach(lc, currentchildren)
192  {
193  Oid child_oid = lfirst_oid(lc);
194  bool found = false;
195  ListCell *lo;
196  ListCell *li;
197 
198  /* if the rel is already there, bump number-of-parents counter */
199  forboth(lo, rels_list, li, rel_numparents)
200  {
201  if (lfirst_oid(lo) == child_oid)
202  {
203  lfirst_int(li)++;
204  found = true;
205  break;
206  }
207  }
208 
209  /* if it's not there, add it. expect 1 parent, initially. */
210  if (!found)
211  {
212  rels_list = lappend_oid(rels_list, child_oid);
213  rel_numparents = lappend_int(rel_numparents, 1);
214  }
215  }
216  }
217 
218  if (numparents)
219  *numparents = rel_numparents;
220  else
221  list_free(rel_numparents);
222  return rels_list;
223 }
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:174
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define lfirst_int(lc)
Definition: pg_list.h:107
#define list_make1_int(x1)
Definition: pg_list.h:139
List * lappend_int(List *list, int datum)
Definition: list.c:146
#define list_make1_oid(x1)
Definition: pg_list.h:145
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:49
void list_free(List *list)
Definition: list.c:1133
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108
List* find_inheritance_children ( Oid  parentrelId,
LOCKMODE  lockmode 
)

Definition at line 49 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().

50 {
51  List *list = NIL;
52  Relation relation;
53  SysScanDesc scan;
54  ScanKeyData key[1];
55  HeapTuple inheritsTuple;
56  Oid inhrelid;
57  Oid *oidarr;
58  int maxoids,
59  numoids,
60  i;
61 
62  /*
63  * Can skip the scan if pg_class shows the relation has never had a
64  * subclass.
65  */
66  if (!has_subclass(parentrelId))
67  return NIL;
68 
69  /*
70  * Scan pg_inherits and build a working array of subclass OIDs.
71  */
72  maxoids = 32;
73  oidarr = (Oid *) palloc(maxoids * sizeof(Oid));
74  numoids = 0;
75 
77 
78  ScanKeyInit(&key[0],
80  BTEqualStrategyNumber, F_OIDEQ,
81  ObjectIdGetDatum(parentrelId));
82 
83  scan = systable_beginscan(relation, InheritsParentIndexId, true,
84  NULL, 1, key);
85 
86  while ((inheritsTuple = systable_getnext(scan)) != NULL)
87  {
88  inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
89  if (numoids >= maxoids)
90  {
91  maxoids *= 2;
92  oidarr = (Oid *) repalloc(oidarr, maxoids * sizeof(Oid));
93  }
94  oidarr[numoids++] = inhrelid;
95  }
96 
97  systable_endscan(scan);
98 
99  heap_close(relation, AccessShareLock);
100 
101  /*
102  * If we found more than one child, sort them by OID. This ensures
103  * reasonably consistent behavior regardless of the vagaries of an
104  * indexscan. This is important since we need to be sure all backends
105  * lock children in the same order to avoid needless deadlocks.
106  */
107  if (numoids > 1)
108  qsort(oidarr, numoids, sizeof(Oid), oid_cmp);
109 
110  /*
111  * Acquire locks and build the result list.
112  */
113  for (i = 0; i < numoids; i++)
114  {
115  inhrelid = oidarr[i];
116 
117  if (lockmode != NoLock)
118  {
119  /* Get the lock to synchronize against concurrent drop */
120  LockRelationOid(inhrelid, lockmode);
121 
122  /*
123  * Now that we have the lock, double-check to see if the relation
124  * really exists or not. If not, assume it was dropped while we
125  * waited to acquire lock, and ignore it.
126  */
128  {
129  /* Release useless lock */
130  UnlockRelationOid(inhrelid, lockmode);
131  /* And ignore this relation */
132  continue;
133  }
134  }
135 
136  list = lappend_oid(list, inhrelid);
137  }
138 
139  pfree(oidarr);
140 
141  return list;
142 }
#define NIL
Definition: pg_list.h:69
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#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:322
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:167
void pfree(void *pointer)
Definition: mcxt.c:992
bool has_subclass(Oid relationId)
Definition: pg_inherits.c:243
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#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:1287
#define InheritsParentIndexId
Definition: indexing.h:169
#define NULL
Definition: c.h:226
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:43
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1021
static int oid_cmp(const void *p1, const void *p2)
Definition: pg_inherits.c:364
#define InheritsRelationId
Definition: pg_inherits.h:29
tuple list
Definition: sort-test.py:11
void * palloc(Size size)
Definition: mcxt.c:891
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 243 of file pg_inherits.c.

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

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

244 {
245  HeapTuple tuple;
246  bool result;
247 
248  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationId));
249  if (!HeapTupleIsValid(tuple))
250  elog(ERROR, "cache lookup failed for relation %u", relationId);
251 
252  result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
253  ReleaseSysCache(tuple);
254  return result;
255 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
#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 263 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, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), and typeidTypeRelid().

Referenced by can_coerce_type(), and coerce_type().

264 {
265  bool result = false;
266  Oid subclassRelid;
267  Oid superclassRelid;
268  Relation inhrel;
269  List *visited,
270  *queue;
271  ListCell *queue_item;
272 
273  /* We need to work with the associated relation OIDs */
274  subclassRelid = typeidTypeRelid(subclassTypeId);
275  if (subclassRelid == InvalidOid)
276  return false; /* not a complex type */
277  superclassRelid = typeidTypeRelid(superclassTypeId);
278  if (superclassRelid == InvalidOid)
279  return false; /* not a complex type */
280 
281  /* No point in searching if the superclass has no subclasses */
282  if (!has_subclass(superclassRelid))
283  return false;
284 
285  /*
286  * Begin the search at the relation itself, so add its relid to the queue.
287  */
288  queue = list_make1_oid(subclassRelid);
289  visited = NIL;
290 
292 
293  /*
294  * Use queue to do a breadth-first traversal of the inheritance graph from
295  * the relid supplied up to the root. Notice that we append to the queue
296  * inside the loop --- this is okay because the foreach() macro doesn't
297  * advance queue_item until the next loop iteration begins.
298  */
299  foreach(queue_item, queue)
300  {
301  Oid this_relid = lfirst_oid(queue_item);
302  ScanKeyData skey;
303  SysScanDesc inhscan;
304  HeapTuple inhtup;
305 
306  /*
307  * If we've seen this relid already, skip it. This avoids extra work
308  * in multiple-inheritance scenarios, and also protects us from an
309  * infinite loop in case there is a cycle in pg_inherits (though
310  * theoretically that shouldn't happen).
311  */
312  if (list_member_oid(visited, this_relid))
313  continue;
314 
315  /*
316  * Okay, this is a not-yet-seen relid. Add it to the list of
317  * already-visited OIDs, then find all the types this relid inherits
318  * from and add them to the queue.
319  */
320  visited = lappend_oid(visited, this_relid);
321 
322  ScanKeyInit(&skey,
324  BTEqualStrategyNumber, F_OIDEQ,
325  ObjectIdGetDatum(this_relid));
326 
327  inhscan = systable_beginscan(inhrel, InheritsRelidSeqnoIndexId, true,
328  NULL, 1, &skey);
329 
330  while ((inhtup = systable_getnext(inhscan)) != NULL)
331  {
333  Oid inhparent = inh->inhparent;
334 
335  /* If this is the target superclass, we're done */
336  if (inhparent == superclassRelid)
337  {
338  result = true;
339  break;
340  }
341 
342  /* Else add to queue */
343  queue = lappend_oid(queue, inhparent);
344  }
345 
346  systable_endscan(inhscan);
347 
348  if (result)
349  break;
350  }
351 
352  /* clean up ... */
353  heap_close(inhrel, AccessShareLock);
354 
355  list_free(visited);
356  list_free(queue);
357 
358  return result;
359 }
#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:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define AccessShareLock
Definition: lockdefs.h:36
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:322
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
bool has_subclass(Oid relationId)
Definition: pg_inherits.c:243
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define list_make1_oid(x1)
Definition: pg_list.h:145
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#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:226
#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