From 5eb6a537c60019c1c715813b8417c04bee1e6e13 Mon Sep 17 00:00:00 2001
From: Joao Foltran <joao@foltrandba.com>
Date: Thu, 19 Mar 2026 19:05:09 -0300
Subject: [PATCH v2 2/5] Add auto_revalidate parameter to
 pg_create_physical_replication_slot

Allow setting auto_revalidate when creating a physical replication slot
via the SQL function:
  pg_create_physical_replication_slot(name, immediately_reserve,
                                      temporary, auto_revalidate)

The flag is set after slot creation (not via ReplicationSlotCreate
parameter) to avoid a cascading signature change across all 6 callers
of that function. The new parameter defaults to false.
---
 contrib/test_decoding/expected/slot.out | 32 +++++++++++++++++++++++++
 contrib/test_decoding/sql/slot.sql      |  7 ++++++
 src/backend/replication/slotfuncs.c     | 20 +++++++++++++---
 src/backend/replication/walsender.c     |  1 +
 src/include/catalog/pg_proc.dat         | 11 +++++----
 src/test/recovery/meson.build           |  1 +
 6 files changed, 64 insertions(+), 8 deletions(-)

diff --git a/contrib/test_decoding/expected/slot.out b/contrib/test_decoding/expected/slot.out
index 7de03c79f6f..1834b42cd92 100644
--- a/contrib/test_decoding/expected/slot.out
+++ b/contrib/test_decoding/expected/slot.out
@@ -406,6 +406,38 @@ SELECT pg_drop_replication_slot('copied_slot2_notemp');
  
 (1 row)
 
+-- Test auto_revalidate is preserved when copying physical slots
+SELECT 'init' FROM pg_create_physical_replication_slot('orig_slot_ar', true, false, true);
+ ?column? 
+----------
+ init
+(1 row)
+
+SELECT 'copy' FROM pg_copy_physical_replication_slot('orig_slot_ar', 'copied_slot_ar');
+ ?column? 
+----------
+ copy
+(1 row)
+
+SELECT slot_name, auto_revalidate FROM pg_replication_slots WHERE slot_name LIKE '%_ar' ORDER BY slot_name;
+   slot_name    | auto_revalidate 
+----------------+-----------------
+ copied_slot_ar | t
+ orig_slot_ar   | t
+(2 rows)
+
+SELECT pg_drop_replication_slot('orig_slot_ar');
+ pg_drop_replication_slot 
+--------------------------
+ 
+(1 row)
+
+SELECT pg_drop_replication_slot('copied_slot_ar');
+ pg_drop_replication_slot 
+--------------------------
+ 
+(1 row)
+
 -- Test failover option of slots.
 SELECT 'init' FROM pg_create_logical_replication_slot('failover_true_slot', 'test_decoding', false, false, true);
  ?column? 
diff --git a/contrib/test_decoding/sql/slot.sql b/contrib/test_decoding/sql/slot.sql
index 580e3ae3bef..98b349d6d60 100644
--- a/contrib/test_decoding/sql/slot.sql
+++ b/contrib/test_decoding/sql/slot.sql
@@ -177,6 +177,13 @@ SELECT pg_drop_replication_slot('orig_slot2');
 SELECT pg_drop_replication_slot('copied_slot2_no_change');
 SELECT pg_drop_replication_slot('copied_slot2_notemp');
 
+-- Test auto_revalidate is preserved when copying physical slots
+SELECT 'init' FROM pg_create_physical_replication_slot('orig_slot_ar', true, false, true);
+SELECT 'copy' FROM pg_copy_physical_replication_slot('orig_slot_ar', 'copied_slot_ar');
+SELECT slot_name, auto_revalidate FROM pg_replication_slots WHERE slot_name LIKE '%_ar' ORDER BY slot_name;
+SELECT pg_drop_replication_slot('orig_slot_ar');
+SELECT pg_drop_replication_slot('copied_slot_ar');
+
 -- Test failover option of slots.
 SELECT 'init' FROM pg_create_logical_replication_slot('failover_true_slot', 'test_decoding', false, false, true);
 SELECT 'init' FROM pg_create_logical_replication_slot('failover_false_slot', 'test_decoding', false, false, false);
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9f5e4f998fe..fdde1530a0c 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -46,7 +46,8 @@ static const char *SlotSyncSkipReasonNames[] = {
  */
 static void
 create_physical_replication_slot(char *name, bool immediately_reserve,
-								 bool temporary, XLogRecPtr restart_lsn)
+								 bool temporary, XLogRecPtr restart_lsn,
+								 bool auto_revalidate)
 {
 	Assert(!MyReplicationSlot);
 
@@ -67,6 +68,16 @@ create_physical_replication_slot(char *name, bool immediately_reserve,
 		ReplicationSlotMarkDirty();
 		ReplicationSlotSave();
 	}
+
+	if (auto_revalidate)
+	{
+		SpinLockAcquire(&MyReplicationSlot->mutex);
+		MyReplicationSlot->data.auto_revalidate = true;
+		SpinLockRelease(&MyReplicationSlot->mutex);
+
+		ReplicationSlotMarkDirty();
+		ReplicationSlotSave();
+	}
 }
 
 /*
@@ -79,6 +90,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 	Name		name = PG_GETARG_NAME(0);
 	bool		immediately_reserve = PG_GETARG_BOOL(1);
 	bool		temporary = PG_GETARG_BOOL(2);
+	bool		auto_revalidate = PG_GETARG_BOOL(3);
 	Datum		values[2];
 	bool		nulls[2];
 	TupleDesc	tupdesc;
@@ -95,7 +107,8 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 	create_physical_replication_slot(NameStr(*name),
 									 immediately_reserve,
 									 temporary,
-									 InvalidXLogRecPtr);
+									 InvalidXLogRecPtr,
+									 auto_revalidate);
 
 	values[0] = NameGetDatum(&MyReplicationSlot->data.name);
 	nulls[0] = false;
@@ -757,7 +770,8 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		create_physical_replication_slot(NameStr(*dst_name),
 										 true,
 										 temporary,
-										 src_restart_lsn);
+										 src_restart_lsn,
+										 first_slot_contents.data.auto_revalidate);
 
 	/*
 	 * Update the destination slot to current values of the source slot;
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 50ada2ed293..0d0c4f8d112 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1254,6 +1254,7 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
 			if (!cmd->temporary)
 				ReplicationSlotSave();
 		}
+
 	}
 	else
 	{
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index fc8d82665b8..de3f99ebb3a 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -11612,11 +11612,12 @@
 # replication slots
 { oid => '3779', descr => 'create a physical replication slot',
   proname => 'pg_create_physical_replication_slot', provolatile => 'v',
-  proparallel => 'u', prorettype => 'record', proargtypes => 'name bool bool',
-  proallargtypes => '{name,bool,bool,name,pg_lsn}',
-  proargmodes => '{i,i,i,o,o}',
-  proargnames => '{slot_name,immediately_reserve,temporary,slot_name,lsn}',
-  proargdefaults => '{false,false}',
+  proparallel => 'u', prorettype => 'record',
+  proargtypes => 'name bool bool bool',
+  proallargtypes => '{name,bool,bool,bool,name,pg_lsn}',
+  proargmodes => '{i,i,i,i,o,o}',
+  proargnames => '{slot_name,immediately_reserve,temporary,auto_revalidate,slot_name,lsn}',
+  proargdefaults => '{false,false,false}',
   prosrc => 'pg_create_physical_replication_slot' },
 { oid => '4220',
   descr => 'copy a physical replication slot, changing temporality',
diff --git a/src/test/recovery/meson.build b/src/test/recovery/meson.build
index 36d789720a3..e1bd2d5d8f5 100644
--- a/src/test/recovery/meson.build
+++ b/src/test/recovery/meson.build
@@ -61,6 +61,7 @@ tests += {
       't/050_redo_segment_missing.pl',
       't/051_effective_wal_level.pl',
       't/052_checkpoint_segment_missing.pl',
+      't/053_auto_revalidate_physical_slot.pl',
     ],
   },
 }
-- 
2.50.1 (Apple Git-155)

