From 2370da9bbe5757f26505dd45a3ddd2091c621108 Mon Sep 17 00:00:00 2001
From: Euler Taveira <euler@eulerto.com>
Date: Wed, 14 Jan 2026 17:29:09 -0300
Subject: [PATCH v8 3/3] fixup! log_min_messages per process type

---
 src/backend/commands/variable.c   | 55 +++++++++++++++++++++++++++++++
 src/test/regress/expected/guc.out |  4 +--
 2 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index f4f5d4c367c..53fcce5ea43 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -42,6 +42,10 @@
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 
+#define	MAX_LMM_STR_LEN (BACKEND_NUM_TYPES * 32)
+
+static int	string_cmp(const ListCell *a, const ListCell *b);
+
 /*
  * DATESTYLE
  */
@@ -1275,10 +1279,16 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 	char	   *rawstring;
 	List	   *elemlist;
 	ListCell   *l;
+	char	   *result;
+	bool		first = true;
 	int			newlevel[BACKEND_NUM_TYPES];
 	bool		assigned[BACKEND_NUM_TYPES];
 	int			genericlevel = -1;	/* -1 means not assigned */
 
+	result = (char *) guc_malloc(LOG, MAX_LMM_STR_LEN);
+	if (!result)
+		return false;
+
 	/* Initialize the array. */
 	for (int i = 0; i < BACKEND_NUM_TYPES; i++)
 	{
@@ -1442,6 +1452,42 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 			newlevel[i] = genericlevel;
 	}
 
+	/*
+	 * Use a stable representation of log_min_messages. The generic level is
+	 * always the first element and the other elements (type:level) are sorted
+	 * by process type.
+	 */
+	list_sort(elemlist, string_cmp);
+	foreach(l, elemlist)
+	{
+		char	   *tok = (char *) lfirst(l);
+
+		if (strchr(tok, ':') == NULL)
+		{
+			elemlist = list_delete(elemlist, tok);
+			elemlist = lcons(tok, elemlist);
+			break;
+		}
+	}
+
+	foreach(l, elemlist)
+	{
+		char	   *tok = (char *) lfirst(l);
+
+		if (first)
+		{
+			strncpy(result, tok, MAX_LMM_STR_LEN);
+			first = false;
+		}
+		else
+		{
+			strlcat(result, ", ", MAX_LMM_STR_LEN);
+			strlcat(result, tok, MAX_LMM_STR_LEN);
+		}
+	}
+	guc_free(*newval);
+	*newval = result;
+
 	guc_free(rawstring);
 	list_free(elemlist);
 
@@ -1456,6 +1502,15 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 	return true;
 }
 
+static int
+string_cmp(const ListCell *a, const ListCell *b)
+{
+	const char *s = lfirst(a);
+	const char *t = lfirst(b);
+
+	return strcmp(s, t);
+}
+
 /*
  * GUC assign_hook for log_min_messages
  */
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 3b8f44566b2..9a6fd503009 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -972,7 +972,7 @@ SET log_min_messages TO 'backend:error, checkpointer:debug3, fatal, archiver:deb
 SHOW log_min_messages;
                                         log_min_messages                                         
 -------------------------------------------------------------------------------------------------
- backend:error, checkpointer:debug3, fatal, archiver:debug2, autovacuum:debug1, walsender:debug3
+ fatal, archiver:debug2, autovacuum:debug1, backend:error, checkpointer:debug3, walsender:debug3
 (1 row)
 
 SET log_min_messages TO 'warning, autovacuum:debug1';
@@ -986,6 +986,6 @@ SET log_min_messages TO 'autovacuum:debug1, warning';
 SHOW log_min_messages;
       log_min_messages      
 ----------------------------
- autovacuum:debug1, warning
+ warning, autovacuum:debug1
 (1 row)
 
-- 
2.39.5

