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