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

Lines changed: 19 additions & 0 deletions
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

Lines changed: 165 additions & 44 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy