pg_rewind: Add dbname to primary_conninfo when using --write-recovery-conf.
authorMasahiko Sawada <[email protected]>
Wed, 12 Mar 2025 23:56:04 +0000 (16:56 -0700)
committerMasahiko Sawada <[email protected]>
Wed, 12 Mar 2025 23:56:04 +0000 (16:56 -0700)
This commit enhances pg_rewind's --write-recovery-conf option to
include the dbname in the generated primary_conninfo value when
specified in the --source-server option. With this modification, the
rewound server can connect to the primary server without manual
configuration file modifications when sync_replication_slots is
enabled.

Reviewed-by: Hayato Kuroda <[email protected]>
Reviewed-by: Peter Smith <[email protected]>
Discussion: https://postgr.es/m/CAD21AoAkW=Ht0k9dVoBTCcqLiiZ2MXhVr+d=j2T_EZMerGrLWQ@mail.gmail.com

doc/src/sgml/ref/pg_rewind.sgml
src/bin/pg_basebackup/pg_basebackup.c
src/bin/pg_basebackup/streamutil.c
src/bin/pg_basebackup/streamutil.h
src/bin/pg_rewind/pg_rewind.c
src/bin/pg_rewind/t/RewindTest.pm
src/fe_utils/recovery_gen.c
src/include/fe_utils/recovery_gen.h

index dc039d875665a9c0a8b4c19bc6a6e28e96aef7b6..5485033ed8c7c16dbcbeb94b0bad70fe5fe94c5f 100644 (file)
@@ -186,8 +186,10 @@ PostgreSQL documentation
        <para>
         Create <filename>standby.signal</filename> and append connection
         settings to <filename>postgresql.auto.conf</filename> in the output
-        directory.  <literal>--source-server</literal> is mandatory with
-        this option.
+        directory.  The dbname will be recorded only if the dbname was
+        specified explicitly in the connection string or <link linkend="libpq-envars">
+        environment variable</link>. <literal>--source-server</literal> is
+        mandatory with this option.
        </para>
       </listitem>
      </varlistentry>
index dc0c805137aa0ddb8bca906cbb731bd3ee25a4c9..d4b4e3340143ae0d81e871c4baac9a6ffd2f7ae7 100644 (file)
@@ -1818,7 +1818,7 @@ BaseBackup(char *compression_algorithm, char *compression_detail,
    if (writerecoveryconf)
        recoveryconfcontents = GenerateRecoveryConfig(conn,
                                                      replication_slot,
-                                                     GetDbnameFromConnectionOptions());
+                                                     GetDbnameFromConnectionOptions(connection_string));
 
    /*
     * Run IDENTIFY_SYSTEM so we can get the timeline
index 021ab61fcb0f83101b16f7910d4c3bf07cdce35c..8e605f43ffef0e23ec665d4753a2f9a37961642b 100644 (file)
@@ -32,7 +32,6 @@
 int            WalSegSz;
 
 static bool RetrieveDataDirCreatePerm(PGconn *conn);
-static char *FindDbnameInConnParams(PQconninfoOption *conn_opts);
 
 /* SHOW command for replication connection was introduced in version 10 */
 #define MINIMUM_VERSION_FOR_SHOW_CMD 100000
@@ -269,74 +268,6 @@ GetConnection(void)
    return tmpconn;
 }
 
-/*
- * FindDbnameInConnParams
- *
- * This is a helper function for GetDbnameFromConnectionOptions(). Extract
- * the value of dbname from PQconninfoOption parameters, if it's present.
- * Returns a strdup'd result or NULL.
- */
-static char *
-FindDbnameInConnParams(PQconninfoOption *conn_opts)
-{
-   PQconninfoOption *conn_opt;
-
-   for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
-   {
-       if (strcmp(conn_opt->keyword, "dbname") == 0 &&
-           conn_opt->val != NULL && conn_opt->val[0] != '\0')
-           return pg_strdup(conn_opt->val);
-   }
-   return NULL;
-}
-
-/*
- * GetDbnameFromConnectionOptions
- *
- * This is a special purpose function to retrieve the dbname from either the
- * connection_string specified by the user or from the environment variables.
- *
- * We follow GetConnection() to fetch the dbname from various connection
- * options.
- *
- * Returns NULL, if dbname is not specified by the user in the above
- * mentioned connection options.
- */
-char *
-GetDbnameFromConnectionOptions(void)
-{
-   PQconninfoOption *conn_opts;
-   char       *err_msg = NULL;
-   char       *dbname;
-
-   /* First try to get the dbname from connection string. */
-   if (connection_string)
-   {
-       conn_opts = PQconninfoParse(connection_string, &err_msg);
-       if (conn_opts == NULL)
-           pg_fatal("%s", err_msg);
-
-       dbname = FindDbnameInConnParams(conn_opts);
-
-       PQconninfoFree(conn_opts);
-       if (dbname)
-           return dbname;
-   }
-
-   /*
-    * Next try to get the dbname from default values that are available from
-    * the environment.
-    */
-   conn_opts = PQconndefaults();
-   if (conn_opts == NULL)
-       pg_fatal("out of memory");
-
-   dbname = FindDbnameInConnParams(conn_opts);
-
-   PQconninfoFree(conn_opts);
-   return dbname;
-}
-
 /*
  * From version 10, explicitly set wal segment size using SHOW wal_segment_size
  * since ControlFile is not accessible here.
index 472193e239f82219373c6c570cd1ec5fd8ae023a..f917c43517fefa20f226aa5a291209e2b07ce8c7 100644 (file)
@@ -31,8 +31,6 @@ extern PGconn *conn;
 
 extern PGconn *GetConnection(void);
 
-extern char *GetDbnameFromConnectionOptions(void);
-
 /* Replication commands */
 extern bool CreateReplicationSlot(PGconn *conn, const char *slot_name,
                                  const char *plugin, bool is_temporary,
index 2ce99d06d1d96f6fcb3ce04748876f4fdeaaa65a..2c8b1a070077f86af9b7349e657a238eda9dcbdb 100644 (file)
@@ -451,7 +451,8 @@ main(int argc, char **argv)
        pg_log_info("no rewind required");
        if (writerecoveryconf && !dry_run)
            WriteRecoveryConfig(conn, datadir_target,
-                               GenerateRecoveryConfig(conn, NULL, NULL));
+                               GenerateRecoveryConfig(conn, NULL,
+                                                      GetDbnameFromConnectionOptions(connstr_source)));
        exit(0);
    }
 
@@ -528,7 +529,8 @@ main(int argc, char **argv)
    /* Also update the standby configuration, if requested. */
    if (writerecoveryconf && !dry_run)
        WriteRecoveryConfig(conn, datadir_target,
-                           GenerateRecoveryConfig(conn, NULL, NULL));
+                           GenerateRecoveryConfig(conn, NULL,
+                                                  GetDbnameFromConnectionOptions(connstr_source)));
 
    /* don't need the source connection anymore */
    source->destroy(source);
index 6115ec21eb9f45bbdb6f1ee4edb4c9699280fba6..ec3b4a519955fab1a80c4da4aa7dfaf3f3c01c06 100644 (file)
@@ -279,6 +279,11 @@ sub run_pg_rewind
            ],
            'pg_rewind remote');
 
+       # Check that pg_rewind with dbname and --write-recovery-conf
+       # wrote the dbname in the generated primary_conninfo value.
+       like(slurp_file("$primary_pgdata/postgresql.auto.conf"),
+            qr/dbname=postgres/m, 'recovery conf file sets dbname');
+
        # Check that standby.signal is here as recovery configuration
        # was requested.
        ok( -e "$primary_pgdata/standby.signal",
index 7c172f65a10411e9d851b275528bbcbbc6277129..e9023584768d5c66cd53ead68d5e709ee7d08ae3 100644 (file)
@@ -14,6 +14,7 @@
 #include "fe_utils/string_utils.h"
 
 static char *escape_quotes(const char *src);
+static char *FindDbnameInConnOpts(PQconninfoOption *conn_opts);
 
 /*
  * Write recovery configuration contents into a fresh PQExpBuffer, and
@@ -168,3 +169,68 @@ escape_quotes(const char *src)
        pg_fatal("out of memory");
    return result;
 }
+
+/*
+ * FindDbnameInConnOpts
+ *
+ * This is a helper function for GetDbnameFromConnectionOptions(). Extract
+ * the value of dbname from PQconninfoOption parameters, if it's present.
+ * Returns a strdup'd result or NULL.
+ */
+static char *
+FindDbnameInConnOpts(PQconninfoOption *conn_opts)
+{
+   for (PQconninfoOption *conn_opt = conn_opts;
+        conn_opt->keyword != NULL;
+        conn_opt++)
+   {
+       if (strcmp(conn_opt->keyword, "dbname") == 0 &&
+           conn_opt->val != NULL && conn_opt->val[0] != '\0')
+           return pg_strdup(conn_opt->val);
+   }
+   return NULL;
+}
+
+/*
+ * GetDbnameFromConnectionOptions
+ *
+ * This is a special purpose function to retrieve the dbname from either the
+ * 'connstr' specified by the caller or from the environment variables.
+ *
+ * Returns NULL, if dbname is not specified by the user in the given
+ * connection options.
+ */
+char *
+GetDbnameFromConnectionOptions(const char *connstr)
+{
+   PQconninfoOption *conn_opts;
+   char       *err_msg = NULL;
+   char       *dbname;
+
+   /* First try to get the dbname from connection string. */
+   if (connstr)
+   {
+       conn_opts = PQconninfoParse(connstr, &err_msg);
+       if (conn_opts == NULL)
+           pg_fatal("%s", err_msg);
+
+       dbname = FindDbnameInConnOpts(conn_opts);
+
+       PQconninfoFree(conn_opts);
+       if (dbname)
+           return dbname;
+   }
+
+   /*
+    * Next try to get the dbname from default values that are available from
+    * the environment.
+    */
+   conn_opts = PQconndefaults();
+   if (conn_opts == NULL)
+       pg_fatal("out of memory");
+
+   dbname = FindDbnameInConnOpts(conn_opts);
+
+   PQconninfoFree(conn_opts);
+   return dbname;
+}
index 6412ffdaffa9e25bcabe39f4b1365e3f07bd3ba7..c13f2263bcd3307c26f2ba87ede3895613fbf7a5 100644 (file)
@@ -25,5 +25,6 @@ extern PQExpBuffer GenerateRecoveryConfig(PGconn *pgconn,
                                          char *dbname);
 extern void WriteRecoveryConfig(PGconn *pgconn, const char *target_dir,
                                PQExpBuffer contents);
+extern char *GetDbnameFromConnectionOptions(const char *connstr);
 
 #endif                         /* RECOVERY_GEN_H */