Re: is_superuser versus set_config_option's parallelism check - Mailing list pgsql-hackers

From Tom Lane
Subject Re: is_superuser versus set_config_option's parallelism check
Date
Msg-id 2920499.1723233855@sss.pgh.pa.us
Whole thread Raw
In response to Re: is_superuser versus set_config_option's parallelism check  (Nathan Bossart <nathandbossart@gmail.com>)
Responses Re: is_superuser versus set_config_option's parallelism check
List pgsql-hackers
Nathan Bossart <nathandbossart@gmail.com> writes:
> On Fri, Aug 09, 2024 at 02:43:59PM -0400, Tom Lane wrote:
>> The simplest fix would be to hack this test to allow the action anyway
>> when context == PGC_INTERNAL, excusing that as "assume the caller
>> knows what it's doing".  That feels pretty grotty though.  Perhaps
>> a cleaner way would be to move this check to some higher code level,
>> but I'm not sure where would be a good place.

> From a couple of quick tests, it looks like setting
> "current_role_is_superuser" directly works.

Yeah, I had been thinking along the same lines.  Here's a draft
patch.  (Still needs some attention to nearby comments, and I can't
avoid the impression that the miscinit.c code in this area could
use refactoring.)

A problem with this is that it couldn't readily be back-patched
further than v14, since we didn't have ReportChangedGUCOptions
before that.  Maybe that doesn't matter; given the lack of
previous complaints, maybe we only need to fix this in HEAD.

            regards, tom lane

diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 6202c5ebe4..7b98b03c10 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -1026,6 +1026,19 @@ show_role(void)
     return role_string ? role_string : "none";
 }

+const char *
+show_is_superuser(void)
+{
+    /*
+     * Report the real value of current_role_is_superuser, not the
+     * possibly-stale value in the GUC mechanism.  The reason we do things
+     * this way is to avoid the overhead and extra failure modes that'd be
+     * involved in using SetConfigOption to set is_superuser every time we
+     * update the session_authorization or role GUCs.
+     */
+    return current_role_is_superuser ? "on" : "off";
+}
+

 /*
  * PATH VARIABLES
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 537d92c0cf..4052b16ecb 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -822,9 +822,7 @@ InitializeSessionUserId(const char *rolename, Oid roleid, bool bypass_login_chec
     /* Record username and superuser status as GUC settings too */
     SetConfigOption("session_authorization", rname,
                     PGC_BACKEND, PGC_S_OVERRIDE);
-    SetConfigOption("is_superuser",
-                    is_superuser ? "on" : "off",
-                    PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+    current_role_is_superuser = is_superuser;

     ReleaseSysCache(roleTup);
 }
@@ -854,8 +852,7 @@ InitializeSessionUserIdStandalone(void)
      * Since we don't, C code will get NULL, and current_setting() will get an
      * empty string.
      */
-    SetConfigOption("is_superuser", "on",
-                    PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+    current_role_is_superuser = true;
 }

 /*
@@ -909,9 +906,7 @@ SetSessionAuthorization(Oid userid, bool is_superuser)
 {
     SetSessionUserId(userid, is_superuser);

-    SetConfigOption("is_superuser",
-                    is_superuser ? "on" : "off",
-                    PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+    current_role_is_superuser = is_superuser;
 }

 /*
@@ -966,9 +961,7 @@ SetCurrentRoleId(Oid roleid, bool is_superuser)

     SetOuterUserId(roleid);

-    SetConfigOption("is_superuser",
-                    is_superuser ? "on" : "off",
-                    PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+    current_role_is_superuser = is_superuser;
 }


diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0c593b81b4..f99975ed61 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2610,6 +2610,15 @@ ReportChangedGUCOptions(void)
         SetConfigOption("in_hot_standby", "false",
                         PGC_INTERNAL, PGC_S_OVERRIDE);

+    /*
+     * Also, check to see if we need to update the is_superuser GUC.  This is
+     * to queue a guc_report_list entry if needed.
+     */
+    if (current_role_is_superuser != current_role_is_superuser_guc)
+        SetConfigOption("is_superuser",
+                        current_role_is_superuser ? "on" : "off",
+                        PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+
     /* Transmit new values of interesting variables */
     slist_foreach_modify(iter, &guc_report_list)
     {
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index c0a52cdcc3..cf09c59e40 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -516,7 +516,8 @@ bool        check_function_bodies = true;
  */
 static bool default_with_oids = false;

-bool        current_role_is_superuser;
+bool        current_role_is_superuser;    /* this is the "real" status */
+bool        current_role_is_superuser_guc;    /* but the GUC table points here */

 int            log_min_error_statement = ERROR;
 int            log_min_messages = WARNING;
@@ -1017,9 +1018,9 @@ struct config_bool ConfigureNamesBool[] =
             NULL,
             GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
         },
-        ¤t_role_is_superuser,
+        ¤t_role_is_superuser_guc,
         false,
-        NULL, NULL, NULL
+        NULL, NULL, show_is_superuser
     },
     {
         /*
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 4129ea37ee..efdb4fc815 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -260,6 +260,7 @@ extern PGDLLIMPORT char *event_source;

 extern PGDLLIMPORT bool check_function_bodies;
 extern PGDLLIMPORT bool current_role_is_superuser;
+extern PGDLLIMPORT bool current_role_is_superuser_guc;    /* don't use this */

 extern PGDLLIMPORT bool AllowAlterSystem;
 extern PGDLLIMPORT bool log_duration;
diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h
index 5813dba0a2..d10eb44a2c 100644
--- a/src/include/utils/guc_hooks.h
+++ b/src/include/utils/guc_hooks.h
@@ -121,6 +121,7 @@ extern void assign_recovery_target_xid(const char *newval, void *extra);
 extern bool check_role(char **newval, void **extra, GucSource source);
 extern void assign_role(const char *newval, void *extra);
 extern const char *show_role(void);
+extern const char *show_is_superuser(void);
 extern bool check_restrict_nonsystem_relation_kind(char **newval, void **extra,
                                                    GucSource source);
 extern void assign_restrict_nonsystem_relation_kind(const char *newval, void *extra);

pgsql-hackers by date:

Previous
From: Bertrand Drouvot
Date:
Subject: Re: Restart pg_usleep when interrupted
Next
From: Corey Huinker
Date:
Subject: Re: optimizing pg_upgrade's once-in-each-database steps