#include "pg_backup_archiver.h"#include "pg_backup_utils.h"#include "parallel.h"
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 |
| static void addHeapElement | ( | int | val, | |
| int * | heap, | |||
| int | heapLength | |||
| ) | [static] |
| 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.
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);
}
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().
DumpId postDataBoundId [static] |
Definition at line 125 of file pg_dump_sort.c.
Referenced by repairDomainConstraintMultiLoop(), repairTableConstraintMultiLoop(), repairViewRuleMultiLoop(), and sortDumpableObjects().
DumpId preDataBoundId [static] |
Definition at line 124 of file pg_dump_sort.c.
Referenced by sortDumpableObjects().
1.7.1