From b19815119909d0529d6c52889ab0959ec44e7e7f Mon Sep 17 00:00:00 2001 From: Hayato Kuroda Date: Wed, 19 Feb 2025 11:37:26 +0900 Subject: [PATCH v4] Prohibit slot operations while in the single user mode --- src/backend/replication/logical/logicalfuncs.c | 2 ++ src/backend/replication/slot.c | 12 ++++++++++++ src/backend/replication/slotfuncs.c | 12 ++++++++++++ src/include/replication/slot.h | 1 + 4 files changed, 27 insertions(+) diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c index ca53caac2f..178a07af7d 100644 --- a/src/backend/replication/logical/logicalfuncs.c +++ b/src/backend/replication/logical/logicalfuncs.c @@ -113,6 +113,8 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin List *options = NIL; DecodingOutputState *p; + CheckSlotIsInSingleUserMode(); + CheckSlotPermissions(); CheckLogicalDecodingRequirements(); diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 719e531eb9..d041adfe48 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -1442,6 +1442,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 146eef5871..b669774c87 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,8 @@ 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"); + CheckSlotIsInSingleUserMode(); + CheckSlotPermissions(); CheckSlotRequirements(); @@ -182,6 +185,8 @@ 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"); + CheckSlotIsInSingleUserMode(); + CheckSlotPermissions(); CheckLogicalDecodingRequirements(); @@ -515,6 +520,8 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS) Assert(!MyReplicationSlot); + CheckSlotIsInSingleUserMode(); + CheckSlotPermissions(); if (XLogRecPtrIsInvalid(moveto)) @@ -612,9 +619,12 @@ 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"); + CheckSlotIsInSingleUserMode(); + CheckSlotPermissions(); if (logical_slot) @@ -871,6 +881,8 @@ pg_sync_replication_slots(PG_FUNCTION_ARGS) char *err; StringInfoData app_name; + CheckSlotIsInSingleUserMode(); + CheckSlotPermissions(); if (!RecoveryInProgress()) diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h index f5a24ccfbf..24523b1001 100644 --- a/src/include/replication/slot.h +++ b/src/include/replication/slot.h @@ -306,6 +306,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.43.5