diff --git a/doc/src/sgml/ref/set_session_auth.sgml b/doc/src/sgml/ref/set_session_auth.sgml
index fa427c10259e7735afffa9c73ba38bde1e958c8a..7cd0d7d1ec7195713e5f23ac9044d77fa710a7fd 100644
--- a/doc/src/sgml/ref/set_session_auth.sgml
+++ b/doc/src/sgml/ref/set_session_auth.sgml
@@ -1,4 +1,4 @@
-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/set_session_auth.sgml,v 1.4 2002/01/20 22:19:57 petere Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/set_session_auth.sgml,v 1.5 2002/05/06 19:47:30 tgl Exp $ -->
 <refentry id="SQL-SET-SESSION-AUTHORIZATION">
  <docinfo>
   <date>2001-04-21</date>
@@ -16,7 +16,9 @@
 
  <refsynopsisdiv>
 <synopsis>
-SET SESSION AUTHORIZATION '<parameter>username</parameter>'
+SET SESSION AUTHORIZATION <parameter>username</parameter>
+SET SESSION AUTHORIZATION DEFAULT
+RESET SESSION AUTHORIZATION
 </synopsis>
  </refsynopsisdiv>
 
@@ -26,7 +28,11 @@ SET SESSION AUTHORIZATION '<parameter>username</parameter>'
   <para>
    This command sets the session user identifier and the current user
    identifier of the current SQL-session context to be
-   <parameter>username</parameter>.
+   <parameter>username</parameter>.  The user name may be written as
+   either an identifier or a string literal.
+   The session user identifier is valid for the duration of a
+   connection; for example, it is possible to temporarily become an
+   unprivileged user and later switch back to become a superuser.
   </para>
 
   <para>
@@ -39,12 +45,18 @@ SET SESSION AUTHORIZATION '<parameter>username</parameter>'
   </para>
 
   <para>
-   Execution of this command is only permitted if the initial session
+   The session user identifier may be changed only if the initial session
    user (the <firstterm>authenticated user</firstterm>) had the
-   superuser privilege.  This permission is kept for the duration of a
-   connection; for example, it is possible to temporarily become an
-   unprivileged user and later switch back to become a superuser.
+   superuser privilege.  Otherwise, the command is accepted only if it
+   specifies the authenticated username.
   </para>
+
+  <para>
+   The <literal>DEFAULT</> and <literal>RESET</> forms reset the session
+   and current user identifiers to be the originally authenticated user
+   name.  These forms are always accepted.
+  </para>
+
  </refsect1>
 
  <refsect1>
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 301a3c86a7449f574edbd333f1ce0d3f91711ab5..de42538bd63107c41fe4bce5de70450f4c10c881 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.65 2002/04/22 15:13:53 thomas Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.66 2002/05/06 19:47:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -815,6 +815,15 @@ reset_server_encoding(void)
 }
 
 
+static bool
+show_session_authorization(void)
+{
+	elog(INFO, "Current session authorization is '%s'",
+		 GetUserName(GetSessionUserId()));
+	return TRUE;
+}
+
+
 
 /* SetPGVariable()
  * Dispatcher for handling SET commands.
@@ -902,6 +911,8 @@ GetPGVariable(const char *name)
 		show_server_encoding();
 	else if (strcasecmp(name, "seed") == 0)
 		show_random_seed();
+	else if (strcasecmp(name, "session_authorization") == 0)
+		show_session_authorization();
 	else if (strcasecmp(name, "all") == 0)
 	{
 		ShowAllGUCConfig();
@@ -935,6 +946,8 @@ ResetPGVariable(const char *name)
 		reset_server_encoding();
 	else if (strcasecmp(name, "seed") == 0)
 		reset_random_seed();
+	else if (strcasecmp(name, "session_authorization") == 0)
+		SetSessionAuthorization(NULL);
 	else if (strcasecmp(name, "all") == 0)
 	{
 		reset_random_seed();
@@ -942,6 +955,7 @@ ResetPGVariable(const char *name)
 		reset_client_encoding();
 		reset_datestyle();
 		reset_timezone();
+		/* should we reset session authorization here? */
 
 		ResetAllOptions(false);
 	}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1d1b7a78a29b9c79a742063150ce5fff922b0101..258a11c11832c2cec6ff72442b3367d826a65480 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.312 2002/05/03 00:32:16 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.313 2002/05/06 19:47:30 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -281,7 +281,7 @@ static void doNegateFloat(Value *v);
 %type <ival>	Iconst
 %type <str>		Sconst, comment_text
 %type <str>		UserId, opt_boolean, ColId_or_Sconst
-%type <list>	var_list
+%type <list>	var_list, var_list_or_default
 %type <str>		ColId, ColLabel, type_name
 %type <node>	var_value, zone_value
 
@@ -833,14 +833,14 @@ schema_stmt: CreateStmt
  *
  *****************************************************************************/
 
-VariableSetStmt:  SET ColId TO var_list
+VariableSetStmt:  SET ColId TO var_list_or_default
 				{
 					VariableSetStmt *n = makeNode(VariableSetStmt);
 					n->name  = $2;
 					n->args = $4;
 					$$ = (Node *) n;
 				}
-		| SET ColId '=' var_list
+		| SET ColId '=' var_list_or_default
 				{
 					VariableSetStmt *n = makeNode(VariableSetStmt);
 					n->name  = $2;
@@ -884,14 +884,25 @@ VariableSetStmt:  SET ColId TO var_list
 					n->args = makeList1(makeStringConst($4, NULL));
 					$$ = (Node *) n;
 				}
+		| SET SESSION AUTHORIZATION DEFAULT
+				{
+					VariableSetStmt *n = makeNode(VariableSetStmt);
+					n->name = "session_authorization";
+					n->args = NIL;
+					$$ = (Node *) n;
+				}
+		;
+
+var_list_or_default:  var_list
+				{ $$ = $1; }
+		| DEFAULT
+				{ $$ = NIL; }
 		;
 
 var_list:  var_value
 				{	$$ = makeList1($1); }
 		| var_list ',' var_value
 				{	$$ = lappend($1, $3); }
-		| DEFAULT
-				{ $$ = NIL; }
 		;
 
 var_value:  opt_boolean
@@ -1017,6 +1028,12 @@ VariableResetStmt:	RESET ColId
 					n->name  = "XactIsoLevel";
 					$$ = (Node *) n;
 				}
+		| RESET SESSION AUTHORIZATION
+				{
+					VariableResetStmt *n = makeNode(VariableResetStmt);
+					n->name = "session_authorization";
+					$$ = (Node *) n;
+				}
 		| RESET ALL
 				{
 					VariableResetStmt *n = makeNode(VariableResetStmt);
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 91c5a3eb2f5240af4d613e74c042fe57d23a1955..4cc9d396c70b470a460396d3261dfea903fac9e7 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.89 2002/05/05 00:03:29 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.90 2002/05/06 19:47:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -529,15 +529,17 @@ GetCharSetByHost(char *TableName, int host, const char *DataDir)
 /* ----------------------------------------------------------------
  *	User ID things
  *
- * The session user is determined at connection start and never
- * changes.  The current user may change when "setuid" functions
+ * The authenticated user is determined at connection start and never
+ * changes.  The session user can be changed only by SET SESSION
+ * AUTHORIZATION.  The current user may change when "setuid" functions
  * are implemented.  Conceptually there is a stack, whose bottom
  * is the session user.  You are yourself responsible to save and
  * restore the current user id if you need to change it.
  * ----------------------------------------------------------------
  */
-static Oid	CurrentUserId = InvalidOid;
+static Oid	AuthenticatedUserId = InvalidOid;
 static Oid	SessionUserId = InvalidOid;
+static Oid	CurrentUserId = InvalidOid;
 
 static bool AuthenticatedUserIsSuperuser = false;
 
@@ -588,6 +590,7 @@ InitializeSessionUserId(const char *username)
 	HeapTuple	userTup;
 	Datum		datum;
 	bool		isnull;
+	Oid			usesysid;
 
 	/*
 	 * Don't do scans if we're bootstrapping, none of the system catalogs
@@ -596,7 +599,7 @@ InitializeSessionUserId(const char *username)
 	AssertState(!IsBootstrapProcessingMode());
 
 	/* call only once */
-	AssertState(!OidIsValid(SessionUserId));
+	AssertState(!OidIsValid(AuthenticatedUserId));
 
 	userTup = SearchSysCache(SHADOWNAME,
 							 PointerGetDatum(username),
@@ -604,10 +607,14 @@ InitializeSessionUserId(const char *username)
 	if (!HeapTupleIsValid(userTup))
 		elog(FATAL, "user \"%s\" does not exist", username);
 
-	SetSessionUserId(((Form_pg_shadow) GETSTRUCT(userTup))->usesysid);
+	usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
 
+	AuthenticatedUserId = usesysid;
 	AuthenticatedUserIsSuperuser = ((Form_pg_shadow) GETSTRUCT(userTup))->usesuper;
 
+	SetSessionUserId(usesysid);	/* sets CurrentUserId too */
+
+
 	/*
 	 * Set up user-specific configuration variables.  This is a good
 	 * place to do it so we don't have to read pg_shadow twice during
@@ -633,25 +640,36 @@ InitializeSessionUserIdStandalone(void)
 	AssertState(!IsUnderPostmaster);
 
 	/* call only once */
-	AssertState(!OidIsValid(SessionUserId));
+	AssertState(!OidIsValid(AuthenticatedUserId));
 
-	SetSessionUserId(BOOTSTRAP_USESYSID);
+	AuthenticatedUserId = BOOTSTRAP_USESYSID;
 	AuthenticatedUserIsSuperuser = true;
+
+	SetSessionUserId(BOOTSTRAP_USESYSID);
 }
 
 
 /*
  * Change session auth ID while running
+ *
+ * Only a superuser may set auth ID to something other than himself.
+ *
+ * username == NULL implies reset to default (AuthenticatedUserId).
  */
 void
 SetSessionAuthorization(const char *username)
 {
-	int32		userid;
-
-	if (!AuthenticatedUserIsSuperuser)
-		elog(ERROR, "permission denied");
+	Oid		userid;
 
-	userid = get_usesysid(username);
+	if (username == NULL)
+		userid = AuthenticatedUserId;
+	else
+	{
+		userid = get_usesysid(username);
+		if (userid != AuthenticatedUserId &&
+			!AuthenticatedUserIsSuperuser)
+			elog(ERROR, "permission denied");
+	}
 
 	SetSessionUserId(userid);
 	SetUserId(userid);