From 8ce4d69f631953e7bf3cd45044156bae758602a2 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 21 Feb 2024 04:15:02 +0000
Subject: [PATCH v2] Add lookup table for replication slot invalidation causes

---
 src/backend/replication/slot.c      | 45 +++++++++++++++++++----------
 src/backend/replication/slotfuncs.c | 24 ++++-----------
 src/include/replication/slot.h      | 16 +++++-----
 3 files changed, 44 insertions(+), 41 deletions(-)

diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a142855bd3..82ad425ef4 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -77,6 +77,19 @@ typedef struct ReplicationSlotOnDisk
 	ReplicationSlotPersistentData slotdata;
 } ReplicationSlotOnDisk;
 
+/*
+ * Lookup table for invalidation cause names indexed by RS_INVAL_XXX.
+ */
+const char *const SlotInvalidationCauses[] = {
+	[RS_INVAL_NONE] = "none",
+	[RS_INVAL_WAL_REMOVED] = "wal_removed",
+	[RS_INVAL_HORIZON] = "rows_removed",
+	[RS_INVAL_WAL_LEVEL] = "wal_level_insufficient",
+};
+
+StaticAssertDecl(lengthof(SlotInvalidationCauses) == (RS_INVAL_MAX_CAUSES + 1),
+				 "array length mismatch");
+
 /* size of version independent data */
 #define ReplicationSlotOnDiskConstantSize \
 	offsetof(ReplicationSlotOnDisk, slotdata)
@@ -2290,23 +2303,25 @@ RestoreSlotFromDisk(const char *name)
 }
 
 /*
- * Maps the pg_replication_slots.conflict_reason text value to
- * ReplicationSlotInvalidationCause enum value
+ * Look up invalidation cause by name.
  */
 ReplicationSlotInvalidationCause
-GetSlotInvalidationCause(char *conflict_reason)
+GetSlotInvalidationCause(char *name)
 {
-	Assert(conflict_reason);
-
-	if (strcmp(conflict_reason, SLOT_INVAL_WAL_REMOVED_TEXT) == 0)
-		return RS_INVAL_WAL_REMOVED;
-	else if (strcmp(conflict_reason, SLOT_INVAL_HORIZON_TEXT) == 0)
-		return RS_INVAL_HORIZON;
-	else if (strcmp(conflict_reason, SLOT_INVAL_WAL_LEVEL_TEXT) == 0)
-		return RS_INVAL_WAL_LEVEL;
-	else
-		Assert(0);
+	ReplicationSlotInvalidationCause cause;
+	bool		found PG_USED_FOR_ASSERTS_ONLY = false;
+
+	Assert(name);
+
+	for (cause = RS_INVAL_NONE; cause <= RS_INVAL_MAX_CAUSES; cause++)
+	{
+		if (strcmp(SlotInvalidationCauses[cause], name) == 0)
+		{
+			found = true;
+			break;
+		}
+	}
 
-	/* Keep compiler quiet */
-	return RS_INVAL_NONE;
+	Assert(found);
+	return cause;
 }
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index d2fa5e669a..c108bf9608 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -413,24 +413,12 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 			nulls[i++] = true;
 		else
 		{
-			switch (slot_contents.data.invalidated)
-			{
-				case RS_INVAL_NONE:
-					nulls[i++] = true;
-					break;
-
-				case RS_INVAL_WAL_REMOVED:
-					values[i++] = CStringGetTextDatum(SLOT_INVAL_WAL_REMOVED_TEXT);
-					break;
-
-				case RS_INVAL_HORIZON:
-					values[i++] = CStringGetTextDatum(SLOT_INVAL_HORIZON_TEXT);
-					break;
-
-				case RS_INVAL_WAL_LEVEL:
-					values[i++] = CStringGetTextDatum(SLOT_INVAL_WAL_LEVEL_TEXT);
-					break;
-			}
+			ReplicationSlotInvalidationCause cause = slot_contents.data.invalidated;
+
+			if (cause == RS_INVAL_NONE)
+				nulls[i++] = true;
+			else
+				values[i++] = CStringGetTextDatum(SlotInvalidationCauses[cause]);
 		}
 
 		values[i++] = BoolGetDatum(slot_contents.data.failover);
diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h
index e706ca834c..b26697ba15 100644
--- a/src/include/replication/slot.h
+++ b/src/include/replication/slot.h
@@ -40,6 +40,9 @@ typedef enum ReplicationSlotPersistency
 /*
  * Slots can be invalidated, e.g. due to max_slot_wal_keep_size. If so, the
  * 'invalidated' field is set to a value other than _NONE.
+ *
+ * If you add a new invalidation cause here, remember to add its name in
+ * SlotInvalidationCauses in the same order as that of the cause.
  */
 typedef enum ReplicationSlotInvalidationCause
 {
@@ -52,13 +55,10 @@ typedef enum ReplicationSlotInvalidationCause
 	RS_INVAL_WAL_LEVEL,
 } ReplicationSlotInvalidationCause;
 
-/*
- * The possible values for 'conflict_reason' returned in
- * pg_get_replication_slots.
- */
-#define SLOT_INVAL_WAL_REMOVED_TEXT "wal_removed"
-#define SLOT_INVAL_HORIZON_TEXT     "rows_removed"
-#define SLOT_INVAL_WAL_LEVEL_TEXT   "wal_level_insufficient"
+/* Maximum number of invalidation causes */
+#define	RS_INVAL_MAX_CAUSES RS_INVAL_WAL_LEVEL
+
+extern PGDLLIMPORT const char *const SlotInvalidationCauses[];
 
 /*
  * On-Disk data of a replication slot, preserved across restarts.
@@ -275,6 +275,6 @@ extern void CheckPointReplicationSlots(bool is_shutdown);
 extern void CheckSlotRequirements(void);
 extern void CheckSlotPermissions(void);
 extern ReplicationSlotInvalidationCause
-			GetSlotInvalidationCause(char *conflict_reason);
+			GetSlotInvalidationCause(char *cause);
 
 #endif							/* SLOT_H */
-- 
2.34.1

