]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Honor GUC settings specified in CREATE SUBSCRIPTION CONNECTION.
authorFujii Masao <fujii@postgresql.org>
Tue, 6 Jan 2026 02:52:22 +0000 (11:52 +0900)
committerFujii Masao <fujii@postgresql.org>
Tue, 6 Jan 2026 02:52:22 +0000 (11:52 +0900)
Prior to v15, GUC settings supplied in the CONNECTION clause of
CREATE SUBSCRIPTION were correctly passed through to
the publisher's walsender. For example:

        CREATE SUBSCRIPTION mysub
            CONNECTION 'options=''-c wal_sender_timeout=1000'''
            PUBLICATION ...

would cause wal_sender_timeout to take effect on the publisher's walsender.

However, commit f3d4019da5d changed the way logical replication
connections are established, forcing the publisher's relevant
GUC settings (datestyle, intervalstyle, extra_float_digits) to
override those provided in the CONNECTION string. As a result,
from v15 through v18, GUC settings in the CONNECTION string were
always ignored.

This regression prevented per-connection tuning of logical replication.
For example, using a shorter timeout for walsender connecting
to a nearby subscriber and a longer one for walsender connecting
to a remote subscriber.

This commit restores the intended behavior by ensuring that
GUC settings in the CONNECTION string are again passed through
and applied by the walsender, allowing per-connection configuration.

Backpatch to v15, where the regression was introduced.

Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <lic@highgo.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Japin Li <japinli@hotmail.com>
Discussion: https://postgr.es/m/CAHGQGwGYV+-abbKwdrM2UHUe-JYOFWmsrs6=QicyJO-j+-Widw@mail.gmail.com
Backpatch-through: 15

src/backend/replication/libpqwalreceiver/libpqwalreceiver.c

index 14e1d212a2b71d442e139b8f4efe74a892541f9b..7c8639b32e9e6e57b2964d355c3f72c0653b0870 100644 (file)
@@ -65,6 +65,8 @@ static void libpqrcv_get_senderinfo(WalReceiverConn *conn,
 static char *libpqrcv_identify_system(WalReceiverConn *conn,
                                                                          TimeLineID *primary_tli);
 static char *libpqrcv_get_dbname_from_conninfo(const char *connInfo);
+static char *libpqrcv_get_option_from_conninfo(const char *connInfo,
+                                                                                          const char *keyword);
 static int     libpqrcv_server_version(WalReceiverConn *conn);
 static void libpqrcv_readtimelinehistoryfile(WalReceiverConn *conn,
                                                                                         TimeLineID tli, char **filename,
@@ -150,6 +152,7 @@ libpqrcv_connect(const char *conninfo, bool replication, bool logical,
        const char *keys[6];
        const char *vals[6];
        int                     i = 0;
+       char       *options_val = NULL;
 
        /*
         * Re-validate connection string. The validation already happened at DDL
@@ -177,6 +180,8 @@ libpqrcv_connect(const char *conninfo, bool replication, bool logical,
 
                if (logical)
                {
+                       char       *opt = NULL;
+
                        /* Tell the publisher to translate to our encoding */
                        keys[++i] = "client_encoding";
                        vals[i] = GetDatabaseEncodingName();
@@ -189,8 +194,13 @@ libpqrcv_connect(const char *conninfo, bool replication, bool logical,
                         * running in the subscriber, such as triggers.)  This should
                         * match what pg_dump does.
                         */
+                       opt = libpqrcv_get_option_from_conninfo(conninfo, "options");
+                       options_val = psprintf("%s -c datestyle=ISO -c intervalstyle=postgres -c extra_float_digits=3",
+                                                                  (opt == NULL) ? "" : opt);
                        keys[++i] = "options";
-                       vals[i] = "-c datestyle=ISO -c intervalstyle=postgres -c extra_float_digits=3";
+                       vals[i] = options_val;
+                       if (opt != NULL)
+                               pfree(opt);
                }
                else
                {
@@ -217,6 +227,9 @@ libpqrcv_connect(const char *conninfo, bool replication, bool logical,
                                                                 /* expand_dbname = */ true,
                                                                WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);
 
+       if (options_val != NULL)
+               pfree(options_val);
+
        if (PQstatus(conn->streamConn) != CONNECTION_OK)
                goto bad_connection_errmsg;
 
@@ -460,9 +473,21 @@ libpqrcv_server_version(WalReceiverConn *conn)
  */
 static char *
 libpqrcv_get_dbname_from_conninfo(const char *connInfo)
+{
+       return libpqrcv_get_option_from_conninfo(connInfo, "dbname");
+}
+
+/*
+ * Get the value of the option with the given keyword from the primary
+ * server's conninfo.
+ *
+ * If the option is not found in connInfo, return NULL value.
+ */
+static char *
+libpqrcv_get_option_from_conninfo(const char *connInfo, const char *keyword)
 {
        PQconninfoOption *opts;
-       char       *dbname = NULL;
+       char       *option = NULL;
        char       *err = NULL;
 
        opts = PQconninfoParse(connInfo, &err);
@@ -480,21 +505,21 @@ libpqrcv_get_dbname_from_conninfo(const char *connInfo)
        for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
        {
                /*
-                * If multiple dbnames are specified, then the last one will be
-                * returned
+                * If the same option appears multiple times, then the last one will
+                * be returned
                 */
-               if (strcmp(opt->keyword, "dbname") == 0 && opt->val &&
+               if (strcmp(opt->keyword, keyword) == 0 && opt->val &&
                        *opt->val)
                {
-                       if (dbname)
-                               pfree(dbname);
+                       if (option)
+                               pfree(option);
 
-                       dbname = pstrdup(opt->val);
+                       option = pstrdup(opt->val);
                }
        }
 
        PQconninfoFree(opts);
-       return dbname;
+       return option;
 }
 
 /*