Header And Logo

PostgreSQL
| The world's most advanced open source database.

pg_dumpall.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pg_dumpall.c
00004  *
00005  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00006  * Portions Copyright (c) 1994, Regents of the University of California
00007  *
00008  * pg_dumpall forces all pg_dump output to be text, since it also outputs
00009  * text into the same output stream.
00010  *
00011  * src/bin/pg_dump/pg_dumpall.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 
00016 #include "postgres_fe.h"
00017 
00018 #include <time.h>
00019 #include <unistd.h>
00020 
00021 #ifdef ENABLE_NLS
00022 #include <locale.h>
00023 #endif
00024 
00025 #include "getopt_long.h"
00026 
00027 #include "dumputils.h"
00028 #include "pg_backup.h"
00029 
00030 /* version string we expect back from pg_dump */
00031 #define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
00032 
00033 
00034 static void help(void);
00035 
00036 static void dropRoles(PGconn *conn);
00037 static void dumpRoles(PGconn *conn);
00038 static void dumpRoleMembership(PGconn *conn);
00039 static void dumpGroups(PGconn *conn);
00040 static void dropTablespaces(PGconn *conn);
00041 static void dumpTablespaces(PGconn *conn);
00042 static void dropDBs(PGconn *conn);
00043 static void dumpCreateDB(PGconn *conn);
00044 static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
00045 static void dumpUserConfig(PGconn *conn, const char *username);
00046 static void dumpDbRoleConfig(PGconn *conn);
00047 static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
00048                        const char *type, const char *name, const char *type2,
00049                        const char *name2);
00050 static void dumpDatabases(PGconn *conn);
00051 static void dumpTimestamp(char *msg);
00052 static void doShellQuoting(PQExpBuffer buf, const char *str);
00053 static void doConnStrQuoting(PQExpBuffer buf, const char *str);
00054 
00055 static int  runPgDump(const char *dbname);
00056 static void buildShSecLabels(PGconn *conn, const char *catalog_name,
00057                  uint32 objectId, PQExpBuffer buffer,
00058                  const char *target, const char *objname);
00059 static PGconn *connectDatabase(const char *dbname, const char *connstr, const char *pghost, const char *pgport,
00060       const char *pguser, enum trivalue prompt_password, bool fail_on_error);
00061 static char *constructConnStr(const char **keywords, const char **values);
00062 static PGresult *executeQuery(PGconn *conn, const char *query);
00063 static void executeCommand(PGconn *conn, const char *query);
00064 
00065 static char pg_dump_bin[MAXPGPATH];
00066 static const char *progname;
00067 static PQExpBuffer pgdumpopts;
00068 static char *connstr = "";
00069 static bool skip_acls = false;
00070 static bool verbose = false;
00071 
00072 static int  binary_upgrade = 0;
00073 static int  column_inserts = 0;
00074 static int  disable_dollar_quoting = 0;
00075 static int  disable_triggers = 0;
00076 static int  inserts = 0;
00077 static int  no_tablespaces = 0;
00078 static int  use_setsessauth = 0;
00079 static int  no_security_labels = 0;
00080 static int  no_unlogged_table_data = 0;
00081 static int  server_version;
00082 
00083 static FILE *OPF;
00084 static char *filename = NULL;
00085 
00086 #define exit_nicely(code) exit(code)
00087 
00088 int
00089 main(int argc, char *argv[])
00090 {
00091     static struct option long_options[] = {
00092         {"data-only", no_argument, NULL, 'a'},
00093         {"clean", no_argument, NULL, 'c'},
00094         {"file", required_argument, NULL, 'f'},
00095         {"globals-only", no_argument, NULL, 'g'},
00096         {"host", required_argument, NULL, 'h'},
00097         {"ignore-version", no_argument, NULL, 'i'},
00098         {"dbname", required_argument, NULL, 'd'},
00099         {"database", required_argument, NULL, 'l'},
00100         {"oids", no_argument, NULL, 'o'},
00101         {"no-owner", no_argument, NULL, 'O'},
00102         {"port", required_argument, NULL, 'p'},
00103         {"roles-only", no_argument, NULL, 'r'},
00104         {"schema-only", no_argument, NULL, 's'},
00105         {"superuser", required_argument, NULL, 'S'},
00106         {"tablespaces-only", no_argument, NULL, 't'},
00107         {"username", required_argument, NULL, 'U'},
00108         {"verbose", no_argument, NULL, 'v'},
00109         {"no-password", no_argument, NULL, 'w'},
00110         {"password", no_argument, NULL, 'W'},
00111         {"no-privileges", no_argument, NULL, 'x'},
00112         {"no-acl", no_argument, NULL, 'x'},
00113 
00114         /*
00115          * the following options don't have an equivalent short option letter
00116          */
00117         {"attribute-inserts", no_argument, &column_inserts, 1},
00118         {"binary-upgrade", no_argument, &binary_upgrade, 1},
00119         {"column-inserts", no_argument, &column_inserts, 1},
00120         {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
00121         {"disable-triggers", no_argument, &disable_triggers, 1},
00122         {"inserts", no_argument, &inserts, 1},
00123         {"lock-wait-timeout", required_argument, NULL, 2},
00124         {"no-tablespaces", no_argument, &no_tablespaces, 1},
00125         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
00126         {"role", required_argument, NULL, 3},
00127         {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
00128         {"no-security-labels", no_argument, &no_security_labels, 1},
00129         {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
00130 
00131         {NULL, 0, NULL, 0}
00132     };
00133 
00134     char       *pghost = NULL;
00135     char       *pgport = NULL;
00136     char       *pguser = NULL;
00137     char       *pgdb = NULL;
00138     char       *use_role = NULL;
00139     enum trivalue prompt_password = TRI_DEFAULT;
00140     bool        data_only = false;
00141     bool        globals_only = false;
00142     bool        output_clean = false;
00143     bool        roles_only = false;
00144     bool        tablespaces_only = false;
00145     PGconn     *conn;
00146     int         encoding;
00147     const char *std_strings;
00148     int         c,
00149                 ret;
00150     int         optindex;
00151 
00152     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
00153 
00154     progname = get_progname(argv[0]);
00155 
00156     if (argc > 1)
00157     {
00158         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
00159         {
00160             help();
00161             exit_nicely(0);
00162         }
00163         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
00164         {
00165             puts("pg_dumpall (PostgreSQL) " PG_VERSION);
00166             exit_nicely(0);
00167         }
00168     }
00169 
00170     if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR,
00171                                pg_dump_bin)) < 0)
00172     {
00173         char        full_path[MAXPGPATH];
00174 
00175         if (find_my_exec(argv[0], full_path) < 0)
00176             strlcpy(full_path, progname, sizeof(full_path));
00177 
00178         if (ret == -1)
00179             fprintf(stderr,
00180                     _("The program \"pg_dump\" is needed by %s "
00181                       "but was not found in the\n"
00182                       "same directory as \"%s\".\n"
00183                       "Check your installation.\n"),
00184                     progname, full_path);
00185         else
00186             fprintf(stderr,
00187                     _("The program \"pg_dump\" was found by \"%s\"\n"
00188                       "but was not the same version as %s.\n"
00189                       "Check your installation.\n"),
00190                     full_path, progname);
00191         exit_nicely(1);
00192     }
00193 
00194     pgdumpopts = createPQExpBuffer();
00195 
00196     while ((c = getopt_long(argc, argv, "acd:f:gh:i:l:oOp:rsS:tU:vwWx", long_options, &optindex)) != -1)
00197     {
00198         switch (c)
00199         {
00200             case 'a':
00201                 data_only = true;
00202                 appendPQExpBuffer(pgdumpopts, " -a");
00203                 break;
00204 
00205             case 'c':
00206                 output_clean = true;
00207                 break;
00208 
00209             case 'd':
00210                 connstr = pg_strdup(optarg);
00211                 break;
00212 
00213             case 'f':
00214                 filename = pg_strdup(optarg);
00215                 appendPQExpBuffer(pgdumpopts, " -f ");
00216                 doShellQuoting(pgdumpopts, filename);
00217                 break;
00218 
00219             case 'g':
00220                 globals_only = true;
00221                 break;
00222 
00223             case 'h':
00224                 pghost = pg_strdup(optarg);
00225                 break;
00226 
00227             case 'i':
00228                 /* ignored, deprecated option */
00229                 break;
00230 
00231             case 'l':
00232                 pgdb = pg_strdup(optarg);
00233                 break;
00234 
00235             case 'o':
00236                 appendPQExpBuffer(pgdumpopts, " -o");
00237                 break;
00238 
00239             case 'O':
00240                 appendPQExpBuffer(pgdumpopts, " -O");
00241                 break;
00242 
00243             case 'p':
00244                 pgport = pg_strdup(optarg);
00245                 break;
00246 
00247             case 'r':
00248                 roles_only = true;
00249                 break;
00250 
00251             case 's':
00252                 appendPQExpBuffer(pgdumpopts, " -s");
00253                 break;
00254 
00255             case 'S':
00256                 appendPQExpBuffer(pgdumpopts, " -S ");
00257                 doShellQuoting(pgdumpopts, optarg);
00258                 break;
00259 
00260             case 't':
00261                 tablespaces_only = true;
00262                 break;
00263 
00264             case 'U':
00265                 pguser = pg_strdup(optarg);
00266                 break;
00267 
00268             case 'v':
00269                 verbose = true;
00270                 appendPQExpBuffer(pgdumpopts, " -v");
00271                 break;
00272 
00273             case 'w':
00274                 prompt_password = TRI_NO;
00275                 appendPQExpBuffer(pgdumpopts, " -w");
00276                 break;
00277 
00278             case 'W':
00279                 prompt_password = TRI_YES;
00280                 appendPQExpBuffer(pgdumpopts, " -W");
00281                 break;
00282 
00283             case 'x':
00284                 skip_acls = true;
00285                 appendPQExpBuffer(pgdumpopts, " -x");
00286                 break;
00287 
00288             case 0:
00289                 break;
00290 
00291             case 2:
00292                 appendPQExpBuffer(pgdumpopts, " --lock-wait-timeout ");
00293                 doShellQuoting(pgdumpopts, optarg);
00294                 break;
00295 
00296             case 3:
00297                 use_role = pg_strdup(optarg);
00298                 appendPQExpBuffer(pgdumpopts, " --role ");
00299                 doShellQuoting(pgdumpopts, use_role);
00300                 break;
00301 
00302             default:
00303                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
00304                 exit_nicely(1);
00305         }
00306     }
00307 
00308     /* Complain if any arguments remain */
00309     if (optind < argc)
00310     {
00311         fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
00312                 progname, argv[optind]);
00313         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
00314                 progname);
00315         exit_nicely(1);
00316     }
00317 
00318     /* Make sure the user hasn't specified a mix of globals-only options */
00319     if (globals_only && roles_only)
00320     {
00321         fprintf(stderr, _("%s: options -g/--globals-only and -r/--roles-only cannot be used together\n"),
00322                 progname);
00323         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
00324                 progname);
00325         exit_nicely(1);
00326     }
00327 
00328     if (globals_only && tablespaces_only)
00329     {
00330         fprintf(stderr, _("%s: options -g/--globals-only and -t/--tablespaces-only cannot be used together\n"),
00331                 progname);
00332         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
00333                 progname);
00334         exit_nicely(1);
00335     }
00336 
00337     if (roles_only && tablespaces_only)
00338     {
00339         fprintf(stderr, _("%s: options -r/--roles-only and -t/--tablespaces-only cannot be used together\n"),
00340                 progname);
00341         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
00342                 progname);
00343         exit_nicely(1);
00344     }
00345 
00346     /* Add long options to the pg_dump argument list */
00347     if (binary_upgrade)
00348         appendPQExpBuffer(pgdumpopts, " --binary-upgrade");
00349     if (column_inserts)
00350         appendPQExpBuffer(pgdumpopts, " --column-inserts");
00351     if (disable_dollar_quoting)
00352         appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting");
00353     if (disable_triggers)
00354         appendPQExpBuffer(pgdumpopts, " --disable-triggers");
00355     if (inserts)
00356         appendPQExpBuffer(pgdumpopts, " --inserts");
00357     if (no_tablespaces)
00358         appendPQExpBuffer(pgdumpopts, " --no-tablespaces");
00359     if (quote_all_identifiers)
00360         appendPQExpBuffer(pgdumpopts, " --quote-all-identifiers");
00361     if (use_setsessauth)
00362         appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
00363     if (no_security_labels)
00364         appendPQExpBuffer(pgdumpopts, " --no-security-labels");
00365     if (no_unlogged_table_data)
00366         appendPQExpBuffer(pgdumpopts, " --no-unlogged-table-data");
00367 
00368     /*
00369      * If there was a database specified on the command line, use that,
00370      * otherwise try to connect to database "postgres", and failing that
00371      * "template1".  "postgres" is the preferred choice for 8.1 and later
00372      * servers, but it usually will not exist on older ones.
00373      */
00374     if (pgdb)
00375     {
00376         conn = connectDatabase(pgdb, connstr, pghost, pgport, pguser,
00377                                prompt_password, false);
00378 
00379         if (!conn)
00380         {
00381             fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
00382                     progname, pgdb);
00383             exit_nicely(1);
00384         }
00385     }
00386     else
00387     {
00388         conn = connectDatabase("postgres", connstr, pghost, pgport, pguser,
00389                                prompt_password, false);
00390         if (!conn)
00391             conn = connectDatabase("template1", connstr, pghost, pgport, pguser,
00392                                    prompt_password, true);
00393 
00394         if (!conn)
00395         {
00396             fprintf(stderr, _("%s: could not connect to databases \"postgres\" or \"template1\"\n"
00397                               "Please specify an alternative database.\n"),
00398                     progname);
00399             fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
00400                     progname);
00401             exit_nicely(1);
00402         }
00403     }
00404 
00405     /*
00406      * Open the output file if required, otherwise use stdout
00407      */
00408     if (filename)
00409     {
00410         OPF = fopen(filename, PG_BINARY_W);
00411         if (!OPF)
00412         {
00413             fprintf(stderr, _("%s: could not open the output file \"%s\": %s\n"),
00414                     progname, filename, strerror(errno));
00415             exit_nicely(1);
00416         }
00417     }
00418     else
00419         OPF = stdout;
00420 
00421     /*
00422      * Get the active encoding and the standard_conforming_strings setting, so
00423      * we know how to escape strings.
00424      */
00425     encoding = PQclientEncoding(conn);
00426     std_strings = PQparameterStatus(conn, "standard_conforming_strings");
00427     if (!std_strings)
00428         std_strings = "off";
00429 
00430     /* Set the role if requested */
00431     if (use_role && server_version >= 80100)
00432     {
00433         PQExpBuffer query = createPQExpBuffer();
00434 
00435         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
00436         executeCommand(conn, query->data);
00437         destroyPQExpBuffer(query);
00438     }
00439 
00440     /* Force quoting of all identifiers if requested. */
00441     if (quote_all_identifiers && server_version >= 90100)
00442         executeCommand(conn, "SET quote_all_identifiers = true");
00443 
00444     fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n");
00445     if (verbose)
00446         dumpTimestamp("Started on");
00447 
00448     /*
00449      * We used to emit \connect postgres here, but that served no purpose
00450      * other than to break things for installations without a postgres
00451      * database.  Everything we're restoring here is a global, so whichever
00452      * database we're connected to at the moment is fine.
00453      */
00454 
00455     /* Replicate encoding and std_strings in output */
00456     fprintf(OPF, "SET client_encoding = '%s';\n",
00457             pg_encoding_to_char(encoding));
00458     fprintf(OPF, "SET standard_conforming_strings = %s;\n", std_strings);
00459     if (strcmp(std_strings, "off") == 0)
00460         fprintf(OPF, "SET escape_string_warning = off;\n");
00461     fprintf(OPF, "\n");
00462 
00463     if (!data_only)
00464     {
00465         /*
00466          * If asked to --clean, do that first.  We can avoid detailed
00467          * dependency analysis because databases never depend on each other,
00468          * and tablespaces never depend on each other.  Roles could have
00469          * grants to each other, but DROP ROLE will clean those up silently.
00470          */
00471         if (output_clean)
00472         {
00473             if (!globals_only && !roles_only && !tablespaces_only)
00474                 dropDBs(conn);
00475 
00476             if (!roles_only && !no_tablespaces)
00477             {
00478                 if (server_version >= 80000)
00479                     dropTablespaces(conn);
00480             }
00481 
00482             if (!tablespaces_only)
00483                 dropRoles(conn);
00484         }
00485 
00486         /*
00487          * Now create objects as requested.  Be careful that option logic here
00488          * is the same as for drops above.
00489          */
00490         if (!tablespaces_only)
00491         {
00492             /* Dump roles (users) */
00493             dumpRoles(conn);
00494 
00495             /* Dump role memberships --- need different method for pre-8.1 */
00496             if (server_version >= 80100)
00497                 dumpRoleMembership(conn);
00498             else
00499                 dumpGroups(conn);
00500         }
00501 
00502         if (!roles_only && !no_tablespaces)
00503         {
00504             /* Dump tablespaces */
00505             if (server_version >= 80000)
00506                 dumpTablespaces(conn);
00507         }
00508 
00509         /* Dump CREATE DATABASE commands */
00510         if (binary_upgrade || (!globals_only && !roles_only && !tablespaces_only))
00511             dumpCreateDB(conn);
00512 
00513         /* Dump role/database settings */
00514         if (!tablespaces_only && !roles_only)
00515         {
00516             if (server_version >= 90000)
00517                 dumpDbRoleConfig(conn);
00518         }
00519     }
00520 
00521     if (!globals_only && !roles_only && !tablespaces_only)
00522         dumpDatabases(conn);
00523 
00524     PQfinish(conn);
00525 
00526     if (verbose)
00527         dumpTimestamp("Completed on");
00528     fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n");
00529 
00530     if (filename)
00531         fclose(OPF);
00532 
00533     exit_nicely(0);
00534 }
00535 
00536 
00537 static void
00538 help(void)
00539 {
00540     printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
00541     printf(_("Usage:\n"));
00542     printf(_("  %s [OPTION]...\n"), progname);
00543 
00544     printf(_("\nGeneral options:\n"));
00545     printf(_("  -f, --file=FILENAME          output file name\n"));
00546     printf(_("  -V, --version                output version information, then exit\n"));
00547     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
00548     printf(_("  -?, --help                   show this help, then exit\n"));
00549     printf(_("\nOptions controlling the output content:\n"));
00550     printf(_("  -a, --data-only              dump only the data, not the schema\n"));
00551     printf(_("  -c, --clean                  clean (drop) databases before recreating\n"));
00552     printf(_("  -g, --globals-only           dump only global objects, no databases\n"));
00553     printf(_("  -o, --oids                   include OIDs in dump\n"));
00554     printf(_("  -O, --no-owner               skip restoration of object ownership\n"));
00555     printf(_("  -r, --roles-only             dump only roles, no databases or tablespaces\n"));
00556     printf(_("  -s, --schema-only            dump only the schema, no data\n"));
00557     printf(_("  -S, --superuser=NAME         superuser user name to use in the dump\n"));
00558     printf(_("  -t, --tablespaces-only       dump only tablespaces, no databases or roles\n"));
00559     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
00560     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
00561     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
00562     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
00563     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
00564     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
00565     printf(_("  --no-security-labels         do not dump security label assignments\n"));
00566     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
00567     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
00568     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
00569     printf(_("  --use-set-session-authorization\n"
00570              "                               use SET SESSION AUTHORIZATION commands instead of\n"
00571              "                               ALTER OWNER commands to set ownership\n"));
00572 
00573     printf(_("\nConnection options:\n"));
00574     printf(_("  -d, --dbname=CONNSTR     connect using connection string\n"));
00575     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
00576     printf(_("  -l, --database=DBNAME    alternative default database\n"));
00577     printf(_("  -p, --port=PORT          database server port number\n"));
00578     printf(_("  -U, --username=NAME      connect as specified database user\n"));
00579     printf(_("  -w, --no-password        never prompt for password\n"));
00580     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
00581     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
00582 
00583     printf(_("\nIf -f/--file is not used, then the SQL script will be written to the standard\n"
00584              "output.\n\n"));
00585     printf(_("Report bugs to <[email protected]>.\n"));
00586 }
00587 
00588 
00589 /*
00590  * Drop roles
00591  */
00592 static void
00593 dropRoles(PGconn *conn)
00594 {
00595     PGresult   *res;
00596     int         i_rolname;
00597     int         i;
00598 
00599     if (server_version >= 80100)
00600         res = executeQuery(conn,
00601                            "SELECT rolname "
00602                            "FROM pg_authid "
00603                            "ORDER BY 1");
00604     else
00605         res = executeQuery(conn,
00606                            "SELECT usename as rolname "
00607                            "FROM pg_shadow "
00608                            "UNION "
00609                            "SELECT groname as rolname "
00610                            "FROM pg_group "
00611                            "ORDER BY 1");
00612 
00613     i_rolname = PQfnumber(res, "rolname");
00614 
00615     if (PQntuples(res) > 0)
00616         fprintf(OPF, "--\n-- Drop roles\n--\n\n");
00617 
00618     for (i = 0; i < PQntuples(res); i++)
00619     {
00620         const char *rolename;
00621 
00622         rolename = PQgetvalue(res, i, i_rolname);
00623 
00624         fprintf(OPF, "DROP ROLE %s;\n", fmtId(rolename));
00625     }
00626 
00627     PQclear(res);
00628 
00629     fprintf(OPF, "\n\n");
00630 }
00631 
00632 /*
00633  * Dump roles
00634  */
00635 static void
00636 dumpRoles(PGconn *conn)
00637 {
00638     PQExpBuffer buf = createPQExpBuffer();
00639     PGresult   *res;
00640     int         i_oid,
00641                 i_rolname,
00642                 i_rolsuper,
00643                 i_rolinherit,
00644                 i_rolcreaterole,
00645                 i_rolcreatedb,
00646                 i_rolcanlogin,
00647                 i_rolconnlimit,
00648                 i_rolpassword,
00649                 i_rolvaliduntil,
00650                 i_rolreplication,
00651                 i_rolcomment,
00652                 i_is_current_user;
00653     int         i;
00654 
00655     /* note: rolconfig is dumped later */
00656     if (server_version >= 90100)
00657         printfPQExpBuffer(buf,
00658                           "SELECT oid, rolname, rolsuper, rolinherit, "
00659                           "rolcreaterole, rolcreatedb, "
00660                           "rolcanlogin, rolconnlimit, rolpassword, "
00661                           "rolvaliduntil, rolreplication, "
00662              "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
00663                           "rolname = current_user AS is_current_user "
00664                           "FROM pg_authid "
00665                           "ORDER BY 2");
00666     else if (server_version >= 80200)
00667         printfPQExpBuffer(buf,
00668                           "SELECT oid, rolname, rolsuper, rolinherit, "
00669                           "rolcreaterole, rolcreatedb, "
00670                           "rolcanlogin, rolconnlimit, rolpassword, "
00671                           "rolvaliduntil, false as rolreplication, "
00672              "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
00673                           "rolname = current_user AS is_current_user "
00674                           "FROM pg_authid "
00675                           "ORDER BY 2");
00676     else if (server_version >= 80100)
00677         printfPQExpBuffer(buf,
00678                           "SELECT oid, rolname, rolsuper, rolinherit, "
00679                           "rolcreaterole, rolcreatedb, "
00680                           "rolcanlogin, rolconnlimit, rolpassword, "
00681                           "rolvaliduntil, false as rolreplication, "
00682                           "null as rolcomment, "
00683                           "rolname = current_user AS is_current_user "
00684                           "FROM pg_authid "
00685                           "ORDER BY 2");
00686     else
00687         printfPQExpBuffer(buf,
00688                           "SELECT 0, usename as rolname, "
00689                           "usesuper as rolsuper, "
00690                           "true as rolinherit, "
00691                           "usesuper as rolcreaterole, "
00692                           "usecreatedb as rolcreatedb, "
00693                           "true as rolcanlogin, "
00694                           "-1 as rolconnlimit, "
00695                           "passwd as rolpassword, "
00696                           "valuntil as rolvaliduntil, "
00697                           "false as rolreplication, "
00698                           "null as rolcomment, "
00699                           "rolname = current_user AS is_current_user "
00700                           "FROM pg_shadow "
00701                           "UNION ALL "
00702                           "SELECT 0, groname as rolname, "
00703                           "false as rolsuper, "
00704                           "true as rolinherit, "
00705                           "false as rolcreaterole, "
00706                           "false as rolcreatedb, "
00707                           "false as rolcanlogin, "
00708                           "-1 as rolconnlimit, "
00709                           "null::text as rolpassword, "
00710                           "null::abstime as rolvaliduntil, "
00711                           "false as rolreplication, "
00712                           "null as rolcomment, false "
00713                           "FROM pg_group "
00714                           "WHERE NOT EXISTS (SELECT 1 FROM pg_shadow "
00715                           " WHERE usename = groname) "
00716                           "ORDER BY 2");
00717 
00718     res = executeQuery(conn, buf->data);
00719 
00720     i_oid = PQfnumber(res, "oid");
00721     i_rolname = PQfnumber(res, "rolname");
00722     i_rolsuper = PQfnumber(res, "rolsuper");
00723     i_rolinherit = PQfnumber(res, "rolinherit");
00724     i_rolcreaterole = PQfnumber(res, "rolcreaterole");
00725     i_rolcreatedb = PQfnumber(res, "rolcreatedb");
00726     i_rolcanlogin = PQfnumber(res, "rolcanlogin");
00727     i_rolconnlimit = PQfnumber(res, "rolconnlimit");
00728     i_rolpassword = PQfnumber(res, "rolpassword");
00729     i_rolvaliduntil = PQfnumber(res, "rolvaliduntil");
00730     i_rolreplication = PQfnumber(res, "rolreplication");
00731     i_rolcomment = PQfnumber(res, "rolcomment");
00732     i_is_current_user = PQfnumber(res, "is_current_user");
00733 
00734     if (PQntuples(res) > 0)
00735         fprintf(OPF, "--\n-- Roles\n--\n\n");
00736 
00737     for (i = 0; i < PQntuples(res); i++)
00738     {
00739         const char *rolename;
00740         Oid         auth_oid;
00741 
00742         auth_oid = atooid(PQgetvalue(res, i, i_oid));
00743         rolename = PQgetvalue(res, i, i_rolname);
00744 
00745         resetPQExpBuffer(buf);
00746 
00747         if (binary_upgrade)
00748         {
00749             appendPQExpBuffer(buf, "\n-- For binary upgrade, must preserve pg_authid.oid\n");
00750             appendPQExpBuffer(buf,
00751                               "SELECT binary_upgrade.set_next_pg_authid_oid('%u'::pg_catalog.oid);\n\n",
00752                               auth_oid);
00753         }
00754 
00755         /*
00756          * We dump CREATE ROLE followed by ALTER ROLE to ensure that the role
00757          * will acquire the right properties even if it already exists (ie, it
00758          * won't hurt for the CREATE to fail).  This is particularly important
00759          * for the role we are connected as, since even with --clean we will
00760          * have failed to drop it.  binary_upgrade cannot generate any errors,
00761          * so we assume the current role is already created.
00762          */
00763         if (!binary_upgrade ||
00764             strcmp(PQgetvalue(res, i, i_is_current_user), "f") == 0)
00765             appendPQExpBuffer(buf, "CREATE ROLE %s;\n", fmtId(rolename));
00766         appendPQExpBuffer(buf, "ALTER ROLE %s WITH", fmtId(rolename));
00767 
00768         if (strcmp(PQgetvalue(res, i, i_rolsuper), "t") == 0)
00769             appendPQExpBuffer(buf, " SUPERUSER");
00770         else
00771             appendPQExpBuffer(buf, " NOSUPERUSER");
00772 
00773         if (strcmp(PQgetvalue(res, i, i_rolinherit), "t") == 0)
00774             appendPQExpBuffer(buf, " INHERIT");
00775         else
00776             appendPQExpBuffer(buf, " NOINHERIT");
00777 
00778         if (strcmp(PQgetvalue(res, i, i_rolcreaterole), "t") == 0)
00779             appendPQExpBuffer(buf, " CREATEROLE");
00780         else
00781             appendPQExpBuffer(buf, " NOCREATEROLE");
00782 
00783         if (strcmp(PQgetvalue(res, i, i_rolcreatedb), "t") == 0)
00784             appendPQExpBuffer(buf, " CREATEDB");
00785         else
00786             appendPQExpBuffer(buf, " NOCREATEDB");
00787 
00788         if (strcmp(PQgetvalue(res, i, i_rolcanlogin), "t") == 0)
00789             appendPQExpBuffer(buf, " LOGIN");
00790         else
00791             appendPQExpBuffer(buf, " NOLOGIN");
00792 
00793         if (strcmp(PQgetvalue(res, i, i_rolreplication), "t") == 0)
00794             appendPQExpBuffer(buf, " REPLICATION");
00795         else
00796             appendPQExpBuffer(buf, " NOREPLICATION");
00797 
00798         if (strcmp(PQgetvalue(res, i, i_rolconnlimit), "-1") != 0)
00799             appendPQExpBuffer(buf, " CONNECTION LIMIT %s",
00800                               PQgetvalue(res, i, i_rolconnlimit));
00801 
00802         if (!PQgetisnull(res, i, i_rolpassword))
00803         {
00804             appendPQExpBuffer(buf, " PASSWORD ");
00805             appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolpassword), conn);
00806         }
00807 
00808         if (!PQgetisnull(res, i, i_rolvaliduntil))
00809             appendPQExpBuffer(buf, " VALID UNTIL '%s'",
00810                               PQgetvalue(res, i, i_rolvaliduntil));
00811 
00812         appendPQExpBuffer(buf, ";\n");
00813 
00814         if (!PQgetisnull(res, i, i_rolcomment))
00815         {
00816             appendPQExpBuffer(buf, "COMMENT ON ROLE %s IS ", fmtId(rolename));
00817             appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolcomment), conn);
00818             appendPQExpBuffer(buf, ";\n");
00819         }
00820 
00821         if (!no_security_labels && server_version >= 90200)
00822             buildShSecLabels(conn, "pg_authid", auth_oid,
00823                              buf, "ROLE", rolename);
00824 
00825         fprintf(OPF, "%s", buf->data);
00826     }
00827 
00828     /*
00829      * Dump configuration settings for roles after all roles have been dumped.
00830      * We do it this way because config settings for roles could mention the
00831      * names of other roles.
00832      */
00833     if (server_version >= 70300)
00834         for (i = 0; i < PQntuples(res); i++)
00835             dumpUserConfig(conn, PQgetvalue(res, i, i_rolname));
00836 
00837     PQclear(res);
00838 
00839     fprintf(OPF, "\n\n");
00840 
00841     destroyPQExpBuffer(buf);
00842 }
00843 
00844 
00845 /*
00846  * Dump role memberships.  This code is used for 8.1 and later servers.
00847  *
00848  * Note: we expect dumpRoles already created all the roles, but there is
00849  * no membership yet.
00850  */
00851 static void
00852 dumpRoleMembership(PGconn *conn)
00853 {
00854     PGresult   *res;
00855     int         i;
00856 
00857     res = executeQuery(conn, "SELECT ur.rolname AS roleid, "
00858                        "um.rolname AS member, "
00859                        "a.admin_option, "
00860                        "ug.rolname AS grantor "
00861                        "FROM pg_auth_members a "
00862                        "LEFT JOIN pg_authid ur on ur.oid = a.roleid "
00863                        "LEFT JOIN pg_authid um on um.oid = a.member "
00864                        "LEFT JOIN pg_authid ug on ug.oid = a.grantor "
00865                        "ORDER BY 1,2,3");
00866 
00867     if (PQntuples(res) > 0)
00868         fprintf(OPF, "--\n-- Role memberships\n--\n\n");
00869 
00870     for (i = 0; i < PQntuples(res); i++)
00871     {
00872         char       *roleid = PQgetvalue(res, i, 0);
00873         char       *member = PQgetvalue(res, i, 1);
00874         char       *option = PQgetvalue(res, i, 2);
00875 
00876         fprintf(OPF, "GRANT %s", fmtId(roleid));
00877         fprintf(OPF, " TO %s", fmtId(member));
00878         if (*option == 't')
00879             fprintf(OPF, " WITH ADMIN OPTION");
00880 
00881         /*
00882          * We don't track the grantor very carefully in the backend, so cope
00883          * with the possibility that it has been dropped.
00884          */
00885         if (!PQgetisnull(res, i, 3))
00886         {
00887             char       *grantor = PQgetvalue(res, i, 3);
00888 
00889             fprintf(OPF, " GRANTED BY %s", fmtId(grantor));
00890         }
00891         fprintf(OPF, ";\n");
00892     }
00893 
00894     PQclear(res);
00895 
00896     fprintf(OPF, "\n\n");
00897 }
00898 
00899 /*
00900  * Dump group memberships from a pre-8.1 server.  It's annoying that we
00901  * can't share any useful amount of code with the post-8.1 case, but
00902  * the catalog representations are too different.
00903  *
00904  * Note: we expect dumpRoles already created all the roles, but there is
00905  * no membership yet.
00906  */
00907 static void
00908 dumpGroups(PGconn *conn)
00909 {
00910     PQExpBuffer buf = createPQExpBuffer();
00911     PGresult   *res;
00912     int         i;
00913 
00914     res = executeQuery(conn,
00915                        "SELECT groname, grolist FROM pg_group ORDER BY 1");
00916 
00917     if (PQntuples(res) > 0)
00918         fprintf(OPF, "--\n-- Role memberships\n--\n\n");
00919 
00920     for (i = 0; i < PQntuples(res); i++)
00921     {
00922         char       *groname = PQgetvalue(res, i, 0);
00923         char       *grolist = PQgetvalue(res, i, 1);
00924         PGresult   *res2;
00925         int         j;
00926 
00927         /*
00928          * Array representation is {1,2,3} ... convert to (1,2,3)
00929          */
00930         if (strlen(grolist) < 3)
00931             continue;
00932 
00933         grolist = pg_strdup(grolist);
00934         grolist[0] = '(';
00935         grolist[strlen(grolist) - 1] = ')';
00936         printfPQExpBuffer(buf,
00937                           "SELECT usename FROM pg_shadow "
00938                           "WHERE usesysid IN %s ORDER BY 1",
00939                           grolist);
00940         free(grolist);
00941 
00942         res2 = executeQuery(conn, buf->data);
00943 
00944         for (j = 0; j < PQntuples(res2); j++)
00945         {
00946             char       *usename = PQgetvalue(res2, j, 0);
00947 
00948             /*
00949              * Don't try to grant a role to itself; can happen if old
00950              * installation has identically named user and group.
00951              */
00952             if (strcmp(groname, usename) == 0)
00953                 continue;
00954 
00955             fprintf(OPF, "GRANT %s", fmtId(groname));
00956             fprintf(OPF, " TO %s;\n", fmtId(usename));
00957         }
00958 
00959         PQclear(res2);
00960     }
00961 
00962     PQclear(res);
00963     destroyPQExpBuffer(buf);
00964 
00965     fprintf(OPF, "\n\n");
00966 }
00967 
00968 
00969 /*
00970  * Drop tablespaces.
00971  */
00972 static void
00973 dropTablespaces(PGconn *conn)
00974 {
00975     PGresult   *res;
00976     int         i;
00977 
00978     /*
00979      * Get all tablespaces except built-in ones (which we assume are named
00980      * pg_xxx)
00981      */
00982     res = executeQuery(conn, "SELECT spcname "
00983                        "FROM pg_catalog.pg_tablespace "
00984                        "WHERE spcname !~ '^pg_' "
00985                        "ORDER BY 1");
00986 
00987     if (PQntuples(res) > 0)
00988         fprintf(OPF, "--\n-- Drop tablespaces\n--\n\n");
00989 
00990     for (i = 0; i < PQntuples(res); i++)
00991     {
00992         char       *spcname = PQgetvalue(res, i, 0);
00993 
00994         fprintf(OPF, "DROP TABLESPACE %s;\n", fmtId(spcname));
00995     }
00996 
00997     PQclear(res);
00998 
00999     fprintf(OPF, "\n\n");
01000 }
01001 
01002 /*
01003  * Dump tablespaces.
01004  */
01005 static void
01006 dumpTablespaces(PGconn *conn)
01007 {
01008     PGresult   *res;
01009     int         i;
01010 
01011     /*
01012      * Get all tablespaces except built-in ones (which we assume are named
01013      * pg_xxx)
01014      */
01015     if (server_version >= 90200)
01016         res = executeQuery(conn, "SELECT oid, spcname, "
01017                          "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
01018                            "pg_catalog.pg_tablespace_location(oid), spcacl, "
01019                            "array_to_string(spcoptions, ', '),"
01020                         "pg_catalog.shobj_description(oid, 'pg_tablespace') "
01021                            "FROM pg_catalog.pg_tablespace "
01022                            "WHERE spcname !~ '^pg_' "
01023                            "ORDER BY 1");
01024     else if (server_version >= 90000)
01025         res = executeQuery(conn, "SELECT oid, spcname, "
01026                          "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
01027                            "spclocation, spcacl, "
01028                            "array_to_string(spcoptions, ', '),"
01029                         "pg_catalog.shobj_description(oid, 'pg_tablespace') "
01030                            "FROM pg_catalog.pg_tablespace "
01031                            "WHERE spcname !~ '^pg_' "
01032                            "ORDER BY 1");
01033     else if (server_version >= 80200)
01034         res = executeQuery(conn, "SELECT oid, spcname, "
01035                          "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
01036                            "spclocation, spcacl, null, "
01037                         "pg_catalog.shobj_description(oid, 'pg_tablespace') "
01038                            "FROM pg_catalog.pg_tablespace "
01039                            "WHERE spcname !~ '^pg_' "
01040                            "ORDER BY 1");
01041     else
01042         res = executeQuery(conn, "SELECT oid, spcname, "
01043                          "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
01044                            "spclocation, spcacl, "
01045                            "null, null "
01046                            "FROM pg_catalog.pg_tablespace "
01047                            "WHERE spcname !~ '^pg_' "
01048                            "ORDER BY 1");
01049 
01050     if (PQntuples(res) > 0)
01051         fprintf(OPF, "--\n-- Tablespaces\n--\n\n");
01052 
01053     for (i = 0; i < PQntuples(res); i++)
01054     {
01055         PQExpBuffer buf = createPQExpBuffer();
01056         uint32      spcoid = atooid(PQgetvalue(res, i, 0));
01057         char       *spcname = PQgetvalue(res, i, 1);
01058         char       *spcowner = PQgetvalue(res, i, 2);
01059         char       *spclocation = PQgetvalue(res, i, 3);
01060         char       *spcacl = PQgetvalue(res, i, 4);
01061         char       *spcoptions = PQgetvalue(res, i, 5);
01062         char       *spccomment = PQgetvalue(res, i, 6);
01063         char       *fspcname;
01064 
01065         /* needed for buildACLCommands() */
01066         fspcname = pg_strdup(fmtId(spcname));
01067 
01068         appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
01069         appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
01070 
01071         appendPQExpBuffer(buf, " LOCATION ");
01072         appendStringLiteralConn(buf, spclocation, conn);
01073         appendPQExpBuffer(buf, ";\n");
01074 
01075         if (spcoptions && spcoptions[0] != '\0')
01076             appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n",
01077                               fspcname, spcoptions);
01078 
01079         if (!skip_acls &&
01080             !buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner,
01081                               "", server_version, buf))
01082         {
01083             fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
01084                     progname, spcacl, fspcname);
01085             PQfinish(conn);
01086             exit_nicely(1);
01087         }
01088 
01089         if (spccomment && strlen(spccomment))
01090         {
01091             appendPQExpBuffer(buf, "COMMENT ON TABLESPACE %s IS ", fspcname);
01092             appendStringLiteralConn(buf, spccomment, conn);
01093             appendPQExpBuffer(buf, ";\n");
01094         }
01095 
01096         if (!no_security_labels && server_version >= 90200)
01097             buildShSecLabels(conn, "pg_tablespace", spcoid,
01098                              buf, "TABLESPACE", fspcname);
01099 
01100         fprintf(OPF, "%s", buf->data);
01101 
01102         free(fspcname);
01103         destroyPQExpBuffer(buf);
01104     }
01105 
01106     PQclear(res);
01107     fprintf(OPF, "\n\n");
01108 }
01109 
01110 
01111 /*
01112  * Dump commands to drop each database.
01113  *
01114  * This should match the set of databases targeted by dumpCreateDB().
01115  */
01116 static void
01117 dropDBs(PGconn *conn)
01118 {
01119     PGresult   *res;
01120     int         i;
01121 
01122     if (server_version >= 70100)
01123         res = executeQuery(conn,
01124                            "SELECT datname "
01125                            "FROM pg_database d "
01126                            "WHERE datallowconn ORDER BY 1");
01127     else
01128         res = executeQuery(conn,
01129                            "SELECT datname "
01130                            "FROM pg_database d "
01131                            "ORDER BY 1");
01132 
01133     if (PQntuples(res) > 0)
01134         fprintf(OPF, "--\n-- Drop databases\n--\n\n");
01135 
01136     for (i = 0; i < PQntuples(res); i++)
01137     {
01138         char       *dbname = PQgetvalue(res, i, 0);
01139 
01140         /*
01141          * Skip "template1" and "postgres"; the restore script is almost
01142          * certainly going to be run in one or the other, and we don't know
01143          * which.  This must agree with dumpCreateDB's choices!
01144          */
01145         if (strcmp(dbname, "template1") != 0 &&
01146             strcmp(dbname, "postgres") != 0)
01147         {
01148             fprintf(OPF, "DROP DATABASE %s;\n", fmtId(dbname));
01149         }
01150     }
01151 
01152     PQclear(res);
01153 
01154     fprintf(OPF, "\n\n");
01155 }
01156 
01157 /*
01158  * Dump commands to create each database.
01159  *
01160  * To minimize the number of reconnections (and possibly ensuing
01161  * password prompts) required by the output script, we emit all CREATE
01162  * DATABASE commands during the initial phase of the script, and then
01163  * run pg_dump for each database to dump the contents of that
01164  * database.  We skip databases marked not datallowconn, since we'd be
01165  * unable to connect to them anyway (and besides, we don't want to
01166  * dump template0).
01167  */
01168 static void
01169 dumpCreateDB(PGconn *conn)
01170 {
01171     PQExpBuffer buf = createPQExpBuffer();
01172     char       *default_encoding = NULL;
01173     char       *default_collate = NULL;
01174     char       *default_ctype = NULL;
01175     PGresult   *res;
01176     int         i;
01177 
01178     fprintf(OPF, "--\n-- Database creation\n--\n\n");
01179 
01180     /*
01181      * First, get the installation's default encoding and locale information.
01182      * We will dump encoding and locale specifications in the CREATE DATABASE
01183      * commands for just those databases with values different from defaults.
01184      *
01185      * We consider template0's encoding and locale (or, pre-7.1, template1's)
01186      * to define the installation default.  Pre-8.4 installations do not have
01187      * per-database locale settings; for them, every database must necessarily
01188      * be using the installation default, so there's no need to do anything
01189      * (which is good, since in very old versions there is no good way to find
01190      * out what the installation locale is anyway...)
01191      */
01192     if (server_version >= 80400)
01193         res = executeQuery(conn,
01194                            "SELECT pg_encoding_to_char(encoding), "
01195                            "datcollate, datctype "
01196                            "FROM pg_database "
01197                            "WHERE datname = 'template0'");
01198     else if (server_version >= 70100)
01199         res = executeQuery(conn,
01200                            "SELECT pg_encoding_to_char(encoding), "
01201                            "null::text AS datcollate, null::text AS datctype "
01202                            "FROM pg_database "
01203                            "WHERE datname = 'template0'");
01204     else
01205         res = executeQuery(conn,
01206                            "SELECT pg_encoding_to_char(encoding), "
01207                            "null::text AS datcollate, null::text AS datctype "
01208                            "FROM pg_database "
01209                            "WHERE datname = 'template1'");
01210 
01211     /* If for some reason the template DB isn't there, treat as unknown */
01212     if (PQntuples(res) > 0)
01213     {
01214         if (!PQgetisnull(res, 0, 0))
01215             default_encoding = pg_strdup(PQgetvalue(res, 0, 0));
01216         if (!PQgetisnull(res, 0, 1))
01217             default_collate = pg_strdup(PQgetvalue(res, 0, 1));
01218         if (!PQgetisnull(res, 0, 2))
01219             default_ctype = pg_strdup(PQgetvalue(res, 0, 2));
01220     }
01221 
01222     PQclear(res);
01223 
01224     /* Now collect all the information about databases to dump */
01225     if (server_version >= 80400)
01226         res = executeQuery(conn,
01227                            "SELECT datname, "
01228                            "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
01229                            "pg_encoding_to_char(d.encoding), "
01230                            "datcollate, datctype, datfrozenxid, "
01231                            "datistemplate, datacl, datconnlimit, "
01232                            "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
01233               "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
01234                            "WHERE datallowconn ORDER BY 1");
01235     else if (server_version >= 80100)
01236         res = executeQuery(conn,
01237                            "SELECT datname, "
01238                            "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
01239                            "pg_encoding_to_char(d.encoding), "
01240            "null::text AS datcollate, null::text AS datctype, datfrozenxid, "
01241                            "datistemplate, datacl, datconnlimit, "
01242                            "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
01243               "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
01244                            "WHERE datallowconn ORDER BY 1");
01245     else if (server_version >= 80000)
01246         res = executeQuery(conn,
01247                            "SELECT datname, "
01248                            "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
01249                            "pg_encoding_to_char(d.encoding), "
01250            "null::text AS datcollate, null::text AS datctype, datfrozenxid, "
01251                            "datistemplate, datacl, -1 as datconnlimit, "
01252                            "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
01253            "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
01254                            "WHERE datallowconn ORDER BY 1");
01255     else if (server_version >= 70300)
01256         res = executeQuery(conn,
01257                            "SELECT datname, "
01258                            "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
01259                            "pg_encoding_to_char(d.encoding), "
01260            "null::text AS datcollate, null::text AS datctype, datfrozenxid, "
01261                            "datistemplate, datacl, -1 as datconnlimit, "
01262                            "'pg_default' AS dattablespace "
01263            "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
01264                            "WHERE datallowconn ORDER BY 1");
01265     else if (server_version >= 70100)
01266         res = executeQuery(conn,
01267                            "SELECT datname, "
01268                            "coalesce("
01269                     "(select usename from pg_shadow where usesysid=datdba), "
01270                            "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
01271                            "pg_encoding_to_char(d.encoding), "
01272                            "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, "
01273                            "datistemplate, '' as datacl, -1 as datconnlimit, "
01274                            "'pg_default' AS dattablespace "
01275                            "FROM pg_database d "
01276                            "WHERE datallowconn ORDER BY 1");
01277     else
01278     {
01279         /*
01280          * Note: 7.0 fails to cope with sub-select in COALESCE, so just deal
01281          * with getting a NULL by not printing any OWNER clause.
01282          */
01283         res = executeQuery(conn,
01284                            "SELECT datname, "
01285                     "(select usename from pg_shadow where usesysid=datdba), "
01286                            "pg_encoding_to_char(d.encoding), "
01287                            "null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, "
01288                            "'f' as datistemplate, "
01289                            "'' as datacl, -1 as datconnlimit, "
01290                            "'pg_default' AS dattablespace "
01291                            "FROM pg_database d "
01292                            "ORDER BY 1");
01293     }
01294 
01295     for (i = 0; i < PQntuples(res); i++)
01296     {
01297         char       *dbname = PQgetvalue(res, i, 0);
01298         char       *dbowner = PQgetvalue(res, i, 1);
01299         char       *dbencoding = PQgetvalue(res, i, 2);
01300         char       *dbcollate = PQgetvalue(res, i, 3);
01301         char       *dbctype = PQgetvalue(res, i, 4);
01302         uint32      dbfrozenxid = atooid(PQgetvalue(res, i, 5));
01303         char       *dbistemplate = PQgetvalue(res, i, 6);
01304         char       *dbacl = PQgetvalue(res, i, 7);
01305         char       *dbconnlimit = PQgetvalue(res, i, 8);
01306         char       *dbtablespace = PQgetvalue(res, i, 9);
01307         char       *fdbname;
01308 
01309         fdbname = pg_strdup(fmtId(dbname));
01310 
01311         resetPQExpBuffer(buf);
01312 
01313         /*
01314          * Skip the CREATE DATABASE commands for "template1" and "postgres",
01315          * since they are presumably already there in the destination cluster.
01316          * We do want to emit their ACLs and config options if any, however.
01317          */
01318         if (strcmp(dbname, "template1") != 0 &&
01319             strcmp(dbname, "postgres") != 0)
01320         {
01321             appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
01322 
01323             appendPQExpBuffer(buf, " WITH TEMPLATE = template0");
01324 
01325             if (strlen(dbowner) != 0)
01326                 appendPQExpBuffer(buf, " OWNER = %s", fmtId(dbowner));
01327 
01328             if (default_encoding && strcmp(dbencoding, default_encoding) != 0)
01329             {
01330                 appendPQExpBuffer(buf, " ENCODING = ");
01331                 appendStringLiteralConn(buf, dbencoding, conn);
01332             }
01333 
01334             if (default_collate && strcmp(dbcollate, default_collate) != 0)
01335             {
01336                 appendPQExpBuffer(buf, " LC_COLLATE = ");
01337                 appendStringLiteralConn(buf, dbcollate, conn);
01338             }
01339 
01340             if (default_ctype && strcmp(dbctype, default_ctype) != 0)
01341             {
01342                 appendPQExpBuffer(buf, " LC_CTYPE = ");
01343                 appendStringLiteralConn(buf, dbctype, conn);
01344             }
01345 
01346             /*
01347              * Output tablespace if it isn't the default.  For default, it
01348              * uses the default from the template database.  If tablespace is
01349              * specified and tablespace creation failed earlier, (e.g. no such
01350              * directory), the database creation will fail too.  One solution
01351              * would be to use 'SET default_tablespace' like we do in pg_dump
01352              * for setting non-default database locations.
01353              */
01354             if (strcmp(dbtablespace, "pg_default") != 0 && !no_tablespaces)
01355                 appendPQExpBuffer(buf, " TABLESPACE = %s",
01356                                   fmtId(dbtablespace));
01357 
01358             if (strcmp(dbconnlimit, "-1") != 0)
01359                 appendPQExpBuffer(buf, " CONNECTION LIMIT = %s",
01360                                   dbconnlimit);
01361 
01362             appendPQExpBuffer(buf, ";\n");
01363 
01364             if (strcmp(dbistemplate, "t") == 0)
01365             {
01366                 appendPQExpBuffer(buf, "UPDATE pg_catalog.pg_database SET datistemplate = 't' WHERE datname = ");
01367                 appendStringLiteralConn(buf, dbname, conn);
01368                 appendPQExpBuffer(buf, ";\n");
01369             }
01370 
01371             if (binary_upgrade)
01372             {
01373                 appendPQExpBuffer(buf, "-- For binary upgrade, set datfrozenxid.\n");
01374                 appendPQExpBuffer(buf, "UPDATE pg_catalog.pg_database "
01375                                   "SET datfrozenxid = '%u' "
01376                                   "WHERE datname = ",
01377                                   dbfrozenxid);
01378                 appendStringLiteralConn(buf, dbname, conn);
01379                 appendPQExpBuffer(buf, ";\n");
01380             }
01381         }
01382 
01383         if (!skip_acls &&
01384             !buildACLCommands(fdbname, NULL, "DATABASE", dbacl, dbowner,
01385                               "", server_version, buf))
01386         {
01387             fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
01388                     progname, dbacl, fdbname);
01389             PQfinish(conn);
01390             exit_nicely(1);
01391         }
01392 
01393         fprintf(OPF, "%s", buf->data);
01394 
01395         if (server_version >= 70300)
01396             dumpDatabaseConfig(conn, dbname);
01397 
01398         free(fdbname);
01399     }
01400 
01401     PQclear(res);
01402     destroyPQExpBuffer(buf);
01403 
01404     fprintf(OPF, "\n\n");
01405 }
01406 
01407 
01408 /*
01409  * Dump database-specific configuration
01410  */
01411 static void
01412 dumpDatabaseConfig(PGconn *conn, const char *dbname)
01413 {
01414     PQExpBuffer buf = createPQExpBuffer();
01415     int         count = 1;
01416 
01417     for (;;)
01418     {
01419         PGresult   *res;
01420 
01421         if (server_version >= 90000)
01422             printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting WHERE "
01423                               "setrole = 0 AND setdatabase = (SELECT oid FROM pg_database WHERE datname = ", count);
01424         else
01425             printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
01426         appendStringLiteralConn(buf, dbname, conn);
01427 
01428         if (server_version >= 90000)
01429             appendPQExpBuffer(buf, ")");
01430 
01431         appendPQExpBuffer(buf, ";");
01432 
01433         res = executeQuery(conn, buf->data);
01434         if (PQntuples(res) == 1 &&
01435             !PQgetisnull(res, 0, 0))
01436         {
01437             makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
01438                                    "DATABASE", dbname, NULL, NULL);
01439             PQclear(res);
01440             count++;
01441         }
01442         else
01443         {
01444             PQclear(res);
01445             break;
01446         }
01447     }
01448 
01449     destroyPQExpBuffer(buf);
01450 }
01451 
01452 
01453 
01454 /*
01455  * Dump user-specific configuration
01456  */
01457 static void
01458 dumpUserConfig(PGconn *conn, const char *username)
01459 {
01460     PQExpBuffer buf = createPQExpBuffer();
01461     int         count = 1;
01462 
01463     for (;;)
01464     {
01465         PGresult   *res;
01466 
01467         if (server_version >= 90000)
01468             printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting WHERE "
01469                               "setdatabase = 0 AND setrole = "
01470                        "(SELECT oid FROM pg_authid WHERE rolname = ", count);
01471         else if (server_version >= 80100)
01472             printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM pg_authid WHERE rolname = ", count);
01473         else
01474             printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
01475         appendStringLiteralConn(buf, username, conn);
01476         if (server_version >= 90000)
01477             appendPQExpBuffer(buf, ")");
01478 
01479         res = executeQuery(conn, buf->data);
01480         if (PQntuples(res) == 1 &&
01481             !PQgetisnull(res, 0, 0))
01482         {
01483             makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
01484                                    "ROLE", username, NULL, NULL);
01485             PQclear(res);
01486             count++;
01487         }
01488         else
01489         {
01490             PQclear(res);
01491             break;
01492         }
01493     }
01494 
01495     destroyPQExpBuffer(buf);
01496 }
01497 
01498 
01499 /*
01500  * Dump user-and-database-specific configuration
01501  */
01502 static void
01503 dumpDbRoleConfig(PGconn *conn)
01504 {
01505     PQExpBuffer buf = createPQExpBuffer();
01506     PGresult   *res;
01507     int         i;
01508 
01509     printfPQExpBuffer(buf, "SELECT rolname, datname, unnest(setconfig) "
01510                       "FROM pg_db_role_setting, pg_authid, pg_database "
01511           "WHERE setrole = pg_authid.oid AND setdatabase = pg_database.oid");
01512     res = executeQuery(conn, buf->data);
01513 
01514     if (PQntuples(res) > 0)
01515     {
01516         fprintf(OPF, "--\n-- Per-Database Role Settings \n--\n\n");
01517 
01518         for (i = 0; i < PQntuples(res); i++)
01519         {
01520             makeAlterConfigCommand(conn, PQgetvalue(res, i, 2),
01521                                    "ROLE", PQgetvalue(res, i, 0),
01522                                    "DATABASE", PQgetvalue(res, i, 1));
01523         }
01524 
01525         fprintf(OPF, "\n\n");
01526     }
01527 
01528     PQclear(res);
01529     destroyPQExpBuffer(buf);
01530 }
01531 
01532 
01533 /*
01534  * Helper function for dumpXXXConfig().
01535  */
01536 static void
01537 makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
01538                        const char *type, const char *name,
01539                        const char *type2, const char *name2)
01540 {
01541     char       *pos;
01542     char       *mine;
01543     PQExpBuffer buf;
01544 
01545     mine = pg_strdup(arrayitem);
01546     pos = strchr(mine, '=');
01547     if (pos == NULL)
01548     {
01549         free(mine);
01550         return;
01551     }
01552 
01553     buf = createPQExpBuffer();
01554 
01555     *pos = 0;
01556     appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
01557     if (type2 != NULL && name2 != NULL)
01558         appendPQExpBuffer(buf, "IN %s %s ", type2, fmtId(name2));
01559     appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
01560 
01561     /*
01562      * Some GUC variable names are 'LIST' type and hence must not be quoted.
01563      */
01564     if (pg_strcasecmp(mine, "DateStyle") == 0
01565         || pg_strcasecmp(mine, "search_path") == 0)
01566         appendPQExpBuffer(buf, "%s", pos + 1);
01567     else
01568         appendStringLiteralConn(buf, pos + 1, conn);
01569     appendPQExpBuffer(buf, ";\n");
01570 
01571     fprintf(OPF, "%s", buf->data);
01572     destroyPQExpBuffer(buf);
01573     free(mine);
01574 }
01575 
01576 
01577 
01578 /*
01579  * Dump contents of databases.
01580  */
01581 static void
01582 dumpDatabases(PGconn *conn)
01583 {
01584     PGresult   *res;
01585     int         i;
01586 
01587     if (server_version >= 70100)
01588         res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1");
01589     else
01590         res = executeQuery(conn, "SELECT datname FROM pg_database ORDER BY 1");
01591 
01592     for (i = 0; i < PQntuples(res); i++)
01593     {
01594         int         ret;
01595 
01596         char       *dbname = PQgetvalue(res, i, 0);
01597 
01598         if (verbose)
01599             fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
01600 
01601         fprintf(OPF, "\\connect %s\n\n", fmtId(dbname));
01602 
01603         if (filename)
01604             fclose(OPF);
01605 
01606         ret = runPgDump(dbname);
01607         if (ret != 0)
01608         {
01609             fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname);
01610             exit_nicely(1);
01611         }
01612 
01613         if (filename)
01614         {
01615             OPF = fopen(filename, PG_BINARY_A);
01616             if (!OPF)
01617             {
01618                 fprintf(stderr, _("%s: could not re-open the output file \"%s\": %s\n"),
01619                         progname, filename, strerror(errno));
01620                 exit_nicely(1);
01621             }
01622         }
01623 
01624     }
01625 
01626     PQclear(res);
01627 }
01628 
01629 
01630 
01631 /*
01632  * Run pg_dump on dbname.
01633  */
01634 static int
01635 runPgDump(const char *dbname)
01636 {
01637     PQExpBuffer connstrbuf = createPQExpBuffer();
01638     PQExpBuffer cmd = createPQExpBuffer();
01639     int         ret;
01640 
01641     appendPQExpBuffer(cmd, SYSTEMQUOTE "\"%s\" %s", pg_dump_bin,
01642                       pgdumpopts->data);
01643 
01644     /*
01645      * If we have a filename, use the undocumented plain-append pg_dump
01646      * format.
01647      */
01648     if (filename)
01649         appendPQExpBuffer(cmd, " -Fa ");
01650     else
01651         appendPQExpBuffer(cmd, " -Fp ");
01652 
01653     /*
01654      * Append the database name to the already-constructed stem of connection
01655      * string.
01656      */
01657     appendPQExpBuffer(connstrbuf, "%s dbname=", connstr);
01658     doConnStrQuoting(connstrbuf, dbname);
01659 
01660     doShellQuoting(cmd, connstrbuf->data);
01661 
01662     appendPQExpBuffer(cmd, "%s", SYSTEMQUOTE);
01663 
01664     if (verbose)
01665         fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
01666 
01667     fflush(stdout);
01668     fflush(stderr);
01669 
01670     ret = system(cmd->data);
01671 
01672     destroyPQExpBuffer(cmd);
01673     destroyPQExpBuffer(connstrbuf);
01674 
01675     return ret;
01676 }
01677 
01678 /*
01679  * buildShSecLabels
01680  *
01681  * Build SECURITY LABEL command(s) for an shared object
01682  *
01683  * The caller has to provide object type and identifier to select security
01684  * labels from pg_seclabels system view.
01685  */
01686 static void
01687 buildShSecLabels(PGconn *conn, const char *catalog_name, uint32 objectId,
01688                  PQExpBuffer buffer, const char *target, const char *objname)
01689 {
01690     PQExpBuffer sql = createPQExpBuffer();
01691     PGresult   *res;
01692 
01693     buildShSecLabelQuery(conn, catalog_name, objectId, sql);
01694     res = executeQuery(conn, sql->data);
01695     emitShSecLabels(conn, res, buffer, target, objname);
01696 
01697     PQclear(res);
01698     destroyPQExpBuffer(sql);
01699 }
01700 
01701 /*
01702  * Make a database connection with the given parameters.  An
01703  * interactive password prompt is automatically issued if required.
01704  *
01705  * If fail_on_error is false, we return NULL without printing any message
01706  * on failure, but preserve any prompted password for the next try.
01707  *
01708  * On success, the global variable 'connstr' is set to a connection string
01709  * containing the options used.
01710  */
01711 static PGconn *
01712 connectDatabase(const char *dbname, const char *connection_string,
01713                 const char *pghost, const char *pgport, const char *pguser,
01714                 enum trivalue prompt_password, bool fail_on_error)
01715 {
01716     PGconn     *conn;
01717     bool        new_pass;
01718     const char *remoteversion_str;
01719     int         my_version;
01720     static char *password = NULL;
01721     const char **keywords = NULL;
01722     const char **values = NULL;
01723     PQconninfoOption *conn_opts = NULL;
01724 
01725     if (prompt_password == TRI_YES && !password)
01726         password = simple_prompt("Password: ", 100, false);
01727 
01728     /*
01729      * Start the connection.  Loop until we have a password if requested by
01730      * backend.
01731      */
01732     do
01733     {
01734         int         argcount = 6;
01735         PQconninfoOption *conn_opt;
01736         char       *err_msg = NULL;
01737         int         i = 0;
01738 
01739         if (keywords)
01740             free(keywords);
01741         if (values)
01742             free(values);
01743         if (conn_opts)
01744             PQconninfoFree(conn_opts);
01745 
01746         /*
01747          * Merge the connection info inputs given in form of connection string
01748          * and other options.
01749          */
01750         if (connection_string)
01751         {
01752             conn_opts = PQconninfoParse(connection_string, &err_msg);
01753             if (conn_opts == NULL)
01754             {
01755                 fprintf(stderr, "%s: %s\n", progname, err_msg);
01756                 exit_nicely(1);
01757             }
01758 
01759             for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
01760             {
01761                 if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
01762                     argcount++;
01763             }
01764 
01765             keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
01766             values = pg_malloc0((argcount + 1) * sizeof(*values));
01767 
01768             for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
01769             {
01770                 if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
01771                 {
01772                     keywords[i] = conn_opt->keyword;
01773                     values[i] = conn_opt->val;
01774                     i++;
01775                 }
01776             }
01777         }
01778         else
01779         {
01780             keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
01781             values = pg_malloc0((argcount + 1) * sizeof(*values));
01782         }
01783 
01784         if (pghost)
01785         {
01786             keywords[i] = "host";
01787             values[i] = pghost;
01788             i++;
01789         }
01790         if (pgport)
01791         {
01792             keywords[i] = "port";
01793             values[i] = pgport;
01794             i++;
01795         }
01796         if (pguser)
01797         {
01798             keywords[i] = "user";
01799             values[i] = pguser;
01800             i++;
01801         }
01802         if (password)
01803         {
01804             keywords[i] = "password";
01805             values[i] = password;
01806             i++;
01807         }
01808         if (dbname)
01809         {
01810             keywords[i] = "dbname";
01811             values[i] = dbname;
01812             i++;
01813         }
01814         keywords[i] = "fallback_application_name";
01815         values[i] = progname;
01816         i++;
01817 
01818         new_pass = false;
01819         conn = PQconnectdbParams(keywords, values, true);
01820 
01821         if (!conn)
01822         {
01823             fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
01824                     progname, dbname);
01825             exit_nicely(1);
01826         }
01827 
01828         if (PQstatus(conn) == CONNECTION_BAD &&
01829             PQconnectionNeedsPassword(conn) &&
01830             password == NULL &&
01831             prompt_password != TRI_NO)
01832         {
01833             PQfinish(conn);
01834             password = simple_prompt("Password: ", 100, false);
01835             new_pass = true;
01836         }
01837     } while (new_pass);
01838 
01839     /* check to see that the backend connection was successfully made */
01840     if (PQstatus(conn) == CONNECTION_BAD)
01841     {
01842         if (fail_on_error)
01843         {
01844             fprintf(stderr,
01845                     _("%s: could not connect to database \"%s\": %s\n"),
01846                     progname, dbname, PQerrorMessage(conn));
01847             exit_nicely(1);
01848         }
01849         else
01850         {
01851             PQfinish(conn);
01852 
01853             free(keywords);
01854             free(values);
01855             PQconninfoFree(conn_opts);
01856 
01857             return NULL;
01858         }
01859     }
01860 
01861     /*
01862      * Ok, connected successfully. Remember the options used, in the form of a
01863      * connection string.
01864      */
01865     connstr = constructConnStr(keywords, values);
01866 
01867     free(keywords);
01868     free(values);
01869     PQconninfoFree(conn_opts);
01870 
01871     /* Check version */
01872     remoteversion_str = PQparameterStatus(conn, "server_version");
01873     if (!remoteversion_str)
01874     {
01875         fprintf(stderr, _("%s: could not get server version\n"), progname);
01876         exit_nicely(1);
01877     }
01878     server_version = PQserverVersion(conn);
01879     if (server_version == 0)
01880     {
01881         fprintf(stderr, _("%s: could not parse server version \"%s\"\n"),
01882                 progname, remoteversion_str);
01883         exit_nicely(1);
01884     }
01885 
01886     my_version = PG_VERSION_NUM;
01887 
01888     /*
01889      * We allow the server to be back to 7.0, and up to any minor release of
01890      * our own major version.  (See also version check in pg_dump.c.)
01891      */
01892     if (my_version != server_version
01893         && (server_version < 70000 ||
01894             (server_version / 100) > (my_version / 100)))
01895     {
01896         fprintf(stderr, _("server version: %s; %s version: %s\n"),
01897                 remoteversion_str, progname, PG_VERSION);
01898         fprintf(stderr, _("aborting because of server version mismatch\n"));
01899         exit_nicely(1);
01900     }
01901 
01902     /*
01903      * On 7.3 and later, make sure we are not fooled by non-system schemas in
01904      * the search path.
01905      */
01906     if (server_version >= 70300)
01907         executeCommand(conn, "SET search_path = pg_catalog");
01908 
01909     return conn;
01910 }
01911 
01912 /* ----------
01913  * Construct a connection string from the given keyword/value pairs. It is
01914  * used to pass the connection options to the pg_dump subprocess.
01915  *
01916  * The following parameters are excluded:
01917  *  dbname      - varies in each pg_dump invocation
01918  *  password    - it's not secure to pass a password on the command line
01919  *  fallback_application_name - we'll let pg_dump set it
01920  * ----------
01921  */
01922 static char *
01923 constructConnStr(const char **keywords, const char **values)
01924 {
01925     PQExpBuffer buf = createPQExpBuffer();
01926     char       *connstr;
01927     int         i;
01928     bool        firstkeyword = true;
01929 
01930     /* Construct a new connection string in key='value' format. */
01931     for (i = 0; keywords[i] != NULL; i++)
01932     {
01933         if (strcmp(keywords[i], "dbname") == 0 ||
01934             strcmp(keywords[i], "password") == 0 ||
01935             strcmp(keywords[i], "fallback_application_name") == 0)
01936             continue;
01937 
01938         if (!firstkeyword)
01939             appendPQExpBufferChar(buf, ' ');
01940         firstkeyword = false;
01941         appendPQExpBuffer(buf, "%s=", keywords[i]);
01942         doConnStrQuoting(buf, values[i]);
01943     }
01944 
01945     connstr = pg_strdup(buf->data);
01946     destroyPQExpBuffer(buf);
01947     return connstr;
01948 }
01949 
01950 /*
01951  * Run a query, return the results, exit program on failure.
01952  */
01953 static PGresult *
01954 executeQuery(PGconn *conn, const char *query)
01955 {
01956     PGresult   *res;
01957 
01958     if (verbose)
01959         fprintf(stderr, _("%s: executing %s\n"), progname, query);
01960 
01961     res = PQexec(conn, query);
01962     if (!res ||
01963         PQresultStatus(res) != PGRES_TUPLES_OK)
01964     {
01965         fprintf(stderr, _("%s: query failed: %s"),
01966                 progname, PQerrorMessage(conn));
01967         fprintf(stderr, _("%s: query was: %s\n"),
01968                 progname, query);
01969         PQfinish(conn);
01970         exit_nicely(1);
01971     }
01972 
01973     return res;
01974 }
01975 
01976 /*
01977  * As above for a SQL command (which returns nothing).
01978  */
01979 static void
01980 executeCommand(PGconn *conn, const char *query)
01981 {
01982     PGresult   *res;
01983 
01984     if (verbose)
01985         fprintf(stderr, _("%s: executing %s\n"), progname, query);
01986 
01987     res = PQexec(conn, query);
01988     if (!res ||
01989         PQresultStatus(res) != PGRES_COMMAND_OK)
01990     {
01991         fprintf(stderr, _("%s: query failed: %s"),
01992                 progname, PQerrorMessage(conn));
01993         fprintf(stderr, _("%s: query was: %s\n"),
01994                 progname, query);
01995         PQfinish(conn);
01996         exit_nicely(1);
01997     }
01998 
01999     PQclear(res);
02000 }
02001 
02002 
02003 /*
02004  * dumpTimestamp
02005  */
02006 static void
02007 dumpTimestamp(char *msg)
02008 {
02009     char        buf[256];
02010     time_t      now = time(NULL);
02011 
02012     /*
02013      * We don't print the timezone on Win32, because the names are long and
02014      * localized, which means they may contain characters in various random
02015      * encodings; this has been seen to cause encoding errors when reading the
02016      * dump script.
02017      */
02018     if (strftime(buf, sizeof(buf),
02019 #ifndef WIN32
02020                  "%Y-%m-%d %H:%M:%S %Z",
02021 #else
02022                  "%Y-%m-%d %H:%M:%S",
02023 #endif
02024                  localtime(&now)) != 0)
02025         fprintf(OPF, "-- %s %s\n\n", msg, buf);
02026 }
02027 
02028 
02029 /*
02030  * Append the given string to the buffer, with suitable quoting for passing
02031  * the string as a value, in a keyword/pair value in a libpq connection
02032  * string
02033  */
02034 static void
02035 doConnStrQuoting(PQExpBuffer buf, const char *str)
02036 {
02037     const char *s;
02038     bool        needquotes;
02039 
02040     /*
02041      * If the string consists entirely of plain ASCII characters, no need to
02042      * quote it. This is quite conservative, but better safe than sorry.
02043      */
02044     needquotes = false;
02045     for (s = str; *s; s++)
02046     {
02047         if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
02048               (*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
02049         {
02050             needquotes = true;
02051             break;
02052         }
02053     }
02054 
02055     if (needquotes)
02056     {
02057         appendPQExpBufferChar(buf, '\'');
02058         while (*str)
02059         {
02060             /* ' and \ must be escaped by to \' and \\ */
02061             if (*str == '\'' || *str == '\\')
02062                 appendPQExpBufferChar(buf, '\\');
02063 
02064             appendPQExpBufferChar(buf, *str);
02065             str++;
02066         }
02067         appendPQExpBufferChar(buf, '\'');
02068     }
02069     else
02070         appendPQExpBufferStr(buf, str);
02071 }
02072 
02073 /*
02074  * Append the given string to the shell command being built in the buffer,
02075  * with suitable shell-style quoting.
02076  */
02077 static void
02078 doShellQuoting(PQExpBuffer buf, const char *str)
02079 {
02080     const char *p;
02081 
02082 #ifndef WIN32
02083     appendPQExpBufferChar(buf, '\'');
02084     for (p = str; *p; p++)
02085     {
02086         if (*p == '\'')
02087             appendPQExpBuffer(buf, "'\"'\"'");
02088         else
02089             appendPQExpBufferChar(buf, *p);
02090     }
02091     appendPQExpBufferChar(buf, '\'');
02092 #else                           /* WIN32 */
02093 
02094     appendPQExpBufferChar(buf, '"');
02095     for (p = str; *p; p++)
02096     {
02097         if (*p == '"')
02098             appendPQExpBuffer(buf, "\\\"");
02099         else
02100             appendPQExpBufferChar(buf, *p);
02101     }
02102     appendPQExpBufferChar(buf, '"');
02103 #endif   /* WIN32 */
02104 }