@@ -56,13 +56,15 @@ static intrunPgDump(const char *dbname);
5656static void buildShSecLabels (PGconn * conn ,const char * catalog_name ,
5757uint32 objectId ,PQExpBuffer buffer ,
5858const 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 ,
6060const char * pguser ,enum trivalue prompt_password ,bool fail_on_error );
61+ static char * constructConnStr (const char * * keywords ,const char * * values );
6162static PGresult * executeQuery (PGconn * conn ,const char * query );
6263static void executeCommand (PGconn * conn ,const char * query );
6364
6465static char pg_dump_bin [MAXPGPATH ];
6566static PQExpBuffer pgdumpopts ;
67+ static char * connstr = "" ;
6668static bool skip_acls = false;
6769static 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
189192pgdumpopts = 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{
193196switch (c )
194197{
@@ -201,6 +204,10 @@ main(int argc, char *argv[])
201204output_clean = true;
202205break ;
203206
207+ case 'd' :
208+ connstr = pg_strdup (optarg );
209+ break ;
210+
204211case 'f' :
205212filename = pg_strdup (optarg );
206213appendPQExpBuffer (pgdumpopts ," -f " );
@@ -213,8 +220,6 @@ main(int argc, char *argv[])
213220
214221case 'h' :
215222pghost = pg_strdup (optarg );
216- appendPQExpBuffer (pgdumpopts ," -h " );
217- doShellQuoting (pgdumpopts ,pghost );
218223break ;
219224
220225case 'i' :
@@ -235,8 +240,6 @@ main(int argc, char *argv[])
235240
236241case 'p' :
237242pgport = pg_strdup (optarg );
238- appendPQExpBuffer (pgdumpopts ," -p " );
239- doShellQuoting (pgdumpopts ,pgport );
240243break ;
241244
242245case 'r' :
@@ -258,8 +261,6 @@ main(int argc, char *argv[])
258261
259262case 'U' :
260263pguser = pg_strdup (optarg );
261- appendPQExpBuffer (pgdumpopts ," -U " );
262- doShellQuoting (pgdumpopts ,pguser );
263264break ;
264265
265266case 'v' :
@@ -370,7 +371,7 @@ main(int argc, char *argv[])
370371 */
371372if (pgdb )
372373{
373- conn = connectDatabase (pgdb ,pghost ,pgport ,pguser ,
374+ conn = connectDatabase (pgdb ,connstr , pghost ,pgport ,pguser ,
374375prompt_password , false);
375376
376377if (!conn )
@@ -382,10 +383,10 @@ main(int argc, char *argv[])
382383}
383384else
384385{
385- conn = connectDatabase ("postgres" ,pghost ,pgport ,pguser ,
386+ conn = connectDatabase ("postgres" ,connstr , pghost ,pgport ,pguser ,
386387prompt_password , false);
387388if (!conn )
388- conn = connectDatabase ("template1" ,pghost ,pgport ,pguser ,
389+ conn = connectDatabase ("template1" ,connstr , pghost ,pgport ,pguser ,
389390prompt_password , true);
390391
391392if (!conn )
@@ -568,6 +569,7 @@ help(void)
568569" ALTER OWNER commands to set ownership\n" ));
569570
570571printf (_ ("\nConnection options:\n" ));
572+ printf (_ (" -d, --dbname=CONNSTR connect using connection string\n" ));
571573printf (_ (" -h, --host=HOSTNAME database server host or socket directory\n" ));
572574printf (_ (" -l, --database=DBNAME alternative default database\n" ));
573575printf (_ (" -p, --port=PORT database server port number\n" ));
@@ -1630,7 +1632,7 @@ dumpDatabases(PGconn *conn)
16301632static int
16311633runPgDump (const char * dbname )
16321634{
1633- PQExpBuffer connstr = createPQExpBuffer ();
1635+ PQExpBuffer connstrbuf = createPQExpBuffer ();
16341636PQExpBuffer cmd = createPQExpBuffer ();
16351637int ret ;
16361638
@@ -1647,16 +1649,13 @@ runPgDump(const char *dbname)
16471649appendPQExpBuffer (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
16611660appendPQExpBuffer (cmd ,"%s" ,SYSTEMQUOTE );
16621661
@@ -1669,7 +1668,7 @@ runPgDump(const char *dbname)
16691668ret = system (cmd -> data );
16701669
16711670destroyPQExpBuffer (cmd );
1672- destroyPQExpBuffer (connstr );
1671+ destroyPQExpBuffer (connstrbuf );
16731672
16741673return 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 */
17071709static 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{
17111714PGconn * conn ;
17121715bool new_pass ;
17131716const char * remoteversion_str ;
17141717int my_version ;
17151718static char * password = NULL ;
1719+ const char * * keywords = NULL ;
1720+ const char * * values = NULL ;
1721+ PQconninfoOption * conn_opts = NULL ;
17161722
17171723if (prompt_password == TRI_YES && !password )
17181724password = simple_prompt ("Password: " ,100 , false);
@@ -1723,31 +1729,93 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
17231729 */
17241730do
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
17451816new_pass = false;
17461817conn = PQconnectdbParams (keywords ,values , true);
17471818
1748- free (keywords );
1749- free (values );
1750-
17511819if (!conn )
17521820{
17531821fprintf (stderr ,_ ("%s: could not connect to database \"%s\"\n" ),
@@ -1779,10 +1847,26 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
17791847else
17801848{
17811849PQfinish (conn );
1850+
1851+ free (keywords );
1852+ free (values );
1853+ PQconninfoFree (conn_opts );
1854+
17821855return 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 */
17861870remoteversion_str = PQparameterStatus (conn ,"server_version" );
17871871if (!remoteversion_str )
17881872{
@@ -1829,6 +1913,43 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
18291913return 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.