diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml
index 150bf7b0f6..baa23d1e5e 100644
--- a/doc/src/sgml/ref/pg_dump.sgml
+++ b/doc/src/sgml/ref/pg_dump.sgml
@@ -1,5 +1,5 @@
@@ -398,24 +398,107 @@ PostgreSQL documentation
Dump data for table
- only. It is possible for there to be
- multiple tables with the same name in different schemas; if that
- is the case, all matching tables will be dumped. Specify both
-
+
+ The options
+
+ For example, to dump a single table named pg_class>:
+
+
+$pg_dump -t pg_class mydb > db.out
+
+
+
+ To dump all tables starting with employee> in the
+ detroit> schema, except for the table named employee_log:
+
+
+$pg_dump -n detroit -t ^employee -T employee_log mydb > db.out
+
+
+
+ To dump all schemas starting with east> or west> and ending in
+ gsm>, but not schemas that contain the letters test>, except for
+ one named east_alpha_test_five>:
+
+
+$pg_dump -n "^(east|west).*gsm$" -N test -n east_alpha_test_five mydb > db.out
+
+
+
+
+ To dump all tables except for those beginning with ts_:
+
+
+$pg_dump -T "^ts_" mydb > db.out
+
+
+
+
In this mode, pg_dump makes no
- attempt to dump any other database objects that the selected table
+ attempt to dump any other database objects that the selected tables
may depend upon. Therefore, there is no guarantee
- that the results of a single-table dump can be successfully
+ that the results of a specific-table dump can be successfully
restored by themselves into a clean database.
+
+
+
+
+
+ Do not dump any matching tables.
+ More than one option can be used, and POSIX regular expressions are handled just
+ like -t>.
+
+
+
+
+
+
+
+
+
+ Dump only the matching schemas.
+ More than one option can be used, and POSIX regular expressions are handled just
+ like -t>.
+
+
+
+
+
+
+
+
+
+
+ Do not dump the matching schemas.
+ More than one option can be used, and POSIX regular expressions are handled just
+ like -t>.
+
+
+
+
+
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index fdaee77739..fc737d59ac 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.91 2006/07/14 14:52:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.92 2006/08/01 18:05:04 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -72,9 +72,7 @@ static int strInArray(const char *pattern, char **arr, int arr_size);
* Collect information about all potentially dumpable objects
*/
TableInfo *
-getSchemaData(int *numTablesPtr,
- const bool schemaOnly,
- const bool dataOnly)
+getSchemaData(int *numTablesPtr)
{
NamespaceInfo *nsinfo;
AggInfo *agginfo;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index ea69773919..bf2874f3df 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.443 2006/08/01 18:05:04 momjian 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 = 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,9 +298,11 @@ 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)
{
+ objnameArg *schemaList_tail = NULL, *tableList_tail = NULL;
+
switch (c)
{
case 'a': /* Dump data only */
@@ -332,8 +351,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 +414,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 +498,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 +617,157 @@ 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 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 oid FROM pg_catalog.pg_class WHERE relkind='r' 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 +823,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 +882,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,18 +935,20 @@ 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)
+ if (matchingTables != NULL)
nsinfo->dobj.dump = false;
- else if (selectSchemaName != NULL)
+ else if (matchingSchemas != NULL)
{
- if (strcmp(nsinfo->dobj.name, selectSchemaName) == 0)
+ char *searchname = NULL;
+ searchname = malloc(20);
+ sprintf(searchname, " %d ", nsinfo->dobj.catId.oid);
+ if (strstr(matchingSchemas, searchname) != NULL)
nsinfo->dobj.dump = true;
- else
- nsinfo->dobj.dump = false;
+ free(searchname);
}
else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
strcmp(nsinfo->dobj.name, "information_schema") == 0)
@@ -771,16 +970,16 @@ selectDumpableTable(TableInfo *tbinfo)
* dump.
*/
tbinfo->dobj.dump = false;
- if (tbinfo->dobj.namespace->dobj.dump)
+ if (tbinfo->dobj.namespace->dobj.dump || matchingTables == NULL)
tbinfo->dobj.dump = true;
- else if (selectTableName != NULL &&
- strcmp(tbinfo->dobj.name, selectTableName) == 0)
+ else
{
- /* If both -s and -t specified, must match both to dump */
- if (selectSchemaName == NULL)
- tbinfo->dobj.dump = true;
- else if (strcmp(tbinfo->dobj.namespace->dobj.name, selectSchemaName) == 0)
+ char *searchname = NULL;
+ searchname = malloc(20);
+ sprintf(searchname, " %d ", tbinfo->dobj.catId.oid);
+ if (strstr(matchingTables, searchname) != NULL)
tbinfo->dobj.dump = true;
+ free(searchname);
}
}
@@ -1722,25 +1921,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);
@@ -2905,26 +3085,6 @@ getTables(int *numTables)
tblinfo[i].dobj.name);
}
- /*
- * 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.)
- */
- if (selectTableName)
- {
- for (i = 0; i < ntups; i++)
- if (strcmp(tblinfo[i].dobj.name, selectTableName) == 0)
- break;
-
- /* Didn't find a match */
- if (i == ntups)
- {
- write_msg(NULL, "specified table \"%s\" does not exist\n",
- selectTableName);
- exit_nicely();
- }
- }
-
PQclear(res);
destroyPQExpBuffer(query);
destroyPQExpBuffer(delqry);
@@ -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)
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 738eff36ac..3650ae50de 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.127 2006/07/27 19:52:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.128 2006/08/01 18:05:04 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -340,9 +340,7 @@ extern char g_opaque_type[10]; /* name for the opaque type */
* common utility functions
*/
-extern TableInfo *getSchemaData(int *numTablesPtr,
- const bool schemaOnly,
- const bool dataOnly);
+extern TableInfo *getSchemaData(int *numTablesPtr);
typedef enum _OidOptions
{