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