From 52524a8e63a34c1aebbbdd598f9322409946151f Mon Sep 17 00:00:00 2001 From: "Chao Li (Evan)" Date: Wed, 5 Aug 2026 15:11:13 +0800 Subject: [PATCH v3] pg_createsubscriber: Allow duplicate subscription names Subscription names are database-local, so the same name can be used in different databases. However, pg_createsubscriber rejected duplicate --subscription values unconditionally. Allow duplicate subscription names when distinct replication slot names are specified explicitly. Continue to reject them when --replication-slot is omitted, because subscription names are then reused as replication slot names, which must be unique within a cluster. Add tests and update the documentation. Suggested-by: Amit Kapila Author: Chao Li Reviewed-by: Hayato Kuroda Reviewed-by: Peter Smith Discussion: https://postgr.es/m/2B037930-9B7F-41D3-98B3-E50FFD94C01A@gmail.com --- doc/src/sgml/ref/pg_createsubscriber.sgml | 9 ++++--- src/bin/pg_basebackup/pg_createsubscriber.c | 23 +++++++++++------- .../t/040_pg_createsubscriber.pl | 24 +++++++++++++++---- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/doc/src/sgml/ref/pg_createsubscriber.sgml b/doc/src/sgml/ref/pg_createsubscriber.sgml index 193f60628bc..78a2596f72e 100644 --- a/doc/src/sgml/ref/pg_createsubscriber.sgml +++ b/doc/src/sgml/ref/pg_createsubscriber.sgml @@ -355,14 +355,17 @@ PostgreSQL documentation - The subscription name to set up the logical replication. Multiple + The subscription name to set up the logical replication. This option + cannot be used together with . Multiple subscriptions can be specified by writing multiple switches. The number of subscription names must match the number of specified databases, otherwise an error is reported. The order of the multiple subscription name switches must match the order of database switches. If this option is not specified, - a generated name is assigned to the subscription name. This option cannot - be used together with . + a generated name is assigned to the subscription name. The same + subscription name can be used in different databases only when + replication slot names are specified with + . diff --git a/src/bin/pg_basebackup/pg_createsubscriber.c b/src/bin/pg_basebackup/pg_createsubscriber.c index 20b354aed56..5d834edbe72 100644 --- a/src/bin/pg_basebackup/pg_createsubscriber.c +++ b/src/bin/pg_basebackup/pg_createsubscriber.c @@ -2262,6 +2262,7 @@ main(int argc, char **argv) int c; int option_index; + bool duplicate_sub_names = false; char *pub_base_conninfo; char *sub_base_conninfo; @@ -2394,13 +2395,10 @@ main(int argc, char **argv) pg_fatal("replication slot \"%s\" specified more than once for --replication-slot", optarg); break; case 4: - if (!simple_string_list_member(&opt.sub_names, optarg)) - { - simple_string_list_append(&opt.sub_names, optarg); - num_subs++; - } - else - pg_fatal("subscription \"%s\" specified more than once for --subscription", optarg); + if (!duplicate_sub_names) + duplicate_sub_names = simple_string_list_member(&opt.sub_names, optarg); + simple_string_list_append(&opt.sub_names, optarg); + num_subs++; break; case 5: if (!simple_string_list_member(&opt.objecttypes_to_clean, optarg)) @@ -2580,7 +2578,16 @@ main(int argc, char **argv) num_subs, num_dbs); exit(1); } - if (num_replslots > 0 && num_replslots != num_dbs) + if (num_replslots == 0) + { + if (duplicate_sub_names) + { + pg_log_error("duplicate subscription names require replication slot names"); + pg_log_error_hint("Specify --replication-slot for each database."); + exit(1); + } + } + else if (num_replslots != num_dbs) { pg_log_error("wrong number of replication slot names specified"); pg_log_error_detail("The number of specified replication slot names (%d) must match the number of specified database names (%d).", diff --git a/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl b/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl index 9252d1c3c5c..7b381637574 100644 --- a/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl +++ b/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl @@ -91,6 +91,19 @@ command_fails( '--database' => 'pg2', ], 'wrong number of subscription names'); +command_fails_like( + [ + 'pg_createsubscriber', + '--verbose', + '--pgdata' => $datadir, + '--publisher-server' => 'port=5432', + '--subscription' => 'bar1', + '--subscription' => 'bar1', + '--database' => 'pg1', + '--database' => 'pg2', + ], + qr/duplicate subscription names require replication slot names/, + 'duplicate subscription names without replication slot names'); command_fails( [ 'pg_createsubscriber', @@ -334,8 +347,9 @@ is($node_s->safe_psql($db1, "SELECT COUNT(*) FROM pg_publication"), $node_s->stop; -# dry run mode on node S. Use the same publication name for different -# databases, since publication names are database-local. +# dry run mode on node S. Use the same publication and subscription names for +# different databases, since both names are database-local. Replication slot +# names are specified because replication slots are cluster-global. command_ok( [ 'pg_createsubscriber', @@ -348,8 +362,10 @@ command_ok( '--subscriber-port' => $node_s->port, '--publication' => 'same_pub', '--publication' => 'same_pub', - '--subscription' => 'sub1', - '--subscription' => 'sub2', + '--subscription' => 'same_sub', + '--subscription' => 'same_sub', + '--replication-slot' => 'slot1', + '--replication-slot' => 'slot2', '--database' => $db1, '--database' => $db2, '--logdir' => $logdir, -- 2.50.1 (Apple Git-155)