* Tom Lane ([EMAIL PROTECTED]) wrote:
> Stephen Frost <[EMAIL PROTECTED]> writes:
> > Tom, if you're watching, are you working on this?  I can probably spend
> > some time today on it, if that'd be helpful.
> 
> I am not; I was hoping you'd deal with SET ROLE.  Is it really much
> different from SET SESSION AUTHORIZATION?

Here's what I've got done so far on SET ROLE.  I wasn't able to get as
much done as I'd hoped to.  This is mostly just to get something posted
before the end of today in case some might think it's more of a feature
than a bug needing to be fixed (which is what I'd consider it,
personally).  I'll try and work on it some this weekend, but in the US
it's a holiday weekend and I'm pretty busy. :/

        Thanks,

                Stephen
? src/backend/parser/.gram.y.swp
Index: src/backend/commands/variable.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/variable.c,v
retrieving revision 1.109
diff -c -r1.109 variable.c
*** src/backend/commands/variable.c     28 Jun 2005 05:08:55 -0000      1.109
--- src/backend/commands/variable.c     1 Jul 2005 21:34:16 -0000
***************
*** 564,569 ****
--- 564,680 ----
  
  
  /*
+  * SET ROLE
+  *
+  * When resetting session auth after an error, we can't expect to do catalog
+  * lookups.  Hence, the stored form of the value must provide a numeric oid
+  * that can be re-used directly.  We store the string in the form of
+  * NAMEDATALEN 'x's, followed by T or F to indicate superuserness, followed
+  * by the numeric oid, followed by a comma, followed by the role name.
+  * This cannot be confused with a plain role name because of the NAMEDATALEN
+  * limit on names, so we can tell whether we're being passed an initial
+  * role name or a saved/restored value.
+  */
+ extern char *role_string;             /* in guc.c */
+ 
+ const char *
+ assign_role(const char *value, bool doit, GucSource source)
+ {
+       Oid             roleid = InvalidOid;
+       bool            is_superuser = false;
+       const char *actual_rolename = NULL;
+       char       *result;
+ 
+       if (strspn(value, "x") == NAMEDATALEN &&
+               (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'))
+       {
+               /* might be a saved userid string */
+               Oid             savedoid;
+               char       *endptr;
+ 
+               savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
+ 
+               if (endptr != value + NAMEDATALEN + 1 && *endptr == ',')
+               {
+                       /* syntactically valid, so break out the data */
+                       roleid = savedoid;
+                       is_superuser = (value[NAMEDATALEN] == 'T');
+                       actual_rolename = endptr + 1;
+               }
+       }
+ 
+       if (roleid == InvalidOid)
+       {
+               /* not a saved ID, so look it up */
+               HeapTuple       roleTup;
+ 
+               if (!IsTransactionState())
+               {
+                       /*
+                        * Can't do catalog lookups, so fail.  The upshot of 
this is
+                        * that session_authorization cannot be set in
+                        * postgresql.conf, which seems like a good thing 
anyway.
+                        */
+                       return NULL;
+               }
+ 
+               roleTup = SearchSysCache(AUTHNAME,
+                                                                
PointerGetDatum(value),
+                                                                0, 0, 0);
+               if (!HeapTupleIsValid(roleTup))
+               {
+                       if (source >= PGC_S_INTERACTIVE)
+                               ereport(ERROR,
+                                               
(errcode(ERRCODE_UNDEFINED_OBJECT),
+                                                errmsg("role \"%s\" does not 
exist", value)));
+                       return NULL;
+               }
+ 
+               roleid = HeapTupleGetOid(roleTup);
+               is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
+               actual_rolename = value;
+ 
+               ReleaseSysCache(roleTup);
+       }
+ 
+       if (doit)
+               SetRole(roleid);
+ 
+       result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_rolename));
+       if (!result)
+               return NULL;
+ 
+       memset(result, 'x', NAMEDATALEN);
+ 
+       sprintf(result + NAMEDATALEN, "%c%u,%s",
+                       is_superuser ? 'T' : 'F',
+                       roleid,
+                       actual_rolename);
+ 
+       return result;
+ }
+ 
+ const char *
+ show_role(void)
+ {
+       /*
+        * Extract the role name from the stored string; see
+        * assign_role
+        */
+       const char *value = role_string;
+       Oid             savedoid;
+       char       *endptr;
+ 
+       Assert(strspn(value, "x") == NAMEDATALEN &&
+                  (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'));
+ 
+       savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
+ 
+       Assert(endptr != value + NAMEDATALEN + 1 && *endptr == ',');
+ 
+       return endptr + 1;
+ }
+ /*
   * SET SESSION AUTHORIZATION
   *
   * When resetting session auth after an error, we can't expect to do catalog
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.501
diff -c -r2.501 gram.y
*** src/backend/parser/gram.y   29 Jun 2005 20:34:13 -0000      2.501
--- src/backend/parser/gram.y   1 Jul 2005 21:34:16 -0000
***************
*** 396,402 ****
        SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
        SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT
        STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SUPERUSER_P SYMMETRIC
!       SYSID SYSTEM_P
  
        TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP
        TO TOAST TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
--- 396,402 ----
        SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
        SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT
        STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SUPERUSER_P SYMMETRIC
!       SYSID SYSTEM_P SYSTEM_USER
  
        TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP
        TO TOAST TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
***************
*** 1004,1009 ****
--- 1004,1023 ----
                                                n->args = 
list_make1(makeStringConst($2, NULL));
                                        $$ = n;
                                }
+                       | ROLE ColId_or_Sconst
+                               {
+                                       VariableSetStmt *n = 
makeNode(VariableSetStmt);
+                                       n->name = "role";
+                                       n->args = 
list_make1(makeStringConst($2, NULL));
+                                       $$ = n;
+                               }
+                       | ROLE NONE
+                               {
+                                       VariableSetStmt *n = 
makeNode(VariableSetStmt);
+                                       n->name = "role";
+                                       n->args = NIL;
+                                       $$ = n;
+                               }
                        | SESSION AUTHORIZATION ColId_or_Sconst
                                {
                                        VariableSetStmt *n = 
makeNode(VariableSetStmt);
***************
*** 1156,1161 ****
--- 1170,1181 ----
                                        n->name = "transaction_isolation";
                                        $$ = (Node *) n;
                                }
+                       | SHOW ROLE
+                               {
+                                       VariableShowStmt *n = 
makeNode(VariableShowStmt);
+                                       n->name = "role";
+                                       $$ = (Node *) n;
+                               }
                        | SHOW SESSION AUTHORIZATION
                                {
                                        VariableShowStmt *n = 
makeNode(VariableShowStmt);
***************
*** 7067,7073 ****
                        | CURRENT_ROLE
                                {
                                        FuncCall *n = makeNode(FuncCall);
!                                       n->funcname = 
SystemFuncName("current_user");
                                        n->args = NIL;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
--- 7087,7093 ----
                        | CURRENT_ROLE
                                {
                                        FuncCall *n = makeNode(FuncCall);
!                                       n->funcname = 
SystemFuncName("current_role");
                                        n->args = NIL;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
***************
*** 7091,7096 ****
--- 7111,7125 ----
                                        n->agg_distinct = FALSE;
                                        $$ = (Node *)n;
                                }
+                       | SYSTEM_USER
+                               {
+                                       FuncCall *n = makeNode(FuncCall);
+                                       n->funcname = 
SystemFuncName("system_user");
+                                       n->args = NIL;
+                                       n->agg_star = FALSE;
+                                       n->agg_distinct = FALSE;
+                                       $$ = (Node *)n;
+                               }
                        | USER
                                {
                                        FuncCall *n = makeNode(FuncCall);
***************
*** 8221,8229 ****
                        | CONSTRAINT
                        | CREATE
                        | CURRENT_DATE
-                       | CURRENT_ROLE
                        | CURRENT_TIME
                        | CURRENT_TIMESTAMP
                        | CURRENT_USER
                        | DEFAULT
                        | DEFERRABLE
--- 8250,8258 ----
                        | CONSTRAINT
                        | CREATE
                        | CURRENT_DATE
                        | CURRENT_TIME
                        | CURRENT_TIMESTAMP
+                       | CURRENT_ROLE
                        | CURRENT_USER
                        | DEFAULT
                        | DEFERRABLE
***************
*** 8265,8270 ****
--- 8294,8300 ----
                        | SESSION_USER
                        | SOME
                        | SYMMETRIC
+                       | SYSTEM_USER
                        | TABLE
                        | THEN
                        | TO
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.162
diff -c -r1.162 keywords.c
*** src/backend/parser/keywords.c       29 Jun 2005 20:34:14 -0000      1.162
--- src/backend/parser/keywords.c       1 Jul 2005 21:34:16 -0000
***************
*** 313,318 ****
--- 313,319 ----
        {"symmetric", SYMMETRIC},
        {"sysid", SYSID},
        {"system", SYSTEM_P},
+       {"system_user", SYSTEM_USER},
        {"table", TABLE},
        {"tablespace", TABLESPACE},
        {"temp", TEMP},
Index: src/backend/utils/adt/name.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/name.c,v
retrieving revision 1.55
diff -c -r1.55 name.c
*** src/backend/utils/adt/name.c        31 Dec 2004 22:01:22 -0000      1.55
--- src/backend/utils/adt/name.c        1 Jul 2005 21:34:16 -0000
***************
*** 316,327 ****
  
  
  /*
!  * SQL-functions CURRENT_USER, SESSION_USER
   */
  Datum
  current_user(PG_FUNCTION_ARGS)
  {
!       PG_RETURN_DATUM(DirectFunctionCall1(namein, 
CStringGetDatum(GetUserNameFromId(GetUserId()))));
  }
  
  Datum
--- 316,333 ----
  
  
  /*
!  * SQL-functions CURRENT_ROLE, CURRENT_USER, SESSION_USER, SYSTEM_USER
   */
  Datum
+ current_role(PG_FUNCTION_ARGS)
+ {
+       PG_RETURN_DATUM(DirectFunctionCall1(namein, 
CStringGetDatum(GetUserNameFromId(GetCurrentRoleId()))));
+ }
+ 
+ Datum
  current_user(PG_FUNCTION_ARGS)
  {
!       PG_RETURN_DATUM(DirectFunctionCall1(namein, 
CStringGetDatum(GetUserNameFromId(GetCurrentUserId()))));
  }
  
  Datum
***************
*** 330,335 ****
--- 336,347 ----
        PG_RETURN_DATUM(DirectFunctionCall1(namein, 
CStringGetDatum(GetUserNameFromId(GetSessionUserId()))));
  }
  
+ Datum
+ system_user(PG_FUNCTION_ARGS)
+ {
+       PG_RETURN_DATUM(DirectFunctionCall1(namein, 
CStringGetDatum(GetUserNameFromId(BOOTSTRAP_SUPERUSERID))));
+ }
+ 
  
  /*
   * SQL-functions CURRENT_SCHEMA, CURRENT_SCHEMAS
Index: src/backend/utils/init/miscinit.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/init/miscinit.c,v
retrieving revision 1.144
diff -c -r1.144 miscinit.c
*** src/backend/utils/init/miscinit.c   28 Jun 2005 22:16:45 -0000      1.144
--- src/backend/utils/init/miscinit.c   1 Jul 2005 21:34:16 -0000
***************
*** 264,269 ****
--- 264,270 ----
  static Oid AuthenticatedUserId = InvalidOid;
  static Oid SessionUserId = InvalidOid;
  static Oid CurrentUserId = InvalidOid;
+ static Oid CurrentRoleId = InvalidOid;
  
  static bool AuthenticatedUserIsSuperuser = false;
  
***************
*** 273,288 ****
  Oid
  GetUserId(void)
  {
        AssertState(OidIsValid(CurrentUserId));
        return CurrentUserId;
  }
  
  
  void
! SetUserId(Oid roleid)
  {
        AssertArg(OidIsValid(roleid));
!       CurrentUserId = roleid;
  }
  
  
--- 274,329 ----
  Oid
  GetUserId(void)
  {
+       /* 
+        * The SQL spec claims CurrentUserId does not have
+        * to always be valid, but it is for us.  The spec
+        * doesn't appear to say where it could possibly be
+        * unset.
+        */
+       AssertState(OidIsValid(CurrentUserId));
+ 
+       /*
+        * CurrentRoleId is the top of the authorization 'stack'.
+        */
+       if (OidIsValid(CurrentRoleId))
+               return CurrentRoleId;
+ 
+       /*
+        * CurrentUserId is below CurrentRoleId on the stack and
+        * so is only seen if CurrentRoleId is not set.
+        * The SQL spec requires that CurrentRoleId or CurrentUserId
+        * be valid at any given time.
+        */
+       return CurrentUserId;
+ }
+ 
+ Oid
+ GetCurrentRoleId(void)
+ {
+       AssertState(OidIsValid(CurrentRoleId));
+       return CurrentRoleId;
+ }
+ 
+ Oid
+ GetCurrentUserId(void)
+ {
        AssertState(OidIsValid(CurrentUserId));
        return CurrentUserId;
  }
  
  
  void
! SetRoleId(Oid roleid)
  {
        AssertArg(OidIsValid(roleid));
!       CurrentRoleId = roleid;
! }
! 
! void
! SetUserId(Oid userid)
! {
!       AssertArg(OidIsValid(userid));
!       CurrentUserId = userid;
  }
  
  
***************
*** 298,310 ****
  
  
  void
! SetSessionUserId(Oid roleid)
  {
!       AssertArg(OidIsValid(roleid));
!       SessionUserId = roleid;
        /* Current user defaults to session user. */
        if (!OidIsValid(CurrentUserId))
!               CurrentUserId = roleid;
  }
  
  
--- 339,354 ----
  
  
  void
! SetSessionUserId(Oid userid)
  {
!       AssertArg(OidIsValid(userid));
!       SessionUserId = userid;
        /* Current user defaults to session user. */
        if (!OidIsValid(CurrentUserId))
!               CurrentUserId = userid;
! 
!       /* Per SQL-spec, current role defaults to invalid */
!       CurrentRoleId = InvalidOid;
  }
  
  
***************
*** 416,421 ****
--- 460,484 ----
                                        PGC_INTERNAL, PGC_S_OVERRIDE);
  }
  
+ /*
+  * Change Role ID while running
+  *
+  * The current user must be in the role to which they want to change.
+  */
+ void
+ SetCurrentRole(Oid roleid)
+ {
+       /* Must have authenticated already, else can't make permission check */
+       AssertState(OidIsValid(AuthenticatedUserId));
+ 
+       if (!is_member_of_role(GetUserId(),roleid))
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                         errmsg("permission denied to set current role")));
+ 
+       SetRoleId(roleid);
+ }
+ 
  
  /*
   * Get user name from user oid
Index: src/backend/utils/misc/check_guc
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/check_guc,v
retrieving revision 1.8
diff -c -r1.8 check_guc
*** src/backend/utils/misc/check_guc    27 Jun 2003 19:08:38 -0000      1.8
--- src/backend/utils/misc/check_guc    1 Jul 2005 21:34:16 -0000
***************
*** 18,24 ****
  ## can be ignored
  INTENTIONALLY_NOT_INCLUDED="autocommit debug_deadlocks exit_on_error \
  is_superuser lc_collate lc_ctype lc_messages lc_monetary lc_numeric lc_time \
! pre_auth_delay seed server_encoding server_version session_authorization \
  trace_lock_oidmin trace_lock_table trace_locks trace_lwlocks trace_notify \
  trace_userlocks transaction_isolation transaction_read_only \
  zero_damaged_pages"
--- 18,24 ----
  ## can be ignored
  INTENTIONALLY_NOT_INCLUDED="autocommit debug_deadlocks exit_on_error \
  is_superuser lc_collate lc_ctype lc_messages lc_monetary lc_numeric lc_time \
! pre_auth_delay role seed server_encoding server_version session_authorization 
\
  trace_lock_oidmin trace_lock_table trace_locks trace_lwlocks trace_notify \
  trace_userlocks transaction_isolation transaction_read_only \
  zero_damaged_pages"
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.271
diff -c -r1.271 guc.c
*** src/backend/utils/misc/guc.c        28 Jun 2005 05:09:02 -0000      1.271
--- src/backend/utils/misc/guc.c        1 Jul 2005 21:34:17 -0000
***************
*** 195,200 ****
--- 195,203 ----
  /* should be static, but commands/variable.c needs to get at it */
  char     *session_authorization_string;
  
+ /* should be static, but commands/variable.c needs to get at it */
+ char     *role_string;
+ 
  
  /*
   * Displayable names for context types (enum GucContext)
***************
*** 1751,1756 ****
--- 1754,1770 ----
        },
  
        {
+               /* Not for general use --- used by SET ROLE */
+               {"role", PGC_USERSET, UNGROUPED,
+                       gettext_noop("Sets the current role."),
+                       NULL,
+                       GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | 
GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+               },
+               &role_string,
+               NULL, assign_role, show_role
+       },
+ 
+       {
                /* Not for general use --- used by SET SESSION AUTHORIZATION */
                {"session_authorization", PGC_USERSET, UNGROUPED,
                        gettext_noop("Sets the session user name."),
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.372
diff -c -r1.372 pg_proc.h
*** src/include/catalog/pg_proc.h       28 Jun 2005 05:09:09 -0000      1.372
--- src/include/catalog/pg_proc.h       1 Jul 2005 21:34:17 -0000
***************
*** 1003,1012 ****
--- 1003,1016 ----
  DATA(insert OID = 743 (  text_ge                 PGNSP PGUID 12 f f t f i 2 
16 "25 25" _null_ _null_ _null_ text_ge - _null_ ));
  DESCR("greater-than-or-equal");
  
+ DATA(insert OID = 1136 (  current_role           PGNSP PGUID 12 f f t f s 0 
19 "" _null_ _null_ _null_ current_role - _null_ ));
+ DESCR("current role name");
  DATA(insert OID = 745 (  current_user    PGNSP PGUID 12 f f t f s 0 19 "" 
_null_ _null_ _null_ current_user - _null_ ));
  DESCR("current user name");
  DATA(insert OID = 746 (  session_user    PGNSP PGUID 12 f f t f s 0 19 "" 
_null_ _null_ _null_ session_user - _null_ ));
  DESCR("session user name");
+ DATA(insert OID = 1137 (  system_user    PGNSP PGUID 12 f f t f s 0 19 "" 
_null_ _null_ _null_ system_user - _null_ ));
+ DESCR("system user name");
  
  DATA(insert OID = 744 (  array_eq                PGNSP PGUID 12 f f t f i 2 
16 "2277 2277" _null_ _null_ _null_ array_eq - _null_ ));
  DESCR("array equal");
Index: src/include/commands/variable.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/variable.h,v
retrieving revision 1.25
diff -c -r1.25 variable.h
*** src/include/commands/variable.h     31 Dec 2004 22:03:28 -0000      1.25
--- src/include/commands/variable.h     1 Jul 2005 21:34:17 -0000
***************
*** 26,31 ****
--- 26,34 ----
  extern const char *show_random_seed(void);
  extern const char *assign_client_encoding(const char *value,
                                           bool doit, GucSource source);
+ extern const char *assign_role(const char *value,
+                                                        bool doit, GucSource 
source);
+ extern const char *show_role(void);
  extern const char *assign_session_authorization(const char *value,
                                                         bool doit, GucSource 
source);
  extern const char *show_session_authorization(void);
Index: src/include/utils/builtins.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.258
diff -c -r1.258 builtins.h
*** src/include/utils/builtins.h        17 Jun 2005 22:32:50 -0000      1.258
--- src/include/utils/builtins.h        1 Jul 2005 21:34:17 -0000
***************
*** 207,214 ****
--- 207,216 ----
  extern int    namecpy(Name n1, Name n2);
  extern int    namestrcpy(Name name, const char *str);
  extern int    namestrcmp(Name name, const char *str);
+ extern Datum current_role(PG_FUNCTION_ARGS);
  extern Datum current_user(PG_FUNCTION_ARGS);
  extern Datum session_user(PG_FUNCTION_ARGS);
+ extern Datum system_user(PG_FUNCTION_ARGS);
  extern Datum current_schema(PG_FUNCTION_ARGS);
  extern Datum current_schemas(PG_FUNCTION_ARGS);
  

Attachment: signature.asc
Description: Digital signature

Reply via email to