diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 593041a5875a34c30e9d57890bb19e7b4ad6e617..3e3266cf5f36a48cca44eeac4c43db955bd48806 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.35 2000/08/29 20:02:07 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.36 2000/09/19 18:17:53 petere Exp $
 -->
 
  <chapter id="datatype">
@@ -211,11 +211,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.35 2000/08/29 20:02:07 mo
       </row>
      </thead>
      <tbody>
-      <row>
-       <entry>getpgusername()</entry>
-       <entry>current_user</entry>
-       <entry>user name in current session</entry>
-      </row>
       <row>
        <entry>date('now')</entry>
        <entry>current_date</entry>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 9f8fdd89324cc64b69ff0438012468b31baa823e..0306f7cf05ca1125950fe53e685fb7208faee670 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1509,6 +1509,61 @@ Not defined by this name. Implements the intersection operator '#'
 
   </sect1>
 
+  <sect1>
+   <title id="misc-funcs">Miscellaneous Functions</>
+
+   <table>
+    <title>Miscellaneous Functions</>
+    <tgroup cols="3">
+     <thead>
+      <row><entry>Name</> <entry>Return type</> <entry>Description</></row>
+     </thead>
+
+     <tbody>
+      <row>
+       <entry>current_user</>
+       <entry>name</>
+       <entry>user name of current execution context</>
+      </row>
+      <row>
+       <entry>user</>
+       <entry>name</>
+       <entry>equivalent to <function>current_user</></>
+      </row>
+      <row>
+       <entry>session_user</>
+       <entry>name</>
+       <entry>session user name</>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para>
+    The <function>session_user</> is the user that initiated a database
+    connection and is fixed for the duration of that connection. The
+    <function>current_user</> is the user identifier that is applicable
+    for permission checking. Currently it is always equal to the session
+    user, but in the future there might be <quote>setuid</> functions and
+    other facilities to allow the current user to change temporarily.
+    In Unix parlance, the session user is the <quote>real user</>
+    and the current user is the <quote>effective user</>.
+   </para>
+
+   <para>
+    Note that these functions have special syntactic status in <acronym>SQL</>;
+    they must be called without trailing parentheses.
+   </para>
+
+   <note>
+    <title>Deprecated</>
+    <para>
+     The function <function>getpgusername()</> is an obsolete equivalent
+     of <function>current_user</>.
+    </para>
+   </note>
+  </sect1>
+
   <sect1>
    <title id="aggregate-funcs">Aggregate Functions</title>
 
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 25150818a722e41ee9172660a228a0017ea07f79..cc57eb7068c335f59421b674966408ed8ba2d7af 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.67 2000/08/27 21:50:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.68 2000/09/19 18:17:54 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -348,7 +348,7 @@ AlterUser(AlterUserStmt *stmt)
 	/* must be superuser or just want to change your own password */
 	if (!superuser() &&
 	  !(stmt->createdb == 0 && stmt->createuser == 0 && !stmt->validUntil
-		&& stmt->password && strcmp(GetPgUserName(), stmt->user) == 0))
+		&& stmt->password && strcmp(GetUserName(GetUserId()), stmt->user) == 0))
 		elog(ERROR, "ALTER USER: permission denied");
 
 	/* changes to the flat password file cannot be rolled back */
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c12cf997b757066b47fe56184a57af8d0ac1da5a..a422bf705ac7117c11d1b8295ff4f15386f503f3 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.190 2000/09/15 18:45:30 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.191 2000/09/19 18:17:55 petere Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -4993,7 +4993,7 @@ c_expr:  attr
 		| CURRENT_USER
 				{
 					FuncCall *n = makeNode(FuncCall);
-					n->funcname = "getpgusername";
+					n->funcname = "current_user";
 					n->args = NIL;
 					n->agg_star = FALSE;
 					n->agg_distinct = FALSE;
@@ -5002,7 +5002,7 @@ c_expr:  attr
 		| SESSION_USER
 				{
 					FuncCall *n = makeNode(FuncCall);
-					n->funcname = "getpgusername";
+					n->funcname = "session_user";
 					n->args = NIL;
 					n->agg_star = FALSE;
 					n->agg_distinct = FALSE;
@@ -5011,7 +5011,7 @@ c_expr:  attr
 		| USER
 				{
 					FuncCall *n = makeNode(FuncCall);
-					n->funcname = "getpgusername";
+					n->funcname = "current_user";
 					n->args = NIL;
 					n->agg_star = FALSE;
 					n->agg_distinct = FALSE;
diff --git a/src/backend/utils/adt/name.c b/src/backend/utils/adt/name.c
index 3acf40e0d43f633250a3db9561cb380ed906143e..edc14303d42b9fd2619b76cd7d01a9a65adb2685 100644
--- a/src/backend/utils/adt/name.c
+++ b/src/backend/utils/adt/name.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/name.c,v 1.29 2000/08/03 16:34:22 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/name.c,v 1.30 2000/09/19 18:17:56 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,13 +136,6 @@ namege(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) >= 0);
 }
 
-/* SQL-function interface to GetPgUserName() */
-Datum
-getpgusername(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_DATUM(DirectFunctionCall1(namein,
-										CStringGetDatum(GetPgUserName())));
-}
 
 /* (see char.c for comparison/operation routines) */
 
@@ -218,6 +211,21 @@ namestrcmp(Name name, const char *str)
 	return strncmp(NameStr(*name), str, NAMEDATALEN);
 }
 
+
+/* SQL-functions CURRENT_USER and SESSION_USER */
+Datum
+current_user(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserName(GetUserId()))));
+}
+
+Datum
+session_user(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserName(GetSessionUserId()))));
+}
+
+
 /*****************************************************************************
  *	 PRIVATE ROUTINES														 *
  *****************************************************************************/
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 20babcc616c8a536e46dfbf73ab29957491825ec..0974a05715981a9f37f44728fda18bc93eafc1df 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.54 2000/09/06 14:15:22 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.55 2000/09/19 18:17:57 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -272,50 +272,65 @@ convertstr(unsigned char *buff, int len, int dest)
 
 #endif
 
-/* ----------------
- *		GetPgUserName
- * ----------------
- */
-char *
-GetPgUserName(void)
-{
-	HeapTuple tuple;
-	Oid userid;
-
-	userid = GetUserId();
-
-	tuple = SearchSysCacheTuple(SHADOWSYSID, ObjectIdGetDatum(userid), 0, 0, 0);
-	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "invalid user id %u", (unsigned) userid);
-
-	return pstrdup( NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename) );
-}
 
 
 /* ----------------------------------------------------------------
- *		GetUserId and SetUserId
+ * 	User ID things
+ *
+ * The session user is determined at connection start and never
+ * changes.  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	UserId = InvalidOid;
+static Oid	CurrentUserId = InvalidOid;
+static Oid	SessionUserId = InvalidOid;
 
 
+/*
+ * This function is relevant for all privilege checks.
+ */
 Oid
-GetUserId()
+GetUserId(void)
 {
-	AssertState(OidIsValid(UserId));
-	return UserId;
+	AssertState(OidIsValid(CurrentUserId));
+	return CurrentUserId;
 }
 
 
 void
 SetUserId(Oid newid)
 {
-	UserId = newid;
+	AssertArg(OidIsValid(newid));
+	CurrentUserId = newid;
+}
+
+
+/*
+ * This value is only relevant for informational purposes.
+ */
+Oid
+GetSessionUserId(void)
+{
+	AssertState(OidIsValid(SessionUserId));
+	return SessionUserId;
+}
+
+
+void
+SetSessionUserId(Oid newid)
+{
+	AssertArg(OidIsValid(newid));
+	SessionUserId = newid;
+	/* Current user defaults to session user. */
+	if (!OidIsValid(CurrentUserId))
+		CurrentUserId = newid;
 }
 
 
 void
-SetUserIdFromUserName(const char *username)
+SetSessionUserIdFromUserName(const char *username)
 {
 	HeapTuple	userTup;
 
@@ -330,13 +345,30 @@ SetUserIdFromUserName(const char *username)
 								  0, 0, 0);
 	if (!HeapTupleIsValid(userTup))
 		elog(FATAL, "user \"%s\" does not exist", username);
-	SetUserId( ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid );
+	SetSessionUserId( ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid );
 }
 
 
+/*
+ * Get user name from user id
+ */
+char *
+GetUserName(Oid userid)
+{
+	HeapTuple tuple;
+
+	tuple = SearchSysCacheTuple(SHADOWSYSID, ObjectIdGetDatum(userid), 0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "invalid user id %u", (unsigned) userid);
+
+	return pstrdup( NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename) );
+}
+
+
+
 /*-------------------------------------------------------------------------
  *
- * posmaster pid file stuffs. $DATADIR/postmaster.pid is created when:
+ * postmaster pid file stuffs. $DATADIR/postmaster.pid is created when:
  *
  *	(1) postmaster starts. In this case pid > 0.
  *	(2) postgres starts in standalone mode. In this case
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index a9e083557e00099f6718e76a2f7c142d8151f117..c0502d99ab3655fa5e2ae77a674918cc6dc94e76 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.65 2000/09/06 14:15:22 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.66 2000/09/19 18:17:57 petere Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -374,9 +374,9 @@ InitPostgres(const char *dbname, const char *username)
 	 * user id.
 	 */
 	if (bootstrap)
-		SetUserId(geteuid());
+		SetSessionUserId(geteuid());
 	else
-		SetUserIdFromUserName(username);
+		SetSessionUserIdFromUserName(username);
 
 	setuid(geteuid());
 
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index e23b8b9cb5379d31d1fd41f2c51b60c00c8eeae1..ab9ee67703c4a8fc5d18f93dedff38f318b7cade 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.46 2000/09/15 18:45:27 tgl Exp $
+ * $Id: catversion.h,v 1.47 2000/09/19 18:18:01 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200009151
+#define CATALOG_VERSION_NO	200009191
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ac1dbabef1e0097d74eaa640a2b18ee21fedf64f..4f2043fb02a4bc43f3571e298e742c808cafc0fe 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.166 2000/09/15 18:45:27 tgl Exp $
+ * $Id: pg_proc.h,v 1.167 2000/09/19 18:18:01 petere Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -928,8 +928,8 @@ DATA(insert OID = 681 (  oidvectorgt	   PGUID 12 f t t t 2 f 16 "30 30" 100 0 0
 DESCR("greater-than");
 
 /* OIDS 700 - 799 */
-DATA(insert OID = 710 (  getpgusername	   PGUID 12 f t f t 0 f 19 "0" 100 0 0 100  getpgusername - ));
-DESCR("Return username");
+DATA(insert OID = 710 (  getpgusername	   PGUID 12 f t f t 0 f 19 "0" 100 0 0 100  current_user - ));
+DESCR("deprecated -- use current_user");
 DATA(insert OID = 711 (  userfntest		   PGUID 12 f t t t 1 f 23 "23" 100 0 0 100  userfntest - ));
 DESCR("");
 DATA(insert OID = 713 (  oidrand		   PGUID 12 f t f t 2 f 16 "26 23" 100 0 0 100  oidrand - ));
@@ -974,6 +974,12 @@ DESCR("greater-than-or-equal");
 
 DATA(insert OID = 744 (  array_eq		   PGUID 12 f t t t 2 f 16 "0 0" 100 0 0 100 array_eq -));
 DESCR("array equal");
+
+DATA(insert OID = 745 (  current_user	   PGUID 12 f t f t 0 f 19 "0" 100 0 0 100  current_user - ));
+DESCR("current user name");
+DATA(insert OID = 746 (  session_user	   PGUID 12 f t f t 0 f 19 "0" 100 0 0 100  session_user - ));
+DESCR("session user name");
+
 DATA(insert OID = 747 (  array_dims		   PGUID 12 f t t t 1 f 25 "0" 100 0 0 100 array_dims -));
 DESCR("array dimensions");
 DATA(insert OID = 750 (  array_in		   PGUID 12 f t t t 3 f 23 "0 26 23" 100 0 0 100	array_in - ));
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 540b7266682750ed1a7b1cde92bdcc5d62c9747f..2132b3bb28ecd6fe310acf1fe48db67221960c43 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: miscadmin.h,v 1.66 2000/09/06 19:54:52 petere Exp $
+ * $Id: miscadmin.h,v 1.67 2000/09/19 18:17:58 petere Exp $
  *
  * NOTES
  *	  some of the information in this file will be moved to
@@ -128,10 +128,14 @@ extern char *ExpandDatabasePath(const char *path);
 extern void SetDatabaseName(const char *name);
 extern void SetDatabasePath(const char *path);
 
-extern char *GetPgUserName(void);
-extern Oid	GetUserId(void);
+extern char *GetUserName(Oid userid);
+
+extern Oid GetUserId(void);
 extern void SetUserId(Oid userid);
-extern void SetUserIdFromUserName(const char *username);
+extern Oid GetSessionUserId(void);
+extern void SetSessionUserId(Oid userid);
+extern void SetSessionUserIdFromUserName(const char *username);
+
 extern int	FindExec(char *full_path, const char *argv0, const char *binary_name);
 extern int	CheckPathAccess(char *path, char *name, int open_mode);
 
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 054f3d5a7aacef1fef342b2c35354a6f68756367..c0528bcecd72ee9759e444436d0b66c33a0ce7f2 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.137 2000/09/15 18:45:29 tgl Exp $
+ * $Id: builtins.h,v 1.138 2000/09/19 18:18:02 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,10 +136,11 @@ extern Datum namelt(PG_FUNCTION_ARGS);
 extern Datum namele(PG_FUNCTION_ARGS);
 extern Datum namegt(PG_FUNCTION_ARGS);
 extern Datum namege(PG_FUNCTION_ARGS);
-extern Datum getpgusername(PG_FUNCTION_ARGS);
 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_user(PG_FUNCTION_ARGS);
+extern Datum session_user(PG_FUNCTION_ARGS);
 
 /* numutils.c */
 extern int32 pg_atoi(char *s, int size, int c);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index eb19122cbcea0ea1cabc2c24a2a616e137fa7835..11e1539778c74d59fc1ab5d2e8b3588d0ea2bc02 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1231,9 +1231,9 @@ SELECT tablename, rulename, definition FROM pg_rules
 	ORDER BY tablename, rulename;
    tablename   |    rulename     |                                                                                                                       definition                                                                                                                       
 ---------------+-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- rtest_emp     | rtest_emp_del   | CREATE RULE rtest_emp_del AS ON DELETE TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (old.ename, getpgusername(), 'fired     '::bpchar, '$0.00'::money, old.salary);
- rtest_emp     | rtest_emp_ins   | CREATE RULE rtest_emp_ins AS ON INSERT TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (new.ename, getpgusername(), 'hired     '::bpchar, new.salary, '$0.00'::money);
- rtest_emp     | rtest_emp_upd   | CREATE RULE rtest_emp_upd AS ON UPDATE TO rtest_emp WHERE (new.salary <> old.salary) DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (new.ename, getpgusername(), 'honored   '::bpchar, new.salary, old.salary);
+ rtest_emp     | rtest_emp_del   | CREATE RULE rtest_emp_del AS ON DELETE TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (old.ename, "current_user"(), 'fired     '::bpchar, '$0.00'::money, old.salary);
+ rtest_emp     | rtest_emp_ins   | CREATE RULE rtest_emp_ins AS ON INSERT TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (new.ename, "current_user"(), 'hired     '::bpchar, new.salary, '$0.00'::money);
+ rtest_emp     | rtest_emp_upd   | CREATE RULE rtest_emp_upd AS ON UPDATE TO rtest_emp WHERE (new.salary <> old.salary) DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (new.ename, "current_user"(), 'honored   '::bpchar, new.salary, old.salary);
  rtest_nothn1  | rtest_nothn_r1  | CREATE RULE rtest_nothn_r1 AS ON INSERT TO rtest_nothn1 WHERE ((new.a >= 10) AND (new.a < 20)) DO INSTEAD SELECT 1;
  rtest_nothn1  | rtest_nothn_r2  | CREATE RULE rtest_nothn_r2 AS ON INSERT TO rtest_nothn1 WHERE ((new.a >= 30) AND (new.a < 40)) DO INSTEAD NOTHING;
  rtest_nothn2  | rtest_nothn_r3  | CREATE RULE rtest_nothn_r3 AS ON INSERT TO rtest_nothn2 WHERE (new.a >= 100) DO INSTEAD INSERT INTO rtest_nothn3 (a, b) VALUES (new.a, new.b);