On Tue, Nov 12, 2024 at 3:30 PM Dickson S. Guedes <gue...@guedesoft.net>
wrote:

Are you planning to add changes in docs? Would be important to have
> this clarification in there also, IMHO.
>

Thanks. Here is an updated version of the patch including documentation.
From 80e2894d3289cebd9c12d457620bf2965cc0252d Mon Sep 17 00:00:00 2001
From: Torsten Foertsch <tfoertsch...@gmail.com>
Date: Sat, 16 Nov 2024 12:42:11 +0100
Subject: [PATCH v3] Allow pg_recvlogical to create temp slots

With this patch pg_recvlogical can be called with the
--temporary-slot option together with --create-slot and --start.

If called that way, the created slot exists only for the duration
of the connection. If the connection is dropped and reestablished
by pg_recvlogical, a new temp slot by the same name is created.

If the slot exists and --if-not-exists is not passed, then
pg_recvlogical fails. If the slot exists and --if-not-exists is
given, the slot will be used.

In addition a few tests have been added for previously untested
options.

Discussion: https://www.postgresql.org/message-id/CAKkG4_%3DoMpa-AXhw9m044ZH5YdneNFTp6WxG_kEPA0cTkfiMNQ%40mail.gmail.com
---
 doc/src/sgml/ref/pg_recvlogical.sgml          | 25 +++++++
 src/bin/pg_basebackup/pg_recvlogical.c        | 33 ++++++++--
 src/bin/pg_basebackup/t/030_pg_recvlogical.pl | 65 +++++++++++++++++++
 3 files changed, 117 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/ref/pg_recvlogical.sgml b/doc/src/sgml/ref/pg_recvlogical.sgml
index 95eb14b635..72e9952966 100644
--- a/doc/src/sgml/ref/pg_recvlogical.sgml
+++ b/doc/src/sgml/ref/pg_recvlogical.sgml
@@ -268,6 +268,31 @@ PostgreSQL documentation
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+       <term><option>--temporary-slot</option></term>
+       <listitem>
+       <para>
+        Create a temporary replication slot. This option is only useful if
+        specified together with <option>--create-slot</option> and
+        <option>--start</option>. A temporary slot is automatically dropped
+        when the database connection is dropped.
+       </para>
+       <para>
+        If used together with <option>--if-not-exists</option> and if a
+        permanent slot by the requested name exists, that slot is used instead
+        of creating a new one. That permanent slot is then not automatically
+        removed when the connection is dropped.
+       </para>
+       <para>
+        Unless <option>--no-loop</option> is specified,
+        <command>pg_recvlogical</command> will try to reconnect automatically
+        when the server connection is lost. If a temporary slot is requested,
+        the slot will be recreated first. If at that time another slot by the
+        same name exists, creation will fail.
+       </para>
+       </listitem>
+     </varlistentry>
+
      <varlistentry>
        <term><option>-t</option></term>
        <term><option>--two-phase</option></term>
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 42b2a7bb9d..6ec02e427f 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -48,6 +48,7 @@ static int	fsync_interval = 10 * 1000; /* 10 sec = default */
 static XLogRecPtr startpos = InvalidXLogRecPtr;
 static XLogRecPtr endpos = InvalidXLogRecPtr;
 static bool do_create_slot = false;
+static bool slot_is_temporary = false;
 static bool slot_exists_ok = false;
 static bool do_start_slot = false;
 static bool do_drop_slot = false;
@@ -102,6 +103,7 @@ usage(void)
 	printf(_("  -s, --status-interval=SECS\n"
 			 "                         time between status packets sent to server (default: %d)\n"), (standby_message_timeout / 1000));
 	printf(_("  -S, --slot=SLOTNAME    name of the logical replication slot\n"));
+	printf(_("      --temporary-slot   the slot created exists until the connection is dropped\n"));
 	printf(_("  -t, --two-phase        enable decoding of prepared transactions when creating a slot\n"));
 	printf(_("  -v, --verbose          output verbose messages\n"));
 	printf(_("  -V, --version          output version information, then exit\n"));
@@ -214,7 +216,7 @@ StreamLogicalLog(void)
 	char	   *copybuf = NULL;
 	TimestampTz last_status = -1;
 	int			i;
-	PQExpBuffer query;
+	PQExpBuffer query = NULL;
 	XLogRecPtr	cur_record_lsn;
 
 	output_written_lsn = InvalidXLogRecPtr;
@@ -225,10 +227,24 @@ StreamLogicalLog(void)
 	 * Connect in replication mode to the server
 	 */
 	if (!conn)
+	{
 		conn = GetConnection();
-	if (!conn)
-		/* Error message already written in GetConnection() */
-		return;
+		if (!conn)
+			/* Error message already written in GetConnection() */
+			return;
+
+		/* Recreate a replication slot. */
+		if (do_create_slot && slot_is_temporary)
+		{
+			if (verbose)
+				pg_log_info("recreating replication slot \"%s\"", replication_slot);
+
+			if (!CreateReplicationSlot(conn, replication_slot, plugin, slot_is_temporary,
+									   false, false, slot_exists_ok, two_phase))
+				goto error;
+			startpos = InvalidXLogRecPtr;
+		}
+	}
 
 	/*
 	 * Start the replication
@@ -654,7 +670,8 @@ error:
 		PQfreemem(copybuf);
 		copybuf = NULL;
 	}
-	destroyPQExpBuffer(query);
+	if (query != NULL)
+		destroyPQExpBuffer(query);
 	PQfinish(conn);
 	conn = NULL;
 }
@@ -717,6 +734,7 @@ main(int argc, char **argv)
 		{"start", no_argument, NULL, 2},
 		{"drop-slot", no_argument, NULL, 3},
 		{"if-not-exists", no_argument, NULL, 4},
+		{"temporary-slot", no_argument, NULL, 5},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -845,6 +863,9 @@ main(int argc, char **argv)
 			case 4:
 				slot_exists_ok = true;
 				break;
+			case 5:
+				slot_is_temporary = true;
+				break;
 
 			default:
 				/* getopt_long already emitted a complaint */
@@ -979,7 +1000,7 @@ main(int argc, char **argv)
 		if (verbose)
 			pg_log_info("creating replication slot \"%s\"", replication_slot);
 
-		if (!CreateReplicationSlot(conn, replication_slot, plugin, false,
+		if (!CreateReplicationSlot(conn, replication_slot, plugin, slot_is_temporary,
 								   false, false, slot_exists_ok, two_phase))
 			exit(1);
 		startpos = InvalidXLogRecPtr;
diff --git a/src/bin/pg_basebackup/t/030_pg_recvlogical.pl b/src/bin/pg_basebackup/t/030_pg_recvlogical.pl
index 8432e5660d..0b46574fc1 100644
--- a/src/bin/pg_basebackup/t/030_pg_recvlogical.pl
+++ b/src/bin/pg_basebackup/t/030_pg_recvlogical.pl
@@ -65,6 +65,23 @@ $node->command_ok(
 	],
 	'replayed a transaction');
 
+$node->command_fails(
+	[
+		'pg_recvlogical', '-S',
+		'test', '-d',
+		$node->connstr('postgres'), '--create-slot'
+	],
+	'slot cannot be created again');
+
+$node->command_ok(
+	[
+		'pg_recvlogical', '-S',
+		'test', '-d',
+		$node->connstr('postgres'), '--create-slot',
+                '--if-not-exists'
+	],
+	'if-not-exists');
+
 $node->command_ok(
 	[
 		'pg_recvlogical', '-S',
@@ -73,6 +90,54 @@ $node->command_ok(
 	],
 	'slot dropped');
 
+# slot() returns a hash with all values set to the empty string if the
+# slot does not exist.
+$slot = $node->slot('test');
+is(0+grep({$_ ne ''} values %$slot), 0, 'slot does not exist anymore');
+
+$node->command_ok(
+	[
+		'pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'),
+		'--create-slot', '--temporary-slot',
+		'--start', '--endpos', "$nextlsn", '--no-loop', '-f', '-'
+	],
+	'create temporary slot');
+
+$slot = $node->slot('test');
+is(0+grep({$_ ne ''} values %$slot), 0, 'temp slot is gone when connection is dropped');
+
+$node->command_ok(
+	[
+		'pg_recvlogical', '-S',
+		'test', '-d',
+		$node->connstr('postgres'), '--create-slot',
+	],
+	'create slot again');
+
+$node->command_fails(
+	[
+		'pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'),
+		'--create-slot', '--temporary-slot',
+		'--start', '--endpos', "$nextlsn", '--no-loop', '-f', '-'
+	],
+	'create temporary slot fails if target slot exists');
+
+$node->command_ok(
+	[
+		'pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'),
+		'--create-slot', '--temporary-slot', '--if-not-exists',
+		'--start', '--endpos', "$nextlsn", '--no-loop', '-f', '-'
+	],
+	'create temporary with --if-not-exists');
+
+$node->command_ok(
+	[
+		'pg_recvlogical', '-S',
+		'test', '-d',
+		$node->connstr('postgres'), '--drop-slot'
+	],
+	'slot dropped again');
+
 #test with two-phase option enabled
 $node->command_ok(
 	[
-- 
2.34.1

Reply via email to