v5-0002-Prohibit-slot-manipulation-while-in-single-user-m.patch
application/octet-stream
Filename: v5-0002-Prohibit-slot-manipulation-while-in-single-user-m.patch
Type: application/octet-stream
Part: 1
Patch
Format: format-patch
Series: patch v5-0002
Subject: Prohibit slot manipulation while in single-user mode
| File | + | − |
|---|---|---|
| doc/src/sgml/func/func-admin.sgml | 5 | 0 |
| src/backend/replication/logical/logicalfuncs.c | 3 | 0 |
| src/backend/replication/slot.c | 12 | 0 |
| src/backend/replication/slotfuncs.c | 17 | 0 |
| src/backend/utils/adt/pg_upgrade_support.c | 3 | 0 |
| src/include/replication/slot.h | 1 | 0 |
From 3ac78c7a7a42afbbc9cb09c03b568c1c39cd035c Mon Sep 17 00:00:00 2001
From: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Date: Wed, 19 Feb 2025 11:37:26 +0900
Subject: [PATCH v5 2/2] Prohibit slot manipulation while in single-user mode
Replication-related commands are rarely used in single-user mode and have been
broken for years. This commit prohibits calling slot manipulation SQL functions
to avoid additional risk of failures. One exception is pg_drop_replication_slot.
It is still allowed because users may want to clean up their mistakes in the mode.
---
doc/src/sgml/func/func-admin.sgml | 5 +++++
src/backend/replication/logical/logicalfuncs.c | 3 +++
src/backend/replication/slot.c | 12 ++++++++++++
src/backend/replication/slotfuncs.c | 17 +++++++++++++++++
src/backend/utils/adt/pg_upgrade_support.c | 3 +++
src/include/replication/slot.h | 1 +
6 files changed, 41 insertions(+)
diff --git a/doc/src/sgml/func/func-admin.sgml b/doc/src/sgml/func/func-admin.sgml
index 446fdfe56f4..cfa09e4b987 100644
--- a/doc/src/sgml/func/func-admin.sgml
+++ b/doc/src/sgml/func/func-admin.sgml
@@ -1012,6 +1012,11 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
are also relevant for replication.
</para>
+ <para>
+ Note that slot manipulation functions except <function>pg_drop_replication_slot</function>
+ cannot be used in single-user mode.
+ </para>
+
<table id="functions-replication-table">
<title>Replication Management Functions</title>
<tgroup cols="1">
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index ca53caac2f2..30877fdc3ab 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -113,6 +113,9 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
List *options = NIL;
DecodingOutputState *p;
+ /* Slot manipulation is not allowed in single-user mode */
+ CheckSlotIsInSingleUserMode();
+
CheckSlotPermissions();
CheckLogicalDecodingRequirements();
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index fd0fdb96d42..4ca1227cc94 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1529,6 +1529,18 @@ CheckSlotPermissions(void)
"REPLICATION")));
}
+/*
+ * Check whether the instance is in single-user mode.
+ */
+void
+CheckSlotIsInSingleUserMode(void)
+{
+ if (!IsUnderPostmaster)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("replication slots cannot be used in single-user mode")));
+}
+
/*
* Reserve WAL for the currently active slot.
*
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 69f4c6157c5..4de2e52fba9 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -17,6 +17,7 @@
#include "access/xlogrecovery.h"
#include "access/xlogutils.h"
#include "funcapi.h"
+#include "miscadmin.h"
#include "replication/logical.h"
#include "replication/slot.h"
#include "replication/slotsync.h"
@@ -76,6 +77,9 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
+ /* Slot manipulation is not allowed in single-user mode */
+ CheckSlotIsInSingleUserMode();
+
CheckSlotPermissions();
CheckSlotRequirements();
@@ -182,6 +186,9 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
+ /* Slot manipulation is not allowed in single-user mode */
+ CheckSlotIsInSingleUserMode();
+
CheckSlotPermissions();
CheckLogicalDecodingRequirements();
@@ -521,6 +528,9 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
Assert(!MyReplicationSlot);
+ /* Slot manipulation is not allowed in single-user mode */
+ CheckSlotIsInSingleUserMode();
+
CheckSlotPermissions();
if (XLogRecPtrIsInvalid(moveto))
@@ -618,9 +628,13 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
TupleDesc tupdesc;
HeapTuple tuple;
+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
+ /* Slot manipulation is not allowed in single-user mode */
+ CheckSlotIsInSingleUserMode();
+
CheckSlotPermissions();
if (logical_slot)
@@ -898,6 +912,9 @@ pg_sync_replication_slots(PG_FUNCTION_ARGS)
char *err;
StringInfoData app_name;
+ /* Slot manipulation is not allowed in single-user mode */
+ CheckSlotIsInSingleUserMode();
+
CheckSlotPermissions();
if (!RecoveryInProgress())
diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c
index a4f8b4faa90..337f705b34b 100644
--- a/src/backend/utils/adt/pg_upgrade_support.c
+++ b/src/backend/utils/adt/pg_upgrade_support.c
@@ -296,6 +296,9 @@ binary_upgrade_logical_slot_has_caught_up(PG_FUNCTION_ARGS)
*/
Assert(has_rolreplication(GetUserId()));
+ /* Slot manipulation is not allowed in single-user mode */
+ CheckSlotIsInSingleUserMode();
+
slot_name = PG_GETARG_NAME(0);
/* Acquire the given slot */
diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h
index e8fc342d1a9..b4d89760f96 100644
--- a/src/include/replication/slot.h
+++ b/src/include/replication/slot.h
@@ -342,6 +342,7 @@ extern void CheckPointReplicationSlots(bool is_shutdown);
extern void CheckSlotRequirements(void);
extern void CheckSlotPermissions(void);
+extern void CheckSlotIsInSingleUserMode(void);
extern ReplicationSlotInvalidationCause
GetSlotInvalidationCause(const char *cause_name);
extern const char *GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause);
--
2.47.1