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