From 456431823892fe98df3fcfa30d8b8c08006d88e6 Mon Sep 17 00:00:00 2001
From: Srinath Reddy Sadipiralla <srinath2133@gmail.com>
Date: Wed, 3 Jun 2026 10:29:30 +0530
Subject: [PATCH] Reject the "pgrepack" output plugin outside REPACK
 (CONCURRENTLY)

The "pgrepack" output plugin is an internal component of REPACK
(CONCURRENTLY) and is not meant to be driven through the generic logical
decoding interface.

---
 contrib/test_decoding/expected/repack.out |  5 +++++
 contrib/test_decoding/sql/repack.sql      |  4 ++++
 src/backend/replication/slotfuncs.c       | 14 ++++++++++++++
 src/backend/replication/walsender.c       | 10 ++++++++++
 4 files changed, 33 insertions(+)

diff --git a/contrib/test_decoding/expected/repack.out b/contrib/test_decoding/expected/repack.out
index 6204e620b43..2732561281b 100644
--- a/contrib/test_decoding/expected/repack.out
+++ b/contrib/test_decoding/expected/repack.out
@@ -99,5 +99,10 @@ REPACK (CONCURRENTLY) repack_conc_replident;
 ERROR:  cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident"
 DETAIL:  REPACK (CONCURRENTLY) does not support deferrable primary keys.
 HINT:  Use ALTER TABLE ... REPLICA IDENTITY USING INDEX to designate another index as replica identity.
+-- The "pgrepack" output plugin is internal to REPACK (CONCURRENTLY); it cannot
+-- be selected through the generic logical decoding interface (bug #19500).
+SELECT pg_create_logical_replication_slot('repack_misuse_slot', 'pgrepack');
+ERROR:  output plugin "pgrepack" cannot be used through the logical decoding interface
+DETAIL:  This output plugin is reserved for internal use by REPACK (CONCURRENTLY).
 -- clean up
 DROP TABLE repack_conc_replident, clstrpart;
diff --git a/contrib/test_decoding/sql/repack.sql b/contrib/test_decoding/sql/repack.sql
index cea3bd33689..a7cb615e55d 100644
--- a/contrib/test_decoding/sql/repack.sql
+++ b/contrib/test_decoding/sql/repack.sql
@@ -73,5 +73,9 @@ REPACK (CONCURRENTLY) repack_conc_replident;
 ALTER TABLE repack_conc_replident ADD PRIMARY KEY (i) DEFERRABLE;
 REPACK (CONCURRENTLY) repack_conc_replident;
 
+-- The "pgrepack" output plugin is internal to REPACK (CONCURRENTLY); it cannot
+-- be selected through the generic logical decoding interface (bug #19500).
+SELECT pg_create_logical_replication_slot('repack_misuse_slot', 'pgrepack');
+
 -- clean up
 DROP TABLE repack_conc_replident, clstrpart;
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 16fbd383735..17548abf601 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -136,6 +136,20 @@ create_logical_replication_slot(char *name, char *plugin,
 
 	Assert(!MyReplicationSlot);
 
+	/*
+	 * The "pgrepack" output plugin is for internal use by REPACK
+	 * (CONCURRENTLY) only.  Reject it here so that misuse through the SQL
+	 * interface fails immediately with a clear message, instead of being
+	 * caught later (and only after some decoding work) by the plugin's own
+	 * magic-number check in its begin callback.  REPACK creates its slot
+	 * directly via ReplicationSlotCreate(), so it is unaffected.
+	 */
+	if (strcmp(plugin, "pgrepack") == 0)
+		ereport(ERROR,
+				errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				errmsg("output plugin \"pgrepack\" cannot be used through the logical decoding interface"),
+				errdetail("This output plugin is reserved for internal use by REPACK (CONCURRENTLY)."));
+
 	/*
 	 * Acquire a logical decoding slot, this will check for conflicting names.
 	 * Initially create persistent slot as ephemeral - that allows us to
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 04aa770d981..b9e52a20173 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1270,6 +1270,16 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
 
 		CheckLogicalDecodingRequirements(false);
 
+		/*
+		 * The "pgrepack" output plugin is reserved for REPACK (CONCURRENTLY);
+		 * reject it here too (see create_logical_replication_slot()).
+		 */
+		if (strcmp(cmd->plugin, "pgrepack") == 0)
+			ereport(ERROR,
+					errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					errmsg("output plugin \"pgrepack\" cannot be used through the logical decoding interface"),
+					errdetail("This output plugin is reserved for internal use by REPACK (CONCURRENTLY)."));
+
 		/*
 		 * Initially create persistent slot as ephemeral - that allows us to
 		 * nicely handle errors during initialization because it'll get
-- 
2.43.0

