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