OSDN Git Service

Tablespaces. Alternate database locations are dead, long live tablespaces.
[pg-rex/syncrep.git] / src / bin / pg_dump / pg_dumpall.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_dumpall
4  *
5  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
6  * Portions Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.42 2004/06/18 06:14:00 tgl Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13
14 #include "postgres_fe.h"
15
16 #include <unistd.h>
17 #ifdef ENABLE_NLS
18 #include <locale.h>
19 #endif
20 #ifndef HAVE_STRDUP
21 #include "strdup.h"
22 #endif
23 #include <errno.h>
24 #include <time.h>
25
26 #include "getopt_long.h"
27
28 #ifndef HAVE_OPTRESET
29 int                     optreset;
30 #endif
31
32 #include "dumputils.h"
33 #include "libpq-fe.h"
34 #include "pg_backup.h"
35 #include "pqexpbuffer.h"
36
37 #define _(x) gettext((x))
38
39 /* version string we expect back from postgres */
40 #define PG_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
41
42
43 static const char *progname;
44
45 static void help(void);
46
47 static void dumpUsers(PGconn *conn);
48 static void dumpGroups(PGconn *conn);
49 static void dumpTablespaces(PGconn *conn);
50 static void dumpCreateDB(PGconn *conn);
51 static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
52 static void dumpUserConfig(PGconn *conn, const char *username);
53 static void makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name);
54 static void dumpDatabases(PGconn *conn);
55 static void dumpTimestamp(char *msg);
56
57 static int      runPgDump(const char *dbname);
58 static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
59                                 const char *pguser, bool require_password);
60 static PGresult *executeQuery(PGconn *conn, const char *query);
61
62
63 char        pg_dump_bin[MAXPGPATH];
64 PQExpBuffer pgdumpopts;
65 bool            output_clean = false;
66 bool            skip_acls = false;
67 bool            verbose = false;
68 int                     server_version;
69
70
71
72 int
73 main(int argc, char *argv[])
74 {
75         char       *pghost = NULL;
76         char       *pgport = NULL;
77         char       *pguser = NULL;
78         bool            force_password = false;
79         bool            data_only = false;
80         bool            globals_only = false;
81         bool            schema_only = false;
82         PGconn     *conn;
83         int                     c, ret;
84
85         static struct option long_options[] = {
86                 {"data-only", no_argument, NULL, 'a'},
87                 {"clean", no_argument, NULL, 'c'},
88                 {"inserts", no_argument, NULL, 'd'},
89                 {"attribute-inserts", no_argument, NULL, 'D'},
90                 {"column-inserts", no_argument, NULL, 'D'},
91                 {"globals-only", no_argument, NULL, 'g'},
92                 {"host", required_argument, NULL, 'h'},
93                 {"ignore-version", no_argument, NULL, 'i'},
94                 {"oids", no_argument, NULL, 'o'},
95                 {"port", required_argument, NULL, 'p'},
96                 {"password", no_argument, NULL, 'W'},
97                 {"schema-only", no_argument, NULL, 's'},
98                 {"username", required_argument, NULL, 'U'},
99                 {"verbose", no_argument, NULL, 'v'},
100                 {"no-privileges", no_argument, NULL, 'x'},
101                 {"no-acl", no_argument, NULL, 'x'},
102                 {NULL, 0, NULL, 0}
103         };
104
105         int                     optindex;
106
107         set_pglocale_pgservice(argv[0], "pg_dump");
108
109         progname = get_progname(argv[0]);
110
111         if (argc > 1)
112         {
113                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
114                 {
115                         help();
116                         exit(0);
117                 }
118                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
119                 {
120                         puts("pg_dumpall (PostgreSQL) " PG_VERSION);
121                         exit(0);
122                 }
123         }
124
125         if ((ret = find_other_exec(argv[0], "pg_dump", PG_VERSIONSTR,
126                                                            pg_dump_bin)) < 0)
127         {
128                 if (ret == -1)
129                         fprintf(stderr,
130                                                 _("The program \"pg_dump\" is needed by %s "
131                                                 "but was not found in the same directory as \"%s\".\n"
132                                                 "Check your installation.\n"),
133                                                 progname, progname);
134                 else
135                         fprintf(stderr,
136                                                 _("The program \"pg_dump\" was found by %s "
137                                                 "but was not the same version as \"%s\".\n"
138                                                 "Check your installation.\n"),
139                                                 progname, progname);
140                 exit(1);
141         }
142
143         pgdumpopts = createPQExpBuffer();
144
145         while ((c = getopt_long(argc, argv, "acdDgh:iop:sU:vWx", long_options, &optindex)) != -1)
146         {
147                 switch (c)
148                 {
149                         case 'a':
150                                 data_only = true;
151                                 appendPQExpBuffer(pgdumpopts, " -a");
152                                 break;
153
154                         case 'c':
155                                 output_clean = true;
156                                 break;
157
158                         case 'd':
159                         case 'D':
160                                 appendPQExpBuffer(pgdumpopts, " -%c", c);
161                                 break;
162
163                         case 'g':
164                                 globals_only = true;
165                                 break;
166
167                         case 'h':
168                                 pghost = optarg;
169                                 appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost);
170                                 break;
171
172                         case 'i':
173                         case 'o':
174                                 appendPQExpBuffer(pgdumpopts, " -%c", c);
175                                 break;
176
177                         case 'p':
178                                 pgport = optarg;
179                                 appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport);
180                                 break;
181
182                         case 's':
183                                 schema_only = true;
184                                 appendPQExpBuffer(pgdumpopts, " -s");
185                                 break;
186
187                         case 'U':
188                                 pguser = optarg;
189                                 appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser);
190                                 break;
191
192                         case 'v':
193                                 verbose = true;
194                                 appendPQExpBuffer(pgdumpopts, " -v");
195                                 break;
196
197                         case 'W':
198                                 force_password = true;
199                                 appendPQExpBuffer(pgdumpopts, " -W");
200                                 break;
201
202                         case 'x':
203                                 skip_acls = true;
204                                 appendPQExpBuffer(pgdumpopts, " -x");
205                                 break;
206
207                         default:
208                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
209                                 exit(1);
210                 }
211         }
212
213         if (optind < argc)
214         {
215                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
216                                 progname, argv[optind]);
217                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
218                                 progname);
219                 exit(1);
220         }
221
222
223         conn = connectDatabase("template1", pghost, pgport, pguser, force_password);
224
225         printf("--\n-- PostgreSQL database cluster dump\n--\n\n");
226         if (verbose)
227                         dumpTimestamp("Started on");
228
229         printf("\\connect \"template1\"\n\n");
230
231         if (!data_only)
232         {
233                 dumpUsers(conn);
234                 dumpGroups(conn);
235                 if (server_version >= 70500)
236                         dumpTablespaces(conn);
237         }
238
239         if (!globals_only)
240         {
241                 if (!data_only)
242                         dumpCreateDB(conn);
243                 dumpDatabases(conn);
244         }
245
246         PQfinish(conn);
247
248         if (verbose)
249                 dumpTimestamp("Completed on");
250         printf("--\n-- PostgreSQL database cluster dump complete\n--\n\n");
251
252         exit(0);
253 }
254
255
256
257 static void
258 help(void)
259 {
260         printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
261         printf(_("Usage:\n"));
262         printf(_("  %s [OPTION]...\n"), progname);
263
264         printf(_("\nOptions:\n"));
265         printf(_("  -a, --data-only          dump only the data, not the schema\n"));
266         printf(_("  -c, --clean              clean (drop) databases prior to create\n"));
267         printf(_("  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"));
268         printf(_("  -D, --column-inserts     dump data as INSERT commands with column names\n"));
269         printf(_("  -g, --globals-only       dump only global objects, no databases\n"));
270         printf(_("  -i, --ignore-version     proceed even when server version mismatches\n"
271                          "                           pg_dumpall version\n"));
272         printf(_("  -s, --schema-only        dump only the schema, no data\n"));
273         printf(_("  -o, --oids               include OIDs in dump\n"));
274         printf(_("  -v, --verbose            verbose mode\n"));
275         printf(_("  -x, --no-privileges      do not dump privileges (grant/revoke)\n"));
276         printf(_("  --help                   show this help, then exit\n"));
277         printf(_("  --version                output version information, then exit\n"));
278
279         printf(_("\nConnection options:\n"));
280         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
281         printf(_("  -p, --port=PORT          database server port number\n"));
282         printf(_("  -U, --username=NAME      connect as specified database user\n"));
283         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
284
285         printf(_("\nThe SQL script will be written to the standard output.\n\n"));
286         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
287 }
288
289
290
291 /*
292  * Dump users (but not the user created by initdb).
293  */
294 static void
295 dumpUsers(PGconn *conn)
296 {
297         PGresult   *res;
298         int                     i;
299
300         printf("--\n-- Users\n--\n\n");
301         printf("DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');\n\n");
302
303         if (server_version >= 70100)
304                 res = executeQuery(conn,
305                                                 "SELECT usename, usesysid, passwd, usecreatedb, "
306                                                    "usesuper, valuntil "
307                                                    "FROM pg_shadow "
308                                                    "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0')");
309         else
310                 res = executeQuery(conn,
311                                                 "SELECT usename, usesysid, passwd, usecreatedb, "
312                                                    "usesuper, valuntil "
313                                                    "FROM pg_shadow "
314                                                    "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template1')");
315
316         for (i = 0; i < PQntuples(res); i++)
317         {
318                 PQExpBuffer buf = createPQExpBuffer();
319                 const char *username;
320
321                 username = PQgetvalue(res, i, 0);
322                 appendPQExpBuffer(buf, "CREATE USER %s WITH SYSID %s",
323                                                   fmtId(username),
324                                                   PQgetvalue(res, i, 1));
325
326                 if (!PQgetisnull(res, i, 2))
327                 {
328                         appendPQExpBuffer(buf, " PASSWORD ");
329                         appendStringLiteral(buf, PQgetvalue(res, i, 2), true);
330                 }
331
332                 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
333                         appendPQExpBuffer(buf, " CREATEDB");
334                 else
335                         appendPQExpBuffer(buf, " NOCREATEDB");
336
337                 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
338                         appendPQExpBuffer(buf, " CREATEUSER");
339                 else
340                         appendPQExpBuffer(buf, " NOCREATEUSER");
341
342                 if (!PQgetisnull(res, i, 5))
343                         appendPQExpBuffer(buf, " VALID UNTIL '%s'",
344                                                           PQgetvalue(res, i, 5));
345
346                 appendPQExpBuffer(buf, ";\n");
347
348                 printf("%s", buf->data);
349                 destroyPQExpBuffer(buf);
350
351                 if (server_version >= 70300)
352                         dumpUserConfig(conn, username);
353         }
354
355         PQclear(res);
356         printf("\n\n");
357 }
358
359
360
361 /*
362  * Dump groups.
363  */
364 static void
365 dumpGroups(PGconn *conn)
366 {
367         PGresult   *res;
368         int                     i;
369
370         printf("--\n-- Groups\n--\n\n");
371         printf("DELETE FROM pg_group;\n\n");
372
373         res = executeQuery(conn, "SELECT groname, grosysid, grolist FROM pg_group");
374
375         for (i = 0; i < PQntuples(res); i++)
376         {
377                 PQExpBuffer buf = createPQExpBuffer();
378                 char       *val;
379                 char       *tok;
380
381                 appendPQExpBuffer(buf, "CREATE GROUP %s WITH SYSID %s;\n",
382                                                   fmtId(PQgetvalue(res, i, 0)),
383                                                   PQgetvalue(res, i, 1));
384
385                 val = strdup(PQgetvalue(res, i, 2));
386                 tok = strtok(val, ",{}");
387                 while (tok)
388                 {
389                         PGresult   *res2;
390                         PQExpBuffer buf2 = createPQExpBuffer();
391                         int                     j;
392
393                         appendPQExpBuffer(buf2, "SELECT usename FROM pg_shadow WHERE usesysid = %s;", tok);
394                         res2 = executeQuery(conn, buf2->data);
395                         destroyPQExpBuffer(buf2);
396
397                         for (j = 0; j < PQntuples(res2); j++)
398                         {
399                                 appendPQExpBuffer(buf, "ALTER GROUP %s ", fmtId(PQgetvalue(res, i, 0)));
400                                 appendPQExpBuffer(buf, "ADD USER %s;\n", fmtId(PQgetvalue(res2, j, 0)));
401                         }
402
403                         PQclear(res2);
404
405                         tok = strtok(NULL, "{},");
406                 }
407                 free(val);
408
409                 printf("%s", buf->data);
410                 destroyPQExpBuffer(buf);
411         }
412
413         PQclear(res);
414         printf("\n\n");
415 }
416
417 /*
418  * Dump tablespaces.
419  */
420 static void
421 dumpTablespaces(PGconn *conn)
422 {
423         PGresult   *res;
424         int                     i;
425
426         printf("--\n-- Tablespaces\n--\n\n");
427
428         /*
429          * Get all tablespaces except for the system default and global
430          * tablespaces
431          */
432         res = executeQuery(conn, "SELECT spcname, "
433                                            "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
434                                            "spclocation, spcacl "
435                                            "FROM pg_catalog.pg_tablespace "
436                                            "WHERE spcname NOT IN ('default', 'global')");
437
438         for (i = 0; i < PQntuples(res); i++)
439         {
440                 PQExpBuffer buf = createPQExpBuffer();
441                 char    *spcname = PQgetvalue(res, i, 0);
442                 char    *spcowner = PQgetvalue(res, i, 1);
443                 char    *spclocation = PQgetvalue(res, i, 2);
444                 char    *spcacl = PQgetvalue(res, i, 3);
445                 char    *fspcname;
446
447                 /* needed for buildACLCommands() */
448                 fspcname = strdup(fmtId(spcname));
449
450                 if (output_clean)
451                         appendPQExpBuffer(buf, "DROP TABLESPACE %s;\n", fspcname);
452
453                 appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
454                 appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
455
456                 appendPQExpBuffer(buf, " LOCATION ");
457                 appendStringLiteral(buf, spclocation, true);
458                 appendPQExpBuffer(buf, ";\n");
459
460                 if (!skip_acls &&
461                         !buildACLCommands(fspcname, "TABLESPACE", spcacl, spcowner,
462                                                           server_version, buf))
463                 {
464                         fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
465                                         progname, spcacl, fspcname);
466                         PQfinish(conn);
467                         exit(1);
468                 }
469
470                 printf("%s", buf->data);
471
472                 free(fspcname);
473                 destroyPQExpBuffer(buf);
474         }
475
476         PQclear(res);
477         printf("\n\n");
478 }
479
480 /*
481  * Dump commands to create each database.
482  *
483  * To minimize the number of reconnections (and possibly ensuing
484  * password prompts) required by the output script, we emit all CREATE
485  * DATABASE commands during the initial phase of the script, and then
486  * run pg_dump for each database to dump the contents of that
487  * database.  We skip databases marked not datallowconn, since we'd be
488  * unable to connect to them anyway (and besides, we don't want to
489  * dump template0).
490  */
491 static void
492 dumpCreateDB(PGconn *conn)
493 {
494         PGresult   *res;
495         int                     i;
496
497         printf("--\n-- Database creation\n--\n\n");
498
499         if (server_version >= 70500)
500                 res = executeQuery(conn,
501                                                    "SELECT datname, "
502                                                    "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
503                                                    "pg_encoding_to_char(d.encoding), "
504                                                    "datistemplate, datacl, "
505                                                    "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
506                 "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
507                                                    "WHERE datallowconn ORDER BY 1");
508         else if (server_version >= 70300)
509                 res = executeQuery(conn,
510                                                    "SELECT datname, "
511                                                    "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
512                                                    "pg_encoding_to_char(d.encoding), "
513                                                    "datistemplate, datacl, "
514                                                    "'default' AS dattablespace "
515                 "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
516                                                    "WHERE datallowconn ORDER BY 1");
517         else if (server_version >= 70100)
518                 res = executeQuery(conn,
519                                                    "SELECT datname, "
520                                                    "coalesce("
521                                 "(select usename from pg_shadow where usesysid=datdba), "
522                                                    "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
523                                                    "pg_encoding_to_char(d.encoding), "
524                                                    "datistemplate, '' as datacl, "
525                                                    "'default' AS dattablespace "
526                                                    "FROM pg_database d "
527                                                    "WHERE datallowconn ORDER BY 1");
528         else
529         {
530                 /*
531                  * Note: 7.0 fails to cope with sub-select in COALESCE, so just
532                  * deal with getting a NULL by not printing any OWNER clause.
533                  */
534                 res = executeQuery(conn,
535                                                    "SELECT datname, "
536                                 "(select usename from pg_shadow where usesysid=datdba), "
537                                                    "pg_encoding_to_char(d.encoding), "
538                                                    "'f' as datistemplate, "
539                                                    "'' as datacl, "
540                                                    "'default' AS dattablespace "
541                                                    "FROM pg_database d "
542                                                    "ORDER BY 1");
543         }
544
545         for (i = 0; i < PQntuples(res); i++)
546         {
547                 PQExpBuffer buf;
548                 char       *dbname = PQgetvalue(res, i, 0);
549                 char       *dbowner = PQgetvalue(res, i, 1);
550                 char       *dbencoding = PQgetvalue(res, i, 2);
551                 char       *dbistemplate = PQgetvalue(res, i, 3);
552                 char       *dbacl = PQgetvalue(res, i, 4);
553                 char       *dbtablespace = PQgetvalue(res, i, 5);
554                 char       *fdbname;
555
556                 if (strcmp(dbname, "template1") == 0)
557                         continue;
558
559                 buf = createPQExpBuffer();
560
561                 /* needed for buildACLCommands() */
562                 fdbname = strdup(fmtId(dbname));
563
564                 if (output_clean)
565                         appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
566
567                 appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
568
569                 appendPQExpBuffer(buf, " WITH TEMPLATE = template0");
570
571                 if (strlen(dbowner) != 0)
572                         appendPQExpBuffer(buf, " OWNER = %s",
573                                                           fmtId(dbowner));
574
575                 appendPQExpBuffer(buf, " ENCODING = ");
576                 appendStringLiteral(buf, dbencoding, true);
577
578                 /* Output tablespace if it isn't default */
579                 if (strcmp(dbtablespace, "default") != 0)
580                         appendPQExpBuffer(buf, " TABLESPACE = %s",
581                                                           fmtId(dbtablespace));
582
583                 appendPQExpBuffer(buf, ";\n");
584
585                 if (strcmp(dbistemplate, "t") == 0)
586                 {
587                         appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
588                         appendStringLiteral(buf, dbname, true);
589                         appendPQExpBuffer(buf, ";\n");
590                 }
591
592                 if (!skip_acls &&
593                         !buildACLCommands(fdbname, "DATABASE", dbacl, dbowner,
594                                                           server_version, buf))
595                 {
596                         fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
597                                         progname, dbacl, fdbname);
598                         PQfinish(conn);
599                         exit(1);
600                 }
601
602                 printf("%s", buf->data);
603                 destroyPQExpBuffer(buf);
604                 free(fdbname);
605
606                 if (server_version >= 70300)
607                         dumpDatabaseConfig(conn, dbname);
608         }
609
610         PQclear(res);
611         printf("\n\n");
612 }
613
614
615
616 /*
617  * Dump database-specific configuration
618  */
619 static void
620 dumpDatabaseConfig(PGconn *conn, const char *dbname)
621 {
622         PQExpBuffer buf = createPQExpBuffer();
623         int                     count = 1;
624
625         for (;;)
626         {
627                 PGresult   *res;
628
629                 printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
630                 appendStringLiteral(buf, dbname, true);
631                 appendPQExpBuffer(buf, ";");
632
633                 res = executeQuery(conn, buf->data);
634                 if (!PQgetisnull(res, 0, 0))
635                 {
636                         makeAlterConfigCommand(PQgetvalue(res, 0, 0), "DATABASE", dbname);
637                         PQclear(res);
638                         count++;
639                 }
640                 else
641                 {
642                         PQclear(res);
643                         break;
644                 }
645         }
646
647         destroyPQExpBuffer(buf);
648 }
649
650
651
652 /*
653  * Dump user-specific configuration
654  */
655 static void
656 dumpUserConfig(PGconn *conn, const char *username)
657 {
658         PQExpBuffer buf = createPQExpBuffer();
659         int                     count = 1;
660
661         for (;;)
662         {
663                 PGresult   *res;
664
665                 printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
666                 appendStringLiteral(buf, username, true);
667                 appendPQExpBuffer(buf, ";");
668
669                 res = executeQuery(conn, buf->data);
670                 if (!PQgetisnull(res, 0, 0))
671                 {
672                         makeAlterConfigCommand(PQgetvalue(res, 0, 0), "USER", username);
673                         PQclear(res);
674                         count++;
675                 }
676                 else
677                 {
678                         PQclear(res);
679                         break;
680                 }
681         }
682
683         destroyPQExpBuffer(buf);
684 }
685
686
687
688 /*
689  * Helper function for dumpXXXConfig().
690  */
691 static void
692 makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name)
693 {
694         char       *pos;
695         char       *mine;
696         PQExpBuffer buf = createPQExpBuffer();
697
698         mine = strdup(arrayitem);
699         pos = strchr(mine, '=');
700         if (pos == NULL)
701                 return;
702
703         *pos = 0;
704         appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
705         appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
706         appendStringLiteral(buf, pos + 1, false);
707         appendPQExpBuffer(buf, ";\n");
708
709         printf("%s", buf->data);
710         destroyPQExpBuffer(buf);
711         free(mine);
712 }
713
714
715
716 /*
717  * Dump contents of databases.
718  */
719 static void
720 dumpDatabases(PGconn *conn)
721 {
722         PGresult   *res;
723         int                     i;
724
725         if (server_version >= 70100)
726                 res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1");
727         else
728                 res = executeQuery(conn, "SELECT datname FROM pg_database ORDER BY 1");
729
730         for (i = 0; i < PQntuples(res); i++)
731         {
732                 int                     ret;
733
734                 char       *dbname = PQgetvalue(res, i, 0);
735
736                 if (verbose)
737                         fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
738
739                 printf("\\connect %s\n\n", fmtId(dbname));
740                 ret = runPgDump(dbname);
741                 if (ret != 0)
742                 {
743                         fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname);
744                         exit(1);
745                 }
746         }
747
748         PQclear(res);
749 }
750
751
752
753 /*
754  * Run pg_dump on dbname.
755  */
756 static int
757 runPgDump(const char *dbname)
758 {
759         PQExpBuffer cmd = createPQExpBuffer();
760         const char *p;
761         int                     ret;
762
763         appendPQExpBuffer(cmd, "%s\"%s\" %s -Fp '", SYSTEMQUOTE, pg_dump_bin,
764                                           pgdumpopts->data);
765
766         /* Shell quoting is not quite like SQL quoting, so can't use fmtId */
767         for (p = dbname; *p; p++)
768         {
769                 if (*p == '\'')
770                         appendPQExpBuffer(cmd, "'\"'\"'");
771                 else
772                         appendPQExpBufferChar(cmd, *p);
773         }
774
775         appendPQExpBufferChar(cmd, '\'');
776         appendStringLiteral(cmd, SYSTEMQUOTE, false);
777
778         if (verbose)
779                 fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
780
781         fflush(stdout);
782         fflush(stderr);
783
784         ret = system(cmd->data);
785
786         destroyPQExpBuffer(cmd);
787
788         return ret;
789 }
790
791
792
793 /*
794  * Make a database connection with the given parameters.  An
795  * interactive password prompt is automatically issued if required.
796  */
797 static PGconn *
798 connectDatabase(const char *dbname, const char *pghost, const char *pgport,
799                                 const char *pguser, bool require_password)
800 {
801         PGconn     *conn;
802         char       *password = NULL;
803         bool            need_pass = false;
804         const char *remoteversion_str;
805
806         if (require_password)
807                 password = simple_prompt("Password: ", 100, false);
808
809         /*
810          * Start the connection.  Loop until we have a password if requested
811          * by backend.
812          */
813         do
814         {
815                 need_pass = false;
816                 conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);
817
818                 if (!conn)
819                 {
820                         fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
821                                         progname, dbname);
822                         exit(1);
823                 }
824
825                 if (PQstatus(conn) == CONNECTION_BAD &&
826                         strcmp(PQerrorMessage(conn), "fe_sendauth: no password supplied\n") == 0 &&
827                         !feof(stdin))
828                 {
829                         PQfinish(conn);
830                         need_pass = true;
831                         free(password);
832                         password = NULL;
833                         password = simple_prompt("Password: ", 100, false);
834                 }
835         } while (need_pass);
836
837         if (password)
838                 free(password);
839
840         /* check to see that the backend connection was successfully made */
841         if (PQstatus(conn) == CONNECTION_BAD)
842         {
843                 fprintf(stderr, _("%s: could not connect to database \"%s\": %s\n"),
844                                 progname, dbname, PQerrorMessage(conn));
845                 exit(1);
846         }
847
848         remoteversion_str = PQparameterStatus(conn, "server_version");
849         if (!remoteversion_str)
850         {
851                 fprintf(stderr, _("%s: could not get server version\n"), progname);
852                 exit(1);
853         }
854         server_version = parse_version(remoteversion_str);
855         if (server_version < 0)
856         {
857                 fprintf(stderr, _("%s: could not parse server version \"%s\"\n"),
858                                 progname, remoteversion_str);
859                 exit(1);
860         }
861
862         return conn;
863 }
864
865
866
867 /*
868  * Run a query, return the results, exit program on failure.
869  */
870 static PGresult *
871 executeQuery(PGconn *conn, const char *query)
872 {
873         PGresult   *res;
874
875         if (verbose)
876                 fprintf(stderr, _("%s: executing %s\n"), progname, query);
877
878         res = PQexec(conn, query);
879         if (!res ||
880                 PQresultStatus(res) != PGRES_TUPLES_OK)
881         {
882                 fprintf(stderr, _("%s: query failed: %s"), progname, PQerrorMessage(conn));
883                 fprintf(stderr, _("%s: query was: %s\n"), progname, query);
884                 PQfinish(conn);
885                 exit(1);
886         }
887
888         return res;
889 }
890
891
892 /*
893  * dumpTimestamp
894  */
895 static void
896 dumpTimestamp(char *msg)
897 {
898         char buf[256];
899         time_t now = time(NULL);
900
901         if (strftime(buf, 256, "%Y-%m-%d %H:%M:%S %Z", localtime(&now)) != 0)
902                 printf("-- %s %s\n\n", msg, buf);
903 }