From fc1291d980626f34e8be8524d871c5f2c401bc71 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 20 Oct 2021 07:53:28 -0700
Subject: [PATCH v1 12/12] Adding role pg_manage_error_handling_settings

This new role can SET or ALTER SYSTEM SET any GUC variable which
controls error handling settings.
---
 doc/src/sgml/user-manag.sgml            | 13 ++--
 src/backend/utils/misc/guc.c            |  8 ++-
 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, 157 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml
index c97350ee92..b459a4e3c0 100644
--- a/doc/src/sgml/user-manag.sgml
+++ b/doc/src/sgml/user-manag.sgml
@@ -622,6 +622,10 @@ DROP ROLE doomed_role;
        <entry>pg_manage_recovery_settings</entry>
        <entry>Allow changing settings which control or are generally used for recovery.</entry>
       </row>
+      <row>
+       <entry>pg_manage_error_handling_settings</entry>
+       <entry>Allow changing settings which control how errors are handled.</entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
@@ -675,10 +679,11 @@ DROP ROLE doomed_role;
   <literal>pg_manage_connection_settings</literal>,
   <literal>pg_manage_wal_settings</literal>,
   <literal>pg_manage_query_tuning_settings</literal>,
-  <literal>pg_manage_stats_settings</literal> and
-  <literal>pg_manage_recovery_settings</literal> roles are intended to allow
-  administrators to have trusted, but non-superuser, roles to configure the
-  server.
+  <literal>pg_manage_stats_settings</literal>,
+  <literal>pg_manage_recovery_settings</literal> and
+  <literal>pg_manage_error_handling_settings</literal> roles are intended to
+  allow administrators to have trusted, but non-superuser, roles to configure
+  the server.
   </para>
 
   <para>
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 5e52b5544d..bc9ddeae38 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1437,7 +1437,7 @@ static struct config_bool ConfigureNamesBool[] =
 		{"exit_on_error", PGC_USERSET, ERROR_HANDLING_OPTIONS,
 			gettext_noop("Terminate session on any error."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_ERROR_HANDLING_SETTINGS
 		},
 		&ExitOnAnyError,
 		false,
@@ -2210,7 +2210,7 @@ static struct config_bool ConfigureNamesBool[] =
 		{"data_sync_retry", PGC_POSTMASTER, ERROR_HANDLING_OPTIONS,
 			gettext_noop("Whether to continue running after a failure to sync data files."),
 			NULL,
-			GUC_SUPERUSER_ONLY
+			GUC_MANAGE_ERROR_HANDLING_SETTINGS
 		},
 		&data_sync_retry,
 		false,
@@ -7671,6 +7671,10 @@ role_has_privileges(Oid roleid, int privileges)
 		! has_privs_of_role(roleid, ROLE_PG_MANAGE_RECOVERY_SETTINGS))
 		return false;
 
+	if ((privileges & GUC_MANAGE_ERROR_HANDLING_SETTINGS) &&
+		! has_privs_of_role(roleid, ROLE_PG_MANAGE_ERROR_HANDLING_SETTINGS))
+		return false;
+
 	return true;
 }
 
diff --git a/src/include/catalog/pg_authid.dat b/src/include/catalog/pg_authid.dat
index 05ac06ccc9..88505dc6d0 100644
--- a/src/include/catalog/pg_authid.dat
+++ b/src/include/catalog/pg_authid.dat
@@ -129,5 +129,10 @@
   rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
   rolreplication => 'f', rolbypassrls => 't', rolconnlimit => '-1',
   rolpassword => '_null_', rolvaliduntil => '_null_' },
+{ oid => '9289', oid_symbol => 'ROLE_PG_MANAGE_ERROR_HANDLING_SETTINGS',
+  rolname => 'pg_manage_error_handling_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 fe1e4b0c4c..d090518b14 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -212,6 +212,7 @@ typedef enum
 #define GUC_MANAGE_QUERY_TUNING_SETTINGS	0x0200	/* 0x0100 = superuser */
 #define GUC_MANAGE_STATS_SETTINGS			0x0400
 #define GUC_MANAGE_RECOVERY_SETTINGS		0x0800
+#define GUC_MANAGE_ERROR_HANDLING_SETTINGS	0x1000
 
 /*
  * 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 91f28d4b75..ee6665a795 100644
--- a/src/test/regress/expected/guc_privs.out
+++ b/src/test/regress/expected/guc_privs.out
@@ -1098,3 +1098,86 @@ ERROR:  parameter "ssl_renegotiation_limit" cannot be changed
 RESET statement_timeout;
 RESET SESSION AUTHORIZATION;
 DROP ROLE regress_recovery_admin;
+-- Test role pg_manage_error_handling_settings
+-- Non-superuser with privileges to configure error handling
+CREATE ROLE regress_error_handling_admin NOSUPERUSER;
+GRANT pg_manage_error_handling_settings TO regress_error_handling_admin;
+-- Perform all operations as user 'regress_error_handling_admin' --
+SET SESSION AUTHORIZATION regress_error_handling_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_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "ignore_system_indexes"
+ALTER SYSTEM RESET ignore_system_indexes;  -- fail, regress_error_handling_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;  -- fail, regress_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "autovacuum_freeze_max_age"
+ALTER SYSTEM RESET autovacuum_freeze_max_age;  -- fail, regress_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "autovacuum_freeze_max_age"
+ALTER SYSTEM SET data_sync_retry = OFF;  -- ok
+ALTER SYSTEM RESET data_sync_retry;  -- ok
+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;  -- fail, regress_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "autovacuum"
+ALTER SYSTEM RESET autovacuum;  -- fail, regress_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "autovacuum"
+-- PGC_SUSET
+SET lc_messages = 'en_US.UTF-8';  -- fail, regress_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "lc_messages"
+RESET lc_messages;  -- fail, regress_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "lc_messages"
+ALTER SYSTEM SET lc_messages = 'en_US.UTF-8';  -- fail, regress_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "lc_messages"
+ALTER SYSTEM RESET lc_messages;  -- fail, regress_error_handling_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_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "jit_debugging_support"
+ALTER SYSTEM RESET jit_debugging_support;  -- fail, regress_error_handling_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_error_handling_admin has insufficient privileges
+ERROR:  permission denied to set parameter "datestyle"
+ALTER SYSTEM RESET DateStyle;  -- fail, regress_error_handling_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
+ALTER SYSTEM SET exit_on_error = OFF;  -- ok
+ALTER SYSTEM RESET exit_on_error;  -- ok
+-- Finished testing role pg_manage_error_handling_settings
+RESET statement_timeout;
+RESET SESSION AUTHORIZATION;
+DROP ROLE regress_error_handling_admin;
diff --git a/src/test/regress/sql/guc_privs.sql b/src/test/regress/sql/guc_privs.sql
index bb25b00e2a..5c21ac3a78 100644
--- a/src/test/regress/sql/guc_privs.sql
+++ b/src/test/regress/sql/guc_privs.sql
@@ -722,3 +722,56 @@ ALTER SYSTEM RESET ssl_renegotiation_limit;  -- fail, cannot be changed
 RESET statement_timeout;
 RESET SESSION AUTHORIZATION;
 DROP ROLE regress_recovery_admin;
+-- Test role pg_manage_error_handling_settings
+-- Non-superuser with privileges to configure error handling
+CREATE ROLE regress_error_handling_admin NOSUPERUSER;
+GRANT pg_manage_error_handling_settings TO regress_error_handling_admin;
+-- Perform all operations as user 'regress_error_handling_admin' --
+SET SESSION AUTHORIZATION regress_error_handling_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_error_handling_admin has insufficient privileges
+ALTER SYSTEM RESET ignore_system_indexes;  -- fail, regress_error_handling_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;  -- fail, regress_error_handling_admin has insufficient privileges
+ALTER SYSTEM RESET autovacuum_freeze_max_age;  -- fail, regress_error_handling_admin has insufficient privileges
+ALTER SYSTEM SET data_sync_retry = OFF;  -- ok
+ALTER SYSTEM RESET data_sync_retry;  -- ok
+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;  -- fail, regress_error_handling_admin has insufficient privileges
+ALTER SYSTEM RESET autovacuum;  -- fail, regress_error_handling_admin has insufficient privileges
+-- PGC_SUSET
+SET lc_messages = 'en_US.UTF-8';  -- fail, regress_error_handling_admin has insufficient privileges
+RESET lc_messages;  -- fail, regress_error_handling_admin has insufficient privileges
+ALTER SYSTEM SET lc_messages = 'en_US.UTF-8';  -- fail, regress_error_handling_admin has insufficient privileges
+ALTER SYSTEM RESET lc_messages;  -- fail, regress_error_handling_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_error_handling_admin has insufficient privileges
+ALTER SYSTEM RESET jit_debugging_support;  -- fail, regress_error_handling_admin has insufficient privileges
+-- PGC_USERSET
+SET DateStyle = 'ISO, MDY';  -- ok
+RESET DateStyle;  -- ok
+ALTER SYSTEM SET DateStyle = 'ISO, MDY';  -- fail, regress_error_handling_admin has insufficient privileges
+ALTER SYSTEM RESET DateStyle;  -- fail, regress_error_handling_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
+ALTER SYSTEM SET exit_on_error = OFF;  -- ok
+ALTER SYSTEM RESET exit_on_error;  -- ok
+-- Finished testing role pg_manage_error_handling_settings
+RESET statement_timeout;
+RESET SESSION AUTHORIZATION;
+DROP ROLE regress_error_handling_admin;
-- 
2.21.1 (Apple Git-122.3)

