]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/common.c
Revert addition of third argument to format_type().
[postgresql] / src / bin / pg_dump / common.c
1 /*-------------------------------------------------------------------------
2  *
3  * common.c
4  *        common routines between pg_dump and pg4_dump
5  *
6  * Since pg4_dump is long-dead code, there is no longer any useful distinction
7  * between this file and pg_dump.c.
8  *
9  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
10  * Portions Copyright (c) 1994, Regents of the University of California
11  *
12  *
13  * IDENTIFICATION
14  *        src/bin/pg_dump/common.c
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres_fe.h"
19
20 #include <ctype.h>
21
22 #include "catalog/pg_class.h"
23
24 #include "pg_backup_archiver.h"
25
26
27 /*
28  * Variables for mapping DumpId to DumpableObject
29  */
30 static DumpableObject **dumpIdMap = NULL;
31 static int      allocedDumpIds = 0;
32 static DumpId lastDumpId = 0;
33
34 /*
35  * Variables for mapping CatalogId to DumpableObject
36  */
37 static bool catalogIdMapValid = false;
38 static DumpableObject **catalogIdMap = NULL;
39 static int      numCatalogIds = 0;
40
41 /*
42  * These variables are static to avoid the notational cruft of having to pass
43  * them into findTableByOid() and friends.      For each of these arrays, we
44  * build a sorted-by-OID index array immediately after it's built, and then
45  * we use binary search in findTableByOid() and friends.  (qsort'ing the base
46  * arrays themselves would be simpler, but it doesn't work because pg_dump.c
47  * may have already established pointers between items.)
48  */
49 static TableInfo *tblinfo;
50 static TypeInfo *typinfo;
51 static FuncInfo *funinfo;
52 static OprInfo *oprinfo;
53 static int      numTables;
54 static int      numTypes;
55 static int      numFuncs;
56 static int      numOperators;
57 static int      numCollations;
58 static DumpableObject **tblinfoindex;
59 static DumpableObject **typinfoindex;
60 static DumpableObject **funinfoindex;
61 static DumpableObject **oprinfoindex;
62 static DumpableObject **collinfoindex;
63
64
65 static void flagInhTables(TableInfo *tbinfo, int numTables,
66                           InhInfo *inhinfo, int numInherits);
67 static void flagInhAttrs(TableInfo *tblinfo, int numTables);
68 static DumpableObject **buildIndexArray(void *objArray, int numObjs,
69                                 Size objSize);
70 static int      DOCatalogIdCompare(const void *p1, const void *p2);
71 static void findParentsByOid(TableInfo *self,
72                                  InhInfo *inhinfo, int numInherits);
73 static int      strInArray(const char *pattern, char **arr, int arr_size);
74
75
76 /*
77  * getSchemaData
78  *        Collect information about all potentially dumpable objects
79  */
80 TableInfo *
81 getSchemaData(int *numTablesPtr)
82 {
83         NamespaceInfo *nsinfo;
84         ExtensionInfo *extinfo;
85         AggInfo    *agginfo;
86         InhInfo    *inhinfo;
87         RuleInfo   *ruleinfo;
88         ProcLangInfo *proclanginfo;
89         CastInfo   *castinfo;
90         OpclassInfo *opcinfo;
91         OpfamilyInfo *opfinfo;
92         CollInfo   *collinfo;
93         ConvInfo   *convinfo;
94         TSParserInfo *prsinfo;
95         TSTemplateInfo *tmplinfo;
96         TSDictInfo *dictinfo;
97         TSConfigInfo *cfginfo;
98         FdwInfo    *fdwinfo;
99         ForeignServerInfo *srvinfo;
100         DefaultACLInfo *daclinfo;
101         int                     numNamespaces;
102         int                     numExtensions;
103         int                     numAggregates;
104         int                     numInherits;
105         int                     numRules;
106         int                     numProcLangs;
107         int                     numCasts;
108         int                     numOpclasses;
109         int                     numOpfamilies;
110         int                     numConversions;
111         int                     numTSParsers;
112         int                     numTSTemplates;
113         int                     numTSDicts;
114         int                     numTSConfigs;
115         int                     numForeignDataWrappers;
116         int                     numForeignServers;
117         int                     numDefaultACLs;
118
119         if (g_verbose)
120                 write_msg(NULL, "reading schemas\n");
121         nsinfo = getNamespaces(&numNamespaces);
122
123         if (g_verbose)
124                 write_msg(NULL, "reading extensions\n");
125         extinfo = getExtensions(&numExtensions);
126
127         if (g_verbose)
128                 write_msg(NULL, "reading user-defined functions\n");
129         funinfo = getFuncs(&numFuncs);
130         funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
131
132         /* this must be after getFuncs */
133         if (g_verbose)
134                 write_msg(NULL, "reading user-defined types\n");
135         typinfo = getTypes(&numTypes);
136         typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
137
138         /* this must be after getFuncs, too */
139         if (g_verbose)
140                 write_msg(NULL, "reading procedural languages\n");
141         proclanginfo = getProcLangs(&numProcLangs);
142
143         if (g_verbose)
144                 write_msg(NULL, "reading user-defined aggregate functions\n");
145         agginfo = getAggregates(&numAggregates);
146
147         if (g_verbose)
148                 write_msg(NULL, "reading user-defined operators\n");
149         oprinfo = getOperators(&numOperators);
150         oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
151
152         if (g_verbose)
153                 write_msg(NULL, "reading user-defined operator classes\n");
154         opcinfo = getOpclasses(&numOpclasses);
155
156         if (g_verbose)
157                 write_msg(NULL, "reading user-defined operator families\n");
158         opfinfo = getOpfamilies(&numOpfamilies);
159
160         if (g_verbose)
161                 write_msg(NULL, "reading user-defined text search parsers\n");
162         prsinfo = getTSParsers(&numTSParsers);
163
164         if (g_verbose)
165                 write_msg(NULL, "reading user-defined text search templates\n");
166         tmplinfo = getTSTemplates(&numTSTemplates);
167
168         if (g_verbose)
169                 write_msg(NULL, "reading user-defined text search dictionaries\n");
170         dictinfo = getTSDictionaries(&numTSDicts);
171
172         if (g_verbose)
173                 write_msg(NULL, "reading user-defined text search configurations\n");
174         cfginfo = getTSConfigurations(&numTSConfigs);
175
176         if (g_verbose)
177                 write_msg(NULL, "reading user-defined foreign-data wrappers\n");
178         fdwinfo = getForeignDataWrappers(&numForeignDataWrappers);
179
180         if (g_verbose)
181                 write_msg(NULL, "reading user-defined foreign servers\n");
182         srvinfo = getForeignServers(&numForeignServers);
183
184         if (g_verbose)
185                 write_msg(NULL, "reading default privileges\n");
186         daclinfo = getDefaultACLs(&numDefaultACLs);
187
188         if (g_verbose)
189                 write_msg(NULL, "reading user-defined collations\n");
190         collinfo = getCollations(&numCollations);
191         collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
192
193         if (g_verbose)
194                 write_msg(NULL, "reading user-defined conversions\n");
195         convinfo = getConversions(&numConversions);
196
197         if (g_verbose)
198                 write_msg(NULL, "reading type casts\n");
199         castinfo = getCasts(&numCasts);
200
201         if (g_verbose)
202                 write_msg(NULL, "reading user-defined tables\n");
203         tblinfo = getTables(&numTables);
204         tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
205
206         if (g_verbose)
207                 write_msg(NULL, "reading table inheritance information\n");
208         inhinfo = getInherits(&numInherits);
209
210         if (g_verbose)
211                 write_msg(NULL, "reading rewrite rules\n");
212         ruleinfo = getRules(&numRules);
213
214         /*
215          * Identify extension member objects and mark them as not to be dumped.
216          * This must happen after reading all objects that can be direct members
217          * of extensions, but before we begin to process table subsidiary objects.
218          */
219         if (g_verbose)
220                 write_msg(NULL, "finding extension members\n");
221         getExtensionMembership(extinfo, numExtensions);
222
223         /* Link tables to parents, mark parents of target tables interesting */
224         if (g_verbose)
225                 write_msg(NULL, "finding inheritance relationships\n");
226         flagInhTables(tblinfo, numTables, inhinfo, numInherits);
227
228         if (g_verbose)
229                 write_msg(NULL, "reading column info for interesting tables\n");
230         getTableAttrs(tblinfo, numTables);
231
232         if (g_verbose)
233                 write_msg(NULL, "flagging inherited columns in subtables\n");
234         flagInhAttrs(tblinfo, numTables);
235
236         if (g_verbose)
237                 write_msg(NULL, "reading indexes\n");
238         getIndexes(tblinfo, numTables);
239
240         if (g_verbose)
241                 write_msg(NULL, "reading constraints\n");
242         getConstraints(tblinfo, numTables);
243
244         if (g_verbose)
245                 write_msg(NULL, "reading triggers\n");
246         getTriggers(tblinfo, numTables);
247
248         *numTablesPtr = numTables;
249         return tblinfo;
250 }
251
252 /* flagInhTables -
253  *       Fill in parent link fields of every target table, and mark
254  *       parents of target tables as interesting
255  *
256  * Note that only direct ancestors of targets are marked interesting.
257  * This is sufficient; we don't much care whether they inherited their
258  * attributes or not.
259  *
260  * modifies tblinfo
261  */
262 static void
263 flagInhTables(TableInfo *tblinfo, int numTables,
264                           InhInfo *inhinfo, int numInherits)
265 {
266         int                     i,
267                                 j;
268         int                     numParents;
269         TableInfo **parents;
270
271         for (i = 0; i < numTables; i++)
272         {
273                 /* Sequences and views never have parents */
274                 if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
275                         tblinfo[i].relkind == RELKIND_VIEW)
276                         continue;
277
278                 /* Don't bother computing anything for non-target tables, either */
279                 if (!tblinfo[i].dobj.dump)
280                         continue;
281
282                 /* Find all the immediate parent tables */
283                 findParentsByOid(&tblinfo[i], inhinfo, numInherits);
284
285                 /* Mark the parents as interesting for getTableAttrs */
286                 numParents = tblinfo[i].numParents;
287                 parents = tblinfo[i].parents;
288                 for (j = 0; j < numParents; j++)
289                         parents[j]->interesting = true;
290         }
291 }
292
293 /* flagInhAttrs -
294  *       for each dumpable table in tblinfo, flag its inherited attributes
295  * so when we dump the table out, we don't dump out the inherited attributes
296  *
297  * modifies tblinfo
298  */
299 static void
300 flagInhAttrs(TableInfo *tblinfo, int numTables)
301 {
302         int                     i,
303                                 j,
304                                 k;
305
306         for (i = 0; i < numTables; i++)
307         {
308                 TableInfo  *tbinfo = &(tblinfo[i]);
309                 int                     numParents;
310                 TableInfo **parents;
311                 TableInfo  *parent;
312
313                 /* Sequences and views never have parents */
314                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
315                         tbinfo->relkind == RELKIND_VIEW)
316                         continue;
317
318                 /* Don't bother computing anything for non-target tables, either */
319                 if (!tbinfo->dobj.dump)
320                         continue;
321
322                 numParents = tbinfo->numParents;
323                 parents = tbinfo->parents;
324
325                 if (numParents == 0)
326                         continue;                       /* nothing to see here, move along */
327
328                 /*----------------------------------------------------------------
329                  * For each attr, check the parent info: if no parent has an attr
330                  * with the same name, then it's not inherited. If there *is* an
331                  * attr with the same name, then only dump it if:
332                  *
333                  * - it is NOT NULL and zero parents are NOT NULL
334                  *       OR
335                  * - it has a default value AND the default value does not match
336                  *       all parent default values, or no parents specify a default.
337                  *
338                  * See discussion on -hackers around 2-Apr-2001.
339                  *----------------------------------------------------------------
340                  */
341                 for (j = 0; j < tbinfo->numatts; j++)
342                 {
343                         bool            foundAttr;              /* Attr was found in a parent */
344                         bool            foundNotNull;   /* Attr was NOT NULL in a parent */
345                         bool            defaultsMatch;  /* All non-empty defaults match */
346                         bool            defaultsFound;  /* Found a default in a parent */
347                         AttrDefInfo *attrDef;
348
349                         foundAttr = false;
350                         foundNotNull = false;
351                         defaultsMatch = true;
352                         defaultsFound = false;
353
354                         attrDef = tbinfo->attrdefs[j];
355
356                         for (k = 0; k < numParents; k++)
357                         {
358                                 int                     inhAttrInd;
359
360                                 parent = parents[k];
361                                 inhAttrInd = strInArray(tbinfo->attnames[j],
362                                                                                 parent->attnames,
363                                                                                 parent->numatts);
364
365                                 if (inhAttrInd != -1)
366                                 {
367                                         AttrDefInfo *inhDef = parent->attrdefs[inhAttrInd];
368
369                                         foundAttr = true;
370                                         foundNotNull |= parent->notnull[inhAttrInd];
371                                         if (inhDef != NULL)
372                                         {
373                                                 defaultsFound = true;
374
375                                                 /*
376                                                  * If any parent has a default and the child doesn't,
377                                                  * we have to emit an explicit DEFAULT NULL clause for
378                                                  * the child, else the parent's default will win.
379                                                  */
380                                                 if (attrDef == NULL)
381                                                 {
382                                                         attrDef = (AttrDefInfo *) malloc(sizeof(AttrDefInfo));
383                                                         attrDef->dobj.objType = DO_ATTRDEF;
384                                                         attrDef->dobj.catId.tableoid = 0;
385                                                         attrDef->dobj.catId.oid = 0;
386                                                         AssignDumpId(&attrDef->dobj);
387                                                         attrDef->adtable = tbinfo;
388                                                         attrDef->adnum = j + 1;
389                                                         attrDef->adef_expr = strdup("NULL");
390
391                                                         attrDef->dobj.name = strdup(tbinfo->dobj.name);
392                                                         attrDef->dobj.namespace = tbinfo->dobj.namespace;
393
394                                                         attrDef->dobj.dump = tbinfo->dobj.dump;
395
396                                                         attrDef->separate = false;
397                                                         addObjectDependency(&tbinfo->dobj,
398                                                                                                 attrDef->dobj.dumpId);
399
400                                                         tbinfo->attrdefs[j] = attrDef;
401                                                 }
402                                                 if (strcmp(attrDef->adef_expr, inhDef->adef_expr) != 0)
403                                                 {
404                                                         defaultsMatch = false;
405
406                                                         /*
407                                                          * Whenever there is a non-matching parent
408                                                          * default, add a dependency to force the parent
409                                                          * default to be dumped first, in case the
410                                                          * defaults end up being dumped as separate
411                                                          * commands.  Otherwise the parent default will
412                                                          * override the child's when it is applied.
413                                                          */
414                                                         addObjectDependency(&attrDef->dobj,
415                                                                                                 inhDef->dobj.dumpId);
416                                                 }
417                                         }
418                                 }
419                         }
420
421                         /*
422                          * Based on the scan of the parents, decide if we can rely on the
423                          * inherited attr
424                          */
425                         if (foundAttr)          /* Attr was inherited */
426                         {
427                                 /* Set inherited flag by default */
428                                 tbinfo->inhAttrs[j] = true;
429                                 tbinfo->inhAttrDef[j] = true;
430                                 tbinfo->inhNotNull[j] = true;
431
432                                 /*
433                                  * Clear it if attr had a default, but parents did not, or
434                                  * mismatch
435                                  */
436                                 if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch))
437                                 {
438                                         tbinfo->inhAttrs[j] = false;
439                                         tbinfo->inhAttrDef[j] = false;
440                                 }
441
442                                 /*
443                                  * Clear it if NOT NULL and none of the parents were NOT NULL
444                                  */
445                                 if (tbinfo->notnull[j] && !foundNotNull)
446                                 {
447                                         tbinfo->inhAttrs[j] = false;
448                                         tbinfo->inhNotNull[j] = false;
449                                 }
450
451                                 /* Clear it if attr has local definition */
452                                 if (tbinfo->attislocal[j])
453                                         tbinfo->inhAttrs[j] = false;
454                         }
455                 }
456         }
457 }
458
459 /*
460  * AssignDumpId
461  *              Given a newly-created dumpable object, assign a dump ID,
462  *              and enter the object into the lookup table.
463  *
464  * The caller is expected to have filled in objType and catId,
465  * but not any of the other standard fields of a DumpableObject.
466  */
467 void
468 AssignDumpId(DumpableObject *dobj)
469 {
470         dobj->dumpId = ++lastDumpId;
471         dobj->name = NULL;                      /* must be set later */
472         dobj->namespace = NULL;         /* may be set later */
473         dobj->dump = true;                      /* default assumption */
474         dobj->ext_member = false;       /* default assumption */
475         dobj->dependencies = NULL;
476         dobj->nDeps = 0;
477         dobj->allocDeps = 0;
478
479         while (dobj->dumpId >= allocedDumpIds)
480         {
481                 int                     newAlloc;
482
483                 if (allocedDumpIds <= 0)
484                 {
485                         newAlloc = 256;
486                         dumpIdMap = (DumpableObject **)
487                                 pg_malloc(newAlloc * sizeof(DumpableObject *));
488                 }
489                 else
490                 {
491                         newAlloc = allocedDumpIds * 2;
492                         dumpIdMap = (DumpableObject **)
493                                 pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
494                 }
495                 memset(dumpIdMap + allocedDumpIds, 0,
496                            (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
497                 allocedDumpIds = newAlloc;
498         }
499         dumpIdMap[dobj->dumpId] = dobj;
500
501         /* mark catalogIdMap invalid, but don't rebuild it yet */
502         catalogIdMapValid = false;
503 }
504
505 /*
506  * Assign a DumpId that's not tied to a DumpableObject.
507  *
508  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
509  * participate in the sorting logic.
510  */
511 DumpId
512 createDumpId(void)
513 {
514         return ++lastDumpId;
515 }
516
517 /*
518  * Return the largest DumpId so far assigned
519  */
520 DumpId
521 getMaxDumpId(void)
522 {
523         return lastDumpId;
524 }
525
526 /*
527  * Find a DumpableObject by dump ID
528  *
529  * Returns NULL for invalid ID
530  */
531 DumpableObject *
532 findObjectByDumpId(DumpId dumpId)
533 {
534         if (dumpId <= 0 || dumpId >= allocedDumpIds)
535                 return NULL;                    /* out of range? */
536         return dumpIdMap[dumpId];
537 }
538
539 /*
540  * Find a DumpableObject by catalog ID
541  *
542  * Returns NULL for unknown ID
543  *
544  * We use binary search in a sorted list that is built on first call.
545  * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
546  * the code would work, but possibly be very slow.      In the current usage
547  * pattern that does not happen, indeed we build the list at most twice.
548  */
549 DumpableObject *
550 findObjectByCatalogId(CatalogId catalogId)
551 {
552         DumpableObject **low;
553         DumpableObject **high;
554
555         if (!catalogIdMapValid)
556         {
557                 if (catalogIdMap)
558                         free(catalogIdMap);
559                 getDumpableObjects(&catalogIdMap, &numCatalogIds);
560                 if (numCatalogIds > 1)
561                         qsort((void *) catalogIdMap, numCatalogIds,
562                                   sizeof(DumpableObject *), DOCatalogIdCompare);
563                 catalogIdMapValid = true;
564         }
565
566         /*
567          * We could use bsearch() here, but the notational cruft of calling
568          * bsearch is nearly as bad as doing it ourselves; and the generalized
569          * bsearch function is noticeably slower as well.
570          */
571         if (numCatalogIds <= 0)
572                 return NULL;
573         low = catalogIdMap;
574         high = catalogIdMap + (numCatalogIds - 1);
575         while (low <= high)
576         {
577                 DumpableObject **middle;
578                 int                     difference;
579
580                 middle = low + (high - low) / 2;
581                 /* comparison must match DOCatalogIdCompare, below */
582                 difference = oidcmp((*middle)->catId.oid, catalogId.oid);
583                 if (difference == 0)
584                         difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
585                 if (difference == 0)
586                         return *middle;
587                 else if (difference < 0)
588                         low = middle + 1;
589                 else
590                         high = middle - 1;
591         }
592         return NULL;
593 }
594
595 /*
596  * Find a DumpableObject by OID, in a pre-sorted array of one type of object
597  *
598  * Returns NULL for unknown OID
599  */
600 static DumpableObject *
601 findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
602 {
603         DumpableObject **low;
604         DumpableObject **high;
605
606         /*
607          * This is the same as findObjectByCatalogId except we assume we need not
608          * look at table OID because the objects are all the same type.
609          *
610          * We could use bsearch() here, but the notational cruft of calling
611          * bsearch is nearly as bad as doing it ourselves; and the generalized
612          * bsearch function is noticeably slower as well.
613          */
614         if (numObjs <= 0)
615                 return NULL;
616         low = indexArray;
617         high = indexArray + (numObjs - 1);
618         while (low <= high)
619         {
620                 DumpableObject **middle;
621                 int                     difference;
622
623                 middle = low + (high - low) / 2;
624                 difference = oidcmp((*middle)->catId.oid, oid);
625                 if (difference == 0)
626                         return *middle;
627                 else if (difference < 0)
628                         low = middle + 1;
629                 else
630                         high = middle - 1;
631         }
632         return NULL;
633 }
634
635 /*
636  * Build an index array of DumpableObject pointers, sorted by OID
637  */
638 static DumpableObject **
639 buildIndexArray(void *objArray, int numObjs, Size objSize)
640 {
641         DumpableObject **ptrs;
642         int                     i;
643
644         ptrs = (DumpableObject **) malloc(numObjs * sizeof(DumpableObject *));
645         for (i = 0; i < numObjs; i++)
646                 ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
647
648         /* We can use DOCatalogIdCompare to sort since its first key is OID */
649         if (numObjs > 1)
650                 qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
651                           DOCatalogIdCompare);
652
653         return ptrs;
654 }
655
656 /*
657  * qsort comparator for pointers to DumpableObjects
658  */
659 static int
660 DOCatalogIdCompare(const void *p1, const void *p2)
661 {
662         DumpableObject *obj1 = *(DumpableObject **) p1;
663         DumpableObject *obj2 = *(DumpableObject **) p2;
664         int                     cmpval;
665
666         /*
667          * Compare OID first since it's usually unique, whereas there will only be
668          * a few distinct values of tableoid.
669          */
670         cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
671         if (cmpval == 0)
672                 cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
673         return cmpval;
674 }
675
676 /*
677  * Build an array of pointers to all known dumpable objects
678  *
679  * This simply creates a modifiable copy of the internal map.
680  */
681 void
682 getDumpableObjects(DumpableObject ***objs, int *numObjs)
683 {
684         int                     i,
685                                 j;
686
687         *objs = (DumpableObject **)
688                 pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
689         j = 0;
690         for (i = 1; i < allocedDumpIds; i++)
691         {
692                 if (dumpIdMap[i])
693                         (*objs)[j++] = dumpIdMap[i];
694         }
695         *numObjs = j;
696 }
697
698 /*
699  * Add a dependency link to a DumpableObject
700  *
701  * Note: duplicate dependencies are currently not eliminated
702  */
703 void
704 addObjectDependency(DumpableObject *dobj, DumpId refId)
705 {
706         if (dobj->nDeps >= dobj->allocDeps)
707         {
708                 if (dobj->allocDeps <= 0)
709                 {
710                         dobj->allocDeps = 16;
711                         dobj->dependencies = (DumpId *)
712                                 pg_malloc(dobj->allocDeps * sizeof(DumpId));
713                 }
714                 else
715                 {
716                         dobj->allocDeps *= 2;
717                         dobj->dependencies = (DumpId *)
718                                 pg_realloc(dobj->dependencies,
719                                                    dobj->allocDeps * sizeof(DumpId));
720                 }
721         }
722         dobj->dependencies[dobj->nDeps++] = refId;
723 }
724
725 /*
726  * Remove a dependency link from a DumpableObject
727  *
728  * If there are multiple links, all are removed
729  */
730 void
731 removeObjectDependency(DumpableObject *dobj, DumpId refId)
732 {
733         int                     i;
734         int                     j = 0;
735
736         for (i = 0; i < dobj->nDeps; i++)
737         {
738                 if (dobj->dependencies[i] != refId)
739                         dobj->dependencies[j++] = dobj->dependencies[i];
740         }
741         dobj->nDeps = j;
742 }
743
744
745 /*
746  * findTableByOid
747  *        finds the entry (in tblinfo) of the table with the given oid
748  *        returns NULL if not found
749  */
750 TableInfo *
751 findTableByOid(Oid oid)
752 {
753         return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
754 }
755
756 /*
757  * findTypeByOid
758  *        finds the entry (in typinfo) of the type with the given oid
759  *        returns NULL if not found
760  */
761 TypeInfo *
762 findTypeByOid(Oid oid)
763 {
764         return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
765 }
766
767 /*
768  * findFuncByOid
769  *        finds the entry (in funinfo) of the function with the given oid
770  *        returns NULL if not found
771  */
772 FuncInfo *
773 findFuncByOid(Oid oid)
774 {
775         return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
776 }
777
778 /*
779  * findOprByOid
780  *        finds the entry (in oprinfo) of the operator with the given oid
781  *        returns NULL if not found
782  */
783 OprInfo *
784 findOprByOid(Oid oid)
785 {
786         return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
787 }
788
789 /*
790  * findCollationByOid
791  *        finds the entry (in collinfo) of the collation with the given oid
792  *        returns NULL if not found
793  */
794 CollInfo *
795 findCollationByOid(Oid oid)
796 {
797         return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
798 }
799
800
801 /*
802  * findParentsByOid
803  *        find a table's parents in tblinfo[]
804  */
805 static void
806 findParentsByOid(TableInfo *self,
807                                  InhInfo *inhinfo, int numInherits)
808 {
809         Oid                     oid = self->dobj.catId.oid;
810         int                     i,
811                                 j;
812         int                     numParents;
813
814         numParents = 0;
815         for (i = 0; i < numInherits; i++)
816         {
817                 if (inhinfo[i].inhrelid == oid)
818                         numParents++;
819         }
820
821         self->numParents = numParents;
822
823         if (numParents > 0)
824         {
825                 self->parents = (TableInfo **)
826                         pg_malloc(sizeof(TableInfo *) * numParents);
827                 j = 0;
828                 for (i = 0; i < numInherits; i++)
829                 {
830                         if (inhinfo[i].inhrelid == oid)
831                         {
832                                 TableInfo  *parent;
833
834                                 parent = findTableByOid(inhinfo[i].inhparent);
835                                 if (parent == NULL)
836                                 {
837                                         write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
838                                                           inhinfo[i].inhparent,
839                                                           self->dobj.name,
840                                                           oid);
841                                         exit_nicely();
842                                 }
843                                 self->parents[j++] = parent;
844                         }
845                 }
846         }
847         else
848                 self->parents = NULL;
849 }
850
851 /*
852  * parseOidArray
853  *        parse a string of numbers delimited by spaces into a character array
854  *
855  * Note: actually this is used for both Oids and potentially-signed
856  * attribute numbers.  This should cause no trouble, but we could split
857  * the function into two functions with different argument types if it does.
858  */
859
860 void
861 parseOidArray(const char *str, Oid *array, int arraysize)
862 {
863         int                     j,
864                                 argNum;
865         char            temp[100];
866         char            s;
867
868         argNum = 0;
869         j = 0;
870         for (;;)
871         {
872                 s = *str++;
873                 if (s == ' ' || s == '\0')
874                 {
875                         if (j > 0)
876                         {
877                                 if (argNum >= arraysize)
878                                 {
879                                         write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
880                                         exit_nicely();
881                                 }
882                                 temp[j] = '\0';
883                                 array[argNum++] = atooid(temp);
884                                 j = 0;
885                         }
886                         if (s == '\0')
887                                 break;
888                 }
889                 else
890                 {
891                         if (!(isdigit((unsigned char) s) || s == '-') ||
892                                 j >= sizeof(temp) - 1)
893                         {
894                                 write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
895                                 exit_nicely();
896                         }
897                         temp[j++] = s;
898                 }
899         }
900
901         while (argNum < arraysize)
902                 array[argNum++] = InvalidOid;
903 }
904
905
906 /*
907  * strInArray:
908  *        takes in a string and a string array and the number of elements in the
909  * string array.
910  *        returns the index if the string is somewhere in the array, -1 otherwise
911  */
912
913 static int
914 strInArray(const char *pattern, char **arr, int arr_size)
915 {
916         int                     i;
917
918         for (i = 0; i < arr_size; i++)
919         {
920                 if (strcmp(pattern, arr[i]) == 0)
921                         return i;
922         }
923         return -1;
924 }
925
926
927 /*
928  * Support for simple list operations
929  */
930
931 void
932 simple_oid_list_append(SimpleOidList *list, Oid val)
933 {
934         SimpleOidListCell *cell;
935
936         cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
937         cell->next = NULL;
938         cell->val = val;
939
940         if (list->tail)
941                 list->tail->next = cell;
942         else
943                 list->head = cell;
944         list->tail = cell;
945 }
946
947 void
948 simple_string_list_append(SimpleStringList *list, const char *val)
949 {
950         SimpleStringListCell *cell;
951
952         /* this calculation correctly accounts for the null trailing byte */
953         cell = (SimpleStringListCell *)
954                 pg_malloc(sizeof(SimpleStringListCell) + strlen(val));
955         cell->next = NULL;
956         strcpy(cell->val, val);
957
958         if (list->tail)
959                 list->tail->next = cell;
960         else
961                 list->head = cell;
962         list->tail = cell;
963 }
964
965 bool
966 simple_oid_list_member(SimpleOidList *list, Oid val)
967 {
968         SimpleOidListCell *cell;
969
970         for (cell = list->head; cell; cell = cell->next)
971         {
972                 if (cell->val == val)
973                         return true;
974         }
975         return false;
976 }
977
978 bool
979 simple_string_list_member(SimpleStringList *list, const char *val)
980 {
981         SimpleStringListCell *cell;
982
983         for (cell = list->head; cell; cell = cell->next)
984         {
985                 if (strcmp(cell->val, val) == 0)
986                         return true;
987         }
988         return false;
989 }
990
991
992 /*
993  * Safer versions of some standard C library functions. If an
994  * out-of-memory condition occurs, these functions will bail out
995  * safely; therefore, their return value is guaranteed to be non-NULL.
996  *
997  * XXX need to refactor things so that these can be in a file that can be
998  * shared by pg_dumpall and pg_restore as well as pg_dump.
999  */
1000
1001 char *
1002 pg_strdup(const char *string)
1003 {
1004         char       *tmp;
1005
1006         if (!string)
1007                 exit_horribly(NULL, NULL, "cannot duplicate null pointer\n");
1008         tmp = strdup(string);
1009         if (!tmp)
1010                 exit_horribly(NULL, NULL, "out of memory\n");
1011         return tmp;
1012 }
1013
1014 void *
1015 pg_malloc(size_t size)
1016 {
1017         void       *tmp;
1018
1019         tmp = malloc(size);
1020         if (!tmp)
1021                 exit_horribly(NULL, NULL, "out of memory\n");
1022         return tmp;
1023 }
1024
1025 void *
1026 pg_calloc(size_t nmemb, size_t size)
1027 {
1028         void       *tmp;
1029
1030         tmp = calloc(nmemb, size);
1031         if (!tmp)
1032                 exit_horribly(NULL, NULL, "out of memory\n");
1033         return tmp;
1034 }
1035
1036 void *
1037 pg_realloc(void *ptr, size_t size)
1038 {
1039         void       *tmp;
1040
1041         tmp = realloc(ptr, size);
1042         if (!tmp)
1043                 exit_horribly(NULL, NULL, "out of memory\n");
1044         return tmp;
1045 }