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