1 /*-------------------------------------------------------------------------
2  *
3  * common.c
4  *	Catalog routines used by pg_dump; long ago these were shared
5  *	by another dump tool, but not anymore.
6  *
7  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *	  src/bin/pg_dump/common.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 <ctype.h>
23 
24 #include "catalog/pg_class_d.h"
25 #include "fe_utils/string_utils.h"
26 
27 
28 /*
29  * Variables for mapping DumpId to DumpableObject
30  */
31 static DumpableObject **dumpIdMap = NULL;
32 static int	allocedDumpIds = 0;
33 static DumpId lastDumpId = 0;	/* Note: 0 is InvalidDumpId */
34 
35 /*
36  * Variables for mapping CatalogId to DumpableObject
37  */
38 static bool catalogIdMapValid = false;
39 static DumpableObject **catalogIdMap = NULL;
40 static int	numCatalogIds = 0;
41 
42 /*
43  * These variables are static to avoid the notational cruft of having to pass
44  * them into findTableByOid() and friends.  For each of these arrays, we build
45  * a sorted-by-OID index array immediately after the objects are fetched,
46  * and then we use binary search in findTableByOid() and friends.  (qsort'ing
47  * the object arrays themselves would be simpler, but it doesn't work because
48  * pg_dump.c may have already established pointers between items.)
49  */
50 static DumpableObject **tblinfoindex;
51 static DumpableObject **typinfoindex;
52 static DumpableObject **funinfoindex;
53 static DumpableObject **oprinfoindex;
54 static DumpableObject **collinfoindex;
55 static DumpableObject **nspinfoindex;
56 static DumpableObject **extinfoindex;
57 static DumpableObject **pubinfoindex;
58 static int	numTables;
59 static int	numTypes;
60 static int	numFuncs;
61 static int	numOperators;
62 static int	numCollations;
63 static int	numNamespaces;
64 static int	numExtensions;
65 static int	numPublications;
66 
67 /* This is an array of object identities, not actual DumpableObjects */
68 static ExtensionMemberId *extmembers;
69 static int	numextmembers;
70 
71 static void flagInhTables(Archive *fout, TableInfo *tbinfo, int numTables,
72 						  InhInfo *inhinfo, int numInherits);
73 static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
74 static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
75 static DumpableObject **buildIndexArray(void *objArray, int numObjs,
76 										Size objSize);
77 static int	DOCatalogIdCompare(const void *p1, const void *p2);
78 static int	ExtensionMemberIdCompare(const void *p1, const void *p2);
79 static void findParentsByOid(TableInfo *self,
80 							 InhInfo *inhinfo, int numInherits);
81 static int	strInArray(const char *pattern, char **arr, int arr_size);
82 static IndxInfo *findIndexByOid(Oid oid, DumpableObject **idxinfoindex,
83 								int numIndexes);
84 
85 
86 /*
87  * getSchemaData
88  *	  Collect information about all potentially dumpable objects
89  */
90 TableInfo *
91 getSchemaData(Archive *fout, int *numTablesPtr)
92 {
93 	TableInfo  *tblinfo;
94 	TypeInfo   *typinfo;
95 	FuncInfo   *funinfo;
96 	OprInfo    *oprinfo;
97 	CollInfo   *collinfo;
98 	NamespaceInfo *nspinfo;
99 	ExtensionInfo *extinfo;
100 	PublicationInfo *pubinfo;
101 	InhInfo    *inhinfo;
102 	int			numAggregates;
103 	int			numInherits;
104 	int			numRules;
105 	int			numProcLangs;
106 	int			numCasts;
107 	int			numTransforms;
108 	int			numAccessMethods;
109 	int			numOpclasses;
110 	int			numOpfamilies;
111 	int			numConversions;
112 	int			numTSParsers;
113 	int			numTSTemplates;
114 	int			numTSDicts;
115 	int			numTSConfigs;
116 	int			numForeignDataWrappers;
117 	int			numForeignServers;
118 	int			numDefaultACLs;
119 	int			numEventTriggers;
120 
121 	/*
122 	 * We must read extensions and extension membership info first, because
123 	 * extension membership needs to be consultable during decisions about
124 	 * whether other objects are to be dumped.
125 	 */
126 	pg_log_info("reading extensions");
127 	extinfo = getExtensions(fout, &numExtensions);
128 	extinfoindex = buildIndexArray(extinfo, numExtensions, sizeof(ExtensionInfo));
129 
130 	pg_log_info("identifying extension members");
131 	getExtensionMembership(fout, extinfo, numExtensions);
132 
133 	pg_log_info("reading schemas");
134 	nspinfo = getNamespaces(fout, &numNamespaces);
135 	nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
136 
137 	/*
138 	 * getTables should be done as soon as possible, so as to minimize the
139 	 * window between starting our transaction and acquiring per-table locks.
140 	 * However, we have to do getNamespaces first because the tables get
141 	 * linked to their containing namespaces during getTables.
142 	 */
143 	pg_log_info("reading user-defined tables");
144 	tblinfo = getTables(fout, &numTables);
145 	tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
146 
147 	/* Do this after we've built tblinfoindex */
148 	getOwnedSeqs(fout, tblinfo, numTables);
149 
150 	pg_log_info("reading user-defined functions");
151 	funinfo = getFuncs(fout, &numFuncs);
152 	funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
153 
154 	/* this must be after getTables and getFuncs */
155 	pg_log_info("reading user-defined types");
156 	typinfo = getTypes(fout, &numTypes);
157 	typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
158 
159 	/* this must be after getFuncs, too */
160 	pg_log_info("reading procedural languages");
161 	getProcLangs(fout, &numProcLangs);
162 
163 	pg_log_info("reading user-defined aggregate functions");
164 	getAggregates(fout, &numAggregates);
165 
166 	pg_log_info("reading user-defined operators");
167 	oprinfo = getOperators(fout, &numOperators);
168 	oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
169 
170 	pg_log_info("reading user-defined access methods");
171 	getAccessMethods(fout, &numAccessMethods);
172 
173 	pg_log_info("reading user-defined operator classes");
174 	getOpclasses(fout, &numOpclasses);
175 
176 	pg_log_info("reading user-defined operator families");
177 	getOpfamilies(fout, &numOpfamilies);
178 
179 	pg_log_info("reading user-defined text search parsers");
180 	getTSParsers(fout, &numTSParsers);
181 
182 	pg_log_info("reading user-defined text search templates");
183 	getTSTemplates(fout, &numTSTemplates);
184 
185 	pg_log_info("reading user-defined text search dictionaries");
186 	getTSDictionaries(fout, &numTSDicts);
187 
188 	pg_log_info("reading user-defined text search configurations");
189 	getTSConfigurations(fout, &numTSConfigs);
190 
191 	pg_log_info("reading user-defined foreign-data wrappers");
192 	getForeignDataWrappers(fout, &numForeignDataWrappers);
193 
194 	pg_log_info("reading user-defined foreign servers");
195 	getForeignServers(fout, &numForeignServers);
196 
197 	pg_log_info("reading default privileges");
198 	getDefaultACLs(fout, &numDefaultACLs);
199 
200 	pg_log_info("reading user-defined collations");
201 	collinfo = getCollations(fout, &numCollations);
202 	collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
203 
204 	pg_log_info("reading user-defined conversions");
205 	getConversions(fout, &numConversions);
206 
207 	pg_log_info("reading type casts");
208 	getCasts(fout, &numCasts);
209 
210 	pg_log_info("reading transforms");
211 	getTransforms(fout, &numTransforms);
212 
213 	pg_log_info("reading table inheritance information");
214 	inhinfo = getInherits(fout, &numInherits);
215 
216 	pg_log_info("reading event triggers");
217 	getEventTriggers(fout, &numEventTriggers);
218 
219 	/* Identify extension configuration tables that should be dumped */
220 	pg_log_info("finding extension tables");
221 	processExtensionTables(fout, extinfo, numExtensions);
222 
223 	/* Link tables to parents, mark parents of target tables interesting */
224 	pg_log_info("finding inheritance relationships");
225 	flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
226 
227 	pg_log_info("reading column info for interesting tables");
228 	getTableAttrs(fout, tblinfo, numTables);
229 
230 	pg_log_info("flagging inherited columns in subtables");
231 	flagInhAttrs(fout->dopt, tblinfo, numTables);
232 
233 	pg_log_info("reading indexes");
234 	getIndexes(fout, tblinfo, numTables);
235 
236 	pg_log_info("flagging indexes in partitioned tables");
237 	flagInhIndexes(fout, tblinfo, numTables);
238 
239 	pg_log_info("reading extended statistics");
240 	getExtendedStatistics(fout);
241 
242 	pg_log_info("reading constraints");
243 	getConstraints(fout, tblinfo, numTables);
244 
245 	pg_log_info("reading triggers");
246 	getTriggers(fout, tblinfo, numTables);
247 
248 	pg_log_info("reading rewrite rules");
249 	getRules(fout, &numRules);
250 
251 	pg_log_info("reading policies");
252 	getPolicies(fout, tblinfo, numTables);
253 
254 	pg_log_info("reading publications");
255 	pubinfo = getPublications(fout, &numPublications);
256 	pubinfoindex = buildIndexArray(pubinfo, numPublications,
257 								   sizeof(PublicationInfo));
258 
259 	pg_log_info("reading publication membership");
260 	getPublicationTables(fout, tblinfo, numTables);
261 
262 	pg_log_info("reading subscriptions");
263 	getSubscriptions(fout);
264 
265 	*numTablesPtr = numTables;
266 	return tblinfo;
267 }
268 
269 /* flagInhTables -
270  *	 Fill in parent link fields of tables for which we need that information,
271  *	 and mark parents of target tables as interesting
272  *
273  * Note that only direct ancestors of targets are marked interesting.
274  * This is sufficient; we don't much care whether they inherited their
275  * attributes or not.
276  *
277  * modifies tblinfo
278  */
279 static void
280 flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
281 			  InhInfo *inhinfo, int numInherits)
282 {
283 	DumpOptions *dopt = fout->dopt;
284 	int			i,
285 				j;
286 
287 	for (i = 0; i < numTables; i++)
288 	{
289 		bool		find_parents = true;
290 		bool		mark_parents = true;
291 
292 		/* Some kinds never have parents */
293 		if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
294 			tblinfo[i].relkind == RELKIND_VIEW ||
295 			tblinfo[i].relkind == RELKIND_MATVIEW)
296 			continue;
297 
298 		/*
299 		 * Normally, we don't bother computing anything for non-target tables,
300 		 * but if load-via-partition-root is specified, we gather information
301 		 * on every partition in the system so that getRootTableInfo can trace
302 		 * from any given to leaf partition all the way up to the root.  (We
303 		 * don't need to mark them as interesting for getTableAttrs, though.)
304 		 */
305 		if (!tblinfo[i].dobj.dump)
306 		{
307 			mark_parents = false;
308 
309 			if (!dopt->load_via_partition_root ||
310 				!tblinfo[i].ispartition)
311 				find_parents = false;
312 		}
313 
314 		/* If needed, find all the immediate parent tables. */
315 		if (find_parents)
316 			findParentsByOid(&tblinfo[i], inhinfo, numInherits);
317 
318 		/*
319 		 * If needed, mark the parents as interesting for getTableAttrs and
320 		 * getIndexes.
321 		 */
322 		if (mark_parents)
323 		{
324 			int			numParents = tblinfo[i].numParents;
325 			TableInfo **parents = tblinfo[i].parents;
326 
327 			for (j = 0; j < numParents; j++)
328 				parents[j]->interesting = true;
329 		}
330 	}
331 }
332 
333 /*
334  * flagInhIndexes -
335  *	 Create IndexAttachInfo objects for partitioned indexes, and add
336  *	 appropriate dependency links.
337  */
338 static void
339 flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
340 {
341 	int			i,
342 				j,
343 				k;
344 	DumpableObject ***parentIndexArray;
345 
346 	parentIndexArray = (DumpableObject ***)
347 		pg_malloc0(getMaxDumpId() * sizeof(DumpableObject **));
348 
349 	for (i = 0; i < numTables; i++)
350 	{
351 		TableInfo  *parenttbl;
352 		IndexAttachInfo *attachinfo;
353 
354 		if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
355 			continue;
356 
357 		Assert(tblinfo[i].numParents == 1);
358 		parenttbl = tblinfo[i].parents[0];
359 
360 		/*
361 		 * We need access to each parent table's index list, but there is no
362 		 * index to cover them outside of this function.  To avoid having to
363 		 * sort every parent table's indexes each time we come across each of
364 		 * its partitions, create an indexed array for each parent the first
365 		 * time it is required.
366 		 */
367 		if (parentIndexArray[parenttbl->dobj.dumpId] == NULL)
368 			parentIndexArray[parenttbl->dobj.dumpId] =
369 				buildIndexArray(parenttbl->indexes,
370 								parenttbl->numIndexes,
371 								sizeof(IndxInfo));
372 
373 		attachinfo = (IndexAttachInfo *)
374 			pg_malloc0(tblinfo[i].numIndexes * sizeof(IndexAttachInfo));
375 		for (j = 0, k = 0; j < tblinfo[i].numIndexes; j++)
376 		{
377 			IndxInfo   *index = &(tblinfo[i].indexes[j]);
378 			IndxInfo   *parentidx;
379 
380 			if (index->parentidx == 0)
381 				continue;
382 
383 			parentidx = findIndexByOid(index->parentidx,
384 									   parentIndexArray[parenttbl->dobj.dumpId],
385 									   parenttbl->numIndexes);
386 			if (parentidx == NULL)
387 				continue;
388 
389 			attachinfo[k].dobj.objType = DO_INDEX_ATTACH;
390 			attachinfo[k].dobj.catId.tableoid = 0;
391 			attachinfo[k].dobj.catId.oid = 0;
392 			AssignDumpId(&attachinfo[k].dobj);
393 			attachinfo[k].dobj.name = pg_strdup(index->dobj.name);
394 			attachinfo[k].dobj.namespace = index->indextable->dobj.namespace;
395 			attachinfo[k].parentIdx = parentidx;
396 			attachinfo[k].partitionIdx = index;
397 
398 			/*
399 			 * We must state the DO_INDEX_ATTACH object's dependencies
400 			 * explicitly, since it will not match anything in pg_depend.
401 			 *
402 			 * Give it dependencies on both the partition index and the parent
403 			 * index, so that it will not be executed till both of those
404 			 * exist.  (There's no need to care what order those are created
405 			 * in.)
406 			 *
407 			 * In addition, give it dependencies on the indexes' underlying
408 			 * tables.  This does nothing of great value so far as serial
409 			 * restore ordering goes, but it ensures that a parallel restore
410 			 * will not try to run the ATTACH concurrently with other
411 			 * operations on those tables.
412 			 */
413 			addObjectDependency(&attachinfo[k].dobj, index->dobj.dumpId);
414 			addObjectDependency(&attachinfo[k].dobj, parentidx->dobj.dumpId);
415 			addObjectDependency(&attachinfo[k].dobj,
416 								index->indextable->dobj.dumpId);
417 			addObjectDependency(&attachinfo[k].dobj,
418 								parentidx->indextable->dobj.dumpId);
419 
420 			/* keep track of the list of partitions in the parent index */
421 			simple_ptr_list_append(&parentidx->partattaches, &attachinfo[k].dobj);
422 
423 			k++;
424 		}
425 	}
426 
427 	for (i = 0; i < numTables; i++)
428 		if (parentIndexArray[i])
429 			pg_free(parentIndexArray[i]);
430 	pg_free(parentIndexArray);
431 }
432 
433 /* flagInhAttrs -
434  *	 for each dumpable table in tblinfo, flag its inherited attributes
435  *
436  * What we need to do here is:
437  *
438  * - Detect child columns that inherit NOT NULL bits from their parents, so
439  *   that we needn't specify that again for the child.
440  *
441  * - Detect child columns that have DEFAULT NULL when their parents had some
442  *   non-null default.  In this case, we make up a dummy AttrDefInfo object so
443  *   that we'll correctly emit the necessary DEFAULT NULL clause; otherwise
444  *   the backend will apply an inherited default to the column.
445  *
446  * - Detect child columns that have a generation expression when their parents
447  *   also have one.  Generation expressions are always inherited, so there is
448  *   no need to set them again in child tables, and there is no syntax for it
449  *   either.  Exceptions: If it's a partition or we are in binary upgrade
450  *   mode, we dump them because in those cases inherited tables are recreated
451  *   standalone first and then reattached to the parent.  (See also the logic
452  *   in dumpTableSchema().)  In that situation, the generation expressions
453  *   must match the parent, enforced by ALTER TABLE.
454  *
455  * modifies tblinfo
456  */
457 static void
458 flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
459 {
460 	int			i,
461 				j,
462 				k;
463 
464 	for (i = 0; i < numTables; i++)
465 	{
466 		TableInfo  *tbinfo = &(tblinfo[i]);
467 		int			numParents;
468 		TableInfo **parents;
469 
470 		/* Some kinds never have parents */
471 		if (tbinfo->relkind == RELKIND_SEQUENCE ||
472 			tbinfo->relkind == RELKIND_VIEW ||
473 			tbinfo->relkind == RELKIND_MATVIEW)
474 			continue;
475 
476 		/* Don't bother computing anything for non-target tables, either */
477 		if (!tbinfo->dobj.dump)
478 			continue;
479 
480 		numParents = tbinfo->numParents;
481 		parents = tbinfo->parents;
482 
483 		if (numParents == 0)
484 			continue;			/* nothing to see here, move along */
485 
486 		/* For each column, search for matching column names in parent(s) */
487 		for (j = 0; j < tbinfo->numatts; j++)
488 		{
489 			bool		foundNotNull;	/* Attr was NOT NULL in a parent */
490 			bool		foundDefault;	/* Found a default in a parent */
491 			bool		foundGenerated;	/* Found a generated in a parent */
492 
493 			/* no point in examining dropped columns */
494 			if (tbinfo->attisdropped[j])
495 				continue;
496 
497 			foundNotNull = false;
498 			foundDefault = false;
499 			foundGenerated = false;
500 			for (k = 0; k < numParents; k++)
501 			{
502 				TableInfo  *parent = parents[k];
503 				int			inhAttrInd;
504 
505 				inhAttrInd = strInArray(tbinfo->attnames[j],
506 										parent->attnames,
507 										parent->numatts);
508 				if (inhAttrInd >= 0)
509 				{
510 					foundNotNull |= parent->notnull[inhAttrInd];
511 					foundDefault |= (parent->attrdefs[inhAttrInd] != NULL && !parent->attgenerated[inhAttrInd]);
512 					foundGenerated |= parent->attgenerated[inhAttrInd];
513 				}
514 			}
515 
516 			/* Remember if we found inherited NOT NULL */
517 			tbinfo->inhNotNull[j] = foundNotNull;
518 
519 			/* Manufacture a DEFAULT NULL clause if necessary */
520 			if (foundDefault && tbinfo->attrdefs[j] == NULL)
521 			{
522 				AttrDefInfo *attrDef;
523 
524 				attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
525 				attrDef->dobj.objType = DO_ATTRDEF;
526 				attrDef->dobj.catId.tableoid = 0;
527 				attrDef->dobj.catId.oid = 0;
528 				AssignDumpId(&attrDef->dobj);
529 				attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
530 				attrDef->dobj.namespace = tbinfo->dobj.namespace;
531 				attrDef->dobj.dump = tbinfo->dobj.dump;
532 
533 				attrDef->adtable = tbinfo;
534 				attrDef->adnum = j + 1;
535 				attrDef->adef_expr = pg_strdup("NULL");
536 
537 				/* Will column be dumped explicitly? */
538 				if (shouldPrintColumn(dopt, tbinfo, j))
539 				{
540 					attrDef->separate = false;
541 					/* No dependency needed: NULL cannot have dependencies */
542 				}
543 				else
544 				{
545 					/* column will be suppressed, print default separately */
546 					attrDef->separate = true;
547 					/* ensure it comes out after the table */
548 					addObjectDependency(&attrDef->dobj,
549 										tbinfo->dobj.dumpId);
550 				}
551 
552 				tbinfo->attrdefs[j] = attrDef;
553 			}
554 
555 			/* Remove generation expression from child */
556 			if (foundGenerated && !tbinfo->ispartition && !dopt->binary_upgrade)
557 				tbinfo->attrdefs[j] = NULL;
558 		}
559 	}
560 }
561 
562 /*
563  * AssignDumpId
564  *		Given a newly-created dumpable object, assign a dump ID,
565  *		and enter the object into the lookup table.
566  *
567  * The caller is expected to have filled in objType and catId,
568  * but not any of the other standard fields of a DumpableObject.
569  */
570 void
571 AssignDumpId(DumpableObject *dobj)
572 {
573 	dobj->dumpId = ++lastDumpId;
574 	dobj->name = NULL;			/* must be set later */
575 	dobj->namespace = NULL;		/* may be set later */
576 	dobj->dump = DUMP_COMPONENT_ALL;	/* default assumption */
577 	dobj->ext_member = false;	/* default assumption */
578 	dobj->depends_on_ext = false;	/* default assumption */
579 	dobj->dependencies = NULL;
580 	dobj->nDeps = 0;
581 	dobj->allocDeps = 0;
582 
583 	while (dobj->dumpId >= allocedDumpIds)
584 	{
585 		int			newAlloc;
586 
587 		if (allocedDumpIds <= 0)
588 		{
589 			newAlloc = 256;
590 			dumpIdMap = (DumpableObject **)
591 				pg_malloc(newAlloc * sizeof(DumpableObject *));
592 		}
593 		else
594 		{
595 			newAlloc = allocedDumpIds * 2;
596 			dumpIdMap = (DumpableObject **)
597 				pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
598 		}
599 		memset(dumpIdMap + allocedDumpIds, 0,
600 			   (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
601 		allocedDumpIds = newAlloc;
602 	}
603 	dumpIdMap[dobj->dumpId] = dobj;
604 
605 	/* mark catalogIdMap invalid, but don't rebuild it yet */
606 	catalogIdMapValid = false;
607 }
608 
609 /*
610  * Assign a DumpId that's not tied to a DumpableObject.
611  *
612  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
613  * participate in the sorting logic.
614  */
615 DumpId
616 createDumpId(void)
617 {
618 	return ++lastDumpId;
619 }
620 
621 /*
622  * Return the largest DumpId so far assigned
623  */
624 DumpId
625 getMaxDumpId(void)
626 {
627 	return lastDumpId;
628 }
629 
630 /*
631  * Find a DumpableObject by dump ID
632  *
633  * Returns NULL for invalid ID
634  */
635 DumpableObject *
636 findObjectByDumpId(DumpId dumpId)
637 {
638 	if (dumpId <= 0 || dumpId >= allocedDumpIds)
639 		return NULL;			/* out of range? */
640 	return dumpIdMap[dumpId];
641 }
642 
643 /*
644  * Find a DumpableObject by catalog ID
645  *
646  * Returns NULL for unknown ID
647  *
648  * We use binary search in a sorted list that is built on first call.
649  * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
650  * the code would work, but possibly be very slow.  In the current usage
651  * pattern that does not happen, indeed we build the list at most twice.
652  */
653 DumpableObject *
654 findObjectByCatalogId(CatalogId catalogId)
655 {
656 	DumpableObject **low;
657 	DumpableObject **high;
658 
659 	if (!catalogIdMapValid)
660 	{
661 		if (catalogIdMap)
662 			free(catalogIdMap);
663 		getDumpableObjects(&catalogIdMap, &numCatalogIds);
664 		if (numCatalogIds > 1)
665 			qsort((void *) catalogIdMap, numCatalogIds,
666 				  sizeof(DumpableObject *), DOCatalogIdCompare);
667 		catalogIdMapValid = true;
668 	}
669 
670 	/*
671 	 * We could use bsearch() here, but the notational cruft of calling
672 	 * bsearch is nearly as bad as doing it ourselves; and the generalized
673 	 * bsearch function is noticeably slower as well.
674 	 */
675 	if (numCatalogIds <= 0)
676 		return NULL;
677 	low = catalogIdMap;
678 	high = catalogIdMap + (numCatalogIds - 1);
679 	while (low <= high)
680 	{
681 		DumpableObject **middle;
682 		int			difference;
683 
684 		middle = low + (high - low) / 2;
685 		/* comparison must match DOCatalogIdCompare, below */
686 		difference = oidcmp((*middle)->catId.oid, catalogId.oid);
687 		if (difference == 0)
688 			difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
689 		if (difference == 0)
690 			return *middle;
691 		else if (difference < 0)
692 			low = middle + 1;
693 		else
694 			high = middle - 1;
695 	}
696 	return NULL;
697 }
698 
699 /*
700  * Find a DumpableObject by OID, in a pre-sorted array of one type of object
701  *
702  * Returns NULL for unknown OID
703  */
704 static DumpableObject *
705 findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
706 {
707 	DumpableObject **low;
708 	DumpableObject **high;
709 
710 	/*
711 	 * This is the same as findObjectByCatalogId except we assume we need not
712 	 * look at table OID because the objects are all the same type.
713 	 *
714 	 * We could use bsearch() here, but the notational cruft of calling
715 	 * bsearch is nearly as bad as doing it ourselves; and the generalized
716 	 * bsearch function is noticeably slower as well.
717 	 */
718 	if (numObjs <= 0)
719 		return NULL;
720 	low = indexArray;
721 	high = indexArray + (numObjs - 1);
722 	while (low <= high)
723 	{
724 		DumpableObject **middle;
725 		int			difference;
726 
727 		middle = low + (high - low) / 2;
728 		difference = oidcmp((*middle)->catId.oid, oid);
729 		if (difference == 0)
730 			return *middle;
731 		else if (difference < 0)
732 			low = middle + 1;
733 		else
734 			high = middle - 1;
735 	}
736 	return NULL;
737 }
738 
739 /*
740  * Build an index array of DumpableObject pointers, sorted by OID
741  */
742 static DumpableObject **
743 buildIndexArray(void *objArray, int numObjs, Size objSize)
744 {
745 	DumpableObject **ptrs;
746 	int			i;
747 
748 	ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
749 	for (i = 0; i < numObjs; i++)
750 		ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
751 
752 	/* We can use DOCatalogIdCompare to sort since its first key is OID */
753 	if (numObjs > 1)
754 		qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
755 			  DOCatalogIdCompare);
756 
757 	return ptrs;
758 }
759 
760 /*
761  * qsort comparator for pointers to DumpableObjects
762  */
763 static int
764 DOCatalogIdCompare(const void *p1, const void *p2)
765 {
766 	const DumpableObject *obj1 = *(DumpableObject *const *) p1;
767 	const DumpableObject *obj2 = *(DumpableObject *const *) p2;
768 	int			cmpval;
769 
770 	/*
771 	 * Compare OID first since it's usually unique, whereas there will only be
772 	 * a few distinct values of tableoid.
773 	 */
774 	cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
775 	if (cmpval == 0)
776 		cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
777 	return cmpval;
778 }
779 
780 /*
781  * Build an array of pointers to all known dumpable objects
782  *
783  * This simply creates a modifiable copy of the internal map.
784  */
785 void
786 getDumpableObjects(DumpableObject ***objs, int *numObjs)
787 {
788 	int			i,
789 				j;
790 
791 	*objs = (DumpableObject **)
792 		pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
793 	j = 0;
794 	for (i = 1; i < allocedDumpIds; i++)
795 	{
796 		if (dumpIdMap[i])
797 			(*objs)[j++] = dumpIdMap[i];
798 	}
799 	*numObjs = j;
800 }
801 
802 /*
803  * Add a dependency link to a DumpableObject
804  *
805  * Note: duplicate dependencies are currently not eliminated
806  */
807 void
808 addObjectDependency(DumpableObject *dobj, DumpId refId)
809 {
810 	if (dobj->nDeps >= dobj->allocDeps)
811 	{
812 		if (dobj->allocDeps <= 0)
813 		{
814 			dobj->allocDeps = 16;
815 			dobj->dependencies = (DumpId *)
816 				pg_malloc(dobj->allocDeps * sizeof(DumpId));
817 		}
818 		else
819 		{
820 			dobj->allocDeps *= 2;
821 			dobj->dependencies = (DumpId *)
822 				pg_realloc(dobj->dependencies,
823 						   dobj->allocDeps * sizeof(DumpId));
824 		}
825 	}
826 	dobj->dependencies[dobj->nDeps++] = refId;
827 }
828 
829 /*
830  * Remove a dependency link from a DumpableObject
831  *
832  * If there are multiple links, all are removed
833  */
834 void
835 removeObjectDependency(DumpableObject *dobj, DumpId refId)
836 {
837 	int			i;
838 	int			j = 0;
839 
840 	for (i = 0; i < dobj->nDeps; i++)
841 	{
842 		if (dobj->dependencies[i] != refId)
843 			dobj->dependencies[j++] = dobj->dependencies[i];
844 	}
845 	dobj->nDeps = j;
846 }
847 
848 
849 /*
850  * findTableByOid
851  *	  finds the entry (in tblinfo) of the table with the given oid
852  *	  returns NULL if not found
853  */
854 TableInfo *
855 findTableByOid(Oid oid)
856 {
857 	return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
858 }
859 
860 /*
861  * findTypeByOid
862  *	  finds the entry (in typinfo) of the type with the given oid
863  *	  returns NULL if not found
864  */
865 TypeInfo *
866 findTypeByOid(Oid oid)
867 {
868 	return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
869 }
870 
871 /*
872  * findFuncByOid
873  *	  finds the entry (in funinfo) of the function with the given oid
874  *	  returns NULL if not found
875  */
876 FuncInfo *
877 findFuncByOid(Oid oid)
878 {
879 	return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
880 }
881 
882 /*
883  * findOprByOid
884  *	  finds the entry (in oprinfo) of the operator with the given oid
885  *	  returns NULL if not found
886  */
887 OprInfo *
888 findOprByOid(Oid oid)
889 {
890 	return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
891 }
892 
893 /*
894  * findCollationByOid
895  *	  finds the entry (in collinfo) of the collation with the given oid
896  *	  returns NULL if not found
897  */
898 CollInfo *
899 findCollationByOid(Oid oid)
900 {
901 	return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
902 }
903 
904 /*
905  * findNamespaceByOid
906  *	  finds the entry (in nspinfo) of the namespace with the given oid
907  *	  returns NULL if not found
908  */
909 NamespaceInfo *
910 findNamespaceByOid(Oid oid)
911 {
912 	return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
913 }
914 
915 /*
916  * findExtensionByOid
917  *	  finds the entry (in extinfo) of the extension with the given oid
918  *	  returns NULL if not found
919  */
920 ExtensionInfo *
921 findExtensionByOid(Oid oid)
922 {
923 	return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
924 }
925 
926 /*
927  * findPublicationByOid
928  *	  finds the entry (in pubinfo) of the publication with the given oid
929  *	  returns NULL if not found
930  */
931 PublicationInfo *
932 findPublicationByOid(Oid oid)
933 {
934 	return (PublicationInfo *) findObjectByOid(oid, pubinfoindex, numPublications);
935 }
936 
937 /*
938  * findIndexByOid
939  *		find the entry of the index with the given oid
940  *
941  * This one's signature is different from the previous ones because we lack a
942  * global array of all indexes, so caller must pass their array as argument.
943  */
944 static IndxInfo *
945 findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
946 {
947 	return (IndxInfo *) findObjectByOid(oid, idxinfoindex, numIndexes);
948 }
949 
950 /*
951  * setExtensionMembership
952  *	  accept and save data about which objects belong to extensions
953  */
954 void
955 setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
956 {
957 	/* Sort array in preparation for binary searches */
958 	if (nextmems > 1)
959 		qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
960 			  ExtensionMemberIdCompare);
961 	/* And save */
962 	extmembers = extmems;
963 	numextmembers = nextmems;
964 }
965 
966 /*
967  * findOwningExtension
968  *	  return owning extension for specified catalog ID, or NULL if none
969  */
970 ExtensionInfo *
971 findOwningExtension(CatalogId catalogId)
972 {
973 	ExtensionMemberId *low;
974 	ExtensionMemberId *high;
975 
976 	/*
977 	 * We could use bsearch() here, but the notational cruft of calling
978 	 * bsearch is nearly as bad as doing it ourselves; and the generalized
979 	 * bsearch function is noticeably slower as well.
980 	 */
981 	if (numextmembers <= 0)
982 		return NULL;
983 	low = extmembers;
984 	high = extmembers + (numextmembers - 1);
985 	while (low <= high)
986 	{
987 		ExtensionMemberId *middle;
988 		int			difference;
989 
990 		middle = low + (high - low) / 2;
991 		/* comparison must match ExtensionMemberIdCompare, below */
992 		difference = oidcmp(middle->catId.oid, catalogId.oid);
993 		if (difference == 0)
994 			difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
995 		if (difference == 0)
996 			return middle->ext;
997 		else if (difference < 0)
998 			low = middle + 1;
999 		else
1000 			high = middle - 1;
1001 	}
1002 	return NULL;
1003 }
1004 
1005 /*
1006  * qsort comparator for ExtensionMemberIds
1007  */
1008 static int
1009 ExtensionMemberIdCompare(const void *p1, const void *p2)
1010 {
1011 	const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
1012 	const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
1013 	int			cmpval;
1014 
1015 	/*
1016 	 * Compare OID first since it's usually unique, whereas there will only be
1017 	 * a few distinct values of tableoid.
1018 	 */
1019 	cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
1020 	if (cmpval == 0)
1021 		cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
1022 	return cmpval;
1023 }
1024 
1025 
1026 /*
1027  * findParentsByOid
1028  *	  find a table's parents in tblinfo[]
1029  */
1030 static void
1031 findParentsByOid(TableInfo *self,
1032 				 InhInfo *inhinfo, int numInherits)
1033 {
1034 	Oid			oid = self->dobj.catId.oid;
1035 	int			i,
1036 				j;
1037 	int			numParents;
1038 
1039 	numParents = 0;
1040 	for (i = 0; i < numInherits; i++)
1041 	{
1042 		if (inhinfo[i].inhrelid == oid)
1043 			numParents++;
1044 	}
1045 
1046 	self->numParents = numParents;
1047 
1048 	if (numParents > 0)
1049 	{
1050 		self->parents = (TableInfo **)
1051 			pg_malloc(sizeof(TableInfo *) * numParents);
1052 		j = 0;
1053 		for (i = 0; i < numInherits; i++)
1054 		{
1055 			if (inhinfo[i].inhrelid == oid)
1056 			{
1057 				TableInfo  *parent;
1058 
1059 				parent = findTableByOid(inhinfo[i].inhparent);
1060 				if (parent == NULL)
1061 				{
1062 					pg_log_error("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
1063 								 inhinfo[i].inhparent,
1064 								 self->dobj.name,
1065 								 oid);
1066 					exit_nicely(1);
1067 				}
1068 				self->parents[j++] = parent;
1069 			}
1070 		}
1071 	}
1072 	else
1073 		self->parents = NULL;
1074 }
1075 
1076 /*
1077  * parseOidArray
1078  *	  parse a string of numbers delimited by spaces into a character array
1079  *
1080  * Note: actually this is used for both Oids and potentially-signed
1081  * attribute numbers.  This should cause no trouble, but we could split
1082  * the function into two functions with different argument types if it does.
1083  */
1084 
1085 void
1086 parseOidArray(const char *str, Oid *array, int arraysize)
1087 {
1088 	int			j,
1089 				argNum;
1090 	char		temp[100];
1091 	char		s;
1092 
1093 	argNum = 0;
1094 	j = 0;
1095 	for (;;)
1096 	{
1097 		s = *str++;
1098 		if (s == ' ' || s == '\0')
1099 		{
1100 			if (j > 0)
1101 			{
1102 				if (argNum >= arraysize)
1103 				{
1104 					pg_log_error("could not parse numeric array \"%s\": too many numbers", str);
1105 					exit_nicely(1);
1106 				}
1107 				temp[j] = '\0';
1108 				array[argNum++] = atooid(temp);
1109 				j = 0;
1110 			}
1111 			if (s == '\0')
1112 				break;
1113 		}
1114 		else
1115 		{
1116 			if (!(isdigit((unsigned char) s) || s == '-') ||
1117 				j >= sizeof(temp) - 1)
1118 			{
1119 				pg_log_error("could not parse numeric array \"%s\": invalid character in number", str);
1120 				exit_nicely(1);
1121 			}
1122 			temp[j++] = s;
1123 		}
1124 	}
1125 
1126 	while (argNum < arraysize)
1127 		array[argNum++] = InvalidOid;
1128 }
1129 
1130 
1131 /*
1132  * strInArray:
1133  *	  takes in a string and a string array and the number of elements in the
1134  * string array.
1135  *	  returns the index if the string is somewhere in the array, -1 otherwise
1136  */
1137 
1138 static int
1139 strInArray(const char *pattern, char **arr, int arr_size)
1140 {
1141 	int			i;
1142 
1143 	for (i = 0; i < arr_size; i++)
1144 	{
1145 		if (strcmp(pattern, arr[i]) == 0)
1146 			return i;
1147 	}
1148 	return -1;
1149 }
1150