From baed4d6390737c4274cd4dc1c21d7bf488c673d4 Mon Sep 17 00:00:00 2001 From: Alena Vinter Date: Tue, 2 Sep 2025 18:15:13 +0700 Subject: [PATCH 2/2] 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 | 77 +++++++++++++++++++++++++++++ src/include/fe_utils/recovery_gen.h | 3 ++ 2 files changed, 80 insertions(+) diff --git a/src/fe_utils/recovery_gen.c b/src/fe_utils/recovery_gen.c index e9023584768..e8e0dde9e00 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,79 @@ GetDbnameFromConnectionOptions(const char *connstr) PQconninfoFree(conn_opts); return dbname; } + +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); + + 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; +} + +void +ReplaceRecoveryConfig(PGconn *pgconn, const char *target_dir, PQExpBuffer contents) +{ + char tmp_filename[MAXPGPATH]; + char filename[MAXPGPATH]; + FILE *cf; + bool use_recovery_conf; + + Assert(pgconn != NULL); + + use_recovery_conf = + PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC; + + snprintf(tmp_filename, MAXPGPATH, "%s/%s.tmp", target_dir, + use_recovery_conf ? "recovery.conf" : "postgresql.auto.conf"); + + snprintf(filename, MAXPGPATH, "%s/%s", target_dir, + use_recovery_conf ? "recovery.conf" : "postgresql.auto.conf"); + + 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); + + 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