Thread: Re: [COMMITTERS] pgsql: Modify pg_dump to use error-free memory allocation macros. This

Bruce Momjian <bruce@momjian.us> writes:
> Bruce Momjian wrote:
>> Tom Lane wrote:
>>> object to arbitrarily moving a bunch of longstanding code from one file
>>> to another.  What that is mainly going to accomplish is creating a big
>>> headache whenever we have to back-patch fixes that touch that code
>>> ... and what exactly did it buy in return?

>> Yes, I didn't like that either.  The problem was that common.c was setup
>> to share code between pg_dump and a long-forgotten tool for Postgres 4.X
>> called pg4_dump (yes, pre-1996).  That code that was moved was really
>> not "common" in any current sense because it was used only by pg_dump
>> (not by pg_restore or pg_dumpall), so I moved it into dumpcatalog.c, and
>> put the really "common" code into common.c. (We could call it dumpmem.c
>> or something.)
>> 
>> Now, one approach would have been to rename common.c to dumpcatalog.c in
>> git, then create a new common.c, but that seems quite confusing to
>> people trying to reconstruct the history.

That will not help.  git is not smart enough to deal with back-patching
changes in code that has moved from one file to another.  If you force
this through it will mean manual adjustment of every back-patchable fix
that has to touch this code, for the next five or six years.  Yes, the
name "common.c" is a bit of a misnomer now, but that doesn't mean we
have to change it, especially since the file's header comment already
explained what it was common for (and could be modified some more if
you don't find that adequate).

>> It is not possible to just link the old common.c into pg_restore and
>> pg_dumpall because it contains calls to pg_dump-only functions.
>> 
>> Ideas?

> The only other idea I have is to keep most functions in the mis-named
> common.c and move the memory functions into dumpmem.c and dumpmem.h and
> include that in the other C files, but that doesn't help with long-term
> code clarity.

I don't think there is any "long-term code clarity" gain here that is
worth the maintenance headache.  Please put the existing functions back
where they were.  Inventing new files for the new code seems fine.
        regards, tom lane


Tom Lane wrote:
> >> It is not possible to just link the old common.c into pg_restore and
> >> pg_dumpall because it contains calls to pg_dump-only functions.
> >> 
> >> Ideas?
> 
> > The only other idea I have is to keep most functions in the mis-named
> > common.c and move the memory functions into dumpmem.c and dumpmem.h and
> > include that in the other C files, but that doesn't help with long-term
> > code clarity.
> 
> I don't think there is any "long-term code clarity" gain here that is
> worth the maintenance headache.  Please put the existing functions back
> where they were.  Inventing new files for the new code seems fine.

Well, you do a lot more backpatching than I do, so I am willing to do as
you request, but looking at the git history for common.c, I don't see a
lot of backpatching for this file.  

Basically, if we keep the existing functions in common.c, we are
deciding that it is never worth moving C functions to new C files for
source code clarity.  I was not sure we had made that decision in the
past.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + It's impossible for everything to be true. +


Bruce Momjian <bruce@momjian.us> writes:
> Basically, if we keep the existing functions in common.c, we are
> deciding that it is never worth moving C functions to new C files for
> source code clarity.  I was not sure we had made that decision in the
> past.

I once held hope that git would let us be more flexible about this,
but experimentation has shown that it's not significantly smarter than
CVS about back-patches in moved code :-(.

I don't want to say that we should *never* move code once it's released;
but I think the bar for that needs to be set pretty high, and this
particular case isn't clearing the bar for me.
        regards, tom lane


Tom Lane wrote:
> Bruce Momjian <bruce@momjian.us> writes:
> > Basically, if we keep the existing functions in common.c, we are
> > deciding that it is never worth moving C functions to new C files for
> > source code clarity.  I was not sure we had made that decision in the
> > past.
>
> I once held hope that git would let us be more flexible about this,
> but experimentation has shown that it's not significantly smarter than
> CVS about back-patches in moved code :-(.
>
> I don't want to say that we should *never* move code once it's released;
> but I think the bar for that needs to be set pretty high, and this
> particular case isn't clearing the bar for me.

OK, hearing no other opinions, I have moved the functions back into
common.c, and created a new dumpmem.c/h.  Applied patch attached.

There is now no need to modify MSVC.

--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + It's impossible for everything to be true. +
diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
new file mode 100644
index 9d13bec..4e8e421
*** a/src/bin/pg_dump/Makefile
--- b/src/bin/pg_dump/Makefile
*************** override CPPFLAGS := -I$(libpq_srcdir) $
*** 20,26 ****

  OBJS=    pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
      pg_backup_files.o pg_backup_null.o pg_backup_tar.o \
!     pg_backup_directory.o common.o dumputils.o compress_io.o $(WIN32RES)

  KEYWRDOBJS = keywords.o kwlookup.o

--- 20,26 ----

  OBJS=    pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
      pg_backup_files.o pg_backup_null.o pg_backup_tar.o \
!     pg_backup_directory.o dumpmem.o dumputils.o compress_io.o $(WIN32RES)

  KEYWRDOBJS = keywords.o kwlookup.o

*************** kwlookup.c: % : $(top_srcdir)/src/backen
*** 29,36 ****

  all: pg_dump pg_restore pg_dumpall

! pg_dump: pg_dump.o dumpcatalog.o pg_dump_sort.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
!     $(CC) $(CFLAGS) pg_dump.o dumpcatalog.o pg_dump_sort.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS)
$(LDFLAGS_EX)$(LIBS) -o $@$(X) 

  pg_restore: pg_restore.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
      $(CC) $(CFLAGS) pg_restore.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
--- 29,36 ----

  all: pg_dump pg_restore pg_dumpall

! pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
!     $(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX)
$(LIBS)-o $@$(X) 

  pg_restore: pg_restore.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
      $(CC) $(CFLAGS) pg_restore.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
new file mode 100644
index 1a3f4cb..6f921f7
*** a/src/bin/pg_dump/common.c
--- b/src/bin/pg_dump/common.c
***************
*** 1,8 ****
  /*-------------------------------------------------------------------------
   *
   * common.c
!  *      common routines between pg_dump and pg_restore (but not pg_dumpall
!  *      because there is no failure location to report).
   *
   * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
--- 1,8 ----
  /*-------------------------------------------------------------------------
   *
   * common.c
!  *    catalog routines used by pg_dump;  long ago these were shared
!  *    by another dump tool, but not anymore.
   *
   * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
***************
*** 14,73 ****
   *-------------------------------------------------------------------------
   */
  #include "postgres_fe.h"
- #include "pg_backup.h"
- #include "common.h"

  #include <ctype.h>

  /*
!  * Safer versions of some standard C library functions. If an
!  * out-of-memory condition occurs, these functions will bail out
!  * safely; therefore, their return value is guaranteed to be non-NULL.
!  * We also report the program name and close the database connection.
   */

! char *
! pg_strdup(const char *string)
  {
!     char       *tmp;

!     if (!string)
!         exit_horribly(NULL, NULL, "cannot duplicate null pointer\n");
!     tmp = strdup(string);
!     if (!tmp)
!         exit_horribly(NULL, NULL, "out of memory\n");
!     return tmp;
  }

! void *
! pg_malloc(size_t size)
  {
!     void       *tmp;

!     tmp = malloc(size);
!     if (!tmp)
!         exit_horribly(NULL, NULL, "out of memory\n");
!     return tmp;
  }

! void *
! pg_calloc(size_t nmemb, size_t size)
  {
!     void       *tmp;

!     tmp = calloc(nmemb, size);
!     if (!tmp)
!         exit_horribly(NULL, NULL, _("out of memory\n"));
!     return tmp;
  }

! void *
! pg_realloc(void *ptr, size_t size)
  {
!     void       *tmp;

!     tmp = realloc(ptr, size);
!     if (!tmp)
!         exit_horribly(NULL, NULL, _("out of memory\n"));
!     return tmp;
  }
--- 14,979 ----
   *-------------------------------------------------------------------------
   */
  #include "postgres_fe.h"

  #include <ctype.h>

+ #include "catalog/pg_class.h"
+
+ #include "pg_backup_archiver.h"
+ #include "dumpmem.h"
+
+
  /*
!  * Variables for mapping DumpId to DumpableObject
   */
+ static DumpableObject **dumpIdMap = NULL;
+ static int    allocedDumpIds = 0;
+ static DumpId lastDumpId = 0;

! /*
!  * Variables for mapping CatalogId to DumpableObject
!  */
! static bool catalogIdMapValid = false;
! static DumpableObject **catalogIdMap = NULL;
! static int    numCatalogIds = 0;
!
! /*
!  * These variables are static to avoid the notational cruft of having to pass
!  * 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 int    numCollations;
! static DumpableObject **tblinfoindex;
! static DumpableObject **typinfoindex;
! static DumpableObject **funinfoindex;
! static DumpableObject **oprinfoindex;
! static DumpableObject **collinfoindex;
!
!
! static void flagInhTables(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);
! static int    strInArray(const char *pattern, char **arr, int arr_size);
!
!
! /*
!  * getSchemaData
!  *      Collect information about all potentially dumpable objects
!  */
! TableInfo *
! getSchemaData(int *numTablesPtr)
  {
!     ExtensionInfo *extinfo;
!     InhInfo    *inhinfo;
!     CollInfo   *collinfo;
!     int            numNamespaces;
!     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;

!     if (g_verbose)
!         write_msg(NULL, "reading schemas\n");
!     getNamespaces(&numNamespaces);
!
!     /*
!      * 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(&numTables);
!     tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
!
!     if (g_verbose)
!         write_msg(NULL, "reading extensions\n");
!     extinfo = getExtensions(&numExtensions);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined functions\n");
!     funinfo = getFuncs(&numFuncs);
!     funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
!
!     /* this must be after getTables and getFuncs */
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined types\n");
!     typinfo = getTypes(&numTypes);
!     typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
!
!     /* this must be after getFuncs, too */
!     if (g_verbose)
!         write_msg(NULL, "reading procedural languages\n");
!     getProcLangs(&numProcLangs);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined aggregate functions\n");
!     getAggregates(&numAggregates);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined operators\n");
!     oprinfo = getOperators(&numOperators);
!     oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined operator classes\n");
!     getOpclasses(&numOpclasses);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined operator families\n");
!     getOpfamilies(&numOpfamilies);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined text search parsers\n");
!     getTSParsers(&numTSParsers);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined text search templates\n");
!     getTSTemplates(&numTSTemplates);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined text search dictionaries\n");
!     getTSDictionaries(&numTSDicts);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined text search configurations\n");
!     getTSConfigurations(&numTSConfigs);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined foreign-data wrappers\n");
!     getForeignDataWrappers(&numForeignDataWrappers);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined foreign servers\n");
!     getForeignServers(&numForeignServers);
!
!     if (g_verbose)
!         write_msg(NULL, "reading default privileges\n");
!     getDefaultACLs(&numDefaultACLs);
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined collations\n");
!     collinfo = getCollations(&numCollations);
!     collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
!
!     if (g_verbose)
!         write_msg(NULL, "reading user-defined conversions\n");
!     getConversions(&numConversions);
!
!     if (g_verbose)
!         write_msg(NULL, "reading type casts\n");
!     getCasts(&numCasts);
!
!     if (g_verbose)
!         write_msg(NULL, "reading table inheritance information\n");
!     inhinfo = getInherits(&numInherits);
!
!     if (g_verbose)
!         write_msg(NULL, "reading rewrite rules\n");
!     getRules(&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, "finding extension members\n");
!     getExtensionMembership(extinfo, numExtensions);
!
!     /* Link tables to parents, mark parents of target tables interesting */
!     if (g_verbose)
!         write_msg(NULL, "finding inheritance relationships\n");
!     flagInhTables(tblinfo, numTables, inhinfo, numInherits);
!
!     if (g_verbose)
!         write_msg(NULL, "reading column info for interesting tables\n");
!     getTableAttrs(tblinfo, numTables);
!
!     if (g_verbose)
!         write_msg(NULL, "flagging inherited columns in subtables\n");
!     flagInhAttrs(tblinfo, numTables);
!
!     if (g_verbose)
!         write_msg(NULL, "reading indexes\n");
!     getIndexes(tblinfo, numTables);
!
!     if (g_verbose)
!         write_msg(NULL, "reading constraints\n");
!     getConstraints(tblinfo, numTables);
!
!     if (g_verbose)
!         write_msg(NULL, "reading triggers\n");
!     getTriggers(tblinfo, numTables);
!
!     *numTablesPtr = numTables;
!     return tblinfo;
  }

! /* flagInhTables -
!  *     Fill in parent link fields of every target table, and mark
!  *     parents of target tables as interesting
!  *
!  * Note that only direct ancestors of targets are marked interesting.
!  * This is sufficient; we don't much care whether they inherited their
!  * attributes or not.
!  *
!  * modifies tblinfo
!  */
! static void
! flagInhTables(TableInfo *tblinfo, int numTables,
!               InhInfo *inhinfo, int numInherits)
  {
!     int            i,
!                 j;
!     int            numParents;
!     TableInfo **parents;

!     for (i = 0; i < numTables; i++)
!     {
!         /* Sequences and views never have parents */
!         if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
!             tblinfo[i].relkind == RELKIND_VIEW)
!             continue;
!
!         /* Don't bother computing anything for non-target tables, either */
!         if (!tblinfo[i].dobj.dump)
!             continue;
!
!         /* Find all the immediate parent tables */
!         findParentsByOid(&tblinfo[i], inhinfo, numInherits);
!
!         /* Mark the parents as interesting for getTableAttrs */
!         numParents = tblinfo[i].numParents;
!         parents = tblinfo[i].parents;
!         for (j = 0; j < numParents; j++)
!             parents[j]->interesting = true;
!     }
  }

! /* 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
!  *
!  * modifies tblinfo
!  */
! static void
! flagInhAttrs(TableInfo *tblinfo, int numTables)
  {
!     int            i,
!                 j,
!                 k;

!     for (i = 0; i < numTables; i++)
!     {
!         TableInfo  *tbinfo = &(tblinfo[i]);
!         int            numParents;
!         TableInfo **parents;
!         TableInfo  *parent;
!
!         /* Sequences and views never have parents */
!         if (tbinfo->relkind == RELKIND_SEQUENCE ||
!             tbinfo->relkind == RELKIND_VIEW)
!             continue;
!
!         /* Don't bother computing anything for non-target tables, either */
!         if (!tbinfo->dobj.dump)
!             continue;
!
!         numParents = tbinfo->numParents;
!         parents = tbinfo->parents;
!
!         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 (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;
!
!             foundAttr = false;
!             foundNotNull = false;
!             defaultsMatch = true;
!             defaultsFound = false;
!
!             attrDef = tbinfo->attrdefs[j];
!
!             for (k = 0; k < numParents; k++)
!             {
!                 int            inhAttrInd;
!
!                 parent = parents[k];
!                 inhAttrInd = strInArray(tbinfo->attnames[j],
!                                         parent->attnames,
!                                         parent->numatts);
!
!                 if (inhAttrInd != -1)
!                 {
!                     AttrDefInfo *inhDef = parent->attrdefs[inhAttrInd];
!
!                     foundAttr = true;
!                     foundNotNull |= parent->notnull[inhAttrInd];
!                     if (inhDef != NULL)
!                     {
!                         defaultsFound = true;
!
!                         /*
!                          * If any parent has a default and the child doesn't,
!                          * we have to emit an explicit DEFAULT NULL clause for
!                          * the child, else the parent's default will win.
!                          */
!                         if (attrDef == NULL)
!                         {
!                             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->adtable = tbinfo;
!                             attrDef->adnum = j + 1;
!                             attrDef->adef_expr = pg_strdup("NULL");
!
!                             attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
!                             attrDef->dobj.namespace = tbinfo->dobj.namespace;
!
!                             attrDef->dobj.dump = tbinfo->dobj.dump;
!
!                             attrDef->separate = false;
!                             addObjectDependency(&tbinfo->dobj,
!                                                 attrDef->dobj.dumpId);
!
!                             tbinfo->attrdefs[j] = attrDef;
!                         }
!                         if (strcmp(attrDef->adef_expr, inhDef->adef_expr) != 0)
!                         {
!                             defaultsMatch = false;
!
!                             /*
!                              * Whenever there is a non-matching parent
!                              * default, add a dependency to force the parent
!                              * default to be dumped first, in case the
!                              * defaults end up being dumped as separate
!                              * commands.  Otherwise the parent default will
!                              * override the child's when it is applied.
!                              */
!                             addObjectDependency(&attrDef->dobj,
!                                                 inhDef->dobj.dumpId);
!                         }
!                     }
!                 }
!             }
!
!             /*
!              * Based on the scan of the parents, decide if we can rely on the
!              * inherited attr
!              */
!             if (foundAttr)        /* Attr was inherited */
!             {
!                 /* 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))
!                 {
!                     tbinfo->inhAttrs[j] = false;
!                     tbinfo->inhAttrDef[j] = false;
!                 }
!
!                 /*
!                  * Clear it if NOT NULL and none of the parents were NOT NULL
!                  */
!                 if (tbinfo->notnull[j] && !foundNotNull)
!                 {
!                     tbinfo->inhAttrs[j] = false;
!                     tbinfo->inhNotNull[j] = false;
!                 }
!
!                 /* Clear it if attr has local definition */
!                 if (tbinfo->attislocal[j])
!                     tbinfo->inhAttrs[j] = false;
!             }
!         }
!     }
  }

! /*
!  * AssignDumpId
!  *        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 catId,
!  * but not any of the other standard fields of a DumpableObject.
!  */
! void
! 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;
!
!         if (allocedDumpIds <= 0)
!         {
!             newAlloc = 256;
!             dumpIdMap = (DumpableObject **)
!                 pg_malloc(newAlloc * sizeof(DumpableObject *));
!         }
!         else
!         {
!             newAlloc = allocedDumpIds * 2;
!             dumpIdMap = (DumpableObject **)
!                 pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
!         }
!         memset(dumpIdMap + allocedDumpIds, 0,
!                (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
!         allocedDumpIds = newAlloc;
!     }
!     dumpIdMap[dobj->dumpId] = dobj;
!
!     /* mark catalogIdMap invalid, but don't rebuild it yet */
!     catalogIdMapValid = false;
! }
!
! /*
!  * Assign a DumpId that's not tied to a DumpableObject.
!  *
!  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
!  * participate in the sorting logic.
!  */
! DumpId
! createDumpId(void)
! {
!     return ++lastDumpId;
! }
!
! /*
!  * Return the largest DumpId so far assigned
!  */
! DumpId
! getMaxDumpId(void)
! {
!     return lastDumpId;
! }
!
! /*
!  * Find a DumpableObject by dump ID
!  *
!  * Returns NULL for invalid ID
!  */
! DumpableObject *
! findObjectByDumpId(DumpId dumpId)
! {
!     if (dumpId <= 0 || dumpId >= allocedDumpIds)
!         return NULL;            /* out of range? */
!     return dumpIdMap[dumpId];
! }
!
! /*
!  * Find a DumpableObject by catalog ID
!  *
!  * 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 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)
! {
!     DumpableObject **low;
!     DumpableObject **high;
!
!     if (!catalogIdMapValid)
!     {
!         if (catalogIdMap)
!             free(catalogIdMap);
!         getDumpableObjects(&catalogIdMap, &numCatalogIds);
!         if (numCatalogIds > 1)
!             qsort((void *) catalogIdMap, numCatalogIds,
!                   sizeof(DumpableObject *), DOCatalogIdCompare);
!         catalogIdMapValid = true;
!     }
!
!     /*
!      * 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 (numCatalogIds <= 0)
!         return NULL;
!     low = catalogIdMap;
!     high = catalogIdMap + (numCatalogIds - 1);
!     while (low <= high)
!     {
!         DumpableObject **middle;
!         int            difference;
!
!         middle = low + (high - low) / 2;
!         /* comparison must match DOCatalogIdCompare, below */
!         difference = oidcmp((*middle)->catId.oid, catalogId.oid);
!         if (difference == 0)
!             difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
!         if (difference == 0)
!             return *middle;
!         else if (difference < 0)
!             low = middle + 1;
!         else
!             high = middle - 1;
!     }
!     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)
! {
!     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.
!      */
!     cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
!     if (cmpval == 0)
!         cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
!     return cmpval;
! }
!
! /*
!  * Build an array of pointers to all known dumpable objects
!  *
!  * This simply creates a modifiable copy of the internal map.
!  */
! void
! getDumpableObjects(DumpableObject ***objs, int *numObjs)
! {
!     int            i,
!                 j;
!
!     *objs = (DumpableObject **)
!         pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
!     j = 0;
!     for (i = 1; i < allocedDumpIds; i++)
!     {
!         if (dumpIdMap[i])
!             (*objs)[j++] = dumpIdMap[i];
!     }
!     *numObjs = j;
! }
!
! /*
!  * Add a dependency link to a DumpableObject
!  *
!  * Note: duplicate dependencies are currently not eliminated
!  */
! void
! addObjectDependency(DumpableObject *dobj, DumpId refId)
! {
!     if (dobj->nDeps >= dobj->allocDeps)
!     {
!         if (dobj->allocDeps <= 0)
!         {
!             dobj->allocDeps = 16;
!             dobj->dependencies = (DumpId *)
!                 pg_malloc(dobj->allocDeps * sizeof(DumpId));
!         }
!         else
!         {
!             dobj->allocDeps *= 2;
!             dobj->dependencies = (DumpId *)
!                 pg_realloc(dobj->dependencies,
!                            dobj->allocDeps * sizeof(DumpId));
!         }
!     }
!     dobj->dependencies[dobj->nDeps++] = refId;
! }
!
! /*
!  * Remove a dependency link from a DumpableObject
!  *
!  * If there are multiple links, all are removed
!  */
! void
! removeObjectDependency(DumpableObject *dobj, DumpId refId)
! {
!     int            i;
!     int            j = 0;
!
!     for (i = 0; i < dobj->nDeps; i++)
!     {
!         if (dobj->dependencies[i] != refId)
!             dobj->dependencies[j++] = dobj->dependencies[i];
!     }
!     dobj->nDeps = j;
! }
!
!
! /*
!  * findTableByOid
!  *      finds the entry (in tblinfo) of the table with the given oid
!  *      returns NULL if not found
!  */
! TableInfo *
! findTableByOid(Oid oid)
! {
!     return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
! }
!
! /*
!  * findTypeByOid
!  *      finds the entry (in typinfo) of the type with the given oid
!  *      returns NULL if not found
!  */
! TypeInfo *
! findTypeByOid(Oid oid)
! {
!     return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
! }
!
! /*
!  * findFuncByOid
!  *      finds the entry (in funinfo) of the function with the given oid
!  *      returns NULL if not found
!  */
! FuncInfo *
! findFuncByOid(Oid oid)
! {
!     return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
! }
!
! /*
!  * findOprByOid
!  *      finds the entry (in oprinfo) of the operator with the given oid
!  *      returns NULL if not found
!  */
! OprInfo *
! findOprByOid(Oid oid)
! {
!     return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
! }
!
! /*
!  * 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);
! }
!
!
! /*
!  * findParentsByOid
!  *      find a table's parents in tblinfo[]
!  */
! static void
! findParentsByOid(TableInfo *self,
!                  InhInfo *inhinfo, int numInherits)
! {
!     Oid            oid = self->dobj.catId.oid;
!     int            i,
!                 j;
!     int            numParents;
!
!     numParents = 0;
!     for (i = 0; i < numInherits; i++)
!     {
!         if (inhinfo[i].inhrelid == oid)
!             numParents++;
!     }
!
!     self->numParents = numParents;
!
!     if (numParents > 0)
!     {
!         self->parents = (TableInfo **)
!             pg_malloc(sizeof(TableInfo *) * numParents);
!         j = 0;
!         for (i = 0; i < numInherits; i++)
!         {
!             if (inhinfo[i].inhrelid == oid)
!             {
!                 TableInfo  *parent;
!
!                 parent = findTableByOid(inhinfo[i].inhparent);
!                 if (parent == NULL)
!                 {
!                     write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
!                               inhinfo[i].inhparent,
!                               self->dobj.name,
!                               oid);
!                     exit_nicely();
!                 }
!                 self->parents[j++] = parent;
!             }
!         }
!     }
!     else
!         self->parents = NULL;
! }
!
! /*
!  * parseOidArray
!  *      parse a string of numbers delimited by spaces into a character array
!  *
!  * Note: actually this is used for both Oids and potentially-signed
!  * attribute numbers.  This should cause no trouble, but we could split
!  * the function into two functions with different argument types if it does.
!  */
!
! void
! parseOidArray(const char *str, Oid *array, int arraysize)
! {
!     int            j,
!                 argNum;
!     char        temp[100];
!     char        s;
!
!     argNum = 0;
!     j = 0;
!     for (;;)
!     {
!         s = *str++;
!         if (s == ' ' || s == '\0')
!         {
!             if (j > 0)
!             {
!                 if (argNum >= arraysize)
!                 {
!                     write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
!                     exit_nicely();
!                 }
!                 temp[j] = '\0';
!                 array[argNum++] = atooid(temp);
!                 j = 0;
!             }
!             if (s == '\0')
!                 break;
!         }
!         else
!         {
!             if (!(isdigit((unsigned char) s) || s == '-') ||
!                 j >= sizeof(temp) - 1)
!             {
!                 write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
!                 exit_nicely();
!             }
!             temp[j++] = s;
!         }
!     }
!
!     while (argNum < arraysize)
!         array[argNum++] = InvalidOid;
! }
!
!
! /*
!  * strInArray:
!  *      takes in a string and a string array and the number of elements in the
!  * string array.
!  *      returns the index if the string is somewhere in the array, -1 otherwise
!  */
!
! static int
! strInArray(const char *pattern, char **arr, int arr_size)
! {
!     int            i;
!
!     for (i = 0; i < arr_size; i++)
!     {
!         if (strcmp(pattern, arr[i]) == 0)
!             return i;
!     }
!     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;
! }
!
! void
! simple_string_list_append(SimpleStringList *list, const char *val)
! {
!     SimpleStringListCell *cell;
!
!     /* this calculation correctly accounts for the null trailing byte */
!     cell = (SimpleStringListCell *)
!         pg_malloc(sizeof(SimpleStringListCell) + strlen(val));
!     cell->next = NULL;
!     strcpy(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;
! }
!
! bool
! simple_string_list_member(SimpleStringList *list, const char *val)
! {
!     SimpleStringListCell *cell;
!
!     for (cell = list->head; cell; cell = cell->next)
!     {
!         if (strcmp(cell->val, val) == 0)
!             return true;
!     }
!     return false;
  }
diff --git a/src/bin/pg_dump/common.h b/src/bin/pg_dump/common.h
new file mode .
index 742d9f6..e69de29
*** a/src/bin/pg_dump/common.h
--- b/src/bin/pg_dump/common.h
***************
*** 1,24 ****
- /*-------------------------------------------------------------------------
-  *
-  * common.h
-  *      Common header file for the pg_dump, pg_dumpall, and pg_restore
-  *
-  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
-  * Portions Copyright (c) 1994, Regents of the University of California
-  *
-  * src/bin/pg_dump/common.h
-  *
-  *-------------------------------------------------------------------------
-  */
-
- #ifndef COMMON_H
- #define COMMON_H
-
- #include "postgres_fe.h"
-
- extern char *pg_strdup(const char *string);
- extern void *pg_malloc(size_t size);
- extern void *pg_calloc(size_t nmemb, size_t size);
- extern void *pg_realloc(void *ptr, size_t size);
-
- #endif   /* COMMON_H */
--- 0 ----
diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c
new file mode 100644
index 8375762..8c1e2b8
*** a/src/bin/pg_dump/compress_io.c
--- b/src/bin/pg_dump/compress_io.c
***************
*** 53,59 ****
   */

  #include "compress_io.h"
! #include "common.h"

  /*----------------------
   * Compressor API
--- 53,59 ----
   */

  #include "compress_io.h"
! #include "dumpmem.h"

  /*----------------------
   * Compressor API
diff --git a/src/bin/pg_dump/dumpcatalog.c b/src/bin/pg_dump/dumpcatalog.c
new file mode .
index 9747d47..e69de29
*** a/src/bin/pg_dump/dumpcatalog.c
--- b/src/bin/pg_dump/dumpcatalog.c
***************
*** 1,978 ****
- /*-------------------------------------------------------------------------
-  *
-  * common.c
-  *      catalog routines used by pg_dump
-  *
-  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
-  * Portions Copyright (c) 1994, Regents of the University of California
-  *
-  *
-  * IDENTIFICATION
-  *      src/bin/pg_dump/dumpcatalog.c
-  *
-  *-------------------------------------------------------------------------
-  */
- #include "postgres_fe.h"
-
- #include <ctype.h>
-
- #include "catalog/pg_class.h"
-
- #include "pg_backup_archiver.h"
- #include "common.h"
-
-
- /*
-  * Variables for mapping DumpId to DumpableObject
-  */
- static DumpableObject **dumpIdMap = NULL;
- static int    allocedDumpIds = 0;
- static DumpId lastDumpId = 0;
-
- /*
-  * Variables for mapping CatalogId to DumpableObject
-  */
- static bool catalogIdMapValid = false;
- static DumpableObject **catalogIdMap = NULL;
- static int    numCatalogIds = 0;
-
- /*
-  * These variables are static to avoid the notational cruft of having to pass
-  * 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 int    numCollations;
- static DumpableObject **tblinfoindex;
- static DumpableObject **typinfoindex;
- static DumpableObject **funinfoindex;
- static DumpableObject **oprinfoindex;
- static DumpableObject **collinfoindex;
-
-
- static void flagInhTables(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);
- static int    strInArray(const char *pattern, char **arr, int arr_size);
-
-
- /*
-  * getSchemaData
-  *      Collect information about all potentially dumpable objects
-  */
- TableInfo *
- getSchemaData(int *numTablesPtr)
- {
-     ExtensionInfo *extinfo;
-     InhInfo    *inhinfo;
-     CollInfo   *collinfo;
-     int            numNamespaces;
-     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;
-
-     if (g_verbose)
-         write_msg(NULL, "reading schemas\n");
-     getNamespaces(&numNamespaces);
-
-     /*
-      * 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(&numTables);
-     tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
-
-     if (g_verbose)
-         write_msg(NULL, "reading extensions\n");
-     extinfo = getExtensions(&numExtensions);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined functions\n");
-     funinfo = getFuncs(&numFuncs);
-     funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
-
-     /* this must be after getTables and getFuncs */
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined types\n");
-     typinfo = getTypes(&numTypes);
-     typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
-
-     /* this must be after getFuncs, too */
-     if (g_verbose)
-         write_msg(NULL, "reading procedural languages\n");
-     getProcLangs(&numProcLangs);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined aggregate functions\n");
-     getAggregates(&numAggregates);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined operators\n");
-     oprinfo = getOperators(&numOperators);
-     oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined operator classes\n");
-     getOpclasses(&numOpclasses);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined operator families\n");
-     getOpfamilies(&numOpfamilies);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined text search parsers\n");
-     getTSParsers(&numTSParsers);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined text search templates\n");
-     getTSTemplates(&numTSTemplates);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined text search dictionaries\n");
-     getTSDictionaries(&numTSDicts);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined text search configurations\n");
-     getTSConfigurations(&numTSConfigs);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined foreign-data wrappers\n");
-     getForeignDataWrappers(&numForeignDataWrappers);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined foreign servers\n");
-     getForeignServers(&numForeignServers);
-
-     if (g_verbose)
-         write_msg(NULL, "reading default privileges\n");
-     getDefaultACLs(&numDefaultACLs);
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined collations\n");
-     collinfo = getCollations(&numCollations);
-     collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
-
-     if (g_verbose)
-         write_msg(NULL, "reading user-defined conversions\n");
-     getConversions(&numConversions);
-
-     if (g_verbose)
-         write_msg(NULL, "reading type casts\n");
-     getCasts(&numCasts);
-
-     if (g_verbose)
-         write_msg(NULL, "reading table inheritance information\n");
-     inhinfo = getInherits(&numInherits);
-
-     if (g_verbose)
-         write_msg(NULL, "reading rewrite rules\n");
-     getRules(&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, "finding extension members\n");
-     getExtensionMembership(extinfo, numExtensions);
-
-     /* Link tables to parents, mark parents of target tables interesting */
-     if (g_verbose)
-         write_msg(NULL, "finding inheritance relationships\n");
-     flagInhTables(tblinfo, numTables, inhinfo, numInherits);
-
-     if (g_verbose)
-         write_msg(NULL, "reading column info for interesting tables\n");
-     getTableAttrs(tblinfo, numTables);
-
-     if (g_verbose)
-         write_msg(NULL, "flagging inherited columns in subtables\n");
-     flagInhAttrs(tblinfo, numTables);
-
-     if (g_verbose)
-         write_msg(NULL, "reading indexes\n");
-     getIndexes(tblinfo, numTables);
-
-     if (g_verbose)
-         write_msg(NULL, "reading constraints\n");
-     getConstraints(tblinfo, numTables);
-
-     if (g_verbose)
-         write_msg(NULL, "reading triggers\n");
-     getTriggers(tblinfo, numTables);
-
-     *numTablesPtr = numTables;
-     return tblinfo;
- }
-
- /* flagInhTables -
-  *     Fill in parent link fields of every target table, and mark
-  *     parents of target tables as interesting
-  *
-  * Note that only direct ancestors of targets are marked interesting.
-  * This is sufficient; we don't much care whether they inherited their
-  * attributes or not.
-  *
-  * modifies tblinfo
-  */
- static void
- flagInhTables(TableInfo *tblinfo, int numTables,
-               InhInfo *inhinfo, int numInherits)
- {
-     int            i,
-                 j;
-     int            numParents;
-     TableInfo **parents;
-
-     for (i = 0; i < numTables; i++)
-     {
-         /* Sequences and views never have parents */
-         if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
-             tblinfo[i].relkind == RELKIND_VIEW)
-             continue;
-
-         /* Don't bother computing anything for non-target tables, either */
-         if (!tblinfo[i].dobj.dump)
-             continue;
-
-         /* Find all the immediate parent tables */
-         findParentsByOid(&tblinfo[i], inhinfo, numInherits);
-
-         /* Mark the parents as interesting for getTableAttrs */
-         numParents = tblinfo[i].numParents;
-         parents = tblinfo[i].parents;
-         for (j = 0; j < numParents; j++)
-             parents[j]->interesting = true;
-     }
- }
-
- /* 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
-  *
-  * modifies tblinfo
-  */
- static void
- flagInhAttrs(TableInfo *tblinfo, int numTables)
- {
-     int            i,
-                 j,
-                 k;
-
-     for (i = 0; i < numTables; i++)
-     {
-         TableInfo  *tbinfo = &(tblinfo[i]);
-         int            numParents;
-         TableInfo **parents;
-         TableInfo  *parent;
-
-         /* Sequences and views never have parents */
-         if (tbinfo->relkind == RELKIND_SEQUENCE ||
-             tbinfo->relkind == RELKIND_VIEW)
-             continue;
-
-         /* Don't bother computing anything for non-target tables, either */
-         if (!tbinfo->dobj.dump)
-             continue;
-
-         numParents = tbinfo->numParents;
-         parents = tbinfo->parents;
-
-         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 (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;
-
-             foundAttr = false;
-             foundNotNull = false;
-             defaultsMatch = true;
-             defaultsFound = false;
-
-             attrDef = tbinfo->attrdefs[j];
-
-             for (k = 0; k < numParents; k++)
-             {
-                 int            inhAttrInd;
-
-                 parent = parents[k];
-                 inhAttrInd = strInArray(tbinfo->attnames[j],
-                                         parent->attnames,
-                                         parent->numatts);
-
-                 if (inhAttrInd != -1)
-                 {
-                     AttrDefInfo *inhDef = parent->attrdefs[inhAttrInd];
-
-                     foundAttr = true;
-                     foundNotNull |= parent->notnull[inhAttrInd];
-                     if (inhDef != NULL)
-                     {
-                         defaultsFound = true;
-
-                         /*
-                          * If any parent has a default and the child doesn't,
-                          * we have to emit an explicit DEFAULT NULL clause for
-                          * the child, else the parent's default will win.
-                          */
-                         if (attrDef == NULL)
-                         {
-                             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->adtable = tbinfo;
-                             attrDef->adnum = j + 1;
-                             attrDef->adef_expr = pg_strdup("NULL");
-
-                             attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
-                             attrDef->dobj.namespace = tbinfo->dobj.namespace;
-
-                             attrDef->dobj.dump = tbinfo->dobj.dump;
-
-                             attrDef->separate = false;
-                             addObjectDependency(&tbinfo->dobj,
-                                                 attrDef->dobj.dumpId);
-
-                             tbinfo->attrdefs[j] = attrDef;
-                         }
-                         if (strcmp(attrDef->adef_expr, inhDef->adef_expr) != 0)
-                         {
-                             defaultsMatch = false;
-
-                             /*
-                              * Whenever there is a non-matching parent
-                              * default, add a dependency to force the parent
-                              * default to be dumped first, in case the
-                              * defaults end up being dumped as separate
-                              * commands.  Otherwise the parent default will
-                              * override the child's when it is applied.
-                              */
-                             addObjectDependency(&attrDef->dobj,
-                                                 inhDef->dobj.dumpId);
-                         }
-                     }
-                 }
-             }
-
-             /*
-              * Based on the scan of the parents, decide if we can rely on the
-              * inherited attr
-              */
-             if (foundAttr)        /* Attr was inherited */
-             {
-                 /* 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))
-                 {
-                     tbinfo->inhAttrs[j] = false;
-                     tbinfo->inhAttrDef[j] = false;
-                 }
-
-                 /*
-                  * Clear it if NOT NULL and none of the parents were NOT NULL
-                  */
-                 if (tbinfo->notnull[j] && !foundNotNull)
-                 {
-                     tbinfo->inhAttrs[j] = false;
-                     tbinfo->inhNotNull[j] = false;
-                 }
-
-                 /* Clear it if attr has local definition */
-                 if (tbinfo->attislocal[j])
-                     tbinfo->inhAttrs[j] = false;
-             }
-         }
-     }
- }
-
- /*
-  * AssignDumpId
-  *        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 catId,
-  * but not any of the other standard fields of a DumpableObject.
-  */
- void
- 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;
-
-         if (allocedDumpIds <= 0)
-         {
-             newAlloc = 256;
-             dumpIdMap = (DumpableObject **)
-                 pg_malloc(newAlloc * sizeof(DumpableObject *));
-         }
-         else
-         {
-             newAlloc = allocedDumpIds * 2;
-             dumpIdMap = (DumpableObject **)
-                 pg_realloc(dumpIdMap, newAlloc * sizeof(DumpableObject *));
-         }
-         memset(dumpIdMap + allocedDumpIds, 0,
-                (newAlloc - allocedDumpIds) * sizeof(DumpableObject *));
-         allocedDumpIds = newAlloc;
-     }
-     dumpIdMap[dobj->dumpId] = dobj;
-
-     /* mark catalogIdMap invalid, but don't rebuild it yet */
-     catalogIdMapValid = false;
- }
-
- /*
-  * Assign a DumpId that's not tied to a DumpableObject.
-  *
-  * This is used when creating a "fixed" ArchiveEntry that doesn't need to
-  * participate in the sorting logic.
-  */
- DumpId
- createDumpId(void)
- {
-     return ++lastDumpId;
- }
-
- /*
-  * Return the largest DumpId so far assigned
-  */
- DumpId
- getMaxDumpId(void)
- {
-     return lastDumpId;
- }
-
- /*
-  * Find a DumpableObject by dump ID
-  *
-  * Returns NULL for invalid ID
-  */
- DumpableObject *
- findObjectByDumpId(DumpId dumpId)
- {
-     if (dumpId <= 0 || dumpId >= allocedDumpIds)
-         return NULL;            /* out of range? */
-     return dumpIdMap[dumpId];
- }
-
- /*
-  * Find a DumpableObject by catalog ID
-  *
-  * 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 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)
- {
-     DumpableObject **low;
-     DumpableObject **high;
-
-     if (!catalogIdMapValid)
-     {
-         if (catalogIdMap)
-             free(catalogIdMap);
-         getDumpableObjects(&catalogIdMap, &numCatalogIds);
-         if (numCatalogIds > 1)
-             qsort((void *) catalogIdMap, numCatalogIds,
-                   sizeof(DumpableObject *), DOCatalogIdCompare);
-         catalogIdMapValid = true;
-     }
-
-     /*
-      * 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 (numCatalogIds <= 0)
-         return NULL;
-     low = catalogIdMap;
-     high = catalogIdMap + (numCatalogIds - 1);
-     while (low <= high)
-     {
-         DumpableObject **middle;
-         int            difference;
-
-         middle = low + (high - low) / 2;
-         /* comparison must match DOCatalogIdCompare, below */
-         difference = oidcmp((*middle)->catId.oid, catalogId.oid);
-         if (difference == 0)
-             difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
-         if (difference == 0)
-             return *middle;
-         else if (difference < 0)
-             low = middle + 1;
-         else
-             high = middle - 1;
-     }
-     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)
- {
-     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.
-      */
-     cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
-     if (cmpval == 0)
-         cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
-     return cmpval;
- }
-
- /*
-  * Build an array of pointers to all known dumpable objects
-  *
-  * This simply creates a modifiable copy of the internal map.
-  */
- void
- getDumpableObjects(DumpableObject ***objs, int *numObjs)
- {
-     int            i,
-                 j;
-
-     *objs = (DumpableObject **)
-         pg_malloc(allocedDumpIds * sizeof(DumpableObject *));
-     j = 0;
-     for (i = 1; i < allocedDumpIds; i++)
-     {
-         if (dumpIdMap[i])
-             (*objs)[j++] = dumpIdMap[i];
-     }
-     *numObjs = j;
- }
-
- /*
-  * Add a dependency link to a DumpableObject
-  *
-  * Note: duplicate dependencies are currently not eliminated
-  */
- void
- addObjectDependency(DumpableObject *dobj, DumpId refId)
- {
-     if (dobj->nDeps >= dobj->allocDeps)
-     {
-         if (dobj->allocDeps <= 0)
-         {
-             dobj->allocDeps = 16;
-             dobj->dependencies = (DumpId *)
-                 pg_malloc(dobj->allocDeps * sizeof(DumpId));
-         }
-         else
-         {
-             dobj->allocDeps *= 2;
-             dobj->dependencies = (DumpId *)
-                 pg_realloc(dobj->dependencies,
-                            dobj->allocDeps * sizeof(DumpId));
-         }
-     }
-     dobj->dependencies[dobj->nDeps++] = refId;
- }
-
- /*
-  * Remove a dependency link from a DumpableObject
-  *
-  * If there are multiple links, all are removed
-  */
- void
- removeObjectDependency(DumpableObject *dobj, DumpId refId)
- {
-     int            i;
-     int            j = 0;
-
-     for (i = 0; i < dobj->nDeps; i++)
-     {
-         if (dobj->dependencies[i] != refId)
-             dobj->dependencies[j++] = dobj->dependencies[i];
-     }
-     dobj->nDeps = j;
- }
-
-
- /*
-  * findTableByOid
-  *      finds the entry (in tblinfo) of the table with the given oid
-  *      returns NULL if not found
-  */
- TableInfo *
- findTableByOid(Oid oid)
- {
-     return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
- }
-
- /*
-  * findTypeByOid
-  *      finds the entry (in typinfo) of the type with the given oid
-  *      returns NULL if not found
-  */
- TypeInfo *
- findTypeByOid(Oid oid)
- {
-     return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
- }
-
- /*
-  * findFuncByOid
-  *      finds the entry (in funinfo) of the function with the given oid
-  *      returns NULL if not found
-  */
- FuncInfo *
- findFuncByOid(Oid oid)
- {
-     return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
- }
-
- /*
-  * findOprByOid
-  *      finds the entry (in oprinfo) of the operator with the given oid
-  *      returns NULL if not found
-  */
- OprInfo *
- findOprByOid(Oid oid)
- {
-     return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
- }
-
- /*
-  * 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);
- }
-
-
- /*
-  * findParentsByOid
-  *      find a table's parents in tblinfo[]
-  */
- static void
- findParentsByOid(TableInfo *self,
-                  InhInfo *inhinfo, int numInherits)
- {
-     Oid            oid = self->dobj.catId.oid;
-     int            i,
-                 j;
-     int            numParents;
-
-     numParents = 0;
-     for (i = 0; i < numInherits; i++)
-     {
-         if (inhinfo[i].inhrelid == oid)
-             numParents++;
-     }
-
-     self->numParents = numParents;
-
-     if (numParents > 0)
-     {
-         self->parents = (TableInfo **)
-             pg_malloc(sizeof(TableInfo *) * numParents);
-         j = 0;
-         for (i = 0; i < numInherits; i++)
-         {
-             if (inhinfo[i].inhrelid == oid)
-             {
-                 TableInfo  *parent;
-
-                 parent = findTableByOid(inhinfo[i].inhparent);
-                 if (parent == NULL)
-                 {
-                     write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
-                               inhinfo[i].inhparent,
-                               self->dobj.name,
-                               oid);
-                     exit_nicely();
-                 }
-                 self->parents[j++] = parent;
-             }
-         }
-     }
-     else
-         self->parents = NULL;
- }
-
- /*
-  * parseOidArray
-  *      parse a string of numbers delimited by spaces into a character array
-  *
-  * Note: actually this is used for both Oids and potentially-signed
-  * attribute numbers.  This should cause no trouble, but we could split
-  * the function into two functions with different argument types if it does.
-  */
-
- void
- parseOidArray(const char *str, Oid *array, int arraysize)
- {
-     int            j,
-                 argNum;
-     char        temp[100];
-     char        s;
-
-     argNum = 0;
-     j = 0;
-     for (;;)
-     {
-         s = *str++;
-         if (s == ' ' || s == '\0')
-         {
-             if (j > 0)
-             {
-                 if (argNum >= arraysize)
-                 {
-                     write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
-                     exit_nicely();
-                 }
-                 temp[j] = '\0';
-                 array[argNum++] = atooid(temp);
-                 j = 0;
-             }
-             if (s == '\0')
-                 break;
-         }
-         else
-         {
-             if (!(isdigit((unsigned char) s) || s == '-') ||
-                 j >= sizeof(temp) - 1)
-             {
-                 write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
-                 exit_nicely();
-             }
-             temp[j++] = s;
-         }
-     }
-
-     while (argNum < arraysize)
-         array[argNum++] = InvalidOid;
- }
-
-
- /*
-  * strInArray:
-  *      takes in a string and a string array and the number of elements in the
-  * string array.
-  *      returns the index if the string is somewhere in the array, -1 otherwise
-  */
-
- static int
- strInArray(const char *pattern, char **arr, int arr_size)
- {
-     int            i;
-
-     for (i = 0; i < arr_size; i++)
-     {
-         if (strcmp(pattern, arr[i]) == 0)
-             return i;
-     }
-     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;
- }
-
- void
- simple_string_list_append(SimpleStringList *list, const char *val)
- {
-     SimpleStringListCell *cell;
-
-     /* this calculation correctly accounts for the null trailing byte */
-     cell = (SimpleStringListCell *)
-         pg_malloc(sizeof(SimpleStringListCell) + strlen(val));
-     cell->next = NULL;
-     strcpy(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;
- }
-
- bool
- simple_string_list_member(SimpleStringList *list, const char *val)
- {
-     SimpleStringListCell *cell;
-
-     for (cell = list->head; cell; cell = cell->next)
-     {
-         if (strcmp(cell->val, val) == 0)
-             return true;
-     }
-     return false;
- }
--- 0 ----
diff --git a/src/bin/pg_dump/dumpmem.c b/src/bin/pg_dump/dumpmem.c
new file mode 100644
index ...a50f4f5
*** a/src/bin/pg_dump/dumpmem.c
--- b/src/bin/pg_dump/dumpmem.c
***************
*** 0 ****
--- 1,73 ----
+ /*-------------------------------------------------------------------------
+  *
+  * dumpmem.c
+  *      memory routines used by pg_dump and pg_restore (but not pg_dumpall
+  *      because there is no failure location to report).
+  *
+  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *      src/bin/pg_dump/dumpmem.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres_fe.h"
+ #include "pg_backup.h"
+ #include "dumpmem.h"
+
+ #include <ctype.h>
+
+ /*
+  * Safer versions of some standard C library functions. If an
+  * out-of-memory condition occurs, these functions will bail out
+  * safely; therefore, their return value is guaranteed to be non-NULL.
+  * We also report the program name and close the database connection.
+  */
+
+ char *
+ pg_strdup(const char *string)
+ {
+     char       *tmp;
+
+     if (!string)
+         exit_horribly(NULL, NULL, "cannot duplicate null pointer\n");
+     tmp = strdup(string);
+     if (!tmp)
+         exit_horribly(NULL, NULL, "out of memory\n");
+     return tmp;
+ }
+
+ void *
+ pg_malloc(size_t size)
+ {
+     void       *tmp;
+
+     tmp = malloc(size);
+     if (!tmp)
+         exit_horribly(NULL, NULL, "out of memory\n");
+     return tmp;
+ }
+
+ void *
+ pg_calloc(size_t nmemb, size_t size)
+ {
+     void       *tmp;
+
+     tmp = calloc(nmemb, size);
+     if (!tmp)
+         exit_horribly(NULL, NULL, _("out of memory\n"));
+     return tmp;
+ }
+
+ void *
+ pg_realloc(void *ptr, size_t size)
+ {
+     void       *tmp;
+
+     tmp = realloc(ptr, size);
+     if (!tmp)
+         exit_horribly(NULL, NULL, _("out of memory\n"));
+     return tmp;
+ }
diff --git a/src/bin/pg_dump/dumpmem.h b/src/bin/pg_dump/dumpmem.h
new file mode 100644
index ...f70b320
*** a/src/bin/pg_dump/dumpmem.h
--- b/src/bin/pg_dump/dumpmem.h
***************
*** 0 ****
--- 1,24 ----
+ /*-------------------------------------------------------------------------
+  *
+  * dumpmem.h
+  *      Common header file for the pg_dump and pg_restore
+  *
+  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * src/bin/pg_dump/dumpmem.h
+  *
+  *-------------------------------------------------------------------------
+  */
+
+ #ifndef DUMPMEM_H
+ #define DUMPMEM_H
+
+ #include "postgres_fe.h"
+
+ extern char *pg_strdup(const char *string);
+ extern void *pg_malloc(size_t size);
+ extern void *pg_calloc(size_t nmemb, size_t size);
+ extern void *pg_realloc(void *ptr, size_t size);
+
+ #endif   /* DUMPMEM_H */
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
new file mode 100644
index 5cc012d..92b9d28
*** a/src/bin/pg_dump/dumputils.c
--- b/src/bin/pg_dump/dumputils.c
***************
*** 16,22 ****

  #include <ctype.h>

! #include "common.h"
  #include "dumputils.h"

  #include "parser/keywords.h"
--- 16,22 ----

  #include <ctype.h>

! #include "dumpmem.h"
  #include "dumputils.h"

  #include "parser/keywords.h"
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
new file mode 100644
index 8fb8382..164d593
*** a/src/bin/pg_dump/pg_backup_archiver.c
--- b/src/bin/pg_dump/pg_backup_archiver.c
***************
*** 21,27 ****
   */

  #include "pg_backup_db.h"
! #include "common.h"
  #include "dumputils.h"

  #include <ctype.h>
--- 21,27 ----
   */

  #include "pg_backup_db.h"
! #include "dumpmem.h"
  #include "dumputils.h"

  #include <ctype.h>
diff --git a/src/bin/pg_dump/pg_backup_custom.c b/src/bin/pg_dump/pg_backup_custom.c
new file mode 100644
index bfdf482..b2f3196
*** a/src/bin/pg_dump/pg_backup_custom.c
--- b/src/bin/pg_dump/pg_backup_custom.c
***************
*** 25,31 ****
   */

  #include "compress_io.h"
! #include "common.h"

  /*--------
   * Routines in the format interface
--- 25,31 ----
   */

  #include "compress_io.h"
! #include "dumpmem.h"

  /*--------
   * Routines in the format interface
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
new file mode 100644
index a58eb2d..bd1b8ef
*** a/src/bin/pg_dump/pg_backup_db.c
--- b/src/bin/pg_dump/pg_backup_db.c
***************
*** 11,17 ****
   */

  #include "pg_backup_db.h"
! #include "common.h"
  #include "dumputils.h"

  #include <unistd.h>
--- 11,17 ----
   */

  #include "pg_backup_db.h"
! #include "dumpmem.h"
  #include "dumputils.h"

  #include <unistd.h>
diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c
new file mode 100644
index 4f9fcc2..bd18ec5
*** a/src/bin/pg_dump/pg_backup_directory.c
--- b/src/bin/pg_dump/pg_backup_directory.c
***************
*** 34,40 ****
   */

  #include "compress_io.h"
! #include "common.h"

  #include <dirent.h>
  #include <sys/stat.h>
--- 34,40 ----
   */

  #include "compress_io.h"
! #include "dumpmem.h"

  #include <dirent.h>
  #include <sys/stat.h>
diff --git a/src/bin/pg_dump/pg_backup_files.c b/src/bin/pg_dump/pg_backup_files.c
new file mode 100644
index 76366e1..85373b5
*** a/src/bin/pg_dump/pg_backup_files.c
--- b/src/bin/pg_dump/pg_backup_files.c
***************
*** 26,32 ****
   */

  #include "pg_backup_archiver.h"
! #include "common.h"

  static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
  static void _StartData(ArchiveHandle *AH, TocEntry *te);
--- 26,32 ----
   */

  #include "pg_backup_archiver.h"
! #include "dumpmem.h"

  static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
  static void _StartData(ArchiveHandle *AH, TocEntry *te);
diff --git a/src/bin/pg_dump/pg_backup_null.c b/src/bin/pg_dump/pg_backup_null.c
new file mode 100644
index 252e7a4..201f0d9
*** a/src/bin/pg_dump/pg_backup_null.c
--- b/src/bin/pg_dump/pg_backup_null.c
***************
*** 23,29 ****
   */

  #include "pg_backup_archiver.h"
! #include "common.h"
  #include "dumputils.h"

  #include <unistd.h>                /* for dup */
--- 23,29 ----
   */

  #include "pg_backup_archiver.h"
! #include "dumpmem.h"
  #include "dumputils.h"

  #include <unistd.h>                /* for dup */
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
new file mode 100644
index 94133cf..39ce417
*** a/src/bin/pg_dump/pg_backup_tar.c
--- b/src/bin/pg_dump/pg_backup_tar.c
***************
*** 28,34 ****
  #include "pg_backup.h"
  #include "pg_backup_archiver.h"
  #include "pg_backup_tar.h"
! #include "common.h"

  #include <sys/stat.h>
  #include <ctype.h>
--- 28,34 ----
  #include "pg_backup.h"
  #include "pg_backup_archiver.h"
  #include "pg_backup_tar.h"
! #include "dumpmem.h"

  #include <sys/stat.h>
  #include <ctype.h>
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
new file mode 100644
index e11ba4d..ec932e4
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 57,63 ****
  #include "libpq/libpq-fs.h"

  #include "pg_backup_archiver.h"
! #include "common.h"
  #include "dumputils.h"

  extern char *optarg;
--- 57,63 ----
  #include "libpq/libpq-fs.h"

  #include "pg_backup_archiver.h"
! #include "dumpmem.h"
  #include "dumputils.h"

  extern char *optarg;
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
new file mode 100644
index 3bb220d..8023450
*** a/src/bin/pg_dump/pg_dump_sort.c
--- b/src/bin/pg_dump/pg_dump_sort.c
***************
*** 14,20 ****
   *-------------------------------------------------------------------------
   */
  #include "pg_backup_archiver.h"
! #include "common.h"

  static const char *modulename = gettext_noop("sorter");

--- 14,20 ----
   *-------------------------------------------------------------------------
   */
  #include "pg_backup_archiver.h"
! #include "dumpmem.h"

  static const char *modulename = gettext_noop("sorter");

diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
new file mode 100644
index a810ed6..ea68f51
*** a/src/bin/pg_dump/pg_restore.c
--- b/src/bin/pg_dump/pg_restore.c
***************
*** 39,45 ****
   *-------------------------------------------------------------------------
   */

! #include "common.h"
  #include "pg_backup_archiver.h"
  #include "dumputils.h"

--- 39,45 ----
   *-------------------------------------------------------------------------
   */

! #include "dumpmem.h"
  #include "pg_backup_archiver.h"
  #include "dumputils.h"