diff --git a/doc/src/sgml/ref/pg_dumpall.sgml b/doc/src/sgml/ref/pg_dumpall.sgml index 0a3b44c48a..cdaf277a30 100644 --- a/doc/src/sgml/ref/pg_dumpall.sgml +++ b/doc/src/sgml/ref/pg_dumpall.sgml @@ -1,5 +1,5 @@ @@ -128,6 +128,18 @@ PostgreSQL documentation + + + + + + + Write the output to the specified file. This is particularly useful + on Windows because output redirection does not work for child + processes. + + + diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h index 3ada7cc73c..a870516d7a 100644 --- a/src/bin/pg_dump/pg_backup.h +++ b/src/bin/pg_dump/pg_backup.h @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup.h,v 1.44 2006/10/14 23:07:22 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup.h,v 1.45 2007/01/25 03:30:43 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -46,6 +46,13 @@ typedef enum _archiveFormat archNull = 4 } ArchiveFormat; +typedef enum _archiveMode +{ + archModeAppend, + archModeWrite, + archModeRead +} ArchiveMode; + /* * We may want to have some more user-readable data, but in the mean * time this gives us some abstraction and type checking. @@ -166,7 +173,7 @@ extern Archive *OpenArchive(const char *FileSpec, const ArchiveFormat fmt); /* Create a new archive */ extern Archive *CreateArchive(const char *FileSpec, const ArchiveFormat fmt, - const int compression); + const int compression, ArchiveMode mode); /* The --list option */ extern void PrintTOCSummary(Archive *AH, RestoreOptions *ropt); diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index a4c5d6d712..cd84c60882 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.139 2007/01/23 17:54:50 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.140 2007/01/25 03:30:43 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -86,10 +86,10 @@ static void ResetOutput(ArchiveHandle *AH, OutputContext savedContext); /* Public */ Archive * CreateArchive(const char *FileSpec, const ArchiveFormat fmt, - const int compression) + const int compression, ArchiveMode mode) { - ArchiveHandle *AH = _allocAH(FileSpec, fmt, compression, archModeWrite); + ArchiveHandle *AH = _allocAH(FileSpec, fmt, compression, mode); return (Archive *) AH; } @@ -203,7 +203,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt) /* * Setup the output file if necessary. - */ + */ if (ropt->filename || ropt->compression) sav = SetOutput(AH, ropt->filename, ropt->compression); @@ -940,10 +940,20 @@ SetOutput(ArchiveHandle *AH, char *filename, int compression) else #endif { /* Use fopen */ - if (fn >= 0) - AH->OF = fdopen(dup(fn), PG_BINARY_W); + if (AH->mode == archModeAppend) + { + if (fn >= 0) + AH->OF = fdopen(dup(fn), PG_BINARY_A); + else + AH->OF = fopen(filename, PG_BINARY_A); + } else - AH->OF = fopen(filename, PG_BINARY_W); + { + if (fn >= 0) + AH->OF = fdopen(dup(fn), PG_BINARY_W); + else + AH->OF = fopen(filename, PG_BINARY_W); + } AH->gzOut = 0; } diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h index b64b8f3d32..4a8cff3598 100644 --- a/src/bin/pg_dump/pg_backup_archiver.h +++ b/src/bin/pg_dump/pg_backup_archiver.h @@ -17,7 +17,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.73 2006/10/04 00:30:05 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.74 2007/01/25 03:30:43 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -122,12 +122,6 @@ typedef void (*PrintTocDataPtr) (struct _archiveHandle * AH, struct _tocEntry * typedef size_t (*CustomOutPtr) (struct _archiveHandle * AH, const void *buf, size_t len); -typedef enum _archiveMode -{ - archModeWrite, - archModeRead -} ArchiveMode; - typedef struct _outputContext { void *OF; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index c8b3e3916a..2fec7326d5 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.458 2007/01/23 17:54:50 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.459 2007/01/25 03:30:43 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -478,25 +478,31 @@ main(int argc, char **argv) /* open the output file */ switch (format[0]) { + case 'a': + case 'A': + plainText = 1; + g_fout = CreateArchive(filename, archNull, 0, archModeAppend); + break; + case 'c': case 'C': - g_fout = CreateArchive(filename, archCustom, compressLevel); + g_fout = CreateArchive(filename, archCustom, compressLevel, archModeWrite); break; case 'f': case 'F': - g_fout = CreateArchive(filename, archFiles, compressLevel); + g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite); break; case 'p': case 'P': plainText = 1; - g_fout = CreateArchive(filename, archNull, 0); + g_fout = CreateArchive(filename, archNull, 0, archModeWrite); break; case 't': case 'T': - g_fout = CreateArchive(filename, archTar, compressLevel); + g_fout = CreateArchive(filename, archTar, compressLevel, archModeWrite); break; default: diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 66c66d8a1a..e2e3a9f5bb 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.88 2007/01/25 02:46:33 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.89 2007/01/25 03:30:43 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -68,23 +68,25 @@ static int disable_triggers = 0; static int use_setsessauth = 0; static int server_version; +static FILE *OPF; +static char *filename = NULL; int main(int argc, char *argv[]) { - char *pghost = NULL; - char *pgport = NULL; - char *pguser = NULL; - char *pgdb = NULL; + char *pghost = NULL; + char *pgport = NULL; + char *pguser = NULL; + char *pgdb = NULL; bool force_password = false; bool data_only = false; bool globals_only = false; bool roles_only = false; bool tablespaces_only = false; bool schema_only = false; - PGconn *conn; + PGconn *conn; int encoding; - const char *std_strings; + const char *std_strings; int c, ret; @@ -94,6 +96,7 @@ main(int argc, char *argv[]) {"inserts", no_argument, NULL, 'd'}, {"attribute-inserts", no_argument, NULL, 'D'}, {"column-inserts", no_argument, NULL, 'D'}, + {"file", required_argument, NULL, 'f'}, {"globals-only", no_argument, NULL, 'g'}, {"host", required_argument, NULL, 'h'}, {"ignore-version", no_argument, NULL, 'i'}, @@ -167,7 +170,7 @@ main(int argc, char *argv[]) pgdumpopts = createPQExpBuffer(); - while ((c = getopt_long(argc, argv, "acdDgh:il:oOp:rsS:tU:vWxX:", long_options, &optindex)) != -1) + while ((c = getopt_long(argc, argv, "acdDf:gh:il:oOp:rsS:tU:vWxX:", long_options, &optindex)) != -1) { switch (c) { @@ -184,6 +187,16 @@ main(int argc, char *argv[]) case 'D': appendPQExpBuffer(pgdumpopts, " -%c", c); break; + + case 'f': + filename = optarg; +#ifndef WIN32 + appendPQExpBuffer(pgdumpopts, " -f '%s'", filename); +#else + appendPQExpBuffer(pgdumpopts, " -f \"%s\"", filename); +#endif + + break; case 'g': globals_only = true; @@ -377,6 +390,22 @@ main(int argc, char *argv[]) exit(1); } } + + /* + * Open the output file if required, otherwise use stdout + */ + if (filename) + { + OPF = fopen(filename, PG_BINARY_W); + if (!OPF) + { + fprintf(stderr, _("%s: could not open the output file \"%s\"\n"), + progname, filename); + exit(1); + } + } + else + OPF = stdout; /* * Get the active encoding and the standard_conforming_strings setting, so @@ -387,21 +416,21 @@ main(int argc, char *argv[]) if (!std_strings) std_strings = "off"; - printf("--\n-- PostgreSQL database cluster dump\n--\n\n"); + fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n"); if (verbose) dumpTimestamp("Started on"); - printf("\\connect postgres\n\n"); + fprintf(OPF, "\\connect postgres\n\n"); if (!data_only) { /* Replicate encoding and std_strings in output */ - printf("SET client_encoding = '%s';\n", + fprintf(OPF, "SET client_encoding = '%s';\n", pg_encoding_to_char(encoding)); - printf("SET standard_conforming_strings = %s;\n", std_strings); + fprintf(OPF, "SET standard_conforming_strings = %s;\n", std_strings); if (strcmp(std_strings, "off") == 0) - printf("SET escape_string_warning = 'off';\n"); - printf("\n"); + fprintf(OPF, "SET escape_string_warning = 'off';\n"); + fprintf(OPF, "\n"); if (!tablespaces_only) { @@ -434,7 +463,10 @@ main(int argc, char *argv[]) if (verbose) dumpTimestamp("Completed on"); - printf("--\n-- PostgreSQL database cluster dump complete\n--\n\n"); + fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n"); + + if (filename) + fclose(OPF); exit(0); } @@ -449,6 +481,7 @@ help(void) printf(_(" %s [OPTION]...\n"), progname); printf(_("\nGeneral options:\n")); + printf(_(" -f, --file=FILENAME output file name\n")); printf(_(" -i, --ignore-version proceed even when server version mismatches\n" " pg_dumpall version\n")); printf(_(" --help show this help, then exit\n")); @@ -571,7 +604,7 @@ dumpRoles(PGconn *conn) i_rolcomment = PQfnumber(res, "rolcomment"); if (PQntuples(res) > 0) - printf("--\n-- Roles\n--\n\n"); + fprintf(OPF, "--\n-- Roles\n--\n\n"); for (i = 0; i < PQntuples(res); i++) { @@ -641,7 +674,7 @@ dumpRoles(PGconn *conn) appendPQExpBuffer(buf, ";\n"); } - printf("%s", buf->data); + fprintf(OPF, "%s", buf->data); if (server_version >= 70300) dumpUserConfig(conn, rolename); @@ -649,7 +682,7 @@ dumpRoles(PGconn *conn) PQclear(res); - printf("\n\n"); + fprintf(OPF, "\n\n"); destroyPQExpBuffer(buf); } @@ -678,7 +711,7 @@ dumpRoleMembership(PGconn *conn) "ORDER BY 1,2,3"); if (PQntuples(res) > 0) - printf("--\n-- Role memberships\n--\n\n"); + fprintf(OPF, "--\n-- Role memberships\n--\n\n"); for (i = 0; i < PQntuples(res); i++) { @@ -687,16 +720,16 @@ dumpRoleMembership(PGconn *conn) char *grantor = PQgetvalue(res, i, 2); char *option = PQgetvalue(res, i, 3); - printf("GRANT %s", fmtId(roleid)); - printf(" TO %s", fmtId(member)); + fprintf(OPF, "GRANT %s", fmtId(roleid)); + fprintf(OPF, " TO %s", fmtId(member)); if (*option == 't') - printf(" WITH ADMIN OPTION"); - printf(" GRANTED BY %s;\n", fmtId(grantor)); + fprintf(OPF, " WITH ADMIN OPTION"); + fprintf(OPF, " GRANTED BY %s;\n", fmtId(grantor)); } PQclear(res); - printf("\n\n"); + fprintf(OPF, "\n\n"); } /* @@ -718,7 +751,7 @@ dumpGroups(PGconn *conn) "SELECT groname, grolist FROM pg_group ORDER BY 1"); if (PQntuples(res) > 0) - printf("--\n-- Role memberships\n--\n\n"); + fprintf(OPF, "--\n-- Role memberships\n--\n\n"); for (i = 0; i < PQntuples(res); i++) { @@ -755,8 +788,8 @@ dumpGroups(PGconn *conn) if (strcmp(groname, usename) == 0) continue; - printf("GRANT %s", fmtId(groname)); - printf(" TO %s;\n", fmtId(usename)); + fprintf(OPF, "GRANT %s", fmtId(groname)); + fprintf(OPF, " TO %s;\n", fmtId(usename)); } PQclear(res2); @@ -765,7 +798,7 @@ dumpGroups(PGconn *conn) PQclear(res); destroyPQExpBuffer(buf); - printf("\n\n"); + fprintf(OPF, "\n\n"); } /* @@ -799,7 +832,7 @@ dumpTablespaces(PGconn *conn) "ORDER BY 1"); if (PQntuples(res) > 0) - printf("--\n-- Tablespaces\n--\n\n"); + fprintf(OPF, "--\n-- Tablespaces\n--\n\n"); for (i = 0; i < PQntuples(res); i++) { @@ -841,14 +874,14 @@ dumpTablespaces(PGconn *conn) appendPQExpBuffer(buf, ";\n"); } - printf("%s", buf->data); + fprintf(OPF, "%s", buf->data); free(fspcname); destroyPQExpBuffer(buf); } PQclear(res); - printf("\n\n"); + fprintf(OPF, "\n\n"); } /* @@ -869,7 +902,7 @@ dumpCreateDB(PGconn *conn) PGresult *res; int i; - printf("--\n-- Database creation\n--\n\n"); + fprintf(OPF, "--\n-- Database creation\n--\n\n"); if (server_version >= 80100) res = executeQuery(conn, @@ -998,7 +1031,7 @@ dumpCreateDB(PGconn *conn) exit(1); } - printf("%s", buf->data); + fprintf(OPF, "%s", buf->data); if (server_version >= 70300) dumpDatabaseConfig(conn, dbname); @@ -1009,7 +1042,7 @@ dumpCreateDB(PGconn *conn) PQclear(res); destroyPQExpBuffer(buf); - printf("\n\n"); + fprintf(OPF, "\n\n"); } @@ -1121,7 +1154,7 @@ makeAlterConfigCommand(PGconn *conn, const char *arrayitem, appendStringLiteralConn(buf, pos + 1, conn); appendPQExpBuffer(buf, ";\n"); - printf("%s", buf->data); + fprintf(OPF, "%s", buf->data); destroyPQExpBuffer(buf); free(mine); } @@ -1151,13 +1184,29 @@ dumpDatabases(PGconn *conn) if (verbose) fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname); - printf("\\connect %s\n\n", fmtId(dbname)); + fprintf(OPF, "\\connect %s\n\n", fmtId(dbname)); + + if (filename) + fclose(OPF); + ret = runPgDump(dbname); if (ret != 0) { fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname); exit(1); } + + if (filename) + { + OPF = fopen(filename, PG_BINARY_A); + if (!OPF) + { + fprintf(stderr, _("%s: could not re-open the output file \"%s\"\n"), + progname, filename); + exit(1); + } + } + } PQclear(res); @@ -1179,13 +1228,28 @@ runPgDump(const char *dbname) * Win32 has to use double-quotes for args, rather than single quotes. * Strangely enough, this is the only place we pass a database name on the * command line, except "postgres" which doesn't need quoting. + * + * If we have a filename, use the undocumented plain-append pg_dump format. */ + if (filename) + { +#ifndef WIN32 + appendPQExpBuffer(cmd, "%s\"%s\" %s -Fa '", SYSTEMQUOTE, pg_dump_bin, +#else + appendPQExpBuffer(cmd, "%s\"%s\" %s -Fa \"", SYSTEMQUOTE, pg_dump_bin, +#endif + pgdumpopts->data); + } + else + { #ifndef WIN32 appendPQExpBuffer(cmd, "%s\"%s\" %s -Fp '", SYSTEMQUOTE, pg_dump_bin, #else appendPQExpBuffer(cmd, "%s\"%s\" %s -Fp \"", SYSTEMQUOTE, pg_dump_bin, #endif pgdumpopts->data); + } + /* Shell quoting is not quite like SQL quoting, so can't use fmtId */ for (p = dbname; *p; p++) @@ -1413,5 +1477,5 @@ dumpTimestamp(char *msg) "%Y-%m-%d %H:%M:%S", #endif localtime(&now)) != 0) - printf("-- %s %s\n\n", msg, buf); + fprintf(OPF, "-- %s %s\n\n", msg, buf); } diff --git a/src/include/c.h b/src/include/c.h index dab8dc2e68..9daa9e4c0e 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/c.h,v 1.216 2007/01/11 02:39:52 momjian Exp $ + * $PostgreSQL: pgsql/src/include/c.h,v 1.217 2007/01/25 03:30:43 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -736,10 +736,12 @@ typedef NameData *Name; */ #if defined(WIN32) || defined(__CYGWIN__) #define PG_BINARY O_BINARY +#define PG_BINARY_A "ab" #define PG_BINARY_R "rb" #define PG_BINARY_W "wb" #else #define PG_BINARY 0 +#define PG_BINARY_A "a" #define PG_BINARY_R "r" #define PG_BINARY_W "w" #endif