@@ -56,13 +56,15 @@ static int runPgDump(const char *dbname);
56
56
static void buildShSecLabels (PGconn * conn , const char * catalog_name ,
57
57
uint32 objectId , PQExpBuffer buffer ,
58
58
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 ,
60
60
const char * pguser , enum trivalue prompt_password , bool fail_on_error );
61
+ static char * constructConnStr (const char * * keywords , const char * * values );
61
62
static PGresult * executeQuery (PGconn * conn , const char * query );
62
63
static void executeCommand (PGconn * conn , const char * query );
63
64
64
65
static char pg_dump_bin [MAXPGPATH ];
65
66
static PQExpBuffer pgdumpopts ;
67
+ static char * connstr = "" ;
66
68
static bool skip_acls = false;
67
69
static bool verbose = false;
68
70
@@ -91,6 +93,7 @@ main(int argc, char *argv[])
91
93
{"globals-only" , no_argument , NULL , 'g' },
92
94
{"host" , required_argument , NULL , 'h' },
93
95
{"ignore-version" , no_argument , NULL , 'i' },
96
+ {"dbname" , required_argument , NULL , 'd' },
94
97
{"database" , required_argument , NULL , 'l' },
95
98
{"oids" , no_argument , NULL , 'o' },
96
99
{"no-owner" , no_argument , NULL , 'O' },
@@ -188,7 +191,7 @@ main(int argc, char *argv[])
188
191
189
192
pgdumpopts = createPQExpBuffer ();
190
193
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 )
192
195
{
193
196
switch (c )
194
197
{
@@ -201,6 +204,10 @@ main(int argc, char *argv[])
201
204
output_clean = true;
202
205
break ;
203
206
207
+ case 'd' :
208
+ connstr = pg_strdup (optarg );
209
+ break ;
210
+
204
211
case 'f' :
205
212
filename = pg_strdup (optarg );
206
213
appendPQExpBuffer (pgdumpopts , " -f " );
@@ -213,8 +220,6 @@ main(int argc, char *argv[])
213
220
214
221
case 'h' :
215
222
pghost = pg_strdup (optarg );
216
- appendPQExpBuffer (pgdumpopts , " -h " );
217
- doShellQuoting (pgdumpopts , pghost );
218
223
break ;
219
224
220
225
case 'i' :
@@ -235,8 +240,6 @@ main(int argc, char *argv[])
235
240
236
241
case 'p' :
237
242
pgport = pg_strdup (optarg );
238
- appendPQExpBuffer (pgdumpopts , " -p " );
239
- doShellQuoting (pgdumpopts , pgport );
240
243
break ;
241
244
242
245
case 'r' :
@@ -258,8 +261,6 @@ main(int argc, char *argv[])
258
261
259
262
case 'U' :
260
263
pguser = pg_strdup (optarg );
261
- appendPQExpBuffer (pgdumpopts , " -U " );
262
- doShellQuoting (pgdumpopts , pguser );
263
264
break ;
264
265
265
266
case 'v' :
@@ -370,7 +371,7 @@ main(int argc, char *argv[])
370
371
*/
371
372
if (pgdb )
372
373
{
373
- conn = connectDatabase (pgdb , pghost , pgport , pguser ,
374
+ conn = connectDatabase (pgdb , connstr , pghost , pgport , pguser ,
374
375
prompt_password , false);
375
376
376
377
if (!conn )
@@ -382,10 +383,10 @@ main(int argc, char *argv[])
382
383
}
383
384
else
384
385
{
385
- conn = connectDatabase ("postgres" , pghost , pgport , pguser ,
386
+ conn = connectDatabase ("postgres" , connstr , pghost , pgport , pguser ,
386
387
prompt_password , false);
387
388
if (!conn )
388
- conn = connectDatabase ("template1" , pghost , pgport , pguser ,
389
+ conn = connectDatabase ("template1" , connstr , pghost , pgport , pguser ,
389
390
prompt_password , true);
390
391
391
392
if (!conn )
@@ -568,6 +569,7 @@ help(void)
568
569
" ALTER OWNER commands to set ownership\n" ));
569
570
570
571
printf (_ ("\nConnection options:\n" ));
572
+ printf (_ (" -d, --dbname=CONNSTR connect using connection string\n" ));
571
573
printf (_ (" -h, --host=HOSTNAME database server host or socket directory\n" ));
572
574
printf (_ (" -l, --database=DBNAME alternative default database\n" ));
573
575
printf (_ (" -p, --port=PORT database server port number\n" ));
@@ -1630,7 +1632,7 @@ dumpDatabases(PGconn *conn)
1630
1632
static int
1631
1633
runPgDump (const char * dbname )
1632
1634
{
1633
- PQExpBuffer connstr = createPQExpBuffer ();
1635
+ PQExpBuffer connstrbuf = createPQExpBuffer ();
1634
1636
PQExpBuffer cmd = createPQExpBuffer ();
1635
1637
int ret ;
1636
1638
@@ -1647,16 +1649,13 @@ runPgDump(const char *dbname)
1647
1649
appendPQExpBuffer (cmd , " -Fp " );
1648
1650
1649
1651
/*
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.
1654
1654
*/
1655
- appendPQExpBuffer (connstr , "dbname='" );
1656
- doConnStrQuoting (connstr , dbname );
1657
- appendPQExpBuffer (connstr , "'" );
1655
+ appendPQExpBuffer (connstrbuf , "%s dbname=" , connstr );
1656
+ doConnStrQuoting (connstrbuf , dbname );
1658
1657
1659
- doShellQuoting (cmd , connstr -> data );
1658
+ doShellQuoting (cmd , connstrbuf -> data );
1660
1659
1661
1660
appendPQExpBuffer (cmd , "%s" , SYSTEMQUOTE );
1662
1661
@@ -1669,7 +1668,7 @@ runPgDump(const char *dbname)
1669
1668
ret = system (cmd -> data );
1670
1669
1671
1670
destroyPQExpBuffer (cmd );
1672
- destroyPQExpBuffer (connstr );
1671
+ destroyPQExpBuffer (connstrbuf );
1673
1672
1674
1673
return ret ;
1675
1674
}
@@ -1703,16 +1702,23 @@ buildShSecLabels(PGconn *conn, const char *catalog_name, uint32 objectId,
1703
1702
*
1704
1703
* If fail_on_error is false, we return NULL without printing any message
1705
1704
* 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.
1706
1708
*/
1707
1709
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 )
1710
1713
{
1711
1714
PGconn * conn ;
1712
1715
bool new_pass ;
1713
1716
const char * remoteversion_str ;
1714
1717
int my_version ;
1715
1718
static char * password = NULL ;
1719
+ const char * * keywords = NULL ;
1720
+ const char * * values = NULL ;
1721
+ PQconninfoOption * conn_opts = NULL ;
1716
1722
1717
1723
if (prompt_password == TRI_YES && !password )
1718
1724
password = simple_prompt ("Password: " , 100 , false);
@@ -1723,31 +1729,93 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
1723
1729
*/
1724
1730
do
1725
1731
{
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 ++ ;
1744
1815
1745
1816
new_pass = false;
1746
1817
conn = PQconnectdbParams (keywords , values , true);
1747
1818
1748
- free (keywords );
1749
- free (values );
1750
-
1751
1819
if (!conn )
1752
1820
{
1753
1821
fprintf (stderr , _ ("%s: could not connect to database \"%s\"\n" ),
@@ -1779,10 +1847,26 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
1779
1847
else
1780
1848
{
1781
1849
PQfinish (conn );
1850
+
1851
+ free (keywords );
1852
+ free (values );
1853
+ PQconninfoFree (conn_opts );
1854
+
1782
1855
return NULL ;
1783
1856
}
1784
1857
}
1785
1858
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 */
1786
1870
remoteversion_str = PQparameterStatus (conn , "server_version" );
1787
1871
if (!remoteversion_str )
1788
1872
{
@@ -1829,6 +1913,43 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
1829
1913
return conn ;
1830
1914
}
1831
1915
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
+ }
1832
1953
1833
1954
/*
1834
1955
* Run a query, return the results, exit program on failure.
0 commit comments