1 /*-------------------------------------------------------------------------
4 * Sort the items of a dump into a safe order for dumping
7 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/bin/pg_dump/pg_dump_sort.c
14 *-------------------------------------------------------------------------
16 #include "pg_backup_archiver.h"
17 #include "pg_backup_utils.h"
20 /* translator: this is a module name */
21 static const char *modulename = gettext_noop("sorter");
24 * Sort priority for object types when dumping a pre-7.3 database.
25 * Objects are sorted by priority levels, and within an equal priority level
26 * by OID. (This is a relatively crude hack to provide semi-reasonable
27 * behavior for old databases without full dependency info.) Note: collations,
28 * extensions, text search, foreign-data, materialized view, event trigger,
29 * and default ACL objects can't really happen here, so the rather bogus
30 * priorities for them don't matter.
32 * NOTE: object-type priorities must match the section assignments made in
33 * pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY,
34 * POST_DATA objects must sort after DO_POST_DATA_BOUNDARY, and DATA objects
35 * must sort between them.
37 static const int oldObjectTypePriority[] =
42 2, /* DO_SHELL_TYPE */
49 5, /* DO_CONVERSION */
55 14, /* DO_CONSTRAINT */
56 18, /* DO_FK_CONSTRAINT */
59 11, /* DO_TABLE_DATA */
60 7, /* DO_DUMMY_TYPE */
63 4, /* DO_TSTEMPLATE */
66 4, /* DO_FOREIGN_SERVER */
67 19, /* DO_DEFAULT_ACL */
69 12, /* DO_BLOB_DATA */
70 10, /* DO_PRE_DATA_BOUNDARY */
71 13, /* DO_POST_DATA_BOUNDARY */
72 20, /* DO_EVENT_TRIGGER */
73 15 /* DO_REFRESH_MATVIEW */
77 * Sort priority for object types when dumping newer databases.
78 * Objects are sorted by type, and within a type by name.
80 * NOTE: object-type priorities must match the section assignments made in
81 * pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY,
82 * POST_DATA objects must sort after DO_POST_DATA_BOUNDARY, and DATA objects
83 * must sort between them.
85 static const int newObjectTypePriority[] =
90 5, /* DO_SHELL_TYPE */
97 11, /* DO_CONVERSION */
103 26, /* DO_CONSTRAINT */
104 30, /* DO_FK_CONSTRAINT */
107 23, /* DO_TABLE_DATA */
108 19, /* DO_DUMMY_TYPE */
109 12, /* DO_TSPARSER */
111 13, /* DO_TSTEMPLATE */
112 15, /* DO_TSCONFIG */
114 17, /* DO_FOREIGN_SERVER */
115 31, /* DO_DEFAULT_ACL */
117 24, /* DO_BLOB_DATA */
118 22, /* DO_PRE_DATA_BOUNDARY */
119 25, /* DO_POST_DATA_BOUNDARY */
120 32, /* DO_EVENT_TRIGGER */
121 33 /* DO_REFRESH_MATVIEW */
124 static DumpId preDataBoundId;
125 static DumpId postDataBoundId;
128 static int DOTypeNameCompare(const void *p1, const void *p2);
129 static int DOTypeOidCompare(const void *p1, const void *p2);
130 static bool TopoSort(DumpableObject **objs,
132 DumpableObject **ordering,
134 static void addHeapElement(int val, int *heap, int heapLength);
135 static int removeHeapElement(int *heap, int heapLength);
136 static void findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs);
137 static int findLoop(DumpableObject *obj,
140 DumpableObject **workspace,
142 static void repairDependencyLoop(DumpableObject **loop,
144 static void describeDumpableObject(DumpableObject *obj,
145 char *buf, int bufsize);
147 static int DOSizeCompare(const void *p1, const void *p2);
150 findFirstEqualType(DumpableObjectType type, DumpableObject **objs, int numObjs)
154 for (i = 0; i < numObjs; i++)
155 if (objs[i]->objType == type)
161 findFirstDifferentType(DumpableObjectType type, DumpableObject **objs, int numObjs, int start)
165 for (i = start; i < numObjs; i++)
166 if (objs[i]->objType != type)
172 * When we do a parallel dump, we want to start with the largest items first.
174 * Say we have the objects in this order:
175 * ....DDDDD....III....
177 * with D = Table data, I = Index, . = other object
179 * This sorting function now takes each of the D or I blocks and sorts them
180 * according to their size.
183 sortDataAndIndexObjectsBySize(DumpableObject **objs, int numObjs)
192 startIdx = findFirstEqualType(DO_TABLE_DATA, objs, numObjs);
195 endIdx = findFirstDifferentType(DO_TABLE_DATA, objs, numObjs, startIdx);
196 startPtr = objs + startIdx;
197 qsort(startPtr, endIdx - startIdx, sizeof(DumpableObject *),
201 startIdx = findFirstEqualType(DO_INDEX, objs, numObjs);
204 endIdx = findFirstDifferentType(DO_INDEX, objs, numObjs, startIdx);
205 startPtr = objs + startIdx;
206 qsort(startPtr, endIdx - startIdx, sizeof(DumpableObject *),
212 DOSizeCompare(const void *p1, const void *p2)
214 DumpableObject *obj1 = *(DumpableObject **) p1;
215 DumpableObject *obj2 = *(DumpableObject **) p2;
219 if (obj1->objType == DO_TABLE_DATA)
220 obj1_size = ((TableDataInfo *) obj1)->tdtable->relpages;
221 if (obj1->objType == DO_INDEX)
222 obj1_size = ((IndxInfo *) obj1)->relpages;
224 if (obj2->objType == DO_TABLE_DATA)
225 obj2_size = ((TableDataInfo *) obj2)->tdtable->relpages;
226 if (obj2->objType == DO_INDEX)
227 obj2_size = ((IndxInfo *) obj2)->relpages;
229 /* we want to see the biggest item go first */
230 if (obj1_size > obj2_size)
232 if (obj2_size > obj1_size)
239 * Sort the given objects into a type/name-based ordering
241 * Normally this is just the starting point for the dependency-based
245 sortDumpableObjectsByTypeName(DumpableObject **objs, int numObjs)
248 qsort((void *) objs, numObjs, sizeof(DumpableObject *),
253 DOTypeNameCompare(const void *p1, const void *p2)
255 DumpableObject *obj1 = *(DumpableObject *const *) p1;
256 DumpableObject *obj2 = *(DumpableObject *const *) p2;
260 cmpval = newObjectTypePriority[obj1->objType] -
261 newObjectTypePriority[obj2->objType];
267 * Sort by namespace. Note that all objects of the same type should
268 * either have or not have a namespace link, so we needn't be fancy about
269 * cases where one link is null and the other not.
271 if (obj1->namespace && obj2->namespace)
273 cmpval = strcmp(obj1->namespace->dobj.name,
274 obj2->namespace->dobj.name);
280 cmpval = strcmp(obj1->name, obj2->name);
284 /* To have a stable sort order, break ties for some object types */
285 if (obj1->objType == DO_FUNC || obj1->objType == DO_AGG)
287 FuncInfo *fobj1 = *(FuncInfo *const *) p1;
288 FuncInfo *fobj2 = *(FuncInfo *const *) p2;
290 cmpval = fobj1->nargs - fobj2->nargs;
293 cmpval = strcmp(fobj1->proiargs, fobj2->proiargs);
297 else if (obj1->objType == DO_OPERATOR)
299 OprInfo *oobj1 = *(OprInfo *const *) p1;
300 OprInfo *oobj2 = *(OprInfo *const *) p2;
302 /* oprkind is 'l', 'r', or 'b'; this sorts prefix, postfix, infix */
303 cmpval = (oobj2->oprkind - oobj1->oprkind);
307 else if (obj1->objType == DO_ATTRDEF)
309 AttrDefInfo *adobj1 = *(AttrDefInfo *const *) p1;
310 AttrDefInfo *adobj2 = *(AttrDefInfo *const *) p2;
312 cmpval = (adobj1->adnum - adobj2->adnum);
317 /* Usually shouldn't get here, but if we do, sort by OID */
318 return oidcmp(obj1->catId.oid, obj2->catId.oid);
323 * Sort the given objects into a type/OID-based ordering
325 * This is used with pre-7.3 source databases as a crude substitute for the
326 * lack of dependency information.
329 sortDumpableObjectsByTypeOid(DumpableObject **objs, int numObjs)
332 qsort((void *) objs, numObjs, sizeof(DumpableObject *),
337 DOTypeOidCompare(const void *p1, const void *p2)
339 DumpableObject *obj1 = *(DumpableObject *const *) p1;
340 DumpableObject *obj2 = *(DumpableObject *const *) p2;
343 cmpval = oldObjectTypePriority[obj1->objType] -
344 oldObjectTypePriority[obj2->objType];
349 return oidcmp(obj1->catId.oid, obj2->catId.oid);
354 * Sort the given objects into a safe dump order using dependency
355 * information (to the extent we have it available).
357 * The DumpIds of the PRE_DATA_BOUNDARY and POST_DATA_BOUNDARY objects are
358 * passed in separately, in case we need them during dependency loop repair.
361 sortDumpableObjects(DumpableObject **objs, int numObjs,
362 DumpId preBoundaryId, DumpId postBoundaryId)
364 DumpableObject **ordering;
367 if (numObjs <= 0) /* can't happen anymore ... */
371 * Saving the boundary IDs in static variables is a bit grotty, but seems
372 * better than adding them to parameter lists of subsidiary functions.
374 preDataBoundId = preBoundaryId;
375 postDataBoundId = postBoundaryId;
377 ordering = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
378 while (!TopoSort(objs, numObjs, ordering, &nOrdering))
379 findDependencyLoops(ordering, nOrdering, numObjs);
381 memcpy(objs, ordering, numObjs * sizeof(DumpableObject *));
387 * TopoSort -- topological sort of a dump list
389 * Generate a re-ordering of the dump list that satisfies all the dependency
390 * constraints shown in the dump list. (Each such constraint is a fact of a
391 * partial ordering.) Minimize rearrangement of the list not needed to
392 * achieve the partial ordering.
394 * The input is the list of numObjs objects in objs[]. This list is not
397 * Returns TRUE if able to build an ordering that satisfies all the
398 * constraints, FALSE if not (there are contradictory constraints).
400 * On success (TRUE result), ordering[] is filled with a sorted array of
401 * DumpableObject pointers, of length equal to the input list length.
403 * On failure (FALSE result), ordering[] is filled with an unsorted array of
404 * DumpableObject pointers of length *nOrdering, listing the objects that
405 * prevented the sort from being completed. In general, these objects either
406 * participate directly in a dependency cycle, or are depended on by objects
407 * that are in a cycle. (The latter objects are not actually problematic,
408 * but it takes further analysis to identify which are which.)
410 * The caller is responsible for allocating sufficient space at *ordering.
413 TopoSort(DumpableObject **objs,
415 DumpableObject **ordering, /* output argument */
416 int *nOrdering) /* output argument */
418 DumpId maxDumpId = getMaxDumpId();
420 int *beforeConstraints;
429 * This is basically the same algorithm shown for topological sorting in
430 * Knuth's Volume 1. However, we would like to minimize unnecessary
431 * rearrangement of the input ordering; that is, when we have a choice of
432 * which item to output next, we always want to take the one highest in
433 * the original list. Therefore, instead of maintaining an unordered
434 * linked list of items-ready-to-output as Knuth does, we maintain a heap
435 * of their item numbers, which we can use as a priority queue. This
436 * turns the algorithm from O(N) to O(N log N) because each insertion or
437 * removal of a heap item takes O(log N) time. However, that's still
438 * plenty fast enough for this application.
441 *nOrdering = numObjs; /* for success return */
443 /* Eliminate the null case */
447 /* Create workspace for the above-described heap */
448 pendingHeap = (int *) pg_malloc(numObjs * sizeof(int));
451 * Scan the constraints, and for each item in the input, generate a count
452 * of the number of constraints that say it must be before something else.
453 * The count for the item with dumpId j is stored in beforeConstraints[j].
454 * We also make a map showing the input-order index of the item with
457 beforeConstraints = (int *) pg_malloc((maxDumpId + 1) * sizeof(int));
458 memset(beforeConstraints, 0, (maxDumpId + 1) * sizeof(int));
459 idMap = (int *) pg_malloc((maxDumpId + 1) * sizeof(int));
460 for (i = 0; i < numObjs; i++)
464 if (j <= 0 || j > maxDumpId)
465 exit_horribly(modulename, "invalid dumpId %d\n", j);
467 for (j = 0; j < obj->nDeps; j++)
469 k = obj->dependencies[j];
470 if (k <= 0 || k > maxDumpId)
471 exit_horribly(modulename, "invalid dependency %d\n", k);
472 beforeConstraints[k]++;
477 * Now initialize the heap of items-ready-to-output by filling it with the
478 * indexes of items that already have beforeConstraints[id] == 0.
480 * The essential property of a heap is heap[(j-1)/2] >= heap[j] for each j
481 * in the range 1..heapLength-1 (note we are using 0-based subscripts
482 * here, while the discussion in Knuth assumes 1-based subscripts). So, if
483 * we simply enter the indexes into pendingHeap[] in decreasing order, we
484 * a-fortiori have the heap invariant satisfied at completion of this
485 * loop, and don't need to do any sift-up comparisons.
488 for (i = numObjs; --i >= 0;)
490 if (beforeConstraints[objs[i]->dumpId] == 0)
491 pendingHeap[heapLength++] = i;
494 /*--------------------
495 * Now emit objects, working backwards in the output list. At each step,
496 * we use the priority heap to select the last item that has no remaining
497 * before-constraints. We remove that item from the heap, output it to
498 * ordering[], and decrease the beforeConstraints count of each of the
499 * items it was constrained against. Whenever an item's beforeConstraints
500 * count is thereby decreased to zero, we insert it into the priority heap
501 * to show that it is a candidate to output. We are done when the heap
502 * becomes empty; if we have output every element then we succeeded,
503 * otherwise we failed.
504 * i = number of ordering[] entries left to output
505 * j = objs[] index of item we are outputting
506 * k = temp for scanning constraint list for item j
507 *--------------------
510 while (heapLength > 0)
512 /* Select object to output by removing largest heap member */
513 j = removeHeapElement(pendingHeap, heapLength--);
515 /* Output candidate to ordering[] */
517 /* Update beforeConstraints counts of its predecessors */
518 for (k = 0; k < obj->nDeps; k++)
520 int id = obj->dependencies[k];
522 if ((--beforeConstraints[id]) == 0)
523 addHeapElement(idMap[id], pendingHeap, heapLength++);
528 * If we failed, report the objects that couldn't be output; these are the
529 * ones with beforeConstraints[] still nonzero.
534 for (j = 1; j <= maxDumpId; j++)
536 if (beforeConstraints[j] != 0)
537 ordering[k++] = objs[idMap[j]];
544 free(beforeConstraints);
551 * Add an item to a heap (priority queue)
553 * heapLength is the current heap size; caller is responsible for increasing
554 * its value after the call. There must be sufficient storage at *heap.
557 addHeapElement(int val, int *heap, int heapLength)
562 * Sift-up the new entry, per Knuth 5.2.3 exercise 16. Note that Knuth is
563 * using 1-based array indexes, not 0-based.
568 int i = (j - 1) >> 1;
579 * Remove the largest item present in a heap (priority queue)
581 * heapLength is the current heap size; caller is responsible for decreasing
582 * its value after the call.
584 * We remove and return heap[0], which is always the largest element of
585 * the heap, and then "sift up" to maintain the heap invariant.
588 removeHeapElement(int *heap, int heapLength)
590 int result = heap[0];
594 if (--heapLength <= 0)
596 val = heap[heapLength]; /* value that must be reinserted */
597 i = 0; /* i is where the "hole" is */
604 if (j + 1 < heapLength &&
605 heap[j] < heap[j + 1])
617 * findDependencyLoops - identify loops in TopoSort's failure output,
618 * and pass each such loop to repairDependencyLoop() for action
620 * In general there may be many loops in the set of objects returned by
621 * TopoSort; for speed we should try to repair as many loops as we can
622 * before trying TopoSort again. We can safely repair loops that are
623 * disjoint (have no members in common); if we find overlapping loops
624 * then we repair only the first one found, because the action taken to
625 * repair the first might have repaired the other as well. (If not,
626 * we'll fix it on the next go-round.)
628 * objs[] lists the objects TopoSort couldn't sort
629 * nObjs is the number of such objects
630 * totObjs is the total number of objects in the universe
633 findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs)
636 * We use two data structures here. One is a bool array processed[],
637 * which is indexed by dump ID and marks the objects already processed
638 * during this invocation of findDependencyLoops(). The other is a
639 * workspace[] array of DumpableObject pointers, in which we try to build
640 * lists of objects constituting loops. We make workspace[] large enough
641 * to hold all the objects, which is huge overkill in most cases but could
642 * theoretically be necessary if there is a single dependency chain
643 * linking all the objects.
646 DumpableObject **workspace;
650 processed = (bool *) pg_malloc0((getMaxDumpId() + 1) * sizeof(bool));
651 workspace = (DumpableObject **) pg_malloc(totObjs * sizeof(DumpableObject *));
654 for (i = 0; i < nObjs; i++)
656 DumpableObject *obj = objs[i];
660 looplen = findLoop(obj, obj->dumpId, processed, workspace, 0);
664 /* Found a loop, repair it */
665 repairDependencyLoop(workspace, looplen);
667 /* Mark loop members as processed */
668 for (j = 0; j < looplen; j++)
669 processed[workspace[j]->dumpId] = true;
674 * There's no loop starting at this object, but mark it processed
675 * anyway. This is not necessary for correctness, but saves later
676 * invocations of findLoop() from uselessly chasing references to
679 processed[obj->dumpId] = true;
683 /* We'd better have fixed at least one loop */
685 exit_horribly(modulename, "could not identify dependency loop\n");
692 * Recursively search for a circular dependency loop that doesn't include
693 * any already-processed objects.
695 * obj: object we are examining now
696 * startPoint: dumpId of starting object for the hoped-for circular loop
697 * processed[]: flag array marking already-processed objects
698 * workspace[]: work array in which we are building list of loop members
699 * depth: number of valid entries in workspace[] at call
701 * On success, the length of the loop is returned, and workspace[] is filled
702 * with pointers to the members of the loop. On failure, we return 0.
704 * Note: it is possible that the given starting object is a member of more
705 * than one cycle; if so, we will find an arbitrary one of the cycles.
708 findLoop(DumpableObject *obj,
711 DumpableObject **workspace,
717 * Reject if obj is already processed. This test prevents us from finding
718 * loops that overlap previously-processed loops.
720 if (processed[obj->dumpId])
724 * Reject if obj is already present in workspace. This test prevents us
725 * from going into infinite recursion if we are given a startPoint object
726 * that links to a cycle it's not a member of, and it guarantees that we
727 * can't overflow the allocated size of workspace[].
729 for (i = 0; i < depth; i++)
731 if (workspace[i] == obj)
736 * Okay, tentatively add obj to workspace
738 workspace[depth++] = obj;
741 * See if we've found a loop back to the desired startPoint; if so, done
743 for (i = 0; i < obj->nDeps; i++)
745 if (obj->dependencies[i] == startPoint)
750 * Recurse down each outgoing branch
752 for (i = 0; i < obj->nDeps; i++)
754 DumpableObject *nextobj = findObjectByDumpId(obj->dependencies[i]);
758 continue; /* ignore dependencies on undumped objects */
759 newDepth = findLoop(nextobj,
772 * A user-defined datatype will have a dependency loop with each of its
773 * I/O functions (since those have the datatype as input or output).
774 * Similarly, a range type will have a loop with its canonicalize function,
775 * if any. Break the loop by making the function depend on the associated
776 * shell type, instead.
779 repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
781 TypeInfo *typeInfo = (TypeInfo *) typeobj;
783 /* remove function's dependency on type */
784 removeObjectDependency(funcobj, typeobj->dumpId);
786 /* add function's dependency on shell type, instead */
787 if (typeInfo->shellType)
789 addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
790 /* Mark shell type as to be dumped if any such function is */
792 typeInfo->shellType->dobj.dump = true;
797 * Because we force a view to depend on its ON SELECT rule, while there
798 * will be an implicit dependency in the other direction, we need to break
799 * the loop. If there are no other objects in the loop then we can remove
800 * the implicit dependency and leave the ON SELECT rule non-separate.
801 * This applies to matviews, as well.
804 repairViewRuleLoop(DumpableObject *viewobj,
805 DumpableObject *ruleobj)
807 /* remove rule's dependency on view */
808 removeObjectDependency(ruleobj, viewobj->dumpId);
812 * However, if there are other objects in the loop, we must break the loop
813 * by making the ON SELECT rule a separately-dumped object.
815 * Because findLoop() finds shorter cycles before longer ones, it's likely
816 * that we will have previously fired repairViewRuleLoop() and removed the
817 * rule's dependency on the view. Put it back to ensure the rule won't be
818 * emitted before the view.
820 * Note: this approach does *not* work for matviews, at the moment.
823 repairViewRuleMultiLoop(DumpableObject *viewobj,
824 DumpableObject *ruleobj)
826 TableInfo *viewinfo = (TableInfo *) viewobj;
827 RuleInfo *ruleinfo = (RuleInfo *) ruleobj;
829 /* remove view's dependency on rule */
830 removeObjectDependency(viewobj, ruleobj->dumpId);
831 /* pretend view is a plain table and dump it that way */
832 viewinfo->relkind = 'r'; /* RELKIND_RELATION */
833 /* mark rule as needing its own dump */
834 ruleinfo->separate = true;
835 /* move any reloptions from view to rule */
836 if (viewinfo->reloptions)
838 ruleinfo->reloptions = viewinfo->reloptions;
839 viewinfo->reloptions = NULL;
841 /* put back rule's dependency on view */
842 addObjectDependency(ruleobj, viewobj->dumpId);
843 /* now that rule is separate, it must be post-data */
844 addObjectDependency(ruleobj, postDataBoundId);
848 * If a matview is involved in a multi-object loop, we can't currently fix
849 * that by splitting off the rule. As a stopgap, we try to fix it by
850 * dropping the constraint that the matview be dumped in the pre-data section.
851 * This is sufficient to handle cases where a matview depends on some unique
852 * index, as can happen if it has a GROUP BY for example.
854 * Note that the "next object" is not necessarily the matview itself;
855 * it could be the matview's rowtype, for example. We may come through here
856 * several times while removing all the pre-data linkages.
859 repairMatViewBoundaryMultiLoop(DumpableObject *matviewobj,
860 DumpableObject *boundaryobj,
861 DumpableObject *nextobj)
863 TableInfo *matviewinfo = (TableInfo *) matviewobj;
865 /* remove boundary's dependency on object after it in loop */
866 removeObjectDependency(boundaryobj, nextobj->dumpId);
867 /* mark matview as postponed into post-data section */
868 matviewinfo->postponed_def = true;
872 * Because we make tables depend on their CHECK constraints, while there
873 * will be an automatic dependency in the other direction, we need to break
874 * the loop. If there are no other objects in the loop then we can remove
875 * the automatic dependency and leave the CHECK constraint non-separate.
878 repairTableConstraintLoop(DumpableObject *tableobj,
879 DumpableObject *constraintobj)
881 /* remove constraint's dependency on table */
882 removeObjectDependency(constraintobj, tableobj->dumpId);
886 * However, if there are other objects in the loop, we must break the loop
887 * by making the CHECK constraint a separately-dumped object.
889 * Because findLoop() finds shorter cycles before longer ones, it's likely
890 * that we will have previously fired repairTableConstraintLoop() and
891 * removed the constraint's dependency on the table. Put it back to ensure
892 * the constraint won't be emitted before the table...
895 repairTableConstraintMultiLoop(DumpableObject *tableobj,
896 DumpableObject *constraintobj)
898 /* remove table's dependency on constraint */
899 removeObjectDependency(tableobj, constraintobj->dumpId);
900 /* mark constraint as needing its own dump */
901 ((ConstraintInfo *) constraintobj)->separate = true;
902 /* put back constraint's dependency on table */
903 addObjectDependency(constraintobj, tableobj->dumpId);
904 /* now that constraint is separate, it must be post-data */
905 addObjectDependency(constraintobj, postDataBoundId);
909 * Attribute defaults behave exactly the same as CHECK constraints...
912 repairTableAttrDefLoop(DumpableObject *tableobj,
913 DumpableObject *attrdefobj)
915 /* remove attrdef's dependency on table */
916 removeObjectDependency(attrdefobj, tableobj->dumpId);
920 repairTableAttrDefMultiLoop(DumpableObject *tableobj,
921 DumpableObject *attrdefobj)
923 /* remove table's dependency on attrdef */
924 removeObjectDependency(tableobj, attrdefobj->dumpId);
925 /* mark attrdef as needing its own dump */
926 ((AttrDefInfo *) attrdefobj)->separate = true;
927 /* put back attrdef's dependency on table */
928 addObjectDependency(attrdefobj, tableobj->dumpId);
932 * CHECK constraints on domains work just like those on tables ...
935 repairDomainConstraintLoop(DumpableObject *domainobj,
936 DumpableObject *constraintobj)
938 /* remove constraint's dependency on domain */
939 removeObjectDependency(constraintobj, domainobj->dumpId);
943 repairDomainConstraintMultiLoop(DumpableObject *domainobj,
944 DumpableObject *constraintobj)
946 /* remove domain's dependency on constraint */
947 removeObjectDependency(domainobj, constraintobj->dumpId);
948 /* mark constraint as needing its own dump */
949 ((ConstraintInfo *) constraintobj)->separate = true;
950 /* put back constraint's dependency on domain */
951 addObjectDependency(constraintobj, domainobj->dumpId);
952 /* now that constraint is separate, it must be post-data */
953 addObjectDependency(constraintobj, postDataBoundId);
957 * Fix a dependency loop, or die trying ...
959 * This routine is mainly concerned with reducing the multiple ways that
960 * a loop might appear to common cases, which it passes off to the
961 * "fixer" routines above.
964 repairDependencyLoop(DumpableObject **loop,
970 /* Datatype and one of its I/O or canonicalize functions */
972 loop[0]->objType == DO_TYPE &&
973 loop[1]->objType == DO_FUNC)
975 repairTypeFuncLoop(loop[0], loop[1]);
979 loop[1]->objType == DO_TYPE &&
980 loop[0]->objType == DO_FUNC)
982 repairTypeFuncLoop(loop[1], loop[0]);
986 /* View (including matview) and its ON SELECT rule */
988 loop[0]->objType == DO_TABLE &&
989 loop[1]->objType == DO_RULE &&
990 (((TableInfo *) loop[0])->relkind == 'v' || /* RELKIND_VIEW */
991 ((TableInfo *) loop[0])->relkind == 'm') && /* RELKIND_MATVIEW */
992 ((RuleInfo *) loop[1])->ev_type == '1' &&
993 ((RuleInfo *) loop[1])->is_instead &&
994 ((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
996 repairViewRuleLoop(loop[0], loop[1]);
1000 loop[1]->objType == DO_TABLE &&
1001 loop[0]->objType == DO_RULE &&
1002 (((TableInfo *) loop[1])->relkind == 'v' || /* RELKIND_VIEW */
1003 ((TableInfo *) loop[1])->relkind == 'm') && /* RELKIND_MATVIEW */
1004 ((RuleInfo *) loop[0])->ev_type == '1' &&
1005 ((RuleInfo *) loop[0])->is_instead &&
1006 ((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
1008 repairViewRuleLoop(loop[1], loop[0]);
1012 /* Indirect loop involving view (but not matview) and ON SELECT rule */
1015 for (i = 0; i < nLoop; i++)
1017 if (loop[i]->objType == DO_TABLE &&
1018 ((TableInfo *) loop[i])->relkind == 'v') /* RELKIND_VIEW */
1020 for (j = 0; j < nLoop; j++)
1022 if (loop[j]->objType == DO_RULE &&
1023 ((RuleInfo *) loop[j])->ev_type == '1' &&
1024 ((RuleInfo *) loop[j])->is_instead &&
1025 ((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
1027 repairViewRuleMultiLoop(loop[i], loop[j]);
1035 /* Indirect loop involving matview and data boundary */
1038 for (i = 0; i < nLoop; i++)
1040 if (loop[i]->objType == DO_TABLE &&
1041 ((TableInfo *) loop[i])->relkind == 'm') /* RELKIND_MATVIEW */
1043 for (j = 0; j < nLoop; j++)
1045 if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
1047 DumpableObject *nextobj;
1049 nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
1050 repairMatViewBoundaryMultiLoop(loop[i], loop[j],
1059 /* Table and CHECK constraint */
1061 loop[0]->objType == DO_TABLE &&
1062 loop[1]->objType == DO_CONSTRAINT &&
1063 ((ConstraintInfo *) loop[1])->contype == 'c' &&
1064 ((ConstraintInfo *) loop[1])->contable == (TableInfo *) loop[0])
1066 repairTableConstraintLoop(loop[0], loop[1]);
1070 loop[1]->objType == DO_TABLE &&
1071 loop[0]->objType == DO_CONSTRAINT &&
1072 ((ConstraintInfo *) loop[0])->contype == 'c' &&
1073 ((ConstraintInfo *) loop[0])->contable == (TableInfo *) loop[1])
1075 repairTableConstraintLoop(loop[1], loop[0]);
1079 /* Indirect loop involving table and CHECK constraint */
1082 for (i = 0; i < nLoop; i++)
1084 if (loop[i]->objType == DO_TABLE)
1086 for (j = 0; j < nLoop; j++)
1088 if (loop[j]->objType == DO_CONSTRAINT &&
1089 ((ConstraintInfo *) loop[j])->contype == 'c' &&
1090 ((ConstraintInfo *) loop[j])->contable == (TableInfo *) loop[i])
1092 repairTableConstraintMultiLoop(loop[i], loop[j]);
1100 /* Table and attribute default */
1102 loop[0]->objType == DO_TABLE &&
1103 loop[1]->objType == DO_ATTRDEF &&
1104 ((AttrDefInfo *) loop[1])->adtable == (TableInfo *) loop[0])
1106 repairTableAttrDefLoop(loop[0], loop[1]);
1110 loop[1]->objType == DO_TABLE &&
1111 loop[0]->objType == DO_ATTRDEF &&
1112 ((AttrDefInfo *) loop[0])->adtable == (TableInfo *) loop[1])
1114 repairTableAttrDefLoop(loop[1], loop[0]);
1118 /* Indirect loop involving table and attribute default */
1121 for (i = 0; i < nLoop; i++)
1123 if (loop[i]->objType == DO_TABLE)
1125 for (j = 0; j < nLoop; j++)
1127 if (loop[j]->objType == DO_ATTRDEF &&
1128 ((AttrDefInfo *) loop[j])->adtable == (TableInfo *) loop[i])
1130 repairTableAttrDefMultiLoop(loop[i], loop[j]);
1138 /* Domain and CHECK constraint */
1140 loop[0]->objType == DO_TYPE &&
1141 loop[1]->objType == DO_CONSTRAINT &&
1142 ((ConstraintInfo *) loop[1])->contype == 'c' &&
1143 ((ConstraintInfo *) loop[1])->condomain == (TypeInfo *) loop[0])
1145 repairDomainConstraintLoop(loop[0], loop[1]);
1149 loop[1]->objType == DO_TYPE &&
1150 loop[0]->objType == DO_CONSTRAINT &&
1151 ((ConstraintInfo *) loop[0])->contype == 'c' &&
1152 ((ConstraintInfo *) loop[0])->condomain == (TypeInfo *) loop[1])
1154 repairDomainConstraintLoop(loop[1], loop[0]);
1158 /* Indirect loop involving domain and CHECK constraint */
1161 for (i = 0; i < nLoop; i++)
1163 if (loop[i]->objType == DO_TYPE)
1165 for (j = 0; j < nLoop; j++)
1167 if (loop[j]->objType == DO_CONSTRAINT &&
1168 ((ConstraintInfo *) loop[j])->contype == 'c' &&
1169 ((ConstraintInfo *) loop[j])->condomain == (TypeInfo *) loop[i])
1171 repairDomainConstraintMultiLoop(loop[i], loop[j]);
1180 * If all the objects are TABLE_DATA items, what we must have is a
1181 * circular set of foreign key constraints (or a single self-referential
1182 * table). Print an appropriate complaint and break the loop arbitrarily.
1184 for (i = 0; i < nLoop; i++)
1186 if (loop[i]->objType != DO_TABLE_DATA)
1191 write_msg(NULL, "NOTICE: there are circular foreign-key constraints among these table(s):\n");
1192 for (i = 0; i < nLoop; i++)
1193 write_msg(NULL, " %s\n", loop[i]->name);
1194 write_msg(NULL, "You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.\n");
1195 write_msg(NULL, "Consider using a full dump instead of a --data-only dump to avoid this problem.\n");
1197 removeObjectDependency(loop[0], loop[1]->dumpId);
1198 else /* must be a self-dependency */
1199 removeObjectDependency(loop[0], loop[0]->dumpId);
1204 * If we can't find a principled way to break the loop, complain and break
1205 * it in an arbitrary fashion.
1207 write_msg(modulename, "WARNING: could not resolve dependency loop among these items:\n");
1208 for (i = 0; i < nLoop; i++)
1212 describeDumpableObject(loop[i], buf, sizeof(buf));
1213 write_msg(modulename, " %s\n", buf);
1217 removeObjectDependency(loop[0], loop[1]->dumpId);
1218 else /* must be a self-dependency */
1219 removeObjectDependency(loop[0], loop[0]->dumpId);
1223 * Describe a dumpable object usefully for errors
1225 * This should probably go somewhere else...
1228 describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
1230 switch (obj->objType)
1233 snprintf(buf, bufsize,
1234 "SCHEMA %s (ID %d OID %u)",
1235 obj->name, obj->dumpId, obj->catId.oid);
1238 snprintf(buf, bufsize,
1239 "EXTENSION %s (ID %d OID %u)",
1240 obj->name, obj->dumpId, obj->catId.oid);
1243 snprintf(buf, bufsize,
1244 "TYPE %s (ID %d OID %u)",
1245 obj->name, obj->dumpId, obj->catId.oid);
1248 snprintf(buf, bufsize,
1249 "SHELL TYPE %s (ID %d OID %u)",
1250 obj->name, obj->dumpId, obj->catId.oid);
1253 snprintf(buf, bufsize,
1254 "FUNCTION %s (ID %d OID %u)",
1255 obj->name, obj->dumpId, obj->catId.oid);
1258 snprintf(buf, bufsize,
1259 "AGGREGATE %s (ID %d OID %u)",
1260 obj->name, obj->dumpId, obj->catId.oid);
1263 snprintf(buf, bufsize,
1264 "OPERATOR %s (ID %d OID %u)",
1265 obj->name, obj->dumpId, obj->catId.oid);
1268 snprintf(buf, bufsize,
1269 "OPERATOR CLASS %s (ID %d OID %u)",
1270 obj->name, obj->dumpId, obj->catId.oid);
1273 snprintf(buf, bufsize,
1274 "OPERATOR FAMILY %s (ID %d OID %u)",
1275 obj->name, obj->dumpId, obj->catId.oid);
1278 snprintf(buf, bufsize,
1279 "COLLATION %s (ID %d OID %u)",
1280 obj->name, obj->dumpId, obj->catId.oid);
1283 snprintf(buf, bufsize,
1284 "CONVERSION %s (ID %d OID %u)",
1285 obj->name, obj->dumpId, obj->catId.oid);
1288 snprintf(buf, bufsize,
1289 "TABLE %s (ID %d OID %u)",
1290 obj->name, obj->dumpId, obj->catId.oid);
1293 snprintf(buf, bufsize,
1294 "ATTRDEF %s.%s (ID %d OID %u)",
1295 ((AttrDefInfo *) obj)->adtable->dobj.name,
1296 ((AttrDefInfo *) obj)->adtable->attnames[((AttrDefInfo *) obj)->adnum - 1],
1297 obj->dumpId, obj->catId.oid);
1300 snprintf(buf, bufsize,
1301 "INDEX %s (ID %d OID %u)",
1302 obj->name, obj->dumpId, obj->catId.oid);
1304 case DO_REFRESH_MATVIEW:
1305 snprintf(buf, bufsize,
1306 "REFRESH MATERIALIZED VIEW %s (ID %d OID %u)",
1307 obj->name, obj->dumpId, obj->catId.oid);
1310 snprintf(buf, bufsize,
1311 "RULE %s (ID %d OID %u)",
1312 obj->name, obj->dumpId, obj->catId.oid);
1315 snprintf(buf, bufsize,
1316 "TRIGGER %s (ID %d OID %u)",
1317 obj->name, obj->dumpId, obj->catId.oid);
1319 case DO_EVENT_TRIGGER:
1320 snprintf(buf, bufsize,
1321 "EVENT TRIGGER %s (ID %d OID %u)",
1322 obj->name, obj->dumpId, obj->catId.oid);
1325 snprintf(buf, bufsize,
1326 "CONSTRAINT %s (ID %d OID %u)",
1327 obj->name, obj->dumpId, obj->catId.oid);
1329 case DO_FK_CONSTRAINT:
1330 snprintf(buf, bufsize,
1331 "FK CONSTRAINT %s (ID %d OID %u)",
1332 obj->name, obj->dumpId, obj->catId.oid);
1335 snprintf(buf, bufsize,
1336 "PROCEDURAL LANGUAGE %s (ID %d OID %u)",
1337 obj->name, obj->dumpId, obj->catId.oid);
1340 snprintf(buf, bufsize,
1341 "CAST %u to %u (ID %d OID %u)",
1342 ((CastInfo *) obj)->castsource,
1343 ((CastInfo *) obj)->casttarget,
1344 obj->dumpId, obj->catId.oid);
1347 snprintf(buf, bufsize,
1348 "TABLE DATA %s (ID %d OID %u)",
1349 obj->name, obj->dumpId, obj->catId.oid);
1352 snprintf(buf, bufsize,
1353 "DUMMY TYPE %s (ID %d OID %u)",
1354 obj->name, obj->dumpId, obj->catId.oid);
1357 snprintf(buf, bufsize,
1358 "TEXT SEARCH PARSER %s (ID %d OID %u)",
1359 obj->name, obj->dumpId, obj->catId.oid);
1362 snprintf(buf, bufsize,
1363 "TEXT SEARCH DICTIONARY %s (ID %d OID %u)",
1364 obj->name, obj->dumpId, obj->catId.oid);
1367 snprintf(buf, bufsize,
1368 "TEXT SEARCH TEMPLATE %s (ID %d OID %u)",
1369 obj->name, obj->dumpId, obj->catId.oid);
1372 snprintf(buf, bufsize,
1373 "TEXT SEARCH CONFIGURATION %s (ID %d OID %u)",
1374 obj->name, obj->dumpId, obj->catId.oid);
1377 snprintf(buf, bufsize,
1378 "FOREIGN DATA WRAPPER %s (ID %d OID %u)",
1379 obj->name, obj->dumpId, obj->catId.oid);
1381 case DO_FOREIGN_SERVER:
1382 snprintf(buf, bufsize,
1383 "FOREIGN SERVER %s (ID %d OID %u)",
1384 obj->name, obj->dumpId, obj->catId.oid);
1386 case DO_DEFAULT_ACL:
1387 snprintf(buf, bufsize,
1388 "DEFAULT ACL %s (ID %d OID %u)",
1389 obj->name, obj->dumpId, obj->catId.oid);
1392 snprintf(buf, bufsize,
1393 "BLOB (ID %d OID %u)",
1394 obj->dumpId, obj->catId.oid);
1397 snprintf(buf, bufsize,
1398 "BLOB DATA (ID %d)",
1401 case DO_PRE_DATA_BOUNDARY:
1402 snprintf(buf, bufsize,
1403 "PRE-DATA BOUNDARY (ID %d)",
1406 case DO_POST_DATA_BOUNDARY:
1407 snprintf(buf, bufsize,
1408 "POST-DATA BOUNDARY (ID %d)",
1412 /* shouldn't get here */
1413 snprintf(buf, bufsize,
1414 "object type %d (ID %d OID %u)",
1416 obj->dumpId, obj->catId.oid);