@@ -56,13 +56,15 @@ static int runPgDump(const char *dbname);
5656static 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 );
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
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)
16301632static int
16311633runPgDump (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 */
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{
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