]> granicus.if.org Git - postgresql/blobdiff - src/bin/pg_dump/common.c
Create libpgcommon, and move pg_malloc et al to it
[postgresql] / src / bin / pg_dump / common.c
index c8ef9ff2cc7a1387cd4e273aa0a33ecbf6b2d125..01739ab717c9ca1c50df9223dcb02e8a631c7dd0 100644 (file)
@@ -1,34 +1,23 @@
 /*-------------------------------------------------------------------------
  *
  * common.c
- *       common routines between pg_dump and pg4_dump
+ *     Catalog routines used by pg_dump; long ago these were shared
+ *     by another dump tool, but not anymore.
  *
- * Since pg4_dump is long-dead code, there is no longer any useful distinction
- * between this file and pg_dump.c.
- *
- * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.82 2004/05/20 17:13:52 tgl Exp $
+ *       src/bin/pg_dump/common.c
  *
  *-------------------------------------------------------------------------
  */
-
-#include "postgres_fe.h"
-#include "pg_dump.h"
 #include "pg_backup_archiver.h"
 
-#include "postgres.h"
-#include "catalog/pg_class.h"
-
 #include <ctype.h>
 
-#include "libpq-fe.h"
-#ifndef HAVE_STRDUP
-#include "strdup.h"
-#endif
+#include "catalog/pg_class.h"
 
 
 /*
@@ -47,25 +36,39 @@ static int  numCatalogIds = 0;
 
 /*
  * These variables are static to avoid the notational cruft of having to pass
- * them into findTableByOid() and friends.
+ * them into findTableByOid() and friends.     For each of these arrays, we
+ * build a sorted-by-OID index array immediately after it's built, and then
+ * we use binary search in findTableByOid() and friends.  (qsort'ing the base
+ * arrays themselves would be simpler, but it doesn't work because pg_dump.c
+ * may have already established pointers between items.)
  */
-static TableInfo  *tblinfo;
-static TypeInfo   *typinfo;
-static FuncInfo   *funinfo;
-static OprInfo    *oprinfo;
-static int             numTables;
-static int             numTypes;
-static int             numFuncs;
-static int             numOperators;
+static TableInfo *tblinfo;
+static TypeInfo *typinfo;
+static FuncInfo *funinfo;
+static OprInfo *oprinfo;
+static NamespaceInfo *nspinfo;
+static int     numTables;
+static int     numTypes;
+static int     numFuncs;
+static int     numOperators;
+static int     numCollations;
+static int     numNamespaces;
+static DumpableObject **tblinfoindex;
+static DumpableObject **typinfoindex;
+static DumpableObject **funinfoindex;
+static DumpableObject **oprinfoindex;
+static DumpableObject **collinfoindex;
+static DumpableObject **nspinfoindex;
 
 
 static void flagInhTables(TableInfo *tbinfo, int numTables,
                          InhInfo *inhinfo, int numInherits);
-static void flagInhAttrs(TableInfo *tbinfo, int numTables,
-                        InhInfo *inhinfo, int numInherits);
+static void flagInhAttrs(TableInfo *tblinfo, int numTables);
+static DumpableObject **buildIndexArray(void *objArray, int numObjs,
+                               Size objSize);
 static int     DOCatalogIdCompare(const void *p1, const void *p2);
 static void findParentsByOid(TableInfo *self,
-                                                        InhInfo *inhinfo, int numInherits);
+                                InhInfo *inhinfo, int numInherits);
 static int     strInArray(const char *pattern, char **arr, int arr_size);
 
 
@@ -74,76 +77,142 @@ static int strInArray(const char *pattern, char **arr, int arr_size);
  *       Collect information about all potentially dumpable objects
  */
 TableInfo *
-getSchemaData(int *numTablesPtr,
-                         const bool schemaOnly,
-                         const bool dataOnly)
+getSchemaData(Archive *fout, int *numTablesPtr)
 {
-       NamespaceInfo *nsinfo;
-       AggInfo    *agginfo;
+       ExtensionInfo *extinfo;
        InhInfo    *inhinfo;
-       RuleInfo   *ruleinfo;
-       ProcLangInfo *proclanginfo;
-       CastInfo   *castinfo;
-       OpclassInfo *opcinfo;
-       ConvInfo   *convinfo;
-       int                     numNamespaces;
+       CollInfo   *collinfo;
+       int                     numExtensions;
        int                     numAggregates;
        int                     numInherits;
        int                     numRules;
        int                     numProcLangs;
        int                     numCasts;
        int                     numOpclasses;
+       int                     numOpfamilies;
        int                     numConversions;
+       int                     numTSParsers;
+       int                     numTSTemplates;
+       int                     numTSDicts;
+       int                     numTSConfigs;
+       int                     numForeignDataWrappers;
+       int                     numForeignServers;
+       int                     numDefaultACLs;
+       int                     numEventTriggers;
 
        if (g_verbose)
                write_msg(NULL, "reading schemas\n");
-       nsinfo = getNamespaces(&numNamespaces);
+       nspinfo = getNamespaces(fout, &numNamespaces);
+       nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
+
+       /*
+        * getTables should be done as soon as possible, so as to minimize the
+        * window between starting our transaction and acquiring per-table locks.
+        * However, we have to do getNamespaces first because the tables get
+        * linked to their containing namespaces during getTables.
+        */
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined tables\n");
+       tblinfo = getTables(fout, &numTables);
+       tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
+
+       /* Do this after we've built tblinfoindex */
+       getOwnedSeqs(fout, tblinfo, numTables);
+
+       if (g_verbose)
+               write_msg(NULL, "reading extensions\n");
+       extinfo = getExtensions(fout, &numExtensions);
 
        if (g_verbose)
                write_msg(NULL, "reading user-defined functions\n");
-       funinfo = getFuncs(&numFuncs);
+       funinfo = getFuncs(fout, &numFuncs);
+       funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
 
-       /* this must be after getFuncs */
+       /* this must be after getTables and getFuncs */
        if (g_verbose)
                write_msg(NULL, "reading user-defined types\n");
-       typinfo = getTypes(&numTypes);
+       typinfo = getTypes(fout, &numTypes);
+       typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
 
        /* this must be after getFuncs, too */
        if (g_verbose)
                write_msg(NULL, "reading procedural languages\n");
-       proclanginfo = getProcLangs(&numProcLangs);
+       getProcLangs(fout, &numProcLangs);
 
        if (g_verbose)
                write_msg(NULL, "reading user-defined aggregate functions\n");
-       agginfo = getAggregates(&numAggregates);
+       getAggregates(fout, &numAggregates);
 
        if (g_verbose)
                write_msg(NULL, "reading user-defined operators\n");
-       oprinfo = getOperators(&numOperators);
+       oprinfo = getOperators(fout, &numOperators);
+       oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
 
        if (g_verbose)
                write_msg(NULL, "reading user-defined operator classes\n");
-       opcinfo = getOpclasses(&numOpclasses);
+       getOpclasses(fout, &numOpclasses);
+
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined operator families\n");
+       getOpfamilies(fout, &numOpfamilies);
+
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined text search parsers\n");
+       getTSParsers(fout, &numTSParsers);
+
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined text search templates\n");
+       getTSTemplates(fout, &numTSTemplates);
+
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined text search dictionaries\n");
+       getTSDictionaries(fout, &numTSDicts);
+
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined text search configurations\n");
+       getTSConfigurations(fout, &numTSConfigs);
+
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined foreign-data wrappers\n");
+       getForeignDataWrappers(fout, &numForeignDataWrappers);
+
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined foreign servers\n");
+       getForeignServers(fout, &numForeignServers);
+
+       if (g_verbose)
+               write_msg(NULL, "reading default privileges\n");
+       getDefaultACLs(fout, &numDefaultACLs);
+
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined collations\n");
+       collinfo = getCollations(fout, &numCollations);
+       collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
 
        if (g_verbose)
                write_msg(NULL, "reading user-defined conversions\n");
-       convinfo = getConversions(&numConversions);
+       getConversions(fout, &numConversions);
 
        if (g_verbose)
-               write_msg(NULL, "reading user-defined tables\n");
-       tblinfo = getTables(&numTables);
+               write_msg(NULL, "reading type casts\n");
+       getCasts(fout, &numCasts);
 
        if (g_verbose)
                write_msg(NULL, "reading table inheritance information\n");
-       inhinfo = getInherits(&numInherits);
+       inhinfo = getInherits(fout, &numInherits);
 
        if (g_verbose)
                write_msg(NULL, "reading rewrite rules\n");
-       ruleinfo = getRules(&numRules);
+       getRules(fout, &numRules);
 
+       /*
+        * Identify extension member objects and mark them as not to be dumped.
+        * This must happen after reading all objects that can be direct members
+        * of extensions, but before we begin to process table subsidiary objects.
+        */
        if (g_verbose)
-               write_msg(NULL, "reading type casts\n");
-       castinfo = getCasts(&numCasts);
+               write_msg(NULL, "finding extension members\n");
+       getExtensionMembership(fout, extinfo, numExtensions);
 
        /* Link tables to parents, mark parents of target tables interesting */
        if (g_verbose)
@@ -152,23 +221,27 @@ getSchemaData(int *numTablesPtr,
 
        if (g_verbose)
                write_msg(NULL, "reading column info for interesting tables\n");
-       getTableAttrs(tblinfo, numTables);
+       getTableAttrs(fout, tblinfo, numTables);
 
        if (g_verbose)
                write_msg(NULL, "flagging inherited columns in subtables\n");
-       flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
+       flagInhAttrs(tblinfo, numTables);
 
        if (g_verbose)
                write_msg(NULL, "reading indexes\n");
-       getIndexes(tblinfo, numTables);
+       getIndexes(fout, tblinfo, numTables);
 
        if (g_verbose)
                write_msg(NULL, "reading constraints\n");
-       getConstraints(tblinfo, numTables);
+       getConstraints(fout, tblinfo, numTables);
 
        if (g_verbose)
                write_msg(NULL, "reading triggers\n");
-       getTriggers(tblinfo, numTables);
+       getTriggers(fout, tblinfo, numTables);
+
+       if (g_verbose)
+               write_msg(NULL, "reading event triggers\n");
+       getEventTriggers(fout, &numEventTriggers);
 
        *numTablesPtr = numTables;
        return tblinfo;
@@ -201,7 +274,7 @@ flagInhTables(TableInfo *tblinfo, int numTables,
                        continue;
 
                /* Don't bother computing anything for non-target tables, either */
-               if (!tblinfo[i].dump)
+               if (!tblinfo[i].dobj.dump)
                        continue;
 
                /* Find all the immediate parent tables */
@@ -217,13 +290,18 @@ flagInhTables(TableInfo *tblinfo, int numTables,
 
 /* flagInhAttrs -
  *      for each dumpable table in tblinfo, flag its inherited attributes
- * so when we dump the table out, we don't dump out the inherited attributes
+ *
+ * What we need to do here is detect child columns that inherit NOT NULL
+ * bits from their parents (so that we needn't specify that again for the
+ * child) and child columns that have DEFAULT NULL when their parents had
+ * some non-null default.  In the latter case, we make up a dummy AttrDefInfo
+ * object so that we'll correctly emit the necessary DEFAULT NULL clause;
+ * otherwise the backend will apply an inherited default to the column.
  *
  * modifies tblinfo
  */
 static void
-flagInhAttrs(TableInfo *tblinfo, int numTables,
-                        InhInfo *inhinfo, int numInherits)
+flagInhAttrs(TableInfo *tblinfo, int numTables)
 {
        int                     i,
                                j,
@@ -234,7 +312,6 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
                TableInfo  *tbinfo = &(tblinfo[i]);
                int                     numParents;
                TableInfo **parents;
-               TableInfo  *parent;
 
                /* Sequences and views never have parents */
                if (tbinfo->relkind == RELKIND_SEQUENCE ||
@@ -242,7 +319,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
                        continue;
 
                /* Don't bother computing anything for non-target tables, either */
-               if (!tbinfo->dump)
+               if (!tbinfo->dobj.dump)
                        continue;
 
                numParents = tbinfo->numParents;
@@ -251,133 +328,70 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
                if (numParents == 0)
                        continue;                       /* nothing to see here, move along */
 
-               /*----------------------------------------------------------------
-                * For each attr, check the parent info: if no parent has an attr
-                * with the same name, then it's not inherited. If there *is* an
-                * attr with the same name, then only dump it if:
-                *
-                * - it is NOT NULL and zero parents are NOT NULL
-                *       OR
-                * - it has a default value AND the default value does not match
-                *       all parent default values, or no parents specify a default.
-                *
-                * See discussion on -hackers around 2-Apr-2001.
-                *----------------------------------------------------------------
-                */
+               /* For each column, search for matching column names in parent(s) */
                for (j = 0; j < tbinfo->numatts; j++)
                {
-                       bool            foundAttr;              /* Attr was found in a parent */
                        bool            foundNotNull;   /* Attr was NOT NULL in a parent */
-                       bool            defaultsMatch;  /* All non-empty defaults match */
-                       bool            defaultsFound;  /* Found a default in a parent */
-                       AttrDefInfo *attrDef;
+                       bool            foundDefault;   /* Found a default in a parent */
 
-                       foundAttr = false;
-                       foundNotNull = false;
-                       defaultsMatch = true;
-                       defaultsFound = false;
-
-                       attrDef = tbinfo->attrdefs[j];
+                       /* no point in examining dropped columns */
+                       if (tbinfo->attisdropped[j])
+                               continue;
 
+                       foundNotNull = false;
+                       foundDefault = false;
                        for (k = 0; k < numParents; k++)
                        {
+                               TableInfo  *parent = parents[k];
                                int                     inhAttrInd;
 
-                               parent = parents[k];
                                inhAttrInd = strInArray(tbinfo->attnames[j],
                                                                                parent->attnames,
                                                                                parent->numatts);
-
-                               if (inhAttrInd != -1)
+                               if (inhAttrInd >= 0)
                                {
-                                       foundAttr = true;
                                        foundNotNull |= parent->notnull[inhAttrInd];
-                                       if (attrDef != NULL)            /* If we have a default,
-                                                                                                * check parent */
-                                       {
-                                               AttrDefInfo *inhDef;
-
-                                               inhDef = parent->attrdefs[inhAttrInd];
-                                               if (inhDef != NULL)
-                                               {
-                                                       defaultsFound = true;
-                                                       defaultsMatch &= (strcmp(attrDef->adef_expr,
-                                                                                                        inhDef->adef_expr) == 0);
-                                               }
-                                       }
+                                       foundDefault |= (parent->attrdefs[inhAttrInd] != NULL);
                                }
                        }
 
-                       /*
-                        * Based on the scan of the parents, decide if we can rely on
-                        * the inherited attr
-                        */
-                       if (foundAttr)          /* Attr was inherited */
+                       /* Remember if we found inherited NOT NULL */
+                       tbinfo->inhNotNull[j] = foundNotNull;
+
+                       /* Manufacture a DEFAULT NULL clause if necessary */
+                       if (foundDefault && tbinfo->attrdefs[j] == NULL)
                        {
-                               /* Set inherited flag by default */
-                               tbinfo->inhAttrs[j] = true;
-                               tbinfo->inhAttrDef[j] = true;
-                               tbinfo->inhNotNull[j] = true;
-
-                               /*
-                                * Clear it if attr had a default, but parents did not, or
-                                * mismatch
-                                */
-                               if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch))
+                               AttrDefInfo *attrDef;
+
+                               attrDef = (AttrDefInfo *) pg_malloc(sizeof(AttrDefInfo));
+                               attrDef->dobj.objType = DO_ATTRDEF;
+                               attrDef->dobj.catId.tableoid = 0;
+                               attrDef->dobj.catId.oid = 0;
+                               AssignDumpId(&attrDef->dobj);
+                               attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
+                               attrDef->dobj.namespace = tbinfo->dobj.namespace;
+                               attrDef->dobj.dump = tbinfo->dobj.dump;
+
+                               attrDef->adtable = tbinfo;
+                               attrDef->adnum = j + 1;
+                               attrDef->adef_expr = pg_strdup("NULL");
+
+                               /* Will column be dumped explicitly? */
+                               if (shouldPrintColumn(tbinfo, j))
                                {
-                                       tbinfo->inhAttrs[j] = false;
-                                       tbinfo->inhAttrDef[j] = false;
+                                       attrDef->separate = false;
+                                       /* No dependency needed: NULL cannot have dependencies */
                                }
-
-                               /*
-                                * Clear it if NOT NULL and none of the parents were NOT
-                                * NULL
-                                */
-                               if (tbinfo->notnull[j] && !foundNotNull)
+                               else
                                {
-                                       tbinfo->inhAttrs[j] = false;
-                                       tbinfo->inhNotNull[j] = false;
+                                       /* column will be suppressed, print default separately */
+                                       attrDef->separate = true;
+                                       /* ensure it comes out after the table */
+                                       addObjectDependency(&attrDef->dobj,
+                                                                               tbinfo->dobj.dumpId);
                                }
 
-                               /* Clear it if attr has local definition */
-                               if (tbinfo->attislocal[j])
-                                       tbinfo->inhAttrs[j] = false;
-                       }
-               }
-
-               /*
-                * Check for inherited CHECK constraints.  We assume a constraint
-                * is inherited if its expression matches the parent and the name
-                * is the same, *or* both names start with '$'.
-                */
-               for (j = 0; j < tbinfo->ncheck; j++)
-               {
-                       ConstraintInfo *constr;
-
-                       constr = &(tbinfo->checkexprs[j]);
-
-                       for (k = 0; k < numParents; k++)
-                       {
-                               int             l;
-
-                               parent = parents[k];
-                               for (l = 0; l < parent->ncheck; l++)
-                               {
-                                       ConstraintInfo *pconstr;
-
-                                       pconstr = &(parent->checkexprs[l]);
-                                       if (strcmp(pconstr->condef, constr->condef) != 0)
-                                               continue;
-                                       if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0 ||
-                                               (pconstr->dobj.name[0] == '$' &&
-                                                constr->dobj.name[0] == '$'))
-                                       {
-                                               constr->coninherited = true;
-                                               break;
-                                       }
-                               }
-                               if (constr->coninherited)
-                                       break;
+                               tbinfo->attrdefs[j] = attrDef;
                        }
                }
        }
@@ -388,7 +402,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
  *             Given a newly-created dumpable object, assign a dump ID,
  *             and enter the object into the lookup table.
  *
- * The caller is expected to have filled in objType and catalogId,
+ * The caller is expected to have filled in objType and catId,
  * but not any of the other standard fields of a DumpableObject.
  */
 void
@@ -397,28 +411,28 @@ AssignDumpId(DumpableObject *dobj)
        dobj->dumpId = ++lastDumpId;
        dobj->name = NULL;                      /* must be set later */
        dobj->namespace = NULL;         /* may be set later */
+       dobj->dump = true;                      /* default assumption */
+       dobj->ext_member = false;       /* default assumption */
        dobj->dependencies = NULL;
        dobj->nDeps = 0;
        dobj->allocDeps = 0;
 
        while (dobj->dumpId >= allocedDumpIds)
        {
-               int             newAlloc;
+               int                     newAlloc;
 
                if (allocedDumpIds <= 0)
                {
                        newAlloc = 256;
                        dumpIdMap = (DumpableObject **)
-                               malloc(newAlloc * sizeof(DumpableObject *));
+                               pg_malloc(newAlloc * sizeof(DumpableObject *));
                }
                else
                {
                        newAlloc = allocedDumpIds * 2;
                        dumpIdMap = (DumpableObject **)
-                               realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
+                               pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
                }
-               if (dumpIdMap == NULL)
-                       exit_horribly(NULL, NULL, "out of memory\n");
                memset(dumpIdMap + allocedDumpIds, 0,
                           (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
                allocedDumpIds = newAlloc;
@@ -469,9 +483,9 @@ findObjectByDumpId(DumpId dumpId)
  * Returns NULL for unknown ID
  *
  * We use binary search in a sorted list that is built on first call.
- * If AssignDumpId() and findObjectByCatalogId() calls were intermixed,
- * the code would work, but possibly be very slow.  In the current usage
- * pattern that does not happen, indeed we only need to build the list once.
+ * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
+ * the code would work, but possibly be very slow.     In the current usage
+ * pattern that does not happen, indeed we build the list at most twice.
  */
 DumpableObject *
 findObjectByCatalogId(CatalogId catalogId)
@@ -519,16 +533,80 @@ findObjectByCatalogId(CatalogId catalogId)
        return NULL;
 }
 
+/*
+ * Find a DumpableObject by OID, in a pre-sorted array of one type of object
+ *
+ * Returns NULL for unknown OID
+ */
+static DumpableObject *
+findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
+{
+       DumpableObject **low;
+       DumpableObject **high;
+
+       /*
+        * This is the same as findObjectByCatalogId except we assume we need not
+        * look at table OID because the objects are all the same type.
+        *
+        * We could use bsearch() here, but the notational cruft of calling
+        * bsearch is nearly as bad as doing it ourselves; and the generalized
+        * bsearch function is noticeably slower as well.
+        */
+       if (numObjs <= 0)
+               return NULL;
+       low = indexArray;
+       high = indexArray + (numObjs - 1);
+       while (low <= high)
+       {
+               DumpableObject **middle;
+               int                     difference;
+
+               middle = low + (high - low) / 2;
+               difference = oidcmp((*middle)->catId.oid, oid);
+               if (difference == 0)
+                       return *middle;
+               else if (difference < 0)
+                       low = middle + 1;
+               else
+                       high = middle - 1;
+       }
+       return NULL;
+}
+
+/*
+ * Build an index array of DumpableObject pointers, sorted by OID
+ */
+static DumpableObject **
+buildIndexArray(void *objArray, int numObjs, Size objSize)
+{
+       DumpableObject **ptrs;
+       int                     i;
+
+       ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
+       for (i = 0; i < numObjs; i++)
+               ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
+
+       /* We can use DOCatalogIdCompare to sort since its first key is OID */
+       if (numObjs > 1)
+               qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
+                         DOCatalogIdCompare);
+
+       return ptrs;
+}
+
+/*
+ * qsort comparator for pointers to DumpableObjects
+ */
 static int
 DOCatalogIdCompare(const void *p1, const void *p2)
 {
-       DumpableObject *obj1 = *(DumpableObject **) p1;
-       DumpableObject *obj2 = *(DumpableObject **) p2;
+       const DumpableObject *obj1 = *(DumpableObject *const *) p1;
+       const DumpableObject *obj2 = *(DumpableObject *const *) p2;
        int                     cmpval;
 
        /*
-        * Compare OID first since it's usually unique, whereas there will
-        * only be a few distinct values of tableoid.
+        * Compare OID first since it's usually unique, whereas there will only be
+        * a few distinct values of tableoid.
         */
        cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
        if (cmpval == 0)
@@ -548,9 +626,7 @@ getDumpableObjects(DumpableObject ***objs, int *numObjs)
                                j;
 
        *objs = (DumpableObject **)
-               malloc(allocedDumpIds * sizeof(DumpableObject *));
-       if (*objs == NULL)
-               exit_horribly(NULL, NULL, "out of memory\n");
+               pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
        j = 0;
        for (i = 1; i < allocedDumpIds; i++)
        {
@@ -574,17 +650,15 @@ addObjectDependency(DumpableObject *dobj, DumpId refId)
                {
                        dobj->allocDeps = 16;
                        dobj->dependencies = (DumpId *)
-                               malloc(dobj->allocDeps * sizeof(DumpId));
+                               pg_malloc(dobj->allocDeps * sizeof(DumpId));
                }
                else
                {
                        dobj->allocDeps *= 2;
                        dobj->dependencies = (DumpId *)
-                               realloc(dobj->dependencies,
-                                               dobj->allocDeps * sizeof(DumpId));
+                               pg_realloc(dobj->dependencies,
+                                                  dobj->allocDeps * sizeof(DumpId));
                }
-               if (dobj->dependencies == NULL)
-                       exit_horribly(NULL, NULL, "out of memory\n");
        }
        dobj->dependencies[dobj->nDeps++] = refId;
 }
@@ -613,80 +687,66 @@ removeObjectDependency(DumpableObject *dobj, DumpId refId)
  * findTableByOid
  *       finds the entry (in tblinfo) of the table with the given oid
  *       returns NULL if not found
- *
- * NOTE:  should hash this, but just do linear search for now
  */
 TableInfo *
 findTableByOid(Oid oid)
 {
-       int                     i;
-
-       for (i = 0; i < numTables; i++)
-       {
-               if (tblinfo[i].dobj.catId.oid == oid)
-                       return &tblinfo[i];
-       }
-       return NULL;
+       return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
 }
 
 /*
  * findTypeByOid
  *       finds the entry (in typinfo) of the type with the given oid
  *       returns NULL if not found
- *
- * NOTE:  should hash this, but just do linear search for now
  */
 TypeInfo *
 findTypeByOid(Oid oid)
 {
-       int                     i;
-
-       for (i = 0; i < numTypes; i++)
-       {
-               if (typinfo[i].dobj.catId.oid == oid)
-                       return &typinfo[i];
-       }
-       return NULL;
+       return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
 }
 
 /*
  * findFuncByOid
  *       finds the entry (in funinfo) of the function with the given oid
  *       returns NULL if not found
- *
- * NOTE:  should hash this, but just do linear search for now
  */
 FuncInfo *
 findFuncByOid(Oid oid)
 {
-       int                     i;
-
-       for (i = 0; i < numFuncs; i++)
-       {
-               if (funinfo[i].dobj.catId.oid == oid)
-                       return &funinfo[i];
-       }
-       return NULL;
+       return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
 }
 
 /*
  * findOprByOid
  *       finds the entry (in oprinfo) of the operator with the given oid
  *       returns NULL if not found
- *
- * NOTE:  should hash this, but just do linear search for now
  */
 OprInfo *
 findOprByOid(Oid oid)
 {
-       int                     i;
+       return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
+}
 
-       for (i = 0; i < numOperators; i++)
-       {
-               if (oprinfo[i].dobj.catId.oid == oid)
-                       return &oprinfo[i];
-       }
-       return NULL;
+/*
+ * findCollationByOid
+ *       finds the entry (in collinfo) of the collation with the given oid
+ *       returns NULL if not found
+ */
+CollInfo *
+findCollationByOid(Oid oid)
+{
+       return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
+}
+
+/*
+ * findNamespaceByOid
+ *       finds the entry (in nspinfo) of the namespace with the given oid
+ *       returns NULL if not found
+ */
+NamespaceInfo *
+findNamespaceByOid(Oid oid)
+{
+       return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
 }
 
 
@@ -714,7 +774,8 @@ findParentsByOid(TableInfo *self,
 
        if (numParents > 0)
        {
-               self->parents = (TableInfo **) malloc(sizeof(TableInfo *) * numParents);
+               self->parents = (TableInfo **)
+                       pg_malloc(sizeof(TableInfo *) * numParents);
                j = 0;
                for (i = 0; i < numInherits; i++)
                {
@@ -729,7 +790,7 @@ findParentsByOid(TableInfo *self,
                                                          inhinfo[i].inhparent,
                                                          self->dobj.name,
                                                          oid);
-                                       exit_nicely();
+                                       exit_nicely(1);
                                }
                                self->parents[j++] = parent;
                        }
@@ -767,8 +828,8 @@ parseOidArray(const char *str, Oid *array, int arraysize)
                        {
                                if (argNum >= arraysize)
                                {
-                                       write_msg(NULL, "could not parse numeric array: too many numbers\n");
-                                       exit_nicely();
+                                       write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
+                                       exit_nicely(1);
                                }
                                temp[j] = '\0';
                                array[argNum++] = atooid(temp);
@@ -782,8 +843,8 @@ parseOidArray(const char *str, Oid *array, int arraysize)
                        if (!(isdigit((unsigned char) s) || s == '-') ||
                                j >= sizeof(temp) - 1)
                        {
-                               write_msg(NULL, "could not parse numeric array: invalid character in number\n");
-                               exit_nicely();
+                               write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
+                               exit_nicely(1);
                        }
                        temp[j++] = s;
                }
@@ -813,3 +874,37 @@ strInArray(const char *pattern, char **arr, int arr_size)
        }
        return -1;
 }
+
+
+/*
+ * Support for simple list operations
+ */
+
+void
+simple_oid_list_append(SimpleOidList *list, Oid val)
+{
+       SimpleOidListCell *cell;
+
+       cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
+       cell->next = NULL;
+       cell->val = val;
+
+       if (list->tail)
+               list->tail->next = cell;
+       else
+               list->head = cell;
+       list->tail = cell;
+}
+
+bool
+simple_oid_list_member(SimpleOidList *list, Oid val)
+{
+       SimpleOidListCell *cell;
+
+       for (cell = list->head; cell; cell = cell->next)
+       {
+               if (cell->val == val)
+                       return true;
+       }
+       return false;
+}