* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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 */
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";
DumpableObject **dobjs;
int numObjs;
int i;
+ bool switch_include_exclude;
bool force_password = false;
int compressLevel = -1;
bool ignore_version = false;
{"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'},
}
}
- 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)
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 */
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);
exit(1);
}
- if (selectTableName != NULL || selectSchemaName != NULL)
+ if (matchingTables != NULL || matchingSchemas != NULL)
outputBlobs = false;
if (dumpInserts == true && oids == true)
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);
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. */
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"));
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;
}
* 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);
}
}
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);
* 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, "
"(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,
{
/*
* 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, "
{
/*
* 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, "
/* 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;
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);
getTableAttrs(TableInfo *tblinfo, int numTables)
{
int i,
- j,
- k;
+ j;
PQExpBuffer q = createPQExpBuffer();
int i_attnum;
int i_attname;
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));
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')
}
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);
static bool
shouldDumpProcLangs(void)
{
- if (selectTableName != NULL || selectSchemaName != NULL)
+ if (matchingTables != NULL || matchingSchemas != NULL)
return false;
/* And they're schema not data */
if (dataOnly)
* 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;
/* 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
{
}
/*
- * 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");
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();
/*
* 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);
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"));
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);