v7-0001-Implements-helper-function-in-recovery_gen.patch
text/x-patch
Filename: v7-0001-Implements-helper-function-in-recovery_gen.patch
Type: text/x-patch
Part: 2
From 29d3f5f7abc730112e8770d3da84232af4754c46 Mon Sep 17 00:00:00 2001
From: Alena Vinter <dlaaren8@gmail.com>
Date: Tue, 2 Sep 2025 18:15:13 +0700
Subject: [PATCH 1/3] Implements helper function in recovery_gen
These functions support pg_createsubscriber's need to temporarily
configure recovery params and ensure proper cleanup after the conversion
to logical replication is complete.
---
src/fe_utils/recovery_gen.c | 113 ++++++++++++++++++++++++++++
src/include/fe_utils/recovery_gen.h | 4 +
2 files changed, 117 insertions(+)
diff --git a/src/fe_utils/recovery_gen.c b/src/fe_utils/recovery_gen.c
index e9023584768..e2e501ce693 100644
--- a/src/fe_utils/recovery_gen.c
+++ b/src/fe_utils/recovery_gen.c
@@ -9,7 +9,9 @@
*/
#include "postgres_fe.h"
+#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"
@@ -234,3 +236,114 @@ GetDbnameFromConnectionOptions(const char *connstr)
PQconninfoFree(conn_opts);
return dbname;
}
+
+/*
+ * GetRecoveryConfig
+ *
+ * Reads the recovery configuration file from the target server's data directory
+ * and returns its contents as a PQExpBuffer.
+ */
+PQExpBuffer
+GetRecoveryConfig(PGconn *pgconn, const char *target_dir)
+{
+ PQExpBuffer contents;
+ char filename[MAXPGPATH];
+ FILE *cf;
+ char *line;
+ bool use_recovery_conf;
+
+ Assert(pgconn != NULL);
+
+ contents = createPQExpBuffer();
+ if (!contents)
+ pg_fatal("out of memory");
+
+ 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, "r");
+ if (cf == NULL)
+ pg_fatal("could not open file \"%s\": %m", filename);
+
+ /* Read file contents line-by-line and append to the buffer */
+ while ((line = pg_get_line(cf, NULL)) != NULL)
+ {
+ appendPQExpBufferStr(contents, line);
+ }
+
+ if (ferror(cf))
+ {
+ pg_fatal("could not read from file \"%s\": %m", filename);
+ }
+
+ fclose(cf);
+
+ return contents;
+}
+
+/*
+ * ReplaceRecoveryConfig
+ *
+ * Replaces the recovery configuration file on the target server with new contents.
+ *
+ * The operation is performed atomically by writing to a temporary file first,
+ * then renaming it to the final filename.
+ *
+ * Returns false if an error occurs. In case of error, a temporary file may
+ * still be present on the server.
+ */
+bool
+ReplaceRecoveryConfig(int version, const char *target_dir, PQExpBuffer contents)
+{
+ char tmp_filename[MAXPGPATH];
+ char filename[MAXPGPATH];
+ FILE *cf;
+ const char *config_filename;
+
+ config_filename =
+ (version < MINIMUM_VERSION_FOR_RECOVERY_GUC)
+ ? "recovery.conf"
+ : "postgresql.auto.conf";
+
+ /*
+ * Construct full paths for the configuration file and its temporary
+ * version
+ */
+ snprintf(filename, MAXPGPATH, "%s/%s", target_dir, config_filename);
+ snprintf(tmp_filename, MAXPGPATH, "%s.tmp", filename);
+
+ /*
+ * Open temporary file for writing. Mode "w" ensures the file is recreated
+ * if it already exists.
+ */
+ cf = fopen(tmp_filename, "w");
+ if (cf == NULL)
+ {
+ pg_log_error("could not open file \"%s\": %m", tmp_filename);
+ return false;
+ }
+
+ if (fwrite(contents->data, contents->len, 1, cf) != 1)
+ {
+ pg_log_error("could not write to file \"%s\": %m", tmp_filename);
+ return false;
+ }
+
+ fclose(cf);
+
+ /*
+ * Atomically replace the old configuration file with the new one by
+ * renaming the temporary file to the final filename.
+ */
+ if (durable_rename(tmp_filename, filename) != 0)
+ {
+ pg_log_error("could not rename file \"%s\" to \"%s\": %m",
+ tmp_filename, filename);
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/include/fe_utils/recovery_gen.h b/src/include/fe_utils/recovery_gen.h
index c13f2263bcd..b54397db740 100644
--- a/src/include/fe_utils/recovery_gen.h
+++ b/src/include/fe_utils/recovery_gen.h
@@ -27,4 +27,8 @@ extern void WriteRecoveryConfig(PGconn *pgconn, const char *target_dir,
PQExpBuffer contents);
extern char *GetDbnameFromConnectionOptions(const char *connstr);
+extern PQExpBuffer GetRecoveryConfig(PGconn *pgconn, const char *target_dir);
+extern bool ReplaceRecoveryConfig(int version, const char *target_dir,
+ PQExpBuffer contents);
+
#endif /* RECOVERY_GEN_H */
--
2.51.0