v5-0001-Implements-helper-function-in-recovery_gen.patch
text/x-patch
Filename: v5-0001-Implements-helper-function-in-recovery_gen.patch
Type: text/x-patch
Part: 1
From 5480fe56ec6b7f51797c2a9566dc555243ad9549 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 | 101 ++++++++++++++++++++++++++++
src/include/fe_utils/recovery_gen.h | 3 +
2 files changed, 104 insertions(+)
diff --git a/src/fe_utils/recovery_gen.c b/src/fe_utils/recovery_gen.c
index e9023584768..f5e9e968863 100644
--- a/src/fe_utils/recovery_gen.c
+++ b/src/fe_utils/recovery_gen.c
@@ -10,6 +10,7 @@
#include "postgres_fe.h"
#include "common/logging.h"
+#include "common/file_utils.h"
#include "fe_utils/recovery_gen.h"
#include "fe_utils/string_utils.h"
@@ -234,3 +235,103 @@ 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;
+ bool use_recovery_conf;
+
+ char data[1024];
+ size_t bytes_read;
+
+ 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 in chunks and append to the buffer */
+ while ((bytes_read = fread(data, 1, sizeof(data), cf)) > 0)
+ {
+ data[bytes_read] = '\0';
+ appendPQExpBufferStr(contents, data);
+ }
+
+ 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.
+ */
+void
+ReplaceRecoveryConfig(PGconn *pgconn, const char *target_dir, PQExpBuffer contents)
+{
+ char tmp_filename[MAXPGPATH];
+ char filename[MAXPGPATH];
+ FILE *cf;
+ const char *config_filename =
+ (PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
+ ? "recovery.conf"
+ : "postgresql.auto.conf";
+
+ Assert(pgconn != NULL);
+
+ /*
+ * 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_fatal("could not open file \"%s\": %m", tmp_filename);
+
+ if (fwrite(contents->data, contents->len, 1, cf) != 1)
+ pg_fatal("could not write to file \"%s\": %m", tmp_filename);
+
+ 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_fatal("could not rename file \"%s\" to \"%s\": %m",
+ tmp_filename, filename);
+}
diff --git a/src/include/fe_utils/recovery_gen.h b/src/include/fe_utils/recovery_gen.h
index c13f2263bcd..18219af966b 100644
--- a/src/include/fe_utils/recovery_gen.h
+++ b/src/include/fe_utils/recovery_gen.h
@@ -27,4 +27,7 @@ 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 void ReplaceRecoveryConfig(PGconn *pgconn, const char *target_dir, PQExpBuffer contents);
+
#endif /* RECOVERY_GEN_H */
--
2.51.0