From 4642e4e0b0a63d9da6ac4479963dec6c7b71ac68 Mon Sep 17 00:00:00 2001
From: Andrew Klychkov <andrew.a.klychkov@gmail.com>
Date: Wed, 3 Sep 2025 10:48:49 +0200
Subject: [PATCH] Fix ALTER SYSTEM empty string bug for GUC_LIST_QUOTE
 parameters

When ALTER SYSTEM SET is used with an empty string for parameters with
GUC_LIST_QUOTE flag (like shared_preload_libraries), the empty string
was being double-quoted, resulting in '""' being written to
postgresql.auto.conf. This caused server crashes on restart due to
malformed configuration syntax.

The fix detects when a GUC_LIST_QUOTE parameter has the value '""' and
writes it as '' instead, preventing the double-quoting issue while
maintaining proper configuration file syntax.

Fixes bug where 'ALTER SYSTEM SET "shared_preload_libraries" TO '''
would write 'shared_preload_libraries = '""'' to postgresql.auto.conf.
---
 src/backend/utils/misc/guc.c | 39 ++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 46fdefebe3..7494cbd56b 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -4497,6 +4497,45 @@ write_auto_conf_file(int fd, const char *filename, ConfigVariable *head)
 	for (item = head; item != NULL; item = item->next)
 	{
 		char	   *escaped;
+		bool		is_guc_list_quote = false;
+
+		/*
+		 * Check if this is a GUC_LIST_QUOTE parameter to handle empty strings
+		 * specially and prevent double-quoting issues.
+		 */
+		if (item->value[0] == '\0' || strcmp(item->value, "\"\"") == 0)
+		{
+			struct config_generic *record = find_option(item->name, false, true, WARNING);
+			if (record && (record->flags & GUC_LIST_QUOTE))
+				is_guc_list_quote = true;
+		}
+
+		/*
+		 * Special handling for GUC_LIST_QUOTE parameters with empty strings.
+		 * When ALTER SYSTEM SET is used with an empty string for such parameters,
+		 * the value comes through as '""' (quoted empty string). We want to write
+		 * this as an empty string rather than the quoted version to avoid the
+		 * double-quoting issue.
+		 */
+		if (is_guc_list_quote && (item->value[0] == '\0' || strcmp(item->value, "\"\"") == 0))
+		{
+			/* For GUC_LIST_QUOTE parameters, write empty string as '' */
+			resetStringInfo(&buf);
+			appendStringInfoString(&buf, item->name);
+			appendStringInfoString(&buf, " = ''\n");
+
+			errno = 0;
+			if (write(fd, buf.data, buf.len) != buf.len)
+			{
+				/* if write didn't set errno, assume problem is no disk space */
+				if (errno == 0)
+					errno = ENOSPC;
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not write to file \"%s\": %m", filename)));
+			}
+			continue;
+		}
 
 		resetStringInfo(&buf);
 
-- 
2.47.0

