#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/fmgroids.h"#include "utils/syscache.h"#include "utils/tqual.h"
Go to the source code of this file.
Functions | |
| static int | oid_cmp (const void *p1, const void *p2) |
| List * | find_inheritance_children (Oid parentrelId, LOCKMODE lockmode) |
| List * | find_all_inheritors (Oid parentrelId, LOCKMODE lockmode, List **numparents) |
| 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;
}
| static int oid_cmp | ( | const void * | p1, | |
| const void * | p2 | |||
| ) | [static] |
Definition at line 364 of file pg_inherits.c.
Referenced by find_inheritance_children().
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;
}
1.7.1