1 /*-------------------------------------------------------------------------
4 * Sort the items of a dump into a safe order for dumping
7 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.5 2004/08/29 04:13:01 momjian Exp $
14 *-------------------------------------------------------------------------
17 #include "pg_backup_archiver.h"
20 static char *modulename = gettext_noop("sorter");
23 * Sort priority for object types when dumping a pre-7.3 database.
24 * Objects are sorted by priority levels, and within an equal priority level
25 * by OID. (This is a relatively crude hack to provide semi-reasonable
26 * behavior for old databases without full dependency info.)
28 static const int oldObjectTypePriority[] =
36 5, /* DO_CONVERSION */
42 11, /* DO_CONSTRAINT */
43 15, /* DO_FK_CONSTRAINT */
46 9, /* DO_TABLE_DATA */
47 7, /* DO_TABLE_TYPE */
52 * Sort priority for object types when dumping newer databases.
53 * Objects are sorted by type, and within a type by name.
55 static const int newObjectTypePriority[] =
63 9, /* DO_CONVERSION */
69 15, /* DO_CONSTRAINT */
70 19, /* DO_FK_CONSTRAINT */
73 13, /* DO_TABLE_DATA */
74 11, /* DO_TABLE_TYPE */
79 static int DOTypeNameCompare(const void *p1, const void *p2);
80 static int DOTypeOidCompare(const void *p1, const void *p2);
81 static bool TopoSort(DumpableObject **objs,
83 DumpableObject **ordering,
85 static void addHeapElement(int val, int *heap, int heapLength);
86 static int removeHeapElement(int *heap, int heapLength);
87 static void findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs);
88 static bool findLoop(DumpableObject *obj,
90 DumpableObject **workspace,
93 static void repairDependencyLoop(DumpableObject **loop,
95 static void describeDumpableObject(DumpableObject *obj,
96 char *buf, int bufsize);
100 * Sort the given objects into a type/name-based ordering
102 * Normally this is just the starting point for the dependency-based
106 sortDumpableObjectsByTypeName(DumpableObject **objs, int numObjs)
109 qsort((void *) objs, numObjs, sizeof(DumpableObject *),
114 DOTypeNameCompare(const void *p1, const void *p2)
116 DumpableObject *obj1 = *(DumpableObject **) p1;
117 DumpableObject *obj2 = *(DumpableObject **) p2;
121 cmpval = newObjectTypePriority[obj1->objType] -
122 newObjectTypePriority[obj2->objType];
128 * Sort by namespace. Note that all objects of the same type should
129 * either have or not have a namespace link, so we needn't be fancy
130 * about cases where one link is null and the other not.
132 if (obj1->namespace && obj2->namespace)
134 cmpval = strcmp(obj1->namespace->dobj.name,
135 obj2->namespace->dobj.name);
141 cmpval = strcmp(obj1->name, obj2->name);
145 /* Probably shouldn't get here, but if we do, sort by OID */
146 return oidcmp(obj1->catId.oid, obj2->catId.oid);
151 * Sort the given objects into a type/OID-based ordering
153 * This is used with pre-7.3 source databases as a crude substitute for the
154 * lack of dependency information.
157 sortDumpableObjectsByTypeOid(DumpableObject **objs, int numObjs)
160 qsort((void *) objs, numObjs, sizeof(DumpableObject *),
165 DOTypeOidCompare(const void *p1, const void *p2)
167 DumpableObject *obj1 = *(DumpableObject **) p1;
168 DumpableObject *obj2 = *(DumpableObject **) p2;
171 cmpval = oldObjectTypePriority[obj1->objType] -
172 oldObjectTypePriority[obj2->objType];
177 return oidcmp(obj1->catId.oid, obj2->catId.oid);
182 * Sort the given objects into a safe dump order using dependency
183 * information (to the extent we have it available).
186 sortDumpableObjects(DumpableObject **objs, int numObjs)
188 DumpableObject **ordering;
194 ordering = (DumpableObject **) malloc(numObjs * sizeof(DumpableObject *));
195 if (ordering == NULL)
196 exit_horribly(NULL, modulename, "out of memory\n");
198 while (!TopoSort(objs, numObjs, ordering, &nOrdering))
199 findDependencyLoops(ordering, nOrdering, numObjs);
201 memcpy(objs, ordering, numObjs * sizeof(DumpableObject *));
207 * TopoSort -- topological sort of a dump list
209 * Generate a re-ordering of the dump list that satisfies all the dependency
210 * constraints shown in the dump list. (Each such constraint is a fact of a
211 * partial ordering.) Minimize rearrangement of the list not needed to
212 * achieve the partial ordering.
214 * The input is the list of numObjs objects in objs[]. This list is not
217 * Returns TRUE if able to build an ordering that satisfies all the
218 * constraints, FALSE if not (there are contradictory constraints).
220 * On success (TRUE result), ordering[] is filled with a sorted array of
221 * DumpableObject pointers, of length equal to the input list length.
223 * On failure (FALSE result), ordering[] is filled with an unsorted array of
224 * DumpableObject pointers of length *nOrdering, listing the objects that
225 * prevented the sort from being completed. In general, these objects either
226 * participate directly in a dependency cycle, or are depended on by objects
227 * that are in a cycle. (The latter objects are not actually problematic,
228 * but it takes further analysis to identify which are which.)
230 * The caller is responsible for allocating sufficient space at *ordering.
233 TopoSort(DumpableObject **objs,
235 DumpableObject **ordering, /* output argument */
236 int *nOrdering) /* output argument */
238 DumpId maxDumpId = getMaxDumpId();
240 int *beforeConstraints;
249 * This is basically the same algorithm shown for topological sorting in
250 * Knuth's Volume 1. However, we would like to minimize unnecessary
251 * rearrangement of the input ordering; that is, when we have a choice
252 * of which item to output next, we always want to take the one highest
253 * in the original list. Therefore, instead of maintaining an unordered
254 * linked list of items-ready-to-output as Knuth does, we maintain a heap
255 * of their item numbers, which we can use as a priority queue. This
256 * turns the algorithm from O(N) to O(N log N) because each insertion or
257 * removal of a heap item takes O(log N) time. However, that's still
258 * plenty fast enough for this application.
261 *nOrdering = numObjs; /* for success return */
263 /* Eliminate the null case */
267 /* Create workspace for the above-described heap */
268 pendingHeap = (int *) malloc(numObjs * sizeof(int));
269 if (pendingHeap == NULL)
270 exit_horribly(NULL, modulename, "out of memory\n");
273 * Scan the constraints, and for each item in the input, generate a
274 * count of the number of constraints that say it must be before
275 * something else. The count for the item with dumpId j is
276 * stored in beforeConstraints[j]. We also make a map showing the
277 * input-order index of the item with dumpId j.
279 beforeConstraints = (int *) malloc((maxDumpId + 1) * sizeof(int));
280 if (beforeConstraints == NULL)
281 exit_horribly(NULL, modulename, "out of memory\n");
282 memset(beforeConstraints, 0, (maxDumpId + 1) * sizeof(int));
283 idMap = (int *) malloc((maxDumpId + 1) * sizeof(int));
285 exit_horribly(NULL, modulename, "out of memory\n");
286 for (i = 0; i < numObjs; i++)
290 if (j <= 0 || j > maxDumpId)
291 exit_horribly(NULL, modulename, "invalid dumpId %d\n", j);
293 for (j = 0; j < obj->nDeps; j++)
295 k = obj->dependencies[j];
296 if (k <= 0 || k > maxDumpId)
297 exit_horribly(NULL, modulename, "invalid dependency %d\n", k);
298 beforeConstraints[k]++;
303 * Now initialize the heap of items-ready-to-output by filling it with
304 * the indexes of items that already have beforeConstraints[id] == 0.
306 * The essential property of a heap is heap[(j-1)/2] >= heap[j] for each
307 * j in the range 1..heapLength-1 (note we are using 0-based subscripts
308 * here, while the discussion in Knuth assumes 1-based subscripts).
309 * So, if we simply enter the indexes into pendingHeap[] in decreasing
310 * order, we a-fortiori have the heap invariant satisfied at completion
311 * of this loop, and don't need to do any sift-up comparisons.
314 for (i = numObjs; --i >= 0; )
316 if (beforeConstraints[objs[i]->dumpId] == 0)
317 pendingHeap[heapLength++] = i;
320 /*--------------------
321 * Now emit objects, working backwards in the output list. At each step,
322 * we use the priority heap to select the last item that has no remaining
323 * before-constraints. We remove that item from the heap, output it to
324 * ordering[], and decrease the beforeConstraints count of each of the
325 * items it was constrained against. Whenever an item's beforeConstraints
326 * count is thereby decreased to zero, we insert it into the priority heap
327 * to show that it is a candidate to output. We are done when the heap
328 * becomes empty; if we have output every element then we succeeded,
329 * otherwise we failed.
330 * i = number of ordering[] entries left to output
331 * j = objs[] index of item we are outputting
332 * k = temp for scanning constraint list for item j
333 *--------------------
336 while (heapLength > 0)
338 /* Select object to output by removing largest heap member */
339 j = removeHeapElement(pendingHeap, heapLength--);
341 /* Output candidate to ordering[] */
343 /* Update beforeConstraints counts of its predecessors */
344 for (k = 0; k < obj->nDeps; k++)
346 int id = obj->dependencies[k];
348 if ((--beforeConstraints[id]) == 0)
349 addHeapElement(idMap[id], pendingHeap, heapLength++);
354 * If we failed, report the objects that couldn't be output; these are
355 * the ones with beforeConstraints[] still nonzero.
360 for (j = 1; j <= maxDumpId; j++)
362 if (beforeConstraints[j] != 0)
363 ordering[k++] = objs[idMap[j]];
370 free(beforeConstraints);
377 * Add an item to a heap (priority queue)
379 * heapLength is the current heap size; caller is responsible for increasing
380 * its value after the call. There must be sufficient storage at *heap.
383 addHeapElement(int val, int *heap, int heapLength)
388 * Sift-up the new entry, per Knuth 5.2.3 exercise 16. Note that Knuth
389 * is using 1-based array indexes, not 0-based.
394 int i = (j - 1) >> 1;
405 * Remove the largest item present in a heap (priority queue)
407 * heapLength is the current heap size; caller is responsible for decreasing
408 * its value after the call.
410 * We remove and return heap[0], which is always the largest element of
411 * the heap, and then "sift up" to maintain the heap invariant.
414 removeHeapElement(int *heap, int heapLength)
416 int result = heap[0];
420 if (--heapLength <= 0)
422 val = heap[heapLength]; /* value that must be reinserted */
423 i = 0; /* i is where the "hole" is */
430 if (j + 1 < heapLength &&
431 heap[j] < heap[j + 1])
443 * findDependencyLoops - identify loops in TopoSort's failure output,
444 * and pass each such loop to repairDependencyLoop() for action
446 * In general there may be many loops in the set of objects returned by
447 * TopoSort; for speed we should try to repair as many loops as we can
448 * before trying TopoSort again. We can safely repair loops that are
449 * disjoint (have no members in common); if we find overlapping loops
450 * then we repair only the first one found, because the action taken to
451 * repair the first might have repaired the other as well. (If not,
452 * we'll fix it on the next go-round.)
454 * objs[] lists the objects TopoSort couldn't sort
455 * nObjs is the number of such objects
456 * totObjs is the total number of objects in the universe
459 findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs)
462 * We use a workspace array, the initial part of which stores
463 * objects already processed, and the rest of which is used as
464 * temporary space to try to build a loop in. This is convenient
465 * because we do not care about loops involving already-processed
466 * objects (see notes above); we can easily reject such loops in
467 * findLoop() because of this representation. After we identify
468 * and process a loop, we can add it to the initial part of the
469 * workspace just by moving the boundary pointer.
471 * When we determine that an object is not part of any interesting
472 * loop, we also add it to the initial part of the workspace. This
473 * is not necessary for correctness, but saves later invocations of
474 * findLoop() from uselessly chasing references to such an object.
476 * We make the workspace large enough to hold all objects in the
477 * original universe. This is probably overkill, but it's provably
480 DumpableObject **workspace;
485 workspace = (DumpableObject **) malloc(totObjs * sizeof(DumpableObject *));
486 if (workspace == NULL)
487 exit_horribly(NULL, modulename, "out of memory\n");
491 for (i = 0; i < nObjs; i++)
493 DumpableObject *obj = objs[i];
496 workspace[initiallen] = NULL; /* see test below */
498 if (findLoop(obj, obj->dumpId, workspace, initiallen, &newlen))
500 /* Found a loop of length newlen - initiallen */
501 repairDependencyLoop(&workspace[initiallen], newlen - initiallen);
502 /* Add loop members to workspace */
509 * Didn't find a loop, but add this object to workspace anyway,
510 * unless it's already present. We piggyback on the test that
511 * findLoop() already did: it won't have tentatively added obj
512 * to workspace if it's already present.
514 if (workspace[initiallen] == obj)
519 /* We'd better have fixed at least one loop */
521 exit_horribly(NULL, modulename, "could not identify dependency loop\n");
527 * Recursively search for a circular dependency loop that doesn't include
528 * any existing workspace members.
530 * obj: object we are examining now
531 * startPoint: dumpId of starting object for the hoped-for circular loop
532 * workspace[]: work array for previously processed and current objects
533 * depth: number of valid entries in workspace[] at call
534 * newDepth: if successful, set to new number of workspace[] entries
536 * On success, *newDepth is set and workspace[] entries depth..*newDepth-1
537 * are filled with pointers to the members of the loop.
539 * Note: it is possible that the given starting object is a member of more
540 * than one cycle; if so, we will find an arbitrary one of the cycles.
543 findLoop(DumpableObject *obj,
545 DumpableObject **workspace,
552 * Reject if obj is already present in workspace. This test serves
553 * three purposes: it prevents us from finding loops that overlap
554 * previously-processed loops, it prevents us from going into infinite
555 * recursion if we are given a startPoint object that links to a cycle
556 * it's not a member of, and it guarantees that we can't overflow the
557 * allocated size of workspace[].
559 for (i = 0; i < depth; i++)
561 if (workspace[i] == obj)
565 * Okay, tentatively add obj to workspace
567 workspace[depth++] = obj;
569 * See if we've found a loop back to the desired startPoint; if so, done
571 for (i = 0; i < obj->nDeps; i++)
573 if (obj->dependencies[i] == startPoint)
580 * Recurse down each outgoing branch
582 for (i = 0; i < obj->nDeps; i++)
584 DumpableObject *nextobj = findObjectByDumpId(obj->dependencies[i]);
587 continue; /* ignore dependencies on undumped objects */
588 if (findLoop(nextobj,
600 * A user-defined datatype will have a dependency loop with each of its
601 * I/O functions (since those have the datatype as input or output).
602 * We want the dump ordering to be the input function, then any other
603 * I/O functions, then the datatype. So we break the circularity in
604 * favor of the functions, and add a dependency from any non-input
605 * function to the input function.
608 repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
610 TypeInfo *typeInfo = (TypeInfo *) typeobj;
611 FuncInfo *inputFuncInfo;
613 /* remove function's dependency on type */
614 removeObjectDependency(funcobj, typeobj->dumpId);
616 /* if this isn't the input function, make it depend on same */
617 if (funcobj->catId.oid == typeInfo->typinput)
618 return; /* it is the input function */
619 inputFuncInfo = findFuncByOid(typeInfo->typinput);
620 if (inputFuncInfo == NULL)
622 addObjectDependency(funcobj, inputFuncInfo->dobj.dumpId);
624 * Make sure the input function's dependency on type gets removed too;
625 * if it hasn't been done yet, we'd end up with loops involving the
626 * type and two or more functions, which repairDependencyLoop() is not
627 * smart enough to handle.
629 removeObjectDependency(&inputFuncInfo->dobj, typeobj->dumpId);
633 * Because we force a view to depend on its ON SELECT rule, while there
634 * will be an implicit dependency in the other direction, we need to break
635 * the loop. We can always do this by removing the implicit dependency.
638 repairViewRuleLoop(DumpableObject *viewobj,
639 DumpableObject *ruleobj)
641 /* remove rule's dependency on view */
642 removeObjectDependency(ruleobj, viewobj->dumpId);
646 * Because we make tables depend on their CHECK constraints, while there
647 * will be an automatic dependency in the other direction, we need to break
648 * the loop. If there are no other objects in the loop then we can remove
649 * the automatic dependency and leave the CHECK constraint non-separate.
652 repairTableConstraintLoop(DumpableObject *tableobj,
653 DumpableObject *constraintobj)
655 /* remove constraint's dependency on table */
656 removeObjectDependency(constraintobj, tableobj->dumpId);
660 * However, if there are other objects in the loop, we must break the loop
661 * by making the CHECK constraint a separately-dumped object.
663 * Because findLoop() finds shorter cycles before longer ones, it's likely
664 * that we will have previously fired repairTableConstraintLoop() and
665 * removed the constraint's dependency on the table. Put it back to ensure
666 * the constraint won't be emitted before the table...
669 repairTableConstraintMultiLoop(DumpableObject *tableobj,
670 DumpableObject *constraintobj)
672 /* remove table's dependency on constraint */
673 removeObjectDependency(tableobj, constraintobj->dumpId);
674 /* mark constraint as needing its own dump */
675 ((ConstraintInfo *) constraintobj)->separate = true;
676 /* put back constraint's dependency on table */
677 addObjectDependency(constraintobj, tableobj->dumpId);
681 * Attribute defaults behave exactly the same as CHECK constraints...
684 repairTableAttrDefLoop(DumpableObject *tableobj,
685 DumpableObject *attrdefobj)
687 /* remove attrdef's dependency on table */
688 removeObjectDependency(attrdefobj, tableobj->dumpId);
692 repairTableAttrDefMultiLoop(DumpableObject *tableobj,
693 DumpableObject *attrdefobj)
695 /* remove table's dependency on attrdef */
696 removeObjectDependency(tableobj, attrdefobj->dumpId);
697 /* mark attrdef as needing its own dump */
698 ((AttrDefInfo *) attrdefobj)->separate = true;
699 /* put back attrdef's dependency on table */
700 addObjectDependency(attrdefobj, tableobj->dumpId);
704 * CHECK constraints on domains work just like those on tables ...
707 repairDomainConstraintLoop(DumpableObject *domainobj,
708 DumpableObject *constraintobj)
710 /* remove constraint's dependency on domain */
711 removeObjectDependency(constraintobj, domainobj->dumpId);
715 repairDomainConstraintMultiLoop(DumpableObject *domainobj,
716 DumpableObject *constraintobj)
718 /* remove domain's dependency on constraint */
719 removeObjectDependency(domainobj, constraintobj->dumpId);
720 /* mark constraint as needing its own dump */
721 ((ConstraintInfo *) constraintobj)->separate = true;
722 /* put back constraint's dependency on domain */
723 addObjectDependency(constraintobj, domainobj->dumpId);
727 * Fix a dependency loop, or die trying ...
729 * This routine is mainly concerned with reducing the multiple ways that
730 * a loop might appear to common cases, which it passes off to the
731 * "fixer" routines above.
734 repairDependencyLoop(DumpableObject **loop,
740 /* Datatype and one of its I/O functions */
742 loop[0]->objType == DO_TYPE &&
743 loop[1]->objType == DO_FUNC)
745 repairTypeFuncLoop(loop[0], loop[1]);
749 loop[1]->objType == DO_TYPE &&
750 loop[0]->objType == DO_FUNC)
752 repairTypeFuncLoop(loop[1], loop[0]);
756 /* View and its ON SELECT rule */
758 loop[0]->objType == DO_TABLE &&
759 loop[1]->objType == DO_RULE &&
760 ((RuleInfo *) loop[1])->ev_type == '1' &&
761 ((RuleInfo *) loop[1])->is_instead)
763 repairViewRuleLoop(loop[0], loop[1]);
767 loop[1]->objType == DO_TABLE &&
768 loop[0]->objType == DO_RULE &&
769 ((RuleInfo *) loop[0])->ev_type == '1' &&
770 ((RuleInfo *) loop[0])->is_instead)
772 repairViewRuleLoop(loop[1], loop[0]);
776 /* Table and CHECK constraint */
778 loop[0]->objType == DO_TABLE &&
779 loop[1]->objType == DO_CONSTRAINT &&
780 ((ConstraintInfo *) loop[1])->contype == 'c' &&
781 ((ConstraintInfo *) loop[1])->contable == (TableInfo *) loop[0])
783 repairTableConstraintLoop(loop[0], loop[1]);
787 loop[1]->objType == DO_TABLE &&
788 loop[0]->objType == DO_CONSTRAINT &&
789 ((ConstraintInfo *) loop[0])->contype == 'c' &&
790 ((ConstraintInfo *) loop[0])->contable == (TableInfo *) loop[1])
792 repairTableConstraintLoop(loop[1], loop[0]);
796 /* Indirect loop involving table and CHECK constraint */
799 for (i = 0; i < nLoop; i++)
801 if (loop[i]->objType == DO_TABLE)
803 for (j = 0; j < nLoop; j++)
805 if (loop[j]->objType == DO_CONSTRAINT &&
806 ((ConstraintInfo *) loop[j])->contype == 'c' &&
807 ((ConstraintInfo *) loop[j])->contable == (TableInfo *) loop[i])
809 repairTableConstraintMultiLoop(loop[i], loop[j]);
817 /* Table and attribute default */
819 loop[0]->objType == DO_TABLE &&
820 loop[1]->objType == DO_ATTRDEF &&
821 ((AttrDefInfo *) loop[1])->adtable == (TableInfo *) loop[0])
823 repairTableAttrDefLoop(loop[0], loop[1]);
827 loop[1]->objType == DO_TABLE &&
828 loop[0]->objType == DO_ATTRDEF &&
829 ((AttrDefInfo *) loop[0])->adtable == (TableInfo *) loop[1])
831 repairTableAttrDefLoop(loop[1], loop[0]);
835 /* Indirect loop involving table and attribute default */
838 for (i = 0; i < nLoop; i++)
840 if (loop[i]->objType == DO_TABLE)
842 for (j = 0; j < nLoop; j++)
844 if (loop[j]->objType == DO_ATTRDEF &&
845 ((AttrDefInfo *) loop[j])->adtable == (TableInfo *) loop[i])
847 repairTableAttrDefMultiLoop(loop[i], loop[j]);
855 /* Domain and CHECK constraint */
857 loop[0]->objType == DO_TYPE &&
858 loop[1]->objType == DO_CONSTRAINT &&
859 ((ConstraintInfo *) loop[1])->contype == 'c' &&
860 ((ConstraintInfo *) loop[1])->condomain == (TypeInfo *) loop[0])
862 repairDomainConstraintLoop(loop[0], loop[1]);
866 loop[1]->objType == DO_TYPE &&
867 loop[0]->objType == DO_CONSTRAINT &&
868 ((ConstraintInfo *) loop[0])->contype == 'c' &&
869 ((ConstraintInfo *) loop[0])->condomain == (TypeInfo *) loop[1])
871 repairDomainConstraintLoop(loop[1], loop[0]);
875 /* Indirect loop involving domain and CHECK constraint */
878 for (i = 0; i < nLoop; i++)
880 if (loop[i]->objType == DO_TYPE)
882 for (j = 0; j < nLoop; j++)
884 if (loop[j]->objType == DO_CONSTRAINT &&
885 ((ConstraintInfo *) loop[j])->contype == 'c' &&
886 ((ConstraintInfo *) loop[j])->condomain == (TypeInfo *) loop[i])
888 repairDomainConstraintMultiLoop(loop[i], loop[j]);
897 * If we can't find a principled way to break the loop, complain and
898 * break it in an arbitrary fashion.
900 write_msg(modulename, "WARNING: could not resolve dependency loop among these items:\n");
901 for (i = 0; i < nLoop; i++)
905 describeDumpableObject(loop[i], buf, sizeof(buf));
906 write_msg(modulename, " %s\n", buf);
908 removeObjectDependency(loop[0], loop[1]->dumpId);
912 * Describe a dumpable object usefully for errors
914 * This should probably go somewhere else...
917 describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
919 switch (obj->objType)
922 snprintf(buf, bufsize,
923 "SCHEMA %s (ID %d OID %u)",
924 obj->name, obj->dumpId, obj->catId.oid);
927 snprintf(buf, bufsize,
928 "TYPE %s (ID %d OID %u)",
929 obj->name, obj->dumpId, obj->catId.oid);
932 snprintf(buf, bufsize,
933 "FUNCTION %s (ID %d OID %u)",
934 obj->name, obj->dumpId, obj->catId.oid);
937 snprintf(buf, bufsize,
938 "AGGREGATE %s (ID %d OID %u)",
939 obj->name, obj->dumpId, obj->catId.oid);
942 snprintf(buf, bufsize,
943 "OPERATOR %s (ID %d OID %u)",
944 obj->name, obj->dumpId, obj->catId.oid);
947 snprintf(buf, bufsize,
948 "OPERATOR CLASS %s (ID %d OID %u)",
949 obj->name, obj->dumpId, obj->catId.oid);
952 snprintf(buf, bufsize,
953 "CONVERSION %s (ID %d OID %u)",
954 obj->name, obj->dumpId, obj->catId.oid);
957 snprintf(buf, bufsize,
958 "TABLE %s (ID %d OID %u)",
959 obj->name, obj->dumpId, obj->catId.oid);
962 snprintf(buf, bufsize,
963 "ATTRDEF %s.%s (ID %d OID %u)",
964 ((AttrDefInfo *) obj)->adtable->dobj.name,
965 ((AttrDefInfo *) obj)->adtable->attnames[((AttrDefInfo *) obj)->adnum - 1],
966 obj->dumpId, obj->catId.oid);
969 snprintf(buf, bufsize,
970 "INDEX %s (ID %d OID %u)",
971 obj->name, obj->dumpId, obj->catId.oid);
974 snprintf(buf, bufsize,
975 "RULE %s (ID %d OID %u)",
976 obj->name, obj->dumpId, obj->catId.oid);
979 snprintf(buf, bufsize,
980 "TRIGGER %s (ID %d OID %u)",
981 obj->name, obj->dumpId, obj->catId.oid);
984 snprintf(buf, bufsize,
985 "CONSTRAINT %s (ID %d OID %u)",
986 obj->name, obj->dumpId, obj->catId.oid);
988 case DO_FK_CONSTRAINT:
989 snprintf(buf, bufsize,
990 "FK CONSTRAINT %s (ID %d OID %u)",
991 obj->name, obj->dumpId, obj->catId.oid);
994 snprintf(buf, bufsize,
995 "PROCEDURAL LANGUAGE %s (ID %d OID %u)",
996 obj->name, obj->dumpId, obj->catId.oid);
999 snprintf(buf, bufsize,
1000 "CAST %u to %u (ID %d OID %u)",
1001 ((CastInfo *) obj)->castsource,
1002 ((CastInfo *) obj)->casttarget,
1003 obj->dumpId, obj->catId.oid);
1006 snprintf(buf, bufsize,
1007 "TABLE DATA %s (ID %d OID %u)",
1008 obj->name, obj->dumpId, obj->catId.oid);
1011 snprintf(buf, bufsize,
1012 "TABLE TYPE %s (ID %d OID %u)",
1013 obj->name, obj->dumpId, obj->catId.oid);
1016 snprintf(buf, bufsize,
1021 /* shouldn't get here */
1022 snprintf(buf, bufsize,
1023 "object type %d (ID %d OID %u)",
1025 obj->dumpId, obj->catId.oid);