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