]> granicus.if.org Git - postgresql/blobdiff - src/bin/pg_dump/pg_dump.c
Fix all known problems with pg_dump's handling of serial sequences
[postgresql] / src / bin / pg_dump / pg_dump.c
index ea697739191a70ff71b45896136794fdb8c2d2cd..78a653fb48c0e40cff40aa819d48e0f82deed8bd 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.442 2006/07/27 19:52:06 tgl Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.447 2006/08/21 00:57:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -91,8 +91,19 @@ static const char *username_subquery;
 /* 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 */
-static char *selectSchemaName = NULL;  /* name of a single schema to dump */
+/* select and exclude tables and schemas */
+typedef struct objnameArg
+{
+       struct objnameArg *next;
+       char *name;                     /* name of the relation */
+       bool is_include;        /* include/exclude? */
+} objnameArg;
+
+objnameArg *schemaList = NULL; /* List of schemas to include/exclude */
+objnameArg *tableList = NULL; /* List of tables to include/exclude */
+
+char *matchingSchemas = NULL; /* Final list of schemas to dump by oid */
+char *matchingTables = NULL; /* Final list of tables to dump by oid */
 
 char           g_opaque_type[10];      /* name for the opaque type */
 
@@ -180,6 +191,9 @@ static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
 int
 main(int argc, char **argv)
 {
+       PQExpBuffer query = createPQExpBuffer();
+       PGresult   *res;
+       objnameArg *this_obj_name, *schemaList_tail = NULL, *tableList_tail = NULL;
        int                     c;
        const char *filename = NULL;
        const char *format = "p";
@@ -195,6 +209,7 @@ main(int argc, char **argv)
        DumpableObject **dobjs;
        int                     numObjs;
        int                     i;
+       bool            switch_include_exclude;
        bool            force_password = false;
        int                     compressLevel = -1;
        bool            ignore_version = false;
@@ -226,9 +241,11 @@ main(int argc, char **argv)
                {"no-owner", no_argument, NULL, 'O'},
                {"port", required_argument, NULL, 'p'},
                {"schema", required_argument, NULL, 'n'},
+               {"exclude-schema", required_argument, NULL, 'N'},
                {"schema-only", no_argument, NULL, 's'},
                {"superuser", required_argument, NULL, 'S'},
                {"table", required_argument, NULL, 't'},
+               {"exclude-table", required_argument, NULL, 'T'},
                {"password", no_argument, NULL, 'W'},
                {"username", required_argument, NULL, 'U'},
                {"verbose", no_argument, NULL, 'v'},
@@ -281,7 +298,7 @@ main(int argc, char **argv)
                }
        }
 
-       while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:oOp:RsS:t:uU:vWxX:Z:",
+       while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:uU:vWxX:Z:",
                                                        long_options, &optindex)) != -1)
        {
                switch (c)
@@ -332,8 +349,42 @@ main(int argc, char **argv)
                                ignore_version = true;
                                break;
 
-                       case 'n':                       /* Dump data for this schema only */
-                               selectSchemaName = strdup(optarg);
+                       case 'n':               /* Include schemas */
+                       case 'N':               /* Exclude schemas */
+                       case 't':               /* Include tables */
+                       case 'T':               /* Exclude tables */
+
+                               if (strlen(optarg) < 1)
+                               {
+                                       fprintf(stderr, _("%s: invalid -%c option\n"), progname, c);
+                                       exit(1);
+                               }
+
+                               {
+                                       /* Create a struct for this name */
+                                       objnameArg *new_obj_name = (objnameArg *)
+                                                                                               malloc(sizeof(objnameArg));
+
+                                       new_obj_name->next = NULL;
+                                       new_obj_name->name = strdup(optarg);
+                                       new_obj_name->is_include = islower(c) ? true : false;
+
+                                       /* add new entry to the proper list */
+                                       if (tolower(c) == 'n')
+                                       {
+                                               if (!schemaList_tail)
+                                                       schemaList_tail = schemaList = new_obj_name;
+                                               else
+                                                       schemaList_tail = schemaList_tail->next = new_obj_name;
+                                       }
+                                       else
+                                       {
+                                               if (!tableList_tail)
+                                                       tableList_tail = tableList = new_obj_name;
+                                               else
+                                                       tableList_tail = tableList_tail->next = new_obj_name;
+                                       }
+                               }
                                break;
 
                        case 'o':                       /* Dump oids */
@@ -361,10 +412,6 @@ main(int argc, char **argv)
                                outputSuperuser = strdup(optarg);
                                break;
 
-                       case 't':                       /* Dump data for this table only */
-                               selectTableName = strdup(optarg);
-                               break;
-
                        case 'u':
                                force_password = true;
                                username = simple_prompt("User name: ", 100, true);
@@ -449,7 +496,7 @@ main(int argc, char **argv)
                exit(1);
        }
 
-       if (selectTableName != NULL || selectSchemaName != NULL)
+       if (matchingTables != NULL || matchingSchemas != NULL)
                outputBlobs = false;
 
        if (dumpInserts == true && oids == true)
@@ -568,11 +615,167 @@ main(int argc, char **argv)
                        write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
        }
 
+
+       if (schemaList != NULL && g_fout->remoteVersion < 70300)
+       {
+               write_msg(NULL, "Postgres must be at least version 7.3 to use schema switches\n");
+               exit_nicely();
+       }
+
+       /* Check schema selection flags */
+       resetPQExpBuffer(query);
+       switch_include_exclude = true;
+
+       for (this_obj_name = schemaList; this_obj_name; this_obj_name = this_obj_name->next)
+       {
+               if (switch_include_exclude)
+               {
+                       /* Special case for when -N is the first argument */
+                       if (this_obj_name == schemaList && !this_obj_name->is_include)
+                               appendPQExpBuffer(query,
+                                       "SELECT oid FROM pg_catalog.pg_namespace "
+                                       "WHERE nspname NOT LIKE 'pg_%%' AND "
+                                       "      nspname != 'information_schema' EXCEPT\n");
+       
+                       appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_namespace WHERE");
+               }
+       
+               appendPQExpBuffer(query, "%s nspname %c ", switch_include_exclude ? "" : " OR",
+                                                       /* any meta-characters? */
+                                                       strpbrk(this_obj_name->name,"([{\\.?+") == NULL ? '=' : '~');
+               appendStringLiteralAH(query, this_obj_name->name, g_fout);
+       
+               if (this_obj_name->next && this_obj_name->next->is_include == this_obj_name->is_include)
+                       switch_include_exclude = false;
+               else
+               {
+                       switch_include_exclude = true;
+       
+                       /* Add the joiner if needed */
+                       if (this_obj_name->next)
+                               appendPQExpBuffer(query, "\n%s\n",
+                                                                 this_obj_name->next->is_include ? "UNION" : "EXCEPT");
+               }
+       }
+
+       /* Construct OID list of matching schemas */
+       if (schemaList)
+       {
+               int len;
+               
+               res = PQexec(g_conn, query->data);
+               check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+               if (PQntuples(res) == 0)
+               {
+                       write_msg(NULL, "No matching schemas were found\n");
+                       exit_nicely();
+               }
+
+               for (i = 0, len = strlen(" "); i < PQntuples(res); i++)
+                       len += strlen(PQgetvalue(res, i, 0)) + 1;
+
+               /*
+                *      Need to use comma separators so it can be used by IN.  zero
+                *      is a dummy placeholder.  Format is " oid oid oid ".
+                */
+               matchingSchemas = malloc(len + 1);
+               strcpy(matchingSchemas, " ");
+               for (i = 0; i < PQntuples(res); i++)
+               {
+                       strcat(matchingSchemas, PQgetvalue(res, i, 0));
+                       strcat(matchingSchemas, " ");
+               }
+       }
+
+       /* Check table selection flags */
+       resetPQExpBuffer(query);
+       switch_include_exclude = true;
+
+       for (this_obj_name = tableList; this_obj_name; this_obj_name = this_obj_name->next)
+       {
+               if (switch_include_exclude)
+               {
+                       /* Special case for when -T is the first argument */
+                       if (this_obj_name == tableList && !this_obj_name->is_include && !strlen(query->data))
+                               appendPQExpBuffer(query,
+                                       "SELECT pg_class.oid FROM pg_catalog.pg_class, pg_catalog.pg_namespace "
+                                       "WHERE relkind='r' AND "
+                                       "      relnamespace = pg_namespace.oid AND "
+                                       "      nspname NOT LIKE 'pg_%%' AND "
+                                       "      nspname != 'information_schema' EXCEPT\n");
+       
+                       appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_class WHERE relkind='r' AND (");
+               }
+       
+               appendPQExpBuffer(query, "%srelname %c ", switch_include_exclude ? "" : " OR ",
+                                                       /* any meta-characters? */
+                                                       strpbrk(this_obj_name->name,"([{\\.?+") == NULL ? '=' : '~');
+               appendStringLiteralAH(query, this_obj_name->name, g_fout);
+       
+               if (this_obj_name->next && this_obj_name->next->is_include == this_obj_name->is_include)
+                       switch_include_exclude = false;
+               else
+               {
+                       switch_include_exclude = true;
+                       appendPQExpBuffer(query, ")");
+               
+                       /* Add the joiner if needed */
+                       if (this_obj_name->next)
+                               appendPQExpBuffer(query, "\n%s\n", this_obj_name->next->is_include ?
+                                                                 "UNION" : "EXCEPT");
+               }
+       }
+
+       /* Construct OID list of matching tables */
+       if (tableList)
+       {
+               int len;
+               
+               /* Restrict by schema? */
+               if (matchingSchemas != NULL)
+               {
+                       char *matchingSchemas_commas = strdup(matchingSchemas), *p;
+
+                       /* Construct "IN" SQL string by adding commas, " oid, oid, oid " */
+                       for (p = matchingSchemas_commas; *p; p++)
+                       {
+                               /* No commas for first/last characters */
+                               if (*p == ' ' && p != matchingSchemas_commas && *(p+1))
+                                       *p = ',';
+                       }
+
+                       appendPQExpBuffer(query,
+                                                         "\nINTERSECT\nSELECT oid FROM pg_catalog.pg_class WHERE relkind='r' AND relnamespace IN (%s)\n",
+                                                         matchingSchemas_commas);
+               }
+
+               res = PQexec(g_conn, query->data);
+               check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+               if (PQntuples(res) == 0)
+               {
+                       write_msg(NULL, "No matching tables were found\n");
+                       exit_nicely();
+               }
+
+               for (i = 0, len = strlen(" "); i < PQntuples(res); i++)
+                       len += strlen(PQgetvalue(res, i, 0)) + 1;
+
+               matchingTables = malloc(len + 1);
+               strcpy(matchingTables, " ");
+               for (i = 0; i < PQntuples(res); i++)
+               {
+                       strcat(matchingTables, PQgetvalue(res, i, 0));
+                       strcat(matchingTables, " ");
+               }
+       }
+
+       destroyPQExpBuffer(query);
+
        /*
         * Now scan the database and create DumpableObject structs for all the
         * objects we intend to dump.
         */
-       tblinfo = getSchemaData(&numTables, schemaOnly, dataOnly);
+       tblinfo = getSchemaData(&numTables);
 
        if (!schemaOnly)
                getTableData(tblinfo, numTables, oids);
@@ -628,7 +831,7 @@ main(int argc, char **argv)
        dumpStdStrings(g_fout);
 
        /* The database item is always next, unless we don't want it at all */
-       if (!dataOnly && selectTableName == NULL && selectSchemaName == NULL)
+       if (!dataOnly && matchingTables == NULL && matchingSchemas == NULL)
                dumpDatabase(g_fout);
 
        /* Now the rearrangeable objects. */
@@ -687,28 +890,30 @@ help(const char *progname)
        printf(_("  --version                output version information, then exit\n"));
 
        printf(_("\nOptions controlling the output content:\n"));
-       printf(_("  -a, --data-only          dump only the data, not the schema\n"));
-       printf(_("  -c, --clean              clean (drop) schema prior to create\n"));
-       printf(_("  -C, --create             include commands to create database in dump\n"));
-       printf(_("  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"));
-       printf(_("  -D, --column-inserts     dump data as INSERT commands with column names\n"));
-       printf(_("  -E, --encoding=ENCODING  dump the data in encoding ENCODING\n"));
-       printf(_("  -n, --schema=SCHEMA      dump the named schema only\n"));
-       printf(_("  -o, --oids               include OIDs in dump\n"));
-       printf(_("  -O, --no-owner           skip restoration of object ownership\n"
-                        "                           in plain text format\n"));
-       printf(_("  -s, --schema-only        dump only the schema, no data\n"));
-       printf(_("  -S, --superuser=NAME     specify the superuser user name to use in\n"
-                        "                           plain text format\n"));
-       printf(_("  -t, --table=TABLE        dump the named table only\n"));
-       printf(_("  -x, --no-privileges      do not dump privileges (grant/revoke)\n"));
+       printf(_("  -a, --data-only             dump only the data, not the schema\n"));
+       printf(_("  -c, --clean                 clean (drop) schema prior to create\n"));
+       printf(_("  -C, --create                include commands to create database in dump\n"));
+       printf(_("  -d, --inserts               dump data as INSERT, rather than COPY, commands\n"));
+       printf(_("  -D, --column-inserts        dump data as INSERT commands with column names\n"));
+       printf(_("  -E, --encoding=ENCODING     dump the data in encoding ENCODING\n"));
+       printf(_("  -n, --schema=SCHEMA         dump the named schema only\n"));
+       printf(_("  -N, --exclude-schema=SCHEMA do NOT dump the named schema\n"));
+       printf(_("  -o, --oids                  include OIDs in dump\n"));
+       printf(_("  -O, --no-owner              skip restoration of object ownership\n"
+                        "                              in plain text format\n"));
+       printf(_("  -s, --schema-only           dump only the schema, no data\n"));
+       printf(_("  -S, --superuser=NAME        specify the superuser user name to use in\n"
+                        "                              plain text format\n"));
+       printf(_("  -t, --table=TABLE           dump the named table only\n"));
+       printf(_("  -T, --exclude-table=TABLE   do NOT dump the named table\n"));
+       printf(_("  -x, --no-privileges         do not dump privileges (grant/revoke)\n"));
        printf(_("  -X disable-dollar-quoting, --disable-dollar-quoting\n"
-                        "                           disable dollar quoting, use SQL standard quoting\n"));
+                        "                              disable dollar quoting, use SQL standard quoting\n"));
        printf(_("  -X disable-triggers, --disable-triggers\n"
-                        "                           disable triggers during data-only restore\n"));
+                        "                              disable triggers during data-only restore\n"));
        printf(_("  -X use-set-session-authorization, --use-set-session-authorization\n"
-                        "                           use SESSION AUTHORIZATION commands instead of\n"
-                        "                           OWNER TO commands\n"));
+                        "                              use SESSION AUTHORIZATION commands instead of\n"
+                        "                              OWNER TO commands\n"));
 
        printf(_("\nConnection options:\n"));
        printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
@@ -738,23 +943,27 @@ static void
 selectDumpableNamespace(NamespaceInfo *nsinfo)
 {
        /*
-        * If a specific table is being dumped, do not dump any complete
-        * namespaces.  If a specific namespace is being dumped, dump just that
-        * namespace. Otherwise, dump all non-system namespaces.
+        * If specific tables are being dumped, do not dump any complete
+        * namespaces.  If specific namespaces are being dumped, dump just 
+        * those namespaces. Otherwise, dump all non-system namespaces.
         */
-       if (selectTableName != NULL)
-               nsinfo->dobj.dump = false;
-       else if (selectSchemaName != NULL)
+       nsinfo->dobj.dump = false;
+
+       if (matchingTables != NULL)
+               /* false */;
+       else if (matchingSchemas != NULL)
        {
-               if (strcmp(nsinfo->dobj.name, selectSchemaName) == 0)
+               char *search_oid = malloc(20);
+
+               sprintf(search_oid, " %d ", nsinfo->dobj.catId.oid);
+               if (strstr(matchingSchemas, search_oid) != NULL)
                        nsinfo->dobj.dump = true;
-               else
-                       nsinfo->dobj.dump = false;
+
+               free(search_oid);
        }
-       else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
-                        strcmp(nsinfo->dobj.name, "information_schema") == 0)
-               nsinfo->dobj.dump = false;
-       else
+       /* The server prevents users from creating pg_ schemas */
+       else if (strncmp(nsinfo->dobj.name, "pg_", 3) != 0 &&
+                        strcmp(nsinfo->dobj.name, "information_schema") != 0)
                nsinfo->dobj.dump = true;
 }
 
@@ -771,16 +980,21 @@ selectDumpableTable(TableInfo *tbinfo)
         * dump.
         */
        tbinfo->dobj.dump = false;
-       if (tbinfo->dobj.namespace->dobj.dump)
-               tbinfo->dobj.dump = true;
-       else if (selectTableName != NULL &&
-                        strcmp(tbinfo->dobj.name, selectTableName) == 0)
+
+       if (matchingTables == NULL)
        {
-               /* If both -s and -t specified, must match both to dump */
-               if (selectSchemaName == NULL)
+               if (tbinfo->dobj.namespace->dobj.dump)
                        tbinfo->dobj.dump = true;
-               else if (strcmp(tbinfo->dobj.namespace->dobj.name, selectSchemaName) == 0)
+       }
+       else
+       {
+               char *search_oid = malloc(20);
+
+               sprintf(search_oid, " %d ", tbinfo->dobj.catId.oid);
+               if (strstr(matchingTables, search_oid) != NULL)
                        tbinfo->dobj.dump = true;
+
+               free(search_oid);
        }
 }
 
@@ -1722,25 +1936,6 @@ getNamespaces(int *numNamespaces)
                                          nsinfo[i].dobj.name);
        }
 
-       /*
-        * If the user attempted to dump a specific namespace, check to ensure
-        * that the specified namespace actually exists.
-        */
-       if (selectSchemaName)
-       {
-               for (i = 0; i < ntups; i++)
-                       if (strcmp(nsinfo[i].dobj.name, selectSchemaName) == 0)
-                               break;
-
-               /* Didn't find a match */
-               if (i == ntups)
-               {
-                       write_msg(NULL, "specified schema \"%s\" does not exist\n",
-                                         selectSchemaName);
-                       exit_nicely();
-               }
-       }
-
        PQclear(res);
        destroyPQExpBuffer(query);
 
@@ -2638,14 +2833,14 @@ getTables(int *numTables)
         * 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. We must fetch all tables in this phase because otherwise
-        * we cannot correctly identify inherited columns, serial columns, etc.
+        * we cannot correctly identify inherited columns, owned sequences, etc.
         */
 
        if (g_fout->remoteVersion >= 80200)
        {
                /*
                 * Left join to pick up dependency info linking sequences to their
-                * serial column, if any
+                * owning column, if any (note this dependency is AUTO as of 8.2)
                 */
                appendPQExpBuffer(query,
                                                  "SELECT c.tableoid, c.oid, relname, "
@@ -2662,7 +2857,7 @@ getTables(int *numTables)
                                                  "(c.relkind = '%c' and "
                                                  "d.classid = c.tableoid and d.objid = c.oid and "
                                                  "d.objsubid = 0 and "
-                                                 "d.refclassid = c.tableoid and d.deptype = 'i') "
+                                                 "d.refclassid = c.tableoid and d.deptype = 'a') "
                                                  "where relkind in ('%c', '%c', '%c', '%c') "
                                                  "order by c.oid",
                                                  username_subquery,
@@ -2674,7 +2869,7 @@ getTables(int *numTables)
        {
                /*
                 * Left join to pick up dependency info linking sequences to their
-                * serial column, if any
+                * owning column, if any
                 */
                appendPQExpBuffer(query,
                                                  "SELECT c.tableoid, c.oid, relname, "
@@ -2703,7 +2898,7 @@ getTables(int *numTables)
        {
                /*
                 * Left join to pick up dependency info linking sequences to their
-                * serial column, if any
+                * owning column, if any
                 */
                appendPQExpBuffer(query,
                                                  "SELECT c.tableoid, c.oid, relname, "
@@ -2866,14 +3061,10 @@ getTables(int *numTables)
                /* other fields were zeroed above */
 
                /*
-                * Decide whether we want to dump this table.  Sequences owned by
-                * serial columns are never dumpable on their own; we will transpose
-                * their owning table's dump flag to them below.
+                * Decide whether we want to dump this table.
                 */
                if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
                        tblinfo[i].dobj.dump = false;
-               else if (OidIsValid(tblinfo[i].owning_tab))
-                       tblinfo[i].dobj.dump = false;
                else
                        selectDumpableTable(&tblinfo[i]);
                tblinfo[i].interesting = tblinfo[i].dobj.dump;
@@ -2905,27 +3096,37 @@ getTables(int *numTables)
                                          tblinfo[i].dobj.name);
        }
 
+       PQclear(res);
+
        /*
-        * If the user is attempting to dump a specific table, check to ensure
-        * that the specified table actually exists.  (This is a bit simplistic
-        * since we don't fully check the combination of -n and -t switches.)
+        * Force sequences that are "owned" by table columns to be dumped
+        * whenever their owning table is being dumped.
         */
-       if (selectTableName)
+       for (i = 0; i < ntups; i++)
        {
-               for (i = 0; i < ntups; i++)
-                       if (strcmp(tblinfo[i].dobj.name, selectTableName) == 0)
-                               break;
+               TableInfo  *seqinfo = &tblinfo[i];
+               int             j;
+
+               if (!OidIsValid(seqinfo->owning_tab))
+                       continue;                       /* not an owned sequence */
+               if (seqinfo->dobj.dump)
+                       continue;                       /* no need to search */
 
-               /* Didn't find a match */
-               if (i == ntups)
+               /* can't use findTableByOid yet, unfortunately */
+               for (j = 0; j < ntups; j++)
                {
-                       write_msg(NULL, "specified table \"%s\" does not exist\n",
-                                         selectTableName);
-                       exit_nicely();
+                       if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
+                       {
+                               if (tblinfo[j].dobj.dump)
+                               {
+                                       seqinfo->interesting = true;
+                                       seqinfo->dobj.dump = true;
+                               }
+                               break;
+                       }
                }
        }
 
-       PQclear(res);
        destroyPQExpBuffer(query);
        destroyPQExpBuffer(delqry);
        destroyPQExpBuffer(lockquery);
@@ -3986,8 +4187,7 @@ void
 getTableAttrs(TableInfo *tblinfo, int numTables)
 {
        int                     i,
-                               j,
-                               k;
+                               j;
        PQExpBuffer q = createPQExpBuffer();
        int                     i_attnum;
        int                     i_attname;
@@ -4106,7 +4306,6 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
                tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
                tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
-               tbinfo->attisserial = (bool *) malloc(ntups * sizeof(bool));
                tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
                tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
                tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
@@ -4130,7 +4329,6 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                        tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
                        tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
                        tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
-                       tbinfo->attisserial[j] = false;         /* fix below */
                        tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
                        tbinfo->attrdefs[j] = NULL; /* fix below */
                        if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
@@ -4363,44 +4561,6 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                        }
                        PQclear(res);
                }
-
-               /*
-                * Check to see if any columns are serial columns.      Our first quick
-                * filter is that it must be integer or bigint with a default.  If so,
-                * we scan to see if we found a sequence linked to this column. If we
-                * did, mark the column and sequence appropriately.
-                */
-               for (j = 0; j < ntups; j++)
-               {
-                       /*
-                        * Note assumption that format_type will show these types as
-                        * exactly "integer" and "bigint" regardless of schema path. This
-                        * is correct in 7.3 but needs to be watched.
-                        */
-                       if (strcmp(tbinfo->atttypnames[j], "integer") != 0 &&
-                               strcmp(tbinfo->atttypnames[j], "bigint") != 0)
-                               continue;
-                       if (tbinfo->attrdefs[j] == NULL)
-                               continue;
-                       for (k = 0; k < numTables; k++)
-                       {
-                               TableInfo  *seqinfo = &tblinfo[k];
-
-                               if (OidIsValid(seqinfo->owning_tab) &&
-                                       seqinfo->owning_tab == tbinfo->dobj.catId.oid &&
-                                       seqinfo->owning_col == j + 1)
-                               {
-                                       /*
-                                        * Found a match.  Copy the table's interesting and
-                                        * dumpable flags to the sequence.
-                                        */
-                                       tbinfo->attisserial[j] = true;
-                                       seqinfo->interesting = tbinfo->interesting;
-                                       seqinfo->dobj.dump = tbinfo->dobj.dump;
-                                       break;
-                               }
-                       }
-               }
        }
 
        destroyPQExpBuffer(q);
@@ -5438,7 +5598,7 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 static bool
 shouldDumpProcLangs(void)
 {
-       if (selectTableName != NULL || selectSchemaName != NULL)
+       if (matchingTables != NULL || matchingSchemas != NULL)
                return false;
        /* And they're schema not data */
        if (dataOnly)
@@ -6002,7 +6162,7 @@ dumpCast(Archive *fout, CastInfo *cast)
         * Skip this cast if all objects are from pg_
         */
        if ((funcInfo == NULL ||
-                strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
+               strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
                strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
                strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
                return;
@@ -7228,16 +7388,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                /* Attribute type */
                                if (g_fout->remoteVersion >= 70100)
                                {
-                                       char       *typname = tbinfo->atttypnames[j];
-
-                                       if (tbinfo->attisserial[j])
-                                       {
-                                               if (strcmp(typname, "integer") == 0)
-                                                       typname = "serial";
-                                               else if (strcmp(typname, "bigint") == 0)
-                                                       typname = "bigserial";
-                                       }
-                                       appendPQExpBuffer(q, "%s", typname);
+                                       appendPQExpBuffer(q, "%s",
+                                                                         tbinfo->atttypnames[j]);
                                }
                                else
                                {
@@ -7248,24 +7400,17 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                }
 
                                /*
-                                * Default value --- suppress if inherited, serial, or to be
+                                * Default value --- suppress if inherited or to be
                                 * printed separately.
                                 */
                                if (tbinfo->attrdefs[j] != NULL &&
                                        !tbinfo->inhAttrDef[j] &&
-                                       !tbinfo->attisserial[j] &&
                                        !tbinfo->attrdefs[j]->separate)
                                        appendPQExpBuffer(q, " DEFAULT %s",
                                                                          tbinfo->attrdefs[j]->adef_expr);
 
                                /*
                                 * Not Null constraint --- suppress if inherited
-                                *
-                                * Note: we could suppress this for serial columns since
-                                * SERIAL implies NOT NULL.  We choose not to for forward
-                                * compatibility, since there has been some talk of making
-                                * SERIAL not imply NOT NULL, in which case the explicit
-                                * specification would be needed.
                                 */
                                if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
                                        appendPQExpBuffer(q, " NOT NULL");
@@ -7422,8 +7567,8 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
        if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
                return;
 
-       /* Don't print inherited or serial defaults, either */
-       if (tbinfo->inhAttrDef[adnum - 1] || tbinfo->attisserial[adnum - 1])
+       /* Don't print inherited defaults, either */
+       if (tbinfo->inhAttrDef[adnum - 1])
                return;
 
        q = createPQExpBuffer();
@@ -7936,15 +8081,14 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
        /*
         * The logic we use for restoring sequences is as follows:
         *
-        * Add a basic CREATE SEQUENCE statement (use last_val for start if called
-        * is false, else use min_val for start_val).  Skip this if the sequence
-        * came from a SERIAL column.
+        * Add a CREATE SEQUENCE statement as part of a "schema" dump
+        * (use last_val for start if called is false, else use min_val for
+        * start_val).  Also, if the sequence is owned by a column, add an
+        * ALTER SEQUENCE SET OWNED command for it.
         *
-        * Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff we load
-        * data. We do this for serial sequences too.
+        * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
         */
-
-       if (!dataOnly && !OidIsValid(tbinfo->owning_tab))
+       if (!dataOnly)
        {
                resetPQExpBuffer(delqry);
 
@@ -7991,32 +8135,57 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
                                         false, "SEQUENCE", query->data, delqry->data, NULL,
                                         tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
                                         NULL, NULL);
+
+               /*
+                * If the sequence is owned by a table column, emit the ALTER for it
+                * as a separate TOC entry immediately following the sequence's own
+                * entry.  It's OK to do this rather than using full sorting logic,
+                * because the dependency that tells us it's owned will have forced
+                * the table to be created first.  We can't just include the ALTER
+                * in the TOC entry because it will fail if we haven't reassigned
+                * the sequence owner to match the table's owner.
+                *
+                * We need not schema-qualify the table reference because both
+                * sequence and table must be in the same schema.
+                */
+               if (OidIsValid(tbinfo->owning_tab))
+               {
+                       TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
+
+                       if (owning_tab)
+                       {
+                               resetPQExpBuffer(query);
+                               appendPQExpBuffer(query, "ALTER SEQUENCE %s",
+                                                                 fmtId(tbinfo->dobj.name));
+                               appendPQExpBuffer(query, " OWNED BY %s",
+                                                                 fmtId(owning_tab->dobj.name));
+                               appendPQExpBuffer(query, ".%s;\n",
+                                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
+
+                               ArchiveEntry(fout, nilCatalogId, createDumpId(),
+                                                        tbinfo->dobj.name,
+                                                        tbinfo->dobj.namespace->dobj.name,
+                                                        NULL,
+                                                        tbinfo->rolname,
+                                                        false, "SEQUENCE OWNED BY", query->data, "", NULL,
+                                                        &(tbinfo->dobj.dumpId), 1,
+                                                        NULL, NULL);
+                       }
+               }
+
+               /* Dump Sequence Comments */
+               resetPQExpBuffer(query);
+               appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
+               dumpComment(fout, query->data,
+                                       tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+                                       tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
        }
 
        if (!schemaOnly)
        {
-               TableInfo  *owning_tab;
-
                resetPQExpBuffer(query);
                appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
-
-               /*
-                * If this is a SERIAL sequence, then use the pg_get_serial_sequence
-                * function to avoid hard-coding the sequence name.  Note that this
-                * implicitly assumes that the sequence and its owning table are in
-                * the same schema, because we don't schema-qualify the reference.
-                */
-               if (OidIsValid(tbinfo->owning_tab) &&
-                       (owning_tab = findTableByOid(tbinfo->owning_tab)) != NULL)
-               {
-                       appendPQExpBuffer(query, "pg_catalog.pg_get_serial_sequence(");
-                       appendStringLiteralAH(query, fmtId(owning_tab->dobj.name), fout);
-                       appendPQExpBuffer(query, ", ");
-                       appendStringLiteralAH(query, owning_tab->attnames[tbinfo->owning_col - 1], fout);
-                       appendPQExpBuffer(query, ")");
-               }
-               else
-                       appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
+               appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
                appendPQExpBuffer(query, ", %s, %s);\n",
                                                  last, (called ? "true" : "false"));
 
@@ -8030,16 +8199,6 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
                                         NULL, NULL);
        }
 
-       if (!dataOnly)
-       {
-               /* Dump Sequence Comments */
-               resetPQExpBuffer(query);
-               appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
-               dumpComment(fout, query->data,
-                                       tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-                                       tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
-       }
-
        PQclear(res);
 
        destroyPQExpBuffer(query);