From 6bb2ff0d16ed183e4a56c41e43de00b1e2550ce8 Mon Sep 17 00:00:00 2001
From: Yuhang Qiu <iamqyh@gmail.com>
Date: Tue, 22 Sep 2026 14:55:29 +0000
Subject: [PATCH] Add ALTER SYSTEM RELOAD

ALTER SYSTEM changes server configuration, but requesting a reload
afterward requires a separate call to pg_reload_conf().  Add ALTER
SYSTEM RELOAD so both steps can use the ALTER SYSTEM command family.

The command form makes the workflow easier to discover and its
administrative purpose clearer.  The existing pg_reload_conf()
function remains available.
---
 doc/src/sgml/ref/alter_system.sgml            | 39 ++++++---
 src/backend/parser/gram.y                     | 13 ++-
 src/backend/tcop/utility.c                    | 20 ++++-
 src/backend/utils/misc/guc.c                  | 22 +++++
 src/bin/psql/tab-complete.in.c                |  4 +-
 src/include/nodes/parsenodes.h                |  8 ++
 src/include/parser/kwlist.h                   |  1 +
 src/include/utils/guc.h                       |  1 +
 src/test/modules/test_misc/meson.build        |  1 +
 .../test_misc/t/016_alter_system_reload.pl    | 84 +++++++++++++++++++
 10 files changed, 176 insertions(+), 17 deletions(-)
 create mode 100644 src/test/modules/test_misc/t/016_alter_system_reload.pl

diff --git a/doc/src/sgml/ref/alter_system.sgml b/doc/src/sgml/ref/alter_system.sgml
index b28919d1b26..7ff4f88d04a 100644
--- a/doc/src/sgml/ref/alter_system.sgml
+++ b/doc/src/sgml/ref/alter_system.sgml
@@ -16,7 +16,7 @@ PostgreSQL documentation
 
  <refnamediv>
   <refname>ALTER SYSTEM</refname>
-  <refpurpose>change a server configuration parameter</refpurpose>
+  <refpurpose>change or reload the server configuration</refpurpose>
  </refnamediv>
 
  <refsynopsisdiv>
@@ -25,6 +25,7 @@ ALTER SYSTEM SET <replaceable class="parameter">configuration_parameter</replace
 
 ALTER SYSTEM RESET <replaceable class="parameter">configuration_parameter</replaceable>
 ALTER SYSTEM RESET ALL
+ALTER SYSTEM RELOAD
 </synopsis>
  </refsynopsisdiv>
 
@@ -32,11 +33,11 @@ ALTER SYSTEM RESET ALL
   <title>Description</title>
 
   <para>
-   <command>ALTER SYSTEM</command> is used for changing server configuration
-   parameters across the entire database cluster.  It can be more convenient
-   than the traditional method of manually editing
-   the <filename>postgresql.conf</filename> file.
-   <command>ALTER SYSTEM</command> writes the given parameter setting to
+   The <command>SET</command> and <command>RESET</command> variants of
+   <command>ALTER SYSTEM</command> change server configuration parameters
+   across the entire database cluster.  They can be more convenient than
+   manually editing the <filename>postgresql.conf</filename> file.
+   <command>SET</command> writes the given parameter setting to
    the <filename>postgresql.auto.conf</filename> file, which is read in
    addition to <filename>postgresql.conf</filename>.
    Setting a parameter to <literal>DEFAULT</literal>, or using the
@@ -45,20 +46,27 @@ ALTER SYSTEM RESET ALL
    ALL</literal> to remove all such configuration entries.
   </para>
 
+  <para>
+   The <command>RELOAD</command> variant requests a reload of the server
+   configuration files.
+  </para>
+
   <para>
    Values set with <command>ALTER SYSTEM</command> will be effective after
    the next server configuration reload, or after the next server restart
    in the case of parameters that can only be changed at server start.
-   A server configuration reload can be commanded by calling the SQL
-   function <function>pg_reload_conf()</function>, running <literal>pg_ctl reload</literal>,
-   or sending a <systemitem>SIGHUP</systemitem> signal to the main server process.
+   A server configuration reload can also be requested by calling the SQL
+   function <function>pg_reload_conf()</function> or running
+   <literal>pg_ctl reload</literal>.
   </para>
 
   <para>
    Only superusers and users granted <literal>ALTER SYSTEM</literal> privilege
-   on a parameter can change it using <command>ALTER SYSTEM</command>.  Also, since
-   this command acts directly on the file system and cannot be rolled back,
-   it is not allowed inside a transaction block or function.
+   on a parameter can change it using <command>ALTER SYSTEM</command>.
+   <command>ALTER SYSTEM RELOAD</command> can only be executed by a
+   superuser.  The <command>SET</command> and <command>RESET</command> variants
+   act directly on the file system and cannot be rolled back.  All variants
+   are disallowed inside a transaction block or function.
   </para>
  </refsect1>
 
@@ -141,6 +149,13 @@ ALTER SYSTEM RESET wal_level;
 </programlisting>
   </para>
 
+  <para>
+   Request a reload of the server configuration files:
+<programlisting>
+ALTER SYSTEM RELOAD;
+</programlisting>
+  </para>
+
   <para>
    Set the list of preloaded extension modules to be empty:
 <programlisting>
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0563453fe24..f271a77f34e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -783,7 +783,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	QUOTE QUOTES
 
 	RANGE READ REAL REASSIGN RECURSIVE REF_P REFERENCES REFERENCING
-	REFRESH REINDEX RELATIVE_P RELEASE RENAME REPACK REPEATABLE REPLACE REPLICA
+	REFRESH REINDEX RELATIVE_P RELEASE RELOAD RENAME REPACK REPEATABLE REPLACE REPLICA
 	RESET RESPECT_P RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
 	ROUTINE ROUTINES ROW ROWS RULE
 
@@ -11846,6 +11846,7 @@ AlterSystemStmt:
 				{
 					AlterSystemStmt *n = makeNode(AlterSystemStmt);
 
+					n->action = ALTER_SYSTEM_SET;
 					n->setstmt = $4;
 					$$ = (Node *) n;
 				}
@@ -11853,9 +11854,17 @@ AlterSystemStmt:
 				{
 					AlterSystemStmt *n = makeNode(AlterSystemStmt);
 
+					n->action = ALTER_SYSTEM_RESET;
 					n->setstmt = $4;
 					$$ = (Node *) n;
 				}
+			| ALTER SYSTEM_P RELOAD
+				{
+					AlterSystemStmt *n = makeNode(AlterSystemStmt);
+
+					n->action = ALTER_SYSTEM_RELOAD;
+					$$ = (Node *) n;
+				}
 		;
 
 
@@ -18301,6 +18310,7 @@ unreserved_keyword:
 			| REINDEX
 			| RELATIVE_P
 			| RELEASE
+			| RELOAD
 			| RENAME
 			| REPACK
 			| REPEATABLE
@@ -18937,6 +18947,7 @@ bare_label_keyword:
 			| REINDEX
 			| RELATIVE_P
 			| RELEASE
+			| RELOAD
 			| RENAME
 			| REPACK
 			| REPEATABLE
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 1512d2df196..d10655638ff 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -869,8 +869,24 @@ standard_ProcessUtility(PlannedStmt *pstmt,
 			break;
 
 		case T_AlterSystemStmt:
-			PreventInTransactionBlock(isTopLevel, "ALTER SYSTEM");
-			AlterSystemSetConfigFile((AlterSystemStmt *) parsetree);
+			{
+				AlterSystemStmt *stmt = (AlterSystemStmt *) parsetree;
+
+				PreventInTransactionBlock(isTopLevel, "ALTER SYSTEM");
+				switch (stmt->action)
+				{
+					case ALTER_SYSTEM_SET:
+					case ALTER_SYSTEM_RESET:
+						AlterSystemSetConfigFile(stmt);
+						break;
+					case ALTER_SYSTEM_RELOAD:
+						AlterSystemReloadConfig();
+						break;
+					default:
+						elog(ERROR, "unrecognized ALTER SYSTEM action: %d",
+							 (int) stmt->action);
+				}
+			}
 			break;
 
 		case T_VariableSetStmt:
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 21c9ccec1e2..4a3bdeeafe5 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -26,6 +26,7 @@
 
 #include <limits.h>
 #include <math.h>
+#include <signal.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
@@ -4785,6 +4786,27 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
 	LWLockRelease(AutoFileLock);
 }
 
+/*
+ * Execute ALTER SYSTEM RELOAD.
+ */
+void
+AlterSystemReloadConfig(void)
+{
+	if (!AllowAlterSystem)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("ALTER SYSTEM is not allowed in this environment")));
+
+	if (!superuser())
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 errmsg("permission denied to perform ALTER SYSTEM RELOAD")));
+
+	if (kill(PostmasterPid, SIGHUP))
+		ereport(ERROR,
+				(errmsg("failed to send signal to postmaster: %m")));
+}
+
 
 /*
  * Common code for DefineCustomXXXVariable subroutines: allocate the
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index b3bfe050b18..a93fed24511 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -2658,9 +2658,9 @@ match_previous_words(int pattern_id,
 	/* ALTER SERVER <name> VERSION <version> */
 	else if (Matches("ALTER", "SERVER", MatchAny, "VERSION", MatchAny))
 		COMPLETE_WITH("OPTIONS");
-	/* ALTER SYSTEM SET, RESET, RESET ALL */
+	/* ALTER SYSTEM SET, RESET, RESET ALL, RELOAD */
 	else if (Matches("ALTER", "SYSTEM"))
-		COMPLETE_WITH("SET", "RESET");
+		COMPLETE_WITH("SET", "RESET", "RELOAD");
 	else if (Matches("ALTER", "SYSTEM", "SET|RESET"))
 		COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_alter_system_set_vars,
 										  "ALL");
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 0debcd193ab..120073f448f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3987,9 +3987,17 @@ typedef struct DropdbStmt
  *		Alter System Statement
  * ----------------------
  */
+typedef enum AlterSystemAction
+{
+	ALTER_SYSTEM_SET,
+	ALTER_SYSTEM_RESET,
+	ALTER_SYSTEM_RELOAD
+} AlterSystemAction;
+
 typedef struct AlterSystemStmt
 {
 	NodeTag		type;
+	AlterSystemAction action;
 	VariableSetStmt *setstmt;	/* SET subcommand */
 } AlterSystemStmt;
 
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 53ae96c0399..a5d6dd17565 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -375,6 +375,7 @@ PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("reload", RELOAD, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("repack", REPACK, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, BARE_LABEL)
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 164efba6b51..95c265ae2e6 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -461,6 +461,7 @@ extern int	set_config_with_handle(const char *name, config_handle *handle,
 								   int elevel, bool is_reload);
 extern config_handle *get_config_handle(const char *name);
 extern void AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt);
+extern void AlterSystemReloadConfig(void);
 extern char *GetConfigOptionByName(const char *name, const char **varname,
 								   bool missing_ok);
 
diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build
index 5d81f5b13be..3eeff8c3f54 100644
--- a/src/test/modules/test_misc/meson.build
+++ b/src/test/modules/test_misc/meson.build
@@ -24,6 +24,7 @@ tests += {
       't/013_temp_obj_multisession.pl',
       't/014_log_statement_max_length.pl',
       't/015_temp_schema_exit_deferrable.pl',
+      't/016_alter_system_reload.pl',
     ],
     # The injection points are cluster-wide, so disable installcheck
     'runningcheck': false,
diff --git a/src/test/modules/test_misc/t/016_alter_system_reload.pl b/src/test/modules/test_misc/t/016_alter_system_reload.pl
new file mode 100644
index 00000000000..5b7049a1c91
--- /dev/null
+++ b/src/test/modules/test_misc/t/016_alter_system_reload.pl
@@ -0,0 +1,84 @@
+# Copyright (c) 2026, PostgreSQL Global Development Group
+
+use strict;
+use warnings FATAL => 'all';
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('main');
+$node->init;
+$node->start;
+
+$node->safe_psql(
+	'postgres',
+	q{
+ALTER SYSTEM SET log_connections = 'all';
+ALTER SYSTEM RELOAD;
+});
+ok( $node->poll_query_until(
+		'postgres', q{SELECT current_setting('log_connections') = 'all'}),
+	'ALTER SYSTEM RELOAD applies configuration changes');
+
+$node->safe_psql('postgres', 'CREATE ROLE regress_alter_system_reload');
+$node->safe_psql(
+	'postgres',
+	'GRANT ALTER SYSTEM ON PARAMETER log_connections TO regress_alter_system_reload');
+my ($ret, $stdout, $stderr) = $node->psql(
+	'postgres',
+	q{
+SET ROLE regress_alter_system_reload;
+ALTER SYSTEM SET log_connections = 'all';
+});
+is($ret, 0, 'parameter privilege allows ALTER SYSTEM SET');
+
+$node->safe_psql(
+	'postgres',
+	'GRANT EXECUTE ON FUNCTION pg_reload_conf() TO regress_alter_system_reload');
+($ret, $stdout, $stderr) = $node->psql(
+	'postgres',
+	q{
+SET ROLE regress_alter_system_reload;
+ALTER SYSTEM RELOAD;
+});
+isnt($ret, 0, 'non-superuser cannot run ALTER SYSTEM RELOAD');
+like(
+	$stderr,
+	qr/permission denied to perform ALTER SYSTEM RELOAD/,
+	'permission error is reported');
+
+($ret, $stdout, $stderr) =
+  $node->psql('postgres', 'BEGIN; ALTER SYSTEM RELOAD;');
+isnt($ret, 0, 'ALTER SYSTEM RELOAD is rejected in a transaction block');
+like(
+	$stderr,
+	qr/ALTER SYSTEM cannot run inside a transaction block/,
+	'transaction block error is reported');
+
+$node->append_conf('postgresql.conf', 'allow_alter_system = off');
+$node->safe_psql('postgres', 'SELECT pg_reload_conf()');
+ok( $node->poll_query_until(
+		'postgres', q{SELECT current_setting('allow_alter_system') = 'off'}),
+	'allow_alter_system is disabled');
+($ret, $stdout, $stderr) =
+  $node->psql('postgres', 'ALTER SYSTEM RELOAD;');
+isnt($ret, 0, 'ALTER SYSTEM RELOAD obeys allow_alter_system');
+like(
+	$stderr,
+	qr/ALTER SYSTEM is not allowed in this environment/,
+	'allow_alter_system error is reported');
+
+# Restore the GUC without relying on the command that it disables.
+$node->append_conf('postgresql.conf', 'allow_alter_system = on');
+$node->safe_psql('postgres', 'SELECT pg_reload_conf()');
+ok( $node->poll_query_until(
+		'postgres', q{SELECT current_setting('allow_alter_system') = 'on'}),
+	'allow_alter_system is restored');
+$node->safe_psql(
+	'postgres',
+	q{
+ALTER SYSTEM RESET log_connections;
+ALTER SYSTEM RELOAD;
+});
+
+done_testing();
-- 
2.43.7

