PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pg_dump_sort.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_dump_sort.c
4  * Sort the items of a dump into a safe order for dumping
5  *
6  *
7  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  * src/bin/pg_dump/pg_dump_sort.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres_fe.h"
17 
18 #include "pg_backup_archiver.h"
19 #include "pg_backup_utils.h"
20 #include "pg_dump.h"
21 
22 /* translator: this is a module name */
23 static const char *modulename = gettext_noop("sorter");
24 
25 /*
26  * Sort priority for database object types.
27  * Objects are sorted by type, and within a type by name.
28  *
29  * NOTE: object-type priorities must match the section assignments made in
30  * pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY,
31  * POST_DATA objects must sort after DO_POST_DATA_BOUNDARY, and DATA objects
32  * must sort between them.
33  */
34 static const int dbObjectTypePriority[] =
35 {
36  1, /* DO_NAMESPACE */
37  4, /* DO_EXTENSION */
38  5, /* DO_TYPE */
39  5, /* DO_SHELL_TYPE */
40  6, /* DO_FUNC */
41  7, /* DO_AGG */
42  8, /* DO_OPERATOR */
43  8, /* DO_ACCESS_METHOD */
44  9, /* DO_OPCLASS */
45  9, /* DO_OPFAMILY */
46  3, /* DO_COLLATION */
47  11, /* DO_CONVERSION */
48  18, /* DO_TABLE */
49  20, /* DO_ATTRDEF */
50  28, /* DO_INDEX */
51  29, /* DO_RULE */
52  30, /* DO_TRIGGER */
53  27, /* DO_CONSTRAINT */
54  31, /* DO_FK_CONSTRAINT */
55  2, /* DO_PROCLANG */
56  10, /* DO_CAST */
57  23, /* DO_TABLE_DATA */
58  24, /* DO_SEQUENCE_SET */
59  19, /* DO_DUMMY_TYPE */
60  12, /* DO_TSPARSER */
61  14, /* DO_TSDICT */
62  13, /* DO_TSTEMPLATE */
63  15, /* DO_TSCONFIG */
64  16, /* DO_FDW */
65  17, /* DO_FOREIGN_SERVER */
66  32, /* DO_DEFAULT_ACL */
67  3, /* DO_TRANSFORM */
68  21, /* DO_BLOB */
69  25, /* DO_BLOB_DATA */
70  22, /* DO_PRE_DATA_BOUNDARY */
71  26, /* DO_POST_DATA_BOUNDARY */
72  33, /* DO_EVENT_TRIGGER */
73  34, /* DO_REFRESH_MATVIEW */
74  35, /* DO_POLICY */
75  36, /* DO_PUBLICATION */
76  37, /* DO_PUBLICATION_REL */
77  38 /* DO_SUBSCRIPTION */
78 };
79 
82 
83 
84 static int DOTypeNameCompare(const void *p1, const void *p2);
85 static bool TopoSort(DumpableObject **objs,
86  int numObjs,
87  DumpableObject **ordering,
88  int *nOrdering);
89 static void addHeapElement(int val, int *heap, int heapLength);
90 static int removeHeapElement(int *heap, int heapLength);
91 static void findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs);
92 static int findLoop(DumpableObject *obj,
93  DumpId startPoint,
94  bool *processed,
95  DumpId *searchFailed,
96  DumpableObject **workspace,
97  int depth);
98 static void repairDependencyLoop(DumpableObject **loop,
99  int nLoop);
100 static void describeDumpableObject(DumpableObject *obj,
101  char *buf, int bufsize);
102 
103 static int DOSizeCompare(const void *p1, const void *p2);
104 
105 static int
107 {
108  int i;
109 
110  for (i = 0; i < numObjs; i++)
111  if (objs[i]->objType == type)
112  return i;
113  return -1;
114 }
115 
116 static int
117 findFirstDifferentType(DumpableObjectType type, DumpableObject **objs, int numObjs, int start)
118 {
119  int i;
120 
121  for (i = start; i < numObjs; i++)
122  if (objs[i]->objType != type)
123  return i;
124  return numObjs - 1;
125 }
126 
127 /*
128  * When we do a parallel dump, we want to start with the largest items first.
129  *
130  * Say we have the objects in this order:
131  * ....DDDDD....III....
132  *
133  * with D = Table data, I = Index, . = other object
134  *
135  * This sorting function now takes each of the D or I blocks and sorts them
136  * according to their size.
137  */
138 void
140 {
141  int startIdx,
142  endIdx;
143  void *startPtr;
144 
145  if (numObjs <= 1)
146  return;
147 
148  startIdx = findFirstEqualType(DO_TABLE_DATA, objs, numObjs);
149  if (startIdx >= 0)
150  {
151  endIdx = findFirstDifferentType(DO_TABLE_DATA, objs, numObjs, startIdx);
152  startPtr = objs + startIdx;
153  qsort(startPtr, endIdx - startIdx, sizeof(DumpableObject *),
154  DOSizeCompare);
155  }
156 
157  startIdx = findFirstEqualType(DO_INDEX, objs, numObjs);
158  if (startIdx >= 0)
159  {
160  endIdx = findFirstDifferentType(DO_INDEX, objs, numObjs, startIdx);
161  startPtr = objs + startIdx;
162  qsort(startPtr, endIdx - startIdx, sizeof(DumpableObject *),
163  DOSizeCompare);
164  }
165 }
166 
167 static int
168 DOSizeCompare(const void *p1, const void *p2)
169 {
170  DumpableObject *obj1 = *(DumpableObject **) p1;
171  DumpableObject *obj2 = *(DumpableObject **) p2;
172  int obj1_size = 0;
173  int obj2_size = 0;
174 
175  if (obj1->objType == DO_TABLE_DATA)
176  obj1_size = ((TableDataInfo *) obj1)->tdtable->relpages;
177  if (obj1->objType == DO_INDEX)
178  obj1_size = ((IndxInfo *) obj1)->relpages;
179 
180  if (obj2->objType == DO_TABLE_DATA)
181  obj2_size = ((TableDataInfo *) obj2)->tdtable->relpages;
182  if (obj2->objType == DO_INDEX)
183  obj2_size = ((IndxInfo *) obj2)->relpages;
184 
185  /* we want to see the biggest item go first */
186  if (obj1_size > obj2_size)
187  return -1;
188  if (obj2_size > obj1_size)
189  return 1;
190 
191  return 0;
192 }
193 
194 /*
195  * Sort the given objects into a type/name-based ordering
196  *
197  * Normally this is just the starting point for the dependency-based
198  * ordering.
199  */
200 void
202 {
203  if (numObjs > 1)
204  qsort((void *) objs, numObjs, sizeof(DumpableObject *),
206 }
207 
208 static int
209 DOTypeNameCompare(const void *p1, const void *p2)
210 {
211  DumpableObject *obj1 = *(DumpableObject *const *) p1;
212  DumpableObject *obj2 = *(DumpableObject *const *) p2;
213  int cmpval;
214 
215  /* Sort by type */
216  cmpval = dbObjectTypePriority[obj1->objType] -
218 
219  if (cmpval != 0)
220  return cmpval;
221 
222  /*
223  * Sort by namespace. Note that all objects of the same type should
224  * either have or not have a namespace link, so we needn't be fancy about
225  * cases where one link is null and the other not.
226  */
227  if (obj1->namespace && obj2->namespace)
228  {
229  cmpval = strcmp(obj1->namespace->dobj.name,
230  obj2->namespace->dobj.name);
231  if (cmpval != 0)
232  return cmpval;
233  }
234 
235  /* Sort by name */
236  cmpval = strcmp(obj1->name, obj2->name);
237  if (cmpval != 0)
238  return cmpval;
239 
240  /* To have a stable sort order, break ties for some object types */
241  if (obj1->objType == DO_FUNC || obj1->objType == DO_AGG)
242  {
243  FuncInfo *fobj1 = *(FuncInfo *const *) p1;
244  FuncInfo *fobj2 = *(FuncInfo *const *) p2;
245  int i;
246 
247  cmpval = fobj1->nargs - fobj2->nargs;
248  if (cmpval != 0)
249  return cmpval;
250  for (i = 0; i < fobj1->nargs; i++)
251  {
252  TypeInfo *argtype1 = findTypeByOid(fobj1->argtypes[i]);
253  TypeInfo *argtype2 = findTypeByOid(fobj2->argtypes[i]);
254 
255  if (argtype1 && argtype2)
256  {
257  if (argtype1->dobj.namespace && argtype2->dobj.namespace)
258  {
259  cmpval = strcmp(argtype1->dobj.namespace->dobj.name,
260  argtype2->dobj.namespace->dobj.name);
261  if (cmpval != 0)
262  return cmpval;
263  }
264  cmpval = strcmp(argtype1->dobj.name, argtype2->dobj.name);
265  if (cmpval != 0)
266  return cmpval;
267  }
268  }
269  }
270  else if (obj1->objType == DO_OPERATOR)
271  {
272  OprInfo *oobj1 = *(OprInfo *const *) p1;
273  OprInfo *oobj2 = *(OprInfo *const *) p2;
274 
275  /* oprkind is 'l', 'r', or 'b'; this sorts prefix, postfix, infix */
276  cmpval = (oobj2->oprkind - oobj1->oprkind);
277  if (cmpval != 0)
278  return cmpval;
279  }
280  else if (obj1->objType == DO_ATTRDEF)
281  {
282  AttrDefInfo *adobj1 = *(AttrDefInfo *const *) p1;
283  AttrDefInfo *adobj2 = *(AttrDefInfo *const *) p2;
284 
285  cmpval = (adobj1->adnum - adobj2->adnum);
286  if (cmpval != 0)
287  return cmpval;
288  }
289 
290  /* Usually shouldn't get here, but if we do, sort by OID */
291  return oidcmp(obj1->catId.oid, obj2->catId.oid);
292 }
293 
294 
295 /*
296  * Sort the given objects into a safe dump order using dependency
297  * information (to the extent we have it available).
298  *
299  * The DumpIds of the PRE_DATA_BOUNDARY and POST_DATA_BOUNDARY objects are
300  * passed in separately, in case we need them during dependency loop repair.
301  */
302 void
304  DumpId preBoundaryId, DumpId postBoundaryId)
305 {
306  DumpableObject **ordering;
307  int nOrdering;
308 
309  if (numObjs <= 0) /* can't happen anymore ... */
310  return;
311 
312  /*
313  * Saving the boundary IDs in static variables is a bit grotty, but seems
314  * better than adding them to parameter lists of subsidiary functions.
315  */
316  preDataBoundId = preBoundaryId;
317  postDataBoundId = postBoundaryId;
318 
319  ordering = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
320  while (!TopoSort(objs, numObjs, ordering, &nOrdering))
321  findDependencyLoops(ordering, nOrdering, numObjs);
322 
323  memcpy(objs, ordering, numObjs * sizeof(DumpableObject *));
324 
325  free(ordering);
326 }
327 
328 /*
329  * TopoSort -- topological sort of a dump list
330  *
331  * Generate a re-ordering of the dump list that satisfies all the dependency
332  * constraints shown in the dump list. (Each such constraint is a fact of a
333  * partial ordering.) Minimize rearrangement of the list not needed to
334  * achieve the partial ordering.
335  *
336  * The input is the list of numObjs objects in objs[]. This list is not
337  * modified.
338  *
339  * Returns TRUE if able to build an ordering that satisfies all the
340  * constraints, FALSE if not (there are contradictory constraints).
341  *
342  * On success (TRUE result), ordering[] is filled with a sorted array of
343  * DumpableObject pointers, of length equal to the input list length.
344  *
345  * On failure (FALSE result), ordering[] is filled with an unsorted array of
346  * DumpableObject pointers of length *nOrdering, listing the objects that
347  * prevented the sort from being completed. In general, these objects either
348  * participate directly in a dependency cycle, or are depended on by objects
349  * that are in a cycle. (The latter objects are not actually problematic,
350  * but it takes further analysis to identify which are which.)
351  *
352  * The caller is responsible for allocating sufficient space at *ordering.
353  */
354 static bool
356  int numObjs,
357  DumpableObject **ordering, /* output argument */
358  int *nOrdering) /* output argument */
359 {
360  DumpId maxDumpId = getMaxDumpId();
361  int *pendingHeap;
362  int *beforeConstraints;
363  int *idMap;
364  DumpableObject *obj;
365  int heapLength;
366  int i,
367  j,
368  k;
369 
370  /*
371  * This is basically the same algorithm shown for topological sorting in
372  * Knuth's Volume 1. However, we would like to minimize unnecessary
373  * rearrangement of the input ordering; that is, when we have a choice of
374  * which item to output next, we always want to take the one highest in
375  * the original list. Therefore, instead of maintaining an unordered
376  * linked list of items-ready-to-output as Knuth does, we maintain a heap
377  * of their item numbers, which we can use as a priority queue. This
378  * turns the algorithm from O(N) to O(N log N) because each insertion or
379  * removal of a heap item takes O(log N) time. However, that's still
380  * plenty fast enough for this application.
381  */
382 
383  *nOrdering = numObjs; /* for success return */
384 
385  /* Eliminate the null case */
386  if (numObjs <= 0)
387  return true;
388 
389  /* Create workspace for the above-described heap */
390  pendingHeap = (int *) pg_malloc(numObjs * sizeof(int));
391 
392  /*
393  * Scan the constraints, and for each item in the input, generate a count
394  * of the number of constraints that say it must be before something else.
395  * The count for the item with dumpId j is stored in beforeConstraints[j].
396  * We also make a map showing the input-order index of the item with
397  * dumpId j.
398  */
399  beforeConstraints = (int *) pg_malloc((maxDumpId + 1) * sizeof(int));
400  memset(beforeConstraints, 0, (maxDumpId + 1) * sizeof(int));
401  idMap = (int *) pg_malloc((maxDumpId + 1) * sizeof(int));
402  for (i = 0; i < numObjs; i++)
403  {
404  obj = objs[i];
405  j = obj->dumpId;
406  if (j <= 0 || j > maxDumpId)
407  exit_horribly(modulename, "invalid dumpId %d\n", j);
408  idMap[j] = i;
409  for (j = 0; j < obj->nDeps; j++)
410  {
411  k = obj->dependencies[j];
412  if (k <= 0 || k > maxDumpId)
413  exit_horribly(modulename, "invalid dependency %d\n", k);
414  beforeConstraints[k]++;
415  }
416  }
417 
418  /*
419  * Now initialize the heap of items-ready-to-output by filling it with the
420  * indexes of items that already have beforeConstraints[id] == 0.
421  *
422  * The essential property of a heap is heap[(j-1)/2] >= heap[j] for each j
423  * in the range 1..heapLength-1 (note we are using 0-based subscripts
424  * here, while the discussion in Knuth assumes 1-based subscripts). So, if
425  * we simply enter the indexes into pendingHeap[] in decreasing order, we
426  * a-fortiori have the heap invariant satisfied at completion of this
427  * loop, and don't need to do any sift-up comparisons.
428  */
429  heapLength = 0;
430  for (i = numObjs; --i >= 0;)
431  {
432  if (beforeConstraints[objs[i]->dumpId] == 0)
433  pendingHeap[heapLength++] = i;
434  }
435 
436  /*--------------------
437  * Now emit objects, working backwards in the output list. At each step,
438  * we use the priority heap to select the last item that has no remaining
439  * before-constraints. We remove that item from the heap, output it to
440  * ordering[], and decrease the beforeConstraints count of each of the
441  * items it was constrained against. Whenever an item's beforeConstraints
442  * count is thereby decreased to zero, we insert it into the priority heap
443  * to show that it is a candidate to output. We are done when the heap
444  * becomes empty; if we have output every element then we succeeded,
445  * otherwise we failed.
446  * i = number of ordering[] entries left to output
447  * j = objs[] index of item we are outputting
448  * k = temp for scanning constraint list for item j
449  *--------------------
450  */
451  i = numObjs;
452  while (heapLength > 0)
453  {
454  /* Select object to output by removing largest heap member */
455  j = removeHeapElement(pendingHeap, heapLength--);
456  obj = objs[j];
457  /* Output candidate to ordering[] */
458  ordering[--i] = obj;
459  /* Update beforeConstraints counts of its predecessors */
460  for (k = 0; k < obj->nDeps; k++)
461  {
462  int id = obj->dependencies[k];
463 
464  if ((--beforeConstraints[id]) == 0)
465  addHeapElement(idMap[id], pendingHeap, heapLength++);
466  }
467  }
468 
469  /*
470  * If we failed, report the objects that couldn't be output; these are the
471  * ones with beforeConstraints[] still nonzero.
472  */
473  if (i != 0)
474  {
475  k = 0;
476  for (j = 1; j <= maxDumpId; j++)
477  {
478  if (beforeConstraints[j] != 0)
479  ordering[k++] = objs[idMap[j]];
480  }
481  *nOrdering = k;
482  }
483 
484  /* Done */
485  free(pendingHeap);
486  free(beforeConstraints);
487  free(idMap);
488 
489  return (i == 0);
490 }
491 
492 /*
493  * Add an item to a heap (priority queue)
494  *
495  * heapLength is the current heap size; caller is responsible for increasing
496  * its value after the call. There must be sufficient storage at *heap.
497  */
498 static void
499 addHeapElement(int val, int *heap, int heapLength)
500 {
501  int j;
502 
503  /*
504  * Sift-up the new entry, per Knuth 5.2.3 exercise 16. Note that Knuth is
505  * using 1-based array indexes, not 0-based.
506  */
507  j = heapLength;
508  while (j > 0)
509  {
510  int i = (j - 1) >> 1;
511 
512  if (val <= heap[i])
513  break;
514  heap[j] = heap[i];
515  j = i;
516  }
517  heap[j] = val;
518 }
519 
520 /*
521  * Remove the largest item present in a heap (priority queue)
522  *
523  * heapLength is the current heap size; caller is responsible for decreasing
524  * its value after the call.
525  *
526  * We remove and return heap[0], which is always the largest element of
527  * the heap, and then "sift up" to maintain the heap invariant.
528  */
529 static int
530 removeHeapElement(int *heap, int heapLength)
531 {
532  int result = heap[0];
533  int val;
534  int i;
535 
536  if (--heapLength <= 0)
537  return result;
538  val = heap[heapLength]; /* value that must be reinserted */
539  i = 0; /* i is where the "hole" is */
540  for (;;)
541  {
542  int j = 2 * i + 1;
543 
544  if (j >= heapLength)
545  break;
546  if (j + 1 < heapLength &&
547  heap[j] < heap[j + 1])
548  j++;
549  if (val >= heap[j])
550  break;
551  heap[i] = heap[j];
552  i = j;
553  }
554  heap[i] = val;
555  return result;
556 }
557 
558 /*
559  * findDependencyLoops - identify loops in TopoSort's failure output,
560  * and pass each such loop to repairDependencyLoop() for action
561  *
562  * In general there may be many loops in the set of objects returned by
563  * TopoSort; for speed we should try to repair as many loops as we can
564  * before trying TopoSort again. We can safely repair loops that are
565  * disjoint (have no members in common); if we find overlapping loops
566  * then we repair only the first one found, because the action taken to
567  * repair the first might have repaired the other as well. (If not,
568  * we'll fix it on the next go-round.)
569  *
570  * objs[] lists the objects TopoSort couldn't sort
571  * nObjs is the number of such objects
572  * totObjs is the total number of objects in the universe
573  */
574 static void
575 findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs)
576 {
577  /*
578  * We use three data structures here:
579  *
580  * processed[] is a bool array indexed by dump ID, marking the objects
581  * already processed during this invocation of findDependencyLoops().
582  *
583  * searchFailed[] is another array indexed by dump ID. searchFailed[j] is
584  * set to dump ID k if we have proven that there is no dependency path
585  * leading from object j back to start point k. This allows us to skip
586  * useless searching when there are multiple dependency paths from k to j,
587  * which is a common situation. We could use a simple bool array for
588  * this, but then we'd need to re-zero it for each start point, resulting
589  * in O(N^2) zeroing work. Using the start point's dump ID as the "true"
590  * value lets us skip clearing the array before we consider the next start
591  * point.
592  *
593  * workspace[] is an array of DumpableObject pointers, in which we try to
594  * build lists of objects constituting loops. We make workspace[] large
595  * enough to hold all the objects in TopoSort's output, which is huge
596  * overkill in most cases but could theoretically be necessary if there is
597  * a single dependency chain linking all the objects.
598  */
599  bool *processed;
600  DumpId *searchFailed;
601  DumpableObject **workspace;
602  bool fixedloop;
603  int i;
604 
605  processed = (bool *) pg_malloc0((getMaxDumpId() + 1) * sizeof(bool));
606  searchFailed = (DumpId *) pg_malloc0((getMaxDumpId() + 1) * sizeof(DumpId));
607  workspace = (DumpableObject **) pg_malloc(totObjs * sizeof(DumpableObject *));
608  fixedloop = false;
609 
610  for (i = 0; i < nObjs; i++)
611  {
612  DumpableObject *obj = objs[i];
613  int looplen;
614  int j;
615 
616  looplen = findLoop(obj,
617  obj->dumpId,
618  processed,
619  searchFailed,
620  workspace,
621  0);
622 
623  if (looplen > 0)
624  {
625  /* Found a loop, repair it */
626  repairDependencyLoop(workspace, looplen);
627  fixedloop = true;
628  /* Mark loop members as processed */
629  for (j = 0; j < looplen; j++)
630  processed[workspace[j]->dumpId] = true;
631  }
632  else
633  {
634  /*
635  * There's no loop starting at this object, but mark it processed
636  * anyway. This is not necessary for correctness, but saves later
637  * invocations of findLoop() from uselessly chasing references to
638  * such an object.
639  */
640  processed[obj->dumpId] = true;
641  }
642  }
643 
644  /* We'd better have fixed at least one loop */
645  if (!fixedloop)
646  exit_horribly(modulename, "could not identify dependency loop\n");
647 
648  free(workspace);
649  free(searchFailed);
650  free(processed);
651 }
652 
653 /*
654  * Recursively search for a circular dependency loop that doesn't include
655  * any already-processed objects.
656  *
657  * obj: object we are examining now
658  * startPoint: dumpId of starting object for the hoped-for circular loop
659  * processed[]: flag array marking already-processed objects
660  * searchFailed[]: flag array marking already-unsuccessfully-visited objects
661  * workspace[]: work array in which we are building list of loop members
662  * depth: number of valid entries in workspace[] at call
663  *
664  * On success, the length of the loop is returned, and workspace[] is filled
665  * with pointers to the members of the loop. On failure, we return 0.
666  *
667  * Note: it is possible that the given starting object is a member of more
668  * than one cycle; if so, we will find an arbitrary one of the cycles.
669  */
670 static int
672  DumpId startPoint,
673  bool *processed,
674  DumpId *searchFailed,
675  DumpableObject **workspace,
676  int depth)
677 {
678  int i;
679 
680  /*
681  * Reject if obj is already processed. This test prevents us from finding
682  * loops that overlap previously-processed loops.
683  */
684  if (processed[obj->dumpId])
685  return 0;
686 
687  /*
688  * If we've already proven there is no path from this object back to the
689  * startPoint, forget it.
690  */
691  if (searchFailed[obj->dumpId] == startPoint)
692  return 0;
693 
694  /*
695  * Reject if obj is already present in workspace. This test prevents us
696  * from going into infinite recursion if we are given a startPoint object
697  * that links to a cycle it's not a member of, and it guarantees that we
698  * can't overflow the allocated size of workspace[].
699  */
700  for (i = 0; i < depth; i++)
701  {
702  if (workspace[i] == obj)
703  return 0;
704  }
705 
706  /*
707  * Okay, tentatively add obj to workspace
708  */
709  workspace[depth++] = obj;
710 
711  /*
712  * See if we've found a loop back to the desired startPoint; if so, done
713  */
714  for (i = 0; i < obj->nDeps; i++)
715  {
716  if (obj->dependencies[i] == startPoint)
717  return depth;
718  }
719 
720  /*
721  * Recurse down each outgoing branch
722  */
723  for (i = 0; i < obj->nDeps; i++)
724  {
725  DumpableObject *nextobj = findObjectByDumpId(obj->dependencies[i]);
726  int newDepth;
727 
728  if (!nextobj)
729  continue; /* ignore dependencies on undumped objects */
730  newDepth = findLoop(nextobj,
731  startPoint,
732  processed,
733  searchFailed,
734  workspace,
735  depth);
736  if (newDepth > 0)
737  return newDepth;
738  }
739 
740  /*
741  * Remember there is no path from here back to startPoint
742  */
743  searchFailed[obj->dumpId] = startPoint;
744 
745  return 0;
746 }
747 
748 /*
749  * A user-defined datatype will have a dependency loop with each of its
750  * I/O functions (since those have the datatype as input or output).
751  * Similarly, a range type will have a loop with its canonicalize function,
752  * if any. Break the loop by making the function depend on the associated
753  * shell type, instead.
754  */
755 static void
757 {
758  TypeInfo *typeInfo = (TypeInfo *) typeobj;
759 
760  /* remove function's dependency on type */
761  removeObjectDependency(funcobj, typeobj->dumpId);
762 
763  /* add function's dependency on shell type, instead */
764  if (typeInfo->shellType)
765  {
766  addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
767 
768  /*
769  * Mark shell type (always including the definition, as we need the
770  * shell type defined to identify the function fully) as to be dumped
771  * if any such function is
772  */
773  if (funcobj->dump)
774  typeInfo->shellType->dobj.dump = funcobj->dump |
776  }
777 }
778 
779 /*
780  * Because we force a view to depend on its ON SELECT rule, while there
781  * will be an implicit dependency in the other direction, we need to break
782  * the loop. If there are no other objects in the loop then we can remove
783  * the implicit dependency and leave the ON SELECT rule non-separate.
784  * This applies to matviews, as well.
785  */
786 static void
788  DumpableObject *ruleobj)
789 {
790  /* remove rule's dependency on view */
791  removeObjectDependency(ruleobj, viewobj->dumpId);
792  /* flags on the two objects are already set correctly for this case */
793 }
794 
795 /*
796  * However, if there are other objects in the loop, we must break the loop
797  * by making the ON SELECT rule a separately-dumped object.
798  *
799  * Because findLoop() finds shorter cycles before longer ones, it's likely
800  * that we will have previously fired repairViewRuleLoop() and removed the
801  * rule's dependency on the view. Put it back to ensure the rule won't be
802  * emitted before the view.
803  *
804  * Note: this approach does *not* work for matviews, at the moment.
805  */
806 static void
808  DumpableObject *ruleobj)
809 {
810  TableInfo *viewinfo = (TableInfo *) viewobj;
811  RuleInfo *ruleinfo = (RuleInfo *) ruleobj;
812 
813  /* remove view's dependency on rule */
814  removeObjectDependency(viewobj, ruleobj->dumpId);
815  /* mark view to be printed with a dummy definition */
816  viewinfo->dummy_view = true;
817  /* mark rule as needing its own dump */
818  ruleinfo->separate = true;
819  /* put back rule's dependency on view */
820  addObjectDependency(ruleobj, viewobj->dumpId);
821  /* now that rule is separate, it must be post-data */
823 }
824 
825 /*
826  * If a matview is involved in a multi-object loop, we can't currently fix
827  * that by splitting off the rule. As a stopgap, we try to fix it by
828  * dropping the constraint that the matview be dumped in the pre-data section.
829  * This is sufficient to handle cases where a matview depends on some unique
830  * index, as can happen if it has a GROUP BY for example.
831  *
832  * Note that the "next object" is not necessarily the matview itself;
833  * it could be the matview's rowtype, for example. We may come through here
834  * several times while removing all the pre-data linkages.
835  */
836 static void
838  DumpableObject *boundaryobj,
839  DumpableObject *nextobj)
840 {
841  TableInfo *matviewinfo = (TableInfo *) matviewobj;
842 
843  /* remove boundary's dependency on object after it in loop */
844  removeObjectDependency(boundaryobj, nextobj->dumpId);
845  /* mark matview as postponed into post-data section */
846  matviewinfo->postponed_def = true;
847 }
848 
849 /*
850  * Because we make tables depend on their CHECK constraints, while there
851  * will be an automatic dependency in the other direction, we need to break
852  * the loop. If there are no other objects in the loop then we can remove
853  * the automatic dependency and leave the CHECK constraint non-separate.
854  */
855 static void
857  DumpableObject *constraintobj)
858 {
859  /* remove constraint's dependency on table */
860  removeObjectDependency(constraintobj, tableobj->dumpId);
861 }
862 
863 /*
864  * However, if there are other objects in the loop, we must break the loop
865  * by making the CHECK constraint a separately-dumped object.
866  *
867  * Because findLoop() finds shorter cycles before longer ones, it's likely
868  * that we will have previously fired repairTableConstraintLoop() and
869  * removed the constraint's dependency on the table. Put it back to ensure
870  * the constraint won't be emitted before the table...
871  */
872 static void
874  DumpableObject *constraintobj)
875 {
876  /* remove table's dependency on constraint */
877  removeObjectDependency(tableobj, constraintobj->dumpId);
878  /* mark constraint as needing its own dump */
879  ((ConstraintInfo *) constraintobj)->separate = true;
880  /* put back constraint's dependency on table */
881  addObjectDependency(constraintobj, tableobj->dumpId);
882  /* now that constraint is separate, it must be post-data */
883  addObjectDependency(constraintobj, postDataBoundId);
884 }
885 
886 /*
887  * Attribute defaults behave exactly the same as CHECK constraints...
888  */
889 static void
891  DumpableObject *attrdefobj)
892 {
893  /* remove attrdef's dependency on table */
894  removeObjectDependency(attrdefobj, tableobj->dumpId);
895 }
896 
897 static void
899  DumpableObject *attrdefobj)
900 {
901  /* remove table's dependency on attrdef */
902  removeObjectDependency(tableobj, attrdefobj->dumpId);
903  /* mark attrdef as needing its own dump */
904  ((AttrDefInfo *) attrdefobj)->separate = true;
905  /* put back attrdef's dependency on table */
906  addObjectDependency(attrdefobj, tableobj->dumpId);
907 }
908 
909 /*
910  * CHECK constraints on domains work just like those on tables ...
911  */
912 static void
914  DumpableObject *constraintobj)
915 {
916  /* remove constraint's dependency on domain */
917  removeObjectDependency(constraintobj, domainobj->dumpId);
918 }
919 
920 static void
922  DumpableObject *constraintobj)
923 {
924  /* remove domain's dependency on constraint */
925  removeObjectDependency(domainobj, constraintobj->dumpId);
926  /* mark constraint as needing its own dump */
927  ((ConstraintInfo *) constraintobj)->separate = true;
928  /* put back constraint's dependency on domain */
929  addObjectDependency(constraintobj, domainobj->dumpId);
930  /* now that constraint is separate, it must be post-data */
931  addObjectDependency(constraintobj, postDataBoundId);
932 }
933 
934 /*
935  * Fix a dependency loop, or die trying ...
936  *
937  * This routine is mainly concerned with reducing the multiple ways that
938  * a loop might appear to common cases, which it passes off to the
939  * "fixer" routines above.
940  */
941 static void
943  int nLoop)
944 {
945  int i,
946  j;
947 
948  /* Datatype and one of its I/O or canonicalize functions */
949  if (nLoop == 2 &&
950  loop[0]->objType == DO_TYPE &&
951  loop[1]->objType == DO_FUNC)
952  {
953  repairTypeFuncLoop(loop[0], loop[1]);
954  return;
955  }
956  if (nLoop == 2 &&
957  loop[1]->objType == DO_TYPE &&
958  loop[0]->objType == DO_FUNC)
959  {
960  repairTypeFuncLoop(loop[1], loop[0]);
961  return;
962  }
963 
964  /* View (including matview) and its ON SELECT rule */
965  if (nLoop == 2 &&
966  loop[0]->objType == DO_TABLE &&
967  loop[1]->objType == DO_RULE &&
968  (((TableInfo *) loop[0])->relkind == 'v' || /* RELKIND_VIEW */
969  ((TableInfo *) loop[0])->relkind == 'm') && /* RELKIND_MATVIEW */
970  ((RuleInfo *) loop[1])->ev_type == '1' &&
971  ((RuleInfo *) loop[1])->is_instead &&
972  ((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
973  {
974  repairViewRuleLoop(loop[0], loop[1]);
975  return;
976  }
977  if (nLoop == 2 &&
978  loop[1]->objType == DO_TABLE &&
979  loop[0]->objType == DO_RULE &&
980  (((TableInfo *) loop[1])->relkind == 'v' || /* RELKIND_VIEW */
981  ((TableInfo *) loop[1])->relkind == 'm') && /* RELKIND_MATVIEW */
982  ((RuleInfo *) loop[0])->ev_type == '1' &&
983  ((RuleInfo *) loop[0])->is_instead &&
984  ((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
985  {
986  repairViewRuleLoop(loop[1], loop[0]);
987  return;
988  }
989 
990  /* Indirect loop involving view (but not matview) and ON SELECT rule */
991  if (nLoop > 2)
992  {
993  for (i = 0; i < nLoop; i++)
994  {
995  if (loop[i]->objType == DO_TABLE &&
996  ((TableInfo *) loop[i])->relkind == 'v') /* RELKIND_VIEW */
997  {
998  for (j = 0; j < nLoop; j++)
999  {
1000  if (loop[j]->objType == DO_RULE &&
1001  ((RuleInfo *) loop[j])->ev_type == '1' &&
1002  ((RuleInfo *) loop[j])->is_instead &&
1003  ((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
1004  {
1005  repairViewRuleMultiLoop(loop[i], loop[j]);
1006  return;
1007  }
1008  }
1009  }
1010  }
1011  }
1012 
1013  /* Indirect loop involving matview and data boundary */
1014  if (nLoop > 2)
1015  {
1016  for (i = 0; i < nLoop; i++)
1017  {
1018  if (loop[i]->objType == DO_TABLE &&
1019  ((TableInfo *) loop[i])->relkind == 'm') /* RELKIND_MATVIEW */
1020  {
1021  for (j = 0; j < nLoop; j++)
1022  {
1023  if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
1024  {
1025  DumpableObject *nextobj;
1026 
1027  nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
1028  repairMatViewBoundaryMultiLoop(loop[i], loop[j],
1029  nextobj);
1030  return;
1031  }
1032  }
1033  }
1034  }
1035  }
1036 
1037  /* Table and CHECK constraint */
1038  if (nLoop == 2 &&
1039  loop[0]->objType == DO_TABLE &&
1040  loop[1]->objType == DO_CONSTRAINT &&
1041  ((ConstraintInfo *) loop[1])->contype == 'c' &&
1042  ((ConstraintInfo *) loop[1])->contable == (TableInfo *) loop[0])
1043  {
1044  repairTableConstraintLoop(loop[0], loop[1]);
1045  return;
1046  }
1047  if (nLoop == 2 &&
1048  loop[1]->objType == DO_TABLE &&
1049  loop[0]->objType == DO_CONSTRAINT &&
1050  ((ConstraintInfo *) loop[0])->contype == 'c' &&
1051  ((ConstraintInfo *) loop[0])->contable == (TableInfo *) loop[1])
1052  {
1053  repairTableConstraintLoop(loop[1], loop[0]);
1054  return;
1055  }
1056 
1057  /* Indirect loop involving table and CHECK constraint */
1058  if (nLoop > 2)
1059  {
1060  for (i = 0; i < nLoop; i++)
1061  {
1062  if (loop[i]->objType == DO_TABLE)
1063  {
1064  for (j = 0; j < nLoop; j++)
1065  {
1066  if (loop[j]->objType == DO_CONSTRAINT &&
1067  ((ConstraintInfo *) loop[j])->contype == 'c' &&
1068  ((ConstraintInfo *) loop[j])->contable == (TableInfo *) loop[i])
1069  {
1070  repairTableConstraintMultiLoop(loop[i], loop[j]);
1071  return;
1072  }
1073  }
1074  }
1075  }
1076  }
1077 
1078  /* Table and attribute default */
1079  if (nLoop == 2 &&
1080  loop[0]->objType == DO_TABLE &&
1081  loop[1]->objType == DO_ATTRDEF &&
1082  ((AttrDefInfo *) loop[1])->adtable == (TableInfo *) loop[0])
1083  {
1084  repairTableAttrDefLoop(loop[0], loop[1]);
1085  return;
1086  }
1087  if (nLoop == 2 &&
1088  loop[1]->objType == DO_TABLE &&
1089  loop[0]->objType == DO_ATTRDEF &&
1090  ((AttrDefInfo *) loop[0])->adtable == (TableInfo *) loop[1])
1091  {
1092  repairTableAttrDefLoop(loop[1], loop[0]);
1093  return;
1094  }
1095 
1096  /* Indirect loop involving table and attribute default */
1097  if (nLoop > 2)
1098  {
1099  for (i = 0; i < nLoop; i++)
1100  {
1101  if (loop[i]->objType == DO_TABLE)
1102  {
1103  for (j = 0; j < nLoop; j++)
1104  {
1105  if (loop[j]->objType == DO_ATTRDEF &&
1106  ((AttrDefInfo *) loop[j])->adtable == (TableInfo *) loop[i])
1107  {
1108  repairTableAttrDefMultiLoop(loop[i], loop[j]);
1109  return;
1110  }
1111  }
1112  }
1113  }
1114  }
1115 
1116  /* Domain and CHECK constraint */
1117  if (nLoop == 2 &&
1118  loop[0]->objType == DO_TYPE &&
1119  loop[1]->objType == DO_CONSTRAINT &&
1120  ((ConstraintInfo *) loop[1])->contype == 'c' &&
1121  ((ConstraintInfo *) loop[1])->condomain == (TypeInfo *) loop[0])
1122  {
1123  repairDomainConstraintLoop(loop[0], loop[1]);
1124  return;
1125  }
1126  if (nLoop == 2 &&
1127  loop[1]->objType == DO_TYPE &&
1128  loop[0]->objType == DO_CONSTRAINT &&
1129  ((ConstraintInfo *) loop[0])->contype == 'c' &&
1130  ((ConstraintInfo *) loop[0])->condomain == (TypeInfo *) loop[1])
1131  {
1132  repairDomainConstraintLoop(loop[1], loop[0]);
1133  return;
1134  }
1135 
1136  /* Indirect loop involving domain and CHECK constraint */
1137  if (nLoop > 2)
1138  {
1139  for (i = 0; i < nLoop; i++)
1140  {
1141  if (loop[i]->objType == DO_TYPE)
1142  {
1143  for (j = 0; j < nLoop; j++)
1144  {
1145  if (loop[j]->objType == DO_CONSTRAINT &&
1146  ((ConstraintInfo *) loop[j])->contype == 'c' &&
1147  ((ConstraintInfo *) loop[j])->condomain == (TypeInfo *) loop[i])
1148  {
1149  repairDomainConstraintMultiLoop(loop[i], loop[j]);
1150  return;
1151  }
1152  }
1153  }
1154  }
1155  }
1156 
1157  /*
1158  * If all the objects are TABLE_DATA items, what we must have is a
1159  * circular set of foreign key constraints (or a single self-referential
1160  * table). Print an appropriate complaint and break the loop arbitrarily.
1161  */
1162  for (i = 0; i < nLoop; i++)
1163  {
1164  if (loop[i]->objType != DO_TABLE_DATA)
1165  break;
1166  }
1167  if (i >= nLoop)
1168  {
1169  write_msg(NULL, ngettext("NOTICE: there are circular foreign-key constraints on this table:\n",
1170  "NOTICE: there are circular foreign-key constraints among these tables:\n",
1171  nLoop));
1172  for (i = 0; i < nLoop; i++)
1173  write_msg(NULL, " %s\n", loop[i]->name);
1174  write_msg(NULL, "You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.\n");
1175  write_msg(NULL, "Consider using a full dump instead of a --data-only dump to avoid this problem.\n");
1176  if (nLoop > 1)
1177  removeObjectDependency(loop[0], loop[1]->dumpId);
1178  else /* must be a self-dependency */
1179  removeObjectDependency(loop[0], loop[0]->dumpId);
1180  return;
1181  }
1182 
1183  /*
1184  * If we can't find a principled way to break the loop, complain and break
1185  * it in an arbitrary fashion.
1186  */
1187  write_msg(modulename, "WARNING: could not resolve dependency loop among these items:\n");
1188  for (i = 0; i < nLoop; i++)
1189  {
1190  char buf[1024];
1191 
1192  describeDumpableObject(loop[i], buf, sizeof(buf));
1193  write_msg(modulename, " %s\n", buf);
1194  }
1195 
1196  if (nLoop > 1)
1197  removeObjectDependency(loop[0], loop[1]->dumpId);
1198  else /* must be a self-dependency */
1199  removeObjectDependency(loop[0], loop[0]->dumpId);
1200 }
1201 
1202 /*
1203  * Describe a dumpable object usefully for errors
1204  *
1205  * This should probably go somewhere else...
1206  */
1207 static void
1208 describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
1209 {
1210  switch (obj->objType)
1211  {
1212  case DO_NAMESPACE:
1213  snprintf(buf, bufsize,
1214  "SCHEMA %s (ID %d OID %u)",
1215  obj->name, obj->dumpId, obj->catId.oid);
1216  return;
1217  case DO_EXTENSION:
1218  snprintf(buf, bufsize,
1219  "EXTENSION %s (ID %d OID %u)",
1220  obj->name, obj->dumpId, obj->catId.oid);
1221  return;
1222  case DO_TYPE:
1223  snprintf(buf, bufsize,
1224  "TYPE %s (ID %d OID %u)",
1225  obj->name, obj->dumpId, obj->catId.oid);
1226  return;
1227  case DO_SHELL_TYPE:
1228  snprintf(buf, bufsize,
1229  "SHELL TYPE %s (ID %d OID %u)",
1230  obj->name, obj->dumpId, obj->catId.oid);
1231  return;
1232  case DO_FUNC:
1233  snprintf(buf, bufsize,
1234  "FUNCTION %s (ID %d OID %u)",
1235  obj->name, obj->dumpId, obj->catId.oid);
1236  return;
1237  case DO_AGG:
1238  snprintf(buf, bufsize,
1239  "AGGREGATE %s (ID %d OID %u)",
1240  obj->name, obj->dumpId, obj->catId.oid);
1241  return;
1242  case DO_OPERATOR:
1243  snprintf(buf, bufsize,
1244  "OPERATOR %s (ID %d OID %u)",
1245  obj->name, obj->dumpId, obj->catId.oid);
1246  return;
1247  case DO_ACCESS_METHOD:
1248  snprintf(buf, bufsize,
1249  "ACCESS METHOD %s (ID %d OID %u)",
1250  obj->name, obj->dumpId, obj->catId.oid);
1251  return;
1252  case DO_OPCLASS:
1253  snprintf(buf, bufsize,
1254  "OPERATOR CLASS %s (ID %d OID %u)",
1255  obj->name, obj->dumpId, obj->catId.oid);
1256  return;
1257  case DO_OPFAMILY:
1258  snprintf(buf, bufsize,
1259  "OPERATOR FAMILY %s (ID %d OID %u)",
1260  obj->name, obj->dumpId, obj->catId.oid);
1261  return;
1262  case DO_COLLATION:
1263  snprintf(buf, bufsize,
1264  "COLLATION %s (ID %d OID %u)",
1265  obj->name, obj->dumpId, obj->catId.oid);
1266  return;
1267  case DO_CONVERSION:
1268  snprintf(buf, bufsize,
1269  "CONVERSION %s (ID %d OID %u)",
1270  obj->name, obj->dumpId, obj->catId.oid);
1271  return;
1272  case DO_TABLE:
1273  snprintf(buf, bufsize,
1274  "TABLE %s (ID %d OID %u)",
1275  obj->name, obj->dumpId, obj->catId.oid);
1276  return;
1277  case DO_ATTRDEF:
1278  snprintf(buf, bufsize,
1279  "ATTRDEF %s.%s (ID %d OID %u)",
1280  ((AttrDefInfo *) obj)->adtable->dobj.name,
1281  ((AttrDefInfo *) obj)->adtable->attnames[((AttrDefInfo *) obj)->adnum - 1],
1282  obj->dumpId, obj->catId.oid);
1283  return;
1284  case DO_INDEX:
1285  snprintf(buf, bufsize,
1286  "INDEX %s (ID %d OID %u)",
1287  obj->name, obj->dumpId, obj->catId.oid);
1288  return;
1289  case DO_REFRESH_MATVIEW:
1290  snprintf(buf, bufsize,
1291  "REFRESH MATERIALIZED VIEW %s (ID %d OID %u)",
1292  obj->name, obj->dumpId, obj->catId.oid);
1293  return;
1294  case DO_RULE:
1295  snprintf(buf, bufsize,
1296  "RULE %s (ID %d OID %u)",
1297  obj->name, obj->dumpId, obj->catId.oid);
1298  return;
1299  case DO_TRIGGER:
1300  snprintf(buf, bufsize,
1301  "TRIGGER %s (ID %d OID %u)",
1302  obj->name, obj->dumpId, obj->catId.oid);
1303  return;
1304  case DO_EVENT_TRIGGER:
1305  snprintf(buf, bufsize,
1306  "EVENT TRIGGER %s (ID %d OID %u)",
1307  obj->name, obj->dumpId, obj->catId.oid);
1308  return;
1309  case DO_CONSTRAINT:
1310  snprintf(buf, bufsize,
1311  "CONSTRAINT %s (ID %d OID %u)",
1312  obj->name, obj->dumpId, obj->catId.oid);
1313  return;
1314  case DO_FK_CONSTRAINT:
1315  snprintf(buf, bufsize,
1316  "FK CONSTRAINT %s (ID %d OID %u)",
1317  obj->name, obj->dumpId, obj->catId.oid);
1318  return;
1319  case DO_PROCLANG:
1320  snprintf(buf, bufsize,
1321  "PROCEDURAL LANGUAGE %s (ID %d OID %u)",
1322  obj->name, obj->dumpId, obj->catId.oid);
1323  return;
1324  case DO_CAST:
1325  snprintf(buf, bufsize,
1326  "CAST %u to %u (ID %d OID %u)",
1327  ((CastInfo *) obj)->castsource,
1328  ((CastInfo *) obj)->casttarget,
1329  obj->dumpId, obj->catId.oid);
1330  return;
1331  case DO_TRANSFORM:
1332  snprintf(buf, bufsize,
1333  "TRANSFORM %u lang %u (ID %d OID %u)",
1334  ((TransformInfo *) obj)->trftype,
1335  ((TransformInfo *) obj)->trflang,
1336  obj->dumpId, obj->catId.oid);
1337  return;
1338  case DO_TABLE_DATA:
1339  snprintf(buf, bufsize,
1340  "TABLE DATA %s (ID %d OID %u)",
1341  obj->name, obj->dumpId, obj->catId.oid);
1342  return;
1343  case DO_SEQUENCE_SET:
1344  snprintf(buf, bufsize,
1345  "SEQUENCE SET %s (ID %d OID %u)",
1346  obj->name, obj->dumpId, obj->catId.oid);
1347  return;
1348  case DO_DUMMY_TYPE:
1349  snprintf(buf, bufsize,
1350  "DUMMY TYPE %s (ID %d OID %u)",
1351  obj->name, obj->dumpId, obj->catId.oid);
1352  return;
1353  case DO_TSPARSER:
1354  snprintf(buf, bufsize,
1355  "TEXT SEARCH PARSER %s (ID %d OID %u)",
1356  obj->name, obj->dumpId, obj->catId.oid);
1357  return;
1358  case DO_TSDICT:
1359  snprintf(buf, bufsize,
1360  "TEXT SEARCH DICTIONARY %s (ID %d OID %u)",
1361  obj->name, obj->dumpId, obj->catId.oid);
1362  return;
1363  case DO_TSTEMPLATE:
1364  snprintf(buf, bufsize,
1365  "TEXT SEARCH TEMPLATE %s (ID %d OID %u)",
1366  obj->name, obj->dumpId, obj->catId.oid);
1367  return;
1368  case DO_TSCONFIG:
1369  snprintf(buf, bufsize,
1370  "TEXT SEARCH CONFIGURATION %s (ID %d OID %u)",
1371  obj->name, obj->dumpId, obj->catId.oid);
1372  return;
1373  case DO_FDW:
1374  snprintf(buf, bufsize,
1375  "FOREIGN DATA WRAPPER %s (ID %d OID %u)",
1376  obj->name, obj->dumpId, obj->catId.oid);
1377  return;
1378  case DO_FOREIGN_SERVER:
1379  snprintf(buf, bufsize,
1380  "FOREIGN SERVER %s (ID %d OID %u)",
1381  obj->name, obj->dumpId, obj->catId.oid);
1382  return;
1383  case DO_DEFAULT_ACL:
1384  snprintf(buf, bufsize,
1385  "DEFAULT ACL %s (ID %d OID %u)",
1386  obj->name, obj->dumpId, obj->catId.oid);
1387  return;
1388  case DO_BLOB:
1389  snprintf(buf, bufsize,
1390  "BLOB (ID %d OID %u)",
1391  obj->dumpId, obj->catId.oid);
1392  return;
1393  case DO_BLOB_DATA:
1394  snprintf(buf, bufsize,
1395  "BLOB DATA (ID %d)",
1396  obj->dumpId);
1397  return;
1398  case DO_POLICY:
1399  snprintf(buf, bufsize,
1400  "POLICY (ID %d OID %u)",
1401  obj->dumpId, obj->catId.oid);
1402  return;
1403  case DO_PUBLICATION:
1404  snprintf(buf, bufsize,
1405  "PUBLICATION (ID %d OID %u)",
1406  obj->dumpId, obj->catId.oid);
1407  return;
1408  case DO_PUBLICATION_REL:
1409  snprintf(buf, bufsize,
1410  "PUBLICATION TABLE (ID %d OID %u)",
1411  obj->dumpId, obj->catId.oid);
1412  return;
1413  case DO_SUBSCRIPTION:
1414  snprintf(buf, bufsize,
1415  "SUBSCRIPTION (ID %d OID %u)",
1416  obj->dumpId, obj->catId.oid);
1417  return;
1418  case DO_PRE_DATA_BOUNDARY:
1419  snprintf(buf, bufsize,
1420  "PRE-DATA BOUNDARY (ID %d)",
1421  obj->dumpId);
1422  return;
1423  case DO_POST_DATA_BOUNDARY:
1424  snprintf(buf, bufsize,
1425  "POST-DATA BOUNDARY (ID %d)",
1426  obj->dumpId);
1427  return;
1428  }
1429  /* shouldn't get here */
1430  snprintf(buf, bufsize,
1431  "object type %d (ID %d OID %u)",
1432  (int) obj->objType,
1433  obj->dumpId, obj->catId.oid);
1434 }
Oid * argtypes
Definition: pg_dump.h:201
char * name
Definition: pg_dump.h:132
static void repairMatViewBoundaryMultiLoop(DumpableObject *matviewobj, DumpableObject *boundaryobj, DumpableObject *nextobj)
Definition: pg_dump_sort.c:837
static int DOTypeNameCompare(const void *p1, const void *p2)
Definition: pg_dump_sort.c:209
int DumpId
Definition: pg_backup.h:228
static void repairDependencyLoop(DumpableObject **loop, int nLoop)
Definition: pg_dump_sort.c:942
DumpableObject dobj
Definition: pg_dump.h:190
static void repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
Definition: pg_dump_sort.c:756
DumpComponents dump
Definition: pg_dump.h:133
#define oidcmp(x, y)
Definition: pg_dump.h:20
DumpId * dependencies
Definition: pg_dump.h:137
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
int nargs
Definition: pg_dump.h:200
void sortDumpableObjects(DumpableObject **objs, int numObjs, DumpId preBoundaryId, DumpId postBoundaryId)
Definition: pg_dump_sort.c:303
static DumpId preDataBoundId
Definition: pg_dump_sort.c:80
static void describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
void sortDataAndIndexObjectsBySize(DumpableObject **objs, int numObjs)
Definition: pg_dump_sort.c:139
bool separate
Definition: pg_dump.h:372
struct _shellTypeInfo * shellType
Definition: pg_dump.h:182
static int removeHeapElement(int *heap, int heapLength)
Definition: pg_dump_sort.c:530
#define gettext_noop(x)
Definition: c.h:139
static int findFirstEqualType(DumpableObjectType type, DumpableObject **objs, int numObjs)
Definition: pg_dump_sort.c:106
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
DumpId dumpId
Definition: pg_dump.h:131
static void findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs)
Definition: pg_dump_sort.c:575
char bool
Definition: c.h:199
DumpableObjectType
Definition: pg_dump.h:41
Definition: pg_dump.h:49
static bool TopoSort(DumpableObject **objs, int numObjs, DumpableObject **ordering, int *nOrdering)
Definition: pg_dump_sort.c:355
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:573
static int DOSizeCompare(const void *p1, const void *p2)
Definition: pg_dump_sort.c:168
static DumpId postDataBoundId
Definition: pg_dump_sort.c:81
static int findLoop(DumpableObject *obj, DumpId startPoint, bool *processed, DumpId *searchFailed, DumpableObject **workspace, int depth)
Definition: pg_dump_sort.c:671
static void repairViewRuleLoop(DumpableObject *viewobj, DumpableObject *ruleobj)
Definition: pg_dump_sort.c:787
static char * buf
Definition: pg_test_fsync.c:65
static void repairTableConstraintMultiLoop(DumpableObject *tableobj, DumpableObject *constraintobj)
Definition: pg_dump_sort.c:873
static void repairViewRuleMultiLoop(DumpableObject *viewobj, DumpableObject *ruleobj)
Definition: pg_dump_sort.c:807
DumpableObject dobj
Definition: pg_dump.h:164
static void repairDomainConstraintLoop(DumpableObject *domainobj, DumpableObject *constraintobj)
Definition: pg_dump_sort.c:913
bool postponed_def
Definition: pg_dump.h:294
#define ngettext(s, p, n)
Definition: c.h:127
static const int dbObjectTypePriority[]
Definition: pg_dump_sort.c:34
void removeObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:772
static int findFirstDifferentType(DumpableObjectType type, DumpableObject **objs, int numObjs, int start)
Definition: pg_dump_sort.c:117
static const char * modulename
Definition: pg_dump_sort.c:23
DumpId getMaxDumpId(void)
Definition: common.c:562
#define DUMP_COMPONENT_DEFINITION
Definition: pg_dump.h:91
#define free(a)
Definition: header.h:60
static void repairTableConstraintLoop(DumpableObject *tableobj, DumpableObject *constraintobj)
Definition: pg_dump_sort.c:856
char oprkind
Definition: pg_dump.h:220
void write_msg(const char *modulename, const char *fmt,...)
Definition: pg_dump.h:72
#define NULL
Definition: c.h:226
const char * name
Definition: encode.c:521
void exit_horribly(const char *modulename, const char *fmt,...)
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:745
CatalogId catId
Definition: pg_dump.h:130
int i
void sortDumpableObjectsByTypeName(DumpableObject **objs, int numObjs)
Definition: pg_dump_sort.c:201
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:803
static void repairTableAttrDefMultiLoop(DumpableObject *tableobj, DumpableObject *attrdefobj)
Definition: pg_dump_sort.c:898
static void addHeapElement(int val, int *heap, int heapLength)
Definition: pg_dump_sort.c:499
#define qsort(a, b, c, d)
Definition: port.h:440
static int * beforeConstraints
Definition: deadlock.c:107
static void repairDomainConstraintMultiLoop(DumpableObject *domainobj, DumpableObject *constraintobj)
Definition: pg_dump_sort.c:921
DumpableObjectType objType
Definition: pg_dump.h:129
bool dummy_view
Definition: pg_dump.h:293
long val
Definition: informix.c:689
static void repairTableAttrDefLoop(DumpableObject *tableobj, DumpableObject *attrdefobj)
Definition: pg_dump_sort.c:890