2012-10-04 16:43 keltezéssel, Tom Lane írta:
Boszormenyi Zoltan <z...@cybertec.at> writes:
Did you think about something like the attached code?
Or rather this one, which fixes a bug so fillPGconn() and PQconninfo() are
symmetric and work for "requiressl".
That's incredibly ugly.  I'm not sure where we should keep the "R"
information, but shoehorning it into the existing PQconninfoOption
struct like that seems totally unacceptable.  Either we're willing to
break backwards compatibility on the Disp-Char strings, or we need
to put that info somewhere else.

I hope only handling the new flag part is ugly. It can be hidden
in the PQconninfoMapping[] array and PQconninfo(conn, true)
pre-filters the list as in the attached version.

Best regards,
Zoltán Böszörményi

--
----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
Gröhrmühlgasse 26
A-2700 Wiener Neustadt, Austria
Web: http://www.postgresql-support.de
     http://www.postgresql.at/

diff -durpN postgresql/doc/src/sgml/libpq.sgml postgresql.1/doc/src/sgml/libpq.sgml
--- postgresql/doc/src/sgml/libpq.sgml	2012-08-03 09:39:30.114266570 +0200
+++ postgresql.1/doc/src/sgml/libpq.sgml	2012-10-04 18:15:11.686199926 +0200
@@ -496,6 +496,37 @@ typedef struct
      </listitem>
     </varlistentry>
 
+    <varlistentry id="libpq-pqconninfo">
+     <term><function>PQconninfo</function><indexterm><primary>PQconninfo</></></term>
+     <listitem>
+      <para>
+       Returns the connection options used by a live connection.
+<synopsis>
+PQconninfoOption *PQconninfo(PGconn *conn, bool for_replication);
+</synopsis>
+      </para>
+
+      <para>
+       Returns a connection options array.  This can be used to determine
+       all possible <function>PQconnectdb</function> options and their
+       current values that were used to connect to the server. The return
+       value points to an array of <structname>PQconninfoOption</structname>
+       structures, which ends with an entry having a null <structfield>keyword</>
+       pointer.  Every notes above for <function>PQconndefaults</function> also apply.
+      </para>
+
+      <para>
+       The <literal>for_replication</> argument can be used to exclude some
+       options from the list which are used by the walreceiver module.
+       <application>pg_basebackup</application> uses this pre-filtered list
+       to construct <literal>primary_conninfo</> in the automatically generated
+       recovery.conf file.
+      </para>
+
+     </listitem>
+    </varlistentry>
+
+
     <varlistentry id="libpq-pqconninfoparse">
      <term><function>PQconninfoParse</function><indexterm><primary>PQconninfoParse</></></term>
      <listitem>
diff -durpN postgresql/src/interfaces/libpq/exports.txt postgresql.1/src/interfaces/libpq/exports.txt
--- postgresql/src/interfaces/libpq/exports.txt	2012-08-03 09:39:30.118266598 +0200
+++ postgresql.1/src/interfaces/libpq/exports.txt	2012-10-04 17:10:11.483654334 +0200
@@ -161,3 +161,4 @@ PQping                    158
 PQpingParams              159
 PQlibVersion              160
 PQsetSingleRowMode        161
+PQconninfo                162
diff -durpN postgresql/src/interfaces/libpq/fe-connect.c postgresql.1/src/interfaces/libpq/fe-connect.c
--- postgresql/src/interfaces/libpq/fe-connect.c	2012-09-09 08:11:09.470401480 +0200
+++ postgresql.1/src/interfaces/libpq/fe-connect.c	2012-10-04 17:53:26.205928500 +0200
@@ -137,6 +137,9 @@ static int ldapServiceLookup(const char
  * PQconninfoOptions[] *must* be NULL.	In a working copy, non-null "val"
  * fields point to malloc'd strings that should be freed when the working
  * array is freed (see PQconninfoFree).
+ *
+ * If you add a new connection option to this list, remember to add it to
+ * PQconninfoMappings[] below.
  * ----------
  */
 static const PQconninfoOption PQconninfoOptions[] = {
@@ -264,6 +267,62 @@ static const PQconninfoOption PQconninfo
 	NULL, NULL, 0}
 };
 
+/*
+ * We need a mapping between the PQconninfoOptions[] array
+ * and PGconn members. We have to keep it separate from
+ * PQconninfoOptions[] to not leak info about PGconn members
+ * to clients.
+ */
+typedef struct PQconninfoMapping {
+	char		*keyword;
+	size_t		member_offset;
+	bool		for_replication;
+	char		*conninfoValue;	/* Special value mapping */
+	char		*connValue;
+} PQconninfoMapping;
+#define PGCONNMEMBERADDR(conn, mapping) ((char **)((char *)conn + mapping->member_offset))
+
+static const PQconninfoMapping PQconninfoMappings[] =
+{
+	/* "authtype" is not used anymore, there is no mapping to PGconn */
+	/* there is no mapping of "service" to PGconn */
+	{ "user", offsetof(struct pg_conn, pguser), true, NULL, NULL },
+	{ "password", offsetof(struct pg_conn, pgpass), true, NULL, NULL },
+	{ "connect_timeout", offsetof(struct pg_conn, connect_timeout), true, NULL, NULL },
+	{ "dbname", offsetof(struct pg_conn, dbName), false, NULL, NULL },
+	{ "host", offsetof(struct pg_conn, pghost), true, NULL, NULL },
+	{ "hostaddr", offsetof(struct pg_conn, pghostaddr), true, NULL, NULL },
+	{ "port", offsetof(struct pg_conn, pgport), true, NULL, NULL },
+	{ "client_encoding", offsetof(struct pg_conn, client_encoding_initial), false, NULL, NULL },
+	{ "tty", offsetof(struct pg_conn, pgtty), false, NULL, NULL },
+	{ "options", offsetof(struct pg_conn, pgoptions), true, NULL, NULL },
+	{ "application_name", offsetof(struct pg_conn, appname), false, NULL, NULL },
+	{ "fallback_application_name", offsetof(struct pg_conn, fbappname), false, NULL, NULL },
+	{ "keepalives", offsetof(struct pg_conn, keepalives), true, NULL, NULL },
+	{ "keepalives_idle", offsetof(struct pg_conn, keepalives_idle), true, NULL, NULL },
+	{ "keepalives_interval", offsetof(struct pg_conn, keepalives_interval), true, NULL, NULL },
+	{ "keepalives_count", offsetof(struct pg_conn, keepalives_count), true, NULL, NULL },
+#ifdef USE_SSL
+	{ "requiressl", offsetof(struct pg_conn, sslmode), false, "1", "require" },
+#endif
+	{ "sslmode", offsetof(struct pg_conn, sslmode), true, NULL, NULL },
+	{ "sslcompression", offsetof(struct pg_conn, sslcompression), true, NULL, NULL },
+	{ "sslcert", offsetof(struct pg_conn, sslcert), true, NULL, NULL },
+	{ "sslkey", offsetof(struct pg_conn, sslkey), true, NULL, NULL },
+	{ "sslrootcert", offsetof(struct pg_conn, sslrootcert), true, NULL, NULL },
+	{ "sslcrl", offsetof(struct pg_conn, sslcrl), true, NULL, NULL },
+	{ "requirepeer", offsetof(struct pg_conn, requirepeer), true, NULL, NULL },
+#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
+	{ "krbsrvname", offsetof(struct pg_conn, krbsrvname), true, NULL, NULL },
+#endif
+#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
+	{ "gsslib", offsetof(struct pg_conn, requirepeer), true, NULL, NULL },
+#endif
+	{ "replication", offsetof(struct pg_conn, replication), false, NULL, NULL },
+	/* Terminating entry --- MUST BE LAST */
+	{ NULL, 0, false, NULL, NULL }
+};
+
 static const PQEnvironmentOption EnvironmentOptions[] =
 {
 	/* common user-interface settings */
@@ -295,7 +354,8 @@ static PGconn *makeEmptyPGconn(void);
 static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
 static void freePGconn(PGconn *conn);
 static void closePGconn(PGconn *conn);
-static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage);
+static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage,
+						bool for_replication);
 static PQconninfoOption *parse_connection_string(const char *conninfo,
 						PQExpBuffer errorMessage, bool use_defaults);
 static int	uri_prefix_length(const char *connstr);
@@ -318,6 +378,8 @@ static char *conninfo_uri_decode(const c
 static bool get_hexdigit(char digit, int *value);
 static const char *conninfo_getval(PQconninfoOption *connOptions,
 				const char *keyword);
+static void conninfo_setval(PQconninfoOption *connOptions,
+				const char *keyword, const char *val);
 static PQconninfoOption *conninfo_storeval(PQconninfoOption *connOptions,
 				  const char *keyword, const char *value,
 			  PQExpBuffer errorMessage, bool ignoreMissing, bool uri_decode);
@@ -627,7 +689,9 @@ PQconnectStart(const char *conninfo)
 static void
 fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
 {
+	const PQconninfoMapping *mapping;
 	const char *tmp;
+	char	   **memberaddr;
 
 	/*
 	 * Move option values into conn structure
@@ -637,72 +701,24 @@ fillPGconn(PGconn *conn, PQconninfoOptio
 	 *
 	 * XXX: probably worth checking strdup() return value here...
 	 */
-	tmp = conninfo_getval(connOptions, "hostaddr");
-	conn->pghostaddr = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "host");
-	conn->pghost = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "port");
-	conn->pgport = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "tty");
-	conn->pgtty = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "options");
-	conn->pgoptions = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "application_name");
-	conn->appname = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "fallback_application_name");
-	conn->fbappname = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "dbname");
-	conn->dbName = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "user");
-	conn->pguser = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "password");
-	conn->pgpass = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "connect_timeout");
-	conn->connect_timeout = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "client_encoding");
-	conn->client_encoding_initial = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "keepalives");
-	conn->keepalives = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "keepalives_idle");
-	conn->keepalives_idle = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "keepalives_interval");
-	conn->keepalives_interval = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "keepalives_count");
-	conn->keepalives_count = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "sslmode");
-	conn->sslmode = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "sslcompression");
-	conn->sslcompression = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "sslkey");
-	conn->sslkey = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "sslcert");
-	conn->sslcert = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "sslrootcert");
-	conn->sslrootcert = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval(connOptions, "sslcrl");
-	conn->sslcrl = tmp ? strdup(tmp) : NULL;
-#ifdef USE_SSL
-	tmp = conninfo_getval(connOptions, "requiressl");
-	if (tmp && tmp[0] == '1')
+	for (mapping = PQconninfoMappings; mapping->keyword; mapping++)
 	{
-		/* here warn that the requiressl option is deprecated? */
-		if (conn->sslmode)
-			free(conn->sslmode);
-		conn->sslmode = strdup("require");
+		tmp = conninfo_getval(connOptions, mapping->keyword);
+		memberaddr = PGCONNMEMBERADDR(conn, mapping);
+
+		if (mapping->conninfoValue && mapping->connValue)
+		{
+			size_t	len = strlen(mapping->conninfoValue);
+			if (tmp && strncmp(tmp, mapping->conninfoValue, len) == 0)
+			{
+				if (*memberaddr)
+					free(*memberaddr);
+				*memberaddr = strdup(mapping->connValue);
+			}
+		}
+		else
+			*memberaddr = tmp ? strdup(tmp) : NULL;
 	}
-#endif
-	tmp = conninfo_getval(connOptions, "requirepeer");
-	conn->requirepeer = tmp ? strdup(tmp) : NULL;
-#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
-	tmp = conninfo_getval(connOptions, "krbsrvname");
-	conn->krbsrvname = tmp ? strdup(tmp) : NULL;
-#endif
-#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
-	tmp = conninfo_getval(connOptions, "gsslib");
-	conn->gsslib = tmp ? strdup(tmp) : NULL;
-#endif
-	tmp = conninfo_getval(connOptions, "replication");
-	conn->replication = tmp ? strdup(tmp) : NULL;
 }
 
 /*
@@ -884,7 +900,7 @@ PQconndefaults(void)
 	if (PQExpBufferDataBroken(errorBuf))
 		return NULL;			/* out of memory already :-( */
 
-	connOptions = conninfo_init(&errorBuf);
+	connOptions = conninfo_init(&errorBuf, false);
 	if (connOptions != NULL)
 	{
 		if (!conninfo_add_defaults(connOptions, &errorBuf))
@@ -4006,9 +4022,11 @@ PQconninfoParse(const char *conninfo, ch
 
 /*
  * Build a working copy of the constant PQconninfoOptions array.
+ * If for_replication is true, only return the options that are
+ * not added by libpqwalreceiver. 
  */
 static PQconninfoOption *
-conninfo_init(PQExpBuffer errorMessage)
+conninfo_init(PQExpBuffer errorMessage, bool for_replication)
 {
 	PQconninfoOption *options;
 
@@ -4019,7 +4037,27 @@ conninfo_init(PQExpBuffer errorMessage)
 						  libpq_gettext("out of memory\n"));
 		return NULL;
 	}
-	memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions));
+	if (for_replication)
+	{
+		const PQconninfoMapping	*mapping = PQconninfoMappings;
+		PQconninfoOption *opt_dest = options;
+
+		while (mapping->keyword)
+		{
+			const PQconninfoOption *opt_src = conninfo_find(PQconninfoOptions, mapping->keyword);
+
+			if (opt_src && mapping->for_replication)
+			{
+				memcpy(opt_dest, opt_src, sizeof(PQconninfoOption));
+				opt_dest++;
+			}
+
+			opt_src++;
+			mapping++;
+		}
+	}
+	else
+		memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions));
 
 	return options;
 }
@@ -4095,7 +4133,7 @@ conninfo_parse(const char *conninfo, PQE
 	PQconninfoOption *options;
 
 	/* Make a working copy of PQconninfoOptions */
-	options = conninfo_init(errorMessage);
+	options = conninfo_init(errorMessage, false);
 	if (options == NULL)
 		return NULL;
 
@@ -4295,7 +4333,7 @@ conninfo_array_parse(const char *const *
 	}
 
 	/* Make a working copy of PQconninfoOptions */
-	options = conninfo_init(errorMessage);
+	options = conninfo_init(errorMessage, false);
 	if (options == NULL)
 	{
 		PQconninfoFree(dbname_options);
@@ -4485,7 +4523,7 @@ conninfo_uri_parse(const char *uri, PQEx
 	PQconninfoOption *options;
 
 	/* Make a working copy of PQconninfoOptions */
-	options = conninfo_init(errorMessage);
+	options = conninfo_init(errorMessage, false);
 	if (options == NULL)
 		return NULL;
 
@@ -4985,6 +5023,24 @@ conninfo_getval(PQconninfoOption *connOp
 }
 
 /*
+ * Set an option value corresponding to the keyword in the connOptions array.
+ */
+static void
+conninfo_setval(PQconninfoOption *connOptions, const char *keyword,
+						const char *val)
+{
+	PQconninfoOption *option;
+
+	option = conninfo_find(connOptions, keyword);
+	if (option)
+	{
+		if (option->val)
+			free(option->val);
+		option->val = val ? strdup(val) : NULL;
+	}
+}
+
+/*
  * Store a (new) value for an option corresponding to the keyword in
  * connOptions array.
  *
@@ -5066,6 +5122,50 @@ conninfo_find(PQconninfoOption *connOpti
 }
 
 
+/*
+ * Return the connection options used for the connections
+ */
+PQconninfoOption *
+PQconninfo(PGconn *conn, bool for_replication)
+{
+	PQExpBufferData errorBuf;
+	PQconninfoOption *connOptions;
+
+	if (conn == NULL)
+		return NULL;
+
+	/* We don't actually report any errors here, but callees want a buffer */
+	initPQExpBuffer(&errorBuf);
+	if (PQExpBufferDataBroken(errorBuf))
+		return NULL;		/* out of memory already :-( */
+
+	connOptions = conninfo_init(&errorBuf, for_replication);
+
+	termPQExpBuffer(&errorBuf);
+
+	if (connOptions != NULL)
+	{
+		const PQconninfoMapping *mapping;
+
+		for (mapping = PQconninfoMappings; mapping->keyword; mapping++)
+		{
+			char **memberaddr = PGCONNMEMBERADDR(conn, mapping);
+
+			if (mapping->conninfoValue && mapping->connValue)
+			{
+				size_t	len = strlen(mapping->connValue);
+				if (*memberaddr && strncmp(*memberaddr, mapping->connValue, len) == 0)
+					conninfo_setval(connOptions, mapping->keyword, mapping->conninfoValue);
+			}
+			else
+				conninfo_setval(connOptions, mapping->keyword, *memberaddr);
+		}
+	}
+
+	return connOptions;
+}
+
+
 void
 PQconninfoFree(PQconninfoOption *connOptions)
 {
diff -durpN postgresql/src/interfaces/libpq/libpq-fe.h postgresql.1/src/interfaces/libpq/libpq-fe.h
--- postgresql/src/interfaces/libpq/libpq-fe.h	2012-08-03 09:39:30.122266626 +0200
+++ postgresql.1/src/interfaces/libpq/libpq-fe.h	2012-10-04 17:56:58.126076978 +0200
@@ -262,6 +262,9 @@ extern PQconninfoOption *PQconndefaults(
 /* parse connection options in same way as PQconnectdb */
 extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg);
 
+/* return the connection options used by a live connection */
+extern PQconninfoOption *PQconninfo(PGconn *conn, bool for_replication);
+
 /* free the data structure returned by PQconndefaults() or PQconninfoParse() */
 extern void PQconninfoFree(PQconninfoOption *connOptions);
 
diff -durpN postgresql.1/doc/src/sgml/ref/pg_basebackup.sgml postgresql.2/doc/src/sgml/ref/pg_basebackup.sgml
--- postgresql.1/doc/src/sgml/ref/pg_basebackup.sgml	2012-08-24 09:49:22.960530329 +0200
+++ postgresql.2/doc/src/sgml/ref/pg_basebackup.sgml	2012-10-04 17:32:59.880177443 +0200
@@ -189,6 +189,27 @@ PostgreSQL documentation
      </varlistentry>
 
      <varlistentry>
+      <term><option>-R</option></term>
+      <term><option>--write-recovery-conf</option></term>
+      <listitem>
+       <para>
+        Write a minimal recovery.conf into the output directory using
+        the connection parameters from the command line to ease
+        setting up the standby. Since creating a backup for a standalone
+        server with <option>-x</option> or <option>-X</option> and adding
+        a recovery.conf to it wouldn't make a working standby, these options
+        naturally conflict.
+       </para>
+       <para>
+        When this option is specified and taking the base backup succeeded,
+        failing to write the <filename>recovery.conf</filename> results
+        in the error code 2. This way, scripts can distinguish between different
+        failure cases of <application>pg_basebackup</application>.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><option>-x</option></term>
       <term><option>--xlog</option></term>
       <listitem>
diff -durpN postgresql.1/src/bin/pg_basebackup/pg_basebackup.c postgresql.2/src/bin/pg_basebackup/pg_basebackup.c
--- postgresql.1/src/bin/pg_basebackup/pg_basebackup.c	2012-10-03 10:40:48.297207389 +0200
+++ postgresql.2/src/bin/pg_basebackup/pg_basebackup.c	2012-10-04 17:34:59.462033508 +0200
@@ -46,6 +46,7 @@ int			compresslevel = 0;
 bool		includewal = false;
 bool		streamwal = false;
 bool		fastcheckpoint = false;
+bool		writerecoveryconf = false;
 int			standby_message_timeout = 10 * 1000;		/* 10 sec = default */
 
 /* Progress counters */
@@ -70,14 +71,18 @@ static int	has_xlogendptr = 0;
 static volatile LONG has_xlogendptr = 0;
 #endif
 
+static PQconninfoOption *connOptions = NULL;
+
 /* Function headers */
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname);
 static void progress_report(int tablespacenum, const char *filename);
+static void stderr_write_error(FILE *cf, char *filename);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void BaseBackup(void);
+static void WriteRecoveryConf(void);
 
 static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 					 bool segment_finished);
@@ -107,6 +112,8 @@ usage(void)
 	printf(_("\nOptions controlling the output:\n"));
 	printf(_("  -D, --pgdata=DIRECTORY receive base backup into directory\n"));
 	printf(_("  -F, --format=p|t       output format (plain (default), tar)\n"));
+	printf(_("  -R, --write-recovery-conf\n"
+			 "                         write recovery.conf after backup\n"));
 	printf(_("  -x, --xlog             include required WAL files in backup (fetch mode)\n"));
 	printf(_("  -X, --xlog-method=fetch|stream\n"
 			 "                         include required WAL files with specified method\n"));
@@ -960,6 +967,10 @@ BaseBackup(void)
 		/* Error message already written in GetConnection() */
 		exit(1);
 
+	/* If recovery.conf is to be written, keep the connection parameters for later usage */
+	if (writerecoveryconf)
+		connOptions = PQconninfo(conn, true);
+
 	/*
 	 * Run IDENTIFY_SYSTEM so we can get the timeline
 	 */
@@ -1234,6 +1245,71 @@ BaseBackup(void)
 }
 
 
+static void
+stderr_write_error(FILE *cf, char *filename)
+{
+	fprintf(stderr, _("cannot write to %s: %s"), filename, strerror(errno));
+	fclose(cf);
+	unlink(filename);
+	exit(2);
+}
+
+
+/*
+ * Attempt to create recovery.conf and write the expected contents to it.
+ */
+static void
+WriteRecoveryConf(void)
+{
+	char		filename[MAXPGPATH];
+	PQconninfoOption   *option;
+	FILE		   *cf;
+
+	if (!writerecoveryconf)
+		return;
+
+	sprintf(filename, "%s/recovery.conf", basedir);
+
+	cf = fopen(filename, "w");
+	if (cf == NULL)
+	{
+		fprintf(stderr, _("cannot create %s: %s"), filename, strerror(errno));
+		exit(2);
+	}
+
+	if (fprintf(cf, "standby_mode = 'on'\n") < 0)
+		stderr_write_error(cf, filename);
+
+	if (fprintf(cf, "primary_conninfo = '") < 0)
+		stderr_write_error(cf, filename);
+
+	for (option = connOptions; option && option->keyword; option++)
+	{
+		/*
+		 * Do not emit this setting if not set, empty or default.
+		 * The list of options was already pre-filtered for options
+		 * usable for replication with PQconninfo(conn, true).
+		 */
+		if (option->val == NULL ||
+				(option->val != NULL && option->val[0] == '\0') ||
+				(option->val &&
+					option->compiled &&
+					strcmp(option->val, option->compiled) == 0))
+			continue;
+
+		/* write "keyword='value'" pieces, single quotes doubled */
+		if (fprintf(cf, "%s=''%s'' ", option->keyword, option->val) < 0)
+			stderr_write_error(cf, filename);
+	}
+
+	if (fprintf(cf, "'\n") < 0)
+		stderr_write_error(cf, filename);
+
+	PQconninfoFree(connOptions);
+
+	fclose(cf);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1243,6 +1319,7 @@ main(int argc, char **argv)
 		{"pgdata", required_argument, NULL, 'D'},
 		{"format", required_argument, NULL, 'F'},
 		{"checkpoint", required_argument, NULL, 'c'},
+		{"write-recovery-conf", no_argument, NULL, 'R'},
 		{"xlog", no_argument, NULL, 'x'},
 		{"xlog-method", required_argument, NULL, 'X'},
 		{"gzip", no_argument, NULL, 'z'},
@@ -1280,7 +1357,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	while ((c = getopt_long(argc, argv, "D:F:xX:l:zZ:c:h:p:U:s:wWvP",
+	while ((c = getopt_long(argc, argv, "D:F:RxX:l:zZ:c:h:p:U:s:wWvP",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -1301,6 +1378,9 @@ main(int argc, char **argv)
 					exit(1);
 				}
 				break;
+			case 'R':
+				writerecoveryconf = true;
+				break;
 			case 'x':
 				if (includewal)
 				{
@@ -1466,6 +1546,13 @@ main(int argc, char **argv)
 	}
 #endif
 
+	if (writerecoveryconf && includewal)
+	{
+		fprintf(stderr,
+				_("--xlog and --writerecoveryconf are mutually exclusive\n"));
+		exit(1);
+	}
+
 	/*
 	 * Verify that the target directory exists, or create it. For plaintext
 	 * backups, always require the directory. For tar backups, require it
@@ -1476,5 +1563,7 @@ main(int argc, char **argv)
 
 	BaseBackup();
 
+	WriteRecoveryConf();
+
 	return 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