From e849c44f71946b8724bcbcc38e78dbeab6a361ba Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 20 Oct 2021 07:49:08 -0700
Subject: [PATCH v1 04/12] Adding role pg_manage_autovacuum_settings

This new role can SET and ALTER SYSTEM SET any GUC variable which
controls autovacuum behavior or resource usage.
---
 doc/src/sgml/user-manag.sgml            |  9 ++-
 src/backend/utils/misc/guc.c            | 30 +++++----
 src/include/catalog/pg_authid.dat       |  5 ++
 src/include/utils/guc.h                 |  1 +
 src/test/regress/expected/guc_privs.out | 83 +++++++++++++++++++++++++
 src/test/regress/sql/guc_privs.sql      | 53 ++++++++++++++++
 6 files changed, 166 insertions(+), 15 deletions(-)

diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml
index 1d91d419e3..42d386b18f 100644
--- a/doc/src/sgml/user-manag.sgml
+++ b/doc/src/sgml/user-manag.sgml
@@ -590,6 +590,10 @@ DROP ROLE doomed_role;
        <entry>pg_manage_vacuum_settings</entry>
        <entry>Allow changing settings which control vacuum behavior.</entry>
       </row>
+      <row>
+       <entry>pg_manage_autovacuum_settings</entry>
+       <entry>Allow changing settings which control autovacuum behavior.</entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
@@ -635,8 +639,9 @@ DROP ROLE doomed_role;
   </para>
 
   <para>
-  The <literal>pg_manage_host_resource_settings</literal> and
-  <literal>pg_manage_vacuum_settings</literal> roles are intended to allow
+  The <literal>pg_manage_host_resource_settings</literal>,
+  <literal>pg_manage_vacuum_settings</literal> and
+  <literal>pg_manage_autovacuum_settings</literal> roles are intended to allow
   administrators to have trusted, but non-superuser, roles to configure the
   server.
   </para>
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 80265559b0..94a1843825 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1631,7 +1631,7 @@ static struct config_bool ConfigureNamesBool[] =
 		{"autovacuum", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Starts the autovacuum subprocess."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_start_daemon,
 		true,
@@ -2678,7 +2678,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"autovacuum_vacuum_cost_limit", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Vacuum cost amount available before napping, for autovacuum."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_vac_cost_limit,
 		-1, -1, 10000,
@@ -3464,7 +3464,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Time to sleep between autovacuum runs."),
 			NULL,
-			GUC_SUPERUSER_ONLY,
+			GUC_MANAGE_AUTOVACUUM_SETTINGS,
 			GUC_UNIT_S
 		},
 		&autovacuum_naptime,
@@ -3475,7 +3475,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_vac_thresh,
 		50, 0, INT_MAX,
@@ -3485,7 +3485,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_vac_ins_thresh,
 		1000, -1, INT_MAX,
@@ -3495,7 +3495,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_anl_thresh,
 		50, 0, INT_MAX,
@@ -3506,7 +3506,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"autovacuum_freeze_max_age", PGC_POSTMASTER, AUTOVACUUM,
 			gettext_noop("Age at which to autovacuum a table to prevent transaction ID wraparound."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_freeze_max_age,
 
@@ -3522,7 +3522,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"autovacuum_multixact_freeze_max_age", PGC_POSTMASTER, AUTOVACUUM,
 			gettext_noop("Multixact age at which to autovacuum a table to prevent multixact wraparound."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_multixact_freeze_max_age,
 		400000000, 10000, 2000000000,
@@ -3533,7 +3533,7 @@ static struct config_int ConfigureNamesInt[] =
 		{"autovacuum_max_workers", PGC_POSTMASTER, AUTOVACUUM,
 			gettext_noop("Sets the maximum number of simultaneously running autovacuum worker processes."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_max_workers,
 		3, 1, MAX_BACKENDS,
@@ -4024,7 +4024,7 @@ static struct config_real ConfigureNamesReal[] =
 		{"autovacuum_vacuum_cost_delay", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Vacuum cost delay in milliseconds, for autovacuum."),
 			NULL,
-			GUC_SUPERUSER_ONLY,
+			GUC_MANAGE_AUTOVACUUM_SETTINGS,
 			GUC_UNIT_MS
 		},
 		&autovacuum_vac_cost_delay,
@@ -4036,7 +4036,7 @@ static struct config_real ConfigureNamesReal[] =
 		{"autovacuum_vacuum_scale_factor", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Number of tuple updates or deletes prior to vacuum as a fraction of reltuples."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_vac_scale,
 		0.2, 0.0, 100.0,
@@ -4047,7 +4047,7 @@ static struct config_real ConfigureNamesReal[] =
 		{"autovacuum_vacuum_insert_scale_factor", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Number of tuple inserts prior to vacuum as a fraction of reltuples."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_vac_ins_scale,
 		0.2, 0.0, 100.0,
@@ -4058,7 +4058,7 @@ static struct config_real ConfigureNamesReal[] =
 		{"autovacuum_analyze_scale_factor", PGC_SIGHUP, AUTOVACUUM,
 			gettext_noop("Number of tuple inserts, updates, or deletes prior to analyze as a fraction of reltuples."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_AUTOVACUUM_SETTINGS
 		},
 		&autovacuum_anl_scale,
 		0.1, 0.0, 100.0,
@@ -7635,6 +7635,10 @@ role_has_privileges(Oid roleid, int privileges)
 		! has_privs_of_role(roleid, ROLE_PG_MANAGE_VACUUM_SETTINGS))
 		return false;
 
+	if ((privileges & GUC_MANAGE_AUTOVACUUM_SETTINGS) &&
+		! has_privs_of_role(roleid, ROLE_PG_MANAGE_AUTOVACUUM_SETTINGS))
+		return false;
+
 	return true;
 }
 
diff --git a/src/include/catalog/pg_authid.dat b/src/include/catalog/pg_authid.dat
index cef9b7f015..588b0954d8 100644
--- a/src/include/catalog/pg_authid.dat
+++ b/src/include/catalog/pg_authid.dat
@@ -89,5 +89,10 @@
   rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
   rolreplication => 'f', rolbypassrls => 't', rolconnlimit => '-1',
   rolpassword => '_null_', rolvaliduntil => '_null_' },
+{ oid => '9281', oid_symbol => 'ROLE_PG_MANAGE_AUTOVACUUM_SETTINGS',
+  rolname => 'pg_manage_autovacuum_settings', rolsuper => 'f', rolinherit => 't',
+  rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
+  rolreplication => 'f', rolbypassrls => 't', rolconnlimit => '-1',
+  rolpassword => '_null_', rolvaliduntil => '_null_' },
 
 ]
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 8555e3f7b8..0a24261156 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -203,6 +203,7 @@ typedef enum
  */
 #define GUC_MANAGE_HOST_RESOURCE_SETTINGS	0x0001
 #define GUC_MANAGE_VACUUM_SETTINGS			0x0002
+#define GUC_MANAGE_AUTOVACUUM_SETTINGS		0x0004
 
 /*
  * bit values in "flags" of a GUC variable
diff --git a/src/test/regress/expected/guc_privs.out b/src/test/regress/expected/guc_privs.out
index 6887a6664a..5841558ada 100644
--- a/src/test/regress/expected/guc_privs.out
+++ b/src/test/regress/expected/guc_privs.out
@@ -232,3 +232,86 @@ ERROR:  parameter "ssl_renegotiation_limit" cannot be changed
 RESET statement_timeout;
 RESET SESSION AUTHORIZATION;
 DROP ROLE regress_vacuum_admin;
+-- Test role pg_manage_autovacuum_settings
+-- Non-superuser with privileges to configure autovacuum processes
+CREATE ROLE regress_autovacuum_admin NOSUPERUSER;
+GRANT pg_manage_autovacuum_settings TO regress_autovacuum_admin;
+-- Perform all operations as user 'regress_autovacuum_admin' --
+SET SESSION AUTHORIZATION regress_autovacuum_admin;
+-- PGC_BACKEND
+SET ignore_system_indexes = OFF;  -- fail, cannot be set after connection start
+ERROR:  parameter "ignore_system_indexes" cannot be set after connection start
+RESET ignore_system_indexes;  -- fail, cannot be set after connection start
+ERROR:  parameter "ignore_system_indexes" cannot be set after connection start
+ALTER SYSTEM SET ignore_system_indexes = OFF;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "ignore_system_indexes"
+ALTER SYSTEM RESET ignore_system_indexes;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "ignore_system_indexes"
+-- PGC_INTERNAL
+SET block_size = 50;  -- fail, cannot be changed
+ERROR:  parameter "block_size" cannot be changed
+RESET block_size;  -- fail, cannot be changed
+ERROR:  parameter "block_size" cannot be changed
+ALTER SYSTEM SET block_size = 50;  -- fail, cannot be changed
+ERROR:  parameter "block_size" cannot be changed
+ALTER SYSTEM RESET block_size;  -- fail, cannot be changed
+ERROR:  parameter "block_size" cannot be changed
+-- PGC_POSTMASTER
+SET autovacuum_freeze_max_age = 1000050000;  -- fail, requires restart
+ERROR:  parameter "autovacuum_freeze_max_age" cannot be changed without restarting the server
+RESET autovacuum_freeze_max_age;  -- fail, requires restart
+ERROR:  parameter "autovacuum_freeze_max_age" cannot be changed without restarting the server
+ALTER SYSTEM SET autovacuum_freeze_max_age = 1000050000;  -- ok
+ALTER SYSTEM RESET autovacuum_freeze_max_age;  -- ok
+ALTER SYSTEM SET jit_provider = 'llvmjit';  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "jit_provider"
+ALTER SYSTEM RESET jit_provider;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "jit_provider"
+ALTER SYSTEM SET config_file = '/usr/local/data/postgresql.conf';  -- fail, cannot be changed
+ERROR:  parameter "config_file" cannot be changed
+ALTER SYSTEM RESET config_file;  -- fail, cannot be changed
+ERROR:  parameter "config_file" cannot be changed
+-- PGC_SIGHUP
+SET autovacuum = OFF;  -- fail, requires reload
+ERROR:  parameter "autovacuum" cannot be changed now
+RESET autovacuum;  -- fail, requires reload
+ERROR:  parameter "autovacuum" cannot be changed now
+ALTER SYSTEM SET autovacuum = OFF;  -- ok
+ALTER SYSTEM RESET autovacuum;  -- ok
+ALTER SYSTEM SET authentication_timeout = 50;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "authentication_timeout"
+ALTER SYSTEM RESET authentication_timeout;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "authentication_timeout"
+-- PGC_SUSET
+SET lc_messages = 'en_US.UTF-8';  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "lc_messages"
+RESET lc_messages;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "lc_messages"
+ALTER SYSTEM SET lc_messages = 'en_US.UTF-8';  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "lc_messages"
+ALTER SYSTEM RESET lc_messages;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "lc_messages"
+-- PGC_SU_BACKEND
+SET jit_debugging_support = OFF;  -- fail, cannot be set after connection start
+ERROR:  parameter "jit_debugging_support" cannot be set after connection start
+RESET jit_debugging_support;  -- fail, cannot be set after connection start
+ERROR:  parameter "jit_debugging_support" cannot be set after connection start
+ALTER SYSTEM SET jit_debugging_support = OFF;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "jit_debugging_support"
+ALTER SYSTEM RESET jit_debugging_support;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "jit_debugging_support"
+-- PGC_USERSET
+SET DateStyle = 'ISO, MDY';  -- ok
+RESET DateStyle;  -- ok
+ALTER SYSTEM SET DateStyle = 'ISO, MDY';  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "datestyle"
+ALTER SYSTEM RESET DateStyle;  -- fail, regress_autovacuum_admin has insufficient privileges
+ERROR:  permission denied to set parameter "datestyle"
+ALTER SYSTEM SET ssl_renegotiation_limit = 0;  -- fail, cannot be changed
+ERROR:  parameter "ssl_renegotiation_limit" cannot be changed
+ALTER SYSTEM RESET ssl_renegotiation_limit;  -- fail, cannot be changed
+ERROR:  parameter "ssl_renegotiation_limit" cannot be changed
+-- Finished testing role pg_manage_autovacuum_settings
+RESET statement_timeout;
+RESET SESSION AUTHORIZATION;
+DROP ROLE regress_autovacuum_admin;
diff --git a/src/test/regress/sql/guc_privs.sql b/src/test/regress/sql/guc_privs.sql
index 6e7494cb3e..9579299097 100644
--- a/src/test/regress/sql/guc_privs.sql
+++ b/src/test/regress/sql/guc_privs.sql
@@ -156,3 +156,56 @@ ALTER SYSTEM RESET ssl_renegotiation_limit;  -- fail, cannot be changed
 RESET statement_timeout;
 RESET SESSION AUTHORIZATION;
 DROP ROLE regress_vacuum_admin;
+-- Test role pg_manage_autovacuum_settings
+-- Non-superuser with privileges to configure autovacuum processes
+CREATE ROLE regress_autovacuum_admin NOSUPERUSER;
+GRANT pg_manage_autovacuum_settings TO regress_autovacuum_admin;
+-- Perform all operations as user 'regress_autovacuum_admin' --
+SET SESSION AUTHORIZATION regress_autovacuum_admin;
+-- PGC_BACKEND
+SET ignore_system_indexes = OFF;  -- fail, cannot be set after connection start
+RESET ignore_system_indexes;  -- fail, cannot be set after connection start
+ALTER SYSTEM SET ignore_system_indexes = OFF;  -- fail, regress_autovacuum_admin has insufficient privileges
+ALTER SYSTEM RESET ignore_system_indexes;  -- fail, regress_autovacuum_admin has insufficient privileges
+-- PGC_INTERNAL
+SET block_size = 50;  -- fail, cannot be changed
+RESET block_size;  -- fail, cannot be changed
+ALTER SYSTEM SET block_size = 50;  -- fail, cannot be changed
+ALTER SYSTEM RESET block_size;  -- fail, cannot be changed
+-- PGC_POSTMASTER
+SET autovacuum_freeze_max_age = 1000050000;  -- fail, requires restart
+RESET autovacuum_freeze_max_age;  -- fail, requires restart
+ALTER SYSTEM SET autovacuum_freeze_max_age = 1000050000;  -- ok
+ALTER SYSTEM RESET autovacuum_freeze_max_age;  -- ok
+ALTER SYSTEM SET jit_provider = 'llvmjit';  -- fail, regress_autovacuum_admin has insufficient privileges
+ALTER SYSTEM RESET jit_provider;  -- fail, regress_autovacuum_admin has insufficient privileges
+ALTER SYSTEM SET config_file = '/usr/local/data/postgresql.conf';  -- fail, cannot be changed
+ALTER SYSTEM RESET config_file;  -- fail, cannot be changed
+-- PGC_SIGHUP
+SET autovacuum = OFF;  -- fail, requires reload
+RESET autovacuum;  -- fail, requires reload
+ALTER SYSTEM SET autovacuum = OFF;  -- ok
+ALTER SYSTEM RESET autovacuum;  -- ok
+ALTER SYSTEM SET authentication_timeout = 50;  -- fail, regress_autovacuum_admin has insufficient privileges
+ALTER SYSTEM RESET authentication_timeout;  -- fail, regress_autovacuum_admin has insufficient privileges
+-- PGC_SUSET
+SET lc_messages = 'en_US.UTF-8';  -- fail, regress_autovacuum_admin has insufficient privileges
+RESET lc_messages;  -- fail, regress_autovacuum_admin has insufficient privileges
+ALTER SYSTEM SET lc_messages = 'en_US.UTF-8';  -- fail, regress_autovacuum_admin has insufficient privileges
+ALTER SYSTEM RESET lc_messages;  -- fail, regress_autovacuum_admin has insufficient privileges
+-- PGC_SU_BACKEND
+SET jit_debugging_support = OFF;  -- fail, cannot be set after connection start
+RESET jit_debugging_support;  -- fail, cannot be set after connection start
+ALTER SYSTEM SET jit_debugging_support = OFF;  -- fail, regress_autovacuum_admin has insufficient privileges
+ALTER SYSTEM RESET jit_debugging_support;  -- fail, regress_autovacuum_admin has insufficient privileges
+-- PGC_USERSET
+SET DateStyle = 'ISO, MDY';  -- ok
+RESET DateStyle;  -- ok
+ALTER SYSTEM SET DateStyle = 'ISO, MDY';  -- fail, regress_autovacuum_admin has insufficient privileges
+ALTER SYSTEM RESET DateStyle;  -- fail, regress_autovacuum_admin has insufficient privileges
+ALTER SYSTEM SET ssl_renegotiation_limit = 0;  -- fail, cannot be changed
+ALTER SYSTEM RESET ssl_renegotiation_limit;  -- fail, cannot be changed
+-- Finished testing role pg_manage_autovacuum_settings
+RESET statement_timeout;
+RESET SESSION AUTHORIZATION;
+DROP ROLE regress_autovacuum_admin;
-- 
2.21.1 (Apple Git-122.3)

