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