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