aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/pg_basebackup/pg_basebackup.c162
-rw-r--r--src/fe_utils/Makefile3
-rw-r--r--src/fe_utils/recovery_gen.c176
-rw-r--r--src/include/fe_utils/recovery_gen.h28
-rw-r--r--src/tools/msvc/Mkvcbuild.pm3
5 files changed, 211 insertions, 161 deletions
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 7986872f106..55ef13926da 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -31,6 +31,7 @@
#include "common/file_utils.h"
#include "common/logging.h"
#include "common/string.h"
+#include "fe_utils/recovery_gen.h"
#include "fe_utils/string_utils.h"
#include "getopt_long.h"
#include "libpq-fe.h"
@@ -68,11 +69,6 @@ typedef struct TablespaceList
#define MINIMUM_VERSION_FOR_TEMP_SLOTS 100000
/*
- * recovery.conf is integrated into postgresql.conf from version 12.
- */
-#define MINIMUM_VERSION_FOR_RECOVERY_GUC 120000
-
-/*
* Different ways to include WAL
*/
typedef enum
@@ -147,8 +143,6 @@ static void progress_report(int tablespacenum, const char *filename, bool force)
static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
-static void GenerateRecoveryConf(PGconn *conn);
-static void WriteRecoveryConf(void);
static void BaseBackup(void);
static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
@@ -1629,7 +1623,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
PQfreemem(copybuf);
if (basetablespace && writerecoveryconf)
- WriteRecoveryConf();
+ WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
/*
* No data is synced here, everything is done for all tablespaces at the
@@ -1637,156 +1631,6 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
*/
}
-/*
- * Escape a string so that it can be used as a value in a key-value pair
- * a configuration file.
- */
-static char *
-escape_quotes(const char *src)
-{
- char *result = escape_single_quotes_ascii(src);
-
- if (!result)
- {
- pg_log_error("out of memory");
- exit(1);
- }
- return result;
-}
-
-/*
- * Create a configuration file in memory using a PQExpBuffer
- */
-static void
-GenerateRecoveryConf(PGconn *conn)
-{
- PQconninfoOption *connOptions;
- PQconninfoOption *option;
- PQExpBufferData conninfo_buf;
- char *escaped;
-
- recoveryconfcontents = createPQExpBuffer();
- if (!recoveryconfcontents)
- {
- pg_log_error("out of memory");
- exit(1);
- }
-
- /*
- * In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
- * standby.signal to trigger a standby state at recovery.
- */
- if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
- appendPQExpBufferStr(recoveryconfcontents, "standby_mode = 'on'\n");
-
- connOptions = PQconninfo(conn);
- if (connOptions == NULL)
- {
- pg_log_error("out of memory");
- exit(1);
- }
-
- initPQExpBuffer(&conninfo_buf);
- for (option = connOptions; option && option->keyword; option++)
- {
- /* Omit empty settings and those libpqwalreceiver overrides. */
- if (strcmp(option->keyword, "replication") == 0 ||
- strcmp(option->keyword, "dbname") == 0 ||
- strcmp(option->keyword, "fallback_application_name") == 0 ||
- (option->val == NULL) ||
- (option->val != NULL && option->val[0] == '\0'))
- continue;
-
- /* Separate key-value pairs with spaces */
- if (conninfo_buf.len != 0)
- appendPQExpBufferChar(&conninfo_buf, ' ');
-
- /*
- * Write "keyword=value" pieces, the value string is escaped and/or
- * quoted if necessary.
- */
- appendPQExpBuffer(&conninfo_buf, "%s=", option->keyword);
- appendConnStrVal(&conninfo_buf, option->val);
- }
-
- /*
- * Escape the connection string, so that it can be put in the config file.
- * Note that this is different from the escaping of individual connection
- * options above!
- */
- escaped = escape_quotes(conninfo_buf.data);
- appendPQExpBuffer(recoveryconfcontents, "primary_conninfo = '%s'\n", escaped);
- free(escaped);
-
- if (replication_slot)
- {
- /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
- appendPQExpBuffer(recoveryconfcontents, "primary_slot_name = '%s'\n",
- replication_slot);
- }
-
- if (PQExpBufferBroken(recoveryconfcontents) ||
- PQExpBufferDataBroken(conninfo_buf))
- {
- pg_log_error("out of memory");
- exit(1);
- }
-
- termPQExpBuffer(&conninfo_buf);
-
- PQconninfoFree(connOptions);
-}
-
-
-/*
- * Write the configuration file into the directory specified in basedir,
- * with the contents already collected in memory appended. Then write
- * the signal file into the basedir. If the server does not support
- * recovery parameters as GUCs, the signal file is not necessary, and
- * configuration is written to recovery.conf.
- */
-static void
-WriteRecoveryConf(void)
-{
- char filename[MAXPGPATH];
- FILE *cf;
- bool is_recovery_guc_supported = true;
-
- if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
- is_recovery_guc_supported = false;
-
- snprintf(filename, MAXPGPATH, "%s/%s", basedir,
- is_recovery_guc_supported ? "postgresql.auto.conf" : "recovery.conf");
-
- cf = fopen(filename, is_recovery_guc_supported ? "a" : "w");
- if (cf == NULL)
- {
- pg_log_error("could not open file \"%s\": %m", filename);
- exit(1);
- }
-
- if (fwrite(recoveryconfcontents->data, recoveryconfcontents->len, 1, cf) != 1)
- {
- pg_log_error("could not write to file \"%s\": %m", filename);
- exit(1);
- }
-
- fclose(cf);
-
- if (is_recovery_guc_supported)
- {
- snprintf(filename, MAXPGPATH, "%s/%s", basedir, "standby.signal");
- cf = fopen(filename, "w");
- if (cf == NULL)
- {
- pg_log_error("could not create file \"%s\": %m", filename);
- exit(1);
- }
-
- fclose(cf);
- }
-}
-
static void
BaseBackup(void)
@@ -1843,7 +1687,7 @@ BaseBackup(void)
* Build contents of configuration file if requested
*/
if (writerecoveryconf)
- GenerateRecoveryConf(conn);
+ recoveryconfcontents = GenerateRecoveryConfig(conn, replication_slot);
/*
* Run IDENTIFY_SYSTEM so we can get the timeline
diff --git a/src/fe_utils/Makefile b/src/fe_utils/Makefile
index 7d738003237..f2e516a2aa3 100644
--- a/src/fe_utils/Makefile
+++ b/src/fe_utils/Makefile
@@ -19,7 +19,8 @@ include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
-OBJS = mbprint.o print.o psqlscan.o simple_list.o string_utils.o conditional.o
+OBJS = conditional.o mbprint.o print.o psqlscan.o recovery_gen.o \
+ simple_list.o string_utils.o
all: libpgfeutils.a
diff --git a/src/fe_utils/recovery_gen.c b/src/fe_utils/recovery_gen.c
new file mode 100644
index 00000000000..6641f95f071
--- /dev/null
+++ b/src/fe_utils/recovery_gen.c
@@ -0,0 +1,176 @@
+/*-------------------------------------------------------------------------
+ *
+ * recovery_gen.c
+ * Generator for recovery configuration
+ *
+ * Portions Copyright (c) 2011-2019, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include "common/logging.h"
+#include "fe_utils/string_utils.h"
+#include "fe_utils/recovery_gen.h"
+
+
+static char *escape_quotes(const char *src);
+
+/*
+ * Write recovery configuration contents into a fresh PQExpBuffer, and
+ * return it.
+ */
+PQExpBuffer
+GenerateRecoveryConfig(PGconn *pgconn, char *replication_slot)
+{
+ PQconninfoOption *connOptions;
+ PQExpBufferData conninfo_buf;
+ char *escaped;
+ PQExpBuffer contents;
+
+ Assert(pgconn != NULL);
+
+ contents = createPQExpBuffer();
+ if (!contents)
+ {
+ pg_log_error("out of memory");
+ exit(1);
+ }
+
+ /*
+ * In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
+ * standby.signal to trigger a standby state at recovery.
+ */
+ if (PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
+ appendPQExpBufferStr(contents, "standby_mode = 'on'\n");
+
+ connOptions = PQconninfo(pgconn);
+ if (connOptions == NULL)
+ {
+ pg_log_error("out of memory");
+ exit(1);
+ }
+
+ initPQExpBuffer(&conninfo_buf);
+ for (PQconninfoOption *opt = connOptions; opt && opt->keyword; opt++)
+ {
+ /* Omit empty settings and those libpqwalreceiver overrides. */
+ if (strcmp(opt->keyword, "replication") == 0 ||
+ strcmp(opt->keyword, "dbname") == 0 ||
+ strcmp(opt->keyword, "fallback_application_name") == 0 ||
+ (opt->val == NULL) ||
+ (opt->val != NULL && opt->val[0] == '\0'))
+ continue;
+
+ /* Separate key-value pairs with spaces */
+ if (conninfo_buf.len != 0)
+ appendPQExpBufferChar(&conninfo_buf, ' ');
+
+ /*
+ * Write "keyword=value" pieces, the value string is escaped and/or
+ * quoted if necessary.
+ */
+ appendPQExpBuffer(&conninfo_buf, "%s=", opt->keyword);
+ appendConnStrVal(&conninfo_buf, opt->val);
+ }
+ if (PQExpBufferDataBroken(conninfo_buf))
+ {
+ pg_log_error("out of memory");
+ exit(1);
+ }
+
+ /*
+ * Escape the connection string, so that it can be put in the config file.
+ * Note that this is different from the escaping of individual connection
+ * options above!
+ */
+ escaped = escape_quotes(conninfo_buf.data);
+ termPQExpBuffer(&conninfo_buf);
+ appendPQExpBuffer(contents, "primary_conninfo = '%s'\n", escaped);
+ free(escaped);
+
+ if (replication_slot)
+ {
+ /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
+ appendPQExpBuffer(contents, "primary_slot_name = '%s'\n",
+ replication_slot);
+ }
+
+ if (PQExpBufferBroken(contents))
+ {
+ pg_log_error("out of memory");
+ exit(1);
+ }
+
+ PQconninfoFree(connOptions);
+
+ return contents;
+}
+
+/*
+ * Write the configuration file in the directory specified in target_dir,
+ * with the contents already collected in memory appended. Then write
+ * the signal file into the target_dir. If the server does not support
+ * recovery parameters as GUCs, the signal file is not necessary, and
+ * configuration is written to recovery.conf.
+ */
+void
+WriteRecoveryConfig(PGconn *pgconn, char *target_dir, PQExpBuffer contents)
+{
+ char filename[MAXPGPATH];
+ FILE *cf;
+ bool use_recovery_conf;
+
+ Assert(pgconn != NULL);
+
+ use_recovery_conf =
+ PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC;
+
+ snprintf(filename, MAXPGPATH, "%s/%s", target_dir,
+ use_recovery_conf ? "recovery.conf" : "postgresql.auto.conf");
+
+ cf = fopen(filename, use_recovery_conf ? "a" : "w");
+ if (cf == NULL)
+ {
+ pg_log_error("could not open file \"%s\": %m", filename);
+ exit(1);
+ }
+
+ if (fwrite(contents->data, contents->len, 1, cf) != 1)
+ {
+ pg_log_error("could not write to file \"%s\": %m", filename);
+ exit(1);
+ }
+
+ fclose(cf);
+
+ if (!use_recovery_conf)
+ {
+ snprintf(filename, MAXPGPATH, "%s/%s", target_dir, "standby.signal");
+ cf = fopen(filename, "w");
+ if (cf == NULL)
+ {
+ pg_log_error("could not create file \"%s\": %m", filename);
+ exit(1);
+ }
+
+ fclose(cf);
+ }
+}
+
+/*
+ * Escape a string so that it can be used as a value in a key-value pair
+ * a configuration file.
+ */
+static char *
+escape_quotes(const char *src)
+{
+ char *result = escape_single_quotes_ascii(src);
+
+ if (!result)
+ {
+ pg_log_error("out of memory");
+ exit(1);
+ }
+ return result;
+}
diff --git a/src/include/fe_utils/recovery_gen.h b/src/include/fe_utils/recovery_gen.h
new file mode 100644
index 00000000000..8b15307dfb8
--- /dev/null
+++ b/src/include/fe_utils/recovery_gen.h
@@ -0,0 +1,28 @@
+/*-------------------------------------------------------------------------
+ *
+ * Generator for recovery configuration
+ *
+ * Portions Copyright (c) 2011-2019, PostgreSQL Global Development Group
+ *
+ * src/include/fe_utils/recovery_gen.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef RECOVERY_GEN_H
+#define RECOVERY_GEN_H
+
+#include "libpq-fe.h"
+#include "pqexpbuffer.h"
+
+/*
+ * recovery configuration is part of postgresql.conf in version 12 and up, and
+ * in recovery.conf before that.
+ */
+#define MINIMUM_VERSION_FOR_RECOVERY_GUC 120000
+
+extern PQExpBuffer GenerateRecoveryConfig(PGconn *pgconn,
+ char *pg_replication_slot);
+extern void WriteRecoveryConfig(PGconn *pgconn, char *target_dir,
+ PQExpBuffer contents);
+
+#endif /* RECOVERY_GEN_H */
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 00b2bc25e50..7a103e61406 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -142,7 +142,8 @@ sub mkvcbuild
our @pgcommonbkndfiles = @pgcommonallfiles;
our @pgfeutilsfiles = qw(
- conditional.c mbprint.c print.c psqlscan.l psqlscan.c simple_list.c string_utils.c);
+ conditional.c mbprint.c print.c psqlscan.l psqlscan.c
+ simple_list.c string_utils.c recovery_gen.c);
$libpgport = $solution->AddProject('libpgport', 'lib', 'misc');
$libpgport->AddDefine('FRONTEND');