Header And Logo

| The world's most advanced open source database.


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/fmgroids.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
Include dependency graph for pg_inherits.c:

Go to the source code of this file.


static int oid_cmp (const void *p1, const void *p2)
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)

Function Documentation

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

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,
    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)
                    found = true;

            /* 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;
    return rels_list;

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(), 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,

     * 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);

                BTEqualStrategyNumber, F_OIDEQ,

    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;


    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 */

        list = lappend_oid(list, inhrelid);


    return list;

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().

    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;
    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().

    Oid         v1 = *((const Oid *) p1);
    Oid         v2 = *((const Oid *) p2);

    if (v1 < v2)
        return -1;
    if (v1 > v2)
        return 1;
    return 0;

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(), 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,
    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))

         * 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);

                    BTEqualStrategyNumber, F_OIDEQ,

        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;

            /* Else add to queue */
            queue = lappend_oid(queue, inhparent);


        if (result)

    /* clean up ... */
    heap_close(inhrel, AccessShareLock);


    return result;