First pass at schema-fying pg_dump/pg_restore. Much to do still,
authorTom Lane
Fri, 10 May 2002 22:36:27 +0000 (22:36 +0000)
committerTom Lane
Fri, 10 May 2002 22:36:27 +0000 (22:36 +0000)
but the basic capability seems to work.

13 files changed:
doc/src/sgml/ref/pg_dump.sgml
doc/src/sgml/ref/pg_restore.sgml
src/bin/pg_dump/common.c
src/bin/pg_dump/pg_backup.h
src/bin/pg_dump/pg_backup_archiver.c
src/bin/pg_dump/pg_backup_archiver.h
src/bin/pg_dump/pg_backup_db.c
src/bin/pg_dump/pg_backup_db.h
src/bin/pg_dump/pg_backup_null.c
src/bin/pg_dump/pg_backup_tar.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/pg_dump/pg_restore.c

index 1167128716e12557a11ea4de1d52710d15c3e385..d2ab719fe341d225a73cc169f5741b8951135e1c 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -407,10 +407,11 @@ PostgreSQL documentation
       
       
        
-        The scripts or archives created by pg_dump
-        need to have superuser access in certain cases, such as when
-        disabling triggers or setting ownership of schema elements.
-        This option specifies the user name to use for those cases.
+        Specify the superuser user name to use when disabling triggers.
+   This is only relevant if 
+   (Usually, it's better to specify
+   
+   resulting script as superuser.)
        
       
      
@@ -481,6 +482,36 @@ PostgreSQL documentation
       
      
 
+     
+      
+      
+      
+       
+        This option is only relevant when creating a data-only dump.
+   It instructs pg_dump to include commands
+   to temporarily disable triggers on the target tables while
+   the data is reloaded.  Use this if you have referential
+   integrity checks or other triggers on the tables that you
+   do not want to invoke during data reload.
+       
+
+       
+        Presently, the commands emitted for 
+   must be done as superuser.  So, you should also specify
+   a superuser name with 
+   
+   start the resulting script as a superuser.  If you give neither
+   option, the entire script must be run as superuser.
+       
+
+       
+        This option is only meaningful for the plain-text format.  For
+        the other formats, you may specify the option when you
+        call pg_restore.
+       
+      
+     
+
      
       
       
index 3e7f2c6fcc0e2ffa674d8232bba54eccfd8476d1..aa87e2e6f44d24f2e3eb6ba999c3c8549fa69fa7 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  
       
       
        
-        Specify the superuser user name to use when disabling triggers and/or setting ownership of schema elements.
-        By default, pg_restore will use the current user name if it is a superuser.
+        Specify the superuser user name to use when disabling triggers.
+   This is only relevant if .
        
       
      
       
      
 
+     
+      
+      
+      
+       
+        This option is only relevant when performing a data-only restore.
+   It instructs pg_restore to execute commands
+   to temporarily disable triggers on the target tables while
+   the data is reloaded.  Use this if you have referential
+   integrity checks or other triggers on the tables that you
+   do not want to invoke during data reload.
+       
+
+       
+        Presently, the commands emitted for 
+   must be done as superuser.  So, you should also specify
+   a superuser name with 
+   
+   pg_restore as a superuser.
+       
+      
+     
+
     
    
 
index 4188746471e678071f3baf13e8d2408c98af4ed9..47692bdeac443d4d62986018ed2261887c5da445 100644 (file)
@@ -3,30 +3,15 @@
  * common.c
  *   common routines between pg_dump and pg4_dump
  *
+ * 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-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.63 2002/04/24 02:44:19 momjian Exp $
- *
- * Modifications - 6/12/96 - [email protected] - version 1.13.dhb.2
- *
- *  - Fixed dumpTable output to output lengths for char and varchar types!
- *  - Added single. quote to twin single quote expansion for 'insert' string
- *    mode.
- *
- * Modifications 14-Sep-2000 - [email protected]
- * -   Added enum for findTypeByOid to specify how to handle OID and which
- *     string to return - formatted type, or base type. If the base type
- *     is returned then fmtId is called on the string.
- *
- * Modifications 4-Apr-2001 - [email protected]
- * -   Changed flagInhAttrs to check all parent tables for overridden settings
- *     and set flags accordingly.
- *
- *     BEWARE: Since fmtId uses a static buffer, using 'useBaseTypeName' on more
- *             than one call in a line will cause problems.
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.64 2002/05/10 22:36:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "strdup.h"
 #endif
 
-static char **findParentsByOid(TableInfo *tbinfo, int numTables,
-                InhInfo *inhinfo, int numInherits,
-                const char *oid,
-                int *numParents,
-                int (**parentIndexes)[]);
-static int findTableByOid(TableInfo *tbinfo, int numTables, const char *oid);
+static void findParentsByOid(TableInfo *tblinfo, int numTables,
+                            InhInfo *inhinfo, int numInherits,
+                            const char *oid,
+                            int *numParentsPtr, int **parentIndexes);
+static void flagInhTables(TableInfo *tbinfo, int numTables,
+            InhInfo *inhinfo, int numInherits);
 static void flagInhAttrs(TableInfo *tbinfo, int numTables,
             InhInfo *inhinfo, int numInherits);
 static int strInArray(const char *pattern, char **arr, int arr_size);
 
-/*
- * findTypeByOid
- *   given an oid of a type, return its typename
- *
- * Can return various special cases for oid 0.
- *
- * NOTE:  should hash this, but just do linear search for now
- */
-
-char *
-findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid, OidOptions opts)
-{
-   int         i;
-
-   if (strcmp(oid, "0") == 0)
-   {
-       if ((opts & zeroAsOpaque) != 0)
-           return g_opaque_type;
-       else if ((opts & zeroAsAny) != 0)
-           return "'any'";
-       else if ((opts & zeroAsStar) != 0)
-           return "*";
-       else if ((opts & zeroAsNone) != 0)
-           return "NONE";
-   }
-
-   for (i = 0; i < numTypes; i++)
-   {
-       if (strcmp(tinfo[i].oid, oid) == 0)
-       {
-           if ((opts & useBaseTypeName) != 0)
-               return (char *) fmtId(tinfo[i].typname, false);
-           else
-               return tinfo[i].typedefn;
-       }
-   }
-
-   /* no suitable type name was found */
-   return (NULL);
-}
-
-/*
- * findOprByOid
- *   given the oid of an operator, return the name of the operator
- *
- *
- * NOTE:  should hash this, but just do linear search for now
- *
- */
-char *
-findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
-{
-   int         i;
-
-   for (i = 0; i < numOprs; i++)
-   {
-       if (strcmp(oprinfo[i].oid, oid) == 0)
-           return oprinfo[i].oprname;
-   }
-
-   /* should never get here */
-   write_msg(NULL, "failed sanity check, operator with oid %s not found\n", oid);
-
-   /* no suitable operator name was found */
-   return (NULL);
-}
-
-
-/*
- * findParentsByOid
- *   given the oid of a class, return the names of its parent classes
- * and assign the number of parents, and parent indexes to the last arguments.
- *
- *
- * returns NULL if none
- */
-
-static char **
-findParentsByOid(TableInfo *tblinfo, int numTables,
-                InhInfo *inhinfo, int numInherits, const char *oid,
-                int *numParentsPtr, int (**parentIndexes)[])
-{
-   int         i,
-               j;
-   int         parentInd,
-               selfInd;
-   char      **result;
-   int         numParents;
-
-   numParents = 0;
-   for (i = 0; i < numInherits; i++)
-   {
-       if (strcmp(inhinfo[i].inhrelid, oid) == 0)
-           numParents++;
-   }
-
-   *numParentsPtr = numParents;
-
-   if (numParents > 0)
-   {
-       result = (char **) malloc(sizeof(char *) * numParents);
-       (*parentIndexes) = malloc(sizeof(int) * numParents);
-       j = 0;
-       for (i = 0; i < numInherits; i++)
-       {
-           if (strcmp(inhinfo[i].inhrelid, oid) == 0)
-           {
-               parentInd = findTableByOid(tblinfo, numTables,
-                                          inhinfo[i].inhparent);
-               if (parentInd < 0)
-               {
-                   selfInd = findTableByOid(tblinfo, numTables, oid);
-                   if (selfInd >= 0)
-                       write_msg(NULL, "failed sanity check, parent oid %s of table %s (oid %s) not found\n",
-                                 inhinfo[i].inhparent,
-                                 tblinfo[selfInd].relname,
-                                 oid);
-                   else
-                       write_msg(NULL, "failed sanity check, parent oid %s of table (oid %s) not found\n",
-                                 inhinfo[i].inhparent,
-                                 oid);
-
-                   exit_nicely();
-               }
-               (**parentIndexes)[j] = parentInd;
-               result[j++] = tblinfo[parentInd].relname;
-           }
-       }
-       return result;
-   }
-   else
-   {
-       (*parentIndexes) = NULL;
-       return NULL;
-   }
-}
-
-/*
- * parseNumericArray
- *   parse a string of numbers delimited by spaces into a character array
- */
-
-void
-parseNumericArray(const char *str, char **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, "parseNumericArray: too many numbers\n");
-                   exit_nicely();
-               }
-               temp[j] = '\0';
-               array[argNum++] = strdup(temp);
-               j = 0;
-           }
-           if (s == '\0')
-               break;
-       }
-       else
-       {
-           if (!(isdigit((unsigned char) s) || s == '-') ||
-               j >= sizeof(temp) - 1)
-           {
-               write_msg(NULL, "parseNumericArray: bogus number\n");
-               exit_nicely();
-           }
-           temp[j++] = s;
-       }
-   }
-
-   while (argNum < arraysize)
-       array[argNum++] = strdup("0");
-}
-
-
-/*
- * 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;
-}
 
 /*
  * dumpSchema:
  *   we have a valid connection, we are now going to dump the schema
  * into the file
- *
  */
 
 TableInfo *
 dumpSchema(Archive *fout,
           int *numTablesPtr,
-          const char *tablename,
           const bool aclsSkip,
-          const bool oids,
           const bool schemaOnly,
           const bool dataOnly)
 {
+   int         numNamespaces;
    int         numTypes;
    int         numFuncs;
    int         numTables;
    int         numInherits;
    int         numAggregates;
    int         numOperators;
-   int         numIndexes;
-   TypeInfo   *tinfo = NULL;
-   FuncInfo   *finfo = NULL;
-   AggInfo    *agginfo = NULL;
-   TableInfo  *tblinfo = NULL;
-   InhInfo    *inhinfo = NULL;
-   OprInfo    *oprinfo = NULL;
-   IndInfo    *indinfo = NULL;
+   NamespaceInfo *nsinfo;
+   TypeInfo   *tinfo;
+   FuncInfo   *finfo;
+   AggInfo    *agginfo;
+   TableInfo  *tblinfo;
+   InhInfo    *inhinfo;
+   OprInfo    *oprinfo;
+
+   if (g_verbose)
+       write_msg(NULL, "reading namespaces\n");
+   nsinfo = getNamespaces(&numNamespaces);
 
    if (g_verbose)
        write_msg(NULL, "reading user-defined types\n");
@@ -312,32 +90,40 @@ dumpSchema(Archive *fout,
 
    if (g_verbose)
        write_msg(NULL, "reading user-defined tables\n");
-   tblinfo = getTables(&numTables, finfo, numFuncs, tablename);
-
-   if (g_verbose)
-       write_msg(NULL, "reading index information\n");
-   indinfo = getIndexes(&numIndexes);
+   tblinfo = getTables(&numTables);
 
    if (g_verbose)
        write_msg(NULL, "reading table inheritance information\n");
    inhinfo = getInherits(&numInherits);
 
+   /* Link tables to parents, mark parents of target tables interesting */
    if (g_verbose)
-       write_msg(NULL, "finding the column names and types for each table\n");
+       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, inhinfo, numInherits);
 
-   if (!tablename && !dataOnly)
+   if (!dataOnly)
    {
        if (g_verbose)
            write_msg(NULL, "dumping out database comment\n");
        dumpDBComment(fout);
    }
 
-   if (!tablename && fout)
+   if (!dataOnly)
+   {
+       if (g_verbose)
+           write_msg(NULL, "dumping out user-defined namespaces\n");
+       dumpNamespaces(fout, nsinfo, numNamespaces);
+   }
+
+   if (!dataOnly)
    {
        if (g_verbose)
            write_msg(NULL, "dumping out user-defined types\n");
@@ -346,63 +132,102 @@ dumpSchema(Archive *fout,
 
    if (g_verbose)
        write_msg(NULL, "dumping out tables\n");
-
-   dumpTables(fout, tblinfo, numTables, tablename,
+   dumpTables(fout, tblinfo, numTables,
               aclsSkip, schemaOnly, dataOnly);
 
-   if (fout && !dataOnly)
+   if (!dataOnly)
    {
        if (g_verbose)
            write_msg(NULL, "dumping out indexes\n");
-       dumpIndexes(fout, indinfo, numIndexes, tblinfo, numTables, tablename);
+       dumpIndexes(fout, tblinfo, numTables);
    }
 
-   if (!tablename && !dataOnly)
+   if (!dataOnly)
    {
        if (g_verbose)
            write_msg(NULL, "dumping out user-defined procedural languages\n");
-       dumpProcLangs(fout, finfo, numFuncs, tinfo, numTypes);
+       dumpProcLangs(fout, finfo, numFuncs);
    }
 
-   if (!tablename && !dataOnly)
+   if (!dataOnly)
    {
        if (g_verbose)
            write_msg(NULL, "dumping out user-defined functions\n");
-       dumpFuncs(fout, finfo, numFuncs, tinfo, numTypes);
+       dumpFuncs(fout, finfo, numFuncs);
    }
 
-   if (!tablename && !dataOnly)
+   if (!dataOnly)
    {
        if (g_verbose)
            write_msg(NULL, "dumping out user-defined aggregate functions\n");
-       dumpAggs(fout, agginfo, numAggregates, tinfo, numTypes);
+       dumpAggs(fout, agginfo, numAggregates);
    }
 
-   if (!tablename && !dataOnly)
+   if (!dataOnly)
    {
        if (g_verbose)
            write_msg(NULL, "dumping out user-defined operators\n");
-       dumpOprs(fout, oprinfo, numOperators, tinfo, numTypes);
+       dumpOprs(fout, oprinfo, numOperators);
    }
 
    *numTablesPtr = numTables;
-   clearAggInfo(agginfo, numAggregates);
-   clearOprInfo(oprinfo, numOperators);
-   clearTypeInfo(tinfo, numTypes);
-   clearFuncInfo(finfo, numFuncs);
-   clearInhInfo(inhinfo, numInherits);
-   clearIndInfo(indinfo, numIndexes);
    return tblinfo;
 }
 
-/* flagInhAttrs -
- *  for each table in tblinfo, flag its inherited attributes
- * so when we dump the table out, we don't dump out the inherited attributes
+/* flagInhTables -
+ *  Fill in parentIndexes fields of every target table, and mark
+ *  parents of target tables as interesting
  *
- * initializes the parentRels field of each table
+ * 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;
+   int        *parentIndexes;
+
+   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].dump)
+           continue;
+
+       /* Find all the immediate parent tables */
+       findParentsByOid(tblinfo, numTables,
+                        inhinfo, numInherits,
+                        tblinfo[i].oid,
+                        &tblinfo[i].numParents,
+                        &tblinfo[i].parentIndexes);
+       numParents = tblinfo[i].numParents;
+       parentIndexes = tblinfo[i].parentIndexes;
+
+       /* Mark the parents as interesting for getTableAttrs */
+       for (j = 0; j < numParents; j++)
+       {
+           int         parentInd = parentIndexes[j];
+
+           tblinfo[parentInd].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,
@@ -413,7 +238,8 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
                k;
    int         parentInd;
    int         inhAttrInd;
-   int         (*parentIndexes)[];
+   int         numParents;
+   int        *parentIndexes;
    bool        foundAttr;      /* Attr was found in a parent */
    bool        foundNotNull;   /* Attr was NOT NULL in a parent */
    bool        defaultsMatch;  /* All non-empty defaults match */
@@ -421,23 +247,22 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
    char       *attrDef;
    char       *inhDef;
 
-   /*
-    * we go backwards because the tables in tblinfo are in OID order,
-    * meaning the subtables are after the parent tables we flag inherited
-    * attributes from child tables first
-    */
-   for (i = numTables - 1; i >= 0; i--)
+   for (i = 0; i < numTables; i++)
    {
-       /* Sequences can never have parents, and attr info is undefined */
-       if (tblinfo[i].relkind == RELKIND_SEQUENCE)
+       /* 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].dump)
            continue;
 
-       /* Get all the parents and their indexes. */
-       tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
-                                                inhinfo, numInherits,
-                                                tblinfo[i].oid,
-                                                &tblinfo[i].numParents,
-                                                &parentIndexes);
+       numParents = tblinfo[i].numParents;
+       parentIndexes = tblinfo[i].parentIndexes;
+
+       if (numParents == 0)
+           continue;           /* nothing to see here, move along */
 
        /*
         * For each attr, check the parent info: if no parent has an attr
@@ -459,18 +284,9 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
 
            attrDef = tblinfo[i].adef_expr[j];
 
-           for (k = 0; k < tblinfo[i].numParents; k++)
+           for (k = 0; k < numParents; k++)
            {
-               parentInd = (*parentIndexes)[k];
-
-               if (parentInd < 0)
-               {
-                   /* shouldn't happen unless findParentsByOid is broken */
-                   write_msg(NULL, "failed sanity check, table \"%s\" not found by flagInhAttrs\n",
-                             tblinfo[i].parentRels[k]);
-                   exit_nicely();
-               };
-
+               parentInd = parentIndexes[k];
                inhAttrInd = strInArray(tblinfo[i].attnames[j],
                                        tblinfo[parentInd].attnames,
                                        tblinfo[parentInd].numatts);
@@ -479,7 +295,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
                {
                    foundAttr = true;
                    foundNotNull |= tblinfo[parentInd].notnull[inhAttrInd];
-                   if (attrDef != NULL)        /* It we have a default,
+                   if (attrDef != NULL)        /* If we have a default,
                                                 * check parent */
                    {
                        inhDef = tblinfo[parentInd].adef_expr[inhAttrInd];
@@ -488,10 +304,10 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
                        {
                            defaultsFound = true;
                            defaultsMatch &= (strcmp(attrDef, inhDef) == 0);
-                       };
-                   };
-               };
-           };
+                       }
+                   }
+               }
+           }
 
            /*
             * Based on the scan of the parents, decide if we can rely on
@@ -500,9 +316,9 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
            if (foundAttr)      /* Attr was inherited */
            {
                /* Set inherited flag by default */
-               tblinfo[i].inhAttrs[j] = 1;
-               tblinfo[i].inhAttrDef[j] = 1;
-               tblinfo[i].inhNotNull[j] = 1;
+               tblinfo[i].inhAttrs[j] = true;
+               tblinfo[i].inhAttrDef[j] = true;
+               tblinfo[i].inhNotNull[j] = true;
 
                /*
                 * Clear it if attr had a default, but parents did not, or
@@ -510,8 +326,8 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
                 */
                if ((attrDef != NULL) && (!defaultsFound || !defaultsMatch))
                {
-                   tblinfo[i].inhAttrs[j] = 0;
-                   tblinfo[i].inhAttrDef[j] = 0;
+                   tblinfo[i].inhAttrs[j] = false;
+                   tblinfo[i].inhAttrDef[j] = false;
                }
 
                /*
@@ -520,8 +336,8 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
                 */
                if (tblinfo[i].notnull[j] && !foundNotNull)
                {
-                   tblinfo[i].inhAttrs[j] = 0;
-                   tblinfo[i].inhNotNull[j] = 0;
+                   tblinfo[i].inhAttrs[j] = false;
+                   tblinfo[i].inhNotNull[j] = false;
                }
            }
        }
@@ -530,64 +346,199 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
 
 
 /*
- * findTableByName
- *   finds the index (in tblinfo) of the table with the given relname
+ * findTableByOid
+ *   finds the index (in tblinfo) of the table with the given oid
  * returns -1 if not found
  *
  * NOTE:  should hash this, but just do linear search for now
  */
-
 int
-findTableByName(TableInfo *tblinfo, int numTables, const char *relname)
+findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
 {
    int         i;
 
    for (i = 0; i < numTables; i++)
    {
-       if (strcmp(tblinfo[i].relname, relname) == 0)
+       if (strcmp(tblinfo[i].oid, oid) == 0)
            return i;
    }
    return -1;
 }
 
+
 /*
- * findTableByOid
- *   finds the index (in tblinfo) of the table with the given oid
+ * findFuncByOid
+ *   finds the index (in finfo) of the function with the given OID
  * returns -1 if not found
  *
  * NOTE:  should hash this, but just do linear search for now
  */
-
-static int
-findTableByOid(TableInfo *tblinfo, int numTables, const char *oid)
+int
+findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid)
 {
    int         i;
 
-   for (i = 0; i < numTables; i++)
+   for (i = 0; i < numFuncs; i++)
    {
-       if (strcmp(tblinfo[i].oid, oid) == 0)
+       if (strcmp(finfo[i].oid, oid) == 0)
            return i;
    }
    return -1;
 }
 
-
 /*
- * findFuncByName
- *   finds the index (in finfo) of the function with the given name
- * returns -1 if not found
+ * findOprByOid
+ *   given the oid of an operator, return the name of the operator
  *
  * NOTE:  should hash this, but just do linear search for now
  */
+char *
+findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid)
+{
+   int         i;
 
-int
-findFuncByName(FuncInfo *finfo, int numFuncs, const char *name)
+   for (i = 0; i < numOprs; i++)
+   {
+       if (strcmp(oprinfo[i].oid, oid) == 0)
+           return oprinfo[i].oprname;
+   }
+
+   /* should never get here */
+   write_msg(NULL, "failed sanity check, operator with oid %s not found\n", oid);
+
+   /* no suitable operator name was found */
+   return (NULL);
+}
+
+
+/*
+ * findParentsByOid
+ *   given the oid of a class, find its parent classes in tblinfo[]
+ *
+ * Returns the number of parents and their array indexes into the
+ * last two arguments.
+ */
+
+static void
+findParentsByOid(TableInfo *tblinfo, int numTables,
+                InhInfo *inhinfo, int numInherits,
+                const char *oid,
+                int *numParentsPtr, int **parentIndexes)
+{
+   int         i,
+               j;
+   int         parentInd,
+               selfInd;
+   int         numParents;
+
+   numParents = 0;
+   for (i = 0; i < numInherits; i++)
+   {
+       if (strcmp(inhinfo[i].inhrelid, oid) == 0)
+           numParents++;
+   }
+
+   *numParentsPtr = numParents;
+
+   if (numParents > 0)
+   {
+       *parentIndexes = (int *) malloc(sizeof(int) * numParents);
+       j = 0;
+       for (i = 0; i < numInherits; i++)
+       {
+           if (strcmp(inhinfo[i].inhrelid, oid) == 0)
+           {
+               parentInd = findTableByOid(tblinfo, numTables,
+                                          inhinfo[i].inhparent);
+               if (parentInd < 0)
+               {
+                   selfInd = findTableByOid(tblinfo, numTables, oid);
+                   if (selfInd >= 0)
+                       write_msg(NULL, "failed sanity check, parent oid %s of table %s (oid %s) not found\n",
+                                 inhinfo[i].inhparent,
+                                 tblinfo[selfInd].relname,
+                                 oid);
+                   else
+                       write_msg(NULL, "failed sanity check, parent oid %s of table (oid %s) not found\n",
+                                 inhinfo[i].inhparent,
+                                 oid);
+
+                   exit_nicely();
+               }
+               (*parentIndexes)[j++] = parentInd;
+           }
+       }
+   }
+   else
+       *parentIndexes = NULL;
+}
+
+/*
+ * parseNumericArray
+ *   parse a string of numbers delimited by spaces into a character array
+ */
+
+void
+parseNumericArray(const char *str, char **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, "parseNumericArray: too many numbers\n");
+                   exit_nicely();
+               }
+               temp[j] = '\0';
+               array[argNum++] = strdup(temp);
+               j = 0;
+           }
+           if (s == '\0')
+               break;
+       }
+       else
+       {
+           if (!(isdigit((unsigned char) s) || s == '-') ||
+               j >= sizeof(temp) - 1)
+           {
+               write_msg(NULL, "parseNumericArray: bogus number\n");
+               exit_nicely();
+           }
+           temp[j++] = s;
+       }
+   }
+
+   while (argNum < arraysize)
+       array[argNum++] = strdup("0");
+}
+
+
+/*
+ * 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 < numFuncs; i++)
+   for (i = 0; i < arr_size; i++)
    {
-       if (strcmp(finfo[i].proname, name) == 0)
+       if (strcmp(pattern, arr[i]) == 0)
            return i;
    }
    return -1;
index 32d4c1e88eb1720eb38eec942b128953cbe77645..dca162cd76d24d7ab646c739665f4a6f4c743637 100644 (file)
  *
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.18 2002/02/11 00:18:20 tgl Exp $
- *
- * Modifications - 28-Jun-2000 - [email protected]
- *
- * Initial version.
- *
- *
- * Modifications - 28-Jul-2000 - [email protected] (1.45)
- *
- *     Added --create, --no-owner, --superuser, --no-reconnect (pg_dump & pg_restore)
- *     Added code to dump 'Create Schema' statement (pg_dump)
- *     Don't bother to disable/enable triggers if we don't have a superuser (pg_restore)
- *     Cleaned up code for reconnecting to database.
- *     Force a reconnect as superuser before enabling/disabling triggers.
- *
- * Modifications - 31-Jul-2000 - [email protected] (1.46, 1.47)
- *     Added & Removed --throttle (pg_dump)
- *     Fixed minor bug in language dumping code: expbuffres were not being reset.
- *     Fixed version number initialization in _allocAH (pg_backup_archiver.c)
- *     Added second connection when restoring BLOBs to allow temp. table to survive
- *     (db reconnection causes temp tables to be lost).
+ *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.19 2002/05/10 22:36:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -87,6 +67,7 @@ typedef struct _restoreOptions
                                 * cirsumstances */
    int         use_setsessauth;/* use SET SESSSION AUTHORIZATION instead
                                 * of \connect */
+   int         disable_triggers;/* disable triggers during data-only restore */
    char       *superuser;      /* Username to use as superuser */
    int         dataOnly;
    int         dropSchema;
@@ -152,10 +133,12 @@ PGconn *ConnectDatabase(Archive *AH,
 
 
 /* Called to add a TOC entry */
-extern void ArchiveEntry(Archive *AH, const char *oid, const char *name,
-            const char *desc, const char *((*deps)[]), const char *defn,
-          const char *dropStmt, const char *copyStmt, const char *owner,
-            DataDumperPtr dumpFn, void *dumpArg);
+extern void ArchiveEntry(Archive *AHX, const char *oid, const char *name,
+                        const char *namespace, const char *owner,
+                        const char *desc, const char *((*deps)[]),
+                        const char *defn, const char *dropStmt,
+                        const char *copyStmt,
+                        DataDumperPtr dumpFn, void *dumpArg);
 
 /* Called to write *data* to the archive */
 extern int WriteData(Archive *AH, const void *data, int dLen);
index 11c62a0298c453fb708e28f74b545eeacac0b2c3..272b98cecef23a756c18bc0bed3f9dd030bc9a0c 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.45 2002/05/06 17:34:45 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.46 2002/05/10 22:36:26 tgl Exp $
  *
  * Modifications - 28-Jun-2000 - [email protected]
  *
@@ -95,8 +95,10 @@ static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
         const int compression, ArchiveMode mode);
 static int _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData);
 
+static void _doSetSessionAuth(ArchiveHandle *AH, const char *autharg);
 static void _reconnectAsOwner(ArchiveHandle *AH, const char *dbname, TocEntry *te);
 static void _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user);
+static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
 
 static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt);
 static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
@@ -208,23 +210,13 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
        AHX->minRemoteVersion = 070100;
        AHX->maxRemoteVersion = 999999;
 
-       ConnectDatabase(AHX, ropt->dbname, ropt->pghost, ropt->pgport, ropt->username,
+       ConnectDatabase(AHX, ropt->dbname,
+                       ropt->pghost, ropt->pgport, ropt->username,
                        ropt->requirePassword, ropt->ignoreVersion);
-
-       /*
-        * If no superuser was specified then see if the current user will
-        * do...
-        */
-       if (!ropt->superuser)
-       {
-           if (UserIsSuperuser(AH, ConnectedUser(AH)))
-               ropt->superuser = strdup(ConnectedUser(AH));
-       }
-
    }
 
    /*
-    * Work out if we have an implied data-only retore. This can happen if
+    * Work out if we have an implied data-only restore. This can happen if
     * the dump was data only or if the user has used a toc list to
     * exclude all of the schema data. All we do is look for schema
     * entries - if none are found then we set the dataOnly flag.
@@ -253,12 +245,6 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
        }
    }
 
-   if (!ropt->superuser)
-       write_msg(modulename, "WARNING:\n"
-                 "  Data restoration may fail because existing triggers cannot be disabled\n"
-                 "  (no superuser user name specified).  This is only a problem when\n"
-       "  restoring into a database with already existing triggers.\n");
-
    /*
     * Setup the output file if necessary.
     */
@@ -280,8 +266,9 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
            {
                /* We want the schema */
                ahlog(AH, 1, "dropping %s %s\n", te->desc, te->name);
-               /* Reconnect if necessary */
+               /* Select owner and schema as necessary */
                _reconnectAsOwner(AH, NULL, te);
+               _selectOutputSchema(AH, te->namespace);
                /* Drop it */
                ahprintf(AH, "%s", te->dropStmt);
            }
@@ -376,6 +363,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
                         * have reconnected)
                         */
                        _reconnectAsOwner(AH, NULL, te);
+                       _selectOutputSchema(AH, te->namespace);
 
                        ahlog(AH, 1, "restoring data for table %s\n", te->name);
 
@@ -433,7 +421,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
                if ((reqs & REQ_DATA) != 0)     /* We loaded the data */
                {
                    ahlog(AH, 1, "fixing up large object cross-reference for %s\n", te->name);
-                   FixupBlobRefs(AH, te->name);
+                   FixupBlobRefs(AH, te);
                }
            }
            else
@@ -501,30 +489,31 @@ _canRestoreBlobs(ArchiveHandle *AH)
 static void
 _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
 {
-   char       *oldUser = NULL;
+   char       *oldUser;
+   char       *oldSchema;
 
-   /* Can't do much if we're connected & don't have a superuser */
-   /* Also, don't bother with triggers unless a data-only retore. */
-   if (!ropt->dataOnly || (_restoringToDB(AH) && !ropt->superuser))
+   /* This hack is only needed in a data-only restore */
+   if (!ropt->dataOnly || !ropt->disable_triggers)
        return;
 
+   oldUser = strdup(AH->currUser);
+   oldSchema = strdup(AH->currSchema);
+
    /*
-    * Reconnect as superuser if possible, since they are the only ones
-    * who can update pg_class...
+    * Become superuser if possible, since they are the only ones
+    * who can update pg_class.  If -S was not given, but we are allowed
+    * to use SET SESSION AUTHORIZATION, assume the initial user identity
+    * is a superuser.  Otherwise we just have to bull ahead anyway.
     */
    if (ropt->superuser)
    {
-       if (!_restoringToDB(AH) || !ConnectedUserIsSuperuser(AH))
-       {
-           /*
-            * If we're not allowing changes for ownership, then remember
-            * the user so we can change it back here. Otherwise, let
-            * _reconnectAsOwner do what it has to do.
-            */
-           if (ropt->noOwner)
-               oldUser = strdup(ConnectedUser(AH));
-           _reconnectAsUser(AH, NULL, ropt->superuser);
-       }
+       _reconnectAsUser(AH, NULL, ropt->superuser);
+       /* be careful to preserve schema setting */
+       _selectOutputSchema(AH, oldSchema);
+   }
+   else if (AH->ropt->use_setsessauth)
+   {
+       _doSetSessionAuth(AH, "DEFAULT");
    }
 
    ahlog(AH, 1, "disabling triggers\n");
@@ -538,52 +527,59 @@ _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *rop
    /*
     * Just update the AFFECTED table, if known.
     */
-
    if (te && te->name && strlen(te->name) > 0)
-       ahprintf(AH, "UPDATE \"pg_class\" SET \"reltriggers\" = 0 WHERE \"relname\" = '%s';\n\n",
-                te->name);
+       ahprintf(AH, "UPDATE pg_class SET reltriggers = 0 "
+                "WHERE oid = '%s'::regclass;\n\n",
+                fmtId(te->name, false));
    else
-       ahprintf(AH, "UPDATE \"pg_class\" SET \"reltriggers\" = 0 WHERE \"relname\" !~ '^pg_';\n\n");
+       ahprintf(AH, "UPDATE pg_class SET reltriggers = 0 FROM pg_namespace "
+                "WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
 
    /*
-    * Restore the user connection from the start of this procedure if
-    * _reconnectAsOwner is disabled.
+    * Restore original user and schema state.
     */
-   if (ropt->noOwner && oldUser)
+   if (ropt->superuser)
    {
        _reconnectAsUser(AH, NULL, oldUser);
-       free(oldUser);
+       /* be careful to preserve schema setting */
+       _selectOutputSchema(AH, oldSchema);
    }
+   else if (AH->ropt->use_setsessauth)
+   {
+       _doSetSessionAuth(AH, fmtId(oldUser, false));
+   }
+   free(oldUser);
+   free(oldSchema);
 }
 
 static void
 _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
 {
-   char       *oldUser = NULL;
+   char       *oldUser;
+   char       *oldSchema;
 
-   /* Can't do much if we're connected & don't have a superuser */
-   /* Also, don't bother with triggers unless a data-only retore. */
-   if (!ropt->dataOnly || (_restoringToDB(AH) && !ropt->superuser))
+   /* This hack is only needed in a data-only restore */
+   if (!ropt->dataOnly || !ropt->disable_triggers)
        return;
 
+   oldUser = strdup(AH->currUser);
+   oldSchema = strdup(AH->currSchema);
+
    /*
-    * Reconnect as superuser if possible, since they are the only ones
-    * who can update pg_class...
+    * Become superuser if possible, since they are the only ones
+    * who can update pg_class.  If -S was not given, but we are allowed
+    * to use SET SESSION AUTHORIZATION, assume the initial user identity
+    * is a superuser.  Otherwise we just have to bull ahead anyway.
     */
    if (ropt->superuser)
    {
-       if (!_restoringToDB(AH) || !ConnectedUserIsSuperuser(AH))
-       {
-           /*
-            * If we're not allowing changes for ownership, then remember
-            * the user so we can change it back here. Otherwise, let
-            * _reconnectAsOwner do what it has to do
-            */
-           if (ropt->noOwner)
-               oldUser = strdup(ConnectedUser(AH));
-
-           _reconnectAsUser(AH, NULL, ropt->superuser);
-       }
+       _reconnectAsUser(AH, NULL, ropt->superuser);
+       /* be careful to preserve schema setting */
+       _selectOutputSchema(AH, oldSchema);
+   }
+   else if (AH->ropt->use_setsessauth)
+   {
+       _doSetSessionAuth(AH, "DEFAULT");
    }
 
    ahlog(AH, 1, "enabling triggers\n");
@@ -593,29 +589,36 @@ _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt
     * 'SET' command when one is available.
     */
    ahprintf(AH, "-- Enable triggers\n");
+
+   /*
+    * Just update the AFFECTED table, if known.
+    */
    if (te && te->name && strlen(te->name) > 0)
-   {
        ahprintf(AH, "UPDATE pg_class SET reltriggers = "
-       "(SELECT count(*) FROM pg_trigger where pg_class.oid = tgrelid) "
-                "WHERE relname = '%s';\n\n",
-                te->name);
-   }
+                "(SELECT count(*) FROM pg_trigger where pg_class.oid = tgrelid) "
+                "WHERE oid = '%s'::regclass;\n\n",
+                fmtId(te->name, false));
    else
-   {
-       ahprintf(AH, "UPDATE \"pg_class\" SET \"reltriggers\" = "
-       "(SELECT count(*) FROM pg_trigger where pg_class.oid = tgrelid) "
-                "WHERE \"relname\" !~ '^pg_';\n\n");
-   }
+       ahprintf(AH, "UPDATE pg_class SET reltriggers = "
+                "(SELECT count(*) FROM pg_trigger where pg_class.oid = tgrelid) "
+                "FROM pg_namespace "
+                "WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
 
    /*
-    * Restore the user connection from the start of this procedure if
-    * _reconnectAsOwner is disabled.
+    * Restore original user and schema state.
     */
-   if (ropt->noOwner && oldUser)
+   if (ropt->superuser)
    {
        _reconnectAsUser(AH, NULL, oldUser);
-       free(oldUser);
+       /* be careful to preserve schema setting */
+       _selectOutputSchema(AH, oldSchema);
    }
+   else if (AH->ropt->use_setsessauth)
+   {
+       _doSetSessionAuth(AH, fmtId(oldUser, false));
+   }
+   free(oldUser);
+   free(oldSchema);
 }
 
 /*
@@ -642,8 +645,10 @@ WriteData(Archive *AHX, const void *data, int dLen)
 /* Public */
 void
 ArchiveEntry(Archive *AHX, const char *oid, const char *name,
-            const char *desc, const char *((*deps)[]), const char *defn,
-          const char *dropStmt, const char *copyStmt, const char *owner,
+            const char *namespace, const char *owner,
+            const char *desc, const char *((*deps)[]),
+            const char *defn, const char *dropStmt,
+            const char *copyStmt,
             DataDumperPtr dumpFn, void *dumpArg)
 {
    ArchiveHandle *AH = (ArchiveHandle *) AHX;
@@ -664,21 +669,21 @@ ArchiveEntry(Archive *AHX, const char *oid, const char *name,
    newToc->id = AH->lastID;
 
    newToc->name = strdup(name);
+   newToc->namespace = namespace ? strdup(namespace) : NULL;
+   newToc->owner = strdup(owner);
    newToc->desc = strdup(desc);
+   newToc->defn = strdup(defn);
+   newToc->dropStmt = strdup(dropStmt);
+   newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
 
    newToc->oid = strdup(oid);
-   newToc->depOid = deps;
+   newToc->depOid = deps;      /* NB: not copied */
    _fixupOidInfo(newToc);
 
-
-   newToc->defn = strdup(defn);
-   newToc->dropStmt = strdup(dropStmt);
-   newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
-   newToc->owner = strdup(owner);
    newToc->printed = 0;
    newToc->formatData = NULL;
-   newToc->dataDumper = dumpFn,
-       newToc->dataDumperArg = dumpArg;
+   newToc->dataDumper = dumpFn;
+   newToc->dataDumperArg = dumpArg;
 
    newToc->hadDumper = dumpFn ? 1 : 0;
 
@@ -1667,6 +1672,7 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
 
    AH->currUser = strdup("");  /* So it's valid, but we can free() it
                                 * later if necessary */
+   AH->currSchema = strdup(""); /* ditto */
 
    AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry));
    if (!AH->toc)
@@ -1789,6 +1795,7 @@ WriteToc(ArchiveHandle *AH)
        WriteStr(AH, te->defn);
        WriteStr(AH, te->dropStmt);
        WriteStr(AH, te->copyStmt);
+       WriteStr(AH, te->namespace);
        WriteStr(AH, te->owner);
 
        /* Dump list of dependencies */
@@ -1840,6 +1847,9 @@ ReadToc(ArchiveHandle *AH)
        if (AH->version >= K_VERS_1_3)
            te->copyStmt = ReadStr(AH);
 
+       if (AH->version >= K_VERS_1_6)
+           te->namespace = ReadStr(AH);
+
        te->owner = ReadStr(AH);
 
        /* Read TOC entry dependencies */
@@ -1975,6 +1985,33 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt)
    return res;
 }
 
+/*
+ * Issue a SET SESSION AUTHORIZATION command.  Caller is responsible
+ * for updating state if appropriate.  Note that caller must also quote
+ * the argument if it's a username (it might be DEFAULT, too).
+ */
+static void
+_doSetSessionAuth(ArchiveHandle *AH, const char *autharg)
+{
+   if (RestoringToDB(AH))
+   {
+       PQExpBuffer qry = createPQExpBuffer();
+       PGresult   *res;
+
+       appendPQExpBuffer(qry, "SET SESSION AUTHORIZATION %s;", autharg);
+       res = PQexec(AH->connection, qry->data);
+
+       if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
+           die_horribly(AH, modulename, "could not set session user to %s: %s",
+                        autharg, PQerrorMessage(AH->connection));
+
+       PQclear(res);
+       destroyPQExpBuffer(qry);
+   }
+   else
+       ahprintf(AH, "SET SESSION AUTHORIZATION %s;\n\n", autharg);
+}
+
 
 /*
  * Issue the commands to connect to the database as the specified user
@@ -1999,25 +2036,7 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user)
     */
    if (!dbname && AH->ropt->use_setsessauth)
    {
-       if (RestoringToDB(AH))
-       {
-           PQExpBuffer qry = createPQExpBuffer();
-           PGresult   *res;
-
-           appendPQExpBuffer(qry, "SET SESSION AUTHORIZATION %s;",
-                             fmtId(user, false));
-           res = PQexec(AH->connection, qry->data);
-
-           if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
-               die_horribly(AH, modulename, "could not set session user to %s: %s",
-                            user, PQerrorMessage(AH->connection));
-
-           PQclear(res);
-           destroyPQExpBuffer(qry);
-       }
-       else
-           ahprintf(AH, "SET SESSION AUTHORIZATION %s;\n\n",
-                    fmtId(user, false));
+       _doSetSessionAuth(AH, fmtId(user, false));
    }
    else if (AH->ropt && AH->ropt->noReconnect)
    {
@@ -2038,6 +2057,11 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user)
        ahprintf(AH, qry->data);
 
        destroyPQExpBuffer(qry);
+
+       /* don't assume we still know the output schema */
+       if (AH->currSchema)
+           free(AH->currSchema);
+       AH->currSchema = strdup("");
    }
 
    /*
@@ -2066,6 +2090,43 @@ _reconnectAsOwner(ArchiveHandle *AH, const char *dbname, TocEntry *te)
 }
 
 
+/*
+ * Issue the commands to select the specified schema as the current schema
+ * in the target database.
+ */
+static void
+_selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
+{
+   if (!schemaName || *schemaName == '\0' ||
+       strcmp(AH->currSchema, schemaName) == 0)
+       return;                 /* no need to do anything */
+
+   if (RestoringToDB(AH))
+   {
+       PQExpBuffer qry = createPQExpBuffer();
+       PGresult   *res;
+
+       appendPQExpBuffer(qry, "SET search_path = %s;",
+                         fmtId(schemaName, false));
+       res = PQexec(AH->connection, qry->data);
+
+       if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
+           die_horribly(AH, modulename, "could not set search_path to %s: %s",
+                        schemaName, PQerrorMessage(AH->connection));
+
+       PQclear(res);
+       destroyPQExpBuffer(qry);
+   }
+   else
+       ahprintf(AH, "SET search_path = %s;\n\n",
+                fmtId(schemaName, false));
+
+   if (AH->currSchema)
+       free(AH->currSchema);
+   AH->currSchema = strdup(schemaName);
+}
+
+
 /*
  * fmtId
  *
@@ -2139,16 +2200,19 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
 {
    char       *pfx;
 
-   /* Reconnect if necessary */
+   /* Select owner and schema as necessary */
    _reconnectAsOwner(AH, NULL, te);
+   _selectOutputSchema(AH, te->namespace);
 
    if (isData)
        pfx = "Data for ";
    else
        pfx = "";
 
-   ahprintf(AH, "--\n-- %sTOC Entry ID %d (OID %s)\n--\n-- Name: %s Type: %s Owner: %s\n",
-            pfx, te->id, te->oid, te->name, te->desc, te->owner);
+   ahprintf(AH, "--\n-- %sTOC Entry ID %d (OID %s)\n--\n-- Name: %s Type: %s Schema: %s Owner: %s\n",
+            pfx, te->id, te->oid, te->name, te->desc,
+            te->namespace ? te->namespace : "-",
+            te->owner);
    if (AH->PrintExtraTocPtr !=NULL)
        (*AH->PrintExtraTocPtr) (AH, te);
    ahprintf(AH, "--\n\n");
index 0fbce03f52c8b79a053ce043b69323959504a88d..95ab2133ca571e32c633024a60ad2d45d193f282 100644 (file)
  *
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.42 2002/04/24 02:21:04 momjian Exp $
- *
- * Modifications - 28-Jun-2000 - [email protected]
- * -   Initial version.
- *
- * Modifications - 15-Sep-2000 - [email protected]
- * -   Added braceDepth to sqlparseInfo to handle braces in rule definitions.
- *
- * Modifications - 31-Mar-2001 - [email protected] (1.50)
- * -   Make dependencies work on ArchiveEntry calls so that UDTs will
- *     dump in correct order.
+ *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.43 2002/05/10 22:36:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -68,8 +58,8 @@ typedef z_stream *z_streamp;
 #include "libpq-fe.h"
 
 #define K_VERS_MAJOR 1
-#define K_VERS_MINOR 5
-#define K_VERS_REV 7
+#define K_VERS_MINOR 6
+#define K_VERS_REV 0
 
 /* Data block types */
 #define BLK_DATA 1
@@ -82,7 +72,8 @@ typedef z_stream *z_streamp;
 #define K_VERS_1_3 (( (1 * 256 + 3) * 256 + 0) * 256 + 0)      /* BLOBs */
 #define K_VERS_1_4 (( (1 * 256 + 4) * 256 + 0) * 256 + 0)      /* Date & name in header */
 #define K_VERS_1_5 (( (1 * 256 + 5) * 256 + 0) * 256 + 0)      /* Handle dependencies */
-#define K_VERS_MAX (( (1 * 256 + 5) * 256 + 255) * 256 + 0)
+#define K_VERS_1_6 (( (1 * 256 + 6) * 256 + 0) * 256 + 0)      /* Schema field in TOCs */
+#define K_VERS_MAX (( (1 * 256 + 6) * 256 + 255) * 256 + 0)
 
 /* No of BLOBs to restore in 1 TX */
 #define BLOB_BATCH_SIZE 100
@@ -235,6 +226,7 @@ typedef struct _archiveHandle
    int         tocCount;       /* Number of TOC entries */
    struct _tocEntry *currToc;  /* Used when dumping data */
    char       *currUser;       /* Restore: current username in script */
+   char       *currSchema;     /* Restore: current schema in script */
    int         compression;    /* Compression requested on open */
    ArchiveMode mode;           /* File mode - r or w */
    void       *formatData;     /* Header data specific to file format */
@@ -254,11 +246,12 @@ typedef struct _tocEntry
    int         hadDumper;      /* Archiver was passed a dumper routine
                                 * (used in restore) */
    char       *name;
+   char       *namespace;      /* null or empty string if not in a schema */
+   char       *owner;
    char       *desc;
    char       *defn;
    char       *dropStmt;
    char       *copyStmt;
-   char       *owner;
    char       *oid;            /* Oid of source of entry */
    Oid         oidVal;         /* Value of above */
    const char *((*depOid)[]);
@@ -314,9 +307,6 @@ extern OutputContext SetOutput(ArchiveHandle *AH, char *filename, int compressio
 extern void ResetOutput(ArchiveHandle *AH, OutputContext savedContext);
 extern int RestoringToDB(ArchiveHandle *AH);
 extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser);
-extern int UserIsSuperuser(ArchiveHandle *AH, char *user);
-extern char *ConnectedUser(ArchiveHandle *AH);
-extern int ConnectedUserIsSuperuser(ArchiveHandle *AH);
 
 int            ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
 int            ahprintf(ArchiveHandle *AH, const char *fmt,...) __attribute__((format(printf, 2, 3)));
index be638d226fccdc0483e625c80b90a4fc16d94bf4..eb7bcafbc30a0b5a1cc8d5cb05f0bbb7d799069a 100644 (file)
@@ -5,25 +5,7 @@
  * Implements the basic DB functions used by the archiver.
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.31 2002/01/18 19:17:05 momjian Exp $
- *
- * NOTES
- *
- * Modifications - 04-Jan-2001 - [email protected]
- *
- *   - Check results of PQ routines more carefully.
- *
- * Modifications - 19-Mar-2001 - [email protected]
- *
- *   - Avoid forcing table name to lower case in FixupBlobXrefs!
- *
- *
- * Modifications - 18-Jan-2002 - [email protected]
- *
- *   - Split ExecuteSqlCommandBuf into 3 routines for (slightly) improved
- *     clarity. Modify loop to cater for COPY commands buried in the SQL
- *     command buffer (prev version assumed COPY command was executed
- *     in prior call). This was to fix the buf in the 'set max oid' code.
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.32 2002/05/10 22:36:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -219,57 +201,6 @@ _check_database_version(ArchiveHandle *AH, bool ignoreVersion)
    }
 }
 
-/*
- * Check if a given user is a superuser.
- */
-int
-UserIsSuperuser(ArchiveHandle *AH, char *user)
-{
-   PQExpBuffer qry = createPQExpBuffer();
-   PGresult   *res;
-   int         i_usesuper;
-   int         ntups;
-   int         isSuper;
-
-   /* Get the superuser setting */
-   appendPQExpBuffer(qry, "select usesuper from pg_user where usename = '%s'", user);
-   res = PQexec(AH->connection, qry->data);
-
-   if (!res)
-       die_horribly(AH, modulename, "null result checking superuser status of %s\n", user);
-
-   if (PQresultStatus(res) != PGRES_TUPLES_OK)
-       die_horribly(AH, modulename, "could not check superuser status of %s: %s",
-                    user, PQerrorMessage(AH->connection));
-
-   ntups = PQntuples(res);
-
-   if (ntups == 0)
-       isSuper = 0;
-   else
-   {
-       i_usesuper = PQfnumber(res, "usesuper");
-       isSuper = (strcmp(PQgetvalue(res, 0, i_usesuper), "t") == 0);
-   }
-   PQclear(res);
-
-   destroyPQExpBuffer(qry);
-
-   return isSuper;
-}
-
-int
-ConnectedUserIsSuperuser(ArchiveHandle *AH)
-{
-   return UserIsSuperuser(AH, PQuser(AH->connection));
-}
-
-char *
-ConnectedUser(ArchiveHandle *AH)
-{
-   return PQuser(AH->connection);
-}
-
 /*
  * Reconnect to the server.  If dbname is not NULL, use that database,
  * else the one associated with the archive handle.  If username is
@@ -310,6 +241,11 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username)
    AH->username = strdup(newusername);
    /* XXX Why don't we update AH->dbname? */
 
+   /* don't assume we still know the output schema */
+   if (AH->currSchema)
+       free(AH->currSchema);
+   AH->currSchema = strdup("");
+
    return 1;
 }
 
@@ -481,13 +417,6 @@ ConnectDatabase(Archive *AHX,
 
    PQsetNoticeProcessor(AH->connection, notice_processor, NULL);
 
-   /*
-    * AH->currUser = PQuser(AH->connection);
-    *
-    * Removed because it prevented an initial \connect when dumping to SQL
-    * in pg_dump.
-    */
-
    return AH->connection;
 }
 
@@ -775,8 +704,9 @@ ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qryv, int bufLen)
 }
 
 void
-FixupBlobRefs(ArchiveHandle *AH, char *tablename)
+FixupBlobRefs(ArchiveHandle *AH, TocEntry *te)
 {
+   PQExpBuffer tblName;
    PQExpBuffer tblQry;
    PGresult   *res,
               *uRes;
@@ -784,44 +714,55 @@ FixupBlobRefs(ArchiveHandle *AH, char *tablename)
                n;
    char       *attr;
 
-   if (strcmp(tablename, BLOB_XREF_TABLE) == 0)
+   if (strcmp(te->name, BLOB_XREF_TABLE) == 0)
        return;
 
+   tblName = createPQExpBuffer();
    tblQry = createPQExpBuffer();
 
-   appendPQExpBuffer(tblQry, "SELECT a.attname FROM pg_class c, pg_attribute a, pg_type t "
-    " WHERE a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid "
-    " AND t.typname in ('oid', 'lo') AND c.relname = '%s';", tablename);
+   if (te->namespace && strlen(te->namespace) > 0)
+       appendPQExpBuffer(tblName, "%s.",
+                         fmtId(te->namespace, false));
+   appendPQExpBuffer(tblName, "%s",
+                     fmtId(te->name, false));
+
+   appendPQExpBuffer(tblQry,
+                     "SELECT a.attname FROM "
+                     "pg_catalog.pg_attribute a, pg_catalog.pg_type t "
+                     "WHERE a.attnum > 0 AND a.attrelid = '%s'::regclass "
+                     "AND a.atttypid = t.oid AND t.typname in ('oid', 'lo')",
+                     tblName->data);
 
    res = PQexec(AH->blobConnection, tblQry->data);
    if (!res)
        die_horribly(AH, modulename, "could not find oid columns of table \"%s\": %s",
-                    tablename, PQerrorMessage(AH->connection));
+                    te->name, PQerrorMessage(AH->connection));
 
    if ((n = PQntuples(res)) == 0)
    {
        /* nothing to do */
-       ahlog(AH, 1, "no OID type columns in table %s\n", tablename);
+       ahlog(AH, 1, "no OID type columns in table %s\n", te->name);
    }
 
    for (i = 0; i < n; i++)
    {
        attr = PQgetvalue(res, i, 0);
 
-       ahlog(AH, 1, "fixing large object cross-references for %s.%s\n", tablename, attr);
+       ahlog(AH, 1, "fixing large object cross-references for %s.%s\n",
+             te->name, attr);
 
        resetPQExpBuffer(tblQry);
 
-       /*
-        * We should use coalesce here (rather than 'exists'), but it
-        * seems to be broken in 7.0.2 (weird optimizer strategy)
-        */
-       appendPQExpBuffer(tblQry, "UPDATE \"%s\" SET \"%s\" = ", tablename, attr);
-       appendPQExpBuffer(tblQry, " (SELECT x.newOid FROM \"%s\" x WHERE x.oldOid = \"%s\".\"%s\")",
-                         BLOB_XREF_TABLE, tablename, attr);
-       appendPQExpBuffer(tblQry, " where exists"
-                 "(select * from %s x where x.oldOid = \"%s\".\"%s\");",
-                         BLOB_XREF_TABLE, tablename, attr);
+       /* Can't use fmtId twice in one call... */
+       appendPQExpBuffer(tblQry,
+                         "UPDATE %s SET %s = %s.newOid",
+                         tblName->data, fmtId(attr, false),
+                         BLOB_XREF_TABLE);
+       appendPQExpBuffer(tblQry,
+                         " FROM %s WHERE %s.oldOid = %s.%s",
+                         BLOB_XREF_TABLE,
+                         BLOB_XREF_TABLE,
+                         tblName->data, fmtId(attr, false));
 
        ahlog(AH, 10, "SQL: %s\n", tblQry->data);
 
@@ -829,17 +770,18 @@ FixupBlobRefs(ArchiveHandle *AH, char *tablename)
        if (!uRes)
            die_horribly(AH, modulename,
                    "could not update column \"%s\" of table \"%s\": %s",
-                   attr, tablename, PQerrorMessage(AH->blobConnection));
+                   attr, te->name, PQerrorMessage(AH->blobConnection));
 
        if (PQresultStatus(uRes) != PGRES_COMMAND_OK)
            die_horribly(AH, modulename,
                "error while updating column \"%s\" of table \"%s\": %s",
-                   attr, tablename, PQerrorMessage(AH->blobConnection));
+                   attr, te->name, PQerrorMessage(AH->blobConnection));
 
        PQclear(uRes);
    }
 
    PQclear(res);
+   destroyPQExpBuffer(tblName);
    destroyPQExpBuffer(tblQry);
 }
 
index 463526922d9cdc2891a4b2deb5f6fc1f6906441d..d4baa55538d1d7eb90d6d44b7f82381214b6d802 100644 (file)
@@ -2,12 +2,12 @@
  * Definitions for pg_backup_db.c
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.h,v 1.5 2001/06/27 21:21:37 petere Exp $
+ *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.h,v 1.6 2002/05/10 22:36:26 tgl Exp $
  */
 
-#define BLOB_XREF_TABLE "dump_blob_xref"       /* MUST be lower case */
+#define BLOB_XREF_TABLE "pg_dump_blob_xref"        /* MUST be lower case */
 
-extern void FixupBlobRefs(ArchiveHandle *AH, char *tablename);
+extern void FixupBlobRefs(ArchiveHandle *AH, TocEntry *te);
 extern int ExecuteSqlCommand(ArchiveHandle *AH, PQExpBuffer qry, char *desc, bool use_blob);
 extern int ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qry, int bufLen);
 
index af8f52a7c206a6f8ab275669db833520248d6ca4..beb6ed12b6438fc6a238cb066322a5a9c9753cfc 100644 (file)
@@ -3,7 +3,7 @@
  * pg_backup_null.c
  *
  * Implementation of an archive that is never saved; it is used by
- * pg_dump to output output a plain text SQL script instead of save
+ * pg_dump to output a plain text SQL script instead of save
  * a real archive.
  *
  * See the headers to pg_restore for more details.
@@ -17,7 +17,7 @@
  *
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.8 2002/04/24 02:21:04 momjian Exp $
+ *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.9 2002/05/10 22:36:26 tgl Exp $
  *
  * Modifications - 09-Jul-2000 - [email protected]
  *
index efd8a03013358764b833a47fa1de6722f43198f7..783b8a3136143115f110c4183fe323191cf8439e 100644 (file)
@@ -16,7 +16,7 @@
  *
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.21 2002/04/24 02:21:04 momjian Exp $
+ *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.22 2002/05/10 22:36:26 tgl Exp $
  *
  * Modifications - 28-Jun-2000 - [email protected]
  *
@@ -835,7 +835,7 @@ _CloseArchive(ArchiveHandle *AH)
        ropt = NewRestoreOptions();
        ropt->dropSchema = 1;
        ropt->compression = 0;
-       ropt->superuser = PQuser(AH->connection);
+       ropt->superuser = NULL;
        ropt->suppressDumpWarnings = true;
 
        savVerbose = AH->public.verbose;
index 20c847ea63c64d283434d3336b50a59595585f90..c3f89cb85dfe300e5ee339b680cc75929f8c47ef 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.258 2002/05/06 18:33:45 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.259 2002/05/10 22:36:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,6 +64,7 @@
 #include "pg_backup.h"
 #include "pg_backup_archiver.h"
 
+
 typedef enum _formatLiteralOptions
 {
    CONV_ALL = 0,
@@ -74,31 +75,55 @@ typedef enum _formatLiteralOptions
    /* only checks for 'opts == CONV_ALL' anyway. */
 } formatLiteralOptions;
 
-static void dumpComment(Archive *fout, const char *target, const char *oid,
-           const char *classname, int subid,
-           const char *((*deps)[]));
+typedef struct _dumpContext
+{
+   TableInfo  *tblinfo;
+   int         tblidx;
+   bool        oids;
+} DumpContext;
+
+static void help(const char *progname);
+static int parse_version(const char *versionString);
+static NamespaceInfo *findNamespace(const char *nsoid, const char *objoid);
+static void dumpClasses(const TableInfo *tblinfo, const int numTables,
+                       Archive *fout, const bool oids);
+static void dumpComment(Archive *fout, const char *target,
+                       const char *namespace, const char *owner,
+                       const char *oid, const char *classname, int subid,
+                       const char *((*deps)[]));
+static void dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
+                           FuncInfo *g_finfo, int numFuncs,
+                           TypeInfo *g_tinfo, int numTypes);
 static void dumpOneDomain(Archive *fout, TypeInfo *tinfo);
-static void dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly);
+static void dumpOneTable(Archive *fout, TableInfo *tbinfo,
+                        TableInfo *g_tblinfo);
+static void dumpOneSequence(Archive *fout, TableInfo *tbinfo,
+                           const bool schemaOnly, const bool dataOnly);
 static void dumpACL(Archive *fout, TableInfo *tbinfo);
-static void dumpTriggers(Archive *fout, const char *tablename,
-            TableInfo *tblinfo, int numTables);
-static void dumpRules(Archive *fout, const char *tablename,
-         TableInfo *tblinfo, int numTables);
-static void formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts);
-static void clearTableInfo(TableInfo *, int);
-static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
-           TypeInfo *tinfo, int numTypes);
+static void dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables);
+static void dumpRules(Archive *fout, TableInfo *tblinfo, int numTables);
+static void formatStringLiteral(PQExpBuffer buf, const char *str,
+                               const formatLiteralOptions opts);
+static void dumpOneFunc(Archive *fout, FuncInfo *finfo);
+static void dumpOneOpr(Archive *fout, OprInfo *oprinfo,
+                      OprInfo *g_oprinfo, int numOperators);
+static const char *convertRegProcReference(const char *proc);
+static const char *convertOperatorReference(const char *opr,
+                       OprInfo *g_oprinfo, int numOperators);
+static void dumpOneAgg(Archive *fout, AggInfo *agginfo);
 static Oid findLastBuiltinOid_V71(const char *);
 static Oid findLastBuiltinOid_V70(void);
 static void setMaxOid(Archive *fout);
-
+static void selectSourceSchema(const char *schemaName);
+static char *getFormattedTypeName(const char *oid, OidOptions opts);
+static char *myFormatType(const char *typname, int32 typmod);
+static const char *fmtQualifiedId(const char *schema, const char *id);
 
 static void AddAcl(char *aclbuf, const char *keyword);
 static char *GetPrivileges(Archive *AH, const char *s);
 
 static int dumpBlobs(Archive *AH, char *, void *);
 static int dumpDatabase(Archive *AH);
-static PQExpBuffer getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo);
 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
 
 extern char *optarg;
@@ -108,10 +133,10 @@ extern int    optind,
 /* global decls */
 bool       g_verbose;          /* User wants verbose narration of our
                                 * activities. */
-Oid            g_last_builtin_oid; /* value of the last builtin oid */
 Archive    *g_fout;                /* the script file */
 PGconn    *g_conn;             /* the database connection */
 
+/* various user-settable parameters */
 bool       force_quotes;       /* User wants to suppress double-quotes */
 bool       dumpData;           /* dump data using proper insert strings */
 bool       attrNames;          /* put attr names into insert strings */
@@ -119,1022 +144,1067 @@ bool      schemaOnly;
 bool       dataOnly;
 bool       aclsSkip;
 
+/* obsolete as of 7.3: */
+static Oid g_last_builtin_oid; /* value of the last builtin oid */
+
+static char *selectTablename = NULL;   /* name of a single table to dump */
+
 char       g_opaque_type[10];  /* name for the opaque type */
 
 /* placeholders for the delimiters for comments */
 char       g_comment_start[10];
 char       g_comment_end[10];
 
+/* these are to avoid passing around info for findNamespace() */
+static NamespaceInfo *g_namespaces;
+static int g_numNamespaces;
 
-typedef struct _dumpContext
+
+int
+main(int argc, char **argv)
 {
+   int         c;
+   const char *filename = NULL;
+   const char *format = "p";
+   const char *dbname = NULL;
+   const char *pghost = NULL;
+   const char *pgport = NULL;
+   const char *username = NULL;
+   bool        oids = false;
    TableInfo  *tblinfo;
-   int         tblidx;
-   bool        oids;
-} DumpContext;
+   int         numTables;
+   bool        force_password = false;
+   int         compressLevel = -1;
+   bool        ignore_version = false;
+   int         plainText = 0;
+   int         outputClean = 0;
+   int         outputCreate = 0;
+   int         outputBlobs = 0;
+   int         outputNoOwner = 0;
+   int         outputNoReconnect = 0;
+   static int  use_setsessauth = 0;
+   static int  disable_triggers = 0;
+   char       *outputSuperuser = NULL;
 
-static void
-help(const char *progname)
-{
-   printf(gettext("%s dumps a database as a text file or to other formats.\n\n"), progname);
-   puts(gettext("Usage:"));
-   printf(gettext("  %s [options] dbname\n\n"), progname);
-   puts(gettext("Options:"));
+   RestoreOptions *ropt;
 
 #ifdef HAVE_GETOPT_LONG
-   puts(gettext(
-       "  -a, --data-only          dump only the data, not the schema\n"
-       "  -b, --blobs              include large objects in dump\n"
-       "  -c, --clean              clean (drop) schema prior to create\n"
-       "  -C, --create             include commands to create database in dump\n"
-       "  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"
-       "  -D, --column-inserts     dump data as INSERT commands with column names\n"
-       "  -f, --file=FILENAME      output file name\n"
-       "  -F, --format {c|t|p}     output file format (custom, tar, plain text)\n"
-       "  -h, --host=HOSTNAME      database server host name\n"
-       "  -i, --ignore-version     proceed even when server version mismatches\n"
-       "                           pg_dump version\n"
-       "  -n, --no-quotes          suppress most quotes around identifiers\n"
-       "  -N, --quotes             enable most quotes around identifiers\n"
-       "  -o, --oids               include oids in dump\n"
-       "  -O, --no-owner           do not output \\connect commands in plain\n"
-       "                           text format\n"
-       "  -p, --port=PORT          database server port number\n"
-       "  -R, --no-reconnect       disable ALL reconnections to the database in\n"
-       "                           plain text format\n"
-       "  -s, --schema-only        dump only the schema, no data\n"
-       "  -S, --superuser=NAME     specify the superuser user name to use in\n"
-       "                           plain text format\n"
-       "  -t, --table=TABLE        dump this table only (* for all)\n"
-       "  -U, --username=NAME      connect as specified database user\n"
-       "  -v, --verbose            verbose mode\n"
-       "  -W, --password           force password prompt (should happen automatically)\n"
-       "  -x, --no-privileges      do not dump privileges (grant/revoke)\n"
-       "  -X use-set-session-authorization, --use-set-session-authorization\n"
-       "                           output SET SESSION AUTHORIZATION commands rather\n"
-       "                           than \\connect commands\n"
-       "  -Z, --compress {0-9}     compression level for compressed formats\n"
-   ));
-#else
-   puts(gettext(
-       "  -a                       dump only the data, not the schema\n"
-       "  -b                       include large objects in dump\n"
-       "  -c                       clean (drop) schema prior to create\n"
-       "  -C                       include commands to create database in dump\n"
-       "  -d                       dump data as INSERT, rather than COPY, commands\n"
-       "  -D                       dump data as INSERT commands with column names\n"
-       "  -f FILENAME              output file name\n"
-       "  -F {c|t|p}               output file format (custom, tar, plain text)\n"
-       "  -h HOSTNAME              database server host name\n"
-       "  -i                       proceed even when server version mismatches\n"
-       "                           pg_dump version\n"
-       "  -n                       suppress most quotes around identifiers\n"
-       "  -N                       enable most quotes around identifiers\n"
-       "  -o                       include oids in dump\n"
-       "  -O                       do not output \\connect commands in plain\n"
-       "                           text format\n"
-       "  -p PORT                  database server port number\n"
-       "  -R                       disable ALL reconnections to the database in\n"
-       "                           plain text format\n"
-       "  -s                       dump only the schema, no data\n"
-       "  -S NAME                  specify the superuser user name to use in\n"
-       "                           plain text format\n"
-       "  -t TABLE                 dump this table only (* for all)\n"
-       "  -U NAME                  connect as specified database user\n"
-       "  -v                       verbose mode\n"
-       "  -W                       force password prompt (should happen automatically)\n"
-       "  -x                       do not dump privileges (grant/revoke)\n"
-       "  -X use-set-session-authorization\n"
-       "                           output SET SESSION AUTHORIZATION commands rather\n"
-       "                           than \\connect commands\n"
-       "  -Z {0-9}                 compression level for compressed formats\n"
-   ));
-#endif
-   puts(gettext("If no database name is not supplied, then the PGDATABASE environment\n"
-                "variable value is used.\n\n"
-                "Report bugs to ."));
-}
-
-
-void
-exit_nicely(void)
-{
-   PQfinish(g_conn);
-   if (g_verbose)
-       write_msg(NULL, "*** aborted because of error\n");
-   exit(1);
-}
-
+   static struct option long_options[] = {
+       {"data-only", no_argument, NULL, 'a'},
+       {"blobs", no_argument, NULL, 'b'},
+       {"clean", no_argument, NULL, 'c'},
+       {"create", no_argument, NULL, 'C'},
+       {"file", required_argument, NULL, 'f'},
+       {"format", required_argument, NULL, 'F'},
+       {"inserts", no_argument, NULL, 'd'},
+       {"attribute-inserts", no_argument, NULL, 'D'},
+       {"column-inserts", no_argument, NULL, 'D'},
+       {"host", required_argument, NULL, 'h'},
+       {"ignore-version", no_argument, NULL, 'i'},
+       {"no-reconnect", no_argument, NULL, 'R'},
+       {"no-quotes", no_argument, NULL, 'n'},
+       {"quotes", no_argument, NULL, 'N'},
+       {"oids", no_argument, NULL, 'o'},
+       {"no-owner", no_argument, NULL, 'O'},
+       {"port", required_argument, NULL, 'p'},
+       {"schema-only", no_argument, NULL, 's'},
+       {"superuser", required_argument, NULL, 'S'},
+       {"table", required_argument, NULL, 't'},
+       {"password", no_argument, NULL, 'W'},
+       {"username", required_argument, NULL, 'U'},
+       {"verbose", no_argument, NULL, 'v'},
+       {"no-privileges", no_argument, NULL, 'x'},
+       {"no-acl", no_argument, NULL, 'x'},
+       {"compress", required_argument, NULL, 'Z'},
+       {"help", no_argument, NULL, '?'},
+       {"version", no_argument, NULL, 'V'},
 
-#define COPYBUFSIZ     8192
+       /*
+        * the following options don't have an equivalent short option
+        * letter, but are available as '-X long-name'
+        */
+       {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+       {"disable-triggers", no_argument, &disable_triggers, 1},
 
-/*
- * Dump a table's contents for loading using the COPY command
- * - this routine is called by the Archiver when it wants the table
- *   to be dumped.
- */
+       {NULL, 0, NULL, 0}
+   };
+   int         optindex;
+#endif
 
-static int
-dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv)
-{
-   const DumpContext *dctx = (DumpContext *) dctxv;
-   const char *classname = dctx->tblinfo[dctx->tblidx].relname;
-   const bool  hasoids = dctx->tblinfo[dctx->tblidx].hasoids;
-   const bool  oids = dctx->oids;
+#ifdef ENABLE_NLS
+   setlocale(LC_ALL, "");
+   bindtextdomain("pg_dump", LOCALEDIR);
+   textdomain("pg_dump");
+#endif
 
-   PGresult   *res;
-   char        query[255];
-   int         ret;
-   bool        copydone;
-   char        copybuf[COPYBUFSIZ];
+   g_verbose = false;
+   force_quotes = true;
 
-   if (g_verbose)
-       write_msg(NULL, "dumping out the contents of table %s\n", classname);
+   strcpy(g_comment_start, "-- ");
+   g_comment_end[0] = '\0';
+   strcpy(g_opaque_type, "opaque");
 
-   if (oids && hasoids)
-   {
-       /*
-        * archprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
-        * fmtId(classname, force_quotes));
-        *
-        * - Not used as of V1.3 (needs to be in ArchiveEntry call)
-        *
-        */
+   dataOnly = schemaOnly = dumpData = attrNames = false;
 
-       sprintf(query, "COPY %s WITH OIDS TO stdout;",
-               fmtId(classname, force_quotes));
-   }
+   if (!strrchr(argv[0], '/'))
+       progname = argv[0];
    else
-   {
-       /*
-        * archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname,
-        * force_quotes));
-        *
-        * - Not used as of V1.3 (needs to be in ArchiveEntry call)
-        *
-        */
+       progname = strrchr(argv[0], '/') + 1;
 
-       sprintf(query, "COPY %s TO stdout;", fmtId(classname, force_quotes));
-   }
-   res = PQexec(g_conn, query);
-   if (!res ||
-       PQresultStatus(res) == PGRES_FATAL_ERROR)
+   /* Set default options based on progname */
+   if (strcmp(progname, "pg_backup") == 0)
    {
-       write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed\n",
-                 classname);
-       write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
-       write_msg(NULL, "The command was: %s\n", query);
-       exit_nicely();
+       format = "c";
+       outputBlobs = true;
    }
-   else
+
+   if (argc > 1)
    {
-       if (PQresultStatus(res) != PGRES_COPY_OUT)
-       {
-           write_msg(NULL, "SQL command to dump the contents of table \"%s\" executed abnormally.\n",
-                     classname);
-           write_msg(NULL, "The server returned status %d when %d was expected.\n",
-                     PQresultStatus(res), PGRES_COPY_OUT);
-           write_msg(NULL, "The command was: %s\n", query);
-           exit_nicely();
-       }
-       else
+       if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
        {
-           copydone = false;
-
-           while (!copydone)
-           {
-               ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
-
-               if (copybuf[0] == '\\' &&
-                   copybuf[1] == '.' &&
-                   copybuf[2] == '\0')
-               {
-                   copydone = true;    /* don't print this... */
-               }
-               else
-               {
-                   archputs(copybuf, fout);
-                   switch (ret)
-                   {
-                       case EOF:
-                           copydone = true;
-                           /* FALLTHROUGH */
-                       case 0:
-                           archputc('\n', fout);
-                           break;
-                       case 1:
-                           break;
-                   }
-               }
-
-               /*
-                * THROTTLE:
-                *
-                * There was considerable discussion in late July, 2000
-                * regarding slowing down pg_dump when backing up large
-                * tables. Users with both slow & fast (muti-processor)
-                * machines experienced performance degradation when doing
-                * a backup.
-                *
-                * Initial attempts based on sleeping for a number of ms for
-                * each ms of work were deemed too complex, then a simple
-                * 'sleep in each loop' implementation was suggested. The
-                * latter failed because the loop was too tight. Finally,
-                * the following was implemented:
-                *
-                * If throttle is non-zero, then See how long since the last
-                * sleep. Work out how long to sleep (based on ratio). If
-                * sleep is more than 100ms, then sleep reset timer EndIf
-                * EndIf
-                *
-                * where the throttle value was the number of ms to sleep per
-                * ms of work. The calculation was done in each loop.
-                *
-                * Most of the hard work is done in the backend, and this
-                * solution still did not work particularly well: on slow
-                * machines, the ratio was 50:1, and on medium paced
-                * machines, 1:1, and on fast multi-processor machines, it
-                * had little or no effect, for reasons that were unclear.
-                *
-                * Further discussion ensued, and the proposal was dropped.
-                *
-                * For those people who want this feature, it can be
-                * implemented using gettimeofday in each loop,
-                * calculating the time since last sleep, multiplying that
-                * by the sleep ratio, then if the result is more than a
-                * preset 'minimum sleep time' (say 100ms), call the
-                * 'select' function to sleep for a subsecond period ie.
-                *
-                * select(0, NULL, NULL, NULL, &tvi);
-                *
-                * This will return after the interval specified in the
-                * structure tvi. Fianally, call gettimeofday again to
-                * save the 'last sleep time'.
-                */
-           }
-           archprintf(fout, "\\.\n");
+           help(progname);
+           exit(0);
        }
-       ret = PQendcopy(g_conn);
-       if (ret != 0)
+       if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
        {
-           write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed: PQendcopy() failed.\n", classname);
-           write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
-           write_msg(NULL, "The command was: %s\n", query);
-           PQclear(res);
-           exit_nicely();
+           puts("pg_dump (PostgreSQL) " PG_VERSION);
+           exit(0);
        }
    }
 
-   return 1;
-}
+#ifdef HAVE_GETOPT_LONG
+   while ((c = getopt_long(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V?", long_options, &optindex)) != -1)
+#else
+   while ((c = getopt(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V?-")) != -1)
+#endif
 
-static int
-dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
-{
-   const DumpContext *dctx = (DumpContext *) dctxv;
-   const char *classname = dctx->tblinfo[dctx->tblidx].relname;
+   {
+       switch (c)
+       {
+           case 'a':           /* Dump data only */
+               dataOnly = true;
+               break;
 
-   PGresult   *res;
-   PQExpBuffer q = createPQExpBuffer();
-   int         tuple;
-   int         field;
+           case 'b':           /* Dump blobs */
+               outputBlobs = true;
+               break;
 
-   if (fout->remoteVersion >= 70100)
-       appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM ONLY %s", fmtId(classname, force_quotes));
-   else
-       appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM %s", fmtId(classname, force_quotes));
+           case 'c':           /* clean (i.e., drop) schema prior to
+                                * create */
+               outputClean = 1;
+               break;
 
-   res = PQexec(g_conn, q->data);
-   if (!res ||
-       PQresultStatus(res) != PGRES_COMMAND_OK)
-   {
-       write_msg(NULL, "dumpClasses(): SQL command failed\n");
-       write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
-       write_msg(NULL, "The command was: %s\n", q->data);
-       exit_nicely();
-   }
+           case 'C':           /* Create DB */
 
-   do
-   {
-       PQclear(res);
+               outputCreate = 1;
+               break;
 
-       res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
-       if (!res ||
-           PQresultStatus(res) != PGRES_TUPLES_OK)
-       {
-           write_msg(NULL, "dumpClasses(): SQL command failed\n");
-           write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
-           write_msg(NULL, "The command was: FETCH 100 FROM _pg_dump_cursor\n");
-           exit_nicely();
-       }
+           case 'd':           /* dump data as proper insert strings */
+               dumpData = true;
+               break;
 
-       for (tuple = 0; tuple < PQntuples(res); tuple++)
-       {
-           archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
-           if (attrNames == true)
-           {
-               resetPQExpBuffer(q);
-               appendPQExpBuffer(q, "(");
-               for (field = 0; field < PQnfields(res); field++)
-               {
-                   if (field > 0)
-                       appendPQExpBuffer(q, ",");
-                   appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
-               }
-               appendPQExpBuffer(q, ") ");
-               archprintf(fout, "%s", q->data);
-           }
-           archprintf(fout, "VALUES (");
-           for (field = 0; field < PQnfields(res); field++)
-           {
-               if (field > 0)
-                   archprintf(fout, ",");
-               if (PQgetisnull(res, tuple, field))
-               {
-                   archprintf(fout, "NULL");
-                   continue;
-               }
-               switch (PQftype(res, field))
-               {
-                   case INT2OID:
-                   case INT4OID:
-                   case OIDOID:        /* int types */
-                   case FLOAT4OID:
-                   case FLOAT8OID:     /* float types */
-                       /* These types are printed without quotes */
-                       archprintf(fout, "%s",
-                                  PQgetvalue(res, tuple, field));
-                       break;
-                   case BITOID:
-                   case VARBITOID:
-                       archprintf(fout, "B'%s'",
-                                  PQgetvalue(res, tuple, field));
-                       break;
-                   default:
+           case 'D':           /* dump data as proper insert strings with
+                                * attr names */
+               dumpData = true;
+               attrNames = true;
+               break;
 
-                       /*
-                        * All other types are printed as string literals,
-                        * with appropriate escaping of special
-                        * characters.
-                        */
-                       resetPQExpBuffer(q);
-                       formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL);
-                       archprintf(fout, "%s", q->data);
-                       break;
-               }
-           }
-           archprintf(fout, ");\n");
-       }
+           case 'f':
+               filename = optarg;
+               break;
 
-   } while (PQntuples(res) > 0);
-   PQclear(res);
+           case 'F':
+               format = optarg;
+               break;
 
-   res = PQexec(g_conn, "CLOSE _pg_dump_cursor");
-   if (!res ||
-       PQresultStatus(res) != PGRES_COMMAND_OK)
-   {
-       write_msg(NULL, "dumpClasses(): SQL command failed\n");
-       write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
-       write_msg(NULL, "The command was: CLOSE _pg_dump_cursor\n");
-       exit_nicely();
-   }
-   PQclear(res);
+           case 'h':           /* server host */
+               pghost = optarg;
+               break;
 
-   destroyPQExpBuffer(q);
-   return 1;
-}
+           case 'i':           /* ignore database version mismatch */
+               ignore_version = true;
+               break;
 
-/*
- * Convert a string value to an SQL string literal,
- * with appropriate escaping of special characters.
- * Quote mark ' goes to '' per SQL standard, other
- * stuff goes to \ sequences.
- * The literal is appended to the given PQExpBuffer.
- */
-static void
-formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts)
-{
-   appendPQExpBufferChar(buf, '\'');
-   while (*str)
-   {
-       char        ch = *str++;
+           case 'n':           /* Do not force double-quotes on
+                                * identifiers */
+               force_quotes = false;
+               break;
 
-       if (ch == '\\' || ch == '\'')
-       {
-           appendPQExpBufferChar(buf, ch);     /* double these */
-           appendPQExpBufferChar(buf, ch);
-       }
-       else if ((unsigned char) ch < (unsigned char) ' ' &&
-                (opts == CONV_ALL
-                 || (ch != '\n' && ch != '\t')
-                 ))
-       {
-           /*
-            * generate octal escape for control chars other than
-            * whitespace
-            */
-           appendPQExpBufferChar(buf, '\\');
-           appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
-           appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
-           appendPQExpBufferChar(buf, (ch & 7) + '0');
-       }
-       else
-           appendPQExpBufferChar(buf, ch);
-   }
-   appendPQExpBufferChar(buf, '\'');
-}
+           case 'N':           /* Force double-quotes on identifiers */
+               force_quotes = true;
+               break;
 
-/*
- * DumpClasses -
- *   dump the contents of all the classes.
- */
-static void
-dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
-        const char *onlytable, const bool oids, const bool force_quotes)
-{
-   int         i;
-   DataDumperPtr dumpFn;
-   DumpContext *dumpCtx;
-   char        copyBuf[512];
-   char       *copyStmt;
+           case 'o':           /* Dump oids */
+               oids = true;
+               break;
 
-   if (g_verbose)
-   {
-       if (onlytable == NULL || (strlen(onlytable) == 0))
-           write_msg(NULL, "preparing to dump the contents of all %d tables/sequences\n", numTables);
-       else
-           write_msg(NULL, "preparing to dump the contents of only one table/sequence\n");
-   }
 
-   for (i = 0; i < numTables; i++)
-   {
-       const char *classname = tblinfo[i].relname;
+           case 'O':           /* Don't reconnect to match owner */
+               outputNoOwner = 1;
+               break;
 
-       /* Skip VIEW relations */
-       if (tblinfo[i].viewdef != NULL)
-           continue;
+           case 'p':           /* server port */
+               pgport = optarg;
+               break;
 
-       if (tblinfo[i].relkind == RELKIND_SEQUENCE)     /* already dumped */
-           continue;
+           case 'R':           /* No reconnect */
+               outputNoReconnect = 1;
+               break;
 
-       if (!onlytable || (strcmp(classname, onlytable) == 0) || (strlen(onlytable) == 0))
-       {
-           if (g_verbose)
-               write_msg(NULL, "preparing to dump the contents of table %s\n", classname);
+           case 's':           /* dump schema only */
+               schemaOnly = true;
+               break;
 
-#if 0
-           becomeUser(fout, tblinfo[i].usename);
-#endif
+           case 'S':           /* Username for superuser in plain text
+                                * output */
+               outputSuperuser = strdup(optarg);
+               break;
 
-           dumpCtx = (DumpContext *) malloc(sizeof(DumpContext));
-           dumpCtx->tblinfo = (TableInfo *) tblinfo;
-           dumpCtx->tblidx = i;
-           dumpCtx->oids = oids;
+           case 't':           /* Dump data for this table only */
+               {
+                   int         i;
 
-           if (!dumpData)
-           {
-               /* Dump/restore using COPY */
-               dumpFn = dumpClasses_nodumpData;
-               sprintf(copyBuf, "COPY %s %sFROM stdin;\n",
-                       fmtId(tblinfo[i].relname, force_quotes),
-                       (oids && tblinfo[i].hasoids) ? "WITH OIDS " : "");
-               copyStmt = copyBuf;
-           }
-           else
-           {
-               /* Restore using INSERT */
-               dumpFn = dumpClasses_dumpData;
-               copyStmt = NULL;
-           }
+                   selectTablename = strdup(optarg);
+
+                   /*
+                    * quoted string? Then strip quotes and preserve
+                    * case...
+                    */
+                   if (selectTablename[0] == '"')
+                   {
+                       char    *endptr;
+
+                       endptr = selectTablename + strlen(selectTablename) - 1;
+                       if (*endptr == '"')
+                           *endptr = '\0';
+                       strcpy(selectTablename, &selectTablename[1]);
+                   }
+                   else
+                   {
+                       /* otherwise, convert table name to lowercase... */
+                       for (i = 0; selectTablename[i]; i++)
+                           if (isupper((unsigned char) selectTablename[i]))
+                               selectTablename[i] = tolower((unsigned char) selectTablename[i]);
+
+                       /*
+                        * '*' is a special case meaning ALL tables, but
+                        * only if unquoted
+                        */
+                       if (strcmp(selectTablename, "*") == 0)
+                           selectTablename[0] = '\0';
+                   }
+               }
+               break;
+
+           case 'u':
+               force_password = true;
+               username = simple_prompt("User name: ", 100, true);
+               break;
+
+           case 'U':
+               username = optarg;
+               break;
+
+           case 'v':           /* verbose */
+               g_verbose = true;
+               break;
+
+           case 'W':
+               force_password = true;
+               break;
+
+           case 'x':           /* skip ACL dump */
+               aclsSkip = true;
+               break;
+
+               /*
+                * Option letters were getting scarce, so I invented this
+                * new scheme: '-X feature' turns on some feature. Compare
+                * to the -f option in GCC.  You should also add an
+                * equivalent GNU-style option --feature.  Features that
+                * require arguments should use '-X feature=foo'.
+                */
+           case 'X':
+               if (strcmp(optarg, "use-set-session-authorization") == 0)
+                   use_setsessauth = 1;
+               else if (strcmp(optarg, "disable-triggers") == 0)
+                   disable_triggers = 1;
+               else
+               {
+                   fprintf(stderr,
+                           gettext("%s: invalid -X option -- %s\n"),
+                           progname, optarg);
+                   fprintf(stderr, gettext("Try '%s --help' for more information.\n"), progname);
+                   exit(1);
+               }
+               break;
+           case 'Z':           /* Compression Level */
+               compressLevel = atoi(optarg);
+               break;
 
-           ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
-                        "TABLE DATA", NULL, "", "",
-                        copyStmt, tblinfo[i].usename,
-                        dumpFn, dumpCtx);
+#ifndef HAVE_GETOPT_LONG
+           case '-':
+               fprintf(stderr,
+                       gettext("%s was compiled without support for long options.\n"
+                        "Use --help for help on invocation options.\n"),
+                       progname);
+               exit(1);
+               break;
+#else
+               /* This covers the long options equivalent to -X xxx. */
+           case 0:
+               break;
+#endif
+           default:
+               fprintf(stderr, gettext("Try '%s --help' for more information.\n"), progname);
+               exit(1);
        }
    }
-}
 
+   if (optind < (argc - 1))
+   {
+       fprintf(stderr,
+           gettext("%s: too many command line options (first is '%s')\n"
+                   "Try '%s --help' for more information.\n"),
+               progname, argv[optind + 1], progname);
+       exit(1);
+   }
 
+   /* Get the target database name */
+   if (optind < argc)
+       dbname = argv[optind];
+   else
+       dbname = getenv("PGDATABASE");
+   if (!dbname)
+   {
+       write_msg(NULL, "no database name specified\n");
+       exit(1);
+   }
 
-static int
-parse_version(const char *versionString)
-{
-   int         cnt;
-   int         vmaj,
-               vmin,
-               vrev;
+   if (dataOnly && schemaOnly)
+   {
+       write_msg(NULL, "The options \"schema only\" (-s) and \"data only\" (-a) cannot be used together.\n");
+       exit(1);
+   }
 
-   cnt = sscanf(versionString, "%d.%d.%d", &vmaj, &vmin, &vrev);
+   if (outputBlobs && selectTablename != NULL && strlen(selectTablename) > 0)
+   {
+       write_msg(NULL, "Large object output is not supported for a single table.\n");
+       write_msg(NULL, "Use all tables or a full dump instead.\n");
+       exit(1);
+   }
 
-   if (cnt < 2)
+   if (dumpData == true && oids == true)
    {
-       write_msg(NULL, "unable to parse version string \"%s\"\n", versionString);
+       write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together.\n");
+       write_msg(NULL, "(The INSERT command cannot set oids.)\n");
        exit(1);
    }
 
-   if (cnt == 2)
-       vrev = 0;
+   if (outputBlobs == true && (format[0] == 'p' || format[0] == 'P'))
+   {
+       write_msg(NULL, "large object output is not supported for plain text dump files.\n");
+       write_msg(NULL, "(Use a different output format.)\n");
+       exit(1);
+   }
 
-   return (100 * vmaj + vmin) * 100 + vrev;
-}
+   /* open the output file */
+   switch (format[0])
+   {
 
+       case 'c':
+       case 'C':
+           g_fout = CreateArchive(filename, archCustom, compressLevel);
+           break;
 
+       case 'f':
+       case 'F':
+           g_fout = CreateArchive(filename, archFiles, compressLevel);
+           break;
 
-int
-main(int argc, char **argv)
-{
-   int         c;
-   const char *filename = NULL;
-   const char *format = "p";
-   const char *dbname = NULL;
-   const char *pghost = NULL;
-   const char *pgport = NULL;
-   const char *username = NULL;
-   char       *tablename = NULL;
-   bool        oids = false;
-   TableInfo  *tblinfo;
-   int         numTables;
-   bool        force_password = false;
-   int         compressLevel = -1;
-   bool        ignore_version = false;
-   int         plainText = 0;
-   int         outputClean = 0;
-   int         outputCreate = 0;
-   int         outputBlobs = 0;
-   int         outputNoOwner = 0;
-   int         outputNoReconnect = 0;
-   static int  use_setsessauth = 0;
-   char       *outputSuperuser = NULL;
+       case 'p':
+       case 'P':
+           plainText = 1;
+           g_fout = CreateArchive(filename, archNull, 0);
+           break;
 
-   RestoreOptions *ropt;
+       case 't':
+       case 'T':
+           g_fout = CreateArchive(filename, archTar, compressLevel);
+           break;
 
-#ifdef HAVE_GETOPT_LONG
-   static struct option long_options[] = {
-       {"data-only", no_argument, NULL, 'a'},
-       {"blobs", no_argument, NULL, 'b'},
-       {"clean", no_argument, NULL, 'c'},
-       {"create", no_argument, NULL, 'C'},
-       {"file", required_argument, NULL, 'f'},
-       {"format", required_argument, NULL, 'F'},
-       {"inserts", no_argument, NULL, 'd'},
-       {"attribute-inserts", no_argument, NULL, 'D'},
-       {"column-inserts", no_argument, NULL, 'D'},
-       {"host", required_argument, NULL, 'h'},
-       {"ignore-version", no_argument, NULL, 'i'},
-       {"no-reconnect", no_argument, NULL, 'R'},
-       {"no-quotes", no_argument, NULL, 'n'},
-       {"quotes", no_argument, NULL, 'N'},
-       {"oids", no_argument, NULL, 'o'},
-       {"no-owner", no_argument, NULL, 'O'},
-       {"port", required_argument, NULL, 'p'},
-       {"schema-only", no_argument, NULL, 's'},
-       {"superuser", required_argument, NULL, 'S'},
-       {"table", required_argument, NULL, 't'},
-       {"password", no_argument, NULL, 'W'},
-       {"username", required_argument, NULL, 'U'},
-       {"verbose", no_argument, NULL, 'v'},
-       {"no-privileges", no_argument, NULL, 'x'},
-       {"no-acl", no_argument, NULL, 'x'},
-       {"compress", required_argument, NULL, 'Z'},
-       {"help", no_argument, NULL, '?'},
-       {"version", no_argument, NULL, 'V'},
+       default:
+           write_msg(NULL, "invalid output format '%s' specified\n", format);
+           exit(1);
+   }
 
-       /*
-        * the following options don't have an equivalent short option
-        * letter, but are available as '-X long-name'
-        */
-       {"use-set-session-authorization", no_argument, &use_setsessauth, 1}
-   };
-   int         optindex;
-#endif
+   if (g_fout == NULL)
+   {
+       write_msg(NULL, "could not open output file %s for writing\n", filename);
+       exit(1);
+   }
 
-#ifdef ENABLE_NLS
-   setlocale(LC_ALL, "");
-   bindtextdomain("pg_dump", LOCALEDIR);
-   textdomain("pg_dump");
-#endif
+   /* Let the archiver know how noisy to be */
+   g_fout->verbose = g_verbose;
 
-   g_verbose = false;
-   force_quotes = true;
+   /*
+    * Open the database using the Archiver, so it knows about it. Errors
+    * mean death.
+    */
+   g_fout->minRemoteVersion = 70000;   /* we can handle back to 7.0 */
+   g_fout->maxRemoteVersion = parse_version(PG_VERSION);
+   g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, username, force_password, ignore_version);
 
-   strcpy(g_comment_start, "-- ");
-   g_comment_end[0] = '\0';
-   strcpy(g_opaque_type, "opaque");
+   /*
+    * Start serializable transaction to dump consistent data
+    */
+   {
+       PGresult   *res;
 
-   dataOnly = schemaOnly = dumpData = attrNames = false;
+       res = PQexec(g_conn, "begin");
+       if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
+           exit_horribly(g_fout, NULL, "BEGIN command failed: %s",
+                         PQerrorMessage(g_conn));
 
-   if (!strrchr(argv[0], '/'))
-       progname = argv[0];
-   else
-       progname = strrchr(argv[0], '/') + 1;
+       PQclear(res);
+       res = PQexec(g_conn, "set transaction isolation level serializable");
+       if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
+           exit_horribly(g_fout, NULL, "could not set transaction isolation level to serializable: %s",
+                         PQerrorMessage(g_conn));
 
-   /* Set default options based on progname */
-   if (strcmp(progname, "pg_backup") == 0)
-   {
-       format = "c";
-       outputBlobs = true;
+       PQclear(res);
    }
 
-   if (argc > 1)
+   if (g_fout->remoteVersion < 70300)
    {
-       if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
-       {
-           help(progname);
-           exit(0);
-       }
-       if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
-       {
-           puts("pg_dump (PostgreSQL) " PG_VERSION);
-           exit(0);
-       }
+       if (g_fout->remoteVersion >= 70100)
+           g_last_builtin_oid = findLastBuiltinOid_V71(dbname);
+       else
+           g_last_builtin_oid = findLastBuiltinOid_V70();
+       if (g_verbose)
+           write_msg(NULL, "last built-in oid is %u\n", g_last_builtin_oid);
    }
 
-#ifdef HAVE_GETOPT_LONG
-   while ((c = getopt_long(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V?", long_options, &optindex)) != -1)
-#else
-   while ((c = getopt(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V?-")) != -1)
-#endif
-
-   {
-       switch (c)
-       {
-           case 'a':           /* Dump data only */
-               dataOnly = true;
-               break;
-
-           case 'b':           /* Dump blobs */
-               outputBlobs = true;
-               break;
-
-           case 'c':           /* clean (i.e., drop) schema prior to
-                                * create */
-               outputClean = 1;
-               break;
+   /* Dump the database definition */
+   if (!dataOnly)
+       dumpDatabase(g_fout);
 
-           case 'C':           /* Create DB */
+   if (oids == true)
+       setMaxOid(g_fout);
 
-               outputCreate = 1;
-               break;
+   tblinfo = dumpSchema(g_fout, &numTables, aclsSkip, schemaOnly, dataOnly);
 
-           case 'd':           /* dump data as proper insert strings */
-               dumpData = true;
-               break;
+   if (!schemaOnly)
+       dumpClasses(tblinfo, numTables, g_fout, oids);
 
-           case 'D':           /* dump data as proper insert strings with
-                                * attr names */
-               dumpData = true;
-               attrNames = true;
-               break;
+   if (outputBlobs)
+       ArchiveEntry(g_fout, "0", "BLOBS", NULL, "",
+                    "BLOBS", NULL, "", "", NULL, dumpBlobs, NULL);
 
-           case 'f':
-               filename = optarg;
-               break;
+   if (!dataOnly)              /* dump indexes and triggers at the end
+                                * for performance */
+   {
+       dumpTriggers(g_fout, tblinfo, numTables);
+       dumpRules(g_fout, tblinfo, numTables);
+   }
 
-           case 'F':
-               format = optarg;
-               break;
+   /* Now sort the output nicely */
+   SortTocByOID(g_fout);
+   MoveToStart(g_fout, "SCHEMA");
+   MoveToStart(g_fout, "DATABASE");
+   MoveToEnd(g_fout, "TABLE DATA");
+   MoveToEnd(g_fout, "BLOBS");
+   MoveToEnd(g_fout, "INDEX");
+   MoveToEnd(g_fout, "CONSTRAINT");
+   MoveToEnd(g_fout, "TRIGGER");
+   MoveToEnd(g_fout, "RULE");
+   MoveToEnd(g_fout, "SEQUENCE SET");
 
-           case 'h':           /* server host */
-               pghost = optarg;
-               break;
+   /*
+    * Moving all comments to end is annoying, but must do it for comments
+    * on stuff we just moved, and we don't seem to have quite enough
+    * dependency structure to get it really right...
+    */
+   MoveToEnd(g_fout, "COMMENT");
 
-           case 'i':           /* ignore database version mismatch */
-               ignore_version = true;
-               break;
+   if (plainText)
+   {
+       ropt = NewRestoreOptions();
+       ropt->filename = (char *) filename;
+       ropt->dropSchema = outputClean;
+       ropt->aclsSkip = aclsSkip;
+       ropt->superuser = outputSuperuser;
+       ropt->create = outputCreate;
+       ropt->noOwner = outputNoOwner;
+       ropt->noReconnect = outputNoReconnect;
+       ropt->use_setsessauth = use_setsessauth;
+       ropt->disable_triggers = disable_triggers;
 
-           case 'n':           /* Do not force double-quotes on
-                                * identifiers */
-               force_quotes = false;
-               break;
+       if (compressLevel == -1)
+           ropt->compression = 0;
+       else
+           ropt->compression = compressLevel;
 
-           case 'N':           /* Force double-quotes on identifiers */
-               force_quotes = true;
-               break;
+       ropt->suppressDumpWarnings = true;      /* We've already shown
+                                                * them */
 
-           case 'o':           /* Dump oids */
-               oids = true;
-               break;
+       RestoreArchive(g_fout, ropt);
+   }
 
+   CloseArchive(g_fout);
 
-           case 'O':           /* Don't reconnect to match owner */
-               outputNoOwner = 1;
-               break;
+   PQfinish(g_conn);
+   exit(0);
+}
 
-           case 'p':           /* server port */
-               pgport = optarg;
-               break;
 
-           case 'R':           /* No reconnect */
-               outputNoReconnect = 1;
-               break;
+static void
+help(const char *progname)
+{
+   printf(gettext("%s dumps a database as a text file or to other formats.\n\n"), progname);
+   puts(gettext("Usage:"));
+   printf(gettext("  %s [options] dbname\n\n"), progname);
+   puts(gettext("Options:"));
 
-           case 's':           /* dump schema only */
-               schemaOnly = true;
-               break;
+#ifdef HAVE_GETOPT_LONG
+   puts(gettext(
+       "  -a, --data-only          dump only the data, not the schema\n"
+       "  -b, --blobs              include large objects in dump\n"
+       "  -c, --clean              clean (drop) schema prior to create\n"
+       "  -C, --create             include commands to create database in dump\n"
+       "  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"
+       "  -D, --column-inserts     dump data as INSERT commands with column names\n"
+       "  -f, --file=FILENAME      output file name\n"
+       "  -F, --format {c|t|p}     output file format (custom, tar, plain text)\n"
+       "  -h, --host=HOSTNAME      database server host name\n"
+       "  -i, --ignore-version     proceed even when server version mismatches\n"
+       "                           pg_dump version\n"
+       "  -n, --no-quotes          suppress most quotes around identifiers\n"
+       "  -N, --quotes             enable most quotes around identifiers\n"
+       "  -o, --oids               include oids in dump\n"
+       "  -O, --no-owner           do not output \\connect commands in plain\n"
+       "                           text format\n"
+       "  -p, --port=PORT          database server port number\n"
+       "  -R, --no-reconnect       disable ALL reconnections to the database in\n"
+       "                           plain text format\n"
+       "  -s, --schema-only        dump only the schema, no data\n"
+       "  -S, --superuser=NAME     specify the superuser user name to use in\n"
+       "                           plain text format\n"
+       "  -t, --table=TABLE        dump this table only (* for all)\n"
+       "  -U, --username=NAME      connect as specified database user\n"
+       "  -v, --verbose            verbose mode\n"
+       "  -W, --password           force password prompt (should happen automatically)\n"
+       "  -x, --no-privileges      do not dump privileges (grant/revoke)\n"
+       "  -X use-set-session-authorization, --use-set-session-authorization\n"
+       "                           output SET SESSION AUTHORIZATION commands rather\n"
+       "                           than \\connect commands\n"
+       "  -X disable-triggers, --disable-triggers\n"
+       "                           disable triggers during data-only restore\n"
+       "  -Z, --compress {0-9}     compression level for compressed formats\n"
+   ));
+#else
+   puts(gettext(
+       "  -a                       dump only the data, not the schema\n"
+       "  -b                       include large objects in dump\n"
+       "  -c                       clean (drop) schema prior to create\n"
+       "  -C                       include commands to create database in dump\n"
+       "  -d                       dump data as INSERT, rather than COPY, commands\n"
+       "  -D                       dump data as INSERT commands with column names\n"
+       "  -f FILENAME              output file name\n"
+       "  -F {c|t|p}               output file format (custom, tar, plain text)\n"
+       "  -h HOSTNAME              database server host name\n"
+       "  -i                       proceed even when server version mismatches\n"
+       "                           pg_dump version\n"
+       "  -n                       suppress most quotes around identifiers\n"
+       "  -N                       enable most quotes around identifiers\n"
+       "  -o                       include oids in dump\n"
+       "  -O                       do not output \\connect commands in plain\n"
+       "                           text format\n"
+       "  -p PORT                  database server port number\n"
+       "  -R                       disable ALL reconnections to the database in\n"
+       "                           plain text format\n"
+       "  -s                       dump only the schema, no data\n"
+       "  -S NAME                  specify the superuser user name to use in\n"
+       "                           plain text format\n"
+       "  -t TABLE                 dump this table only (* for all)\n"
+       "  -U NAME                  connect as specified database user\n"
+       "  -v                       verbose mode\n"
+       "  -W                       force password prompt (should happen automatically)\n"
+       "  -x                       do not dump privileges (grant/revoke)\n"
+       "  -X use-set-session-authorization\n"
+       "                           output SET SESSION AUTHORIZATION commands rather\n"
+       "                           than \\connect commands\n"
+       "  -X disable-triggers      disable triggers during data-only restore\n"
+       "  -Z {0-9}                 compression level for compressed formats\n"
+   ));
+#endif
+   puts(gettext("If no database name is not supplied, then the PGDATABASE environment\n"
+                "variable value is used.\n\n"
+                "Report bugs to ."));
+}
 
-           case 'S':           /* Username for superuser in plain text
-                                * output */
-               outputSuperuser = strdup(optarg);
-               break;
+static int
+parse_version(const char *versionString)
+{
+   int         cnt;
+   int         vmaj,
+               vmin,
+               vrev;
 
-           case 't':           /* Dump data for this table only */
-               {
-                   int         i;
+   cnt = sscanf(versionString, "%d.%d.%d", &vmaj, &vmin, &vrev);
 
-                   tablename = strdup(optarg);
+   if (cnt < 2)
+   {
+       write_msg(NULL, "unable to parse version string \"%s\"\n", versionString);
+       exit(1);
+   }
 
-                   /*
-                    * quoted string? Then strip quotes and preserve
-                    * case...
-                    */
-                   if (tablename[0] == '"')
-                   {
-                       strcpy(tablename, &tablename[1]);
-                       if (*(tablename + strlen(tablename) - 1) == '"')
-                           *(tablename + strlen(tablename) - 1) = '\0';
-                   }
-                   /* otherwise, convert table name to lowercase... */
-                   else
-                   {
-                       for (i = 0; tablename[i]; i++)
-                           if (isupper((unsigned char) tablename[i]))
-                               tablename[i] = tolower((unsigned char) tablename[i]);
+   if (cnt == 2)
+       vrev = 0;
 
-                       /*
-                        * '*' is a special case meaning ALL tables, but
-                        * only if unquoted
-                        */
-                       if (strcmp(tablename, "*") == 0)
-                           tablename[0] = '\0';
+   return (100 * vmaj + vmin) * 100 + vrev;
+}
 
-                   }
-               }
-               break;
+void
+exit_nicely(void)
+{
+   PQfinish(g_conn);
+   if (g_verbose)
+       write_msg(NULL, "*** aborted because of error\n");
+   exit(1);
+}
 
-           case 'u':
-               force_password = true;
-               username = simple_prompt("User name: ", 100, true);
-               break;
+/*
+ * selectDumpableNamespace: policy-setting subroutine
+ *     Mark a namespace as to be dumped or not
+ */
+static void
+selectDumpableNamespace(NamespaceInfo *nsinfo)
+{
+   /*
+    * If a specific table is being dumped, do not dump any complete
+    * namespaces.  Otherwise, dump all non-system namespaces.
+    */
+   if (selectTablename != NULL)
+       nsinfo->dump = false;
+   else if (strncmp(nsinfo->nspname, "pg_", 3) == 0)
+       nsinfo->dump = false;
+   else
+       nsinfo->dump = true;
+}
 
-           case 'U':
-               username = optarg;
-               break;
+/*
+ * selectDumpableTable: policy-setting subroutine
+ *     Mark a table as to be dumped or not
+ */
+static void
+selectDumpableTable(TableInfo *tbinfo)
+{
+   /*
+    * Always dump if dumping parent namespace; else, if a particular
+    * tablename has been specified, dump matching table name; else,
+    * do not dump.
+    */
+   if (tbinfo->relnamespace->dump)
+       tbinfo->dump = true;
+   else if (selectTablename != NULL)
+       tbinfo->dump = (strcmp(tbinfo->relname, selectTablename) == 0);
+   else
+       tbinfo->dump = false;
+}
 
-           case 'v':           /* verbose */
-               g_verbose = true;
-               break;
+/*
+ * Dump a table's contents for loading using the COPY command
+ * - this routine is called by the Archiver when it wants the table
+ *   to be dumped.
+ */
 
-           case 'W':
-               force_password = true;
-               break;
+#define COPYBUFSIZ     8192
 
-           case 'x':           /* skip ACL dump */
-               aclsSkip = true;
-               break;
+static int
+dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv)
+{
+   const DumpContext *dctx = (DumpContext *) dctxv;
+   TableInfo  *tbinfo = &dctx->tblinfo[dctx->tblidx];
+   const char *classname = tbinfo->relname;
+   const bool  hasoids = tbinfo->hasoids;
+   const bool  oids = dctx->oids;
+   PQExpBuffer q = createPQExpBuffer();
+   PGresult   *res;
+   int         ret;
+   bool        copydone;
+   char        copybuf[COPYBUFSIZ];
 
-               /*
-                * Option letters were getting scarce, so I invented this
-                * new scheme: '-X feature' turns on some feature. Compare
-                * to the -f option in GCC.  You should also add an
-                * equivalent GNU-style option --feature.  Features that
-                * require arguments should use '-X feature=foo'.
-                */
-           case 'X':
-               if (strcmp(optarg, "use-set-session-authorization") == 0)
-                   use_setsessauth = 1;
-               else
-               {
-                   fprintf(stderr,
-                           gettext("%s: invalid -X option -- %s\n"),
-                           progname, optarg);
-                   fprintf(stderr, gettext("Try '%s --help' for more information.\n"), progname);
-                   exit(1);
-               }
-               break;
-           case 'Z':           /* Compression Level */
-               compressLevel = atoi(optarg);
-               break;
+   if (g_verbose)
+       write_msg(NULL, "dumping out the contents of table %s\n", classname);
 
-#ifndef HAVE_GETOPT_LONG
-           case '-':
-               fprintf(stderr,
-                       gettext("%s was compiled without support for long options.\n"
-                        "Use --help for help on invocation options.\n"),
-                       progname);
-               exit(1);
-               break;
-#else
-               /* This covers the long options equivalent to -X xxx. */
-           case 0:
-               break;
-#endif
-           default:
-               fprintf(stderr, gettext("Try '%s --help' for more information.\n"), progname);
-               exit(1);
-       }
-   }
+   /*
+    * Make sure we are in proper schema.  We will qualify the table name
+    * below anyway (in case its name conflicts with a pg_catalog table);
+    * but this ensures reproducible results in case the table contains
+    * regproc, regclass, etc columns.
+    */
+   selectSourceSchema(tbinfo->relnamespace->nspname);
 
-   if (optind < (argc - 1))
+   if (oids && hasoids)
    {
-       fprintf(stderr,
-           gettext("%s: too many command line options (first is '%s')\n"
-                   "Try '%s --help' for more information.\n"),
-               progname, argv[optind + 1], progname);
-       exit(1);
+       appendPQExpBuffer(q, "COPY %s WITH OIDS TO stdout;",
+                         fmtQualifiedId(tbinfo->relnamespace->nspname,
+                                        classname));
    }
-
-   /* Get the target database name */
-   if (optind < argc)
-       dbname = argv[optind];
    else
-       dbname = getenv("PGDATABASE");
-   if (!dbname)
-   {
-       write_msg(NULL, "no database name specified\n");
-       exit(1);
-   }
-
-   if (dataOnly && schemaOnly)
    {
-       write_msg(NULL, "The options \"schema only\" (-s) and \"data only\" (-a) cannot be used together.\n");
-       exit(1);
+       appendPQExpBuffer(q, "COPY %s TO stdout;",
+                         fmtQualifiedId(tbinfo->relnamespace->nspname,
+                                        classname));
    }
-
-   if (outputBlobs && tablename != NULL && strlen(tablename) > 0)
+   res = PQexec(g_conn, q->data);
+   if (!res ||
+       PQresultStatus(res) == PGRES_FATAL_ERROR)
    {
-       write_msg(NULL, "Large object output is not supported for a single table.\n");
-       write_msg(NULL, "Use all tables or a full dump instead.\n");
-       exit(1);
+       write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed\n",
+                 classname);
+       write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
+       write_msg(NULL, "The command was: %s\n", q->data);
+       exit_nicely();
    }
-
-   if (dumpData == true && oids == true)
+   if (PQresultStatus(res) != PGRES_COPY_OUT)
    {
-       write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together.\n");
-       write_msg(NULL, "(The INSERT command cannot set oids.)\n");
-       exit(1);
+       write_msg(NULL, "SQL command to dump the contents of table \"%s\" executed abnormally.\n",
+                 classname);
+       write_msg(NULL, "The server returned status %d when %d was expected.\n",
+                 PQresultStatus(res), PGRES_COPY_OUT);
+       write_msg(NULL, "The command was: %s\n", q->data);
+       exit_nicely();
    }
 
-   if (outputBlobs == true && (format[0] == 'p' || format[0] == 'P'))
-   {
-       write_msg(NULL, "large object output is not supported for plain text dump files.\n");
-       write_msg(NULL, "(Use a different output format.)\n");
-       exit(1);
-   }
+   copydone = false;
 
-   /* open the output file */
-   switch (format[0])
+   while (!copydone)
    {
+       ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
 
-       case 'c':
-       case 'C':
-           g_fout = CreateArchive(filename, archCustom, compressLevel);
-           break;
-
-       case 'f':
-       case 'F':
-           g_fout = CreateArchive(filename, archFiles, compressLevel);
-           break;
-
-       case 'p':
-       case 'P':
-           plainText = 1;
-           g_fout = CreateArchive(filename, archNull, 0);
-           break;
-
-       case 't':
-       case 'T':
-           g_fout = CreateArchive(filename, archTar, compressLevel);
-           break;
+       if (copybuf[0] == '\\' &&
+           copybuf[1] == '.' &&
+           copybuf[2] == '\0')
+       {
+           copydone = true;    /* don't print this... */
+       }
+       else
+       {
+           archputs(copybuf, fout);
+           switch (ret)
+           {
+               case EOF:
+                   copydone = true;
+                   /* FALLTHROUGH */
+               case 0:
+                   archputc('\n', fout);
+                   break;
+               case 1:
+                   break;
+           }
+       }
 
-       default:
-           write_msg(NULL, "invalid output format '%s' specified\n", format);
-           exit(1);
+       /*
+        * THROTTLE:
+        *
+        * There was considerable discussion in late July, 2000
+        * regarding slowing down pg_dump when backing up large
+        * tables. Users with both slow & fast (muti-processor)
+        * machines experienced performance degradation when doing
+        * a backup.
+        *
+        * Initial attempts based on sleeping for a number of ms for
+        * each ms of work were deemed too complex, then a simple
+        * 'sleep in each loop' implementation was suggested. The
+        * latter failed because the loop was too tight. Finally,
+        * the following was implemented:
+        *
+        * If throttle is non-zero, then See how long since the last
+        * sleep. Work out how long to sleep (based on ratio). If
+        * sleep is more than 100ms, then sleep reset timer EndIf
+        * EndIf
+        *
+        * where the throttle value was the number of ms to sleep per
+        * ms of work. The calculation was done in each loop.
+        *
+        * Most of the hard work is done in the backend, and this
+        * solution still did not work particularly well: on slow
+        * machines, the ratio was 50:1, and on medium paced
+        * machines, 1:1, and on fast multi-processor machines, it
+        * had little or no effect, for reasons that were unclear.
+        *
+        * Further discussion ensued, and the proposal was dropped.
+        *
+        * For those people who want this feature, it can be
+        * implemented using gettimeofday in each loop,
+        * calculating the time since last sleep, multiplying that
+        * by the sleep ratio, then if the result is more than a
+        * preset 'minimum sleep time' (say 100ms), call the
+        * 'select' function to sleep for a subsecond period ie.
+        *
+        * select(0, NULL, NULL, NULL, &tvi);
+        *
+        * This will return after the interval specified in the
+        * structure tvi. Fianally, call gettimeofday again to
+        * save the 'last sleep time'.
+        */
    }
+   archprintf(fout, "\\.\n");
 
-   if (g_fout == NULL)
+   ret = PQendcopy(g_conn);
+   if (ret != 0)
    {
-       write_msg(NULL, "could not open output file %s for writing\n", filename);
-       exit(1);
+       write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed: PQendcopy() failed.\n", classname);
+       write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
+       write_msg(NULL, "The command was: %s\n", q->data);
+       PQclear(res);
+       exit_nicely();
    }
 
-   /* Let the archiver know how noisy to be */
-   g_fout->verbose = g_verbose;
+   destroyPQExpBuffer(q);
+   return 1;
+}
 
-   /*
-    * Open the database using the Archiver, so it knows about it. Errors
-    * mean death.
-    */
-   g_fout->minRemoteVersion = 70000;   /* we can handle back to 7.0 */
-   g_fout->maxRemoteVersion = parse_version(PG_VERSION);
-   g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, username, force_password, ignore_version);
+static int
+dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
+{
+   const DumpContext *dctx = (DumpContext *) dctxv;
+   TableInfo  *tbinfo = &dctx->tblinfo[dctx->tblidx];
+   const char *classname = tbinfo->relname;
+   PQExpBuffer q = createPQExpBuffer();
+   PGresult   *res;
+   int         tuple;
+   int         field;
 
    /*
-    * Start serializable transaction to dump consistent data
+    * Make sure we are in proper schema.  We will qualify the table name
+    * below anyway (in case its name conflicts with a pg_catalog table);
+    * but this ensures reproducible results in case the table contains
+    * regproc, regclass, etc columns.
     */
-   {
-       PGresult   *res;
-
-       res = PQexec(g_conn, "begin");
-       if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
-           exit_horribly(g_fout, NULL, "BEGIN command failed: %s",
-                         PQerrorMessage(g_conn));
-
-       PQclear(res);
-       res = PQexec(g_conn, "set transaction isolation level serializable");
-       if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
-           exit_horribly(g_fout, NULL, "could not set transaction isolation level to serializable: %s",
-                         PQerrorMessage(g_conn));
+   selectSourceSchema(tbinfo->relnamespace->nspname);
 
-       PQclear(res);
+   if (fout->remoteVersion >= 70100)
+   {
+       appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
+                         "SELECT * FROM ONLY %s",
+                         fmtQualifiedId(tbinfo->relnamespace->nspname,
+                                        classname));
    }
-
-   if (g_fout->remoteVersion >= 70100)
-       g_last_builtin_oid = findLastBuiltinOid_V71(dbname);
    else
-       g_last_builtin_oid = findLastBuiltinOid_V70();
+   {
+       appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
+                         "SELECT * FROM %s",
+                         fmtQualifiedId(tbinfo->relnamespace->nspname,
+                                        classname));
+   }
 
-   /* Dump the database definition */
-   if (!dataOnly)
-       dumpDatabase(g_fout);
+   res = PQexec(g_conn, q->data);
+   if (!res ||
+       PQresultStatus(res) != PGRES_COMMAND_OK)
+   {
+       write_msg(NULL, "dumpClasses(): SQL command failed\n");
+       write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
+       write_msg(NULL, "The command was: %s\n", q->data);
+       exit_nicely();
+   }
 
-   if (oids == true)
-       setMaxOid(g_fout);
+   do
+   {
+       PQclear(res);
 
-   if (g_verbose)
-       write_msg(NULL, "last built-in oid is %u\n", g_last_builtin_oid);
-   tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsSkip, oids, schemaOnly, dataOnly);
+       res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
+       if (!res ||
+           PQresultStatus(res) != PGRES_TUPLES_OK)
+       {
+           write_msg(NULL, "dumpClasses(): SQL command failed\n");
+           write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
+           write_msg(NULL, "The command was: FETCH 100 FROM _pg_dump_cursor\n");
+           exit_nicely();
+       }
+
+       for (tuple = 0; tuple < PQntuples(res); tuple++)
+       {
+           archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
+           if (attrNames == true)
+           {
+               resetPQExpBuffer(q);
+               appendPQExpBuffer(q, "(");
+               for (field = 0; field < PQnfields(res); field++)
+               {
+                   if (field > 0)
+                       appendPQExpBuffer(q, ",");
+                   appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
+               }
+               appendPQExpBuffer(q, ") ");
+               archprintf(fout, "%s", q->data);
+           }
+           archprintf(fout, "VALUES (");
+           for (field = 0; field < PQnfields(res); field++)
+           {
+               if (field > 0)
+                   archprintf(fout, ",");
+               if (PQgetisnull(res, tuple, field))
+               {
+                   archprintf(fout, "NULL");
+                   continue;
+               }
+               switch (PQftype(res, field))
+               {
+                   case INT2OID:
+                   case INT4OID:
+                   case OIDOID:        /* int types */
+                   case FLOAT4OID:
+                   case FLOAT8OID:     /* float types */
+                       /* These types are printed without quotes */
+                       archprintf(fout, "%s",
+                                  PQgetvalue(res, tuple, field));
+                       break;
+                   case BITOID:
+                   case VARBITOID:
+                       archprintf(fout, "B'%s'",
+                                  PQgetvalue(res, tuple, field));
+                       break;
+                   default:
 
-   if (!schemaOnly)
-       dumpClasses(tblinfo, numTables, g_fout, tablename, oids, force_quotes);
+                       /*
+                        * All other types are printed as string literals,
+                        * with appropriate escaping of special
+                        * characters.
+                        */
+                       resetPQExpBuffer(q);
+                       formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL);
+                       archprintf(fout, "%s", q->data);
+                       break;
+               }
+           }
+           archprintf(fout, ");\n");
+       }
 
-   if (outputBlobs)
-       ArchiveEntry(g_fout, "0", "BLOBS", "BLOBS", NULL, "", "", "", "", dumpBlobs, 0);
+   } while (PQntuples(res) > 0);
+   PQclear(res);
 
-   if (!dataOnly)              /* dump indexes and triggers at the end
-                                * for performance */
+   res = PQexec(g_conn, "CLOSE _pg_dump_cursor");
+   if (!res ||
+       PQresultStatus(res) != PGRES_COMMAND_OK)
    {
-       dumpTriggers(g_fout, tablename, tblinfo, numTables);
-       dumpRules(g_fout, tablename, tblinfo, numTables);
+       write_msg(NULL, "dumpClasses(): SQL command failed\n");
+       write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
+       write_msg(NULL, "The command was: CLOSE _pg_dump_cursor\n");
+       exit_nicely();
    }
+   PQclear(res);
 
-   /* Now sort the output nicely */
-   SortTocByOID(g_fout);
-   MoveToStart(g_fout, "DATABASE");
-   MoveToEnd(g_fout, "TABLE DATA");
-   MoveToEnd(g_fout, "BLOBS");
-   MoveToEnd(g_fout, "INDEX");
-   MoveToEnd(g_fout, "CONSTRAINT");
-   MoveToEnd(g_fout, "TRIGGER");
-   MoveToEnd(g_fout, "RULE");
-   MoveToEnd(g_fout, "SEQUENCE SET");
-
-   /*
-    * Moving all comments to end is annoying, but must do it for comments
-    * on stuff we just moved, and we don't seem to have quite enough
-    * dependency structure to get it really right...
-    */
-   MoveToEnd(g_fout, "COMMENT");
+   destroyPQExpBuffer(q);
+   return 1;
+}
 
-   if (plainText)
+/*
+ * Convert a string value to an SQL string literal,
+ * with appropriate escaping of special characters.
+ * Quote mark ' goes to '' per SQL standard, other
+ * stuff goes to \ sequences.
+ * The literal is appended to the given PQExpBuffer.
+ */
+static void
+formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts)
+{
+   appendPQExpBufferChar(buf, '\'');
+   while (*str)
    {
-       ropt = NewRestoreOptions();
-       ropt->filename = (char *) filename;
-       ropt->dropSchema = outputClean;
-       ropt->aclsSkip = aclsSkip;
-       ropt->superuser = outputSuperuser;
-       ropt->create = outputCreate;
-       ropt->noOwner = outputNoOwner;
-       ropt->noReconnect = outputNoReconnect;
-       ropt->use_setsessauth = use_setsessauth;
+       char        ch = *str++;
 
-       if (outputSuperuser)
-           ropt->superuser = outputSuperuser;
+       if (ch == '\\' || ch == '\'')
+       {
+           appendPQExpBufferChar(buf, ch);     /* double these */
+           appendPQExpBufferChar(buf, ch);
+       }
+       else if ((unsigned char) ch < (unsigned char) ' ' &&
+                (opts == CONV_ALL
+                 || (ch != '\n' && ch != '\t')
+                 ))
+       {
+           /*
+            * generate octal escape for control chars other than
+            * whitespace
+            */
+           appendPQExpBufferChar(buf, '\\');
+           appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
+           appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
+           appendPQExpBufferChar(buf, (ch & 7) + '0');
+       }
        else
-           ropt->superuser = PQuser(g_conn);
+           appendPQExpBufferChar(buf, ch);
+   }
+   appendPQExpBufferChar(buf, '\'');
+}
 
-       if (compressLevel == -1)
-           ropt->compression = 0;
-       else
-           ropt->compression = compressLevel;
+/*
+ * DumpClasses -
+ *   dump the contents of all the classes.
+ */
+static void
+dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
+           const bool oids)
+{
+   int         i;
+   DataDumperPtr dumpFn;
+   DumpContext *dumpCtx;
+   char        copyBuf[512];
+   char       *copyStmt;
 
-       ropt->suppressDumpWarnings = true;      /* We've already shown
-                                                * them */
+   for (i = 0; i < numTables; i++)
+   {
+       const char *classname = tblinfo[i].relname;
 
-       RestoreArchive(g_fout, ropt);
-   }
+       /* Skip VIEW relations */
+       if (tblinfo[i].relkind == RELKIND_VIEW)
+           continue;
 
-   CloseArchive(g_fout);
+       if (tblinfo[i].relkind == RELKIND_SEQUENCE)     /* already dumped */
+           continue;
 
-   clearTableInfo(tblinfo, numTables);
-   PQfinish(g_conn);
-   exit(0);
+       if (tblinfo[i].dump)
+       {
+           if (g_verbose)
+               write_msg(NULL, "preparing to dump the contents of table %s\n",
+                         classname);
+
+           dumpCtx = (DumpContext *) malloc(sizeof(DumpContext));
+           dumpCtx->tblinfo = (TableInfo *) tblinfo;
+           dumpCtx->tblidx = i;
+           dumpCtx->oids = oids;
+
+           if (!dumpData)
+           {
+               /* Dump/restore using COPY */
+               dumpFn = dumpClasses_nodumpData;
+               sprintf(copyBuf, "COPY %s %sFROM stdin;\n",
+                       fmtId(tblinfo[i].relname, force_quotes),
+                       (oids && tblinfo[i].hasoids) ? "WITH OIDS " : "");
+               copyStmt = copyBuf;
+           }
+           else
+           {
+               /* Restore using INSERT */
+               dumpFn = dumpClasses_dumpData;
+               copyStmt = NULL;
+           }
+
+           ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
+                        tblinfo[i].relnamespace->nspname, tblinfo[i].usename,
+                        "TABLE DATA", NULL, "", "", copyStmt,
+                        dumpFn, dumpCtx);
+       }
+   }
 }
 
+
 /*
  * dumpDatabase:
  * dump the database definition
- *
  */
 static int
 dumpDatabase(Archive *AH)
@@ -1157,6 +1227,9 @@ dumpDatabase(Archive *AH)
    if (g_verbose)
        write_msg(NULL, "saving database definition\n");
 
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
+
    /* Get the database owner and parameters from pg_database */
    appendPQExpBuffer(dbQry, "select (select usename from pg_user where usesysid = datdba) as dba,"
                      " encoding, datpath from pg_database"
@@ -1207,10 +1280,17 @@ dumpDatabase(Archive *AH)
    appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
                      fmtId(datname, force_quotes));
 
-   ArchiveEntry(AH, "0" /* OID */ , datname /* Name */ , "DATABASE", NULL,
-                creaQry->data /* Create */ , delQry->data /* Del */ ,
-                "" /* Copy */ , dba /* Owner */ ,
-                NULL /* Dumper */ , NULL /* Dumper Arg */ );
+   ArchiveEntry(AH, "0",       /* OID */
+                datname,       /* Name */
+                NULL,          /* Namespace */
+                dba,           /* Owner */
+                "DATABASE",    /* Desc */
+                NULL,          /* Deps */
+                creaQry->data, /* Create */
+                delQry->data,  /* Del */
+                NULL,          /* Copy */
+                NULL,          /* Dumper */
+                NULL);         /* Dumper Arg */
 
    PQclear(res);
 
@@ -1246,6 +1326,9 @@ dumpBlobs(Archive *AH, char *junkOid, void *junkVal)
    if (g_verbose)
        write_msg(NULL, "saving large objects\n");
 
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
+
    /* Cursor to get all BLOB tables */
    if (AH->remoteVersion >= 70100)
        appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
@@ -1290,1487 +1373,779 @@ dumpBlobs(Archive *AH, char *junkOid, void *junkVal)
 
            StartBlob(AH, blobOid);
 
-           /* Now read it in chunks, sending data to archive */
-           do
-           {
-               cnt = lo_read(g_conn, loFd, buf, loBufSize);
-               if (cnt < 0)
-               {
-                   write_msg(NULL, "dumpBlobs(): error reading large object: %s",
-                             PQerrorMessage(g_conn));
-                   exit_nicely();
-               }
-
-               WriteData(AH, buf, cnt);
-
-           } while (cnt > 0);
-
-           lo_close(g_conn, loFd);
-
-           EndBlob(AH, blobOid);
-
-       }
-   } while (PQntuples(res) > 0);
-
-   destroyPQExpBuffer(oidQry);
-   destroyPQExpBuffer(oidFetchQry);
-
-   return 1;
-}
-
-/*
- * getTypes:
- *   read all base types in the system catalogs and return them in the
- * TypeInfo* structure
- *
- * numTypes is set to the number of types read in
- *
- */
-TypeInfo *
-getTypes(int *numTypes)
-{
-   PGresult   *res;
-   int         ntups;
-   int         i;
-   PQExpBuffer query = createPQExpBuffer();
-   TypeInfo   *tinfo;
-
-   int         i_oid;
-   int         i_typowner;
-   int         i_typname;
-   int         i_typlen;
-   int         i_typprtlen;
-   int         i_typinput;
-   int         i_typoutput;
-   int         i_typreceive;
-   int         i_typsend;
-   int         i_typelem;
-   int         i_typdelim;
-   int         i_typdefault;
-   int         i_typrelid;
-   int         i_typalign;
-   int         i_typstorage;
-   int         i_typbyval;
-   int         i_typisdefined;
-   int         i_usename;
-   int         i_typedefn;
-   int         i_typtype;
-
-   /* find all base types */
-
-   /*
-    * we include even the built-in types because those may be used as
-    * array elements by user-defined types
-    *
-    * we filter out the built-in types when we dump out the types
-    */
-
-   if (g_fout->remoteVersion < 70100)
-   {
-       appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
-         "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
-                         "typdefault, typrelid, typalign, 'p'::char as typstorage, typbyval, typisdefined, "
-                         "(select usename from pg_user where typowner = usesysid) as usename, "
-                         "typname as typedefn, typtype "
-                         "from pg_type");
-   }
-   else
-   {
-       appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
-         "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
-                         "typdefault, typrelid, typalign, typstorage, typbyval, typisdefined, "
-                         "(select usename from pg_user where typowner = usesysid) as usename, "
-                         "format_type(pg_type.oid, NULL) as typedefn, typtype "
-                         "from pg_type");
-   }
-
-   res = PQexec(g_conn, query->data);
-   if (!res ||
-       PQresultStatus(res) != PGRES_TUPLES_OK)
-   {
-       write_msg(NULL, "query to obtain list of data types failed: %s", PQerrorMessage(g_conn));
-       exit_nicely();
-   }
-
-   ntups = PQntuples(res);
-
-   tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
-
-   i_oid = PQfnumber(res, "oid");
-   i_typowner = PQfnumber(res, "typowner");
-   i_typname = PQfnumber(res, "typname");
-   i_typlen = PQfnumber(res, "typlen");
-   i_typprtlen = PQfnumber(res, "typprtlen");
-   i_typinput = PQfnumber(res, "typinput");
-   i_typoutput = PQfnumber(res, "typoutput");
-   i_typreceive = PQfnumber(res, "typreceive");
-   i_typsend = PQfnumber(res, "typsend");
-   i_typelem = PQfnumber(res, "typelem");
-   i_typdelim = PQfnumber(res, "typdelim");
-   i_typdefault = PQfnumber(res, "typdefault");
-   i_typrelid = PQfnumber(res, "typrelid");
-   i_typalign = PQfnumber(res, "typalign");
-   i_typstorage = PQfnumber(res, "typstorage");
-   i_typbyval = PQfnumber(res, "typbyval");
-   i_typisdefined = PQfnumber(res, "typisdefined");
-   i_usename = PQfnumber(res, "usename");
-   i_typedefn = PQfnumber(res, "typedefn");
-   i_typtype = PQfnumber(res, "typtype");
-
-   for (i = 0; i < ntups; i++)
-   {
-       tinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
-       tinfo[i].typowner = strdup(PQgetvalue(res, i, i_typowner));
-       tinfo[i].typname = strdup(PQgetvalue(res, i, i_typname));
-       tinfo[i].typlen = strdup(PQgetvalue(res, i, i_typlen));
-       tinfo[i].typprtlen = strdup(PQgetvalue(res, i, i_typprtlen));
-       tinfo[i].typinput = strdup(PQgetvalue(res, i, i_typinput));
-       tinfo[i].typoutput = strdup(PQgetvalue(res, i, i_typoutput));
-       tinfo[i].typreceive = strdup(PQgetvalue(res, i, i_typreceive));
-       tinfo[i].typsend = strdup(PQgetvalue(res, i, i_typsend));
-       tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
-       tinfo[i].typdelim = strdup(PQgetvalue(res, i, i_typdelim));
-       if (PQgetisnull(res, i, i_typdefault))
-           tinfo[i].typdefault = NULL;
-       else
-           tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
-       tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
-       tinfo[i].typalign = strdup(PQgetvalue(res, i, i_typalign));
-       tinfo[i].typstorage = strdup(PQgetvalue(res, i, i_typstorage));
-       tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
-       tinfo[i].typedefn = strdup(PQgetvalue(res, i, i_typedefn));
-       tinfo[i].typtype = strdup(PQgetvalue(res, i, i_typtype));
-
-       if (strlen(tinfo[i].usename) == 0)
-           write_msg(NULL, "WARNING: owner of data type %s appears to be invalid\n",
-                     tinfo[i].typname);
+           /* Now read it in chunks, sending data to archive */
+           do
+           {
+               cnt = lo_read(g_conn, loFd, buf, loBufSize);
+               if (cnt < 0)
+               {
+                   write_msg(NULL, "dumpBlobs(): error reading large object: %s",
+                             PQerrorMessage(g_conn));
+                   exit_nicely();
+               }
 
-       if (strcmp(PQgetvalue(res, i, i_typbyval), "f") == 0)
-           tinfo[i].passedbyvalue = 0;
-       else
-           tinfo[i].passedbyvalue = 1;
+               WriteData(AH, buf, cnt);
 
-       /*
-        * check for user-defined array types, omit system generated ones
-        */
-       if ((strcmp(tinfo[i].typelem, "0") != 0) &&
-           tinfo[i].typname[0] != '_')
-           tinfo[i].isArray = 1;
-       else
-           tinfo[i].isArray = 0;
+           } while (cnt > 0);
 
-       if (strcmp(PQgetvalue(res, i, i_typisdefined), "f") == 0)
-           tinfo[i].isDefined = 0;
-       else
-           tinfo[i].isDefined = 1;
-   }
+           lo_close(g_conn, loFd);
 
-   *numTypes = ntups;
+           EndBlob(AH, blobOid);
 
-   PQclear(res);
+       }
+   } while (PQntuples(res) > 0);
 
-   destroyPQExpBuffer(query);
+   destroyPQExpBuffer(oidQry);
+   destroyPQExpBuffer(oidFetchQry);
 
-   return tinfo;
+   return 1;
 }
 
 /*
- * getOperators:
- *   read all operators in the system catalogs and return them in the
- * OprInfo* structure
+ * getNamespaces:
+ *   read all namespaces in the system catalogs and return them in the
+ * NamespaceInfo* structure
  *
- * numOprs is set to the number of operators read in
+ * numNamespaces is set to the number of namespaces read in
  */
-OprInfo *
-getOperators(int *numOprs)
+NamespaceInfo *
+getNamespaces(int *numNamespaces)
 {
    PGresult   *res;
    int         ntups;
    int         i;
-   PQExpBuffer query = createPQExpBuffer();
-
-   OprInfo    *oprinfo;
-
+   PQExpBuffer query;
+   NamespaceInfo *nsinfo;
    int         i_oid;
-   int         i_oprname;
-   int         i_oprkind;
-   int         i_oprcode;
-   int         i_oprleft;
-   int         i_oprright;
-   int         i_oprcom;
-   int         i_oprnegate;
-   int         i_oprrest;
-   int         i_oprjoin;
-   int         i_oprcanhash;
-   int         i_oprlsortop;
-   int         i_oprrsortop;
+   int         i_nspname;
    int         i_usename;
+   int         i_nspacl;
 
    /*
-    * find all operators, including builtin operators, filter out
-    * system-defined operators at dump-out time
+    * Before 7.3, there are no real namespaces; create two dummy entries,
+    * one for user stuff and one for system stuff.
     */
+   if (g_fout->remoteVersion < 70300)
+   {
+       nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
+
+       nsinfo[0].oid = strdup("0");
+       nsinfo[0].nspname = strdup("");
+       nsinfo[0].usename = strdup("");
+       nsinfo[0].nspacl = strdup("");
+
+       selectDumpableNamespace(&nsinfo[0]);
+
+       nsinfo[1].oid = strdup("1");
+       nsinfo[1].nspname = strdup("pg_catalog");
+       nsinfo[1].usename = strdup("");
+       nsinfo[1].nspacl = strdup("");
+
+       selectDumpableNamespace(&nsinfo[1]);
+
+       g_namespaces = nsinfo;
+       g_numNamespaces = *numNamespaces = 2;
+
+       return nsinfo;
+   }
+
+   query = createPQExpBuffer();
+
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
 
-   appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
-              "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
-                     "oprcanhash, oprlsortop, oprrsortop, "
-   "(select usename from pg_user where oprowner = usesysid) as usename "
-                     "from pg_operator");
+   /*
+    * we fetch all namespaces including system ones, so that every object
+    * we read in can be linked to a containing namespace.
+    */
+   appendPQExpBuffer(query, "SELECT oid, nspname, "
+                         "(select usename from pg_user where nspowner = usesysid) as usename, "
+                         "nspacl "
+                         "FROM pg_namespace");
 
    res = PQexec(g_conn, query->data);
    if (!res ||
        PQresultStatus(res) != PGRES_TUPLES_OK)
    {
-       write_msg(NULL, "query to obtain list of operators failed: %s", PQerrorMessage(g_conn));
+       write_msg(NULL, "query to obtain list of namespaces failed: %s", PQerrorMessage(g_conn));
        exit_nicely();
    }
 
    ntups = PQntuples(res);
-   *numOprs = ntups;
 
-   oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
+   nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
 
    i_oid = PQfnumber(res, "oid");
-   i_oprname = PQfnumber(res, "oprname");
-   i_oprkind = PQfnumber(res, "oprkind");
-   i_oprcode = PQfnumber(res, "oprcode");
-   i_oprleft = PQfnumber(res, "oprleft");
-   i_oprright = PQfnumber(res, "oprright");
-   i_oprcom = PQfnumber(res, "oprcom");
-   i_oprnegate = PQfnumber(res, "oprnegate");
-   i_oprrest = PQfnumber(res, "oprrest");
-   i_oprjoin = PQfnumber(res, "oprjoin");
-   i_oprcanhash = PQfnumber(res, "oprcanhash");
-   i_oprlsortop = PQfnumber(res, "oprlsortop");
-   i_oprrsortop = PQfnumber(res, "oprrsortop");
+   i_nspname = PQfnumber(res, "nspname");
    i_usename = PQfnumber(res, "usename");
+   i_nspacl = PQfnumber(res, "nspacl");
 
    for (i = 0; i < ntups; i++)
    {
-       oprinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
-       oprinfo[i].oprname = strdup(PQgetvalue(res, i, i_oprname));
-       oprinfo[i].oprkind = strdup(PQgetvalue(res, i, i_oprkind));
-       oprinfo[i].oprcode = strdup(PQgetvalue(res, i, i_oprcode));
-       oprinfo[i].oprleft = strdup(PQgetvalue(res, i, i_oprleft));
-       oprinfo[i].oprright = strdup(PQgetvalue(res, i, i_oprright));
-       oprinfo[i].oprcom = strdup(PQgetvalue(res, i, i_oprcom));
-       oprinfo[i].oprnegate = strdup(PQgetvalue(res, i, i_oprnegate));
-       oprinfo[i].oprrest = strdup(PQgetvalue(res, i, i_oprrest));
-       oprinfo[i].oprjoin = strdup(PQgetvalue(res, i, i_oprjoin));
-       oprinfo[i].oprcanhash = strdup(PQgetvalue(res, i, i_oprcanhash));
-       oprinfo[i].oprlsortop = strdup(PQgetvalue(res, i, i_oprlsortop));
-       oprinfo[i].oprrsortop = strdup(PQgetvalue(res, i, i_oprrsortop));
-       oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
+       nsinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
+       nsinfo[i].nspname = strdup(PQgetvalue(res, i, i_nspname));
+       nsinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
+       nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
 
-       if (strlen(oprinfo[i].usename) == 0)
-           write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
-                     oprinfo[i].oprname);
+       /* Decide whether to dump this namespace */
+       selectDumpableNamespace(&nsinfo[i]);
 
+       if (strlen(nsinfo[i].usename) == 0)
+           write_msg(NULL, "WARNING: owner of namespace %s appears to be invalid\n",
+                     nsinfo[i].nspname);
    }
 
    PQclear(res);
-
    destroyPQExpBuffer(query);
 
-   return oprinfo;
-}
-
-void
-clearTypeInfo(TypeInfo *tp, int numTypes)
-{
-   int         i;
-
-   for (i = 0; i < numTypes; ++i)
-   {
-       if (tp[i].oid)
-           free(tp[i].oid);
-       if (tp[i].typowner)
-           free(tp[i].typowner);
-       if (tp[i].typname)
-           free(tp[i].typname);
-       if (tp[i].typlen)
-           free(tp[i].typlen);
-       if (tp[i].typprtlen)
-           free(tp[i].typprtlen);
-       if (tp[i].typinput)
-           free(tp[i].typinput);
-       if (tp[i].typoutput)
-           free(tp[i].typoutput);
-       if (tp[i].typreceive)
-           free(tp[i].typreceive);
-       if (tp[i].typsend)
-           free(tp[i].typsend);
-       if (tp[i].typelem)
-           free(tp[i].typelem);
-       if (tp[i].typdelim)
-           free(tp[i].typdelim);
-       if (tp[i].typdefault)
-           free(tp[i].typdefault);
-       if (tp[i].typrelid)
-           free(tp[i].typrelid);
-       if (tp[i].typalign)
-           free(tp[i].typalign);
-       if (tp[i].typstorage)
-           free(tp[i].typstorage);
-       if (tp[i].usename)
-           free(tp[i].usename);
-       if (tp[i].typedefn)
-           free(tp[i].typedefn);
-   }
-   free(tp);
-}
-
-void
-clearFuncInfo(FuncInfo *fun, int numFuncs)
-{
-   int         i,
-               a;
+   g_namespaces = nsinfo;
+   g_numNamespaces = *numNamespaces = ntups;
 
-   if (!fun)
-       return;
-   for (i = 0; i < numFuncs; ++i)
-   {
-       if (fun[i].oid)
-           free(fun[i].oid);
-       if (fun[i].proname)
-           free(fun[i].proname);
-       if (fun[i].usename)
-           free(fun[i].usename);
-       if (fun[i].argtypes)
-       {
-           for (a = 0; a < fun[i].nargs; ++a)
-               if (fun[i].argtypes[a])
-                   free(fun[i].argtypes[a]);
-           free(fun[i].argtypes);
-       }
-       if (fun[i].prorettype)
-           free(fun[i].prorettype);
-       if (fun[i].prosrc)
-           free(fun[i].prosrc);
-       if (fun[i].probin)
-           free(fun[i].probin);
-   }
-   free(fun);
+   return nsinfo;
 }
 
-static void
-clearTableInfo(TableInfo *tblinfo, int numTables)
+/*
+ * findNamespace:
+ *     given a namespace OID and an object OID, look up the info read by
+ *     getNamespaces
+ *
+ * NB: for pre-7.3 source database, we use object OID to guess whether it's
+ * a system object or not.  In 7.3 and later there is no guessing.
+ */
+static NamespaceInfo *
+findNamespace(const char *nsoid, const char *objoid)
 {
-   int         i,
-               j;
+   int         i;
 
-   for (i = 0; i < numTables; ++i)
+   if (g_fout->remoteVersion >= 70300)
    {
-
-       if (tblinfo[i].oid)
-           free(tblinfo[i].oid);
-       if (tblinfo[i].relacl)
-           free(tblinfo[i].relacl);
-       if (tblinfo[i].usename)
-           free(tblinfo[i].usename);
-
-       if (tblinfo[i].relname)
-           free(tblinfo[i].relname);
-
-       if (tblinfo[i].relkind == RELKIND_SEQUENCE)
-           continue;
-
-       /* Process Attributes */
-       for (j = 0; j < tblinfo[i].numatts; j++)
+       for (i = 0; i < g_numNamespaces; i++)
        {
-           if (tblinfo[i].attnames[j])
-               free(tblinfo[i].attnames[j]);
-           if (tblinfo[i].typnames[j])
-               free(tblinfo[i].typnames[j]);
-       }
+           NamespaceInfo  *nsinfo = &g_namespaces[i];
 
-       if (tblinfo[i].triggers)
-       {
-           for (j = 0; j < tblinfo[i].ntrig; j++)
-           {
-               if (tblinfo[i].triggers[j].tgsrc)
-                   free(tblinfo[i].triggers[j].tgsrc);
-               if (tblinfo[i].triggers[j].oid)
-                   free(tblinfo[i].triggers[j].oid);
-               if (tblinfo[i].triggers[j].tgname)
-                   free(tblinfo[i].triggers[j].tgname);
-               if (tblinfo[i].triggers[j].tgdel)
-                   free(tblinfo[i].triggers[j].tgdel);
-           }
-           free(tblinfo[i].triggers);
+           if (strcmp(nsoid, nsinfo->oid) == 0)
+               return nsinfo;
        }
-
-       if (tblinfo[i].atttypmod)
-           free((int *) tblinfo[i].atttypmod);
-       if (tblinfo[i].inhAttrs)
-           free((int *) tblinfo[i].inhAttrs);
-       if (tblinfo[i].inhAttrDef)
-           free((int *) tblinfo[i].inhAttrDef);
-       if (tblinfo[i].inhNotNull)
-           free((int *) tblinfo[i].inhNotNull);
-       if (tblinfo[i].attnames)
-           free(tblinfo[i].attnames);
-       if (tblinfo[i].atttypedefns)
-           free(tblinfo[i].atttypedefns);
-       if (tblinfo[i].typnames)
-           free(tblinfo[i].typnames);
-       if (tblinfo[i].notnull)
-           free(tblinfo[i].notnull);
-       if (tblinfo[i].primary_key_name)
-           free(tblinfo[i].primary_key_name);
-   }
-   free(tblinfo);
-}
-
-void
-clearInhInfo(InhInfo *inh, int numInherits)
-{
-   int         i;
-
-   if (!inh)
-       return;
-   for (i = 0; i < numInherits; ++i)
-   {
-       if (inh[i].inhrelid)
-           free(inh[i].inhrelid);
-       if (inh[i].inhparent)
-           free(inh[i].inhparent);
+       write_msg(NULL, "Failed to find namespace with OID %s.\n", nsoid);
+       exit_nicely();
    }
-   free(inh);
-}
-
-void
-clearOprInfo(OprInfo *opr, int numOprs)
-{
-   int         i;
-
-   if (!opr)
-       return;
-   for (i = 0; i < numOprs; ++i)
-   {
-       if (opr[i].oid)
-           free(opr[i].oid);
-       if (opr[i].oprname)
-           free(opr[i].oprname);
-       if (opr[i].oprkind)
-           free(opr[i].oprkind);
-       if (opr[i].oprcode)
-           free(opr[i].oprcode);
-       if (opr[i].oprleft)
-           free(opr[i].oprleft);
-       if (opr[i].oprright)
-           free(opr[i].oprright);
-       if (opr[i].oprcom)
-           free(opr[i].oprcom);
-       if (opr[i].oprnegate)
-           free(opr[i].oprnegate);
-       if (opr[i].oprrest)
-           free(opr[i].oprrest);
-       if (opr[i].oprjoin)
-           free(opr[i].oprjoin);
-       if (opr[i].oprcanhash)
-           free(opr[i].oprcanhash);
-       if (opr[i].oprlsortop)
-           free(opr[i].oprlsortop);
-       if (opr[i].oprrsortop)
-           free(opr[i].oprrsortop);
-       if (opr[i].usename)
-           free(opr[i].usename);
-   }
-   free(opr);
-}
-
-void
-clearIndInfo(IndInfo *ind, int numIndexes)
-{
-   int         i,
-               a;
-
-   if (!ind)
-       return;
-   for (i = 0; i < numIndexes; ++i)
-   {
-       if (ind[i].indexreloid)
-           free(ind[i].indexreloid);
-       if (ind[i].indreloid)
-           free(ind[i].indreloid);
-       if (ind[i].indexrelname)
-           free(ind[i].indexrelname);
-       if (ind[i].indrelname)
-           free(ind[i].indrelname);
-       if (ind[i].indexdef)
-           free(ind[i].indexdef);
-       if (ind[i].indisprimary)
-           free(ind[i].indisprimary);
-       if (ind[i].indkey)
-       {
-           for (a = 0; a < ind[i].indnkeys; ++a)
-               if (ind[i].indkey[a])
-                   free(ind[i].indkey[a]);
-           free(ind[i].indkey);
-       }
+   else
+   {
+       /* This code depends on the layout set up by getNamespaces. */
+       if (atooid(objoid) > g_last_builtin_oid)
+           i = 0;              /* user object */
+       else
+           i = 1;              /* system object */
+       return &g_namespaces[i];
    }
-   free(ind);
-}
-
-void
-clearAggInfo(AggInfo *agginfo, int numArgs)
-{
-   int         i;
 
-   if (!agginfo)
-       return;
-   for (i = 0; i < numArgs; ++i)
-   {
-       if (agginfo[i].oid)
-           free(agginfo[i].oid);
-       if (agginfo[i].aggname)
-           free(agginfo[i].aggname);
-       if (agginfo[i].aggtransfn)
-           free(agginfo[i].aggtransfn);
-       if (agginfo[i].aggfinalfn)
-           free(agginfo[i].aggfinalfn);
-       if (agginfo[i].aggtranstype)
-           free(agginfo[i].aggtranstype);
-       if (agginfo[i].aggbasetype)
-           free(agginfo[i].aggbasetype);
-       if (agginfo[i].agginitval)
-           free(agginfo[i].agginitval);
-       if (agginfo[i].usename)
-           free(agginfo[i].usename);
-   }
-   free(agginfo);
+   return NULL;                /* keep compiler quiet */
 }
 
 /*
- * getAggregates:
- *   read all the user-defined aggregates in the system catalogs and
- * return them in the AggInfo* structure
+ * getTypes:
+ *   read all types in the system catalogs and return them in the
+ * TypeInfo* structure
  *
- * numAggs is set to the number of aggregates read in
+ * numTypes is set to the number of types read in
  */
-AggInfo *
-getAggregates(int *numAggs)
+TypeInfo *
+getTypes(int *numTypes)
 {
    PGresult   *res;
    int         ntups;
    int         i;
    PQExpBuffer query = createPQExpBuffer();
-   AggInfo    *agginfo;
-
+   TypeInfo   *tinfo;
    int         i_oid;
-   int         i_aggname;
-   int         i_aggtransfn;
-   int         i_aggfinalfn;
-   int         i_aggtranstype;
-   int         i_aggbasetype;
-   int         i_agginitval;
+   int         i_typname;
+   int         i_typnamespace;
    int         i_usename;
-   int         i_convertok;
+   int         i_typelem;
+   int         i_typrelid;
+   int         i_typtype;
+   int         i_typisdefined;
 
-   /* find all user-defined aggregates */
+   /*
+    * we include even the built-in types because those may be used as
+    * array elements by user-defined types
+    *
+    * we filter out the built-in types when we dump out the types
+    */
 
-   if (g_fout->remoteVersion < 70100)
-   {
-       appendPQExpBuffer(query, "SELECT pg_aggregate.oid, aggname, aggtransfn1 as aggtransfn, "
-              "aggfinalfn, aggtranstype1 as aggtranstype, aggbasetype, "
-                         "agginitval1 as agginitval, "
-                         "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok, "
-                         "(select usename from pg_user where aggowner = usesysid) as usename "
-                         "from pg_aggregate");
-   }
-   else if (g_fout->remoteVersion < 70300)
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
+
+   if (g_fout->remoteVersion >= 70300)
    {
-       appendPQExpBuffer(query, "SELECT pg_aggregate.oid, aggname, aggtransfn, "
-                         "aggfinalfn, aggtranstype, aggbasetype, "
-                         "agginitval, "
-                         "'t'::boolean as convertok, "
-                         "(select usename from pg_user where aggowner = usesysid) as usename "
-                         "from pg_aggregate");
+       appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
+                         "typnamespace, "
+                         "(select usename from pg_user where typowner = usesysid) as usename, "
+                         "typelem, typrelid, typtype, typisdefined "
+                         "FROM pg_type");
    }
    else
    {
-       appendPQExpBuffer(query, "SELECT p.oid, proname as aggname, aggtransfn, "
-                         "aggfinalfn, aggtranstype, proargtypes[0] as aggbasetype, "
-                         "agginitval, "
-                         "'t'::boolean as convertok, "
-                         "(select usename from pg_user where proowner = usesysid) as usename "
-                         "from pg_aggregate a, pg_proc p "
-                         "where a.aggfnoid = p.oid");
+       appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
+                         "0::oid as typnamespace, "
+                         "(select usename from pg_user where typowner = usesysid) as usename, "
+                         "typelem, typrelid, typtype, typisdefined "
+                         "FROM pg_type");
    }
 
    res = PQexec(g_conn, query->data);
    if (!res ||
        PQresultStatus(res) != PGRES_TUPLES_OK)
    {
-       write_msg(NULL, "query to obtain list of aggregate functions failed: %s",
-                 PQerrorMessage(g_conn));
+       write_msg(NULL, "query to obtain list of data types failed: %s", PQerrorMessage(g_conn));
        exit_nicely();
    }
 
    ntups = PQntuples(res);
-   *numAggs = ntups;
 
-   agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
+   tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
 
    i_oid = PQfnumber(res, "oid");
-   i_aggname = PQfnumber(res, "aggname");
-   i_aggtransfn = PQfnumber(res, "aggtransfn");
-   i_aggfinalfn = PQfnumber(res, "aggfinalfn");
-   i_aggtranstype = PQfnumber(res, "aggtranstype");
-   i_aggbasetype = PQfnumber(res, "aggbasetype");
-   i_agginitval = PQfnumber(res, "agginitval");
+   i_typname = PQfnumber(res, "typname");
+   i_typnamespace = PQfnumber(res, "typnamespace");
    i_usename = PQfnumber(res, "usename");
-   i_convertok = PQfnumber(res, "convertok");
+   i_typelem = PQfnumber(res, "typelem");
+   i_typrelid = PQfnumber(res, "typrelid");
+   i_typtype = PQfnumber(res, "typtype");
+   i_typisdefined = PQfnumber(res, "typisdefined");
 
    for (i = 0; i < ntups; i++)
    {
-       agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
-       agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
-       agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
-       agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
-       agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
-       agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
-       agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
-       agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
-       if (strlen(agginfo[i].usename) == 0)
-           write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
-                     agginfo[i].aggname);
+       tinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
+       tinfo[i].typname = strdup(PQgetvalue(res, i, i_typname));
+       tinfo[i].typnamespace = findNamespace(PQgetvalue(res, i, i_typnamespace),
+                                             tinfo[i].oid);
+       tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
+       tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
+       tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
+       tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
+
+       if (strlen(tinfo[i].usename) == 0)
+           write_msg(NULL, "WARNING: owner of data type %s appears to be invalid\n",
+                     tinfo[i].typname);
 
-       agginfo[i].convertok = (PQgetvalue(res, i, i_convertok)[0] == 't');
+       /*
+        * check for user-defined array types, omit system generated ones
+        */
+       if ((strcmp(tinfo[i].typelem, "0") != 0) &&
+           tinfo[i].typname[0] != '_')
+           tinfo[i].isArray = true;
+       else
+           tinfo[i].isArray = false;
 
+       if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
+           tinfo[i].isDefined = true;
+       else
+           tinfo[i].isDefined = false;
    }
 
+   *numTypes = ntups;
+
    PQclear(res);
 
    destroyPQExpBuffer(query);
 
-   return agginfo;
+   return tinfo;
 }
 
 /*
- * getFuncs:
- *   read all the user-defined functions in the system catalogs and
- * return them in the FuncInfo* structure
- *
- * numFuncs is set to the number of functions read in
- *
+ * getOperators:
+ *   read all operators in the system catalogs and return them in the
+ * OprInfo* structure
  *
+ * numOprs is set to the number of operators read in
  */
-FuncInfo *
-getFuncs(int *numFuncs)
+OprInfo *
+getOperators(int *numOprs)
 {
    PGresult   *res;
    int         ntups;
    int         i;
    PQExpBuffer query = createPQExpBuffer();
-   FuncInfo   *finfo;
-
+   OprInfo    *oprinfo;
    int         i_oid;
-   int         i_proname;
-   int         i_prolang;
-   int         i_pronargs;
-   int         i_proargtypes;
-   int         i_prorettype;
-   int         i_proretset;
-   int         i_prosrc;
-   int         i_probin;
-   int         i_provolatile;
-   int         i_isimplicit;
-   int         i_isstrict;
+   int         i_oprname;
+   int         i_oprnamespace;
    int         i_usename;
+   int         i_oprcode;
 
-   /* find all user-defined funcs */
+   /*
+    * find all operators, including builtin operators;
+    * we filter out system-defined operators at dump-out time.
+    */
 
-   if (g_fout->remoteVersion < 70100)
-   {
-       appendPQExpBuffer(query,
-          "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
-                         "proretset, proargtypes, prosrc, probin, "
-                         "(select usename from pg_user where proowner = usesysid) as usename, "
-                         "case when proiscachable then 'i' else 'v' end as provolatile, "
-                         "'f'::boolean as proimplicit, "
-                         "'f'::boolean as proisstrict "
-                         "from pg_proc "
-                         "where pg_proc.oid > '%u'::oid",
-                         g_last_builtin_oid);
-   }
-   else if (g_fout->remoteVersion < 70300)
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
+
+   if (g_fout->remoteVersion >= 70300)
    {
-       appendPQExpBuffer(query,
-          "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
-                         "proretset, proargtypes, prosrc, probin, "
-                         "(select usename from pg_user where proowner = usesysid) as usename, "
-                         "case when proiscachable then 'i' else 'v' end as provolatile, "
-                         "'f'::boolean as proimplicit, "
-                         "proisstrict "
-                         "from pg_proc "
-                         "where pg_proc.oid > '%u'::oid",
-                         g_last_builtin_oid);
+       appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, "
+                         "oprnamespace, "
+                         "(select usename from pg_user where oprowner = usesysid) as usename, "
+                         "oprcode::oid "
+                         "from pg_operator");
    }
    else
    {
-       appendPQExpBuffer(query,
-          "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
-                         "proretset, proargtypes, prosrc, probin, "
-                         "(select usename from pg_user where proowner = usesysid) as usename, "
-                         "provolatile, proimplicit, proisstrict "
-                         "from pg_proc "
-                         "where pg_proc.oid > '%u'::oid and not proisagg",
-                         g_last_builtin_oid);
+       appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, "
+                         "0::oid as oprnamespace, "
+                         "(select usename from pg_user where oprowner = usesysid) as usename, "
+                         "oprcode::oid "
+                         "from pg_operator");
    }
 
    res = PQexec(g_conn, query->data);
    if (!res ||
        PQresultStatus(res) != PGRES_TUPLES_OK)
    {
-       write_msg(NULL, "query to obtain list of functions failed: %s",
-                 PQerrorMessage(g_conn));
+       write_msg(NULL, "query to obtain list of operators failed: %s", PQerrorMessage(g_conn));
        exit_nicely();
    }
 
    ntups = PQntuples(res);
+   *numOprs = ntups;
 
-   *numFuncs = ntups;
-
-   finfo = (FuncInfo *) malloc(ntups * sizeof(FuncInfo));
-
-   memset((char *) finfo, 0, ntups * sizeof(FuncInfo));
+   oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
 
    i_oid = PQfnumber(res, "oid");
-   i_proname = PQfnumber(res, "proname");
-   i_prolang = PQfnumber(res, "prolang");
-   i_pronargs = PQfnumber(res, "pronargs");
-   i_proargtypes = PQfnumber(res, "proargtypes");
-   i_prorettype = PQfnumber(res, "prorettype");
-   i_proretset = PQfnumber(res, "proretset");
-   i_prosrc = PQfnumber(res, "prosrc");
-   i_probin = PQfnumber(res, "probin");
-   i_provolatile = PQfnumber(res, "provolatile");
-   i_isimplicit = PQfnumber(res, "proimplicit");
-   i_isstrict = PQfnumber(res, "proisstrict");
+   i_oprname = PQfnumber(res, "oprname");
+   i_oprnamespace = PQfnumber(res, "oprnamespace");
    i_usename = PQfnumber(res, "usename");
+   i_oprcode = PQfnumber(res, "oprcode");
 
    for (i = 0; i < ntups; i++)
    {
-       finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
-       finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));
-
-       finfo[i].prosrc = strdup(PQgetvalue(res, i, i_prosrc));
-       finfo[i].probin = strdup(PQgetvalue(res, i, i_probin));
-
-       finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
-       finfo[i].retset = (strcmp(PQgetvalue(res, i, i_proretset), "t") == 0);
-       finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
-       finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
-       finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
-       finfo[i].provolatile = (PQgetvalue(res, i, i_provolatile))[0];
-       finfo[i].isimplicit = (strcmp(PQgetvalue(res, i, i_isimplicit), "t") == 0);
-       finfo[i].isstrict = (strcmp(PQgetvalue(res, i, i_isstrict), "t") == 0);
-
-       if (strlen(finfo[i].usename) == 0)
-           write_msg(NULL, "WARNING: owner of function \"%s\" appears to be invalid\n",
-                     finfo[i].proname);
+       oprinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
+       oprinfo[i].oprname = strdup(PQgetvalue(res, i, i_oprname));
+       oprinfo[i].oprnamespace = findNamespace(PQgetvalue(res, i, i_oprnamespace),
+                                               oprinfo[i].oid);
+       oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
+       oprinfo[i].oprcode = strdup(PQgetvalue(res, i, i_oprcode));
 
-       finfo[i].argtypes = malloc(finfo[i].nargs * sizeof(finfo[i].argtypes[0]));
-       parseNumericArray(PQgetvalue(res, i, i_proargtypes),
-                         finfo[i].argtypes,
-                         finfo[i].nargs);
-       finfo[i].dumped = 0;
+       if (strlen(oprinfo[i].usename) == 0)
+           write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
+                     oprinfo[i].oprname);
    }
 
    PQclear(res);
 
    destroyPQExpBuffer(query);
 
-   return finfo;
+   return oprinfo;
 }
 
 /*
- * getTables
- *   read all the user-defined tables (no indexes, no catalogs)
- * in the system catalogs return them in the TableInfo* structure
+ * getAggregates:
+ *   read all the user-defined aggregates in the system catalogs and
+ * return them in the AggInfo* structure
  *
- * numTables is set to the number of tables read in
+ * numAggs is set to the number of aggregates read in
  */
-TableInfo *
-getTables(int *numTables, FuncInfo *finfo, int numFuncs, const char *tablename)
+AggInfo *
+getAggregates(int *numAggs)
 {
    PGresult   *res;
    int         ntups;
    int         i;
    PQExpBuffer query = createPQExpBuffer();
-   PQExpBuffer delqry = createPQExpBuffer();
-   PQExpBuffer lockquery = createPQExpBuffer();
-   TableInfo  *tblinfo;
+   AggInfo    *agginfo;
 
-   int         i_reloid;
-   int         i_relname;
-   int         i_relkind;
-   int         i_relacl;
+   int         i_oid;
+   int         i_aggname;
+   int         i_aggnamespace;
    int         i_usename;
-   int         i_relchecks;
-   int         i_reltriggers;
-   int         i_relhasindex;
-   int         i_relhasoids;
 
-   /*
-    * find all the user-defined tables (no indexes and no catalogs),
-    * ordering by oid is important so that we always process the parent
-    * tables before the child tables when traversing the tblinfo*
-    *
-    * we ignore tables that are not type 'r' (ordinary relation) or 'S'
-    * (sequence) or 'v' (view).
-    */
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
 
-   if (g_fout->remoteVersion >= 70200)
-   {
-       appendPQExpBuffer(query,
-                       "SELECT pg_class.oid, relname, relacl, relkind, "
-                         "(select usename from pg_user where relowner = usesysid) as usename, "
-                      "relchecks, reltriggers, relhasindex, relhasoids "
-                         "from pg_class "
-                         "where relname !~ '^pg_' "
-                         "and relkind in ('%c', '%c', '%c') "
-                         "order by oid",
-                      RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
-   }
-   else if (g_fout->remoteVersion >= 70100)
+   /* find all user-defined aggregates */
+
+   if (g_fout->remoteVersion >= 70300)
    {
-       /* all tables have oids in 7.1 */
-       appendPQExpBuffer(query,
-                       "SELECT pg_class.oid, relname, relacl, relkind, "
-                         "(select usename from pg_user where relowner = usesysid) as usename, "
-         "relchecks, reltriggers, relhasindex, 't'::bool as relhasoids "
-                         "from pg_class "
-                         "where relname !~ '^pg_' "
-                         "and relkind in ('%c', '%c', '%c') "
-                         "order by oid",
-                      RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
+       appendPQExpBuffer(query, "SELECT pg_proc.oid, proname as aggname, "
+                         "pronamespace as aggnamespace, "
+                         "(select usename from pg_user where proowner = usesysid) as usename "
+                         "FROM pg_proc "
+                         "WHERE proisagg "
+                         "AND pronamespace != "
+                         "(select oid from pg_namespace where nspname = 'pg_catalog')");
    }
    else
    {
-       /*
-        * Before 7.1, view relkind was not set to 'v', so we must check
-        * if we have a view by looking for a rule in pg_rewrite.
-        */
-       appendPQExpBuffer(query,
-                         "SELECT c.oid, relname, relacl, "
-                         "CASE WHEN relhasrules and relkind = 'r' "
-                 "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
-                 "             r.ev_class = c.oid AND r.ev_type = '1') "
-                         "THEN '%c'::\"char\" "
-                         "ELSE relkind END AS relkind,"
-                         "(select usename from pg_user where relowner = usesysid) as usename, "
-         "relchecks, reltriggers, relhasindex, 't'::bool as relhasoids "
-                         "from pg_class c "
-                         "where relname !~ '^pg_' "
-                         "and relkind in ('%c', '%c', '%c') "
-                         "order by oid",
-                         RELKIND_VIEW,
-                      RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
+       appendPQExpBuffer(query, "SELECT pg_aggregate.oid, aggname, "
+                         "0::oid as aggnamespace, "
+                         "(select usename from pg_user where aggowner = usesysid) as usename "
+                         "from pg_aggregate "
+                         "where oid > '%u'::oid",
+                         g_last_builtin_oid);
    }
 
    res = PQexec(g_conn, query->data);
    if (!res ||
        PQresultStatus(res) != PGRES_TUPLES_OK)
    {
-       write_msg(NULL, "query to obtain list of tables failed: %s",
+       write_msg(NULL, "query to obtain list of aggregate functions failed: %s",
                  PQerrorMessage(g_conn));
        exit_nicely();
    }
 
    ntups = PQntuples(res);
+   *numAggs = ntups;
 
-   *numTables = ntups;
-
-   /*
-    * First pass: extract data from result and lock tables.  We do the
-    * locking before anything else, to minimize the window wherein a
-    * table could disappear under us.
-    *
-    * Note that we have to collect info about all tables here, even when
-    * dumping only one, because we don't know which tables might be
-    * inheritance ancestors of the target table.  Possible future
-    * improvement: suppress later collection of schema info about tables
-    * that are determined not to be either targets or ancestors of
-    * targets.
-    */
-   tblinfo = (TableInfo *) malloc(ntups * sizeof(TableInfo));
+   agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
 
-   i_reloid = PQfnumber(res, "oid");
-   i_relname = PQfnumber(res, "relname");
-   i_relacl = PQfnumber(res, "relacl");
-   i_relkind = PQfnumber(res, "relkind");
+   i_oid = PQfnumber(res, "oid");
+   i_aggname = PQfnumber(res, "aggname");
+   i_aggnamespace = PQfnumber(res, "aggnamespace");
    i_usename = PQfnumber(res, "usename");
-   i_relchecks = PQfnumber(res, "relchecks");
-   i_reltriggers = PQfnumber(res, "reltriggers");
-   i_relhasindex = PQfnumber(res, "relhasindex");
-   i_relhasoids = PQfnumber(res, "relhasoids");
 
    for (i = 0; i < ntups; i++)
    {
-       tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
-       tblinfo[i].relname = strdup(PQgetvalue(res, i, i_relname));
-       tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
-       tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
-       tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
-       tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
-       tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
-       tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
-       tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
-
-       /*
-        * Read-lock target tables to make sure they aren't DROPPED or
-        * altered in schema before we get around to dumping them.
-        *
-        * If no target tablename was specified, lock all tables we see,
-        * otherwise lock only the specified table.  (This is incomplete
-        * because we'll still try to collect schema info about all
-        * tables, and could possibly lose during that phase.  But for the
-        * typical use where we're dumping all tables anyway, it matters
-        * not.)
-        *
-        * NOTE: it'd be kinda nice to lock views and sequences too, not only
-        * plain tables, but the backend doesn't presently allow that.
-        */
-       if ((tblinfo[i].relkind == RELKIND_RELATION) &&
-       (tablename == NULL || strcmp(tblinfo[i].relname, tablename) == 0))
-       {
-           PGresult   *lres;
-
-           resetPQExpBuffer(lockquery);
-           appendPQExpBuffer(lockquery,
-                             "LOCK TABLE %s IN ACCESS SHARE MODE",
-                             fmtId(tblinfo[i].relname, force_quotes));
-           lres = PQexec(g_conn, lockquery->data);
-           if (!lres || PQresultStatus(lres) != PGRES_COMMAND_OK)
-           {
-               write_msg(NULL, "Attempt to lock table \"%s\" failed.  %s",
-                         tblinfo[i].relname, PQerrorMessage(g_conn));
-               exit_nicely();
-           }
-           PQclear(lres);
-       }
-   }
-
-   PQclear(res);
-   res = NULL;
-
-   /*
-    * Second pass: pick up additional information about each table, as
-    * required.
-    */
-   for (i = 0; i < *numTables; i++)
-   {
-       /* Emit notice if join for owner failed */
-       if (strlen(tblinfo[i].usename) == 0)
-           write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
-                     tblinfo[i].relname);
-
-       /* Get definition if it's a view */
-       if (tblinfo[i].relkind == RELKIND_VIEW)
-       {
-           PGresult   *res2;
-
-           resetPQExpBuffer(query);
-
-           if (g_fout->remoteVersion < 70300)
-           {
-               appendPQExpBuffer(query, "SELECT definition as viewdef, "
-                                 "(select oid from pg_rewrite where "
-                                 " rulename=('_RET' || viewname)::name) as view_oid"
-                                 " from pg_views where viewname = ");
-               formatStringLiteral(query, tblinfo[i].relname, CONV_ALL);
-               appendPQExpBuffer(query, ";");
-           }
-           else
-           {
-               /* Beginning in 7.3, viewname is not unique; use OID */
-               appendPQExpBuffer(query, "SELECT pg_get_viewdef(ev_class) as viewdef, "
-                                 "oid as view_oid"
-                                 " from pg_rewrite where"
-                                 " ev_class = '%s'::oid and"
-                                 " rulename = '_RETURN';",
-                                 tblinfo[i].oid);
-           }
-
-           res2 = PQexec(g_conn, query->data);
-           if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
-           {
-               write_msg(NULL, "query to obtain definition of view \"%s\" failed: %s",
-                         tblinfo[i].relname, PQerrorMessage(g_conn));
-               exit_nicely();
-           }
-
-           if (PQntuples(res2) != 1)
-           {
-               if (PQntuples(res2) < 1)
-                   write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
-                             tblinfo[i].relname);
-               else
-                   write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
-                             tblinfo[i].relname);
-               exit_nicely();
-           }
-
-           if (PQgetisnull(res2, 0, 1))
-           {
-               write_msg(NULL, "query to obtain definition of view \"%s\" returned NULL oid\n",
-                         tblinfo[i].relname);
-               exit_nicely();
-           }
-
-           tblinfo[i].viewdef = strdup(PQgetvalue(res2, 0, 0));
-           tblinfo[i].viewoid = strdup(PQgetvalue(res2, 0, 1));
-
-           if (strlen(tblinfo[i].viewdef) == 0)
-           {
-               write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
-                         tblinfo[i].relname);
-               exit_nicely();
-           }
-           PQclear(res2);
-       }
-       else
-           tblinfo[i].viewdef = NULL;
-
-       /*
-        * Get non-inherited CHECK constraints, if any.
-        *
-        * Exclude inherited CHECKs from CHECK constraints total. If a
-        * constraint matches by name and condition with a constraint
-        * belonging to a parent class (OR conditions match and both names
-        * start with '$', we assume it was inherited.
-        */
-       if (tblinfo[i].ncheck > 0)
-       {
-           PGresult   *res2;
-           int         i_rcname,
-                       i_rcsrc;
-           int         ntups2;
-           int         i2;
+       agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
+       agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
+       agginfo[i].aggnamespace = findNamespace(PQgetvalue(res, i, i_aggnamespace),
+                                               agginfo[i].oid);
+       agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
+       if (strlen(agginfo[i].usename) == 0)
+           write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
+                     agginfo[i].aggname);
+   }
 
-           if (g_verbose)
-               write_msg(NULL, "finding CHECK constraints for table %s\n",
-                         tblinfo[i].relname);
+   PQclear(res);
 
-           resetPQExpBuffer(query);
-           appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
-                             " where rcrelid = '%s'::oid "
-                             "   and not exists "
-                  "  (select * from pg_relcheck as c, pg_inherits as i "
-                           "    where i.inhrelid = pg_relcheck.rcrelid "
-                             "      and (c.rcname = pg_relcheck.rcname "
-                             "          or (    c.rcname[0] = '$' "
-                        "              and pg_relcheck.rcname[0] = '$')"
-                             "          )"
-                             "      and c.rcsrc = pg_relcheck.rcsrc "
-                             "      and c.rcrelid = i.inhparent) "
-                             " order by rcname ",
-                             tblinfo[i].oid);
-           res2 = PQexec(g_conn, query->data);
-           if (!res2 ||
-               PQresultStatus(res2) != PGRES_TUPLES_OK)
-           {
-               write_msg(NULL, "query to obtain check constraints failed: %s", PQerrorMessage(g_conn));
-               exit_nicely();
-           }
-           ntups2 = PQntuples(res2);
-           if (ntups2 > tblinfo[i].ncheck)
-           {
-               write_msg(NULL, "expected %d check constraints on table \"%s\" but found %d\n",
-                         tblinfo[i].ncheck, tblinfo[i].relname, ntups2);
-               write_msg(NULL, "(The system catalogs might be corrupted.)\n");
-               exit_nicely();
-           }
+   destroyPQExpBuffer(query);
 
-           /*
-            * Set ncheck to the number of *non-inherited* CHECK
-            * constraints
-            */
-           tblinfo[i].ncheck = ntups2;
+   return agginfo;
+}
 
-           i_rcname = PQfnumber(res2, "rcname");
-           i_rcsrc = PQfnumber(res2, "rcsrc");
-           tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
-           for (i2 = 0; i2 < ntups2; i2++)
-           {
-               const char *name = PQgetvalue(res2, i2, i_rcname);
-               const char *expr = PQgetvalue(res2, i2, i_rcsrc);
+/*
+ * getFuncs:
+ *   read all the user-defined functions in the system catalogs and
+ * return them in the FuncInfo* structure
+ *
+ * numFuncs is set to the number of functions read in
+ */
+FuncInfo *
+getFuncs(int *numFuncs)
+{
+   PGresult   *res;
+   int         ntups;
+   int         i;
+   PQExpBuffer query = createPQExpBuffer();
+   FuncInfo   *finfo;
 
-               resetPQExpBuffer(query);
-               if (name[0] != '$')
-               {
-                   appendPQExpBuffer(query, "CONSTRAINT %s ",
-                                     fmtId(name, force_quotes));
-               }
-               appendPQExpBuffer(query, "CHECK (%s)", expr);
-               tblinfo[i].check_expr[i2] = strdup(query->data);
-           }
-           PQclear(res2);
-       }
-       else
-           tblinfo[i].check_expr = NULL;
+   int         i_oid;
+   int         i_proname;
+   int         i_pronamespace;
+   int         i_usename;
+   int         i_prolang;
+   int         i_pronargs;
+   int         i_proargtypes;
+   int         i_prorettype;
 
-       /* Get primary key */
-       if (tblinfo[i].hasindex)
-       {
-           PGresult   *res2;
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
 
-           resetPQExpBuffer(query);
-           appendPQExpBuffer(query,
-                             "SELECT indexrelid FROM pg_index i WHERE i.indisprimary AND i.indrelid = '%s'::oid ",
-                             tblinfo[i].oid);
-           res2 = PQexec(g_conn, query->data);
-           if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
-           {
-               write_msg(NULL, "query to obtain primary key of table \"%s\" failed: %s",
-                         tblinfo[i].relname, PQerrorMessage(g_conn));
-               exit_nicely();
-           }
+   /* find all user-defined funcs */
 
-           if (PQntuples(res2) > 1)
-           {
-               write_msg(NULL, "query to obtain primary key of table \"%s\" produced more than one result\n",
-                         tblinfo[i].relname);
-               exit_nicely();
-           }
+   if (g_fout->remoteVersion >= 70300)
+   {
+       appendPQExpBuffer(query,
+                         "SELECT pg_proc.oid, proname, prolang, "
+                         "pronargs, proargtypes, prorettype, "
+                         "pronamespace, "
+                         "(select usename from pg_user where proowner = usesysid) as usename "
+                         "FROM pg_proc "
+                         "WHERE NOT proisagg "
+                         "AND pronamespace != "
+                         "(select oid from pg_namespace where nspname = 'pg_catalog')");
+   }
+   else
+   {
+       appendPQExpBuffer(query,
+                         "SELECT pg_proc.oid, proname, prolang, "
+                         "pronargs, proargtypes, prorettype, "
+                         "0::oid as pronamespace, "
+                         "(select usename from pg_user where proowner = usesysid) as usename "
+                         "FROM pg_proc "
+                         "where pg_proc.oid > '%u'::oid",
+                         g_last_builtin_oid);
+   }
 
-           if (PQntuples(res2) == 1)
-               tblinfo[i].pkIndexOid = strdup(PQgetvalue(res2, 0, 0));
-           else
-               tblinfo[i].pkIndexOid = NULL;
+   res = PQexec(g_conn, query->data);
+   if (!res ||
+       PQresultStatus(res) != PGRES_TUPLES_OK)
+   {
+       write_msg(NULL, "query to obtain list of functions failed: %s",
+                 PQerrorMessage(g_conn));
+       exit_nicely();
+   }
 
-       }
-       else
-           tblinfo[i].pkIndexOid = NULL;
+   ntups = PQntuples(res);
 
-       /* Get primary key name (if primary key exist) */
-       if (tblinfo[i].pkIndexOid != NULL)
-       {
-           PGresult   *res2;
-           int         n;
+   *numFuncs = ntups;
 
-           resetPQExpBuffer(query);
-           appendPQExpBuffer(query,
-                             "SELECT relname FROM pg_class "
-                             "WHERE oid = '%s'::oid",
-                             tblinfo[i].pkIndexOid);
+   finfo = (FuncInfo *) malloc(ntups * sizeof(FuncInfo));
 
-           res2 = PQexec(g_conn, query->data);
-           if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
-           {
-               write_msg(NULL, "query to obtain name of primary key of table \"%s\" failed: %s",
-                         tblinfo[i].relname, PQerrorMessage(g_conn));
-               exit_nicely();
-           }
+   memset((char *) finfo, 0, ntups * sizeof(FuncInfo));
 
-           n = PQntuples(res2);
-           if (n != 1)
-           {
-               if (n == 0)
-                   write_msg(NULL, "query to obtain name of primary key of table \"%s\" returned no rows\n",
-                             tblinfo[i].relname);
-               else
-                   write_msg(NULL, "query to obtain name of primary key of table \"%s\" returned %d rows\n",
-                             tblinfo[i].relname, n);
-               exit_nicely();
-           }
+   i_oid = PQfnumber(res, "oid");
+   i_proname = PQfnumber(res, "proname");
+   i_pronamespace = PQfnumber(res, "pronamespace");
+   i_usename = PQfnumber(res, "usename");
+   i_prolang = PQfnumber(res, "prolang");
+   i_pronargs = PQfnumber(res, "pronargs");
+   i_proargtypes = PQfnumber(res, "proargtypes");
+   i_prorettype = PQfnumber(res, "prorettype");
 
-           tblinfo[i].primary_key_name =
-               strdup(fmtId(PQgetvalue(res2, 0, 0), force_quotes));
-           if (tblinfo[i].primary_key_name == NULL)
-           {
-               write_msg(NULL, "out of memory\n");
-               exit_nicely();
-           }
-       }
+   for (i = 0; i < ntups; i++)
+   {
+       finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
+       finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));
+       finfo[i].pronamespace = findNamespace(PQgetvalue(res, i, i_pronamespace),
+                                             finfo[i].oid);
+       finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
+       finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
+       finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
+       finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
+       if (finfo[i].nargs == 0)
+           finfo[i].argtypes = NULL;
        else
-           tblinfo[i].primary_key_name = NULL;
-
-       /* Get Triggers */
-       if (tblinfo[i].ntrig > 0)
        {
-           PGresult   *res2;
-           int         i_tgoid,
-                       i_tgname,
-                       i_tgfoid,
-                       i_tgtype,
-                       i_tgnargs,
-                       i_tgargs,
-                       i_tgisconstraint,
-                       i_tgconstrname,
-                       i_tgdeferrable,
-                       i_tgconstrrelid,
-                       i_tgconstrrelname,
-                       i_tginitdeferred;
-           int         ntups2;
-           int         i2;
-
-           if (g_verbose)
-               write_msg(NULL, "finding triggers for table %s\n", tblinfo[i].relname);
+           finfo[i].argtypes = malloc(finfo[i].nargs * sizeof(finfo[i].argtypes[0]));
+           parseNumericArray(PQgetvalue(res, i, i_proargtypes),
+                             finfo[i].argtypes,
+                             finfo[i].nargs);
+       }
 
-           resetPQExpBuffer(query);
-           appendPQExpBuffer(query,
-                      "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, "
-                          "tgisconstraint, tgconstrname, tgdeferrable, "
-                             "tgconstrrelid, tginitdeferred, oid, "
-             "(select relname from pg_class where oid = tgconstrrelid) "
-                             "     as tgconstrrelname "
-                             "from pg_trigger "
-                             "where tgrelid = '%s'::oid ",
-                             tblinfo[i].oid);
-           res2 = PQexec(g_conn, query->data);
-           if (!res2 ||
-               PQresultStatus(res2) != PGRES_TUPLES_OK)
-           {
-               write_msg(NULL, "query to obtain list of triggers failed: %s", PQerrorMessage(g_conn));
-               exit_nicely();
-           }
-           ntups2 = PQntuples(res2);
-           if (ntups2 != tblinfo[i].ntrig)
-           {
-               write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
-                         tblinfo[i].ntrig, tblinfo[i].relname, ntups2);
-               exit_nicely();
-           }
-           i_tgname = PQfnumber(res2, "tgname");
-           i_tgfoid = PQfnumber(res2, "tgfoid");
-           i_tgtype = PQfnumber(res2, "tgtype");
-           i_tgnargs = PQfnumber(res2, "tgnargs");
-           i_tgargs = PQfnumber(res2, "tgargs");
-           i_tgoid = PQfnumber(res2, "oid");
-           i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
-           i_tgconstrname = PQfnumber(res2, "tgconstrname");
-           i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
-           i_tgconstrrelid = PQfnumber(res2, "tgconstrrelid");
-           i_tgconstrrelname = PQfnumber(res2, "tgconstrrelname");
-           i_tginitdeferred = PQfnumber(res2, "tginitdeferred");
-
-           tblinfo[i].triggers = (TrigInfo *) malloc(ntups2 * sizeof(TrigInfo));
-           resetPQExpBuffer(query);
-           for (i2 = 0; i2 < ntups2; i2++)
-           {
-               const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
-               char       *tgfunc = NULL;
-               int2        tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
-               int         tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
-               const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
-               int         tgisconstraint;
-               int         tgdeferrable;
-               int         tginitdeferred;
-               char       *tgconstrrelid;
-               char       *tgname;
-               const char *p;
-               int         findx;
-
-               tgname = PQgetvalue(res2, i2, i_tgname);
-
-               if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
-                   tgisconstraint = 0;
-               else
-                   tgisconstraint = 1;
+       finfo[i].dumped = false;
 
-               if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
-                   tgdeferrable = 0;
-               else
-                   tgdeferrable = 1;
+       if (strlen(finfo[i].usename) == 0)
+           write_msg(NULL, "WARNING: owner of function \"%s\" appears to be invalid\n",
+                     finfo[i].proname);
+   }
 
-               if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
-                   tginitdeferred = 0;
-               else
-                   tginitdeferred = 1;
+   PQclear(res);
 
-               for (findx = 0; findx < numFuncs; findx++)
-               {
-                   if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
-                       finfo[findx].nargs == 0 &&
-                       strcmp(finfo[findx].prorettype, "0") == 0)
-                       break;
-               }
+   destroyPQExpBuffer(query);
 
-               if (findx == numFuncs)
-               {
-                   PGresult   *r;
-                   int         numFuncs;
+   return finfo;
+}
 
-                   /*
-                    * the funcname is an oid which we use to find the
-                    * name of the pg_proc.  We need to do this because
-                    * getFuncs() only reads in the user-defined funcs not
-                    * all the funcs.  We might not find what we want by
-                    * looking in FuncInfo*
-                    */
-                   resetPQExpBuffer(query);
-                   appendPQExpBuffer(query,
-                                     "SELECT proname from pg_proc "
-                                     "where pg_proc.oid = '%s'::oid",
-                                     tgfuncoid);
-
-                   r = PQexec(g_conn, query->data);
-                   if (!r || PQresultStatus(r) != PGRES_TUPLES_OK)
-                   {
-                       write_msg(NULL, "query to obtain procedure name for trigger \"%s\" failed: %s",
-                                 tgname, PQerrorMessage(g_conn));
-                       exit_nicely();
-                   }
+/*
+ * getTables
+ *   read all the user-defined tables (no indexes, no catalogs)
+ * in the system catalogs return them in the TableInfo* structure
+ *
+ * numTables is set to the number of tables read in
+ */
+TableInfo *
+getTables(int *numTables)
+{
+   PGresult   *res;
+   int         ntups;
+   int         i;
+   PQExpBuffer query = createPQExpBuffer();
+   PQExpBuffer delqry = createPQExpBuffer();
+   PQExpBuffer lockquery = createPQExpBuffer();
+   TableInfo  *tblinfo;
 
-                   /* Sanity: Check we got only one tuple */
-                   numFuncs = PQntuples(r);
-                   if (numFuncs != 1)
-                   {
-                       if (numFuncs == 0)
-                           write_msg(NULL, "query to obtain procedure name for trigger \"%s\" (procedure OID %s) returned no rows\n",
-                                     tgname, tgfuncoid);
-                       else
-                           write_msg(NULL, "query to obtain procedure name for trigger \"%s\" (procedure OID %s) returned %d rows\n",
-                                     tgname, tgfuncoid, numFuncs);
-                       exit_nicely();
-                   }
+   int         i_reloid;
+   int         i_relname;
+   int         i_relnamespace;
+   int         i_relkind;
+   int         i_relacl;
+   int         i_usename;
+   int         i_relchecks;
+   int         i_reltriggers;
+   int         i_relhasindex;
+   int         i_relhasrules;
+   int         i_relhasoids;
 
-                   tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
-                   PQclear(r);
-               }
-               else
-                   tgfunc = strdup(finfo[findx].proname);
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
 
-               appendPQExpBuffer(delqry, "DROP TRIGGER %s ", fmtId(tgname, force_quotes));
-               appendPQExpBuffer(delqry, "ON %s;\n",
-                               fmtId(tblinfo[i].relname, force_quotes));
+   /*
+    * Find all the tables (including views and sequences).
+    *
+    * We include system catalogs, so that we can work if a user table
+    * is defined to inherit from a system catalog (pretty weird, but...)
+    *
+    * We ignore tables that are not type 'r' (ordinary relation) or 'S'
+    * (sequence) or 'v' (view).
+    *
+    * Note: in this phase we should collect only a minimal amount of
+    * information about each table, basically just enough to decide if
+    * it is interesting.
+    */
 
-               resetPQExpBuffer(query);
-               if (tgisconstraint)
-               {
-                   appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
-                   appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
-               }
-               else
-               {
-                   appendPQExpBuffer(query, "CREATE TRIGGER ");
-                   appendPQExpBuffer(query, fmtId(tgname, force_quotes));
-               }
-               appendPQExpBufferChar(query, ' ');
-               /* Trigger type */
-               findx = 0;
-               if (TRIGGER_FOR_BEFORE(tgtype))
-                   appendPQExpBuffer(query, "BEFORE");
-               else
-                   appendPQExpBuffer(query, "AFTER");
-               if (TRIGGER_FOR_INSERT(tgtype))
-               {
-                   appendPQExpBuffer(query, " INSERT");
-                   findx++;
-               }
-               if (TRIGGER_FOR_DELETE(tgtype))
-               {
-                   if (findx > 0)
-                       appendPQExpBuffer(query, " OR DELETE");
-                   else
-                       appendPQExpBuffer(query, " DELETE");
-                   findx++;
-               }
-               if (TRIGGER_FOR_UPDATE(tgtype))
-               {
-                   if (findx > 0)
-                       appendPQExpBuffer(query, " OR UPDATE");
-                   else
-                       appendPQExpBuffer(query, " UPDATE");
-               }
-               appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));
+   if (g_fout->remoteVersion >= 70300)
+   {
+       appendPQExpBuffer(query,
+                         "SELECT pg_class.oid, relname, relacl, relkind, "
+                         "relnamespace, "
 
-               if (tgisconstraint)
-               {
-                   tgconstrrelid = PQgetvalue(res2, i2, i_tgconstrrelid);
+                         "(select usename from pg_user where relowner = usesysid) as usename, "
+                         "relchecks, reltriggers, "
+                         "relhasindex, relhasrules, relhasoids "
+                         "from pg_class "
+                         "where relkind in ('%c', '%c', '%c') "
+                         "order by oid",
+                         RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
+   }
+   else if (g_fout->remoteVersion >= 70200)
+   {
+       appendPQExpBuffer(query,
+                         "SELECT pg_class.oid, relname, relacl, relkind, "
+                         "0::oid as relnamespace, "
+                         "(select usename from pg_user where relowner = usesysid) as usename, "
+                         "relchecks, reltriggers, "
+                         "relhasindex, relhasrules, relhasoids "
+                         "from pg_class "
+                         "where relkind in ('%c', '%c', '%c') "
+                         "order by oid",
+                      RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
+   }
+   else if (g_fout->remoteVersion >= 70100)
+   {
+       /* all tables have oids in 7.1 */
+       appendPQExpBuffer(query,
+                       "SELECT pg_class.oid, relname, relacl, relkind, "
+                         "0::oid as relnamespace, "
+                         "(select usename from pg_user where relowner = usesysid) as usename, "
+                         "relchecks, reltriggers, "
+                         "relhasindex, relhasrules, 't'::bool as relhasoids "
+                         "from pg_class "
+                         "where relkind in ('%c', '%c', '%c') "
+                         "order by oid",
+                      RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
+   }
+   else
+   {
+       /*
+        * Before 7.1, view relkind was not set to 'v', so we must check
+        * if we have a view by looking for a rule in pg_rewrite.
+        */
+       appendPQExpBuffer(query,
+                         "SELECT c.oid, relname, relacl, "
+                         "CASE WHEN relhasrules and relkind = 'r' "
+                 "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
+                 "             r.ev_class = c.oid AND r.ev_type = '1') "
+                         "THEN '%c'::\"char\" "
+                         "ELSE relkind END AS relkind,"
+                         "0::oid as relnamespace, "
+                         "(select usename from pg_user where relowner = usesysid) as usename, "
+                         "relchecks, reltriggers, "
+                         "relhasindex, relhasrules, 't'::bool as relhasoids "
+                         "from pg_class c "
+                         "where relkind in ('%c', '%c') "
+                         "order by oid",
+                         RELKIND_VIEW,
+                         RELKIND_RELATION, RELKIND_SEQUENCE);
+   }
 
-                   if (strcmp(tgconstrrelid, "0") != 0)
-                   {
+   res = PQexec(g_conn, query->data);
+   if (!res ||
+       PQresultStatus(res) != PGRES_TUPLES_OK)
+   {
+       write_msg(NULL, "query to obtain list of tables failed: %s",
+                 PQerrorMessage(g_conn));
+       exit_nicely();
+   }
 
-                       if (PQgetisnull(res2, i2, i_tgconstrrelname))
-                       {
-                           write_msg(NULL, "query produced NULL referenced table name for foreign key trigger \"%s\" on table \"%s\" (oid of table: %s)\n",
-                             tgname, tblinfo[i].relname, tgconstrrelid);
-                           exit_nicely();
-                       }
+   ntups = PQntuples(res);
 
-                       appendPQExpBuffer(query, " FROM %s",
-                                         fmtId(PQgetvalue(res2, i2, i_tgconstrrelname), force_quotes));
-                   }
-                   if (!tgdeferrable)
-                       appendPQExpBuffer(query, " NOT");
-                   appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
-                   if (tginitdeferred)
-                       appendPQExpBuffer(query, "DEFERRED");
-                   else
-                       appendPQExpBuffer(query, "IMMEDIATE");
+   *numTables = ntups;
 
-               }
+   /*
+    * Extract data from result and lock dumpable tables.  We do the
+    * locking before anything else, to minimize the window wherein a
+    * table could disappear under us.
+    *
+    * Note that we have to save info about all tables here, even when
+    * dumping only one, because we don't yet know which tables might be
+    * inheritance ancestors of the target table.
+    */
+   tblinfo = (TableInfo *) malloc(ntups * sizeof(TableInfo));
+   memset(tblinfo, 0, ntups * sizeof(TableInfo));
 
-               appendPQExpBuffer(query, " FOR EACH ROW");
-               appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
-                                 fmtId(tgfunc, force_quotes));
-               for (findx = 0; findx < tgnargs; findx++)
-               {
-                   const char *s;
+   i_reloid = PQfnumber(res, "oid");
+   i_relname = PQfnumber(res, "relname");
+   i_relnamespace = PQfnumber(res, "relnamespace");
+   i_relacl = PQfnumber(res, "relacl");
+   i_relkind = PQfnumber(res, "relkind");
+   i_usename = PQfnumber(res, "usename");
+   i_relchecks = PQfnumber(res, "relchecks");
+   i_reltriggers = PQfnumber(res, "reltriggers");
+   i_relhasindex = PQfnumber(res, "relhasindex");
+   i_relhasrules = PQfnumber(res, "relhasrules");
+   i_relhasoids = PQfnumber(res, "relhasoids");
 
-                   for (p = tgargs;;)
-                   {
-                       p = strchr(p, '\\');
-                       if (p == NULL)
-                       {
-                           write_msg(NULL, "bad argument string (%s) for trigger \"%s\" on table \"%s\"\n",
-                                     PQgetvalue(res2, i2, i_tgargs),
-                                     tgname,
-                                     tblinfo[i].relname);
-                           exit_nicely();
-                       }
-                       p++;
-                       if (*p == '\\')
-                       {
-                           p++;
-                           continue;
-                       }
-                       if (p[0] == '0' && p[1] == '0' && p[2] == '0')
-                           break;
-                   }
-                   p--;
-                   appendPQExpBufferChar(query, '\'');
-                   for (s = tgargs; s < p;)
-                   {
-                       if (*s == '\'')
-                           appendPQExpBufferChar(query, '\\');
-                       appendPQExpBufferChar(query, *s++);
-                   }
-                   appendPQExpBufferChar(query, '\'');
-                   appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
-                   tgargs = p + 4;
-               }
-               appendPQExpBuffer(query, ");\n");
+   for (i = 0; i < ntups; i++)
+   {
+       tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
+       tblinfo[i].relname = strdup(PQgetvalue(res, i, i_relname));
+       tblinfo[i].relnamespace = findNamespace(PQgetvalue(res, i, i_relnamespace),
+                                               tblinfo[i].oid);
+       tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
+       tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
+       tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
+       tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
+       tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
+       tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
+       tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
+       tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
 
-               tblinfo[i].triggers[i2].tgsrc = strdup(query->data);
+       /* other fields were zeroed above */
 
-               /*** Initialize trcomments and troids ***/
+       /*
+        * Decide whether we want to dump this table.
+        */
+       selectDumpableTable(&tblinfo[i]);
+       tblinfo[i].interesting = tblinfo[i].dump;
 
-               resetPQExpBuffer(query);
-               appendPQExpBuffer(query, "TRIGGER %s ",
-                                 fmtId(tgname, force_quotes));
-               appendPQExpBuffer(query, "ON %s",
-                               fmtId(tblinfo[i].relname, force_quotes));
-               tblinfo[i].triggers[i2].tgcomment = strdup(query->data);
-               tblinfo[i].triggers[i2].oid = strdup(PQgetvalue(res2, i2, i_tgoid));
-               tblinfo[i].triggers[i2].tgname = strdup(fmtId(tgname, false));
-               tblinfo[i].triggers[i2].tgdel = strdup(delqry->data);
+       /*
+        * Read-lock target tables to make sure they aren't DROPPED or
+        * altered in schema before we get around to dumping them.
+        *
+        * Note that we don't explicitly lock parents of the target tables;
+        * we assume our lock on the child is enough to prevent schema
+        * alterations to parent tables.
+        *
+        * NOTE: it'd be kinda nice to lock views and sequences too, not only
+        * plain tables, but the backend doesn't presently allow that.
+        */
+       if (tblinfo[i].dump && tblinfo[i].relkind == RELKIND_RELATION)
+       {
+           PGresult   *lres;
 
-               if (tgfunc)
-                   free(tgfunc);
+           resetPQExpBuffer(lockquery);
+           appendPQExpBuffer(lockquery,
+                             "LOCK TABLE %s IN ACCESS SHARE MODE",
+                             fmtQualifiedId(tblinfo[i].relnamespace->nspname,
+                                            tblinfo[i].relname));
+           lres = PQexec(g_conn, lockquery->data);
+           if (!lres || PQresultStatus(lres) != PGRES_COMMAND_OK)
+           {
+               write_msg(NULL, "Attempt to lock table \"%s\" failed.  %s",
+                         tblinfo[i].relname, PQerrorMessage(g_conn));
+               exit_nicely();
            }
-           PQclear(res2);
+           PQclear(lres);
        }
-       else
-           tblinfo[i].triggers = NULL;
 
+       /* Emit notice if join for owner failed */
+       if (strlen(tblinfo[i].usename) == 0)
+           write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
+                     tblinfo[i].relname);
    }
 
+   PQclear(res);
    destroyPQExpBuffer(query);
    destroyPQExpBuffer(delqry);
    destroyPQExpBuffer(lockquery);
@@ -2783,7 +2158,7 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs, const char *tablename)
  *   read all the inheritance information
  * from the system catalogs return them in the InhInfo* structure
  *
- * numInherits is set to the number of tables read in
+ * numInherits is set to the number of pairs read in
  */
 InhInfo *
 getInherits(int *numInherits)
@@ -2797,6 +2172,9 @@ getInherits(int *numInherits)
    int         i_inhrelid;
    int         i_inhparent;
 
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
+
    /* find all the inheritance information */
 
    appendPQExpBuffer(query, "SELECT inhrelid, inhparent from pg_inherits");
@@ -2834,7 +2212,7 @@ getInherits(int *numInherits)
 
 /*
  * getTableAttrs -
- *   for each table in tblinfo, read its attributes types and names
+ *   for each interesting table, read its attributes types and names
  *
  * this is implemented in a very inefficient way right now, looping
  * through the tblinfo and doing a join per table to find the attrs and their
@@ -2849,25 +2227,39 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                j;
    PQExpBuffer q = createPQExpBuffer();
    int         i_attname;
-   int         i_typname;
+   int         i_atttypname;
    int         i_atttypmod;
    int         i_attnotnull;
    int         i_atthasdef;
-   int         i_atttypedefn;
    PGresult   *res;
    int         ntups;
+   bool        hasdefaults;
 
    for (i = 0; i < numTables; i++)
    {
+       /* Don't bother to collect info for sequences */
        if (tblinfo[i].relkind == RELKIND_SEQUENCE)
            continue;
 
+       /* Don't bother with uninteresting tables, either */
+       if (!tblinfo[i].interesting)
+           continue;
+
+       /*
+        * Make sure we are in proper schema for this table; this allows
+        * correct retrieval of formatted type names and default exprs
+        */
+       selectSourceSchema(tblinfo[i].relnamespace->nspname);
+
        /* find all the user attributes and their types */
-       /* we must read the attribute names in attribute number order! */
 
        /*
+        * we must read the attribute names in attribute number order!
         * because we will use the attnum to index into the attnames array
-        * later
+        * later.  We actually ask to order by "attrelid, attnum" because
+        * (at least up to 7.3) the planner is not smart enough to realize
+        * it needn't re-sort the output of an indexscan on
+        * pg_attribute_relid_attnum_index.
         */
        if (g_verbose)
            write_msg(NULL, "finding the columns and types for table %s\n",
@@ -2875,33 +2267,27 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 
        resetPQExpBuffer(q);
 
-       if (g_fout->remoteVersion < 70100)
+       if (g_fout->remoteVersion >= 70100)
        {
-           /* Fake the LOJ below */
-           appendPQExpBuffer(q,
-                "  SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
-               "        a.attnotnull, a.atthasdef, NULL as atttypedefn "
-                             "    from pg_attribute a, pg_type t "
-                             "    where a.attrelid = '%s'::oid "
-                             "        and a.attnum > 0 "
-                             "        and a.atttypid = t.oid "
-                             " UNION ALL SELECT a.attnum, a.attname, NULL as typname, a.atttypmod, "
-               "        a.attnotnull, a.atthasdef, NULL as atttypedefn "
-                             "    from pg_attribute a "
-                             "    where a.attrelid = '%s'::oid "
-                             "        and a.attnum > 0 "
-                             "        and Not Exists(Select * From pg_type t where a.atttypid = t.oid)"
-                             "    order by attnum",
-                             tblinfo[i].oid, tblinfo[i].oid);
-
+           appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
+                             "attnotnull, atthasdef, "
+                             "format_type(atttypid,atttypmod) as atttypname "
+                             "from pg_attribute a "
+                             "where attrelid = '%s'::oid "
+                             "and attnum > 0::int2 "
+                             "order by attrelid, attnum",
+                             tblinfo[i].oid);
        }
        else
        {
-           appendPQExpBuffer(q, "SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
-                             "a.attnotnull, a.atthasdef, format_type(a.atttypid, a.atttypmod) as atttypedefn "
-                             "from pg_attribute a LEFT OUTER JOIN pg_type t ON a.atttypid = t.oid "
-                             "where a.attrelid = '%s'::oid "
-                             "and a.attnum > 0 order by attnum",
+           /* format_type not available before 7.1 */
+           appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
+                             "attnotnull, atthasdef, "
+                             "(select typname from pg_type where oid = atttypid) as atttypname "
+                             "from pg_attribute a "
+                             "where attrelid = '%s'::oid "
+                             "and attnum > 0::int2 "
+                             "order by attrelid, attnum",
                              tblinfo[i].oid);
        }
 
@@ -2916,82 +2302,87 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
        ntups = PQntuples(res);
 
        i_attname = PQfnumber(res, "attname");
-       i_typname = PQfnumber(res, "typname");
+       i_atttypname = PQfnumber(res, "atttypname");
        i_atttypmod = PQfnumber(res, "atttypmod");
        i_attnotnull = PQfnumber(res, "attnotnull");
        i_atthasdef = PQfnumber(res, "atthasdef");
-       i_atttypedefn = PQfnumber(res, "atttypedefn");
 
        tblinfo[i].numatts = ntups;
        tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
-       tblinfo[i].atttypedefns = (char **) malloc(ntups * sizeof(char *));
-       tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
+       tblinfo[i].atttypnames = (char **) malloc(ntups * sizeof(char *));
        tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
-       tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
-       tblinfo[i].inhAttrDef = (int *) malloc(ntups * sizeof(int));
-       tblinfo[i].inhNotNull = (int *) malloc(ntups * sizeof(int));
        tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
        tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
-       tblinfo[i].parentRels = NULL;
-       tblinfo[i].numParents = 0;
+       tblinfo[i].inhAttrs = (bool *) malloc(ntups * sizeof(bool));
+       tblinfo[i].inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
+       tblinfo[i].inhNotNull = (bool *) malloc(ntups * sizeof(bool));
+       hasdefaults = false;
+
        for (j = 0; j < ntups; j++)
        {
-           /* Sanity check on LOJ */
-           if (PQgetisnull(res, j, i_typname))
-           {
-               write_msg(NULL, "query produced NULL name for data type of column %d of table %s\n",
-                         j + 1, tblinfo[i].relname);
-               exit_nicely();
-           }
-
            tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
-           tblinfo[i].atttypedefns[j] = strdup(PQgetvalue(res, j, i_atttypedefn));
-           tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
+           tblinfo[i].atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
            tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
-           tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
-                                        * flagInhAttrs() */
-           tblinfo[i].inhAttrDef[j] = 0;
-           tblinfo[i].inhNotNull[j] = 0;
-
-           tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't') ? true : false;
+           tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
+           tblinfo[i].adef_expr[j] = NULL; /* fix below */
            if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
-           {
-               PGresult   *res2;
-               int         numAttr;
+               hasdefaults = true;
+           /* these flags will be set in flagInhAttrs() */
+           tblinfo[i].inhAttrs[j] = false;
+           tblinfo[i].inhAttrDef[j] = false;
+           tblinfo[i].inhNotNull[j] = false;
+       }
 
-               if (g_verbose)
-                   write_msg(NULL, "finding DEFAULT expression for column %s\n",
-                             tblinfo[i].attnames[j]);
+       PQclear(res);
 
-               resetPQExpBuffer(q);
-               appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
-                            "where adrelid = '%s'::oid and adnum = %d ",
-                                 tblinfo[i].oid, j + 1);
-               res2 = PQexec(g_conn, q->data);
-               if (!res2 ||
-                   PQresultStatus(res2) != PGRES_TUPLES_OK)
-               {
-                   write_msg(NULL, "query to get column default value failed: %s",
-                             PQerrorMessage(g_conn));
-                   exit_nicely();
-               }
+       if (hasdefaults)
+       {
+           int         numDefaults;
+
+           if (g_verbose)
+               write_msg(NULL, "finding DEFAULT expressions for table %s\n",
+                         tblinfo[i].relname);
+
+           resetPQExpBuffer(q);
+           if (g_fout->remoteVersion >= 70200)
+           {
+               appendPQExpBuffer(q, "SELECT adnum, "
+                                 "pg_get_expr(adbin, adrelid) AS adsrc "
+                                 "FROM pg_attrdef "
+                                 "WHERE adrelid = '%s'::oid",
+                                 tblinfo[i].oid);
+           }
+           else
+           {
+               /* no pg_get_expr, so must rely on adsrc */
+               appendPQExpBuffer(q, "SELECT adnum, adsrc FROM pg_attrdef "
+                                 "WHERE adrelid = '%s'::oid",
+                                 tblinfo[i].oid);
+           }
+           res = PQexec(g_conn, q->data);
+           if (!res ||
+               PQresultStatus(res) != PGRES_TUPLES_OK)
+           {
+               write_msg(NULL, "query to get column default values failed: %s",
+                         PQerrorMessage(g_conn));
+               exit_nicely();
+           }
 
-               /* Sanity: Check we got only one tuple */
-               numAttr = PQntuples(res2);
-               if (numAttr != 1)
+           numDefaults = PQntuples(res);
+           for (j = 0; j < numDefaults; j++)
+           {
+               int     adnum = atoi(PQgetvalue(res, j, 0));
+
+               if (adnum <= 0 || adnum > ntups)
                {
-                   write_msg(NULL, "query to get default value for column \"%s\" returned %d rows; expected 1\n",
-                             tblinfo[i].attnames[j], numAttr);
+                   write_msg(NULL, "bogus adnum value %d for table %s\n",
+                             adnum, tblinfo[i].relname);
                    exit_nicely();
                }
-
-               tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
-               PQclear(res2);
+               tblinfo[i].adef_expr[adnum-1] = strdup(PQgetvalue(res, j, 1));
            }
-           else
-               tblinfo[i].adef_expr[j] = NULL;
+           PQclear(res);
        }
-       PQclear(res);
    }
 
    destroyPQExpBuffer(q);
@@ -2999,121 +2390,23 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 
 
 /*
- * getIndexes
- *   read all the user-defined indexes information
- * from the system catalogs return them in the InhInfo* structure
- *
- * numIndexes is set to the number of indexes read in
- *
- *
- */
-IndInfo *
-getIndexes(int *numIndexes)
-{
-   int         i;
-   PQExpBuffer query = createPQExpBuffer();
-   PGresult   *res;
-   int         ntups;
-   IndInfo    *indinfo;
-
-   int         i_indexreloid;
-   int         i_indreloid;
-   int         i_indexrelname;
-   int         i_indrelname;
-   int         i_indexdef;
-   int         i_indisprimary;
-   int         i_indnkeys;
-   int         i_indkey;
-
-   /*
-    * find all the user-defined indexes.
-    *
-    * Notice we skip indexes on system classes
-    *
-    * XXXX: Use LOJ
-    */
-
-   appendPQExpBuffer(query,
-                     "SELECT i.indexrelid as indexreloid, "
-                     "i.indrelid as indreloid, "
-                     "t1.relname as indexrelname, t2.relname as indrelname, "
-                     "pg_get_indexdef(i.indexrelid) as indexdef, "
-                     "i.indisprimary, i.indkey, "
-                     "CASE WHEN i.indproc <> 0 "
-                     "  THEN (SELECT pronargs FROM pg_proc WHERE pg_proc.oid = i.indproc) "
-                     "  ELSE t1.relnatts END as indnkeys "
-                     "FROM pg_index i, pg_class t1, pg_class t2 "
-                     "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
-                     "and i.indexrelid > '%u'::oid "
-                     "and t2.relname !~ '^pg_' ",
-                     g_last_builtin_oid);
-
-   if (g_fout->remoteVersion < 70100)
-       appendPQExpBuffer(query, " and t2.relkind != 'l'");
-
-   res = PQexec(g_conn, query->data);
-   if (!res ||
-       PQresultStatus(res) != PGRES_TUPLES_OK)
-   {
-       write_msg(NULL, "query to obtain list of indexes failed: %s", PQerrorMessage(g_conn));
-       exit_nicely();
-   }
-
-   ntups = PQntuples(res);
-
-   *numIndexes = ntups;
-
-   indinfo = (IndInfo *) malloc(ntups * sizeof(IndInfo));
-
-   memset((char *) indinfo, 0, ntups * sizeof(IndInfo));
-
-   i_indexreloid = PQfnumber(res, "indexreloid");
-   i_indreloid = PQfnumber(res, "indreloid");
-   i_indexrelname = PQfnumber(res, "indexrelname");
-   i_indrelname = PQfnumber(res, "indrelname");
-   i_indexdef = PQfnumber(res, "indexdef");
-   i_indisprimary = PQfnumber(res, "indisprimary");
-   i_indnkeys = PQfnumber(res, "indnkeys");
-   i_indkey = PQfnumber(res, "indkey");
-
-   for (i = 0; i < ntups; i++)
-   {
-       indinfo[i].indexreloid = strdup(PQgetvalue(res, i, i_indexreloid));
-       indinfo[i].indreloid = strdup(PQgetvalue(res, i, i_indreloid));
-       indinfo[i].indexrelname = strdup(PQgetvalue(res, i, i_indexrelname));
-       indinfo[i].indrelname = strdup(PQgetvalue(res, i, i_indrelname));
-       indinfo[i].indexdef = strdup(PQgetvalue(res, i, i_indexdef));
-       indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary));
-       indinfo[i].indnkeys = atoi(PQgetvalue(res, i, i_indnkeys));
-       indinfo[i].indkey = malloc(indinfo[i].indnkeys * sizeof(indinfo[i].indkey[0]));
-       parseNumericArray(PQgetvalue(res, i, i_indkey),
-                         indinfo[i].indkey,
-                         indinfo[i].indnkeys);
-   }
-   PQclear(res);
-
-   destroyPQExpBuffer(query);
-
-   return indinfo;
-}
-
-/*------------------------------------------------------------------
  * dumpComment --
  *
  * This routine is used to dump any comments associated with the
  * oid handed to this routine. The routine takes a constant character
  * string for the target part of the comment-creation command, plus
- * OID, class name, and subid which are the primary key for pg_description.
+ * the namespace and owner of the object (for labeling the ArchiveEntry),
+ * plus OID, class name, and subid which are the lookup key for pg_description.
  * If a matching pg_description entry is found, it is dumped.
  * Additional dependencies can be passed for the comment, too --- this is
  * needed for VIEWs, whose comments are filed under the table OID but
  * which are dumped in order by their rule OID.
- *------------------------------------------------------------------
-*/
+ */
 
 static void
-dumpComment(Archive *fout, const char *target, const char *oid,
-           const char *classname, int subid,
+dumpComment(Archive *fout, const char *target,
+           const char *namespace, const char *owner,
+           const char *oid, const char *classname, int subid,
            const char *((*deps)[]))
 {
    PGresult   *res;
@@ -3124,11 +2417,24 @@ dumpComment(Archive *fout, const char *target, const char *oid,
    if (dataOnly)
        return;
 
+   /*
+    * Note we do NOT change source schema here; preserve the caller's
+    * setting, instead.
+    */
+
    /*** Build query to find comment ***/
 
    query = createPQExpBuffer();
 
-   if (fout->remoteVersion >= 70200)
+   if (fout->remoteVersion >= 70300)
+   {
+       appendPQExpBuffer(query, "SELECT description FROM pg_catalog.pg_description "
+                         "WHERE objoid = '%s'::oid and classoid = "
+                         "'pg_catalog.%s'::regclass "
+                         "and objsubid = %d",
+                         oid, classname, subid);
+   }
+   else if (fout->remoteVersion >= 70200)
    {
        appendPQExpBuffer(query, "SELECT description FROM pg_description "
                          "WHERE objoid = '%s'::oid and classoid = "
@@ -3163,27 +2469,140 @@ dumpComment(Archive *fout, const char *target, const char *oid,
                            PASS_LFTAB);
        appendPQExpBuffer(query, ";\n");
 
-       ArchiveEntry(fout, oid, target, "COMMENT", deps,
-                    query->data, "" /* Del */ ,
-                    "" /* Copy */ , "" /* Owner */ , NULL, NULL);
-   }
+       ArchiveEntry(fout, oid, target, namespace, owner,
+                    "COMMENT", deps,
+                    query->data, "", NULL, NULL, NULL);
+   }
+
+   PQclear(res);
+   destroyPQExpBuffer(query);
+}
+
+/*
+ * dumpTableComment --
+ *
+ * As above, but dump comments for both the specified table (or view)
+ * and its columns.  For speed, we want to do this with only one query.
+ */
+static void
+dumpTableComment(Archive *fout, TableInfo *tbinfo,
+                const char *reltypename,
+                const char *((*deps)[]))
+{
+   PGresult   *res;
+   PQExpBuffer query;
+   PQExpBuffer target;
+   int         i_description;
+   int         i_objsubid;
+   int         ntups;
+   int         i;
+
+   /* Comments are SCHEMA not data */
+   if (dataOnly)
+       return;
+
+   /*
+    * Note we do NOT change source schema here; preserve the caller's
+    * setting, instead.
+    */
+
+   /*** Build query to find comments ***/
+
+   query = createPQExpBuffer();
+   target = createPQExpBuffer();
+
+   if (fout->remoteVersion >= 70300)
+   {
+       appendPQExpBuffer(query, "SELECT description, objsubid FROM pg_catalog.pg_description "
+                         "WHERE objoid = '%s'::oid and classoid = "
+                         "'pg_catalog.pg_class'::regclass "
+                         "ORDER BY objoid, classoid, objsubid",
+                         tbinfo->oid);
+   }
+   else if (fout->remoteVersion >= 70200)
+   {
+       appendPQExpBuffer(query, "SELECT description, objsubid FROM pg_description "
+                         "WHERE objoid = '%s'::oid and classoid = "
+                      "(SELECT oid FROM pg_class where relname = 'pg_class') "
+                         "ORDER BY objoid, classoid, objsubid",
+                         tbinfo->oid);
+   }
+   else
+   {
+       /* Note: this will fail to find attribute comments in pre-7.2... */
+       appendPQExpBuffer(query, "SELECT description, 0 as objsubid FROM pg_description WHERE objoid = '%s'::oid", tbinfo->oid);
+   }
+
+   /*** Execute query ***/
+
+   res = PQexec(g_conn, query->data);
+   if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
+   {
+       write_msg(NULL, "query to get comments on table %s failed: %s",
+                 tbinfo->relname, PQerrorMessage(g_conn));
+       exit_nicely();
+   }
+   i_description = PQfnumber(res, "description");
+   i_objsubid = PQfnumber(res, "objsubid");
+
+   /*** If comments exist, build COMMENT ON statements ***/
+
+   ntups = PQntuples(res);
+   for (i = 0; i < ntups; i++)
+   {
+       const char *descr = PQgetvalue(res, i, i_description);
+       int objsubid = atoi(PQgetvalue(res, i, i_objsubid));
+
+       if (objsubid == 0)
+       {
+           resetPQExpBuffer(target);
+           appendPQExpBuffer(target, "%s %s", reltypename,
+                             fmtId(tbinfo->relname, force_quotes));
+
+           resetPQExpBuffer(query);
+           appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
+           formatStringLiteral(query, descr, PASS_LFTAB);
+           appendPQExpBuffer(query, ";\n");
+
+           ArchiveEntry(fout, tbinfo->oid, target->data,
+                        tbinfo->relnamespace->nspname, tbinfo->usename,
+                        "COMMENT", deps,
+                        query->data, "", NULL, NULL, NULL);
+       }
+       else if (objsubid > 0 && objsubid <= tbinfo->numatts)
+       {
+           resetPQExpBuffer(target);
+           appendPQExpBuffer(target, "COLUMN %s.",
+                             fmtId(tbinfo->relname, force_quotes));
+           appendPQExpBuffer(target, "%s",
+                             fmtId(tbinfo->attnames[objsubid-1],
+                                   force_quotes));
 
-   /*** Clear the statement buffer and return ***/
+           resetPQExpBuffer(query);
+           appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
+           formatStringLiteral(query, descr, PASS_LFTAB);
+           appendPQExpBuffer(query, ";\n");
+
+           ArchiveEntry(fout, tbinfo->oid, target->data,
+                        tbinfo->relnamespace->nspname, tbinfo->usename,
+                        "COMMENT", deps,
+                        query->data, "", NULL, NULL, NULL);
+       }
+   }
 
    PQclear(res);
    destroyPQExpBuffer(query);
+   destroyPQExpBuffer(target);
 }
 
-/*------------------------------------------------------------------
+/*
  * dumpDBComment --
  *
  * This routine is used to dump any comments associated with the
  * database to which we are currently connected. If the user chose
  * to dump the schema of the database, then this is the first
  * statement issued.
- *------------------------------------------------------------------
-*/
-
+ */
 void
 dumpDBComment(Archive *fout)
 {
@@ -3191,6 +2610,9 @@ dumpDBComment(Archive *fout)
    PQExpBuffer query;
    int         i_oid;
 
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
+
    /*** Build query to find comment ***/
 
    query = createPQExpBuffer();
@@ -3214,19 +2636,303 @@ dumpDBComment(Archive *fout)
        i_oid = PQfnumber(res, "oid");
        resetPQExpBuffer(query);
        appendPQExpBuffer(query, "DATABASE %s", fmtId(PQdb(g_conn), force_quotes));
-       dumpComment(fout, query->data, PQgetvalue(res, 0, i_oid),
-                   "pg_database", 0, NULL);
+       dumpComment(fout, query->data, NULL, "",
+                   PQgetvalue(res, 0, i_oid), "pg_database", 0, NULL);
+   }
+
+   PQclear(res);
+   destroyPQExpBuffer(query);
+}
+
+/*
+ * dumpNamespaces
+ *    writes out to fout the queries to recreate user-defined namespaces
+ */
+void
+dumpNamespaces(Archive *fout, NamespaceInfo *nsinfo, int numNamespaces)
+{
+   PQExpBuffer q = createPQExpBuffer();
+   PQExpBuffer delq = createPQExpBuffer();
+   int         i;
+
+   for (i = 0; i < numNamespaces; i++)
+   {
+       /* skip if not to be dumped */
+       if (!nsinfo[i].dump)
+           continue;
+
+       /* don't dump dummy namespace from pre-7.3 source */
+       if (strlen(nsinfo[i].nspname) == 0)
+           continue;
+
+       /* quick hack: don't dump CREATE SCHEMA for public namespace */
+       /* XXX need a better idea */
+       if (strcmp(nsinfo[i].nspname, "public") == 0)
+           continue;
+
+       resetPQExpBuffer(q);
+       resetPQExpBuffer(delq);
+
+#ifdef NOTYET                  /* suppress till DROP SCHEMA works */
+       appendPQExpBuffer(delq, "DROP SCHEMA %s;\n",
+                         fmtId(nsinfo[i].nspname, force_quotes));
+#endif
+
+       appendPQExpBuffer(q, "CREATE SCHEMA %s;\n",
+                         fmtId(nsinfo[i].nspname, force_quotes));
+
+       ArchiveEntry(fout, nsinfo[i].oid, nsinfo[i].nspname,
+                    NULL,
+                    nsinfo[i].usename, "SCHEMA", NULL,
+                    q->data, delq->data, NULL, NULL, NULL);
+
+#ifdef NOTYET                  /* suppress till COMMENT ON SCHEMA works */
+       /*** Dump Schema Comments ***/
+       resetPQExpBuffer(q);
+       appendPQExpBuffer(q, "SCHEMA %s",
+                         fmtId(nsinfo[i].nspname, force_quotes));
+       dumpComment(fout, q->data,
+                   NULL, nsinfo[i].usename,
+                   nsinfo[i].oid, "pg_namespace", 0, NULL);
+#endif
+   }
+
+   destroyPQExpBuffer(q);
+   destroyPQExpBuffer(delq);
+}
+
+/*
+ * dumpOneBaseType
+ *    writes out to fout the queries to recreate a user-defined base type
+ *    as requested by dumpTypes
+ */
+static void
+dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
+               FuncInfo *g_finfo, int numFuncs,
+               TypeInfo *g_tinfo, int numTypes)
+{
+   PQExpBuffer q = createPQExpBuffer();
+   PQExpBuffer delq = createPQExpBuffer();
+   PQExpBuffer query = createPQExpBuffer();
+   PGresult   *res;
+   int         ntups;
+   int         funcInd;
+   char       *typlen;
+   char       *typprtlen;
+   char       *typinput;
+   char       *typoutput;
+   char       *typreceive;
+   char       *typsend;
+   char       *typinputoid;
+   char       *typoutputoid;
+   char       *typreceiveoid;
+   char       *typsendoid;
+   char       *typdelim;
+   char       *typdefault;
+   char       *typbyval;
+   char       *typalign;
+   char       *typstorage;
+   const char *((*deps)[]);
+   int         depIdx = 0;
+
+   deps = malloc(sizeof(char *) * 10);
+
+   /* Set proper schema search path so regproc references list correctly */
+   selectSourceSchema(tinfo->typnamespace->nspname);
+
+   /* Fetch type-specific details */
+   if (fout->remoteVersion >= 70100)
+   {
+       appendPQExpBuffer(query, "SELECT typlen, typprtlen, "
+                         "typinput, typoutput, typreceive, typsend, "
+                         "typinput::oid as typinputoid, "
+                         "typoutput::oid as typoutputoid, "
+                         "typreceive::oid as typreceiveoid, "
+                         "typsend::oid as typsendoid, "
+                         "typdelim, typdefault, typbyval, typalign, "
+                         "typstorage "
+                         "FROM pg_type "
+                         "WHERE oid = '%s'::oid",
+                         tinfo->oid);
+   }
+   else
+   {
+       appendPQExpBuffer(query, "SELECT typlen, typprtlen, "
+                         "typinput, typoutput, typreceive, typsend, "
+                         "typinput::oid as typinputoid, "
+                         "typoutput::oid as typoutputoid, "
+                         "typreceive::oid as typreceiveoid, "
+                         "typsend::oid as typsendoid, "
+                         "typdelim, typdefault, typbyval, typalign, "
+                         "'p'::char as typstorage "
+                         "FROM pg_type "
+                         "WHERE oid = '%s'::oid",
+                         tinfo->oid);
+   }
+
+   res = PQexec(g_conn, query->data);
+   if (!res ||
+       PQresultStatus(res) != PGRES_TUPLES_OK)
+   {
+       write_msg(NULL, "query to obtain type information for %s failed: %s",
+                 tinfo->typname, PQerrorMessage(g_conn));
+       exit_nicely();
+   }
+
+   /* Expecting a single result only */
+   ntups = PQntuples(res);
+   if (ntups != 1)
+   {
+       write_msg(NULL, "Got %d rows instead of one from: %s",
+                 ntups, query->data);
+       exit_nicely();
+   }
+
+   typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
+   typprtlen = PQgetvalue(res, 0, PQfnumber(res, "typprtlen"));
+   typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
+   typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
+   typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
+   typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
+   typinputoid = PQgetvalue(res, 0, PQfnumber(res, "typinputoid"));
+   typoutputoid = PQgetvalue(res, 0, PQfnumber(res, "typoutputoid"));
+   typreceiveoid = PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid"));
+   typsendoid = PQgetvalue(res, 0, PQfnumber(res, "typsendoid"));
+   typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
+   if (PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
+       typdefault = NULL;
+   else
+       typdefault = strdup(PQgetvalue(res, 0, PQfnumber(res, "typdefault")));
+   typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
+   typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
+   typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
+
+   /*
+    * Before we create a type, we need to create the input and output
+    * functions for it, if they haven't been created already.  So make
+    * sure there are dependency entries for this.  But don't include
+    * dependencies if the functions aren't going to be dumped.
+    */
+   funcInd = findFuncByOid(g_finfo, numFuncs, typinputoid);
+   if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
+       (*deps)[depIdx++] = strdup(typinputoid);
+
+   funcInd = findFuncByOid(g_finfo, numFuncs, typoutputoid);
+   if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
+       (*deps)[depIdx++] = strdup(typoutputoid);
+
+   if (strcmp(typreceiveoid, typinputoid) != 0)
+   {
+       funcInd = findFuncByOid(g_finfo, numFuncs, typreceiveoid);
+       if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
+           (*deps)[depIdx++] = strdup(typreceiveoid);
+   }
+
+   if (strcmp(typsendoid, typoutputoid) != 0)
+   {
+       funcInd = findFuncByOid(g_finfo, numFuncs, typsendoid);
+       if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
+           (*deps)[depIdx++] = strdup(typsendoid);
+   }
+
+   appendPQExpBuffer(delq, "DROP TYPE %s;\n",
+                     fmtId(tinfo->typname, force_quotes));
+
+   appendPQExpBuffer(q,
+                     "CREATE TYPE %s "
+                     "( internallength = %s, externallength = %s,",
+                     fmtId(tinfo->typname, force_quotes),
+                     (strcmp(typlen, "-1") == 0) ? "variable" : typlen,
+                     (strcmp(typprtlen, "-1") == 0) ? "variable" : typprtlen);
+
+   if (fout->remoteVersion >= 70300)
+   {
+       /* regproc result is correctly quoted in 7.3 */
+       appendPQExpBuffer(q, " input = %s, output = %s, "
+                         "send = %s, receive = %s",
+                         typinput, typoutput, typsend, typreceive);
+   }
+   else
+   {
+       /* regproc delivers an unquoted name before 7.3 */
+       /* cannot combine these because fmtId uses static result area */
+       appendPQExpBuffer(q, " input = %s,",
+                         fmtId(typinput, force_quotes));
+       appendPQExpBuffer(q, " output = %s,",
+                         fmtId(typoutput, force_quotes));
+       appendPQExpBuffer(q, " send = %s,",
+                         fmtId(typsend, force_quotes));
+       appendPQExpBuffer(q, " receive = %s",
+                         fmtId(typreceive, force_quotes));
    }
 
-   /*** Clear the statement buffer and return ***/
+   if (typdefault != NULL)
+   {
+       appendPQExpBuffer(q, ", default = ");
+       formatStringLiteral(q, typdefault, CONV_ALL);
+   }
+
+   if (tinfo->isArray)
+   {
+       char       *elemType;
+
+       /* reselect schema in case changed by function dump */
+       selectSourceSchema(tinfo->typnamespace->nspname);
+       elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
+       appendPQExpBuffer(q, ", element = %s, delimiter = ", elemType);
+       formatStringLiteral(q, typdelim, CONV_ALL);
+       free(elemType);
+
+       (*deps)[depIdx++] = strdup(tinfo->typelem);
+   }
+
+   if (strcmp(typalign, "c") == 0)
+       appendPQExpBuffer(q, ", alignment = char");
+   else if (strcmp(typalign, "s") == 0)
+       appendPQExpBuffer(q, ", alignment = int2");
+   else if (strcmp(typalign, "i") == 0)
+       appendPQExpBuffer(q, ", alignment = int4");
+   else if (strcmp(typalign, "d") == 0)
+       appendPQExpBuffer(q, ", alignment = double");
+
+   if (strcmp(typstorage, "p") == 0)
+       appendPQExpBuffer(q, ", storage = plain");
+   else if (strcmp(typstorage, "e") == 0)
+       appendPQExpBuffer(q, ", storage = external");
+   else if (strcmp(typstorage, "x") == 0)
+       appendPQExpBuffer(q, ", storage = extended");
+   else if (strcmp(typstorage, "m") == 0)
+       appendPQExpBuffer(q, ", storage = main");
+
+   if (strcmp(typbyval, "t") == 0)
+       appendPQExpBuffer(q, ", passedbyvalue);\n");
+   else
+       appendPQExpBuffer(q, ");\n");
+
+   (*deps)[depIdx++] = NULL;       /* End of List */
+
+   ArchiveEntry(fout, tinfo->oid, tinfo->typname,
+                tinfo->typnamespace->nspname,
+                tinfo->usename, "TYPE", deps,
+                q->data, delq->data, NULL, NULL, NULL);
+
+   /*** Dump Type Comments ***/
+   resetPQExpBuffer(q);
+
+   appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->typname, force_quotes));
+   dumpComment(fout, q->data,
+               tinfo->typnamespace->nspname, tinfo->usename,
+               tinfo->oid, "pg_type", 0, NULL);
 
    PQclear(res);
+   destroyPQExpBuffer(q);
+   destroyPQExpBuffer(delq);
    destroyPQExpBuffer(query);
 }
 
 /*
  * dumpOneDomain
- *    wites out to fout the queries to recrease a user-defined domains
+ *    writes out to fout the queries to recreate a user-defined domain
  *    as requested by dumpTypes
  */
 static void
@@ -3234,24 +2940,28 @@ dumpOneDomain(Archive *fout, TypeInfo *tinfo)
 {
    PQExpBuffer q = createPQExpBuffer();
    PQExpBuffer delq = createPQExpBuffer();
-
-   PGresult   *res;
    PQExpBuffer query = createPQExpBuffer();
+   PGresult   *res;
    int         ntups;
+   char       *typnotnull;
+   char       *typdefn;
+   char       *typdefault;
+   char       *typbasetype;
    const char *((*deps)[]);
    int         depIdx = 0;
 
-
    deps = malloc(sizeof(char *) * 10);
 
+   /* Set proper schema search path so type references list correctly */
+   selectSourceSchema(tinfo->typnamespace->nspname);
+
    /* Fetch domain specific details */
-   resetPQExpBuffer(query);
    appendPQExpBuffer(query, "SELECT typnotnull, "
-                            "format_type(typbasetype, typtypmod) as typdefn, "
-                            "typbasetype "
-                            "FROM pg_type "
-                            "WHERE typname = '%s'",
-                            tinfo->typname);
+                     "format_type(typbasetype, typtypmod) as typdefn, "
+                     "typdefault, typbasetype "
+                     "FROM pg_type "
+                     "WHERE oid = '%s'::oid",
+                     tinfo->oid);
 
    res = PQexec(g_conn, query->data);
    if (!res ||
@@ -3264,68 +2974,79 @@ dumpOneDomain(Archive *fout, TypeInfo *tinfo)
    /* Expecting a single result only */
    ntups = PQntuples(res);
    if (ntups != 1)
-       write_msg(NULL, "Domain %s non-existant.", fmtId(tinfo->typname, force_quotes));
+   {
+       write_msg(NULL, "Got %d rows instead of one from: %s",
+                 ntups, query->data);
+       exit_nicely();
+   }
 
+   typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
+   typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
+   if (PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
+       typdefault = NULL;
+   else
+       typdefault = strdup(PQgetvalue(res, 0, PQfnumber(res, "typdefault")));
+   typbasetype = PQgetvalue(res, 0, PQfnumber(res, "typbasetype"));
 
-   /* Drop the old copy */
-   resetPQExpBuffer(delq);
-   appendPQExpBuffer(delq, "DROP DOMAIN %s RESTRICT;\n", fmtId(tinfo->typname, force_quotes));
+   /* Command to drop the old copy */
+   appendPQExpBuffer(delq, "DROP DOMAIN %s RESTRICT;\n",
+                     fmtId(tinfo->typname, force_quotes));
 
-   resetPQExpBuffer(q);
    appendPQExpBuffer(q,
                      "CREATE DOMAIN %s AS %s",
                      fmtId(tinfo->typname, force_quotes),
-                     PQgetvalue(res, 0, PQfnumber(res, "typdefn"))
-                     );
+                     typdefn);
 
    /* Depends on the base type */
-   (*deps)[depIdx++] = strdup(PQgetvalue(res, 0, PQfnumber(res, "typbasetype")));
+   (*deps)[depIdx++] = strdup(typbasetype);
 
-   if (PQgetvalue(res, 0, PQfnumber(res, "typnotnull"))[0] == 't')
+   if (typnotnull[0] == 't')
        appendPQExpBuffer(q, " NOT NULL");
 
-   if (tinfo->typdefault)
+   if (typdefault)
    {
        appendPQExpBuffer(q,
                          " DEFAULT %s",
-                         tinfo->typdefault);
+                         typdefault);
    }
 
    appendPQExpBuffer(q, ";\n");
 
-
    (*deps)[depIdx++] = NULL;       /* End of List */
 
-   ArchiveEntry(fout, tinfo->oid, tinfo->typname, "DOMAIN", deps,
-                q->data, delq->data, "", tinfo->usename, NULL, NULL);
+   ArchiveEntry(fout, tinfo->oid, tinfo->typname,
+                tinfo->typnamespace->nspname,
+                tinfo->usename, "DOMAIN", deps,
+                q->data, delq->data, NULL, NULL, NULL);
 
    /*** Dump Domain Comments ***/
    resetPQExpBuffer(q);
 
    appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->typname, force_quotes));
-   dumpComment(fout, q->data, tinfo->oid, "pg_type", 0, NULL);
+   dumpComment(fout, q->data,
+               tinfo->typnamespace->nspname, tinfo->usename,
+               tinfo->oid, "pg_type", 0, NULL);
+
+   PQclear(res);
+   destroyPQExpBuffer(q);
+   destroyPQExpBuffer(delq);
+   destroyPQExpBuffer(query);
 }
 
 /*
  * dumpTypes
  *   writes out to fout the queries to recreate all the user-defined types
- *
  */
 void
 dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
          TypeInfo *tinfo, int numTypes)
 {
    int         i;
-   PQExpBuffer q = createPQExpBuffer();
-   PQExpBuffer delq = createPQExpBuffer();
-   int         funcInd;
-   const char *((*deps)[]);
-   int         depIdx;
 
    for (i = 0; i < numTypes; i++)
    {
-       /* skip all the builtin types */
-       if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
+       /* Dump only types in dumpable namespaces */
+       if (!tinfo[i].typnamespace->dump)
            continue;
 
        /* skip relation types */
@@ -3338,133 +3059,24 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
 
        /* skip all array types that start w/ underscore */
        if ((tinfo[i].typname[0] == '_') &&
-           (strcmp(tinfo[i].typinput, "array_in") == 0))
+           atooid(tinfo[i].typelem) != 0)
            continue;
 
-       /* Dump out domains as we run across them */
-       if (strcmp(tinfo[i].typtype, "d") == 0) {
+       /* Dump out in proper style */
+       if (tinfo[i].typtype == 'b')
+           dumpOneBaseType(fout, &tinfo[i],
+                           finfo, numFuncs, tinfo, numTypes);
+       else if (tinfo[i].typtype == 'd')
            dumpOneDomain(fout, &tinfo[i]);
-           continue;
-       }
-
-
-       deps = malloc(sizeof(char *) * 10);
-       depIdx = 0;
-
-       /*
-        * before we create a type, we need to create the input and output
-        * functions for it, if they haven't been created already
-        */
-       funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput);
-       if (funcInd != -1)
-       {
-           (*deps)[depIdx++] = strdup(finfo[funcInd].oid);
-           dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
-       }
-
-       funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
-       if (funcInd != -1)
-       {
-           (*deps)[depIdx++] = strdup(finfo[funcInd].oid);
-           dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
-       }
-
-       resetPQExpBuffer(delq);
-       appendPQExpBuffer(delq, "DROP TYPE %s;\n", fmtId(tinfo[i].typname, force_quotes));
-
-       resetPQExpBuffer(q);
-       appendPQExpBuffer(q,
-                         "CREATE TYPE %s "
-                         "( internallength = %s, externallength = %s,",
-                         fmtId(tinfo[i].typname, force_quotes),
-                         (strcmp(tinfo[i].typlen, "-1") == 0) ?
-                         "variable" : tinfo[i].typlen,
-                         (strcmp(tinfo[i].typprtlen, "-1") == 0) ?
-                         "variable" : tinfo[i].typprtlen);
-       /* cannot combine these because fmtId uses static result area */
-       appendPQExpBuffer(q, " input = %s,",
-                         fmtId(tinfo[i].typinput, force_quotes));
-       appendPQExpBuffer(q, " output = %s,",
-                         fmtId(tinfo[i].typoutput, force_quotes));
-       appendPQExpBuffer(q, " send = %s,",
-                         fmtId(tinfo[i].typsend, force_quotes));
-       appendPQExpBuffer(q, " receive = %s",
-                         fmtId(tinfo[i].typreceive, force_quotes));
-
-       if (tinfo[i].typdefault != NULL)
-       {
-           appendPQExpBuffer(q, ", default = ");
-           formatStringLiteral(q, tinfo[i].typdefault, CONV_ALL);
-       }
-
-       if (tinfo[i].isArray)
-       {
-           char       *elemType;
-
-           elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
-           if (elemType == NULL)
-           {
-               write_msg(NULL, "notice: array type %s - type for elements (oid %s) is not dumped\n",
-                         tinfo[i].typname, tinfo[i].typelem);
-               continue;
-           }
-
-           appendPQExpBuffer(q, ", element = %s, delimiter = ", elemType);
-           formatStringLiteral(q, tinfo[i].typdelim, CONV_ALL);
-
-           (*deps)[depIdx++] = strdup(tinfo[i].typelem);
-       }
-
-       if (strcmp(tinfo[i].typalign, "c") == 0)
-           appendPQExpBuffer(q, ", alignment = char");
-       else if (strcmp(tinfo[i].typalign, "s") == 0)
-           appendPQExpBuffer(q, ", alignment = int2");
-       else if (strcmp(tinfo[i].typalign, "i") == 0)
-           appendPQExpBuffer(q, ", alignment = int4");
-       else if (strcmp(tinfo[i].typalign, "d") == 0)
-           appendPQExpBuffer(q, ", alignment = double");
-
-       if (strcmp(tinfo[i].typstorage, "p") == 0)
-           appendPQExpBuffer(q, ", storage = plain");
-       else if (strcmp(tinfo[i].typstorage, "e") == 0)
-           appendPQExpBuffer(q, ", storage = external");
-       else if (strcmp(tinfo[i].typstorage, "x") == 0)
-           appendPQExpBuffer(q, ", storage = extended");
-       else if (strcmp(tinfo[i].typstorage, "m") == 0)
-           appendPQExpBuffer(q, ", storage = main");
-
-       if (tinfo[i].passedbyvalue)
-           appendPQExpBuffer(q, ", passedbyvalue);\n");
-       else
-           appendPQExpBuffer(q, ");\n");
-
-       (*deps)[depIdx++] = NULL;       /* End of List */
-
-       ArchiveEntry(fout, tinfo[i].oid, tinfo[i].typname, "TYPE", deps,
-                 q->data, delq->data, "", tinfo[i].usename, NULL, NULL);
-
-
-
-       /*** Dump Type Comments ***/
-
-       resetPQExpBuffer(q);
-
-       appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo[i].typname, force_quotes));
-       dumpComment(fout, q->data, tinfo[i].oid, "pg_type", 0, NULL);
    }
-
-   destroyPQExpBuffer(q);
-   destroyPQExpBuffer(delq);
 }
 
 /*
  * dumpProcLangs
  *       writes out to fout the queries to recreate user-defined procedural languages
- *
  */
 void
-dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
-             TypeInfo *tinfo, int numTypes)
+dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs)
 {
    PGresult   *res;
    PQExpBuffer query = createPQExpBuffer();
@@ -3476,13 +3088,18 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
    int         i_lanpltrusted;
    int         i_lanplcallfoid;
    int         i_lancompiler;
-   Oid         lanoid;
+   char       *lanoid;
    char       *lanname;
    char       *lancompiler;
    const char *lanplcallfoid;
+   const char *((*deps)[]);
+   int         depIdx;
    int         i,
                fidx;
 
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
+
    appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
                      "WHERE lanispl "
                      "ORDER BY oid");
@@ -3504,29 +3121,38 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
 
    for (i = 0; i < ntups; i++)
    {
-       lanoid = atooid(PQgetvalue(res, i, i_oid));
-       if (lanoid <= g_last_builtin_oid)
-           continue;
-
+       lanoid = PQgetvalue(res, i, i_oid);
        lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
+       lanname = PQgetvalue(res, i, i_lanname);
+       lancompiler = PQgetvalue(res, i, i_lancompiler);
 
-
-       for (fidx = 0; fidx < numFuncs; fidx++)
-       {
-           if (!strcmp(finfo[fidx].oid, lanplcallfoid))
-               break;
-       }
-       if (fidx >= numFuncs)
+       fidx = findFuncByOid(finfo, numFuncs, lanplcallfoid);
+       if (fidx < 0)
        {
            write_msg(NULL, "handler procedure for procedural language %s not found\n",
-                     PQgetvalue(res, i, i_lanname));
+                     lanname);
            exit_nicely();
        }
 
-       dumpOneFunc(fout, finfo, fidx, tinfo, numTypes);
+       /*
+        * Current theory is to dump PLs iff their underlying functions
+        * will be dumped (are in a dumpable namespace, or have a non-system
+        * OID in pre-7.3 databases).  Actually, we treat the PL itself
+        * as being in the underlying function's namespace, though it
+        * isn't really.  This avoids searchpath problems for the HANDLER
+        * clause.
+        */
+       if (!finfo[fidx].pronamespace->dump)
+           continue;
+
+       resetPQExpBuffer(defqry);
+       resetPQExpBuffer(delqry);
 
-       lanname = PQgetvalue(res, i, i_lanname);
-       lancompiler = PQgetvalue(res, i, i_lancompiler);
+       /* Make a dependency to ensure function is dumped first */
+       deps = malloc(sizeof(char *) * 2);
+       depIdx = 0;
+
+       (*deps)[depIdx++] = strdup(lanplcallfoid);
 
        appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
        formatStringLiteral(delqry, lanname, CONV_ALL);
@@ -3541,11 +3167,12 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
        formatStringLiteral(defqry, lancompiler, CONV_ALL);
        appendPQExpBuffer(defqry, ";\n");
 
-       ArchiveEntry(fout, PQgetvalue(res, i, i_oid), lanname, "PROCEDURAL LANGUAGE",
-                  NULL, defqry->data, delqry->data, "", "", NULL, NULL);
+       (*deps)[depIdx++] = NULL;       /* End of List */
 
-       resetPQExpBuffer(defqry);
-       resetPQExpBuffer(delqry);
+       ArchiveEntry(fout, lanoid, lanname,
+                    finfo[fidx].pronamespace->nspname, "",
+                    "PROCEDURAL LANGUAGE", deps,
+                    defqry->data, delqry->data, NULL, NULL, NULL);
    }
 
    PQclear(res);
@@ -3558,179 +3185,199 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
 /*
  * dumpFuncs
  *   writes out to fout the queries to recreate all the user-defined functions
- *
  */
 void
-dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
-         TypeInfo *tinfo, int numTypes)
+dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs)
 {
    int         i;
 
    for (i = 0; i < numFuncs; i++)
-       dumpOneFunc(fout, finfo, i, tinfo, numTypes);
+   {
+       /* Dump only funcs in dumpable namespaces */
+       if (!finfo[i].pronamespace->dump)
+           continue;
+
+       dumpOneFunc(fout, &finfo[i]);
+   }
 }
 
 /*
  * dumpOneFunc:
- *   dump out only one function,  the index of which is given in the third
- * argument
- *
+ *   dump out only one function
  */
-
 static void
-dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
-           TypeInfo *tinfo, int numTypes)
+dumpOneFunc(Archive *fout, FuncInfo *finfo)
 {
+   PQExpBuffer query = createPQExpBuffer();
    PQExpBuffer q = createPQExpBuffer();
    PQExpBuffer fn = createPQExpBuffer();
    PQExpBuffer delqry = createPQExpBuffer();
-   PQExpBuffer fnlist = createPQExpBuffer();
    PQExpBuffer asPart = createPQExpBuffer();
-   char       *func_lang = NULL;
-   PGresult   *res;
-   int         nlangs;
+   PGresult   *res = NULL;
+   int         ntups;
    int         j;
-   int         i_lanname;
-   char        query[256];
-
+   char       *proretset;
+   char       *prosrc;
+   char       *probin;
+   char       *provolatile;
+   char       *proimplicit;
+   char       *proisstrict;
+   char       *lanname;
    char       *listSep;
    char       *listSepComma = ",";
    char       *listSepNone = "";
    char       *rettypename;
 
-   if (finfo[i].dumped)
+   if (finfo->dumped)
        goto done;
 
-   finfo[i].dumped = 1;
+   finfo->dumped = true;
 
-   /* becomeUser(fout, finfo[i].usename); */
+   /* Set proper schema search path so type references list correctly */
+   selectSourceSchema(finfo->pronamespace->nspname);
+
+   /* Fetch function-specific details */
+   if (g_fout->remoteVersion >= 70300)
+   {
+       appendPQExpBuffer(query,
+                         "SELECT proretset, prosrc, probin, "
+                         "provolatile, proimplicit, proisstrict, "
+                         "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
+                         "FROM pg_proc "
+                         "WHERE oid = '%s'::oid",
+                         finfo->oid);
+   }
+   else if (g_fout->remoteVersion >= 70100)
+   {
+       appendPQExpBuffer(query,
+                         "SELECT proretset, prosrc, probin, "
+                         "case when proiscachable then 'i' else 'v' end as provolatile, "
+                         "'f'::boolean as proimplicit, "
+                         "proisstrict, "
+                         "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
+                         "FROM pg_proc "
+                         "WHERE oid = '%s'::oid",
+                         finfo->oid);
+   }
+   else
+   {
+       appendPQExpBuffer(query,
+                         "SELECT proretset, prosrc, probin, "
+                         "case when proiscachable then 'i' else 'v' end as provolatile, "
+                         "'f'::boolean as proimplicit, "
+                         "'f'::boolean as proisstrict, "
+                         "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
+                         "FROM pg_proc "
+                         "WHERE oid = '%s'::oid",
+                         finfo->oid);
+   }
 
-   sprintf(query, "SELECT lanname FROM pg_language WHERE oid = '%u'::oid",
-           finfo[i].lang);
-   res = PQexec(g_conn, query);
+   res = PQexec(g_conn, query->data);
    if (!res ||
        PQresultStatus(res) != PGRES_TUPLES_OK)
    {
-       write_msg(NULL, "query to get name of procedural language failed: %s", PQerrorMessage(g_conn));
+       write_msg(NULL, "query to obtain function information for %s failed: %s",
+                 finfo->proname, PQerrorMessage(g_conn));
        exit_nicely();
    }
-   nlangs = PQntuples(res);
 
-   if (nlangs != 1)
+   /* Expecting a single result only */
+   ntups = PQntuples(res);
+   if (ntups != 1)
    {
-       write_msg(NULL, "procedural language for function %s not found\n", finfo[i].proname);
+       write_msg(NULL, "Got %d rows instead of one from: %s",
+                 ntups, query->data);
        exit_nicely();
    }
 
-   i_lanname = PQfnumber(res, "lanname");
+   proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
+   prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
+   probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
+   provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
+   proimplicit = PQgetvalue(res, 0, PQfnumber(res, "proimplicit"));
+   proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
+   lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
 
    /*
     * See backend/commands/define.c for details of how the 'AS' clause is
     * used.
     */
-   if (strcmp(finfo[i].probin, "-") != 0)
+   if (strcmp(probin, "-") != 0)
    {
        appendPQExpBuffer(asPart, "AS ");
-       formatStringLiteral(asPart, finfo[i].probin, CONV_ALL);
-       if (strcmp(finfo[i].prosrc, "-") != 0)
+       formatStringLiteral(asPart, probin, CONV_ALL);
+       if (strcmp(prosrc, "-") != 0)
        {
            appendPQExpBuffer(asPart, ", ");
-           formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
+           formatStringLiteral(asPart, prosrc, PASS_LFTAB);
        }
    }
    else
    {
-       if (strcmp(finfo[i].prosrc, "-") != 0)
+       if (strcmp(prosrc, "-") != 0)
        {
            appendPQExpBuffer(asPart, "AS ");
-           formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
+           formatStringLiteral(asPart, prosrc, PASS_LFTAB);
        }
    }
 
-   func_lang = strdup(PQgetvalue(res, 0, i_lanname));
-
-   PQclear(res);
-
-   resetPQExpBuffer(fn);
-   appendPQExpBuffer(fn, "%s (", fmtId(finfo[i].proname, force_quotes));
-   for (j = 0; j < finfo[i].nargs; j++)
+   appendPQExpBuffer(fn, "%s (", fmtId(finfo->proname, force_quotes));
+   for (j = 0; j < finfo->nargs; j++)
    {
        char       *typname;
 
-       typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j], zeroAsOpaque);
-       if (typname == NULL)
-       {
-           write_msg(NULL, "WARNING: function \"%s\" not dumped\n",
-                     finfo[i].proname);
-
-           write_msg(NULL, "reason: data type name of argument %d (oid %s) not found\n",
-                     j, finfo[i].argtypes[j]);
-           goto done;
-       }
-
+       typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
        appendPQExpBuffer(fn, "%s%s",
                          (j > 0) ? "," : "",
                          typname);
-       appendPQExpBuffer(fnlist, "%s%s",
-                         (j > 0) ? "," : "",
-                         typname);
+       free(typname);
    }
    appendPQExpBuffer(fn, ")");
 
-   resetPQExpBuffer(delqry);
    appendPQExpBuffer(delqry, "DROP FUNCTION %s;\n", fn->data);
 
-   rettypename = findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque);
-
-   if (rettypename == NULL)
-   {
-       write_msg(NULL, "WARNING: function \"%s\" not dumped\n",
-                 finfo[i].proname);
-
-       write_msg(NULL, "reason: name of return data type (oid %s) not found\n",
-                 finfo[i].prorettype);
-       goto done;
-   }
+   rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
 
-   resetPQExpBuffer(q);
    appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data);
    appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
-                     (finfo[i].retset) ? "SETOF " : "",
+                     (proretset[0] == 't') ? "SETOF " : "",
                      rettypename,
                      asPart->data);
-   formatStringLiteral(q, func_lang, CONV_ALL);
+   formatStringLiteral(q, lanname, CONV_ALL);
+
+   free(rettypename);
 
-   if (finfo[i].provolatile != PROVOLATILE_VOLATILE ||
-       finfo[i].isimplicit ||
-       finfo[i].isstrict)      /* OR in new attrs here */
+   if (provolatile[0] != PROVOLATILE_VOLATILE ||
+       proimplicit[0] == 't' ||
+       proisstrict[0] == 't')  /* OR in new attrs here */
    {
        appendPQExpBuffer(q, " WITH (");
        listSep = listSepNone;
 
-       if (finfo[i].provolatile == PROVOLATILE_IMMUTABLE)
+       if (provolatile[0] == PROVOLATILE_IMMUTABLE)
        {
            appendPQExpBuffer(q, "%s isImmutable", listSep);
            listSep = listSepComma;
        }
-       else if (finfo[i].provolatile == PROVOLATILE_STABLE)
+       else if (provolatile[0] == PROVOLATILE_STABLE)
        {
            appendPQExpBuffer(q, "%s isStable", listSep);
            listSep = listSepComma;
        }
-       else if (finfo[i].provolatile != PROVOLATILE_VOLATILE)
+       else if (provolatile[0] != PROVOLATILE_VOLATILE)
        {
            write_msg(NULL, "Unexpected provolatile value for function %s\n",
-                     finfo[i].proname);
+                     finfo->proname);
            exit_nicely();
        }
 
-       if (finfo[i].isimplicit)
+       if (proimplicit[0] == 't')
        {
            appendPQExpBuffer(q, "%s implicitCoercion", listSep);
            listSep = listSepComma;
        }
 
-       if (finfo[i].isstrict)
+       if (proisstrict[0] == 't')
        {
            appendPQExpBuffer(q, "%s isStrict", listSep);
            listSep = listSepComma;
@@ -3741,331 +3388,608 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
 
    appendPQExpBuffer(q, ";\n");
 
-   ArchiveEntry(fout, finfo[i].oid, fn->data, "FUNCTION", NULL, q->data, delqry->data,
-                "", finfo[i].usename, NULL, NULL);
+   ArchiveEntry(fout, finfo->oid, fn->data, finfo->pronamespace->nspname,
+                finfo->usename, "FUNCTION", NULL,
+                q->data, delqry->data,
+                NULL, NULL, NULL);
 
    /*** Dump Function Comments ***/
 
    resetPQExpBuffer(q);
-   appendPQExpBuffer(q, "FUNCTION %s ",
-                     fmtId(finfo[i].proname, force_quotes));
-   appendPQExpBuffer(q, "( %s )", fnlist->data);
-   dumpComment(fout, q->data, finfo[i].oid, "pg_proc", 0, NULL);
+   appendPQExpBuffer(q, "FUNCTION %s ", fn->data);
+   dumpComment(fout, q->data,
+               finfo->pronamespace->nspname, finfo->usename,
+               finfo->oid, "pg_proc", 0, NULL);
 
 done:
+   PQclear(res);
+
+   destroyPQExpBuffer(query);
    destroyPQExpBuffer(q);
    destroyPQExpBuffer(fn);
    destroyPQExpBuffer(delqry);
-   destroyPQExpBuffer(fnlist);
    destroyPQExpBuffer(asPart);
-   free(func_lang);
 }
 
 /*
  * dumpOprs
  *   writes out to fout the queries to recreate all the user-defined operators
- *
  */
 void
-dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
-        TypeInfo *tinfo, int numTypes)
+dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators)
 {
    int         i;
-   PQExpBuffer q = createPQExpBuffer();
-   PQExpBuffer delq = createPQExpBuffer();
-   PQExpBuffer leftarg = createPQExpBuffer();
-   PQExpBuffer rightarg = createPQExpBuffer();
-   PQExpBuffer commutator = createPQExpBuffer();
-   PQExpBuffer negator = createPQExpBuffer();
-   PQExpBuffer restrictor = createPQExpBuffer();
-   PQExpBuffer join = createPQExpBuffer();
-   PQExpBuffer sort1 = createPQExpBuffer();
-   PQExpBuffer sort2 = createPQExpBuffer();
 
    for (i = 0; i < numOperators; i++)
    {
-       char       *name;
-
-       resetPQExpBuffer(leftarg);
-       resetPQExpBuffer(rightarg);
-       resetPQExpBuffer(commutator);
-       resetPQExpBuffer(negator);
-       resetPQExpBuffer(restrictor);
-       resetPQExpBuffer(join);
-       resetPQExpBuffer(sort1);
-       resetPQExpBuffer(sort2);
-
-       /* skip all the builtin oids */
-       if (atooid(oprinfo[i].oid) <= g_last_builtin_oid)
+       /* Dump only operators in dumpable namespaces */
+       if (!oprinfo[i].oprnamespace->dump)
            continue;
 
        /*
-        * some operator are invalid because they were the result of user
+        * some operators are invalid because they were the result of user
         * defining operators before commutators exist
         */
-       if (strcmp(oprinfo[i].oprcode, "-") == 0)
+       if (strcmp(oprinfo[i].oprcode, "0") == 0)
            continue;
 
-       /*
-        * right unary means there's a left arg and left unary means
-        * there's a right arg
-        */
-       if (strcmp(oprinfo[i].oprkind, "r") == 0 ||
-           strcmp(oprinfo[i].oprkind, "b") == 0)
-       {
-           name = findTypeByOid(tinfo, numTypes,
-                                oprinfo[i].oprleft, zeroAsOpaque);
-           if (name == NULL)
-           {
-               write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
-                         oprinfo[i].oprname, oprinfo[i].oid);
-               write_msg(NULL, "reason: oprleft (oid %s) not found\n",
-                         oprinfo[i].oprleft);
-               continue;
-           }
-           appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ", name);
-       }
+       /* OK, dump it */
+       dumpOneOpr(fout, &oprinfo[i],
+                  oprinfo, numOperators);
+   }
+}
 
-       if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
-           strcmp(oprinfo[i].oprkind, "b") == 0)
-       {
-           name = findTypeByOid(tinfo, numTypes,
-                                oprinfo[i].oprright, zeroAsOpaque);
-           if (name == NULL)
-           {
-               write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
-                         oprinfo[i].oprname, oprinfo[i].oid);
-               write_msg(NULL, "reason: oprright (oid %s) not found\n",
-                         oprinfo[i].oprright);
-               continue;
-           }
-           appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ", name);
-       }
+/*
+ * dumpOneOpr
+ *   write out a single operator definition
+ */
+static void
+dumpOneOpr(Archive *fout, OprInfo *oprinfo,
+          OprInfo *g_oprinfo, int numOperators)
+{
+   PQExpBuffer query = createPQExpBuffer();
+   PQExpBuffer q = createPQExpBuffer();
+   PQExpBuffer delq = createPQExpBuffer();
+   PQExpBuffer oprid = createPQExpBuffer();
+   PQExpBuffer details = createPQExpBuffer();
+   const char *name;
+   PGresult   *res;
+   int         ntups;
+   int         i_oprkind;
+   int         i_oprcode;
+   int         i_oprleft;
+   int         i_oprright;
+   int         i_oprcom;
+   int         i_oprnegate;
+   int         i_oprrest;
+   int         i_oprjoin;
+   int         i_oprcanhash;
+   int         i_oprlsortop;
+   int         i_oprrsortop;
+   int         i_oprltcmpop;
+   int         i_oprgtcmpop;
+   char       *oprkind;
+   char       *oprcode;
+   char       *oprleft;
+   char       *oprright;
+   char       *oprcom;
+   char       *oprnegate;
+   char       *oprrest;
+   char       *oprjoin;
+   char       *oprcanhash;
+   char       *oprlsortop;
+   char       *oprrsortop;
+   char       *oprltcmpop;
+   char       *oprgtcmpop;
+
+   /* Make sure we are in proper schema so regoperator works correctly */
+   selectSourceSchema(oprinfo->oprnamespace->nspname);
+
+   if (g_fout->remoteVersion >= 70300)
+   {
+       appendPQExpBuffer(query, "SELECT oprkind, oprcode::regprocedure, "
+                         "oprleft::regtype, oprright::regtype, "
+                         "oprcom::regoperator, oprnegate::regoperator, "
+                         "oprrest::regprocedure, oprjoin::regprocedure, "
+                         "oprcanhash, "
+                         "oprlsortop::regoperator, oprrsortop::regoperator, "
+                         "oprltcmpop::regoperator, oprgtcmpop::regoperator "
+                         "from pg_operator "
+                         "where oid = '%s'::oid",
+                         oprinfo->oid);
+   }
+   else if (g_fout->remoteVersion >= 70100)
+   {
+       appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
+                         "CASE WHEN oprleft = 0 THEN '-' "
+                         "ELSE format_type(oprleft, NULL) END as oprleft, "
+                         "CASE WHEN oprright = 0 THEN '-' "
+                         "ELSE format_type(oprright, NULL) END as oprright, "
+                         "oprcom, oprnegate, oprrest, oprjoin, "
+                         "oprcanhash, oprlsortop, oprrsortop, "
+                         "0 as oprltcmpop, 0 as oprgtcmpop "
+                         "from pg_operator "
+                         "where oid = '%s'::oid",
+                         oprinfo->oid);
+   }
+   else
+   {
+       appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
+                         "CASE WHEN oprleft = 0 THEN '-'::name "
+                         "ELSE (select typname from pg_type where oid = oprleft) END as oprleft, "
+                         "CASE WHEN oprright = 0 THEN '-'::name "
+                         "ELSE (select typname from pg_type where oid = oprright) END as oprright, "
+                         "oprcom, oprnegate, oprrest, oprjoin, "
+                         "oprcanhash, oprlsortop, oprrsortop, "
+                         "0 as oprltcmpop, 0 as oprgtcmpop "
+                         "from pg_operator "
+                         "where oid = '%s'::oid",
+                         oprinfo->oid);
+   }
 
-       if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
-       {
-           name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom);
-           if (name == NULL)
-           {
-               write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
-                         oprinfo[i].oprname, oprinfo[i].oid);
-               write_msg(NULL, "reason: oprcom (oid %s) not found\n",
-                         oprinfo[i].oprcom);
-               continue;
-           }
-           appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ", name);
-       }
+   res = PQexec(g_conn, query->data);
+   if (!res ||
+       PQresultStatus(res) != PGRES_TUPLES_OK)
+   {
+       write_msg(NULL, "query to obtain list of operators failed: %s", PQerrorMessage(g_conn));
+       exit_nicely();
+   }
 
-       if (!(strcmp(oprinfo[i].oprnegate, "0") == 0))
-       {
-           name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate);
-           if (name == NULL)
-           {
-               write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
-                         oprinfo[i].oprname, oprinfo[i].oid);
-               write_msg(NULL, "reason: oprnegate (oid %s) not found\n",
-                         oprinfo[i].oprnegate);
-               continue;
-           }
-           appendPQExpBuffer(negator, ",\n\tNEGATOR = %s ", name);
-       }
+   /* Expecting a single result only */
+   ntups = PQntuples(res);
+   if (ntups != 1)
+   {
+       write_msg(NULL, "Got %d rows instead of one from: %s",
+                 ntups, query->data);
+       exit_nicely();
+   }
+
+   i_oprkind = PQfnumber(res, "oprkind");
+   i_oprcode = PQfnumber(res, "oprcode");
+   i_oprleft = PQfnumber(res, "oprleft");
+   i_oprright = PQfnumber(res, "oprright");
+   i_oprcom = PQfnumber(res, "oprcom");
+   i_oprnegate = PQfnumber(res, "oprnegate");
+   i_oprrest = PQfnumber(res, "oprrest");
+   i_oprjoin = PQfnumber(res, "oprjoin");
+   i_oprcanhash = PQfnumber(res, "oprcanhash");
+   i_oprlsortop = PQfnumber(res, "oprlsortop");
+   i_oprrsortop = PQfnumber(res, "oprrsortop");
+   i_oprltcmpop = PQfnumber(res, "oprltcmpop");
+   i_oprgtcmpop = PQfnumber(res, "oprgtcmpop");
+
+   oprkind = PQgetvalue(res, 0, i_oprkind);
+   oprcode = PQgetvalue(res, 0, i_oprcode);
+   oprleft = PQgetvalue(res, 0, i_oprleft);
+   oprright = PQgetvalue(res, 0, i_oprright);
+   oprcom = PQgetvalue(res, 0, i_oprcom);
+   oprnegate = PQgetvalue(res, 0, i_oprnegate);
+   oprrest = PQgetvalue(res, 0, i_oprrest);
+   oprjoin = PQgetvalue(res, 0, i_oprjoin);
+   oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
+   oprlsortop = PQgetvalue(res, 0, i_oprlsortop);
+   oprrsortop = PQgetvalue(res, 0, i_oprrsortop);
+   oprltcmpop = PQgetvalue(res, 0, i_oprltcmpop);
+   oprgtcmpop = PQgetvalue(res, 0, i_oprgtcmpop);
+
+   appendPQExpBuffer(details, "PROCEDURE = %s ",
+                     convertRegProcReference(oprcode));
+
+   appendPQExpBuffer(oprid, "%s (",
+                     oprinfo->oprname);
+
+   /*
+    * right unary means there's a left arg and left unary means
+    * there's a right arg
+    */
+   if (strcmp(oprkind, "r") == 0 ||
+       strcmp(oprkind, "b") == 0)
+   {
+       if (g_fout->remoteVersion >= 70100)
+           name = oprleft;
+       else
+           name = fmtId(oprleft, force_quotes);
+       appendPQExpBuffer(details, ",\n\tLEFTARG = %s ", name);
+       appendPQExpBuffer(oprid, "%s", name);
+   }
+   else
+       appendPQExpBuffer(oprid, "NONE");
+
+   if (strcmp(oprkind, "l") == 0 ||
+       strcmp(oprkind, "b") == 0)
+   {
+       if (g_fout->remoteVersion >= 70100)
+           name = oprright;
+       else
+           name = fmtId(oprright, force_quotes);
+       appendPQExpBuffer(details, ",\n\tRIGHTARG = %s ", name);
+       appendPQExpBuffer(oprid, ", %s)", name);
+   }
+   else
+       appendPQExpBuffer(oprid, ", NONE)");
+
+   name = convertOperatorReference(oprcom, g_oprinfo, numOperators);
+   if (name)
+       appendPQExpBuffer(details, ",\n\tCOMMUTATOR = %s ", name);
+
+   name = convertOperatorReference(oprnegate, g_oprinfo, numOperators);
+   if (name)
+       appendPQExpBuffer(details, ",\n\tNEGATOR = %s ", name);
+
+   if (strcmp(oprcanhash, "t") == 0)
+       appendPQExpBuffer(details, ",\n\tHASHES");
+
+   name = convertRegProcReference(oprrest);
+   if (name)
+       appendPQExpBuffer(details, ",\n\tRESTRICT = %s ", name);
+
+   name = convertRegProcReference(oprjoin);
+   if (name)
+       appendPQExpBuffer(details, ",\n\tJOIN = %s ", name);
+
+   name = convertOperatorReference(oprlsortop, g_oprinfo, numOperators);
+   if (name)
+       appendPQExpBuffer(details, ",\n\tSORT1 = %s ", name);
+
+   name = convertOperatorReference(oprrsortop, g_oprinfo, numOperators);
+   if (name)
+       appendPQExpBuffer(details, ",\n\tSORT2 = %s ", name);
 
-       if (!(strcmp(oprinfo[i].oprrest, "-") == 0))
-           appendPQExpBuffer(restrictor, ",\n\tRESTRICT = %s ", oprinfo[i].oprrest);
+   name = convertOperatorReference(oprltcmpop, g_oprinfo, numOperators);
+   if (name)
+       appendPQExpBuffer(details, ",\n\tLTCMP = %s ", name);
 
-       if (!(strcmp(oprinfo[i].oprjoin, "-") == 0))
-           appendPQExpBuffer(join, ",\n\tJOIN = %s ", oprinfo[i].oprjoin);
+   name = convertOperatorReference(oprgtcmpop, g_oprinfo, numOperators);
+   if (name)
+       appendPQExpBuffer(details, ",\n\tGTCMP = %s ", name);
 
-       if (!(strcmp(oprinfo[i].oprlsortop, "0") == 0))
+   appendPQExpBuffer(delq, "DROP OPERATOR %s;\n",
+                     oprid->data);
+
+   appendPQExpBuffer(q, "CREATE OPERATOR %s (%s);\n",
+                     oprinfo->oprname, details->data);
+
+   ArchiveEntry(fout, oprinfo->oid, oprinfo->oprname,
+                oprinfo->oprnamespace->nspname, oprinfo->usename,
+                "OPERATOR", NULL,
+                q->data, delq->data,
+                NULL, NULL, NULL);
+
+   /*
+    * Note: no need to dump operator comment; we expect that the comment
+    * is attached to the underlying function instead.  (If the function
+    * isn't getting dumped ... you lose.)
+    */
+
+   PQclear(res);
+
+   destroyPQExpBuffer(query);
+   destroyPQExpBuffer(q);
+   destroyPQExpBuffer(delq);
+   destroyPQExpBuffer(oprid);
+   destroyPQExpBuffer(details);
+}
+
+/*
+ * Convert a function reference obtained from pg_operator
+ *
+ * Returns what to print, or NULL if function references is InvalidOid
+ *
+ * In 7.3 the input is a REGPROCEDURE display; we have to strip the
+ * argument-types part.  In prior versions, the input is a REGPROC display.
+ */
+static const char *
+convertRegProcReference(const char *proc)
+{
+   /* In all cases "-" means a null reference */
+   if (strcmp(proc, "-") == 0)
+       return NULL;
+
+   if (g_fout->remoteVersion >= 70300)
+   {
+       char   *name;
+       char   *paren;
+       bool    inquote;
+
+       name = strdup(proc);
+       /* find non-double-quoted left paren */
+       inquote = false;
+       for (paren = name; *paren; paren++)
        {
-           name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprlsortop);
-           if (name == NULL)
+           if (*paren == '(' && !inquote)
            {
-               write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
-                         oprinfo[i].oprname, oprinfo[i].oid);
-               write_msg(NULL, "reason: oprlsortop (oid %s) not found\n",
-                         oprinfo[i].oprlsortop);
-               continue;
+               *paren = '\0';
+               break;
            }
-           appendPQExpBuffer(sort1, ",\n\tSORT1 = %s ", name);
+           if (*paren == '"')
+               inquote = !inquote;
        }
+       return name;
+   }
+
+   /* REGPROC before 7.3 does not quote its result */
+   return fmtId(proc, false);
+}
+
+/*
+ * Convert an operator cross-reference obtained from pg_operator
+ *
+ * Returns what to print, or NULL to print nothing
+ *
+ * In 7.3 the input is a REGOPERATOR display; we have to strip the
+ * argument-types part.  In prior versions, the input is just a
+ * numeric OID, which we search our operator list for.
+ */
+static const char *
+convertOperatorReference(const char *opr,
+                        OprInfo *g_oprinfo, int numOperators)
+{
+   char   *name;
+
+   /* In all cases "0" means a null reference */
+   if (strcmp(opr, "0") == 0)
+       return NULL;
+
+   if (g_fout->remoteVersion >= 70300)
+   {
+       char   *paren;
+       bool    inquote;
 
-       if (!(strcmp(oprinfo[i].oprrsortop, "0") == 0))
+       name = strdup(opr);
+       /* find non-double-quoted left paren */
+       inquote = false;
+       for (paren = name; *paren; paren++)
        {
-           name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprrsortop);
-           if (name == NULL)
+           if (*paren == '(' && !inquote)
            {
-               write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
-                         oprinfo[i].oprname, oprinfo[i].oid);
-               write_msg(NULL, "reason: oprrsortop (oid %s) not found\n",
-                         oprinfo[i].oprrsortop);
-               continue;
+               *paren = '\0';
+               break;
            }
-           appendPQExpBuffer(sort2, ",\n\tSORT2 = %s ", name);
+           if (*paren == '"')
+               inquote = !inquote;
        }
-
-       resetPQExpBuffer(delq);
-       appendPQExpBuffer(delq, "DROP OPERATOR %s (%s",
-                         oprinfo[i].oprname,
-                      findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft,
-                                    zeroAsNone));
-       appendPQExpBuffer(delq, ", %s);\n",
-                     findTypeByOid(tinfo, numTypes, oprinfo[i].oprright,
-                                   zeroAsNone));
-
-       resetPQExpBuffer(q);
-       appendPQExpBuffer(q,
-                         "CREATE OPERATOR %s "
-                         "(PROCEDURE = %s %s%s%s%s%s%s%s%s%s);\n",
-                         oprinfo[i].oprname,
-                         oprinfo[i].oprcode,
-                         leftarg->data,
-                         rightarg->data,
-                         commutator->data,
-                         negator->data,
-                         restrictor->data,
-         (strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
-                         join->data,
-                         sort1->data,
-                         sort2->data);
-
-       ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
-               q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
+       return name;
    }
 
-   destroyPQExpBuffer(q);
-   destroyPQExpBuffer(delq);
-   destroyPQExpBuffer(leftarg);
-   destroyPQExpBuffer(rightarg);
-   destroyPQExpBuffer(commutator);
-   destroyPQExpBuffer(negator);
-   destroyPQExpBuffer(restrictor);
-   destroyPQExpBuffer(join);
-   destroyPQExpBuffer(sort1);
-   destroyPQExpBuffer(sort2);
+   name = findOprByOid(g_oprinfo, numOperators, opr);
+   if (name == NULL)
+       write_msg(NULL, "WARNING: cannot find operator with OID %s\n",
+                 opr);
+   return name;
 }
 
 /*
  * dumpAggs
  *   writes out to fout the queries to create all the user-defined aggregates
- *
  */
 void
-dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
-        TypeInfo *tinfo, int numTypes)
+dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs)
 {
    int         i;
+
+   for (i = 0; i < numAggs; i++)
+   {
+       /* Dump only aggs in dumpable namespaces */
+       if (!agginfo[i].aggnamespace->dump)
+           continue;
+
+       dumpOneAgg(fout, &agginfo[i]);
+   }
+}
+
+/*
+ * dumpOneAgg
+ *   write out a single aggregate definition
+ */
+static void
+dumpOneAgg(Archive *fout, AggInfo *agginfo)
+{
+   PQExpBuffer query = createPQExpBuffer();
    PQExpBuffer q = createPQExpBuffer();
    PQExpBuffer delq = createPQExpBuffer();
    PQExpBuffer aggSig = createPQExpBuffer();
    PQExpBuffer details = createPQExpBuffer();
+   PGresult   *res;
+   int         ntups;
+   int         i_aggtransfn;
+   int         i_aggfinalfn;
+   int         i_aggtranstype;
+   int         i_aggbasetype;
+   int         i_agginitval;
+   int         i_convertok;
+   const char *aggtransfn;
+   const char *aggfinalfn;
+   const char *aggtranstype;
+   const char *aggbasetype;
+   const char *agginitval;
+   bool        convertok;
+   bool        anybasetype;
+
+   /* Make sure we are in proper schema */
+   selectSourceSchema(agginfo->aggnamespace->nspname);
+
+   /* Get aggregate-specific details */
+   if (g_fout->remoteVersion >= 70300)
+   {
+       appendPQExpBuffer(query, "SELECT aggtransfn, "
+                         "aggfinalfn, aggtranstype::regtype, "
+                         "proargtypes[0]::regtype as aggbasetype, "
+                         "agginitval, "
+                         "'t'::boolean as convertok "
+                         "from pg_aggregate a, pg_proc p "
+                         "where a.aggfnoid = p.oid "
+                         "and p.oid = '%s'::oid",
+                         agginfo->oid);
+   }
+   else if (g_fout->remoteVersion >= 70100)
+   {
+       appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
+                         "format_type(aggtranstype, NULL) as aggtranstype, "
+                         "CASE WHEN aggbasetype = 0 THEN '-' "
+                         "ELSE format_type(aggbasetype, NULL) END as aggbasetype, "
+                         "agginitval, 't'::boolean as convertok "
+                         "from pg_aggregate "
+                         "where oid = '%s'::oid",
+                         agginfo->oid);
+   }
+   else
+   {
+       appendPQExpBuffer(query, "SELECT aggtransfn1 as aggtransfn, "
+                         "aggfinalfn, "
+                         "(select typname from pg_type where oid = aggtranstype1) as aggtranstype, "
+                         "CASE WHEN aggbasetype = 0 THEN '-'::name "
+                         "ELSE (select typname from pg_type where oid = aggbasetype) END as aggbasetype, "
+                         "agginitval1 as agginitval, "
+                         "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok "
+                         "from pg_aggregate "
+                         "where oid = '%s'::oid",
+                         agginfo->oid);
+   }
 
-   for (i = 0; i < numAggs; i++)
+   res = PQexec(g_conn, query->data);
+   if (!res ||
+       PQresultStatus(res) != PGRES_TUPLES_OK)
    {
-       char       *name;
+       write_msg(NULL, "query to obtain list of aggregate functions failed: %s",
+                 PQerrorMessage(g_conn));
+       exit_nicely();
+   }
 
-       resetPQExpBuffer(details);
+   /* Expecting a single result only */
+   ntups = PQntuples(res);
+   if (ntups != 1)
+   {
+       write_msg(NULL, "Got %d rows instead of one from: %s",
+                 ntups, query->data);
+       exit_nicely();
+   }
 
-       /* skip all the builtin oids */
-       if (oidle(atooid(agginfo[i].oid), g_last_builtin_oid))
-           continue;
+   i_aggtransfn = PQfnumber(res, "aggtransfn");
+   i_aggfinalfn = PQfnumber(res, "aggfinalfn");
+   i_aggtranstype = PQfnumber(res, "aggtranstype");
+   i_aggbasetype = PQfnumber(res, "aggbasetype");
+   i_agginitval = PQfnumber(res, "agginitval");
+   i_convertok = PQfnumber(res, "convertok");
 
-       resetPQExpBuffer(aggSig);
-       appendPQExpBuffer(aggSig, "%s(%s)", agginfo[i].aggname,
-                         findTypeByOid(tinfo, numTypes,
-                                       agginfo[i].aggbasetype,
-                                       zeroAsStar + useBaseTypeName));
+   aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
+   aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
+   aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
+   aggbasetype = PQgetvalue(res, 0, i_aggbasetype);
+   agginitval = PQgetvalue(res, 0, i_agginitval);
+   convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
 
-       if (!agginfo[i].convertok)
-       {
-           write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
-                     aggSig->data);
+   anybasetype = (strcmp(aggbasetype, "-") == 0);
 
-           resetPQExpBuffer(q);
-           appendPQExpBuffer(q, "-- WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
-                             aggSig->data);
-           ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
-            q->data, "" /* Del */ , "", agginfo[i].usename, NULL, NULL);
-           continue;
-       }
+   appendPQExpBuffer(aggSig, "%s",
+                     fmtId(agginfo->aggname, force_quotes));
 
-       name = findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype,
-                            zeroAsAny + useBaseTypeName);
-       if (name == NULL)
-       {
-           write_msg(NULL, "WARNING: aggregate function \"%s\" (oid %s) not dumped\n",
-                     agginfo[i].aggname, agginfo[i].oid);
-           write_msg(NULL, "reason: aggbasetype (oid %s) not found\n",
-                     agginfo[i].aggbasetype);
+   /* If using regtype or format_type, name is already quoted */
+   if (g_fout->remoteVersion >= 70100)
+   {
+       if (anybasetype)
+           appendPQExpBuffer(aggSig, "(*)");
+       else
+           appendPQExpBuffer(aggSig, "(%s)", aggbasetype);
+   }
+   else
+   {
+       if (anybasetype)
+           appendPQExpBuffer(aggSig, "(*)");
+       else
+           appendPQExpBuffer(aggSig, "(%s)",
+                             fmtId(aggbasetype, force_quotes));
+   }
 
-           resetPQExpBuffer(q);
-           appendPQExpBuffer(q, "-- WARNING: aggregate function \"%s\" (oid %s) not dumped\n", agginfo[i].aggname, agginfo[i].oid);
-           appendPQExpBuffer(q, "-- reason: aggbasetype (oid %s) not found\n", agginfo[i].aggbasetype);
-           ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
-            q->data, "" /* Del */ , "", agginfo[i].usename, NULL, NULL);
-           continue;
-       }
-       appendPQExpBuffer(details, "BASETYPE = %s, ", name);
+   if (!convertok)
+   {
+       write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
+                 aggSig->data);
+
+       appendPQExpBuffer(q, "-- WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
+                         aggSig->data);
+       ArchiveEntry(fout, agginfo->oid, aggSig->data,
+                    agginfo->aggnamespace->nspname, agginfo->usename,
+                    "WARNING", NULL,
+                    q->data, "" /* Del */ ,
+                    NULL, NULL, NULL);
+       return;
+   }
 
-       name = findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype,
-                            zeroAsOpaque + useBaseTypeName);
-       if (name == NULL)
-       {
-           write_msg(NULL, "WARNING: aggregate function \"%s\" (oid %s) not dumped\n",
-                     agginfo[i].aggname, agginfo[i].oid);
-           write_msg(NULL, "reason: aggtranstype (oid %s) not found\n",
-                     agginfo[i].aggtranstype);
+   if (g_fout->remoteVersion >= 70300)
+   {
+       /* If using 7.3's regproc or regtype, data is already quoted */
+       appendPQExpBuffer(details, "BASETYPE = %s, SFUNC = %s, STYPE = %s",
+                         anybasetype ? "'any'" : aggbasetype,
+                         aggtransfn,
+                         aggtranstype);
+   }
+   else if (g_fout->remoteVersion >= 70100)
+   {
+       /* format_type quotes, regproc does not */
+       appendPQExpBuffer(details, "BASETYPE = %s, SFUNC = %s, STYPE = %s",
+                         anybasetype ? "'any'" : aggbasetype,
+                         fmtId(aggtransfn, force_quotes),
+                         aggtranstype);
+   }
+   else
+   {
+       /* need quotes all around */
+       appendPQExpBuffer(details, "BASETYPE = %s, ",
+                         anybasetype ? "'any'" :
+                         fmtId(aggbasetype, force_quotes));
+       appendPQExpBuffer(details, "SFUNC = %s, ",
+                         fmtId(aggtransfn, force_quotes));
+       appendPQExpBuffer(details, "STYPE = %s",
+                         fmtId(aggtranstype, force_quotes));
+   }
 
-           resetPQExpBuffer(q);
-           appendPQExpBuffer(q, "-- WARNING: aggregate function \"%s\" (oid %s) not dumped\n", agginfo[i].aggname, agginfo[i].oid);
-           appendPQExpBuffer(q, "-- reason: aggtranstype (oid %s) not found\n", agginfo[i].aggtranstype);
-           ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
-            q->data, "" /* Del */ , "", agginfo[i].usename, NULL, NULL);
-           continue;
-       }
-       appendPQExpBuffer(details,
-                         "SFUNC = %s, STYPE = %s",
-                         agginfo[i].aggtransfn, name);
+   if (!PQgetisnull(res, 0, i_agginitval))
+   {
+       appendPQExpBuffer(details, ", INITCOND = ");
+       formatStringLiteral(details, agginitval, CONV_ALL);
+   }
 
-       if (agginfo[i].agginitval)
-       {
-           appendPQExpBuffer(details, ", INITCOND = ");
-           formatStringLiteral(details, agginfo[i].agginitval, CONV_ALL);
-       }
+   if (strcmp(aggfinalfn, "-") != 0)
+   {
+       appendPQExpBuffer(details, ", FINALFUNC = %s",
+                         aggfinalfn);
+   }
 
-       if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
-           appendPQExpBuffer(details, ", FINALFUNC = %s",
-                             agginfo[i].aggfinalfn);
+   appendPQExpBuffer(delq, "DROP AGGREGATE %s;\n", aggSig->data);
 
-       resetPQExpBuffer(delq);
-       appendPQExpBuffer(delq, "DROP AGGREGATE %s;\n", aggSig->data);
+   appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
+                     fmtId(agginfo->aggname, force_quotes),
+                     details->data);
 
-       resetPQExpBuffer(q);
-       appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
-                         agginfo[i].aggname,
-                         details->data);
+   ArchiveEntry(fout, agginfo->oid, aggSig->data,
+                agginfo->aggnamespace->nspname, agginfo->usename,
+                "AGGREGATE", NULL,
+                q->data, delq->data,
+                NULL, NULL, NULL);
 
-       ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
-               q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
+   /*** Dump Aggregate Comments ***/
 
-       /*** Dump Aggregate Comments ***/
+   resetPQExpBuffer(q);
+   appendPQExpBuffer(q, "AGGREGATE %s", aggSig->data);
+   if (g_fout->remoteVersion >= 70300)
+       dumpComment(fout, q->data,
+                   agginfo->aggnamespace->nspname, agginfo->usename,
+                   agginfo->oid, "pg_proc", 0, NULL);
+   else
+       dumpComment(fout, q->data,
+                   agginfo->aggnamespace->nspname, agginfo->usename,
+                   agginfo->oid, "pg_aggregate", 0, NULL);
 
-       resetPQExpBuffer(q);
-       appendPQExpBuffer(q, "AGGREGATE %s", aggSig->data);
-       if (g_fout->remoteVersion < 70300)
-           dumpComment(fout, q->data, agginfo[i].oid, "pg_aggregate",
-                       0, NULL);
-       else
-           dumpComment(fout, q->data, agginfo[i].oid, "pg_proc",
-                       0, NULL);
-   }
+   PQclear(res);
 
+   destroyPQExpBuffer(query);
    destroyPQExpBuffer(q);
    destroyPQExpBuffer(delq);
    destroyPQExpBuffer(aggSig);
    destroyPQExpBuffer(details);
 }
 
+
 /*
  * These are some support functions to fix the acl problem of pg_dump
  *
@@ -4237,310 +4161,345 @@ dumpACL(Archive *fout, TableInfo *tbinfo)
 
    free(aclbuf);
 
-   if (tbinfo->viewdef != NULL)
+   if (tbinfo->viewoid != NULL)
        objoid = tbinfo->viewoid;
    else
        objoid = tbinfo->oid;
 
-   ArchiveEntry(fout, objoid, tbinfo->relname, "ACL",
-                NULL, sql->data, "", "", "", NULL, NULL);
+   ArchiveEntry(fout, objoid, tbinfo->relname,
+                tbinfo->relnamespace->nspname,
+                tbinfo->usename, "ACL", NULL,
+                sql->data, "", NULL, NULL, NULL);
 
    destroyPQExpBuffer(sql);
 }
 
-static void
-_dumpTableAttr70(TableInfo *tblinfo, int i, int j, PQExpBuffer q)
+/*
+ * dumpTables:
+ *   write out to fout the declarations (not data) of all user-defined tables
+ */
+void
+dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
+          const bool aclsSkip, const bool schemaOnly, const bool dataOnly)
 {
-   int32       tmp_typmod;
-   int         precision;
-   int         scale;
+   int         i;
 
-   /* Show lengths on bpchar and varchar */
-   if (!strcmp(tblinfo[i].typnames[j], "bpchar"))
+   /* Dump sequences first, in case they are referenced in table defn's */
+   for (i = 0; i < numTables; i++)
    {
-       int         len = (tblinfo[i].atttypmod[j] - VARHDRSZ);
+       TableInfo      *tbinfo = &tblinfo[i];
 
-       appendPQExpBuffer(q, "character");
-       if (len > 1)
-           appendPQExpBuffer(q, "(%d)",
-                             tblinfo[i].atttypmod[j] - VARHDRSZ);
-   }
-   else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
-   {
-       appendPQExpBuffer(q, "character varying");
-       if (tblinfo[i].atttypmod[j] != -1)
+       if (tbinfo->relkind != RELKIND_SEQUENCE)
+           continue;
+       if (tbinfo->dump)
        {
-           appendPQExpBuffer(q, "(%d)",
-                             tblinfo[i].atttypmod[j] - VARHDRSZ);
+           dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly);
+           if (!dataOnly && !aclsSkip)
+               dumpACL(fout, tbinfo);
        }
    }
-   else if (!strcmp(tblinfo[i].typnames[j], "numeric"))
+
+   if (!dataOnly)
    {
-       appendPQExpBuffer(q, "numeric");
-       if (tblinfo[i].atttypmod[j] != -1)
+       for (i = 0; i < numTables; i++)
        {
-           tmp_typmod = tblinfo[i].atttypmod[j] - VARHDRSZ;
-           precision = (tmp_typmod >> 16) & 0xffff;
-           scale = tmp_typmod & 0xffff;
-           appendPQExpBuffer(q, "(%d,%d)",
-                             precision, scale);
-       }
-   }
+           TableInfo      *tbinfo = &tblinfo[i];
 
-   /*
-    * char is an internal single-byte data type; Let's make sure we force
-    * it through with quotes. - thomas 1998-12-13
-    */
-   else if (!strcmp(tblinfo[i].typnames[j], "char"))
-   {
-       appendPQExpBuffer(q, "%s",
-                         fmtId(tblinfo[i].typnames[j], true));
-   }
-   else
-   {
-       appendPQExpBuffer(q, "%s",
-                         fmtId(tblinfo[i].typnames[j], false));
+           if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */
+               continue;
+
+           if (tbinfo->dump)
+           {
+               dumpOneTable(fout, tbinfo, tblinfo);
+               if (!aclsSkip)
+                   dumpACL(fout, tbinfo);
+           }
+       }
    }
 }
 
 /*
- * dumpTables:
- *   write out to fout all the user-define tables
+ * dumpOneTable
+ *   write the declaration (not data) of one user-defined table or view
  */
-
-void
-dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
-          const char *tablename, const bool aclsSkip,
-          const bool schemaOnly, const bool dataOnly)
+static void
+dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo)
 {
-   int         i,
-               j,
-               k;
+   PQExpBuffer query = createPQExpBuffer();
    PQExpBuffer q = createPQExpBuffer();
    PQExpBuffer delq = createPQExpBuffer();
-   char       *serialSeq = NULL;       /* implicit sequence name created
-                                        * by SERIAL datatype */
-   const char *serialSeqSuffix = "_id_seq";    /* suffix for implicit
-                                                * SERIAL sequences */
-   char      **parentRels;     /* list of names of parent relations */
+   PGresult   *res;
    int         numParents;
+   int        *parentIndexes;
    int         actual_atts;    /* number of attrs in this CREATE statment */
    char       *reltypename;
    char       *objoid;
    const char *((*commentDeps)[]);
+   int         j,
+               k;
 
-   /* First - dump SEQUENCEs */
-   if (tablename && strlen(tablename) > 0)
-   {
-       /* XXX this code only works for serial columns named "id" */
-       /* We really need dependency analysis! */
-       serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
-       strcpy(serialSeq, tablename);
-       strcat(serialSeq, serialSeqSuffix);
-   }
-   for (i = 0; i < numTables; i++)
-   {
-       if (tblinfo[i].relkind != RELKIND_SEQUENCE)
-           continue;
-       if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
-           || (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
-       {
-           /* becomeUser(fout, tblinfo[i].usename); */
-           dumpSequence(fout, tblinfo[i], schemaOnly, dataOnly);
-           if (!aclsSkip)
-               dumpACL(fout, &tblinfo[i]);
-       }
-   }
-   if (serialSeq)
-       free(serialSeq);
+   /* Make sure we are in proper schema */
+   selectSourceSchema(tbinfo->relnamespace->nspname);
 
-   for (i = 0; i < numTables; i++)
+   /* Is it a table or a view? */
+   if (tbinfo->relkind == RELKIND_VIEW)
    {
-       if (tblinfo[i].relkind == RELKIND_SEQUENCE)     /* already dumped */
-           continue;
+       char       *viewdef;
 
-       if (!tablename || (!strcmp(tblinfo[i].relname, tablename)) || (strlen(tablename) == 0))
-       {
-
-           resetPQExpBuffer(delq);
-           resetPQExpBuffer(q);
+       reltypename = "VIEW";
 
-           /* Use the view definition if there is one */
-           if (tblinfo[i].viewdef != NULL)
-           {
-               reltypename = "VIEW";
-               objoid = tblinfo[i].viewoid;
-               appendPQExpBuffer(delq, "DROP VIEW %s;\n", fmtId(tblinfo[i].relname, force_quotes));
-               appendPQExpBuffer(q, "CREATE VIEW %s as %s\n", fmtId(tblinfo[i].relname, force_quotes), tblinfo[i].viewdef);
+       /* Fetch the view definition */
+       if (g_fout->remoteVersion >= 70300)
+       {
+           /* Beginning in 7.3, viewname is not unique; use OID */
+           appendPQExpBuffer(query, "SELECT pg_get_viewdef(ev_class) as viewdef, "
+                             "oid as view_oid"
+                             " from pg_rewrite where"
+                             " ev_class = '%s'::oid and"
+                             " rulename = '_RETURN';",
+                             tbinfo->oid);
+       }
+       else
+       {
+           appendPQExpBuffer(query, "SELECT definition as viewdef, "
+                             "(select oid from pg_rewrite where "
+                             " rulename=('_RET' || viewname)::name) as view_oid"
+                             " from pg_views where viewname = ");
+           formatStringLiteral(query, tbinfo->relname, CONV_ALL);
+           appendPQExpBuffer(query, ";");
+       }
 
-               /*
-                * Views can have default values -- however, they must be
-                * specified in an ALTER TABLE command after the view has
-                * been created, not in the view definition itself.
-                */
-               for (j = 0; j < tblinfo[i].numatts; j++)
-               {
-                   if (tblinfo[i].adef_expr[j] != NULL && tblinfo[i].inhAttrDef[j] == 0) {
-                       appendPQExpBuffer(q, "ALTER TABLE %s ", fmtId(tblinfo[i].relname, force_quotes));
-                       appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
-                                         fmtId(tblinfo[i].attnames[j], force_quotes),
-                                         tblinfo[i].adef_expr[j]);
-                   }
-               }
+       res = PQexec(g_conn, query->data);
+       if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
+       {
+           write_msg(NULL, "query to obtain definition of view \"%s\" failed: %s",
+                     tbinfo->relname, PQerrorMessage(g_conn));
+           exit_nicely();
+       }
 
-               commentDeps = malloc(sizeof(char *) * 2);
-               (*commentDeps)[0] = strdup(objoid);
-               (*commentDeps)[1] = NULL;       /* end of list */
-           }
+       if (PQntuples(res) != 1)
+       {
+           if (PQntuples(res) < 1)
+               write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
+                         tbinfo->relname);
            else
-           {
-               reltypename = "TABLE";
-               objoid = tblinfo[i].oid;
-               commentDeps = NULL;
-               parentRels = tblinfo[i].parentRels;
-               numParents = tblinfo[i].numParents;
-
-               appendPQExpBuffer(delq, "DROP TABLE %s;\n", fmtId(tblinfo[i].relname, force_quotes));
+               write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
+                         tbinfo->relname);
+           exit_nicely();
+       }
 
-               appendPQExpBuffer(q, "CREATE TABLE %s (\n\t", fmtId(tblinfo[i].relname, force_quotes));
-               actual_atts = 0;
-               for (j = 0; j < tblinfo[i].numatts; j++)
-               {
-                   /* Is this one of the table's own attrs ? */
-                   if (tblinfo[i].inhAttrs[j] == 0)
-                   {
-                       /* Format properly if not first attr */
-                       if (actual_atts > 0)
-                           appendPQExpBuffer(q, ",\n\t");
+       if (PQgetisnull(res, 0, 1))
+       {
+           write_msg(NULL, "query to obtain definition of view \"%s\" returned NULL oid\n",
+                     tbinfo->relname);
+           exit_nicely();
+       }
 
-                       /* Attr name & type */
-                       appendPQExpBuffer(q, "%s ", fmtId(tblinfo[i].attnames[j], force_quotes));
+       viewdef = PQgetvalue(res, 0, 0);
 
-                       if (g_fout->remoteVersion >= 70100)
-                           appendPQExpBuffer(q, "%s", tblinfo[i].atttypedefns[j]);
-                       else
-                           _dumpTableAttr70(tblinfo, i, j, q);
+       if (strlen(viewdef) == 0)
+       {
+           write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
+                     tbinfo->relname);
+           exit_nicely();
+       }
 
-                       /* Default value */
-                       if (tblinfo[i].adef_expr[j] != NULL && tblinfo[i].inhAttrDef[j] == 0)
-                           appendPQExpBuffer(q, " DEFAULT %s",
-                                             tblinfo[i].adef_expr[j]);
+       /* We use the OID of the view rule as the object OID */
+       objoid = strdup(PQgetvalue(res, 0, 1));
+       /* Save it for use by dumpACL, too */
+       tbinfo->viewoid = objoid;
 
-                       /* Not Null constraint */
-                       if (tblinfo[i].notnull[j] && tblinfo[i].inhNotNull[j] == 0)
-                           appendPQExpBuffer(q, " NOT NULL");
+       appendPQExpBuffer(delq, "DROP VIEW %s;\n",
+                         fmtId(tbinfo->relname, force_quotes));
+       appendPQExpBuffer(q, "CREATE VIEW %s AS %s\n",
+                         fmtId(tbinfo->relname, force_quotes), viewdef);
 
-                       actual_atts++;
-                   }
-               }
+       PQclear(res);
 
+       /*
+        * Views can have default values -- however, they must be
+        * specified in an ALTER TABLE command after the view has
+        * been created, not in the view definition itself.
+        */
+       for (j = 0; j < tbinfo->numatts; j++)
+       {
+           if (tbinfo->adef_expr[j] != NULL && !tbinfo->inhAttrDef[j])
+           {
+               appendPQExpBuffer(q, "ALTER TABLE %s ",
+                                 fmtId(tbinfo->relname, force_quotes));
+               appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
+                                 fmtId(tbinfo->attnames[j], force_quotes),
+                                 tbinfo->adef_expr[j]);
+           }
+       }
 
+       commentDeps = malloc(sizeof(char *) * 2);
+       (*commentDeps)[0] = strdup(objoid);
+       (*commentDeps)[1] = NULL;       /* end of list */
+   }
+   else
+   {
+       reltypename = "TABLE";
+       objoid = tbinfo->oid;
+       commentDeps = NULL;
+       numParents = tbinfo->numParents;
+       parentIndexes = tbinfo->parentIndexes;
 
-               /* Put the CONSTRAINTS inside the table def */
-               for (k = 0; k < tblinfo[i].ncheck; k++)
-               {
-                   if (actual_atts + k > 0)
-                       appendPQExpBuffer(q, ",\n\t");
+       appendPQExpBuffer(delq, "DROP TABLE %s;\n",
+                         fmtId(tbinfo->relname, force_quotes));
 
-                   appendPQExpBuffer(q, "%s",
-                                     tblinfo[i].check_expr[k]);
-               }
+       appendPQExpBuffer(q, "CREATE TABLE %s (\n\t",
+                         fmtId(tbinfo->relname, force_quotes));
+       actual_atts = 0;
+       for (j = 0; j < tbinfo->numatts; j++)
+       {
+           /* Is this one of the table's own attrs ? */
+           if (!tbinfo->inhAttrs[j])
+           {
+               /* Format properly if not first attr */
+               if (actual_atts > 0)
+                   appendPQExpBuffer(q, ",\n\t");
 
-               /*
-                * Primary Key: In versions of PostgreSQL prior to 7.2, we
-                * needed to include the primary key in the table definition.
-                * However, this is not ideal because it creates an index
-                * on the table, which makes COPY slower. As of release 7.2,
-                * we can add primary keys to a table after is has been created,
-                * using ALTER TABLE ; see dumpIndexes() for more information.
-                * Therefore, we ignore primary keys in this function.
-                */
+               /* Attr name & type */
+               appendPQExpBuffer(q, "%s ",
+                                 fmtId(tbinfo->attnames[j], force_quotes));
 
-               appendPQExpBuffer(q, "\n)");
+               /* If no format_type, fake it */
+               if (g_fout->remoteVersion >= 70100)
+                   appendPQExpBuffer(q, "%s", tbinfo->atttypnames[j]);
+               else
+                   appendPQExpBuffer(q, "%s",
+                                     myFormatType(tbinfo->atttypnames[j],
+                                                  tbinfo->atttypmod[j]));
 
-               if (numParents > 0)
-               {
-                   appendPQExpBuffer(q, "\nINHERITS (");
-                   for (k = 0; k < numParents; k++)
-                   {
-                       appendPQExpBuffer(q, "%s%s",
-                                         (k > 0) ? ", " : "",
-                                    fmtId(parentRels[k], force_quotes));
-                   }
-                   appendPQExpBuffer(q, ")");
-               }
+               /* Default value */
+               if (tbinfo->adef_expr[j] != NULL && !tbinfo->inhAttrDef[j])
+                   appendPQExpBuffer(q, " DEFAULT %s",
+                                     tbinfo->adef_expr[j]);
 
-               if (!tblinfo[i].hasoids)
-                   appendPQExpBuffer(q, " WITHOUT OIDS");
+               /* Not Null constraint */
+               if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
+                   appendPQExpBuffer(q, " NOT NULL");
 
-               appendPQExpBuffer(q, ";\n");
+               actual_atts++;
            }
+       }
 
-           if (!dataOnly)
-           {
-
-               ArchiveEntry(fout, objoid, tblinfo[i].relname,
-                            reltypename, NULL, q->data, delq->data, "", tblinfo[i].usename,
-                            NULL, NULL);
+       /*
+        * Add non-inherited CHECK constraints, if any. If a
+        * constraint matches by name and condition with a constraint
+        * belonging to a parent class (OR conditions match and both names
+        * start with '$'), we assume it was inherited.
+        */
+       if (tbinfo->ncheck > 0)
+       {
+           PGresult   *res2;
+           int         i_rcname,
+                       i_rcsrc;
+           int         ntups2;
 
-               if (!aclsSkip)
-                   dumpACL(fout, &tblinfo[i]);
+           if (g_verbose)
+               write_msg(NULL, "finding CHECK constraints for table %s\n",
+                         tbinfo->relname);
 
+           resetPQExpBuffer(query);
+           appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
+                             " where rcrelid = '%s'::oid "
+                             "   and not exists "
+                             "  (select 1 from pg_relcheck as c, "
+                             "    pg_inherits as i "
+                             "    where i.inhrelid = pg_relcheck.rcrelid "
+                             "      and (c.rcname = pg_relcheck.rcname "
+                             "          or (c.rcname[0] = '$' "
+                             "              and pg_relcheck.rcname[0] = '$')"
+                             "          )"
+                             "      and c.rcsrc = pg_relcheck.rcsrc "
+                             "      and c.rcrelid = i.inhparent) "
+                             " order by rcname ",
+                             tbinfo->oid);
+           res2 = PQexec(g_conn, query->data);
+           if (!res2 ||
+               PQresultStatus(res2) != PGRES_TUPLES_OK)
+           {
+               write_msg(NULL, "query to obtain check constraints failed: %s", PQerrorMessage(g_conn));
+               exit_nicely();
            }
-
-           /* Dump Field Comments */
-
-           for (j = 0; j < tblinfo[i].numatts; j++)
+           ntups2 = PQntuples(res2);
+           if (ntups2 > tbinfo->ncheck)
            {
-               resetPQExpBuffer(q);
-               appendPQExpBuffer(q, "COLUMN %s", fmtId(tblinfo[i].relname, force_quotes));
-               appendPQExpBuffer(q, ".");
-               appendPQExpBuffer(q, "%s", fmtId(tblinfo[i].attnames[j], force_quotes));
-               dumpComment(fout, q->data, tblinfo[i].oid,
-                           "pg_class", j + 1, commentDeps);
+               write_msg(NULL, "expected %d check constraints on table \"%s\" but found %d\n",
+                         tbinfo->ncheck, tbinfo->relname, ntups2);
+               write_msg(NULL, "(The system catalogs might be corrupted.)\n");
+               exit_nicely();
            }
 
-           /* Dump Table Comments */
+           i_rcname = PQfnumber(res2, "rcname");
+           i_rcsrc = PQfnumber(res2, "rcsrc");
 
-           resetPQExpBuffer(q);
-           appendPQExpBuffer(q, "%s %s", reltypename, fmtId(tblinfo[i].relname, force_quotes));
-           dumpComment(fout, q->data, tblinfo[i].oid,
-                       "pg_class", 0, commentDeps);
+           for (j = 0; j < ntups2; j++)
+           {
+               const char *name = PQgetvalue(res2, j, i_rcname);
+               const char *expr = PQgetvalue(res2, j, i_rcsrc);
+
+               if (actual_atts + j > 0)
+                   appendPQExpBuffer(q, ",\n\t");
 
+               if (name[0] != '$')
+                   appendPQExpBuffer(q, "CONSTRAINT %s ",
+                                     fmtId(name, force_quotes));
+               appendPQExpBuffer(q, "CHECK (%s)", expr);
+           }
+           PQclear(res2);
        }
-   }
 
-   destroyPQExpBuffer(q);
-   destroyPQExpBuffer(delq);
-}
+       /*
+        * Primary Key: In versions of PostgreSQL prior to 7.2, we
+        * needed to include the primary key in the table definition.
+        * However, this is not ideal because it creates an index
+        * on the table, which makes COPY slower. As of release 7.2,
+        * we can add primary keys to a table after it has been created,
+        * using ALTER TABLE; see dumpIndexes() for more information.
+        * Therefore, we ignore primary keys in this function.
+        */
 
-static PQExpBuffer
-getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo)
-{
-   PQExpBuffer pkBuf = createPQExpBuffer();
-   int         k;
+       appendPQExpBuffer(q, "\n)");
 
-   appendPQExpBuffer(pkBuf, "Constraint %s Primary Key (",
-                     tblInfo->primary_key_name);
+       if (numParents > 0)
+       {
+           appendPQExpBuffer(q, "\nINHERITS (");
+           for (k = 0; k < numParents; k++)
+           {
+               TableInfo  *parentRel = &g_tblinfo[parentIndexes[k]];
 
-   for (k = 0; k < indInfo->indnkeys; k++)
-   {
-       int         indkey;
-       const char *attname;
+               if (k > 0)
+                   appendPQExpBuffer(q, ", ");
+               if (parentRel->relnamespace != tbinfo->relnamespace)
+                   appendPQExpBuffer(q, "%s.",
+                                     fmtId(parentRel->relnamespace->nspname,
+                                           force_quotes));
+               appendPQExpBuffer(q, "%s",
+                                 fmtId(parentRel->relname, force_quotes));
+           }
+           appendPQExpBuffer(q, ")");
+       }
 
-       indkey = atoi(indInfo->indkey[k]);
-       if (indkey == InvalidAttrNumber)
-           break;
-       attname = getAttrName(indkey, tblInfo);
+       if (!tbinfo->hasoids)
+           appendPQExpBuffer(q, " WITHOUT OIDS");
 
-       appendPQExpBuffer(pkBuf, "%s%s",
-                         (k == 0) ? "" : ", ",
-                         fmtId(attname, force_quotes));
+       appendPQExpBuffer(q, ";\n");
    }
 
-   appendPQExpBuffer(pkBuf, ")");
+   ArchiveEntry(fout, objoid, tbinfo->relname,
+                tbinfo->relnamespace->nspname, tbinfo->usename,
+                reltypename, NULL, q->data, delq->data,
+                NULL, NULL, NULL);
 
-   return pkBuf;
+   /* Dump Table Comments */
+   dumpTableComment(fout, tbinfo, reltypename, commentDeps);
+
+   destroyPQExpBuffer(query);
+   destroyPQExpBuffer(q);
+   destroyPQExpBuffer(delq);
 }
 
 /*
@@ -4580,149 +4539,154 @@ getAttrName(int attrnum, TableInfo *tblInfo)
 
 /*
  * dumpIndexes:
- *   write out to fout all the user-defined indexes
+ *   write out to fout all the user-defined indexes for dumpable tables
  */
 void
-dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes,
-           TableInfo *tblinfo, int numTables, const char *tablename)
+dumpIndexes(Archive *fout, TableInfo *tblinfo, int numTables)
 {
-   int         i;
-   int         tableInd;
+   int         i,
+               j;
+   PQExpBuffer query = createPQExpBuffer();
    PQExpBuffer q = createPQExpBuffer();
    PQExpBuffer delq = createPQExpBuffer();
-   PQExpBuffer id1 = createPQExpBuffer();
+   PGresult   *res;
+   int         ntups;
+   int         i_indexreloid;
+   int         i_indexrelname;
+   int         i_indexdef;
+   int         i_indisprimary;
+   int         i_indkey;
+   int         i_indnkeys;
 
-   for (i = 0; i < numIndexes; i++)
+   for (i = 0; i < numTables; i++)
    {
-       if (tablename && tablename[0] &&
-           (strcmp(indinfo[i].indrelname, tablename) != 0))
-           continue;
-
-       tableInd = findTableByName(tblinfo, numTables,
-                                  indinfo[i].indrelname);
-       if (tableInd < 0)
-       {
-           write_msg(NULL, "dumpIndexes(): failed sanity check, table %s was not found\n",
-                     indinfo[i].indrelname);
-           exit_nicely();
-       }
-
-       /* Handle PK indexes */
-       if (strcmp(indinfo[i].indisprimary, "t") == 0)
-       {
-           PQExpBuffer consDef = getPKconstraint(&tblinfo[tableInd], &indinfo[i]);
+       TableInfo  *tbinfo = &tblinfo[i];
 
-           resetPQExpBuffer(q);
-
-           appendPQExpBuffer(q, "Alter Table %s Add %s;",
-                             fmtId(tblinfo[tableInd].relname, force_quotes),
-                             consDef->data);
-
-           ArchiveEntry(fout, indinfo[i].indexreloid, tblinfo[tableInd].primary_key_name,
-                        "CONSTRAINT", NULL, q->data, "",
-                        "", tblinfo[tableInd].usename, NULL, NULL);
-
-           destroyPQExpBuffer(consDef);
-
-           /*
-            * Don't need to do anything else for this system-generated
-            * index
-            */
+       /* Only plain tables have indexes */
+       if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
            continue;
-       }
 
-       resetPQExpBuffer(id1);
-       appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
-
-       resetPQExpBuffer(q);
-       appendPQExpBuffer(q, "%s;\n", indinfo[i].indexdef);
-
-       resetPQExpBuffer(delq);
-       appendPQExpBuffer(delq, "DROP INDEX %s;\n", id1->data);
-
-       /*
-        * We make the index belong to the owner of its table, which is
-        * not necessarily right but should answer 99% of the time. Would
-        * have to add owner name to IndInfo to do it right.
-        */
-       ArchiveEntry(fout, indinfo[i].indexreloid, id1->data,
-                    "INDEX", NULL, q->data, delq->data,
-                    "", tblinfo[tableInd].usename, NULL, NULL);
+       if (!tbinfo->dump)
+           continue;
 
-       /* Dump Index Comments */
-       resetPQExpBuffer(q);
-       appendPQExpBuffer(q, "INDEX %s", id1->data);
-       dumpComment(fout, q->data, indinfo[i].indexreloid,
-                   "pg_class", 0, NULL);
-   }
+       /* Make sure we are in proper schema so indexdef is right */
+       selectSourceSchema(tbinfo->relnamespace->nspname);
 
-   destroyPQExpBuffer(q);
-   destroyPQExpBuffer(delq);
-   destroyPQExpBuffer(id1);
-}
+       resetPQExpBuffer(query);
+       appendPQExpBuffer(query,
+                         "SELECT i.indexrelid as indexreloid, "
+                         "t.relname as indexrelname, "
+                         "pg_get_indexdef(i.indexrelid) as indexdef, "
+                         "i.indisprimary, i.indkey, "
+                         "t.relnatts as indnkeys "
+                         "FROM pg_index i, pg_class t "
+                         "WHERE t.oid = i.indexrelid "
+                         "AND i.indrelid = '%s'::oid "
+                         "ORDER BY indexrelname",
+                         tbinfo->oid);
 
-/*
- * dumpTuples
- *   prints out the tuples in ASCII representation. The output is a valid
- *   input to COPY FROM stdin.
- *
- *   We only need to do this for POSTGRES 4.2 databases since the
- *   COPY TO statment doesn't escape newlines properly. It's been fixed
- *   in PostgreSQL.
- *
- * the attrmap passed in tells how to map the attributes copied in to the
- * attributes copied out
- */
-#ifdef NOT_USED
-void
-dumpTuples(PGresult *res, FILE *fout, int *attrmap)
-{
-   int         j,
-               k;
-   int         m,
-               n;
-   char      **outVals = NULL; /* values to copy out */
+       res = PQexec(g_conn, query->data);
+       if (!res ||
+           PQresultStatus(res) != PGRES_TUPLES_OK)
+       {
+           write_msg(NULL, "query to obtain list of indexes failed: %s", PQerrorMessage(g_conn));
+           exit_nicely();
+       }
 
-   n = PQntuples(res);
-   m = PQnfields(res);
+       ntups = PQntuples(res);
 
-   if (m > 0)
-   {
-       /*
-        * Print out the tuples but only print tuples with at least 1
-        * field.
-        */
-       outVals = (char **) malloc(m * sizeof(char *));
+       i_indexreloid = PQfnumber(res, "indexreloid");
+       i_indexrelname = PQfnumber(res, "indexrelname");
+       i_indexdef = PQfnumber(res, "indexdef");
+       i_indisprimary = PQfnumber(res, "indisprimary");
+       i_indkey = PQfnumber(res, "indkey");
+       i_indnkeys = PQfnumber(res, "indnkeys");
 
-       for (j = 0; j < n; j++)
+       for (j = 0; j < ntups; j++)
        {
-           for (k = 0; k < m; k++)
-               outVals[attrmap[k]] = PQgetvalue(res, j, k);
-           for (k = 0; k < m; k++)
+           const char *indexreloid = PQgetvalue(res, j, i_indexreloid);
+           const char *indexrelname = PQgetvalue(res, j, i_indexrelname);
+           const char *indexdef = PQgetvalue(res, j, i_indexdef);
+           const char *indisprimary = PQgetvalue(res, j, i_indisprimary);
+
+           resetPQExpBuffer(q);
+           resetPQExpBuffer(delq);
+
+           if (strcmp(indisprimary, "t") == 0)
            {
-               char       *pval = outVals[k];
+               /* Handle PK indexes specially */
+               int indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
+               char **indkeys = (char **) malloc(indnkeys * sizeof(char *));
+               int         k;
+
+               parseNumericArray(PQgetvalue(res, j, i_indkey),
+                                 indkeys, indnkeys);
 
-               if (k != 0)
-                   fputc('\t', fout);  /* delimiter for attribute */
+               appendPQExpBuffer(q, "ALTER TABLE %s ADD ",
+                                 fmtId(tbinfo->relname, force_quotes));
+               appendPQExpBuffer(q, "CONSTRAINT %s PRIMARY KEY (",
+                                 fmtId(indexrelname, force_quotes));
 
-               if (pval)
+               for (k = 0; k < indnkeys; k++)
                {
-                   while (*pval != '\0')
-                   {
-                       /* escape tabs, newlines and backslashes */
-                       if (*pval == '\t' || *pval == '\n' || *pval == '\\')
-                           fputc('\\', fout);
-                       fputc(*pval, fout);
-                       pval++;
-                   }
+                   int         indkey = atoi(indkeys[k]);
+                   const char *attname;
+
+                   if (indkey == InvalidAttrNumber)
+                       break;
+                   attname = getAttrName(indkey, tbinfo);
+
+                   appendPQExpBuffer(q, "%s%s",
+                                     (k == 0) ? "" : ", ",
+                                     fmtId(attname, force_quotes));
                }
+
+               appendPQExpBuffer(q, ");\n");
+
+               ArchiveEntry(fout, indexreloid,
+                            indexrelname,
+                            tbinfo->relnamespace->nspname,
+                            tbinfo->usename,
+                            "CONSTRAINT", NULL,
+                            q->data, "",
+                            NULL, NULL, NULL);
+
+               free(indkeys);
+           }
+           else
+           {
+               /* Plain secondary index */
+               appendPQExpBuffer(q, "%s;\n", indexdef);
+
+               appendPQExpBuffer(delq, "DROP INDEX %s;\n",
+                                 fmtId(indexrelname, force_quotes));
+
+               ArchiveEntry(fout, indexreloid,
+                            indexrelname,
+                            tbinfo->relnamespace->nspname,
+                            tbinfo->usename,
+                            "INDEX", NULL,
+                            q->data, delq->data,
+                            NULL, NULL, NULL);
            }
-           fputc('\n', fout);  /* delimiter for a tuple */
+
+           /* Dump Index Comments */
+           resetPQExpBuffer(q);
+           appendPQExpBuffer(q, "INDEX %s",
+                             fmtId(indexrelname, force_quotes));
+           dumpComment(fout, q->data,
+                       tbinfo->relnamespace->nspname,
+                       tbinfo->usename,
+                       indexreloid, "pg_class", 0, NULL);
        }
-       free(outVals);
+
+       PQclear(res);
    }
+
+   destroyPQExpBuffer(query);
+   destroyPQExpBuffer(q);
+   destroyPQExpBuffer(delq);
 }
-#endif
 
 /*
  * setMaxOid -
@@ -4776,7 +4740,10 @@ setMaxOid(Archive *fout)
             "DROP TABLE pgdump_oid;\n",
             max_oid);
 
-   ArchiveEntry(fout, "0", "Max OID", "", NULL, sql, "", "", "", NULL, NULL);
+   ArchiveEntry(fout, "0", "Max OID", NULL, "",
+                "", NULL,
+                sql, "",
+                NULL, NULL, NULL);
 }
 
 /*
@@ -4860,7 +4827,8 @@ findLastBuiltinOid_V70(void)
 }
 
 static void
-dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly)
+dumpOneSequence(Archive *fout, TableInfo *tbinfo,
+               const bool schemaOnly, const bool dataOnly)
 {
    PGresult   *res;
    char       *last,
@@ -4873,31 +4841,34 @@ dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool
    PQExpBuffer query = createPQExpBuffer();
    PQExpBuffer delqry = createPQExpBuffer();
 
+   /* Make sure we are in proper schema */
+   selectSourceSchema(tbinfo->relnamespace->nspname);
+
    appendPQExpBuffer(query,
            "SELECT sequence_name, last_value, increment_by, max_value, "
                  "min_value, cache_value, is_cycled, is_called from %s",
-                     fmtId(tbinfo.relname, force_quotes));
+                     fmtId(tbinfo->relname, force_quotes));
 
    res = PQexec(g_conn, query->data);
    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
    {
-       write_msg(NULL, "query to get data of sequence \"%s\" failed: %s", tbinfo.relname, PQerrorMessage(g_conn));
+       write_msg(NULL, "query to get data of sequence \"%s\" failed: %s", tbinfo->relname, PQerrorMessage(g_conn));
        exit_nicely();
    }
 
    if (PQntuples(res) != 1)
    {
        write_msg(NULL, "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
-                 tbinfo.relname, PQntuples(res));
+                 tbinfo->relname, PQntuples(res));
        exit_nicely();
    }
 
    /* Disable this check: it fails if sequence has been renamed */
 #ifdef NOT_USED
-   if (strcmp(PQgetvalue(res, 0, 0), tbinfo.relname) != 0)
+   if (strcmp(PQgetvalue(res, 0, 0), tbinfo->relname) != 0)
    {
        write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
-                 tbinfo.relname, PQgetvalue(res, 0, 0));
+                 tbinfo->relname, PQgetvalue(res, 0, 0));
        exit_nicely();
    }
 #endif
@@ -4923,33 +4894,37 @@ dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool
    {
        resetPQExpBuffer(delqry);
        appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
-                         fmtId(tbinfo.relname, force_quotes));
+                         fmtId(tbinfo->relname, force_quotes));
 
        resetPQExpBuffer(query);
        appendPQExpBuffer(query,
                          "CREATE SEQUENCE %s start %s increment %s "
                          "maxvalue %s minvalue %s cache %s%s;\n",
-                         fmtId(tbinfo.relname, force_quotes),
+                         fmtId(tbinfo->relname, force_quotes),
                          (called ? minv : last),
                          incby, maxv, minv, cache,
                          (cycled ? " cycle" : ""));
 
-       ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE", NULL,
-                    query->data, delqry->data, "", tbinfo.usename,
-                    NULL, NULL);
+       ArchiveEntry(fout, tbinfo->oid, tbinfo->relname,
+                    tbinfo->relnamespace->nspname, tbinfo->usename,
+                    "SEQUENCE", NULL,
+                    query->data, delqry->data,
+                    NULL, NULL, NULL);
    }
 
    if (!schemaOnly)
    {
        resetPQExpBuffer(query);
        appendPQExpBuffer(query, "SELECT setval (");
-       formatStringLiteral(query, fmtId(tbinfo.relname, force_quotes), CONV_ALL);
+       formatStringLiteral(query, fmtId(tbinfo->relname, force_quotes), CONV_ALL);
        appendPQExpBuffer(query, ", %s, %s);\n",
                          last, (called ? "true" : "false"));
 
-       ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE SET", NULL,
-                    query->data, "" /* Del */ , "", tbinfo.usename,
-                    NULL, NULL);
+       ArchiveEntry(fout, tbinfo->oid, tbinfo->relname,
+                    tbinfo->relnamespace->nspname, tbinfo->usename,
+                    "SEQUENCE SET", NULL,
+                    query->data, "" /* Del */ ,
+                    NULL, NULL, NULL);
    }
 
    if (!dataOnly)
@@ -4957,9 +4932,10 @@ dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool
        /* Dump Sequence Comments */
 
        resetPQExpBuffer(query);
-       appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo.relname, force_quotes));
-       dumpComment(fout, query->data, tbinfo.oid,
-                   "pg_class", 0, NULL);
+       appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->relname, force_quotes));
+       dumpComment(fout, query->data,
+                   tbinfo->relnamespace->nspname, tbinfo->usename,
+                   tbinfo->oid, "pg_class", 0, NULL);
    }
 
    PQclear(res);
@@ -4970,45 +4946,286 @@ dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool
 
 
 static void
-dumpTriggers(Archive *fout, const char *tablename,
-            TableInfo *tblinfo, int numTables)
+dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables)
 {
    int         i,
                j;
-
-   if (g_verbose)
-       write_msg(NULL, "dumping out triggers\n");
+   PQExpBuffer query = createPQExpBuffer();
+   PQExpBuffer delqry = createPQExpBuffer();
+   PGresult   *res;
+   int         i_tgoid,
+               i_tgname,
+               i_tgfname,
+               i_tgtype,
+               i_tgnargs,
+               i_tgargs,
+               i_tgisconstraint,
+               i_tgconstrname,
+               i_tgdeferrable,
+               i_tgconstrrelid,
+               i_tgconstrrelname,
+               i_tginitdeferred;
+   int         ntups;
 
    for (i = 0; i < numTables; i++)
    {
-       if (tablename && (strcmp(tblinfo[i].relname, tablename) != 0) && (strlen(tablename) > 0))
+       TableInfo      *tbinfo = &tblinfo[i];
+
+       if (tbinfo->ntrig == 0 || !tbinfo->dump)
            continue;
 
-       for (j = 0; j < tblinfo[i].ntrig; j++)
+       if (g_verbose)
+           write_msg(NULL, "dumping triggers for table %s\n",
+                     tbinfo->relname);
+
+       /* select table schema to ensure regproc name is qualified if needed */
+       selectSourceSchema(tbinfo->relnamespace->nspname);
+
+       resetPQExpBuffer(query);
+       if (g_fout->remoteVersion >= 70300)
+       {
+           appendPQExpBuffer(query,
+                             "SELECT tgname, tgfoid::regproc as tgfname, "
+                             "tgtype, tgnargs, tgargs, "
+                             "tgisconstraint, tgconstrname, tgdeferrable, "
+                             "tgconstrrelid, tginitdeferred, oid, "
+                             "tgconstrrelid::regclass as tgconstrrelname "
+                             "from pg_trigger "
+                             "where tgrelid = '%s'::oid",
+                             tbinfo->oid);
+       }
+       else
+       {
+           appendPQExpBuffer(query,
+                             "SELECT tgname, tgfoid::regproc as tgfname, "
+                             "tgtype, tgnargs, tgargs, "
+                             "tgisconstraint, tgconstrname, tgdeferrable, "
+                             "tgconstrrelid, tginitdeferred, oid, "
+                             "(select relname from pg_class where oid = tgconstrrelid) "
+                             "     as tgconstrrelname "
+                             "from pg_trigger "
+                             "where tgrelid = '%s'::oid",
+                             tbinfo->oid);
+       }
+       res = PQexec(g_conn, query->data);
+       if (!res ||
+           PQresultStatus(res) != PGRES_TUPLES_OK)
+       {
+           write_msg(NULL, "query to obtain list of triggers failed: %s", PQerrorMessage(g_conn));
+           exit_nicely();
+       }
+       ntups = PQntuples(res);
+       if (ntups != tbinfo->ntrig)
+       {
+           write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
+                     tbinfo->ntrig, tbinfo->relname, ntups);
+           exit_nicely();
+       }
+       i_tgname = PQfnumber(res, "tgname");
+       i_tgfname = PQfnumber(res, "tgfname");
+       i_tgtype = PQfnumber(res, "tgtype");
+       i_tgnargs = PQfnumber(res, "tgnargs");
+       i_tgargs = PQfnumber(res, "tgargs");
+       i_tgoid = PQfnumber(res, "oid");
+       i_tgisconstraint = PQfnumber(res, "tgisconstraint");
+       i_tgconstrname = PQfnumber(res, "tgconstrname");
+       i_tgdeferrable = PQfnumber(res, "tgdeferrable");
+       i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
+       i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
+       i_tginitdeferred = PQfnumber(res, "tginitdeferred");
+
+       for (j = 0; j < ntups; j++)
        {
-           ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
-                  "TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "",
-                        tblinfo[i].usename, NULL, NULL);
-           dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid,
-                       "pg_trigger", 0, NULL);
+           const char *tgoid = PQgetvalue(res, j, i_tgoid);
+           char       *tgname = PQgetvalue(res, j, i_tgname);
+           const char *tgfname = PQgetvalue(res, j, i_tgfname);
+           int2        tgtype = atoi(PQgetvalue(res, j, i_tgtype));
+           int         tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
+           const char *tgargs = PQgetvalue(res, j, i_tgargs);
+           int         tgisconstraint;
+           int         tgdeferrable;
+           int         tginitdeferred;
+           char       *tgconstrrelid;
+           const char *p;
+           int         findx;
+
+           if (strcmp(PQgetvalue(res, j, i_tgisconstraint), "f") == 0)
+               tgisconstraint = 0;
+           else
+               tgisconstraint = 1;
+
+           if (strcmp(PQgetvalue(res, j, i_tgdeferrable), "f") == 0)
+               tgdeferrable = 0;
+           else
+               tgdeferrable = 1;
+
+           if (strcmp(PQgetvalue(res, j, i_tginitdeferred), "f") == 0)
+               tginitdeferred = 0;
+           else
+               tginitdeferred = 1;
+
+           resetPQExpBuffer(delqry);
+           appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
+                             fmtId(tgname, force_quotes));
+           appendPQExpBuffer(delqry, "ON %s;\n",
+                             fmtId(tbinfo->relname, force_quotes));
+
+           resetPQExpBuffer(query);
+           if (tgisconstraint)
+           {
+               appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
+               appendPQExpBuffer(query, fmtId(PQgetvalue(res, j, i_tgconstrname), force_quotes));
+           }
+           else
+           {
+               appendPQExpBuffer(query, "CREATE TRIGGER ");
+               appendPQExpBuffer(query, fmtId(tgname, force_quotes));
+           }
+           appendPQExpBufferChar(query, ' ');
+           /* Trigger type */
+           findx = 0;
+           if (TRIGGER_FOR_BEFORE(tgtype))
+               appendPQExpBuffer(query, "BEFORE");
+           else
+               appendPQExpBuffer(query, "AFTER");
+           if (TRIGGER_FOR_INSERT(tgtype))
+           {
+               appendPQExpBuffer(query, " INSERT");
+               findx++;
+           }
+           if (TRIGGER_FOR_DELETE(tgtype))
+           {
+               if (findx > 0)
+                   appendPQExpBuffer(query, " OR DELETE");
+               else
+                   appendPQExpBuffer(query, " DELETE");
+               findx++;
+           }
+           if (TRIGGER_FOR_UPDATE(tgtype))
+           {
+               if (findx > 0)
+                   appendPQExpBuffer(query, " OR UPDATE");
+               else
+                   appendPQExpBuffer(query, " UPDATE");
+           }
+           appendPQExpBuffer(query, " ON %s ",
+                             fmtId(tbinfo->relname, force_quotes));
+
+           if (tgisconstraint)
+           {
+               tgconstrrelid = PQgetvalue(res, j, i_tgconstrrelid);
+
+               if (strcmp(tgconstrrelid, "0") != 0)
+               {
+
+                   if (PQgetisnull(res, j, i_tgconstrrelname))
+                   {
+                       write_msg(NULL, "query produced NULL referenced table name for foreign key trigger \"%s\" on table \"%s\" (oid of table: %s)\n",
+                                 tgname, tbinfo->relname, tgconstrrelid);
+                       exit_nicely();
+                   }
+
+                   /* If we are using regclass, name is already quoted */
+                   if (g_fout->remoteVersion >= 70300)
+                       appendPQExpBuffer(query, " FROM %s",
+                                         PQgetvalue(res, j, i_tgconstrrelname));
+                   else
+                       appendPQExpBuffer(query, " FROM %s",
+                                         fmtId(PQgetvalue(res, j, i_tgconstrrelname), force_quotes));
+               }
+               if (!tgdeferrable)
+                   appendPQExpBuffer(query, " NOT");
+               appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
+               if (tginitdeferred)
+                   appendPQExpBuffer(query, "DEFERRED");
+               else
+                   appendPQExpBuffer(query, "IMMEDIATE");
+
+           }
+
+           appendPQExpBuffer(query, " FOR EACH ROW");
+           /* In 7.3, result of regproc is already quoted */
+           if (g_fout->remoteVersion >= 70300)
+               appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
+                                 tgfname);
+           else
+               appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
+                                 fmtId(tgfname, force_quotes));
+           for (findx = 0; findx < tgnargs; findx++)
+           {
+               const char *s;
+
+               for (p = tgargs;;)
+               {
+                   p = strchr(p, '\\');
+                   if (p == NULL)
+                   {
+                       write_msg(NULL, "bad argument string (%s) for trigger \"%s\" on table \"%s\"\n",
+                                 PQgetvalue(res, j, i_tgargs),
+                                 tgname,
+                                 tbinfo->relname);
+                       exit_nicely();
+                   }
+                   p++;
+                   if (*p == '\\')
+                   {
+                       p++;
+                       continue;
+                   }
+                   if (p[0] == '0' && p[1] == '0' && p[2] == '0')
+                       break;
+               }
+               p--;
+               appendPQExpBufferChar(query, '\'');
+               for (s = tgargs; s < p;)
+               {
+                   if (*s == '\'')
+                       appendPQExpBufferChar(query, '\\');
+                   appendPQExpBufferChar(query, *s++);
+               }
+               appendPQExpBufferChar(query, '\'');
+               appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
+               tgargs = p + 4;
+           }
+           appendPQExpBuffer(query, ");\n");
+
+           ArchiveEntry(fout, tgoid,
+                        tgname,
+                        tbinfo->relnamespace->nspname,
+                        tbinfo->usename,
+                        "TRIGGER", NULL,
+                        query->data, delqry->data,
+                        NULL, NULL, NULL);
+
+           resetPQExpBuffer(query);
+           appendPQExpBuffer(query, "TRIGGER %s ",
+                             fmtId(tgname, force_quotes));
+           appendPQExpBuffer(query, "ON %s",
+                             fmtId(tbinfo->relname, force_quotes));
+
+           dumpComment(fout, query->data,
+                       tbinfo->relnamespace->nspname, tbinfo->usename,
+                       tgoid, "pg_trigger", 0, NULL);
        }
+
+       PQclear(res);
    }
+
+   destroyPQExpBuffer(query);
+   destroyPQExpBuffer(delqry);
 }
 
 
 static void
-dumpRules(Archive *fout, const char *tablename,
-         TableInfo *tblinfo, int numTables)
+dumpRules(Archive *fout, TableInfo *tblinfo, int numTables)
 {
    PGresult   *res;
    int         nrules;
    int         i,
                t;
    PQExpBuffer query = createPQExpBuffer();
-
    int         i_definition;
    int         i_oid;
-   int         i_owner;
    int         i_rulename;
 
    if (g_verbose)
@@ -5019,9 +5236,14 @@ dumpRules(Archive *fout, const char *tablename,
     */
    for (t = 0; t < numTables; t++)
    {
-       if (tablename && (strcmp(tblinfo[t].relname, tablename) != 0) && (strlen(tablename) > 0))
+       TableInfo      *tbinfo = &tblinfo[t];
+
+       if (!tbinfo->hasrules || !tbinfo->dump)
            continue;
 
+       /* Make sure we are in proper schema */
+       selectSourceSchema(tbinfo->relnamespace->nspname);
+
        /*
         * Get all rules defined for this table, except view select rules
         */
@@ -5034,11 +5256,10 @@ dumpRules(Archive *fout, const char *tablename,
             * rules (pjw 15-Sep-2000).
             */
            appendPQExpBuffer(query, "SELECT definition,"
-                             "   (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
                              "   pg_rewrite.oid, pg_rewrite.rulename "
                              "FROM pg_rewrite, pg_class, pg_rules "
                              "WHERE pg_class.relname = ");
-           formatStringLiteral(query, tblinfo[t].relname, CONV_ALL);
+           formatStringLiteral(query, tbinfo->relname, CONV_ALL);
            appendPQExpBuffer(query,
                              "    AND pg_rewrite.ev_class = pg_class.oid "
                              "    AND pg_rules.tablename = pg_class.relname "
@@ -5047,15 +5268,14 @@ dumpRules(Archive *fout, const char *tablename,
        }
        else
        {
-           appendPQExpBuffer(query, "SELECT pg_get_ruledef(pg_rewrite.oid) AS definition,"
-                             " (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
-                             " pg_rewrite.oid, pg_rewrite.rulename "
-                             "FROM pg_rewrite, pg_class "
-                             "WHERE pg_class.oid = '%s'::oid "
-                             " AND pg_rewrite.ev_class = pg_class.oid "
-                             " AND pg_rewrite.rulename != '_RETURN' "
-                             "ORDER BY pg_rewrite.oid",
-                             tblinfo[t].oid);
+           appendPQExpBuffer(query,
+                             "SELECT pg_get_ruledef(oid) AS definition,"
+                             " oid, rulename "
+                             "FROM pg_rewrite "
+                             "WHERE ev_class = '%s'::oid "
+                             "AND rulename != '_RETURN' "
+                             "ORDER BY oid",
+                             tbinfo->oid);
        }
 
        res = PQexec(g_conn, query->data);
@@ -5063,13 +5283,12 @@ dumpRules(Archive *fout, const char *tablename,
            PQresultStatus(res) != PGRES_TUPLES_OK)
        {
            write_msg(NULL, "query to get rules associated with table \"%s\" failed: %s",
-                     tblinfo[t].relname, PQerrorMessage(g_conn));
+                     tbinfo->relname, PQerrorMessage(g_conn));
            exit_nicely();
        }
 
        nrules = PQntuples(res);
        i_definition = PQfnumber(res, "definition");
-       i_owner = PQfnumber(res, "viewowner");
        i_oid = PQfnumber(res, "oid");
        i_rulename = PQfnumber(res, "rulename");
 
@@ -5079,17 +5298,24 @@ dumpRules(Archive *fout, const char *tablename,
 
        for (i = 0; i < nrules; i++)
        {
-           ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
-                        "RULE", NULL, PQgetvalue(res, i, i_definition),
-                        "", "", PQgetvalue(res, i, i_owner), NULL, NULL);
+           ArchiveEntry(fout, PQgetvalue(res, i, i_oid),
+                        PQgetvalue(res, i, i_rulename),
+                        tbinfo->relnamespace->nspname,
+                        tbinfo->usename,
+                        "RULE", NULL,
+                        PQgetvalue(res, i, i_definition),
+                        "",    /* Del */
+                        NULL, NULL, NULL);
 
            /* Dump rule comments */
 
            resetPQExpBuffer(query);
            appendPQExpBuffer(query, "RULE %s", fmtId(PQgetvalue(res, i, i_rulename), force_quotes));
-           appendPQExpBuffer(query, " ON %s", fmtId(tblinfo[t].relname, force_quotes));
-           dumpComment(fout, query->data, PQgetvalue(res, i, i_oid),
-                       "pg_rewrite", 0, NULL);
+           appendPQExpBuffer(query, " ON %s", fmtId(tbinfo->relname, force_quotes));
+           dumpComment(fout, query->data,
+                       tbinfo->relnamespace->nspname,
+                       tbinfo->usename,
+                       PQgetvalue(res, i, i_oid), "pg_rewrite", 0, NULL);
 
        }
 
@@ -5098,3 +5324,206 @@ dumpRules(Archive *fout, const char *tablename,
 
    destroyPQExpBuffer(query);
 }
+
+/*
+ * selectSourceSchema - make the specified schema the active search path
+ * in the source database.
+ *
+ * NB: pg_catalog is implicitly searched before the specified schema;
+ * so system names are never qualified, and user names are only qualified
+ * if they are cross-schema references or duplicate system names.
+ */
+static void
+selectSourceSchema(const char *schemaName)
+{
+   static char    *curSchemaName = NULL;
+   PQExpBuffer query;
+   PGresult   *res;
+
+   /* Not relevant if fetching from pre-7.3 DB */
+   if (g_fout->remoteVersion < 70300)
+       return;
+   /* Ignore null schema names */
+   if (schemaName == NULL || *schemaName == '\0')
+       return;
+   /* Optimize away repeated selection of same schema */
+   if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
+       return;
+
+   query = createPQExpBuffer();
+   appendPQExpBuffer(query, "SET search_path = %s",
+                     fmtId(schemaName, force_quotes));
+   res = PQexec(g_conn, query->data);
+   if (!res ||
+       PQresultStatus(res) != PGRES_COMMAND_OK)
+   {
+       write_msg(NULL, "query to set search_path failed: %s",
+                 PQerrorMessage(g_conn));
+       exit_nicely();
+   }
+   PQclear(res);
+   destroyPQExpBuffer(query);
+
+   if (curSchemaName)
+       free(curSchemaName);
+   curSchemaName = strdup(schemaName);
+}
+
+/*
+ * getFormattedTypeName - retrieve a nicely-formatted type name for the
+ * given type name.
+ *
+ * NB: in 7.3 and up the result may depend on the currently-selected
+ * schema; this is why we don't try to cache the names.
+ */
+static char *
+getFormattedTypeName(const char *oid, OidOptions opts)
+{
+   char       *result;
+   PQExpBuffer query;
+   PGresult   *res;
+   int         ntups;
+
+   if (atooid(oid) == 0)
+   {
+       if ((opts & zeroAsOpaque) != 0)
+           return strdup(g_opaque_type);
+       else if ((opts & zeroAsAny) != 0)
+           return strdup("'any'");
+       else if ((opts & zeroAsStar) != 0)
+           return strdup("*");
+       else if ((opts & zeroAsNone) != 0)
+           return strdup("NONE");
+   }
+
+   query = createPQExpBuffer();
+   if (g_fout->remoteVersion >= 70100)
+   {
+       appendPQExpBuffer(query, "SELECT format_type('%s'::oid, NULL)",
+                         oid);
+   }
+   else
+   {
+       appendPQExpBuffer(query, "SELECT typname "
+                         "FROM pg_type "
+                         "WHERE oid = '%s'::oid",
+                         oid);
+   }
+
+   res = PQexec(g_conn, query->data);
+   if (!res ||
+       PQresultStatus(res) != PGRES_TUPLES_OK)
+   {
+       write_msg(NULL, "query to obtain type name for %s failed: %s",
+                 oid, PQerrorMessage(g_conn));
+       exit_nicely();
+   }
+
+   /* Expecting a single result only */
+   ntups = PQntuples(res);
+   if (ntups != 1)
+   {
+       write_msg(NULL, "Got %d rows instead of one from: %s",
+                 ntups, query->data);
+       exit_nicely();
+   }
+
+   result = strdup(PQgetvalue(res, 0, 0));
+
+   PQclear(res);
+   destroyPQExpBuffer(query);
+
+   return result;
+}
+
+/*
+ * myFormatType --- local implementation of format_type for use with 7.0.
+ */
+static char *
+myFormatType(const char *typname, int32 typmod)
+{
+   char       *result;
+   PQExpBuffer buf = createPQExpBuffer();
+
+   /* Show lengths on bpchar and varchar */
+   if (!strcmp(typname, "bpchar"))
+   {
+       int         len = (typmod - VARHDRSZ);
+
+       appendPQExpBuffer(buf, "character");
+       if (len > 1)
+           appendPQExpBuffer(buf, "(%d)",
+                             typmod - VARHDRSZ);
+   }
+   else if (!strcmp(typname, "varchar"))
+   {
+       appendPQExpBuffer(buf, "character varying");
+       if (typmod != -1)
+           appendPQExpBuffer(buf, "(%d)",
+                             typmod - VARHDRSZ);
+   }
+   else if (!strcmp(typname, "numeric"))
+   {
+       appendPQExpBuffer(buf, "numeric");
+       if (typmod != -1)
+       {
+           int32       tmp_typmod;
+           int         precision;
+           int         scale;
+
+           tmp_typmod = typmod - VARHDRSZ;
+           precision = (tmp_typmod >> 16) & 0xffff;
+           scale = tmp_typmod & 0xffff;
+           appendPQExpBuffer(buf, "(%d,%d)",
+                             precision, scale);
+       }
+   }
+
+   /*
+    * char is an internal single-byte data type; Let's make sure we force
+    * it through with quotes. - thomas 1998-12-13
+    */
+   else if (!strcmp(typname, "char"))
+   {
+       appendPQExpBuffer(buf, "%s",
+                         fmtId(typname, true));
+   }
+   else
+   {
+       appendPQExpBuffer(buf, "%s",
+                         fmtId(typname, false));
+   }
+
+   result = strdup(buf->data);
+   destroyPQExpBuffer(buf);
+
+   return result;
+}
+
+/*
+ * fmtQualifiedId - convert a qualified name to the proper format for
+ * the source database.
+ *
+ * Like fmtId, use the result before calling again.
+ */
+static const char *
+fmtQualifiedId(const char *schema, const char *id)
+{
+   static PQExpBuffer id_return = NULL;
+
+   if (id_return)              /* first time through? */
+       resetPQExpBuffer(id_return);
+   else
+       id_return = createPQExpBuffer();
+
+   /* Suppress schema name if fetching from pre-7.3 DB */
+   if (g_fout->remoteVersion >= 70300 && schema && *schema)
+   {
+       appendPQExpBuffer(id_return, "%s.",
+                         fmtId(schema, force_quotes));
+   }
+   appendPQExpBuffer(id_return, "%s",
+                     fmtId(id, force_quotes));
+
+   return id_return->data;
+}
index 580dacf66df042179f1b733a2728bf6a31077519..1cf7a02e304cffbd6bcf277c8181a71e81cf15c0 100644 (file)
@@ -1,27 +1,12 @@
 /*-------------------------------------------------------------------------
  *
  * pg_dump.h
- *   header file for the pg_dump utility
+ *   Common header file for the pg_dump utility
  *
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_dump.h,v 1.84 2002/04/24 22:39:49 petere Exp $
- *
- * Modifications - 6/12/96 - [email protected] - version 1.13.dhb.2
- *
- *  - Fixed dumpTable output to output lengths for char and varchar types!
- *  - Added single. quote to twin single quote expansion for 'insert' string
- *    mode.
- *
- * Modifications - 6/1/97 - [email protected]
- * - Added extern's for the functions that clear allocated memory
- *  in pg_dump.c
- *
- * Modifications - 14-Sep-2000 - [email protected]
- * -   Added typedefn fields to typeinfo and relinfo
- * -   Added enum for findTypeByOid to allow special handling of
- *     '0' OID.
+ * $Id: pg_dump.h,v 1.85 2002/05/10 22:36:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "pg_backup.h"
 #include "pqexpbuffer.h"
 
-/* The data structures used to store system catalog information */
+/*
+ * The data structures used to store system catalog information
+ *
+ * NOTE: the structures described here live for the entire pg_dump run;
+ * and in most cases we make a struct for every object we can find in the
+ * catalogs, not only those we are actually going to dump.  Hence, it's
+ * best to store a minimal amount of per-object info in these structs,
+ * and retrieve additional per-object info when and if we dump a specific
+ * object.  In particular, try to avoid retrieving expensive-to-compute
+ * information until it's known to be needed.
+ */
+
+typedef struct _namespaceInfo
+{
+   char       *oid;
+   char       *nspname;
+   char       *usename;        /* name of owner, or empty string */
+   char       *nspacl;
+   bool        dump;           /* true if need to dump definition */
+} NamespaceInfo;
 
 typedef struct _typeInfo
 {
    char       *oid;
-   char       *typowner;
-   char       *typname;
-   char       *typlen;
-   char       *typprtlen;
-   char       *typinput;
-   char       *typoutput;
-   char       *typreceive;
-   char       *typsend;
-   char       *typelem;
-   char       *typdelim;
-   char       *typdefault;
-   char       *typrelid;
-   char       *typalign;
-   char       *typstorage;
-   char       *usename;
-   char       *typedefn;
-   char       *typtype;
-   int         passedbyvalue;
-   int         isArray;
-   int         isDefined;
+   char       *typname;        /* name as seen in catalog */
+   /* Note: format_type might produce something different than typname */
+   NamespaceInfo *typnamespace;    /* link to containing namespace */
+   char       *usename;        /* name of owner, or empty string */
+   char       *typelem;        /* OID */
+   char       *typrelid;       /* OID */
+   char        typtype;        /* 'b', 'c', etc */
+   bool        isArray;        /* true if user-defined array type */
+   bool        isDefined;      /* true if typisdefined */
 } TypeInfo;
 
 typedef struct _funcInfo
 {
    char       *oid;
    char       *proname;
-   char       *proowner;
+   NamespaceInfo *pronamespace;    /* link to containing namespace */
+   char       *usename;        /* name of owner, or empty string */
    Oid         lang;
    int         nargs;
-   char       **argtypes;
-   char       *prorettype;
-   int         retset;         /* 1 if the function returns a set, else 0 */
-   char       *prosrc;
-   char       *probin;
-   char       *usename;
-   char        provolatile;    /* Attr */
-   bool        isimplicit;     /* Attr */
-   bool        isstrict;       /* Attr */
-   int         dumped;         /* 1 if already dumped */
+   char       **argtypes;      /* OIDs */
+   char       *prorettype;     /* OID */
+   bool        dumped;         /* true if already dumped */
 } FuncInfo;
 
-typedef struct _trigInfo
+typedef struct _aggInfo
 {
    char       *oid;
-   char       *tgname;
-   char       *tgsrc;
-   char       *tgdel;
-   char       *tgcomment;
-} TrigInfo;
+   char       *aggname;
+   NamespaceInfo *aggnamespace;    /* link to containing namespace */
+   char       *usename;
+} AggInfo;
+
+typedef struct _oprInfo
+{
+   char       *oid;
+   char       *oprname;
+   NamespaceInfo *oprnamespace;    /* link to containing namespace */
+   char       *usename;
+   char       *oprcode;        /* as OID, not regproc name */
+} OprInfo;
 
 typedef struct _tableInfo
 {
+   /*
+    * These fields are collected for every table in the database.
+    */
    char       *oid;
    char       *relname;
+   NamespaceInfo *relnamespace;    /* link to containing namespace */
+   char       *usename;        /* name of owner, or empty string */
    char       *relacl;
-   char       *viewdef;
-   char       *viewoid;        /* OID of view - should be >= oid of table
-                                * important because views may be
-                                * constructed manually from rules, and
-                                * rule may ref things created after the
-                                * base table was created. */
    char        relkind;
    bool        hasindex;       /* does it have any indexes? */
+   bool        hasrules;       /* does it have any rules? */
    bool        hasoids;        /* does it have OIDs? */
+   int         ncheck;         /* # of CHECK expressions */
+   int         ntrig;          /* # of triggers */
+
+   bool        interesting;    /* true if need to collect more data */
+   bool        dump;           /* true if we want to dump it */
+
+   /*
+    * These fields are computed only if we decide the table is interesting
+    * (it's either a table to dump, or a direct parent of a dumpable table).
+    */
    int         numatts;        /* number of attributes */
-   int        *inhAttrs;       /* an array of flags, one for each
-                                * attribute if the value is 1, then this
-                                * attribute is an inherited attribute */
-   int        *inhAttrDef;     /* Flags indicating if attrdef is
-                                * inherited */
-   int        *inhNotNull;     /* Flags indicating if NOT NULL in
-                                * inherited */
    char      **attnames;       /* the attribute names */
-   char      **atttypedefns;   /* formatted column type definitions */
-   char      **typnames;       /* fill out attributes */
-   bool       *notnull;        /* Not null constraints of an attribute */
+   char      **atttypnames;    /* attribute type names */
+   int        *atttypmod;      /* type-specific type modifiers */
+   /*
+    * Note: we need to store per-attribute notnull and default stuff for
+    * all interesting tables so that we can tell which constraints were
+    * inherited.
+    */
+   bool       *notnull;        /* Not null constraints on attributes */
    char      **adef_expr;      /* DEFAULT expressions */
-   int         numParents;     /* number of (immediate) parent
-                                * supertables */
-   char      **parentRels;     /* names of parent relations, NULL if
-                                * numParents == 0 */
-   char      **out_attnames;   /* the attribute names, in the order they
-                                * would be in, when the table is created
-                                * in the target query language. this is
-                                * needed because the SQL tables will not
-                                * have the same order of attributes as
-                                * the POSTQUEL tables */
-   int        *atttypmod;      /* type-specific type modifier */
-   char       *usename;
-   int         ncheck;         /* # of CHECK expressions */
-   char      **check_expr;     /* [CONSTRAINT name] CHECK expressions */
-   int         ntrig;          /* # of triggers */
-   TrigInfo   *triggers;       /* Triggers on the table */
-   char       *pkIndexOid;     /* Primary Key index OID */
-   char       *primary_key_name;       /* PRIMARY KEY name, if any */
+   bool       *inhAttrs;       /* true if each attribute is inherited */
+   bool       *inhAttrDef;     /* true if attr's default is inherited */
+   bool       *inhNotNull;     /* true if NOT NULL is inherited */
+
+   /*
+    * Stuff computed only for dumpable tables.
+    */
+   int         numParents;     /* number of (immediate) parent tables */
+   int        *parentIndexes;  /* TableInfo indexes of immediate parents */
+
+   char       *viewoid;        /* OID of view - should be >= oid of table
+                                * important because views may be
+                                * constructed manually from rules, and
+                                * rule may ref things created after the
+                                * base table was created. */
 } TableInfo;
 
 typedef struct _inhInfo
 {
-   char       *inhrelid;
-   char       *inhparent;
+   char       *inhrelid;       /* OID of a child table */
+   char       *inhparent;      /* OID of its parent */
 } InhInfo;
 
-typedef struct _indInfo
-{
-   char       *indexreloid;    /* oid of the index itself */
-   char       *indreloid;      /* oid of the table the index is on */
-   char       *indexrelname;   /* name of the index itself */
-   char       *indrelname;     /* name of the indexed table */
-   char       *indexdef;       /* index definitional command */
-   char       *indisprimary;   /* is this a PK index? */
-   int         indnkeys;       /* number of keys in index */
-   char      **indkey;         /* attribute numbers of the key
-                                * attributes */
-} IndInfo;
-
-typedef struct _aggInfo
-{
-   char       *oid;
-   char       *aggname;
-   char       *aggtransfn;
-   char       *aggfinalfn;
-   char       *aggtranstype;
-   char       *aggbasetype;
-   char       *agginitval;
-   char       *usename;
-   int         convertok;      /* Flag to indicate of version convertsion
-                                * is OK */
-} AggInfo;
-
-typedef struct _oprInfo
-{
-   char       *oid;
-   char       *oprname;
-   char       *oprkind;        /*----------
-                                *  b = binary,
-                                *  l = left unary
-                                *  r = right unary
-                                *----------
-                                */
-   char       *oprcode;        /* operator function name */
-   char       *oprleft;        /* left operand type */
-   char       *oprright;       /* right operand type */
-   char       *oprcom;         /* oid of the commutator operator */
-   char       *oprnegate;      /* oid of the negator operator */
-   char       *oprrest;        /* name of the function to calculate
-                                * operator restriction selectivity */
-   char       *oprjoin;        /* name of the function to calculate
-                                * operator join selectivity */
-   char       *oprcanhash;     /* can we use hash join strategy ? */
-   char       *oprlsortop;     /* oid's of the left and right sort
-                                * operators */
-   char       *oprrsortop;
-   char       *usename;
-} OprInfo;
 
 /* global decls */
 extern bool force_quotes;      /* double-quotes for identifiers flag */
 extern bool g_verbose;         /* verbose flag */
-extern Oid g_last_builtin_oid; /* value of the last builtin oid */
 extern Archive *g_fout;            /* the script file */
 
 /* placeholders for comment starting and ending delimiters */
@@ -212,73 +159,55 @@ extern char g_opaque_type[10];    /* name for the opaque type */
 */
 /*
  * common utility functions
-*/
+ */
 
 extern TableInfo *dumpSchema(Archive *fout,
           int *numTablesPtr,
-          const char *tablename,
-          const bool acls,
-          const bool oids,
+          const bool aclsSkip,
           const bool schemaOnly,
           const bool dataOnly);
-extern void dumpSchemaIdx(Archive *fout,
-             const char *tablename,
-             TableInfo *tblinfo,
-             int numTables);
 
 typedef enum _OidOptions
 {
    zeroAsOpaque = 1,
    zeroAsAny = 2,
    zeroAsStar = 4,
-   zeroAsNone = 8,
-   useBaseTypeName = 1024
+   zeroAsNone = 8
 } OidOptions;
 
-extern char *findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid, OidOptions opts);
+extern int findTableByOid(TableInfo *tbinfo, int numTables, const char *oid);
 extern char *findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid);
-extern int findFuncByName(FuncInfo *finfo, int numFuncs, const char *name);
-extern int findTableByName(TableInfo *tbinfo, int numTables, const char *relname);
+extern int findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid);
 
 extern void check_conn_and_db(void);
+extern void exit_nicely(void);
+
 extern void parseNumericArray(const char *str, char **array, int arraysize);
 
 /*
  * version specific routines
  */
+extern NamespaceInfo *getNamespaces(int *numNamespaces);
 extern TypeInfo *getTypes(int *numTypes);
 extern FuncInfo *getFuncs(int *numFuncs);
 extern AggInfo *getAggregates(int *numAggregates);
-
-extern void clearAggInfo(AggInfo *, int);
-extern void clearFuncInfo(FuncInfo *, int);
-extern void clearInhInfo(InhInfo *, int);
-extern void clearIndInfo(IndInfo *, int);
-extern void clearOprInfo(OprInfo *, int);
-extern void clearTypeInfo(TypeInfo *, int);
-
 extern OprInfo *getOperators(int *numOperators);
-extern TableInfo *getTables(int *numTables, FuncInfo *finfo, int numFuncs,
-                           const char* tablename);
+extern TableInfo *getTables(int *numTables);
 extern InhInfo *getInherits(int *numInherits);
+
 extern void getTableAttrs(TableInfo *tbinfo, int numTables);
-extern IndInfo *getIndexes(int *numIndexes);
 extern void dumpDBComment(Archive *outfile);
+extern void dumpNamespaces(Archive *fout,
+                          NamespaceInfo *nsinfo, int numNamespaces);
 extern void dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
          TypeInfo *tinfo, int numTypes);
-extern void dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
-             TypeInfo *tinfo, int numTypes);
-extern void dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
-         TypeInfo *tinfo, int numTypes);
-extern void dumpAggs(Archive *fout, AggInfo *agginfo, int numAggregates,
-        TypeInfo *tinfo, int numTypes);
-extern void dumpOprs(Archive *fout, OprInfo *agginfo, int numOperators,
-        TypeInfo *tinfo, int numTypes);
-extern void dumpTables(Archive *fout, TableInfo *tbinfo, int numTables,
-          const char *tablename, const bool acls,
-          const bool schemaOnly, const bool dataOnly);
-extern void dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes,
-           TableInfo *tbinfo, int numTables, const char *tablename);
-extern void exit_nicely(void);
+extern void dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs);
+extern void dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs);
+extern void dumpAggs(Archive *fout, AggInfo *agginfo, int numAggregates);
+extern void dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators);
+extern void dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
+                      const bool aclsSkip,
+                      const bool schemaOnly, const bool dataOnly);
+extern void dumpIndexes(Archive *fout, TableInfo *tbinfo, int numTables);
 
 #endif   /* PG_DUMP_H */
index e6747fd53f7455a573256e37b11f38a21a6572ac..9d2af919acac884413b1a69a9a9a9c60a2a6cf77 100644 (file)
  *
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.33 2002/01/18 19:17:05 momjian Exp $
- *
- * Modifications - 28-Jun-2000 - [email protected]
- *
- *     Initial version. Command processing taken from original pg_dump.
- *
- * Modifications - 28-Jul-2000 - [email protected] (1.45)
- *
- *     Added --create, --no-owner, --superuser, --no-reconnect (pg_dump & pg_restore)
- *     Added code to dump 'Create Schema' statement (pg_dump)
- *     Don't bother to disable/enable triggers if we don't have a superuser (pg_restore)
- *     Cleaned up code for reconnecting to database.
- *     Force a reconnect as superuser before enabling/disabling triggers.
- *
- * Modifications - 6-Mar-2001 - [email protected]
- *     Change -U option to -L to allow -U to specify username in future.
+ *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.34 2002/05/10 22:36:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -94,6 +79,7 @@ main(int argc, char **argv)
    extern int  optind;
    extern char *optarg;
    static int  use_setsessauth = 0;
+   static int  disable_triggers = 0;
 
 #ifdef HAVE_GETOPT_LONG
    struct option cmdopts[] = {
@@ -130,6 +116,8 @@ main(int argc, char **argv)
         * letter, but are available as '-X long-name'
         */
        {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+       {"disable-triggers", no_argument, &disable_triggers, 1},
+
        {NULL, 0, NULL, 0}
    };
 #endif   /* HAVE_GETOPT_LONG */
@@ -281,6 +269,8 @@ main(int argc, char **argv)
            case 'X':
                if (strcmp(optarg, "use-set-session-authorization") == 0)
                    use_setsessauth = 1;
+               else if (strcmp(optarg, "disable-triggers") == 0)
+                   disable_triggers = 1;
                else
                {
                    fprintf(stderr,
@@ -309,6 +299,7 @@ main(int argc, char **argv)
        fileSpec = NULL;
 
    opts->use_setsessauth = use_setsessauth;
+   opts->disable_triggers = disable_triggers;
 
    if (opts->formatName)
    {
@@ -385,74 +376,77 @@ usage(const char *progname)
           progname, progname);
 #ifdef HAVE_GETOPT_LONG
    puts(gettext(
-         "  -a, --data-only          restore only the data, no schema\n"
-      "  -c, --clean              clean (drop) schema prior to create\n"
-    "  -C, --create             issue commands to create the database\n"
-                "  -d, --dbname=NAME        output database name\n"
-                "  -f, --file=FILENAME      output file name\n"
-                "  -F, --format={c|t}       specify backup file format\n"
-                "  -h, --host=HOSTNAME      server host name\n"
-                "  -i, --index=NAME         restore named index\n"
-      "  -l, --list               print summarized TOC of the archive\n"
-                "  -L, --use-list=FILENAME  use specified table of contents for ordering\n"
-                "                           output from this file\n"
-           "  -N, --orig-order         restore in original dump order\n"
-                "  -o, --oid-order          restore in OID order\n"
-    "  -O, --no-owner           do not reconnect to database to match\n"
-                "                           object owner\n"
-                "  -p, --port=PORT          server port number\n"
-                "  -P, --function=NAME      restore named function\n"
-                "  -r, --rearrange          rearrange output to put indexes etc. at end\n"
-                "  -R, --no-reconnect       disallow ALL reconnections to the database\n"
-         "  -s, --schema-only        restore only the schema, no data\n"
-                "  -S, --superuser=NAME     specify the superuser user name to use for\n"
-                "                           disabling triggers\n"
-                "  -t, --table=NAME         restore named table\n"
-                "  -T, --trigger=NAME       restore named trigger\n"
+       "  -a, --data-only          restore only the data, no schema\n"
+       "  -c, --clean              clean (drop) schema prior to create\n"
+       "  -C, --create             issue commands to create the database\n"
+       "  -d, --dbname=NAME        output database name\n"
+       "  -f, --file=FILENAME      output file name\n"
+       "  -F, --format={c|t}       specify backup file format\n"
+       "  -h, --host=HOSTNAME      server host name\n"
+       "  -i, --index=NAME         restore named index\n"
+       "  -l, --list               print summarized TOC of the archive\n"
+       "  -L, --use-list=FILENAME  use specified table of contents for ordering\n"
+       "                           output from this file\n"
+       "  -N, --orig-order         restore in original dump order\n"
+       "  -o, --oid-order          restore in OID order\n"
+       "  -O, --no-owner           do not reconnect to database to match\n"
+       "                           object owner\n"
+       "  -p, --port=PORT          server port number\n"
+       "  -P, --function=NAME      restore named function\n"
+       "  -r, --rearrange          rearrange output to put indexes etc. at end\n"
+       "  -R, --no-reconnect       disallow ALL reconnections to the database\n"
+       "  -s, --schema-only        restore only the schema, no data\n"
+       "  -S, --superuser=NAME     specify the superuser user name to use for\n"
+       "                           disabling triggers\n"
+       "  -t, --table=NAME         restore named table\n"
+       "  -T, --trigger=NAME       restore named trigger\n"
        "  -U, --username=NAME      connect as specified database user\n"
-                "  -v, --verbose            verbose mode\n"
-                "  -W, --password           force password prompt (should happen automatically)\n"
-                "  -x, --no-privileges      skip restoration of access privileges (grant/revoke)\n"
-                "  -X use-set-session-authorization, --use-set-session-authorization\n"
-                "                           use SET SESSION AUTHORIZATION commands instead\n"
-             "                           of reconnecting, if possible\n"
-                ));
+       "  -v, --verbose            verbose mode\n"
+       "  -W, --password           force password prompt (should happen automatically)\n"
+       "  -x, --no-privileges      skip restoration of access privileges (grant/revoke)\n"
+       "  -X use-set-session-authorization, --use-set-session-authorization\n"
+       "                           use SET SESSION AUTHORIZATION commands instead\n"
+       "                           of reconnecting, if possible\n"
+       "  -X disable-triggers, --disable-triggers\n"
+       "                           disable triggers during data-only restore\n"
+       ));
 
 #else                          /* not HAVE_GETOPT_LONG */
 
    puts(gettext(
-         "  -a                       restore only the data, no schema\n"
-      "  -c                       clean (drop) schema prior to create\n"
-    "  -C                       issue commands to create the database\n"
-                "  -d NAME                  output database name\n"
-                "  -f FILENAME              output file name\n"
-                "  -F {c|t}                 specify backup file format\n"
-                "  -h HOSTNAME              server host name\n"
-                "  -i NAME                  restore named index\n"
-      "  -l                       print summarized TOC of the archive\n"
-                "  -L FILENAME              use specified table of contents for ordering\n"
-                "                           output from this file\n"
-           "  -N                       restore in original dump order\n"
-                "  -o                       restore in OID order\n"
-    "  -O                       do not reconnect to database to match\n"
-                "                           object owner\n"
-                "  -p PORT                  server port number\n"
-                "  -P NAME                  restore named function\n"
-                "  -r                       rearrange output to put indexes etc. at end\n"
-                "  -R                       disallow ALL reconnections to the database\n"
-         "  -s                       restore only the schema, no data\n"
-                "  -S NAME                  specify the superuser user name to use for\n"
-                "                           disabling triggers\n"
-                "  -t NAME                  restore named table\n"
-                "  -T NAME                  restore named trigger\n"
+       "  -a                       restore only the data, no schema\n"
+       "  -c                       clean (drop) schema prior to create\n"
+       "  -C                       issue commands to create the database\n"
+       "  -d NAME                  output database name\n"
+       "  -f FILENAME              output file name\n"
+       "  -F {c|t}                 specify backup file format\n"
+       "  -h HOSTNAME              server host name\n"
+       "  -i NAME                  restore named index\n"
+       "  -l                       print summarized TOC of the archive\n"
+       "  -L FILENAME              use specified table of contents for ordering\n"
+       "                           output from this file\n"
+       "  -N                       restore in original dump order\n"
+       "  -o                       restore in OID order\n"
+       "  -O                       do not reconnect to database to match\n"
+       "                           object owner\n"
+       "  -p PORT                  server port number\n"
+       "  -P NAME                  restore named function\n"
+       "  -r                       rearrange output to put indexes etc. at end\n"
+       "  -R                       disallow ALL reconnections to the database\n"
+       "  -s                       restore only the schema, no data\n"
+       "  -S NAME                  specify the superuser user name to use for\n"
+       "                           disabling triggers\n"
+       "  -t NAME                  restore named table\n"
+       "  -T NAME                  restore named trigger\n"
        "  -U NAME                  connect as specified database user\n"
-                "  -v                       verbose mode\n"
-                "  -W                       force password prompt (should happen automatically)\n"
-                "  -x                       skip restoration of access privileges (grant/revoke)\n"
-                "  -X use-set-session-authorization\n"
-                "                           use SET SESSION AUTHORIZATION commands instead\n"
-             "                           of reconnecting, if possible\n"
-                ));
+       "  -v                       verbose mode\n"
+       "  -W                       force password prompt (should happen automatically)\n"
+       "  -x                       skip restoration of access privileges (grant/revoke)\n"
+       "  -X use-set-session-authorization\n"
+       "                           use SET SESSION AUTHORIZATION commands instead\n"
+       "                           of reconnecting, if possible\n"
+       "  -X disable-triggers      disable triggers during data-only restore\n"
+       ));
 #endif
    puts(gettext("If no input file name is supplied, then standard input is used.\n"));
    puts(gettext("Report bugs to ."));