Skip to content

Commit 3dee636

Browse files
committed
Add -d option to pg_dumpall, for specifying a connection string.
Like with pg_basebackup and pg_receivexlog, it's a bit strange to call the option -d/--dbname, when in fact you cannot pass a database name in it. Original patch by Amit Kapila, heavily modified by me.
1 parent 691e595 commit 3dee636

File tree

2 files changed

+184
-44
lines changed

2 files changed

+184
-44
lines changed

doc/src/sgml/ref/pg_dumpall.sgml

+19
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,25 @@ PostgreSQL documentation
405405
The following command-line options control the database connection parameters.
406406

407407
<variablelist>
408+
<varlistentry>
409+
<term><option>-d <replaceable class="parameter">connstr</replaceable></option></term>
410+
<term><option>--dbname=<replaceable class="parameter">connstr</replaceable></option></term>
411+
<listitem>
412+
<para>
413+
Specifies parameters used to connect to the server, as a connection
414+
string. See <xref linkend="libpq-connstring"> for more information.
415+
</para>
416+
<para>
417+
The option is called <literal>--dbname</> for consistency with other
418+
client applications, but because <application>pg_dumpall</application>
419+
needs to connect to many databases, database name in the connection
420+
string will be ignored. Use <literal>-l</literal> option to specify
421+
the name of the database used to dump global objects and to discover
422+
what other databases should be dumped.
423+
</para>
424+
</listitem>
425+
</varlistentry>
426+
408427
<varlistentry>
409428
<term><option>-h <replaceable>host</replaceable></option></term>
410429
<term><option>--host=<replaceable>host</replaceable></option></term>

src/bin/pg_dump/pg_dumpall.c

+165-44
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,15 @@ static int runPgDump(const char *dbname);
5656
static void buildShSecLabels(PGconn *conn, const char *catalog_name,
5757
uint32 objectId, PQExpBuffer buffer,
5858
const char *target, const char *objname);
59-
static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
59+
static PGconn *connectDatabase(const char *dbname, const char *connstr, const char *pghost, const char *pgport,
6060
const char *pguser, enum trivalue prompt_password, bool fail_on_error);
61+
static char *constructConnStr(const char **keywords, const char **values);
6162
static PGresult *executeQuery(PGconn *conn, const char *query);
6263
static void executeCommand(PGconn *conn, const char *query);
6364

6465
static char pg_dump_bin[MAXPGPATH];
6566
static PQExpBuffer pgdumpopts;
67+
static char *connstr = "";
6668
static bool skip_acls = false;
6769
static bool verbose = false;
6870

@@ -91,6 +93,7 @@ main(int argc, char *argv[])
9193
{"globals-only", no_argument, NULL, 'g'},
9294
{"host", required_argument, NULL, 'h'},
9395
{"ignore-version", no_argument, NULL, 'i'},
96+
{"dbname", required_argument, NULL, 'd'},
9497
{"database", required_argument, NULL, 'l'},
9598
{"oids", no_argument, NULL, 'o'},
9699
{"no-owner", no_argument, NULL, 'O'},
@@ -188,7 +191,7 @@ main(int argc, char *argv[])
188191

189192
pgdumpopts = createPQExpBuffer();
190193

191-
while ((c = getopt_long(argc, argv, "acf:gh:il:oOp:rsS:tU:vwWx", long_options, &optindex)) != -1)
194+
while ((c = getopt_long(argc, argv, "acd:f:gh:i:l:oOp:rsS:tU:vwWx", long_options, &optindex)) != -1)
192195
{
193196
switch (c)
194197
{
@@ -201,6 +204,10 @@ main(int argc, char *argv[])
201204
output_clean = true;
202205
break;
203206

207+
case 'd':
208+
connstr = pg_strdup(optarg);
209+
break;
210+
204211
case 'f':
205212
filename = pg_strdup(optarg);
206213
appendPQExpBuffer(pgdumpopts, " -f ");
@@ -213,8 +220,6 @@ main(int argc, char *argv[])
213220

214221
case 'h':
215222
pghost = pg_strdup(optarg);
216-
appendPQExpBuffer(pgdumpopts, " -h ");
217-
doShellQuoting(pgdumpopts, pghost);
218223
break;
219224

220225
case 'i':
@@ -235,8 +240,6 @@ main(int argc, char *argv[])
235240

236241
case 'p':
237242
pgport = pg_strdup(optarg);
238-
appendPQExpBuffer(pgdumpopts, " -p ");
239-
doShellQuoting(pgdumpopts, pgport);
240243
break;
241244

242245
case 'r':
@@ -258,8 +261,6 @@ main(int argc, char *argv[])
258261

259262
case 'U':
260263
pguser = pg_strdup(optarg);
261-
appendPQExpBuffer(pgdumpopts, " -U ");
262-
doShellQuoting(pgdumpopts, pguser);
263264
break;
264265

265266
case 'v':
@@ -370,7 +371,7 @@ main(int argc, char *argv[])
370371
*/
371372
if (pgdb)
372373
{
373-
conn = connectDatabase(pgdb, pghost, pgport, pguser,
374+
conn = connectDatabase(pgdb, connstr, pghost, pgport, pguser,
374375
prompt_password, false);
375376

376377
if (!conn)
@@ -382,10 +383,10 @@ main(int argc, char *argv[])
382383
}
383384
else
384385
{
385-
conn = connectDatabase("postgres", pghost, pgport, pguser,
386+
conn = connectDatabase("postgres", connstr, pghost, pgport, pguser,
386387
prompt_password, false);
387388
if (!conn)
388-
conn = connectDatabase("template1", pghost, pgport, pguser,
389+
conn = connectDatabase("template1", connstr, pghost, pgport, pguser,
389390
prompt_password, true);
390391

391392
if (!conn)
@@ -568,6 +569,7 @@ help(void)
568569
" ALTER OWNER commands to set ownership\n"));
569570

570571
printf(_("\nConnection options:\n"));
572+
printf(_(" -d, --dbname=CONNSTR connect using connection string\n"));
571573
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
572574
printf(_(" -l, --database=DBNAME alternative default database\n"));
573575
printf(_(" -p, --port=PORT database server port number\n"));
@@ -1630,7 +1632,7 @@ dumpDatabases(PGconn *conn)
16301632
static int
16311633
runPgDump(const char *dbname)
16321634
{
1633-
PQExpBuffer connstr = createPQExpBuffer();
1635+
PQExpBuffer connstrbuf = createPQExpBuffer();
16341636
PQExpBuffer cmd = createPQExpBuffer();
16351637
int ret;
16361638

@@ -1647,16 +1649,13 @@ runPgDump(const char *dbname)
16471649
appendPQExpBuffer(cmd, " -Fp ");
16481650

16491651
/*
1650-
* Construct a connection string from the database name, like
1651-
* dbname='<database name>'. pg_dump would usually also accept the
1652-
* database name as is, but if it contains any = characters, it would
1653-
* incorrectly treat it as a connection string.
1652+
* Append the database name to the already-constructed stem of connection
1653+
* string.
16541654
*/
1655-
appendPQExpBuffer(connstr, "dbname='");
1656-
doConnStrQuoting(connstr, dbname);
1657-
appendPQExpBuffer(connstr, "'");
1655+
appendPQExpBuffer(connstrbuf, "%s dbname=", connstr);
1656+
doConnStrQuoting(connstrbuf, dbname);
16581657

1659-
doShellQuoting(cmd, connstr->data);
1658+
doShellQuoting(cmd, connstrbuf->data);
16601659

16611660
appendPQExpBuffer(cmd, "%s", SYSTEMQUOTE);
16621661

@@ -1669,7 +1668,7 @@ runPgDump(const char *dbname)
16691668
ret = system(cmd->data);
16701669

16711670
destroyPQExpBuffer(cmd);
1672-
destroyPQExpBuffer(connstr);
1671+
destroyPQExpBuffer(connstrbuf);
16731672

16741673
return ret;
16751674
}
@@ -1703,16 +1702,23 @@ buildShSecLabels(PGconn *conn, const char *catalog_name, uint32 objectId,
17031702
*
17041703
* If fail_on_error is false, we return NULL without printing any message
17051704
* on failure, but preserve any prompted password for the next try.
1705+
*
1706+
* On success, the global variable 'connstr' is set to a connection string
1707+
* containing the options used.
17061708
*/
17071709
static PGconn *
1708-
connectDatabase(const char *dbname, const char *pghost, const char *pgport,
1709-
const char *pguser, enum trivalue prompt_password, bool fail_on_error)
1710+
connectDatabase(const char *dbname, const char *connection_string,
1711+
const char *pghost, const char *pgport, const char *pguser,
1712+
enum trivalue prompt_password, bool fail_on_error)
17101713
{
17111714
PGconn *conn;
17121715
bool new_pass;
17131716
const char *remoteversion_str;
17141717
int my_version;
17151718
static char *password = NULL;
1719+
const char **keywords = NULL;
1720+
const char **values = NULL;
1721+
PQconninfoOption *conn_opts = NULL;
17161722

17171723
if (prompt_password == TRI_YES && !password)
17181724
password = simple_prompt("Password: ", 100, false);
@@ -1723,31 +1729,93 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
17231729
*/
17241730
do
17251731
{
1726-
#define PARAMS_ARRAY_SIZE 7
1727-
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
1728-
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
1729-
1730-
keywords[0] = "host";
1731-
values[0] = pghost;
1732-
keywords[1] = "port";
1733-
values[1] = pgport;
1734-
keywords[2] = "user";
1735-
values[2] = pguser;
1736-
keywords[3] = "password";
1737-
values[3] = password;
1738-
keywords[4] = "dbname";
1739-
values[4] = dbname;
1740-
keywords[5] = "fallback_application_name";
1741-
values[5] = progname;
1742-
keywords[6] = NULL;
1743-
values[6] = NULL;
1732+
int argcount = 6;
1733+
PQconninfoOption *conn_opt;
1734+
char *err_msg = NULL;
1735+
int i = 0;
1736+
1737+
if (keywords)
1738+
free(keywords);
1739+
if (values)
1740+
free(values);
1741+
if (conn_opts)
1742+
PQconninfoFree(conn_opts);
1743+
1744+
/*
1745+
* Merge the connection info inputs given in form of connection string
1746+
* and other options.
1747+
*/
1748+
if (connection_string)
1749+
{
1750+
conn_opts = PQconninfoParse(connection_string, &err_msg);
1751+
if (conn_opts == NULL)
1752+
{
1753+
fprintf(stderr, "%s: %s\n", progname, err_msg);
1754+
exit_nicely(1);
1755+
}
1756+
1757+
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
1758+
{
1759+
if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
1760+
argcount++;
1761+
}
1762+
1763+
keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
1764+
values = pg_malloc0((argcount + 1) * sizeof(*values));
1765+
1766+
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
1767+
{
1768+
if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
1769+
{
1770+
keywords[i] = conn_opt->keyword;
1771+
values[i] = conn_opt->val;
1772+
i++;
1773+
}
1774+
}
1775+
}
1776+
else
1777+
{
1778+
keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
1779+
values = pg_malloc0((argcount + 1) * sizeof(*values));
1780+
}
1781+
1782+
if (pghost)
1783+
{
1784+
keywords[i] = "host";
1785+
values[i] = pghost;
1786+
i++;
1787+
}
1788+
if (pgport)
1789+
{
1790+
keywords[i] = "port";
1791+
values[i] = pgport;
1792+
i++;
1793+
}
1794+
if (pguser)
1795+
{
1796+
keywords[i] = "user";
1797+
values[i] = pguser;
1798+
i++;
1799+
}
1800+
if (password)
1801+
{
1802+
keywords[i] = "password";
1803+
values[i] = password;
1804+
i++;
1805+
}
1806+
if (dbname)
1807+
{
1808+
keywords[i] = "dbname";
1809+
values[i] = dbname;
1810+
i++;
1811+
}
1812+
keywords[i] = "fallback_application_name";
1813+
values[i] = progname;
1814+
i++;
17441815

17451816
new_pass = false;
17461817
conn = PQconnectdbParams(keywords, values, true);
17471818

1748-
free(keywords);
1749-
free(values);
1750-
17511819
if (!conn)
17521820
{
17531821
fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
@@ -1779,10 +1847,26 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
17791847
else
17801848
{
17811849
PQfinish(conn);
1850+
1851+
free(keywords);
1852+
free(values);
1853+
PQconninfoFree(conn_opts);
1854+
17821855
return NULL;
17831856
}
17841857
}
17851858

1859+
/*
1860+
* Ok, connected successfully. Remember the options used, in the form of
1861+
* a connection string.
1862+
*/
1863+
connstr = constructConnStr(keywords, values);
1864+
1865+
free(keywords);
1866+
free(values);
1867+
PQconninfoFree(conn_opts);
1868+
1869+
/* Check version */
17861870
remoteversion_str = PQparameterStatus(conn, "server_version");
17871871
if (!remoteversion_str)
17881872
{
@@ -1829,6 +1913,43 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
18291913
return conn;
18301914
}
18311915

1916+
/* ----------
1917+
* Construct a connection string from the given keyword/value pairs. It is
1918+
* used to pass the connection options to the pg_dump subprocess.
1919+
*
1920+
* The following parameters are excluded:
1921+
* dbname - varies in each pg_dump invocation
1922+
* password - it's not secure to pass a password on the command line
1923+
* fallback_application_name - we'll let pg_dump set it
1924+
* ----------
1925+
*/
1926+
static char *
1927+
constructConnStr(const char **keywords, const char **values)
1928+
{
1929+
PQExpBuffer buf = createPQExpBuffer();
1930+
char *connstr;
1931+
int i;
1932+
bool firstkeyword = true;
1933+
1934+
/* Construct a new connection string in key='value' format. */
1935+
for (i = 0; keywords[i] != NULL; i++)
1936+
{
1937+
if (strcmp(keywords[i], "dbname") == 0 ||
1938+
strcmp(keywords[i], "password") == 0 ||
1939+
strcmp(keywords[i], "fallback_application_name") == 0)
1940+
continue;
1941+
1942+
if (!firstkeyword)
1943+
appendPQExpBufferChar(buf, ' ');
1944+
firstkeyword = false;
1945+
appendPQExpBuffer(buf, "%s=", keywords[i]);
1946+
doConnStrQuoting(buf, values[i]);
1947+
}
1948+
1949+
connstr = pg_strdup(buf->data);
1950+
destroyPQExpBuffer(buf);
1951+
return connstr;
1952+
}
18321953

18331954
/*
18341955
* Run a query, return the results, exit program on failure.

0 commit comments

Comments
 (0)