Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions | Variables

pg_dump_sort.c File Reference

#include "pg_backup_archiver.h"
#include "pg_backup_utils.h"
#include "parallel.h"
Include dependency graph for pg_dump_sort.c:

Go to the source code of this file.

Functions

static int DOTypeNameCompare (const void *p1, const void *p2)
static int DOTypeOidCompare (const void *p1, const void *p2)
static bool TopoSort (DumpableObject **objs, int numObjs, DumpableObject **ordering, int *nOrdering)
static void addHeapElement (int val, int *heap, int heapLength)
static int removeHeapElement (int *heap, int heapLength)
static void findDependencyLoops (DumpableObject **objs, int nObjs, int totObjs)
static int findLoop (DumpableObject *obj, DumpId startPoint, bool *processed, DumpableObject **workspace, int depth)
static void repairDependencyLoop (DumpableObject **loop, int nLoop)
static void describeDumpableObject (DumpableObject *obj, char *buf, int bufsize)
static int DOSizeCompare (const void *p1, const void *p2)
static int findFirstEqualType (DumpableObjectType type, DumpableObject **objs, int numObjs)
static int findFirstDifferentType (DumpableObjectType type, DumpableObject **objs, int numObjs, int start)
void sortDataAndIndexObjectsBySize (DumpableObject **objs, int numObjs)
void sortDumpableObjectsByTypeName (DumpableObject **objs, int numObjs)
void sortDumpableObjectsByTypeOid (DumpableObject **objs, int numObjs)
void sortDumpableObjects (DumpableObject **objs, int numObjs, DumpId preBoundaryId, DumpId postBoundaryId)
static void repairTypeFuncLoop (DumpableObject *typeobj, DumpableObject *funcobj)
static void repairViewRuleLoop (DumpableObject *viewobj, DumpableObject *ruleobj)
static void repairViewRuleMultiLoop (DumpableObject *viewobj, DumpableObject *ruleobj)
static void repairTableConstraintLoop (DumpableObject *tableobj, DumpableObject *constraintobj)
static void repairTableConstraintMultiLoop (DumpableObject *tableobj, DumpableObject *constraintobj)
static void repairTableAttrDefLoop (DumpableObject *tableobj, DumpableObject *attrdefobj)
static void repairTableAttrDefMultiLoop (DumpableObject *tableobj, DumpableObject *attrdefobj)
static void repairDomainConstraintLoop (DumpableObject *domainobj, DumpableObject *constraintobj)
static void repairDomainConstraintMultiLoop (DumpableObject *domainobj, DumpableObject *constraintobj)

Variables

static const char * modulename = gettext_noop("sorter")
static const int oldObjectTypePriority []
static const int newObjectTypePriority []
static DumpId preDataBoundId
static DumpId postDataBoundId

Function Documentation

static void addHeapElement ( int  val,
int *  heap,
int  heapLength 
) [static]

Definition at line 557 of file pg_dump_sort.c.

References i.

Referenced by TopoSort().

{
    int         j;

    /*
     * Sift-up the new entry, per Knuth 5.2.3 exercise 16. Note that Knuth is
     * using 1-based array indexes, not 0-based.
     */
    j = heapLength;
    while (j > 0)
    {
        int         i = (j - 1) >> 1;

        if (val <= heap[i])
            break;
        heap[j] = heap[i];
        j = i;
    }
    heap[j] = val;
}

static void describeDumpableObject ( DumpableObject obj,
char *  buf,
int  bufsize 
) [static]

Definition at line 1172 of file pg_dump_sort.c.

References _dumpableObject::catId, DO_AGG, DO_ATTRDEF, DO_BLOB, DO_BLOB_DATA, DO_CAST, DO_COLLATION, DO_CONSTRAINT, DO_CONVERSION, DO_DEFAULT_ACL, DO_DUMMY_TYPE, DO_EVENT_TRIGGER, DO_EXTENSION, DO_FDW, DO_FK_CONSTRAINT, DO_FOREIGN_SERVER, DO_FUNC, DO_INDEX, DO_NAMESPACE, DO_OPCLASS, DO_OPERATOR, DO_OPFAMILY, DO_POST_DATA_BOUNDARY, DO_PRE_DATA_BOUNDARY, DO_PROCLANG, DO_REFRESH_MATVIEW, DO_RULE, DO_SHELL_TYPE, DO_TABLE, DO_TABLE_DATA, DO_TRIGGER, DO_TSCONFIG, DO_TSDICT, DO_TSPARSER, DO_TSTEMPLATE, DO_TYPE, _dumpableObject::dumpId, _dumpableObject::name, _dumpableObject::objType, CatalogId::oid, and snprintf().

Referenced by repairDependencyLoop().

{
    switch (obj->objType)
    {
        case DO_NAMESPACE:
            snprintf(buf, bufsize,
                     "SCHEMA %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_EXTENSION:
            snprintf(buf, bufsize,
                     "EXTENSION %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_TYPE:
            snprintf(buf, bufsize,
                     "TYPE %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_SHELL_TYPE:
            snprintf(buf, bufsize,
                     "SHELL TYPE %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_FUNC:
            snprintf(buf, bufsize,
                     "FUNCTION %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_AGG:
            snprintf(buf, bufsize,
                     "AGGREGATE %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_OPERATOR:
            snprintf(buf, bufsize,
                     "OPERATOR %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_OPCLASS:
            snprintf(buf, bufsize,
                     "OPERATOR CLASS %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_OPFAMILY:
            snprintf(buf, bufsize,
                     "OPERATOR FAMILY %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_COLLATION:
            snprintf(buf, bufsize,
                     "COLLATION %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_CONVERSION:
            snprintf(buf, bufsize,
                     "CONVERSION %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_TABLE:
            snprintf(buf, bufsize,
                     "TABLE %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_ATTRDEF:
            snprintf(buf, bufsize,
                     "ATTRDEF %s.%s  (ID %d OID %u)",
                     ((AttrDefInfo *) obj)->adtable->dobj.name,
                     ((AttrDefInfo *) obj)->adtable->attnames[((AttrDefInfo *) obj)->adnum - 1],
                     obj->dumpId, obj->catId.oid);
            return;
        case DO_INDEX:
            snprintf(buf, bufsize,
                     "INDEX %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_REFRESH_MATVIEW:
            snprintf(buf, bufsize,
                     "REFRESH MATERIALIZED VIEW %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_RULE:
            snprintf(buf, bufsize,
                     "RULE %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_TRIGGER:
            snprintf(buf, bufsize,
                     "TRIGGER %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_EVENT_TRIGGER:
            snprintf(buf, bufsize,
                     "EVENT TRIGGER %s (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_CONSTRAINT:
            snprintf(buf, bufsize,
                     "CONSTRAINT %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_FK_CONSTRAINT:
            snprintf(buf, bufsize,
                     "FK CONSTRAINT %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_PROCLANG:
            snprintf(buf, bufsize,
                     "PROCEDURAL LANGUAGE %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_CAST:
            snprintf(buf, bufsize,
                     "CAST %u to %u  (ID %d OID %u)",
                     ((CastInfo *) obj)->castsource,
                     ((CastInfo *) obj)->casttarget,
                     obj->dumpId, obj->catId.oid);
            return;
        case DO_TABLE_DATA:
            snprintf(buf, bufsize,
                     "TABLE DATA %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_DUMMY_TYPE:
            snprintf(buf, bufsize,
                     "DUMMY TYPE %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_TSPARSER:
            snprintf(buf, bufsize,
                     "TEXT SEARCH PARSER %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_TSDICT:
            snprintf(buf, bufsize,
                     "TEXT SEARCH DICTIONARY %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_TSTEMPLATE:
            snprintf(buf, bufsize,
                     "TEXT SEARCH TEMPLATE %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_TSCONFIG:
            snprintf(buf, bufsize,
                     "TEXT SEARCH CONFIGURATION %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_FDW:
            snprintf(buf, bufsize,
                     "FOREIGN DATA WRAPPER %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_FOREIGN_SERVER:
            snprintf(buf, bufsize,
                     "FOREIGN SERVER %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_DEFAULT_ACL:
            snprintf(buf, bufsize,
                     "DEFAULT ACL %s  (ID %d OID %u)",
                     obj->name, obj->dumpId, obj->catId.oid);
            return;
        case DO_BLOB:
            snprintf(buf, bufsize,
                     "BLOB  (ID %d OID %u)",
                     obj->dumpId, obj->catId.oid);
            return;
        case DO_BLOB_DATA:
            snprintf(buf, bufsize,
                     "BLOB DATA  (ID %d)",
                     obj->dumpId);
            return;
        case DO_PRE_DATA_BOUNDARY:
            snprintf(buf, bufsize,
                     "PRE-DATA BOUNDARY  (ID %d)",
                     obj->dumpId);
            return;
        case DO_POST_DATA_BOUNDARY:
            snprintf(buf, bufsize,
                     "POST-DATA BOUNDARY  (ID %d)",
                     obj->dumpId);
            return;
    }
    /* shouldn't get here */
    snprintf(buf, bufsize,
             "object type %d  (ID %d OID %u)",
             (int) obj->objType,
             obj->dumpId, obj->catId.oid);
}

static int DOSizeCompare ( const void *  p1,
const void *  p2 
) [static]

Definition at line 212 of file pg_dump_sort.c.

References DO_INDEX, DO_TABLE_DATA, and _dumpableObject::objType.

Referenced by sortDataAndIndexObjectsBySize().

{
    DumpableObject *obj1 = *(DumpableObject **) p1;
    DumpableObject *obj2 = *(DumpableObject **) p2;
    int         obj1_size = 0;
    int         obj2_size = 0;

    if (obj1->objType == DO_TABLE_DATA)
        obj1_size = ((TableDataInfo *) obj1)->tdtable->relpages;
    if (obj1->objType == DO_INDEX)
        obj1_size = ((IndxInfo *) obj1)->relpages;

    if (obj2->objType == DO_TABLE_DATA)
        obj2_size = ((TableDataInfo *) obj2)->tdtable->relpages;
    if (obj2->objType == DO_INDEX)
        obj2_size = ((IndxInfo *) obj2)->relpages;

    /* we want to see the biggest item go first */
    if (obj1_size > obj2_size)
        return -1;
    if (obj2_size > obj1_size)
        return 1;

    return 0;
}

static int DOTypeNameCompare ( const void *  p1,
const void *  p2 
) [static]

Definition at line 253 of file pg_dump_sort.c.

References _attrDefInfo::adnum, _dumpableObject::catId, DO_AGG, DO_ATTRDEF, DO_FUNC, DO_OPERATOR, _dumpableObject::name, _funcInfo::nargs, newObjectTypePriority, _dumpableObject::objType, CatalogId::oid, oidcmp, _oprInfo::oprkind, and _funcInfo::proiargs.

Referenced by sortDumpableObjectsByTypeName().

{
    DumpableObject *obj1 = *(DumpableObject *const *) p1;
    DumpableObject *obj2 = *(DumpableObject *const *) p2;
    int         cmpval;

    /* Sort by type */
    cmpval = newObjectTypePriority[obj1->objType] -
        newObjectTypePriority[obj2->objType];

    if (cmpval != 0)
        return cmpval;

    /*
     * Sort by namespace.  Note that all objects of the same type should
     * either have or not have a namespace link, so we needn't be fancy about
     * cases where one link is null and the other not.
     */
    if (obj1->namespace && obj2->namespace)
    {
        cmpval = strcmp(obj1->namespace->dobj.name,
                        obj2->namespace->dobj.name);
        if (cmpval != 0)
            return cmpval;
    }

    /* Sort by name */
    cmpval = strcmp(obj1->name, obj2->name);
    if (cmpval != 0)
        return cmpval;

    /* To have a stable sort order, break ties for some object types */
    if (obj1->objType == DO_FUNC || obj1->objType == DO_AGG)
    {
        FuncInfo   *fobj1 = *(FuncInfo *const *) p1;
        FuncInfo   *fobj2 = *(FuncInfo *const *) p2;

        cmpval = fobj1->nargs - fobj2->nargs;
        if (cmpval != 0)
            return cmpval;
        cmpval = strcmp(fobj1->proiargs, fobj2->proiargs);
        if (cmpval != 0)
            return cmpval;
    }
    else if (obj1->objType == DO_OPERATOR)
    {
        OprInfo    *oobj1 = *(OprInfo *const *) p1;
        OprInfo    *oobj2 = *(OprInfo *const *) p2;

        /* oprkind is 'l', 'r', or 'b'; this sorts prefix, postfix, infix */
        cmpval = (oobj2->oprkind - oobj1->oprkind);
        if (cmpval != 0)
            return cmpval;
    }
    else if (obj1->objType == DO_ATTRDEF)
    {
        AttrDefInfo *adobj1 = *(AttrDefInfo *const *) p1;
        AttrDefInfo *adobj2 = *(AttrDefInfo *const *) p2;

        cmpval = (adobj1->adnum - adobj2->adnum);
        if (cmpval != 0)
            return cmpval;
    }

    /* Usually shouldn't get here, but if we do, sort by OID */
    return oidcmp(obj1->catId.oid, obj2->catId.oid);
}

static int DOTypeOidCompare ( const void *  p1,
const void *  p2 
) [static]

Definition at line 337 of file pg_dump_sort.c.

References _dumpableObject::catId, _dumpableObject::objType, CatalogId::oid, oidcmp, and oldObjectTypePriority.

Referenced by sortDumpableObjectsByTypeOid().

{
    DumpableObject *obj1 = *(DumpableObject *const *) p1;
    DumpableObject *obj2 = *(DumpableObject *const *) p2;
    int         cmpval;

    cmpval = oldObjectTypePriority[obj1->objType] -
        oldObjectTypePriority[obj2->objType];

    if (cmpval != 0)
        return cmpval;

    return oidcmp(obj1->catId.oid, obj2->catId.oid);
}

static void findDependencyLoops ( DumpableObject **  objs,
int  nObjs,
int  totObjs 
) [static]

Definition at line 633 of file pg_dump_sort.c.

References _dumpableObject::dumpId, exit_horribly(), findLoop(), free, getMaxDumpId(), i, modulename, pg_malloc(), pg_malloc0(), and repairDependencyLoop().

Referenced by sortDumpableObjects().

{
    /*
     * We use two data structures here.  One is a bool array processed[],
     * which is indexed by dump ID and marks the objects already processed
     * during this invocation of findDependencyLoops().  The other is a
     * workspace[] array of DumpableObject pointers, in which we try to build
     * lists of objects constituting loops.  We make workspace[] large enough
     * to hold all the objects, which is huge overkill in most cases but could
     * theoretically be necessary if there is a single dependency chain
     * linking all the objects.
     */
    bool       *processed;
    DumpableObject **workspace;
    bool        fixedloop;
    int         i;

    processed = (bool *) pg_malloc0((getMaxDumpId() + 1) * sizeof(bool));
    workspace = (DumpableObject **) pg_malloc(totObjs * sizeof(DumpableObject *));
    fixedloop = false;

    for (i = 0; i < nObjs; i++)
    {
        DumpableObject *obj = objs[i];
        int         looplen;
        int         j;

        looplen = findLoop(obj, obj->dumpId, processed, workspace, 0);

        if (looplen > 0)
        {
            /* Found a loop, repair it */
            repairDependencyLoop(workspace, looplen);
            fixedloop = true;
            /* Mark loop members as processed */
            for (j = 0; j < looplen; j++)
                processed[workspace[j]->dumpId] = true;
        }
        else
        {
            /*
             * There's no loop starting at this object, but mark it processed
             * anyway.  This is not necessary for correctness, but saves later
             * invocations of findLoop() from uselessly chasing references to
             * such an object.
             */
            processed[obj->dumpId] = true;
        }
    }

    /* We'd better have fixed at least one loop */
    if (!fixedloop)
        exit_horribly(modulename, "could not identify dependency loop\n");

    free(workspace);
    free(processed);
}

static int findFirstDifferentType ( DumpableObjectType  type,
DumpableObject **  objs,
int  numObjs,
int  start 
) [static]

Definition at line 161 of file pg_dump_sort.c.

References i.

Referenced by sortDataAndIndexObjectsBySize().

{
    int         i;

    for (i = start; i < numObjs; i++)
        if (objs[i]->objType != type)
            return i;
    return numObjs - 1;
}

static int findFirstEqualType ( DumpableObjectType  type,
DumpableObject **  objs,
int  numObjs 
) [static]

Definition at line 150 of file pg_dump_sort.c.

References i.

Referenced by sortDataAndIndexObjectsBySize().

{
    int         i;

    for (i = 0; i < numObjs; i++)
        if (objs[i]->objType == type)
            return i;
    return -1;
}

static int findLoop ( DumpableObject obj,
DumpId  startPoint,
bool processed,
DumpableObject **  workspace,
int  depth 
) [static]

Definition at line 708 of file pg_dump_sort.c.

References _dumpableObject::dependencies, _dumpableObject::dumpId, findObjectByDumpId(), i, and _dumpableObject::nDeps.

Referenced by findDependencyLoops().

{
    int         i;

    /*
     * Reject if obj is already processed.  This test prevents us from finding
     * loops that overlap previously-processed loops.
     */
    if (processed[obj->dumpId])
        return 0;

    /*
     * Reject if obj is already present in workspace.  This test prevents us
     * from going into infinite recursion if we are given a startPoint object
     * that links to a cycle it's not a member of, and it guarantees that we
     * can't overflow the allocated size of workspace[].
     */
    for (i = 0; i < depth; i++)
    {
        if (workspace[i] == obj)
            return 0;
    }

    /*
     * Okay, tentatively add obj to workspace
     */
    workspace[depth++] = obj;

    /*
     * See if we've found a loop back to the desired startPoint; if so, done
     */
    for (i = 0; i < obj->nDeps; i++)
    {
        if (obj->dependencies[i] == startPoint)
            return depth;
    }

    /*
     * Recurse down each outgoing branch
     */
    for (i = 0; i < obj->nDeps; i++)
    {
        DumpableObject *nextobj = findObjectByDumpId(obj->dependencies[i]);
        int         newDepth;

        if (!nextobj)
            continue;           /* ignore dependencies on undumped objects */
        newDepth = findLoop(nextobj,
                            startPoint,
                            processed,
                            workspace,
                            depth);
        if (newDepth > 0)
            return newDepth;
    }

    return 0;
}

static int removeHeapElement ( int *  heap,
int  heapLength 
) [static]

Definition at line 588 of file pg_dump_sort.c.

References i, and val.

Referenced by TopoSort().

{
    int         result = heap[0];
    int         val;
    int         i;

    if (--heapLength <= 0)
        return result;
    val = heap[heapLength];     /* value that must be reinserted */
    i = 0;                      /* i is where the "hole" is */
    for (;;)
    {
        int         j = 2 * i + 1;

        if (j >= heapLength)
            break;
        if (j + 1 < heapLength &&
            heap[j] < heap[j + 1])
            j++;
        if (val >= heap[j])
            break;
        heap[i] = heap[j];
        i = j;
    }
    heap[i] = val;
    return result;
}

static void repairDependencyLoop ( DumpableObject **  loop,
int  nLoop 
) [static]

Definition at line 937 of file pg_dump_sort.c.

References buf, describeDumpableObject(), DO_ATTRDEF, DO_CONSTRAINT, DO_FUNC, DO_RULE, DO_TABLE, DO_TABLE_DATA, DO_TYPE, i, modulename, name, NULL, removeObjectDependency(), repairDomainConstraintLoop(), repairDomainConstraintMultiLoop(), repairTableAttrDefLoop(), repairTableAttrDefMultiLoop(), repairTableConstraintLoop(), repairTableConstraintMultiLoop(), repairTypeFuncLoop(), repairViewRuleLoop(), repairViewRuleMultiLoop(), and write_msg().

Referenced by findDependencyLoops().

{
    int         i,
                j;

    /* Datatype and one of its I/O or canonicalize functions */
    if (nLoop == 2 &&
        loop[0]->objType == DO_TYPE &&
        loop[1]->objType == DO_FUNC)
    {
        repairTypeFuncLoop(loop[0], loop[1]);
        return;
    }
    if (nLoop == 2 &&
        loop[1]->objType == DO_TYPE &&
        loop[0]->objType == DO_FUNC)
    {
        repairTypeFuncLoop(loop[1], loop[0]);
        return;
    }

    /* View and its ON SELECT rule */
    if (nLoop == 2 &&
        loop[0]->objType == DO_TABLE &&
        loop[1]->objType == DO_RULE &&
        ((RuleInfo *) loop[1])->ev_type == '1' &&
        ((RuleInfo *) loop[1])->is_instead &&
        ((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
    {
        repairViewRuleLoop(loop[0], loop[1]);
        return;
    }
    if (nLoop == 2 &&
        loop[1]->objType == DO_TABLE &&
        loop[0]->objType == DO_RULE &&
        ((RuleInfo *) loop[0])->ev_type == '1' &&
        ((RuleInfo *) loop[0])->is_instead &&
        ((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
    {
        repairViewRuleLoop(loop[1], loop[0]);
        return;
    }

    /* Indirect loop involving view and ON SELECT rule */
    if (nLoop > 2)
    {
        for (i = 0; i < nLoop; i++)
        {
            if (loop[i]->objType == DO_TABLE)
            {
                for (j = 0; j < nLoop; j++)
                {
                    if (loop[j]->objType == DO_RULE &&
                        ((RuleInfo *) loop[j])->ev_type == '1' &&
                        ((RuleInfo *) loop[j])->is_instead &&
                        ((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
                    {
                        repairViewRuleMultiLoop(loop[i], loop[j]);
                        return;
                    }
                }
            }
        }
    }

    /* Table and CHECK constraint */
    if (nLoop == 2 &&
        loop[0]->objType == DO_TABLE &&
        loop[1]->objType == DO_CONSTRAINT &&
        ((ConstraintInfo *) loop[1])->contype == 'c' &&
        ((ConstraintInfo *) loop[1])->contable == (TableInfo *) loop[0])
    {
        repairTableConstraintLoop(loop[0], loop[1]);
        return;
    }
    if (nLoop == 2 &&
        loop[1]->objType == DO_TABLE &&
        loop[0]->objType == DO_CONSTRAINT &&
        ((ConstraintInfo *) loop[0])->contype == 'c' &&
        ((ConstraintInfo *) loop[0])->contable == (TableInfo *) loop[1])
    {
        repairTableConstraintLoop(loop[1], loop[0]);
        return;
    }

    /* Indirect loop involving table and CHECK constraint */
    if (nLoop > 2)
    {
        for (i = 0; i < nLoop; i++)
        {
            if (loop[i]->objType == DO_TABLE)
            {
                for (j = 0; j < nLoop; j++)
                {
                    if (loop[j]->objType == DO_CONSTRAINT &&
                        ((ConstraintInfo *) loop[j])->contype == 'c' &&
                        ((ConstraintInfo *) loop[j])->contable == (TableInfo *) loop[i])
                    {
                        repairTableConstraintMultiLoop(loop[i], loop[j]);
                        return;
                    }
                }
            }
        }
    }

    /* Table and attribute default */
    if (nLoop == 2 &&
        loop[0]->objType == DO_TABLE &&
        loop[1]->objType == DO_ATTRDEF &&
        ((AttrDefInfo *) loop[1])->adtable == (TableInfo *) loop[0])
    {
        repairTableAttrDefLoop(loop[0], loop[1]);
        return;
    }
    if (nLoop == 2 &&
        loop[1]->objType == DO_TABLE &&
        loop[0]->objType == DO_ATTRDEF &&
        ((AttrDefInfo *) loop[0])->adtable == (TableInfo *) loop[1])
    {
        repairTableAttrDefLoop(loop[1], loop[0]);
        return;
    }

    /* Indirect loop involving table and attribute default */
    if (nLoop > 2)
    {
        for (i = 0; i < nLoop; i++)
        {
            if (loop[i]->objType == DO_TABLE)
            {
                for (j = 0; j < nLoop; j++)
                {
                    if (loop[j]->objType == DO_ATTRDEF &&
                        ((AttrDefInfo *) loop[j])->adtable == (TableInfo *) loop[i])
                    {
                        repairTableAttrDefMultiLoop(loop[i], loop[j]);
                        return;
                    }
                }
            }
        }
    }

    /* Domain and CHECK constraint */
    if (nLoop == 2 &&
        loop[0]->objType == DO_TYPE &&
        loop[1]->objType == DO_CONSTRAINT &&
        ((ConstraintInfo *) loop[1])->contype == 'c' &&
        ((ConstraintInfo *) loop[1])->condomain == (TypeInfo *) loop[0])
    {
        repairDomainConstraintLoop(loop[0], loop[1]);
        return;
    }
    if (nLoop == 2 &&
        loop[1]->objType == DO_TYPE &&
        loop[0]->objType == DO_CONSTRAINT &&
        ((ConstraintInfo *) loop[0])->contype == 'c' &&
        ((ConstraintInfo *) loop[0])->condomain == (TypeInfo *) loop[1])
    {
        repairDomainConstraintLoop(loop[1], loop[0]);
        return;
    }

    /* Indirect loop involving domain and CHECK constraint */
    if (nLoop > 2)
    {
        for (i = 0; i < nLoop; i++)
        {
            if (loop[i]->objType == DO_TYPE)
            {
                for (j = 0; j < nLoop; j++)
                {
                    if (loop[j]->objType == DO_CONSTRAINT &&
                        ((ConstraintInfo *) loop[j])->contype == 'c' &&
                        ((ConstraintInfo *) loop[j])->condomain == (TypeInfo *) loop[i])
                    {
                        repairDomainConstraintMultiLoop(loop[i], loop[j]);
                        return;
                    }
                }
            }
        }
    }

    /*
     * If all the objects are TABLE_DATA items, what we must have is a
     * circular set of foreign key constraints (or a single self-referential
     * table).  Print an appropriate complaint and break the loop arbitrarily.
     */
    for (i = 0; i < nLoop; i++)
    {
        if (loop[i]->objType != DO_TABLE_DATA)
            break;
    }
    if (i >= nLoop)
    {
        write_msg(NULL, "NOTICE: there are circular foreign-key constraints among these table(s):\n");
        for (i = 0; i < nLoop; i++)
            write_msg(NULL, "  %s\n", loop[i]->name);
        write_msg(NULL, "You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.\n");
        write_msg(NULL, "Consider using a full dump instead of a --data-only dump to avoid this problem.\n");
        if (nLoop > 1)
            removeObjectDependency(loop[0], loop[1]->dumpId);
        else    /* must be a self-dependency */
            removeObjectDependency(loop[0], loop[0]->dumpId);
        return;
    }

    /*
     * If we can't find a principled way to break the loop, complain and break
     * it in an arbitrary fashion.
     */
    write_msg(modulename, "WARNING: could not resolve dependency loop among these items:\n");
    for (i = 0; i < nLoop; i++)
    {
        char        buf[1024];

        describeDumpableObject(loop[i], buf, sizeof(buf));
        write_msg(modulename, "  %s\n", buf);
    }

    if (nLoop > 1)
        removeObjectDependency(loop[0], loop[1]->dumpId);
    else    /* must be a self-dependency */
        removeObjectDependency(loop[0], loop[0]->dumpId);
}

static void repairDomainConstraintLoop ( DumpableObject domainobj,
DumpableObject constraintobj 
) [static]

Definition at line 908 of file pg_dump_sort.c.

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

{
    /* remove constraint's dependency on domain */
    removeObjectDependency(constraintobj, domainobj->dumpId);
}

static void repairDomainConstraintMultiLoop ( DumpableObject domainobj,
DumpableObject constraintobj 
) [static]

Definition at line 916 of file pg_dump_sort.c.

References addObjectDependency(), _dumpableObject::dumpId, postDataBoundId, and removeObjectDependency().

Referenced by repairDependencyLoop().

{
    /* remove domain's dependency on constraint */
    removeObjectDependency(domainobj, constraintobj->dumpId);
    /* mark constraint as needing its own dump */
    ((ConstraintInfo *) constraintobj)->separate = true;
    /* put back constraint's dependency on domain */
    addObjectDependency(constraintobj, domainobj->dumpId);
    /* now that constraint is separate, it must be post-data */
    addObjectDependency(constraintobj, postDataBoundId);
}

static void repairTableAttrDefLoop ( DumpableObject tableobj,
DumpableObject attrdefobj 
) [static]

Definition at line 885 of file pg_dump_sort.c.

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

{
    /* remove attrdef's dependency on table */
    removeObjectDependency(attrdefobj, tableobj->dumpId);
}

static void repairTableAttrDefMultiLoop ( DumpableObject tableobj,
DumpableObject attrdefobj 
) [static]

Definition at line 893 of file pg_dump_sort.c.

References addObjectDependency(), _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

{
    /* remove table's dependency on attrdef */
    removeObjectDependency(tableobj, attrdefobj->dumpId);
    /* mark attrdef as needing its own dump */
    ((AttrDefInfo *) attrdefobj)->separate = true;
    /* put back attrdef's dependency on table */
    addObjectDependency(attrdefobj, tableobj->dumpId);
}

static void repairTableConstraintLoop ( DumpableObject tableobj,
DumpableObject constraintobj 
) [static]

Definition at line 851 of file pg_dump_sort.c.

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

{
    /* remove constraint's dependency on table */
    removeObjectDependency(constraintobj, tableobj->dumpId);
}

static void repairTableConstraintMultiLoop ( DumpableObject tableobj,
DumpableObject constraintobj 
) [static]

Definition at line 868 of file pg_dump_sort.c.

References addObjectDependency(), _dumpableObject::dumpId, postDataBoundId, and removeObjectDependency().

Referenced by repairDependencyLoop().

{
    /* remove table's dependency on constraint */
    removeObjectDependency(tableobj, constraintobj->dumpId);
    /* mark constraint as needing its own dump */
    ((ConstraintInfo *) constraintobj)->separate = true;
    /* put back constraint's dependency on table */
    addObjectDependency(constraintobj, tableobj->dumpId);
    /* now that constraint is separate, it must be post-data */
    addObjectDependency(constraintobj, postDataBoundId);
}

static void repairTypeFuncLoop ( DumpableObject typeobj,
DumpableObject funcobj 
) [static]

Definition at line 779 of file pg_dump_sort.c.

References addObjectDependency(), _dumpableObject::dump, _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

{
    TypeInfo   *typeInfo = (TypeInfo *) typeobj;

    /* remove function's dependency on type */
    removeObjectDependency(funcobj, typeobj->dumpId);

    /* add function's dependency on shell type, instead */
    if (typeInfo->shellType)
    {
        addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
        /* Mark shell type as to be dumped if any such function is */
        if (funcobj->dump)
            typeInfo->shellType->dobj.dump = true;
    }
}

static void repairViewRuleLoop ( DumpableObject viewobj,
DumpableObject ruleobj 
) [static]

Definition at line 803 of file pg_dump_sort.c.

References _dumpableObject::dumpId, and removeObjectDependency().

Referenced by repairDependencyLoop().

{
    /* remove rule's dependency on view */
    removeObjectDependency(ruleobj, viewobj->dumpId);
}

static void repairViewRuleMultiLoop ( DumpableObject viewobj,
DumpableObject ruleobj 
) [static]

Definition at line 820 of file pg_dump_sort.c.

References addObjectDependency(), _dumpableObject::dumpId, postDataBoundId, _tableInfo::relkind, _ruleInfo::reloptions, _tableInfo::reloptions, removeObjectDependency(), and _ruleInfo::separate.

Referenced by repairDependencyLoop().

{
    TableInfo  *viewinfo = (TableInfo *) viewobj;
    RuleInfo   *ruleinfo = (RuleInfo *) ruleobj;

    /* remove view's dependency on rule */
    removeObjectDependency(viewobj, ruleobj->dumpId);
    /* pretend view is a plain table and dump it that way */
    viewinfo->relkind = 'r';    /* RELKIND_RELATION */
    /* mark rule as needing its own dump */
    ruleinfo->separate = true;
    /* move any reloptions from view to rule */
    if (viewinfo->reloptions)
    {
        ruleinfo->reloptions = viewinfo->reloptions;
        viewinfo->reloptions = NULL;
    }
    /* put back rule's dependency on view */
    addObjectDependency(ruleobj, viewobj->dumpId);
    /* now that rule is separate, it must be post-data */
    addObjectDependency(ruleobj, postDataBoundId);
}

void sortDataAndIndexObjectsBySize ( DumpableObject **  objs,
int  numObjs 
)

Definition at line 183 of file pg_dump_sort.c.

References DO_INDEX, DO_TABLE_DATA, DOSizeCompare(), findFirstDifferentType(), findFirstEqualType(), and qsort.

Referenced by main().

{
    int         startIdx,
                endIdx;
    void       *startPtr;

    if (numObjs <= 1)
        return;

    startIdx = findFirstEqualType(DO_TABLE_DATA, objs, numObjs);
    if (startIdx >= 0)
    {
        endIdx = findFirstDifferentType(DO_TABLE_DATA, objs, numObjs, startIdx);
        startPtr = objs + startIdx;
        qsort(startPtr, endIdx - startIdx, sizeof(DumpableObject *),
              DOSizeCompare);
    }

    startIdx = findFirstEqualType(DO_INDEX, objs, numObjs);
    if (startIdx >= 0)
    {
        endIdx = findFirstDifferentType(DO_INDEX, objs, numObjs, startIdx);
        startPtr = objs + startIdx;
        qsort(startPtr, endIdx - startIdx, sizeof(DumpableObject *),
              DOSizeCompare);
    }
}

void sortDumpableObjects ( DumpableObject **  objs,
int  numObjs,
DumpId  preBoundaryId,
DumpId  postBoundaryId 
)

Definition at line 361 of file pg_dump_sort.c.

References findDependencyLoops(), free, pg_malloc(), postDataBoundId, preDataBoundId, and TopoSort().

Referenced by main().

{
    DumpableObject **ordering;
    int         nOrdering;

    if (numObjs <= 0)           /* can't happen anymore ... */
        return;

    /*
     * Saving the boundary IDs in static variables is a bit grotty, but seems
     * better than adding them to parameter lists of subsidiary functions.
     */
    preDataBoundId = preBoundaryId;
    postDataBoundId = postBoundaryId;

    ordering = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
    while (!TopoSort(objs, numObjs, ordering, &nOrdering))
        findDependencyLoops(ordering, nOrdering, numObjs);

    memcpy(objs, ordering, numObjs * sizeof(DumpableObject *));

    free(ordering);
}

void sortDumpableObjectsByTypeName ( DumpableObject **  objs,
int  numObjs 
)

Definition at line 245 of file pg_dump_sort.c.

References DOTypeNameCompare(), and qsort.

Referenced by main().

{
    if (numObjs > 1)
        qsort((void *) objs, numObjs, sizeof(DumpableObject *),
              DOTypeNameCompare);
}

void sortDumpableObjectsByTypeOid ( DumpableObject **  objs,
int  numObjs 
)

Definition at line 329 of file pg_dump_sort.c.

References DOTypeOidCompare(), and qsort.

Referenced by main().

{
    if (numObjs > 1)
        qsort((void *) objs, numObjs, sizeof(DumpableObject *),
              DOTypeOidCompare);
}

static bool TopoSort ( DumpableObject **  objs,
int  numObjs,
DumpableObject **  ordering,
int *  nOrdering 
) [static]

Definition at line 413 of file pg_dump_sort.c.

References addHeapElement(), beforeConstraints, _dumpableObject::dependencies, _dumpableObject::dumpId, exit_horribly(), free, getMaxDumpId(), i, modulename, _dumpableObject::nDeps, pg_malloc(), and removeHeapElement().

Referenced by sortDumpableObjects().

{
    DumpId      maxDumpId = getMaxDumpId();
    int        *pendingHeap;
    int        *beforeConstraints;
    int        *idMap;
    DumpableObject *obj;
    int         heapLength;
    int         i,
                j,
                k;

    /*
     * This is basically the same algorithm shown for topological sorting in
     * Knuth's Volume 1.  However, we would like to minimize unnecessary
     * rearrangement of the input ordering; that is, when we have a choice of
     * which item to output next, we always want to take the one highest in
     * the original list.  Therefore, instead of maintaining an unordered
     * linked list of items-ready-to-output as Knuth does, we maintain a heap
     * of their item numbers, which we can use as a priority queue.  This
     * turns the algorithm from O(N) to O(N log N) because each insertion or
     * removal of a heap item takes O(log N) time.  However, that's still
     * plenty fast enough for this application.
     */

    *nOrdering = numObjs;       /* for success return */

    /* Eliminate the null case */
    if (numObjs <= 0)
        return true;

    /* Create workspace for the above-described heap */
    pendingHeap = (int *) pg_malloc(numObjs * sizeof(int));

    /*
     * Scan the constraints, and for each item in the input, generate a count
     * of the number of constraints that say it must be before something else.
     * The count for the item with dumpId j is stored in beforeConstraints[j].
     * We also make a map showing the input-order index of the item with
     * dumpId j.
     */
    beforeConstraints = (int *) pg_malloc((maxDumpId + 1) * sizeof(int));
    memset(beforeConstraints, 0, (maxDumpId + 1) * sizeof(int));
    idMap = (int *) pg_malloc((maxDumpId + 1) * sizeof(int));
    for (i = 0; i < numObjs; i++)
    {
        obj = objs[i];
        j = obj->dumpId;
        if (j <= 0 || j > maxDumpId)
            exit_horribly(modulename, "invalid dumpId %d\n", j);
        idMap[j] = i;
        for (j = 0; j < obj->nDeps; j++)
        {
            k = obj->dependencies[j];
            if (k <= 0 || k > maxDumpId)
                exit_horribly(modulename, "invalid dependency %d\n", k);
            beforeConstraints[k]++;
        }
    }

    /*
     * Now initialize the heap of items-ready-to-output by filling it with the
     * indexes of items that already have beforeConstraints[id] == 0.
     *
     * The essential property of a heap is heap[(j-1)/2] >= heap[j] for each j
     * in the range 1..heapLength-1 (note we are using 0-based subscripts
     * here, while the discussion in Knuth assumes 1-based subscripts). So, if
     * we simply enter the indexes into pendingHeap[] in decreasing order, we
     * a-fortiori have the heap invariant satisfied at completion of this
     * loop, and don't need to do any sift-up comparisons.
     */
    heapLength = 0;
    for (i = numObjs; --i >= 0;)
    {
        if (beforeConstraints[objs[i]->dumpId] == 0)
            pendingHeap[heapLength++] = i;
    }

    /*--------------------
     * Now emit objects, working backwards in the output list.  At each step,
     * we use the priority heap to select the last item that has no remaining
     * before-constraints.  We remove that item from the heap, output it to
     * ordering[], and decrease the beforeConstraints count of each of the
     * items it was constrained against.  Whenever an item's beforeConstraints
     * count is thereby decreased to zero, we insert it into the priority heap
     * to show that it is a candidate to output.  We are done when the heap
     * becomes empty; if we have output every element then we succeeded,
     * otherwise we failed.
     * i = number of ordering[] entries left to output
     * j = objs[] index of item we are outputting
     * k = temp for scanning constraint list for item j
     *--------------------
     */
    i = numObjs;
    while (heapLength > 0)
    {
        /* Select object to output by removing largest heap member */
        j = removeHeapElement(pendingHeap, heapLength--);
        obj = objs[j];
        /* Output candidate to ordering[] */
        ordering[--i] = obj;
        /* Update beforeConstraints counts of its predecessors */
        for (k = 0; k < obj->nDeps; k++)
        {
            int         id = obj->dependencies[k];

            if ((--beforeConstraints[id]) == 0)
                addHeapElement(idMap[id], pendingHeap, heapLength++);
        }
    }

    /*
     * If we failed, report the objects that couldn't be output; these are the
     * ones with beforeConstraints[] still nonzero.
     */
    if (i != 0)
    {
        k = 0;
        for (j = 1; j <= maxDumpId; j++)
        {
            if (beforeConstraints[j] != 0)
                ordering[k++] = objs[idMap[j]];
        }
        *nOrdering = k;
    }

    /* Done */
    free(pendingHeap);
    free(beforeConstraints);
    free(idMap);

    return (i == 0);
}


Variable Documentation

const char* modulename = gettext_noop("sorter") [static]

Definition at line 21 of file pg_dump_sort.c.

Referenced by findDependencyLoops(), repairDependencyLoop(), and TopoSort().

const int newObjectTypePriority[] [static]

Definition at line 85 of file pg_dump_sort.c.

Referenced by DOTypeNameCompare().

const int oldObjectTypePriority[] [static]

Definition at line 37 of file pg_dump_sort.c.

Referenced by DOTypeOidCompare().

Definition at line 124 of file pg_dump_sort.c.

Referenced by sortDumpableObjects().