? 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);