On 16.03.24 16:42, Euler Taveira wrote:
I'm attaching a new version (v30) that adds:

I have some review comments and attached a patch with some smaller fixups (mainly message wording and avoid fixed-size string buffers).

* doc/src/sgml/ref/pg_createsubscriber.sgml

I would remove the "How It Works" section.  This is not relevant to
users, and it is very detailed and will require updating whenever the
implementation changes.  It could be a source code comment instead.

* src/bin/pg_basebackup/pg_createsubscriber.c

I think the connection string handling is not robust against funny
characters, like spaces, in database names etc.

Most SQL commands need to be amended for proper identifier or string
literal quoting and/or escaping.

In check_subscriber(): All these permissions checks seem problematic
to me.  We shouldn't reimplement our own copy of the server's
permission checks.  The server can check the permissions.  And if the
permission checking in the server ever changes, then we have
inconsistencies to take care of.  Also, the error messages "permission
denied" are inappropriate, because we are not doing the actual thing.
Maybe we want to do a dry-run for the benefit of the user, but then we
should do the actual thing, like try to create a replication slot, or
whatever.  But I would rather just remove all this, it seems too
problematic.

In main(): The first check if the standby is running is problematic.
I think it would be better to require that the standby is initially
shut down.  Consider, the standby might be running under systemd.
This tool will try to stop it, systemd will try to restart it.  Let's
avoid these kinds of battles.  It's also safer if we don't try to
touch running servers.

The -p option (--subscriber-port) doesn't seem to do anything.  In my
testing, it always uses the compiled-in default port.

Printing all the server log lines to the terminal doesn't seem very
user-friendly. Not sure what to do about that, short of keeping a pg_upgrade-style directory of log files. But it's ugly.

From ec8e6ed6c3325a6f9fde2d1632346e212ade9c9f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 18 Mar 2024 14:48:55 +0100
Subject: [PATCH] Various improvements

---
 src/bin/pg_basebackup/Makefile              |  2 +-
 src/bin/pg_basebackup/nls.mk                |  1 +
 src/bin/pg_basebackup/pg_createsubscriber.c | 49 +++++++++------------
 3 files changed, 23 insertions(+), 29 deletions(-)

diff --git a/src/bin/pg_basebackup/Makefile b/src/bin/pg_basebackup/Makefile
index e9a920dbcda..26c53e473f5 100644
--- a/src/bin/pg_basebackup/Makefile
+++ b/src/bin/pg_basebackup/Makefile
@@ -49,7 +49,7 @@ all: pg_basebackup pg_createsubscriber pg_receivewal 
pg_recvlogical
 pg_basebackup: $(BBOBJS) $(OBJS) | submake-libpq submake-libpgport 
submake-libpgfeutils
        $(CC) $(CFLAGS) $(BBOBJS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o 
$@$(X)
 
-pg_createsubscriber: $(WIN32RES) pg_createsubscriber.o | submake-libpq 
submake-libpgport submake-libpgfeutils
+pg_createsubscriber: pg_createsubscriber.o $(WIN32RES) | submake-libpq 
submake-libpgport submake-libpgfeutils
        $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 pg_receivewal: pg_receivewal.o $(OBJS) | submake-libpq submake-libpgport 
submake-libpgfeutils
diff --git a/src/bin/pg_basebackup/nls.mk b/src/bin/pg_basebackup/nls.mk
index fc475003e8e..7870cea71ce 100644
--- a/src/bin/pg_basebackup/nls.mk
+++ b/src/bin/pg_basebackup/nls.mk
@@ -8,6 +8,7 @@ GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) \
                    bbstreamer_tar.c \
                    bbstreamer_zstd.c \
                    pg_basebackup.c \
+                   pg_createsubscriber.c \
                    pg_receivewal.c \
                    pg_recvlogical.c \
                    receivelog.c \
diff --git a/src/bin/pg_basebackup/pg_createsubscriber.c 
b/src/bin/pg_basebackup/pg_createsubscriber.c
index e24ed7ef506..91c3a2f0036 100644
--- a/src/bin/pg_basebackup/pg_createsubscriber.c
+++ b/src/bin/pg_basebackup/pg_createsubscriber.c
@@ -43,7 +43,7 @@ struct CreateSubscriberOptions
        SimpleStringList sub_names; /* list of subscription names */
        SimpleStringList replslot_names;        /* list of replication slot 
names */
        int                     recovery_timeout;       /* stop recovery after 
this time */
-}                      CreateSubscriberOptions;
+};
 
 struct LogicalRepInfo
 {
@@ -57,7 +57,7 @@ struct LogicalRepInfo
 
        bool            made_replslot;  /* replication slot was created */
        bool            made_publication;       /* publication was created */
-}                      LogicalRepInfo;
+};
 
 static void cleanup_objects_atexit(void);
 static void usage();
@@ -155,9 +155,9 @@ cleanup_objects_atexit(void)
         */
        if (recovery_ended)
        {
-               pg_log_warning("pg_createsubscriber failed after the end of 
recovery");
-               pg_log_warning_hint("The target server cannot be used as a 
physical replica anymore.");
-               pg_log_warning_hint("You must recreate the physical replica 
before continuing.");
+               pg_log_warning("failed after the end of recovery");
+               pg_log_warning_hint("The target server cannot be used as a 
physical replica anymore.  "
+                                                       "You must recreate the 
physical replica before continuing.");
        }
 
        for (int i = 0; i < num_dbs; i++)
@@ -184,13 +184,13 @@ cleanup_objects_atexit(void)
                                 */
                                if (dbinfo[i].made_publication)
                                {
-                                       pg_log_warning("There might be a 
publication \"%s\" in database \"%s\" on primary",
+                                       pg_log_warning("publication \"%s\" in 
database \"%s\" on primary might be left behind",
                                                                   
dbinfo[i].pubname, dbinfo[i].dbname);
                                        pg_log_warning_hint("Consider dropping 
this publication before trying again.");
                                }
                                if (dbinfo[i].made_replslot)
                                {
-                                       pg_log_warning("There might be a 
replication slot \"%s\" in database \"%s\" on primary",
+                                       pg_log_warning("replication slot \"%s\" 
in database \"%s\" on primary might be left behind",
                                                                   
dbinfo[i].replslotname, dbinfo[i].dbname);
                                        pg_log_warning_hint("Drop this 
replication slot soon to avoid retention of WAL files.");
                                }
@@ -420,7 +420,7 @@ store_pub_sub_info(const struct CreateSubscriberOptions 
*opt, const char *pub_ba
        SimpleStringListCell *replslotcell = NULL;
        int                     i = 0;
 
-       dbinfo = (struct LogicalRepInfo *) pg_malloc(num_dbs * sizeof(struct 
LogicalRepInfo));
+       dbinfo = pg_malloc_array(struct LogicalRepInfo, num_dbs);
 
        if (num_pubs > 0)
                pubcell = opt->pub_names.head;
@@ -611,7 +611,7 @@ modify_subscriber_sysid(const struct 
CreateSubscriberOptions *opt)
 
        char       *cmd_str;
 
-       pg_log_info("modifying system identifier from subscriber");
+       pg_log_info("modifying system identifier of subscriber");
 
        cf = get_controlfile(subscriber_dir, &crc_ok);
        if (!crc_ok)
@@ -965,7 +965,7 @@ check_subscriber(const struct LogicalRepInfo *dbinfo)
        /* The target server must be a standby */
        if (!server_is_in_recovery(conn))
        {
-               pg_log_error("The target server must be a standby");
+               pg_log_error("target server must be a standby");
                disconnect_database(conn, true);
        }
 
@@ -1217,13 +1217,11 @@ create_logical_replication_slot(PGconn *conn, struct 
LogicalRepInfo *dbinfo)
 {
        PQExpBuffer str = createPQExpBuffer();
        PGresult   *res = NULL;
-       char            slot_name[NAMEDATALEN];
+       const char *slot_name = dbinfo->replslotname;
        char       *lsn = NULL;
 
        Assert(conn != NULL);
 
-       snprintf(slot_name, NAMEDATALEN, "%s", dbinfo->replslotname);
-
        pg_log_info("creating the replication slot \"%s\" on database \"%s\"",
                                slot_name, dbinfo->dbname);
 
@@ -1451,8 +1449,7 @@ wait_for_end_recovery(const char *conninfo, const struct 
CreateSubscriberOptions
                pg_fatal("server did not end recovery");
 
        pg_log_info("target server reached the consistent state");
-       pg_log_info_hint("If pg_createsubscriber fails after this point, "
-                                        "you must recreate the physical 
replica before continuing.");
+       pg_log_info_hint("If pg_createsubscriber fails after this point, you 
must recreate the physical replica before continuing.");
 }
 
 /*
@@ -1625,8 +1622,8 @@ set_replication_progress(PGconn *conn, const struct 
LogicalRepInfo *dbinfo, cons
        PQExpBuffer str = createPQExpBuffer();
        PGresult   *res;
        Oid                     suboid;
-       char            originname[NAMEDATALEN];
-       char            lsnstr[17 + 1]; /* MAXPG_LSNLEN = 17 */
+       char       *originname;
+       char       *lsnstr;
 
        Assert(conn != NULL);
 
@@ -1653,13 +1650,12 @@ set_replication_progress(PGconn *conn, const struct 
LogicalRepInfo *dbinfo, cons
        if (dry_run)
        {
                suboid = InvalidOid;
-               snprintf(lsnstr, sizeof(lsnstr), "%X/%X",
-                                LSN_FORMAT_ARGS((XLogRecPtr) 
InvalidXLogRecPtr));
+               lsnstr = psprintf("%X/%X", LSN_FORMAT_ARGS((XLogRecPtr) 
InvalidXLogRecPtr));
        }
        else
        {
                suboid = strtoul(PQgetvalue(res, 0, 0), NULL, 10);
-               snprintf(lsnstr, sizeof(lsnstr), "%s", lsn);
+               lsnstr = psprintf("%s", lsn);
        }
 
        PQclear(res);
@@ -1668,7 +1664,7 @@ set_replication_progress(PGconn *conn, const struct 
LogicalRepInfo *dbinfo, cons
         * The origin name is defined as pg_%u. %u is the subscription OID. See
         * ApplyWorkerMain().
         */
-       snprintf(originname, sizeof(originname), "pg_%u", suboid);
+       originname = psprintf("pg_%u", suboid);
 
        pg_log_info("setting the replication progress (node name \"%s\" ; LSN 
%s) on database \"%s\"",
                                originname, lsnstr, dbinfo->dbname);
@@ -1692,6 +1688,8 @@ set_replication_progress(PGconn *conn, const struct 
LogicalRepInfo *dbinfo, cons
                PQclear(res);
        }
 
+       pg_free(originname);
+       pg_free(lsnstr);
        destroyPQExpBuffer(str);
 }
 
@@ -1797,13 +1795,9 @@ main(int argc, char **argv)
        opt.config_file = NULL;
        opt.pub_conninfo_str = NULL;
        opt.socket_dir = NULL;
-       opt.sub_port = palloc(16);
-       strcpy(opt.sub_port, DEFAULT_SUB_PORT);
+       opt.sub_port = DEFAULT_SUB_PORT;
        opt.sub_username = NULL;
-       opt.database_names = (SimpleStringList)
-       {
-               NULL, NULL
-       };
+       opt.database_names = (SimpleStringList){0};
        opt.recovery_timeout = 0;
 
        /*
@@ -1847,7 +1841,6 @@ main(int argc, char **argv)
                                dry_run = true;
                                break;
                        case 'p':
-                               pg_free(opt.sub_port);
                                opt.sub_port = pg_strdup(optarg);
                                break;
                        case 'P':

base-commit: 48018f1d8c12d42b53c2a855626ee1ceb7f4ca71
prerequisite-patch-id: e4c7223061ca1e12dfa84f4a5ccdc3a9ab0c268a
prerequisite-patch-id: 6cc7583799a18d1119c8ecbb400b4471c6873768
-- 
2.44.0

Reply via email to