X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbin%2Fpg_dump%2Fpg_dump.c;h=78a653fb48c0e40cff40aa819d48e0f82deed8bd;hb=2b2a50722cb1863147b4a86b3db80553f989a14c;hp=ea697739191a70ff71b45896136794fdb8c2d2cd;hpb=108fe4730152058f9b576969d08898b39bf7fc38;p=postgresql diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index ea69773919..78a653fb48 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -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);