#include "nodes/pg_list.h"
#include "storage/lock.h"
Go to the source code of this file.
Functions | |
List * | find_inheritance_children (Oid parentrelId, LOCKMODE lockmode) |
List * | find_all_inheritors (Oid parentrelId, LOCKMODE lockmode, List **parents) |
bool | has_subclass (Oid relationId) |
bool | typeInheritsFrom (Oid subclassTypeId, Oid superclassTypeId) |
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(), ATExecValidateConstraint(), ATSimpleRecursion(), ExecuteTruncate(), expand_inherited_rtentry(), rename_constraint_internal(), renameatt_internal(), and sepgsql_dml_privileges().
{ List *rels_list, *rel_numparents; ListCell *l; /* * We build a list starting with the given rel and adding all direct and * indirect children. We can use a single list as both the record of * already-found rels and the agenda of rels yet to be scanned for more * children. This is a bit tricky but works because the foreach() macro * doesn't fetch the next list element until the bottom of the loop. */ rels_list = list_make1_oid(parentrelId); rel_numparents = list_make1_int(0); foreach(l, rels_list) { Oid currentrel = lfirst_oid(l); List *currentchildren; ListCell *lc; /* Get the direct children of this rel */ currentchildren = find_inheritance_children(currentrel, lockmode); /* * Add to the queue only those children not already seen. This avoids * making duplicate entries in case of multiple inheritance paths from * the same parent. (It'll also keep us from getting into an infinite * loop, though theoretically there can't be any cycles in the * inheritance graph anyway.) */ foreach(lc, currentchildren) { Oid child_oid = lfirst_oid(lc); bool found = false; ListCell *lo; ListCell *li; /* if the rel is already there, bump number-of-parents counter */ forboth(lo, rels_list, li, rel_numparents) { if (lfirst_oid(lo) == child_oid) { lfirst_int(li)++; found = true; break; } } /* if it's not there, add it. expect 1 parent, initially. */ if (!found) { rels_list = lappend_oid(rels_list, child_oid); rel_numparents = lappend_int(rel_numparents, 1); } } } if (numparents) *numparents = rel_numparents; else list_free(rel_numparents); return rels_list; }
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(), NoLock, NULL, ObjectIdGetDatum, oid_cmp(), palloc(), pfree(), qsort, RELOID, repalloc(), ScanKeyInit(), SearchSysCacheExists1, SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and UnlockRelationOid().
Referenced by ATAddCheckConstraint(), ATExecAddColumn(), ATExecDropColumn(), ATExecDropConstraint(), ATPrepAlterColumnType(), find_all_inheritors(), LockTableRecurse(), rename_constraint_internal(), and renameatt_internal().
{ List *list = NIL; Relation relation; SysScanDesc scan; ScanKeyData key[1]; HeapTuple inheritsTuple; Oid inhrelid; Oid *oidarr; int maxoids, numoids, i; /* * Can skip the scan if pg_class shows the relation has never had a * subclass. */ if (!has_subclass(parentrelId)) return NIL; /* * Scan pg_inherits and build a working array of subclass OIDs. */ maxoids = 32; oidarr = (Oid *) palloc(maxoids * sizeof(Oid)); numoids = 0; relation = heap_open(InheritsRelationId, AccessShareLock); ScanKeyInit(&key[0], Anum_pg_inherits_inhparent, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(parentrelId)); scan = systable_beginscan(relation, InheritsParentIndexId, true, SnapshotNow, 1, key); while ((inheritsTuple = systable_getnext(scan)) != NULL) { inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid; if (numoids >= maxoids) { maxoids *= 2; oidarr = (Oid *) repalloc(oidarr, maxoids * sizeof(Oid)); } oidarr[numoids++] = inhrelid; } systable_endscan(scan); heap_close(relation, AccessShareLock); /* * If we found more than one child, sort them by OID. This ensures * reasonably consistent behavior regardless of the vagaries of an * indexscan. This is important since we need to be sure all backends * lock children in the same order to avoid needless deadlocks. */ if (numoids > 1) qsort(oidarr, numoids, sizeof(Oid), oid_cmp); /* * Acquire locks and build the result list. */ for (i = 0; i < numoids; i++) { inhrelid = oidarr[i]; if (lockmode != NoLock) { /* Get the lock to synchronize against concurrent drop */ LockRelationOid(inhrelid, lockmode); /* * Now that we have the lock, double-check to see if the relation * really exists or not. If not, assume it was dropped while we * waited to acquire lock, and ignore it. */ if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(inhrelid))) { /* Release useless lock */ UnlockRelationOid(inhrelid, lockmode); /* And ignore this relation */ continue; } } list = lappend_oid(list, inhrelid); } pfree(oidarr); return list; }
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().
{ HeapTuple tuple; bool result; tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationId)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", relationId); result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass; ReleaseSysCache(tuple); return result; }
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(), NULL, ObjectIdGetDatum, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and typeidTypeRelid().
Referenced by can_coerce_type(), and coerce_type().
{ bool result = false; Oid subclassRelid; Oid superclassRelid; Relation inhrel; List *visited, *queue; ListCell *queue_item; /* We need to work with the associated relation OIDs */ subclassRelid = typeidTypeRelid(subclassTypeId); if (subclassRelid == InvalidOid) return false; /* not a complex type */ superclassRelid = typeidTypeRelid(superclassTypeId); if (superclassRelid == InvalidOid) return false; /* not a complex type */ /* No point in searching if the superclass has no subclasses */ if (!has_subclass(superclassRelid)) return false; /* * Begin the search at the relation itself, so add its relid to the queue. */ queue = list_make1_oid(subclassRelid); visited = NIL; inhrel = heap_open(InheritsRelationId, AccessShareLock); /* * Use queue to do a breadth-first traversal of the inheritance graph from * the relid supplied up to the root. Notice that we append to the queue * inside the loop --- this is okay because the foreach() macro doesn't * advance queue_item until the next loop iteration begins. */ foreach(queue_item, queue) { Oid this_relid = lfirst_oid(queue_item); ScanKeyData skey; SysScanDesc inhscan; HeapTuple inhtup; /* * If we've seen this relid already, skip it. This avoids extra work * in multiple-inheritance scenarios, and also protects us from an * infinite loop in case there is a cycle in pg_inherits (though * theoretically that shouldn't happen). */ if (list_member_oid(visited, this_relid)) continue; /* * Okay, this is a not-yet-seen relid. Add it to the list of * already-visited OIDs, then find all the types this relid inherits * from and add them to the queue. */ visited = lappend_oid(visited, this_relid); ScanKeyInit(&skey, Anum_pg_inherits_inhrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(this_relid)); inhscan = systable_beginscan(inhrel, InheritsRelidSeqnoIndexId, true, SnapshotNow, 1, &skey); while ((inhtup = systable_getnext(inhscan)) != NULL) { Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup); Oid inhparent = inh->inhparent; /* If this is the target superclass, we're done */ if (inhparent == superclassRelid) { result = true; break; } /* Else add to queue */ queue = lappend_oid(queue, inhparent); } systable_endscan(inhscan); if (result) break; } /* clean up ... */ heap_close(inhrel, AccessShareLock); list_free(visited); list_free(queue); return result; }