From 6bb2ff0d16ed183e4a56c41e43de00b1e2550ce8 Mon Sep 17 00:00:00 2001 From: Yuhang Qiu 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 ALTER SYSTEM - change a server configuration parameter + change or reload the server configuration @@ -25,6 +25,7 @@ ALTER SYSTEM SET configuration_parameterconfiguration_parameter ALTER SYSTEM RESET ALL +ALTER SYSTEM RELOAD @@ -32,11 +33,11 @@ ALTER SYSTEM RESET ALL Description - ALTER SYSTEM 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 postgresql.conf file. - ALTER SYSTEM writes the given parameter setting to + The SET and RESET variants of + ALTER SYSTEM change server configuration parameters + across the entire database cluster. They can be more convenient than + manually editing the postgresql.conf file. + SET writes the given parameter setting to the postgresql.auto.conf file, which is read in addition to postgresql.conf. Setting a parameter to DEFAULT, or using the @@ -45,20 +46,27 @@ ALTER SYSTEM RESET ALL ALL to remove all such configuration entries. + + The RELOAD variant requests a reload of the server + configuration files. + + Values set with ALTER SYSTEM 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 pg_reload_conf(), running pg_ctl reload, - or sending a SIGHUP signal to the main server process. + A server configuration reload can also be requested by calling the SQL + function pg_reload_conf() or running + pg_ctl reload. Only superusers and users granted ALTER SYSTEM privilege - on a parameter can change it using ALTER SYSTEM. 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 ALTER SYSTEM. + ALTER SYSTEM RELOAD can only be executed by a + superuser. The SET and RESET variants + act directly on the file system and cannot be rolled back. All variants + are disallowed inside a transaction block or function. @@ -141,6 +149,13 @@ ALTER SYSTEM RESET wal_level; + + Request a reload of the server configuration files: + +ALTER SYSTEM RELOAD; + + + Set the list of preloaded extension modules to be empty: 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 #include +#include #include #include @@ -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 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