Heikki Linnakangas <hlinnakan...@vmware.com> writes:
>>
>> It appears that replication connection doesn't support URI but only the
>> traditional conninfo string.
>>
>> src/backend/replication/libpqwalreceiver/libpqwalreceiver.c:99: in 
>> libpqrcv_connect():
>>
>>      snprintf(conninfo_repl, sizeof(conninfo_repl),
>>               "%s dbname=replication replication=true 
>> fallback_application_name=walreceiver",
>>               conninfo);
>>
>> A patch to fix this welcome?
>
> Yeah, seems like an oversight. Hopefully you can fix that without
> teaching libpqwalreceiver what connection URIs look like..

Please see attached.  We're lucky that PQconnectdbParams has an option
to parse and expand the first dbname parameter if it looks like a
connection string (or a URI).

The first patch is not on topic, I just spotted this missing check.

The second one is a self-contained fix, but the third one which is the
actual patch depends on the second one, because it specifies the dbname
keyword two times: first to parse the conninfo/URI, then to override any
dbname provided by the user with "replication" pseudo-database name.

Have a nice day!
--
Alex

>From 156e6faa96ad6a2ce58055ad72883ed78c576e5b Mon Sep 17 00:00:00 2001
From: Alex Shulgin <a...@commandprompt.com>
Date: Mon, 24 Nov 2014 16:55:50 +0300
Subject: [PATCH 1/3] Add missing check on OOM in expand_dbname path of
 conninfo_array_parse().

---
 src/interfaces/libpq/fe-connect.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
new file mode 100644
index 3fe8c21..d7f2ec2
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
*************** conninfo_array_parse(const char *const *
*** 4402,4407 ****
--- 4402,4415 ----
  								if (options[k].val)
  									free(options[k].val);
  								options[k].val = strdup(str_option->val);
+ 								if (!options[k].val)
+ 								{
+ 									printfPQExpBuffer(errorMessage,
+ 													  libpq_gettext("out of memory\n"));
+ 									PQconninfoFree(options);
+ 									PQconninfoFree(dbname_options);
+ 									return NULL;
+ 								}
  								break;
  							}
  						}
-- 
2.1.0

>From 44d9d6a2c9cf5af83988f9d3b6eeb39c36104ef9 Mon Sep 17 00:00:00 2001
From: Alex Shulgin <a...@commandprompt.com>
Date: Mon, 24 Nov 2014 18:12:51 +0300
Subject: [PATCH 2/3] Allow further dbname=value to override conninfo parsed
 from an expanded dbname in conninfo_array_parse().

---
 src/interfaces/libpq/fe-connect.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
new file mode 100644
index d7f2ec2..5b45128
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
*************** conninfo_parse(const char *conninfo, PQE
*** 4302,4311 ****
   * Defaults are supplied (from a service file, environment variables, etc)
   * for unspecified options, but only if use_defaults is TRUE.
   *
!  * If expand_dbname is non-zero, and the value passed for keyword "dbname" is a
!  * connection string (as indicated by recognized_connection_string) then parse
!  * and process it, overriding any previously processed conflicting
!  * keywords. Subsequent keywords will take precedence, however.
   */
  static PQconninfoOption *
  conninfo_array_parse(const char *const * keywords, const char *const * values,
--- 4302,4313 ----
   * Defaults are supplied (from a service file, environment variables, etc)
   * for unspecified options, but only if use_defaults is TRUE.
   *
!  * If expand_dbname is non-zero, and the value passed for the first occurrence
!  * of "dbname" keyword is a connection string (as indicated by
!  * recognized_connection_string) then parse and process it, overriding any
!  * previously processed conflicting keywords. Subsequent keywords will take
!  * precedence, however. In particular, a further occurrence of "dbname" may
!  * override the dbname provided in the connection string.
   */
  static PQconninfoOption *
  conninfo_array_parse(const char *const * keywords, const char *const * values,
*************** conninfo_array_parse(const char *const *
*** 4381,4387 ****
  			}
  
  			/*
! 			 * If we are on the dbname parameter, and we have a parsed
  			 * connection string, copy those parameters across, overriding any
  			 * existing previous settings.
  			 */
--- 4383,4389 ----
  			}
  
  			/*
! 			 * If we are on the *first* dbname parameter, and we have a parsed
  			 * connection string, copy those parameters across, overriding any
  			 * existing previous settings.
  			 */
*************** conninfo_array_parse(const char *const *
*** 4415,4420 ****
--- 4417,4428 ----
  						}
  					}
  				}
+ 				/*
+ 				 * Clear out the parsed dbname, so that a possible further
+ 				 * occurrence of dbname have the chance to override it.
+ 				 */
+ 				PQconninfoFree(dbname_options);
+ 				dbname_options = NULL;
  			}
  			else
  			{
-- 
2.1.0

>From 69e7c676e3af6f25520990cfb4337fc129741a95 Mon Sep 17 00:00:00 2001
From: Alex Shulgin <a...@commandprompt.com>
Date: Mon, 24 Nov 2014 18:54:01 +0300
Subject: [PATCH 3/3] Allow URI in primary_conninfo line of recovery.conf file.

---
 doc/src/sgml/high-availability.sgml                      |  6 +++---
 doc/src/sgml/recovery-config.sgml                        |  4 ++--
 src/backend/access/transam/recovery.conf.sample          |  3 ++-
 .../replication/libpqwalreceiver/libpqwalreceiver.c      | 16 +++++++---------
 4 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
new file mode 100644
index d249959..61cf585
*** a/doc/src/sgml/high-availability.sgml
--- b/doc/src/sgml/high-availability.sgml
*************** protocol to make nodes agree on a serial
*** 681,689 ****
  
     <para>
       If you want to use streaming replication, fill in
!      <varname>primary_conninfo</> with a libpq connection string, including
!      the host name (or IP address) and any additional details needed to
!      connect to the primary server. If the primary needs a password for
       authentication, the password needs to be specified in
       <varname>primary_conninfo</> as well.
     </para>
--- 681,689 ----
  
     <para>
       If you want to use streaming replication, fill in
!      <varname>primary_conninfo</> with a libpq connection string or a URI,
!      including the host name (or IP address) and any additional details needed
!      to connect to the primary server. If the primary needs a password for
       authentication, the password needs to be specified in
       <varname>primary_conninfo</> as well.
     </para>
diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
new file mode 100644
index 0f1ff34..9e17e20
*** a/doc/src/sgml/recovery-config.sgml
--- b/doc/src/sgml/recovery-config.sgml
*************** restore_command = 'copy "C:\\server\\arc
*** 342,349 ****
          </term>
          <listitem>
           <para>
!           Specifies a connection string to be used for the standby server
!           to connect with the primary. This string is in the format
            described in <xref linkend="libpq-connstring">. If any option is
            unspecified in this string, then the corresponding environment
            variable (see <xref linkend="libpq-envars">) is checked. If the
--- 342,349 ----
          </term>
          <listitem>
           <para>
!           Specifies a connection string or a URI to be used for the standby
!           server to connect with the primary. This string is in the format
            described in <xref linkend="libpq-connstring">. If any option is
            unspecified in this string, then the corresponding environment
            variable (see <xref linkend="libpq-envars">) is checked. If the
diff --git a/src/backend/access/transam/recovery.conf.sample b/src/backend/access/transam/recovery.conf.sample
new file mode 100644
index 7657df3..b1815be
*** a/src/backend/access/transam/recovery.conf.sample
--- b/src/backend/access/transam/recovery.conf.sample
***************
*** 116,124 ****
  # primary_conninfo
  #
  # If set, the PostgreSQL server will try to connect to the primary using this
! # connection string and receive XLOG records continuously.
  #
  #primary_conninfo = ''		# e.g. 'host=localhost port=5432'
  #
  # If set, the PostgreSQL server will use the specified replication slot when
  # connecting to the primary via streaming replication to control resource
--- 116,125 ----
  # primary_conninfo
  #
  # If set, the PostgreSQL server will try to connect to the primary using this
! # connection string or URI and receive XLOG records continuously.
  #
  #primary_conninfo = ''		# e.g. 'host=localhost port=5432'
+ 				# or 'postgres://localhost:5432/'
  #
  # If set, the PostgreSQL server will use the specified replication slot when
  # connecting to the primary via streaming replication to control resource
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
new file mode 100644
index 65e95c5..eebb3bb
*** a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
--- b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
*************** _PG_init(void)
*** 89,106 ****
  static void
  libpqrcv_connect(char *conninfo)
  {
! 	char		conninfo_repl[MAXCONNINFO + 75];
  
  	/*
! 	 * Connect using deliberately undocumented parameter: replication. The
! 	 * database name is ignored by the server in replication mode, but specify
! 	 * "replication" for .pgpass lookup.
  	 */
! 	snprintf(conninfo_repl, sizeof(conninfo_repl),
! 			 "%s dbname=replication replication=true fallback_application_name=walreceiver",
! 			 conninfo);
! 
! 	streamConn = PQconnectdb(conninfo_repl);
  	if (PQstatus(streamConn) != CONNECTION_OK)
  		ereport(ERROR,
  				(errmsg("could not connect to the primary server: %s",
--- 89,104 ----
  static void
  libpqrcv_connect(char *conninfo)
  {
! 	const char	*keys[] = { "dbname", "dbname",      "replication", "fallback_application_name", NULL };
! 	const char	*vals[] = { conninfo, "replication", "true",        "walreceiver",               NULL };
  
  	/*
! 	 * We exploit the expand_dbname parameter to process the connection string
! 	 * (or URI), then override the options that are necessary to establish the
! 	 * replication type of connection.  In particular, we override any
! 	 * database name provided in conninfo with "replication".
  	 */
! 	streamConn = PQconnectdbParams(keys, vals, /* expand_dbname = */ true);
  	if (PQstatus(streamConn) != CONNECTION_OK)
  		ereport(ERROR,
  				(errmsg("could not connect to the primary server: %s",
-- 
2.1.0

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to