@@ -56,13 +56,15 @@ static intrunPgDump(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.