diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 2b1318b05e4f87b6832063ff1ae491e3ae200696..7358dfb5122e3b44d6c01635bb10df404cb1d792 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,6 +1,6 @@
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.105 2005/06/18 19:33:41 tgl Exp $
+ $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.106 2005/06/28 05:08:50 tgl Exp $
  -->
 
 <chapter id="catalogs">
@@ -78,6 +78,16 @@
       <entry>table columns (<quote>attributes</quote>)</entry>
      </row>
 
+     <row>
+      <entry><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link></entry>
+      <entry>authorization identifiers (roles)</entry>
+     </row>
+
+     <row>
+      <entry><link linkend="catalog-pg-auth-members"><structname>pg_auth_members</structname></link></entry>
+      <entry>authorization identifier membership relationships</entry>
+     </row>
+
      <row>
       <entry><link linkend="catalog-pg-cast"><structname>pg_cast</structname></link></entry>
       <entry>casts (data type conversions)</entry>
@@ -113,11 +123,6 @@
       <entry>descriptions or comments on database objects</entry>
      </row>
 
-     <row>
-      <entry><link linkend="catalog-pg-group"><structname>pg_group</structname></link></entry>
-      <entry>groups of database users</entry>
-     </row>
-
      <row>
       <entry><link linkend="catalog-pg-index"><structname>pg_index</structname></link></entry>
       <entry>additional index information</entry>
@@ -168,11 +173,6 @@
       <entry>query rewrite rules</entry>
      </row>
 
-     <row>
-      <entry><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link></entry>
-      <entry>database users</entry>
-     </row>
-
      <row>
       <entry><link linkend="catalog-pg-statistic"><structname>pg_statistic</structname></link></entry>
       <entry>planner statistics</entry>
@@ -902,6 +902,201 @@
  </sect1>
 
 
+ <sect1 id="catalog-pg-authid">
+  <title><structname>pg_authid</structname></title>
+
+  <indexterm zone="catalog-pg-authid">
+   <primary>pg_authid</primary>
+  </indexterm>
+
+  <para>
+   The catalog <structname>pg_authid</structname> contains information about
+   database authorization identifiers (roles).  A role subsumes the concepts
+   of <quote>users</> and <quote>groups</>.  A user is essentially just a
+   role with the <structfield>rolcanlogin</> flag set.  Any role (with or
+   without <structfield>rolcanlogin</>) may have other roles as members; see
+   <link linkend="catalog-pg-auth-members"><structname>pg_auth_members</structname></link>.
+  </para>
+
+  <para>
+   Since this catalog contains passwords, it must not be publicly readable.
+   <link linkend="view-pg-roles"><structname>pg_roles</structname></link>
+   is a publicly readable view on
+   <structname>pg_authid</structname> that blanks out the password field.
+  </para>
+
+  <para>
+   <xref linkend="user-manag"> contains detailed information about user and
+   privilege management.
+  </para>
+
+  <para>
+   Because user identities are cluster-wide,
+   <structname>pg_authid</structname>
+   is shared across all databases of a cluster: there is only one
+   copy of <structname>pg_authid</structname> per cluster, not
+   one per database.
+  </para>
+
+  <table>
+   <title><structname>pg_authid</> Columns</title>
+
+   <tgroup cols=4>
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>rolname</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry></entry>
+      <entry>Role name</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolsuper</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>Role has superuser privileges</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolcreaterole</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>Role may create more roles</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolcreatedb</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>Role may create databases</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolcatupdate</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>
+       Role may update system catalogs directly.  (Even a superuser may not do
+       this unless this column is true.)
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolcanlogin</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>
+       Role may log in, that is, this role can be given as the initial
+       session authorization identifier.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolpassword</structfield></entry>
+      <entry><type>text</type></entry>
+      <entry></entry>
+      <entry>Password (possibly encrypted); NULL if none</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolvaliduntil</structfield></entry>
+      <entry><type>timestamptz</type></entry>
+      <entry></entry>
+      <entry>Password expiry time (only used for password authentication);
+       NULL if no expiration</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolconfig</structfield></entry>
+      <entry><type>text[]</type></entry>
+      <entry></entry>
+      <entry>Session defaults for run-time configuration variables</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
+
+ <sect1 id="catalog-pg-auth-members">
+  <title><structname>pg_auth_members</structname></title>
+
+  <indexterm zone="catalog-pg-auth-members">
+   <primary>pg_auth_members</primary>
+  </indexterm>
+
+  <para>
+   The catalog <structname>pg_auth_members</structname> shows the membership
+   relations between roles.  Any non-circular set of relationships is allowed.
+  </para>
+
+  <para>
+   Because user identities are cluster-wide,
+   <structname>pg_auth_members</structname>
+   is shared across all databases of a cluster: there is only one
+   copy of <structname>pg_auth_members</structname> per cluster, not
+   one per database.
+  </para>
+
+  <table>
+   <title><structname>pg_auth_members</> Columns</title>
+
+   <tgroup cols=4>
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>roleid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>ID of a role that has a member</entry>
+     </row>
+
+     <row>
+      <entry><structfield>member</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>ID of a role that is a member of <structfield>roleid</></entry>
+     </row>
+
+     <row>
+      <entry><structfield>grantor</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>ID of the role that granted this membership</entry>
+     </row>
+
+     <row>
+      <entry><structfield>admin_option</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>True if <structfield>member</> may grant membership in
+       <structfield>roleid</> to others</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
+
  <sect1 id="catalog-pg-cast">
   <title><structname>pg_cast</structname></title>
 
@@ -1065,8 +1260,8 @@
 
      <row>
       <entry><structfield>relowner</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
       <entry>Owner of the relation</entry>
      </row>
 
@@ -1492,8 +1687,8 @@
 
      <row>
       <entry><structfield>conowner</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
       <entry>Owner of the conversion</entry>
      </row>
 
@@ -1576,8 +1771,8 @@
 
      <row>
       <entry><structfield>datdba</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
       <entry>Owner of the database, usually the user who created it</entry>
      </row>
 
@@ -1917,69 +2112,6 @@
  </sect1>
 
 
- <sect1 id="catalog-pg-group">
-  <title><structname>pg_group</structname></title>
-
-  <indexterm zone="catalog-pg-group">
-   <primary>pg_group</primary>
-  </indexterm>
-
-  <para>
-   The catalog <structname>pg_group</structname> defines groups and stores what users belong to what
-   groups.  Groups are created with the <command>CREATE
-   GROUP</command> command.  Consult <xref linkend="user-manag"> for information
-   about user privilege management.
-  </para>
-
-  <para>
-   Because user and group identities are cluster-wide,
-   <structname>pg_group</structname>
-   is shared across all databases of a cluster: there is only one
-   copy of <structname>pg_group</structname> per cluster, not
-   one per database.
-  </para>
-
-  <table>
-   <title><structname>pg_group</> Columns</title>
-
-   <tgroup cols=4>
-    <thead>
-     <row>
-      <entry>Name</entry>
-      <entry>Type</entry>
-      <entry>References</entry>
-      <entry>Description</entry>
-     </row>
-    </thead>
-
-    <tbody>
-     <row>
-      <entry><structfield>groname</structfield></entry>
-      <entry><type>name</type></entry>
-      <entry></entry>
-      <entry>Name of the group</entry>
-     </row>
-
-     <row>
-      <entry><structfield>grosysid</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry></entry>
-      <entry>An arbitrary number to identify this group</entry>
-     </row>
-
-     <row>
-      <entry><structfield>grolist</structfield></entry>
-      <entry><type>int4[]</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
-      <entry>An array containing the IDs of the users in this group</entry>
-     </row>
-    </tbody>
-   </tgroup>
-  </table>
-
- </sect1>
-
-
  <sect1 id="catalog-pg-index">
   <title><structname>pg_index</structname></title>
 
@@ -2437,8 +2569,8 @@
 
      <row>
       <entry><structfield>nspowner</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
       <entry>Owner of the namespace</entry>
      </row>
 
@@ -2517,9 +2649,9 @@
 
      <row>
       <entry><structfield>opcowner</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
-      <entry>Operator class owner</entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>Owner of the operator class</entry>
      </row>
 
      <row>
@@ -2606,8 +2738,8 @@
 
      <row>
       <entry><structfield>oprowner</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
       <entry>Owner of the operator</entry>
      </row>
 
@@ -2786,8 +2918,8 @@
 
      <row>
       <entry><structfield>proowner</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
       <entry>Owner of the function</entry>
      </row>
 
@@ -3066,149 +3198,41 @@
  </sect1>
 
 
- <sect1 id="catalog-pg-shadow">
-  <title><structname>pg_shadow</structname></title>
+ <sect1 id="catalog-pg-statistic">
+  <title><structname>pg_statistic</structname></title>
 
-  <indexterm zone="catalog-pg-shadow">
-   <primary>pg_shadow</primary>
+  <indexterm zone="catalog-pg-statistic">
+   <primary>pg_statistic</primary>
   </indexterm>
 
   <para>
-   The catalog <structname>pg_shadow</structname> contains information about
-   database users.  The name stems from the fact that this table
-   should not be readable by the public since it contains passwords.
-   <link linkend="view-pg-user"><structname>pg_user</structname></link>
-   is a publicly readable view on
-   <structname>pg_shadow</structname> that blanks out the password field.
+   The catalog <structname>pg_statistic</structname> stores statistical data
+   about the contents of the database.  Entries are created by
+   <command>ANALYZE</command> and subsequently used by the query planner.
+   There is one entry for each table column that has been analyzed.
+   Note that all the statistical data is inherently approximate,
+   even assuming that it is up-to-date.
   </para>
 
   <para>
-   <xref linkend="user-manag"> contains detailed information about user and
-   privilege management.
+   <structname>pg_statistic</structname> also stores statistical data about
+   the values of index expressions.  These are described as if they were
+   actual data columns; in particular, <structfield>starelid</structfield>
+   references the index.  No entry is made for an ordinary non-expression
+   index column, however, since it would be redundant with the entry
+   for the underlying table column.
   </para>
 
   <para>
-   Because user identities are cluster-wide,
-   <structname>pg_shadow</structname>
-   is shared across all databases of a cluster: there is only one
-   copy of <structname>pg_shadow</structname> per cluster, not
-   one per database.
-  </para>
-
-  <table>
-   <title><structname>pg_shadow</> Columns</title>
-
-   <tgroup cols=4>
-    <thead>
-     <row>
-      <entry>Name</entry>
-      <entry>Type</entry>
-      <entry>References</entry>
-      <entry>Description</entry>
-     </row>
-    </thead>
-
-    <tbody>
-     <row>
-      <entry><structfield>usename</structfield></entry>
-      <entry><type>name</type></entry>
-      <entry></entry>
-      <entry>User name</entry>
-     </row>
-
-     <row>
-      <entry><structfield>usesysid</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry></entry>
-      <entry>User ID (arbitrary number used to reference this user)</entry>
-     </row>
-
-     <row>
-      <entry><structfield>usecreatedb</structfield></entry>
-      <entry><type>bool</type></entry>
-      <entry></entry>
-      <entry>User may create databases</entry>
-     </row>
-
-     <row>
-      <entry><structfield>usesuper</structfield></entry>
-      <entry><type>bool</type></entry>
-      <entry></entry>
-      <entry>User is a superuser</entry>
-     </row>
-
-     <row>
-      <entry><structfield>usecatupd</structfield></entry>
-      <entry><type>bool</type></entry>
-      <entry></entry>
-      <entry>
-       User may update system catalogs.  (Even a superuser may not do
-       this unless this column is true.)
-      </entry>
-     </row>
-
-     <row>
-      <entry><structfield>passwd</structfield></entry>
-      <entry><type>text</type></entry>
-      <entry></entry>
-      <entry>Password (possibly encrypted)</entry>
-     </row>
-
-     <row>
-      <entry><structfield>valuntil</structfield></entry>
-      <entry><type>abstime</type></entry>
-      <entry></entry>
-      <entry>Password expiry time (only used for password authentication)</entry>
-     </row>
-
-     <row>
-      <entry><structfield>useconfig</structfield></entry>
-      <entry><type>text[]</type></entry>
-      <entry></entry>
-      <entry>Session defaults for run-time configuration variables</entry>
-     </row>
-    </tbody>
-   </tgroup>
-  </table>
-
- </sect1>
-
-
- <sect1 id="catalog-pg-statistic">
-  <title><structname>pg_statistic</structname></title>
-
-  <indexterm zone="catalog-pg-statistic">
-   <primary>pg_statistic</primary>
-  </indexterm>
-
-  <para>
-   The catalog <structname>pg_statistic</structname> stores statistical data
-   about the contents of the database.  Entries are created by
-   <command>ANALYZE</command> and subsequently used by the query planner.
-   There is one entry for each table column that has been analyzed.
-   Note that all the statistical data is inherently approximate,
-   even assuming that it is up-to-date.
-  </para>
-
-  <para>
-   <structname>pg_statistic</structname> also stores statistical data about
-   the values of index expressions.  These are described as if they were
-   actual data columns; in particular, <structfield>starelid</structfield>
-   references the index.  No entry is made for an ordinary non-expression
-   index column, however, since it would be redundant with the entry
-   for the underlying table column.
-  </para>
-
-  <para>
-   Since different kinds of statistics may be appropriate for different
-   kinds of data, <structname>pg_statistic</structname> is designed not
-   to assume very much about what sort of statistics it stores.  Only
-   extremely general statistics (such as nullness) are given dedicated
-   columns in <structname>pg_statistic</structname>.  Everything else
-   is stored in <quote>slots</quote>, which are groups of associated columns
-   whose content is identified by a code number in one of the slot's columns.
-   For more information see
-   <filename>src/include/catalog/pg_statistic.h</filename>.
+   Since different kinds of statistics may be appropriate for different
+   kinds of data, <structname>pg_statistic</structname> is designed not
+   to assume very much about what sort of statistics it stores.  Only
+   extremely general statistics (such as nullness) are given dedicated
+   columns in <structname>pg_statistic</structname>.  Everything else
+   is stored in <quote>slots</quote>, which are groups of associated columns
+   whose content is identified by a code number in one of the slot's columns.
+   For more information see
+   <filename>src/include/catalog/pg_statistic.h</filename>.
   </para>
 
   <para>
@@ -3374,8 +3398,8 @@
 
      <row>
       <entry><structfield>spcowner</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
       <entry>Owner of the tablespace, usually the user who created it</entry>
      </row>
 
@@ -3586,8 +3610,8 @@
 
      <row>
       <entry><structfield>typowner</structfield></entry>
-      <entry><type>int4</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
       <entry>Owner of the type</entry>
      </row>
 
@@ -3922,6 +3946,11 @@
     </thead>
 
     <tbody>
+     <row>
+      <entry><link linkend="view-pg-group"><structname>pg_group</structname></link></entry>
+      <entry>groups of database users</entry>
+     </row>
+
      <row>
       <entry><link linkend="view-pg-indexes"><structname>pg_indexes</structname></link></entry>
       <entry>indexes</entry>
@@ -3937,6 +3966,11 @@
       <entry>currently prepared transactions</entry>
      </row>
 
+     <row>
+      <entry><link linkend="view-pg-roles"><structname>pg_roles</structname></link></entry>
+      <entry>database roles</entry>
+     </row>
+
      <row>
       <entry><link linkend="view-pg-rules"><structname>pg_rules</structname></link></entry>
       <entry>rules</entry>
@@ -3947,6 +3981,11 @@
       <entry>parameter settings</entry>
      </row>
 
+     <row>
+      <entry><link linkend="view-pg-shadow"><structname>pg_shadow</structname></link></entry>
+      <entry>database users</entry>
+     </row>
+
      <row>
       <entry><link linkend="view-pg-stats"><structname>pg_stats</structname></link></entry>
       <entry>planner statistics</entry>
@@ -3972,6 +4011,62 @@
   </table>
  </sect1>
 
+ <sect1 id="view-pg-group">
+  <title><structname>pg_group</structname></title>
+
+  <indexterm zone="view-pg-group">
+   <primary>pg_group</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_group</structname> exists for backwards
+   compatibility: it emulates a catalog that existed in
+   <productname>PostgreSQL</productname> before version 8.1.
+   It shows the names and members of all roles that are marked as not
+   <structfield>rolcanlogin</>, which is an approximation to the set
+   of roles that are being used as groups.
+  </para>
+
+  <table>
+   <title><structname>pg_group</> Columns</title>
+
+   <tgroup cols=4>
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>groname</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.rolname</literal></entry>
+      <entry>Name of the group</entry>
+     </row>
+
+     <row>
+      <entry><structfield>grosysid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>ID of this group</entry>
+     </row>
+
+     <row>
+      <entry><structfield>grolist</structfield></entry>
+      <entry><type>oid[]</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>An array containing the IDs of the roles in this group</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
  <sect1 id="view-pg-indexes">
   <title><structname>pg_indexes</structname></title>
 
@@ -4332,7 +4427,7 @@
      <row>
       <entry><structfield>owner</structfield></entry>
       <entry><type>name</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usename</literal></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.rolname</literal></entry>
       <entry>
        Name of the user that executed the transaction
       </entry>
@@ -4361,6 +4456,110 @@
 
  </sect1>
 
+ <sect1 id="view-pg-roles">
+  <title><structname>pg_roles</structname></title>
+
+  <indexterm zone="view-pg-roles">
+   <primary>pg_roles</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_roles</structname> provides access to
+   information about database roles.  This is simply a publicly
+   readable view of 
+   <link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>
+   that blanks out the password field.
+  </para>
+
+  <table>
+   <title><structname>pg_roles</> Columns</title>
+
+   <tgroup cols=4>
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>rolname</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry></entry>
+      <entry>Role name</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolsuper</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>Role has superuser privileges</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolcreaterole</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>Role may create more roles</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolcreatedb</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>Role may create databases</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolcatupdate</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>
+       Role may update system catalogs directly.  (Even a superuser may not do
+       this unless this column is true.)
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolcanlogin</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>
+       Role may log in, that is, this role can be given as the initial
+       session authorization identifier.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolpassword</structfield></entry>
+      <entry><type>text</type></entry>
+      <entry></entry>
+      <entry>Not the password (always reads as <literal>********</>)</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolvaliduntil</structfield></entry>
+      <entry><type>timestamptz</type></entry>
+      <entry></entry>
+      <entry>Password expiry time (only used for password authentication);
+       NULL if no expiration</entry>
+     </row>
+
+     <row>
+      <entry><structfield>rolconfig</structfield></entry>
+      <entry><type>text[]</type></entry>
+      <entry></entry>
+      <entry>Session defaults for run-time configuration variables</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
  <sect1 id="view-pg-rules">
   <title><structname>pg_rules</structname></title>
 
@@ -4534,6 +4733,107 @@
 
  </sect1>
 
+ <sect1 id="view-pg-shadow">
+  <title><structname>pg_shadow</structname></title>
+
+  <indexterm zone="view-pg-shadow">
+   <primary>pg_shadow</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_shadow</structname> exists for backwards
+   compatibility: it emulates a catalog that existed in
+   <productname>PostgreSQL</productname> before version 8.1.
+   It shows properties of all roles that are marked as
+   <structfield>rolcanlogin</>.
+  </para>
+
+  <para>
+   The name stems from the fact that this table
+   should not be readable by the public since it contains passwords.
+   <link linkend="view-pg-user"><structname>pg_user</structname></link>
+   is a publicly readable view on
+   <structname>pg_shadow</structname> that blanks out the password field.
+  </para>
+
+  <table>
+   <title><structname>pg_shadow</> Columns</title>
+
+   <tgroup cols=4>
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>usename</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.rolname</literal></entry>
+      <entry>User name</entry>
+     </row>
+
+     <row>
+      <entry><structfield>usesysid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>ID of this user</entry>
+     </row>
+
+     <row>
+      <entry><structfield>usecreatedb</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>User may create databases</entry>
+     </row>
+
+     <row>
+      <entry><structfield>usesuper</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>User is a superuser</entry>
+     </row>
+
+     <row>
+      <entry><structfield>usecatupd</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>
+       User may update system catalogs.  (Even a superuser may not do
+       this unless this column is true.)
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>passwd</structfield></entry>
+      <entry><type>text</type></entry>
+      <entry></entry>
+      <entry>Password (possibly encrypted)</entry>
+     </row>
+
+     <row>
+      <entry><structfield>valuntil</structfield></entry>
+      <entry><type>abstime</type></entry>
+      <entry></entry>
+      <entry>Password expiry time (only used for password authentication)</entry>
+     </row>
+
+     <row>
+      <entry><structfield>useconfig</structfield></entry>
+      <entry><type>text[]</type></entry>
+      <entry></entry>
+      <entry>Session defaults for run-time configuration variables</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
  <sect1 id="view-pg-stats">
   <title><structname>pg_stats</structname></title>
 
@@ -4720,7 +5020,7 @@
      <row>
       <entry><structfield>tableowner</structfield></entry>
       <entry><type>name</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usename</literal></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.rolname</literal></entry>
       <entry>name of table's owner</entry>
      </row>
      <row>
@@ -4764,7 +5064,7 @@
    The view <structname>pg_user</structname> provides access to
    information about database users.  This is simply a publicly
    readable view of 
-   <link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>
+   <link linkend="view-pg-shadow"><structname>pg_shadow</structname></link>
    that blanks out the password field.
   </para>
 
@@ -4885,7 +5185,7 @@
      <row>
       <entry><structfield>viewowner</structfield></entry>
       <entry><type>name</type></entry>
-      <entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usename</literal></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.rolname</literal></entry>
       <entry>name of view's owner</entry>
      </row>
      <row>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index d7430f1ccf8053623d8d15eecfabd4e42b31e051..734686bf4a4317e50e5beb14c40874cbd3679f0c 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.260 2005/06/26 22:05:35 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.261 2005/06/28 05:08:50 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -8443,8 +8443,8 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, ..
    <para>
     <function>has_table_privilege</function> checks whether a user
     can access a table in a particular way.  The user can be
-    specified by name or by ID
-    (<literal>pg_user.usesysid</literal>), or if the argument is
+    specified by name or by OID
+    (<literal>pg_authid.oid</literal>), or if the argument is
     omitted
     <function>current_user</function> is assumed.  The table can be specified
     by name or by OID.  (Thus, there are actually six variants of
@@ -8756,9 +8756,9 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
        in it refer to the relation indicated by the second parameter</entry>
       </row>
       <row>
-       <entry><literal><function>pg_get_userbyid</function>(<parameter>userid</parameter>)</literal></entry>
+       <entry><literal><function>pg_get_userbyid</function>(<parameter>roleid</parameter>)</literal></entry>
        <entry><type>name</type></entry>
-       <entry>get user name with given ID</entry>
+       <entry>get role name with given ID</entry>
       </row>
       <row>
        <entry><literal><function>pg_get_serial_sequence</function>(<parameter>table_name</parameter>, <parameter>column_name</parameter>)</literal></entry>
@@ -8805,7 +8805,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
 
   <para>
    <function>pg_get_userbyid</function>
-   extracts a user's name given a user ID number.
+   extracts a role's name given its OID.
    <function>pg_get_serial_sequence</function>
    fetches the name of the sequence associated with a serial or
    bigserial column.  The name is suitably formatted
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 7c8102d87c92d4db9ff825074233442f5d0dd6db..ccd8b802157ad16bebd4a067fab19cf72a755fe9 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *		$PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.6 2005/06/19 22:34:56 tgl Exp $
+ *		$PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.7 2005/06/28 05:08:51 tgl Exp $
  *
  * NOTES
  *		Each global transaction is associated with a global transaction
@@ -107,7 +107,7 @@ typedef struct GlobalTransactionData
 	PGPROC		proc;			/* dummy proc */
 	TimestampTz	prepared_at;	/* time of preparation */
 	XLogRecPtr	prepare_lsn;	/* XLOG offset of prepare record */
-	AclId		owner;			/* ID of user that executed the xact */
+	Oid			owner;			/* ID of user that executed the xact */
 	TransactionId locking_xid;	/* top-level XID of backend working on xact */
 	bool		valid;			/* TRUE if fully prepared */
 	char gid[GIDSIZE];			/* The GID assigned to the prepared xact */
@@ -206,7 +206,7 @@ TwoPhaseShmemInit(void)
  */
 GlobalTransaction
 MarkAsPreparing(TransactionId xid, const char *gid,
-				TimestampTz prepared_at, AclId owner, Oid databaseid)
+				TimestampTz prepared_at, Oid owner, Oid databaseid)
 {
 	GlobalTransaction	gxact;
 	int i;
@@ -350,7 +350,7 @@ MarkAsPrepared(GlobalTransaction gxact)
  *		Locate the prepared transaction and mark it busy for COMMIT or PREPARE.
  */
 static GlobalTransaction
-LockGXact(const char *gid, AclId user)
+LockGXact(const char *gid, Oid user)
 {
 	int i;
 
@@ -559,7 +559,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepared",
 						   TIMESTAMPTZOID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "ownerid",
-						   INT4OID, -1, 0);
+						   OIDOID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "dbid",
 						   OIDOID, -1, 0);
 
@@ -601,7 +601,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[0] = TransactionIdGetDatum(gxact->proc.xid);
 		values[1] = DirectFunctionCall1(textin, CStringGetDatum(gxact->gid));
 		values[2] = TimestampTzGetDatum(gxact->prepared_at);
-		values[3] = Int32GetDatum(gxact->owner);
+		values[3] = ObjectIdGetDatum(gxact->owner);
 		values[4] = ObjectIdGetDatum(gxact->proc.databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
@@ -690,7 +690,7 @@ typedef struct TwoPhaseFileHeader
 	TransactionId	xid;				/* original transaction XID */
 	Oid				database;			/* OID of database it was in */
 	TimestampTz		prepared_at;		/* time of preparation */
-	AclId			owner;				/* user running the transaction */
+	Oid				owner;				/* user running the transaction */
 	int32			nsubxacts;			/* number of following subxact XIDs */
 	int32			ncommitrels;		/* number of delete-on-commit rels */
 	int32			nabortrels;			/* number of delete-on-abort rels */
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 98e56c400202c45514c291f659a47470df1360b0..a5d53d3e1457381b140677ead6d89cadc6b646a0 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.207 2005/06/19 20:00:38 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.208 2005/06/28 05:08:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -121,7 +121,7 @@ typedef struct TransactionStateData
 												 * context */
 	ResourceOwner curTransactionOwner;	/* my query resources */
 	List	   *childXids;		/* subcommitted child XIDs */
-	AclId		currentUser;	/* subxact start current_user */
+	Oid			currentUser;	/* subxact start current_user */
 	bool		prevXactReadOnly;		/* entry-time xact r/o state */
 	struct TransactionStateData *parent;		/* back link to parent */
 } TransactionStateData;
@@ -1488,8 +1488,10 @@ CommitTransaction(void)
 	/* NOTIFY commit must come before lower-level cleanup */
 	AtCommit_Notify();
 
-	/* Update flat files if we changed pg_database, pg_shadow or pg_group */
-	/* This should be the last step before commit */
+	/*
+	 * Update flat files if we changed pg_database, pg_authid or
+	 * pg_auth_members.  This should be the last step before commit.
+	 */
 	AtEOXact_UpdateFlatFiles(true);
 
 	/* Prevent cancel/die interrupt while cleaning up */
@@ -3847,7 +3849,7 @@ PushTransaction(void)
 {
 	TransactionState p = CurrentTransactionState;
 	TransactionState s;
-	AclId	currentUser;
+	Oid	currentUser;
 
 	/*
 	 * At present, GetUserId cannot fail, but let's not assume that.  Get
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index a77b41b441ff6b6ba4acb7768e9fb1589a8f8ee1..09addc4af1cb3968404c52af58ad290b6b5cd93e 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -2,7 +2,7 @@
 #
 # Makefile for backend/catalog
 #
-# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.53 2004/07/21 20:34:45 momjian Exp $
+# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.54 2005/06/28 05:08:52 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -31,8 +31,9 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
 	pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
 	pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
-	pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
-	pg_tablespace.h pg_depend.h indexing.h \
+	pg_namespace.h pg_conversion.h pg_database.h \
+	pg_authid.h pg_auth_members.h pg_tablespace.h pg_depend.h \
+	indexing.h \
     )
 
 pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 5eba84f995fddcd497abc477c622e756334afc9e..6ff89eb0425b52c87eed91aa6cc7fbfb1fe781ca 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.112 2005/05/29 23:38:05 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.113 2005/06/28 05:08:52 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -21,15 +21,15 @@
 #include "catalog/catalog.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_auth_members.h"
+#include "catalog/pg_authid.h"
 #include "catalog/pg_conversion.h"
 #include "catalog/pg_database.h"
-#include "catalog/pg_group.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
-#include "catalog/pg_shadow.h"
 #include "catalog/pg_tablespace.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
@@ -76,10 +76,10 @@ dumpacl(Acl *acl)
  * all granted privileges appear to flow from the object owner, and there
  * are never multiple "original sources" of a privilege.
  */
-static AclId
-select_grantor(AclId ownerId)
+static Oid
+select_grantor(Oid ownerId)
 {
-	AclId		grantorId;
+	Oid		grantorId;
 
 	grantorId = GetUserId();
 
@@ -105,7 +105,7 @@ static Acl *
 merge_acl_with_grant(Acl *old_acl, bool is_grant,
 					 bool grant_option, DropBehavior behavior,
 					 List *grantees, AclMode privileges,
-					 AclId grantor_uid, AclId owner_uid)
+					 Oid grantorId, Oid ownerId)
 {
 	unsigned	modechg;
 	ListCell   *j;
@@ -122,41 +122,25 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
 	{
 		PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
 		AclItem aclitem;
-		uint32		idtype;
 		Acl		   *newer_acl;
 
-		if (grantee->username)
-		{
-			aclitem.	ai_grantee = get_usesysid(grantee->username);
-
-			idtype = ACL_IDTYPE_UID;
-		}
-		else if (grantee->groupname)
-		{
-			aclitem.	ai_grantee = get_grosysid(grantee->groupname);
-
-			idtype = ACL_IDTYPE_GID;
-		}
+		if (grantee->rolname)
+			aclitem.ai_grantee = get_roleid_checked(grantee->rolname);
 		else
-		{
-			aclitem.	ai_grantee = ACL_ID_WORLD;
-
-			idtype = ACL_IDTYPE_WORLD;
-		}
+			aclitem.ai_grantee = ACL_ID_PUBLIC;
 
 		/*
-		 * Grant options can only be granted to individual users, not
-		 * groups or public.  The reason is that if a user would re-grant
-		 * a privilege that he held through a group having a grant option,
-		 * and later the user is removed from the group, the situation is
-		 * impossible to clean up.
+		 * Grant options can only be granted to individual roles, not PUBLIC.
+		 * The reason is that if a user would re-grant a privilege that he
+		 * held through PUBLIC, and later the user is removed, the situation
+		 * is impossible to clean up.
 		 */
-		if (is_grant && grant_option && idtype != ACL_IDTYPE_UID)
+		if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_GRANT_OPERATION),
-					 errmsg("grant options can only be granted to individual users")));
+					 errmsg("grant options can only be granted to roles")));
 
-		aclitem.	ai_grantor = grantor_uid;
+		aclitem.ai_grantor = grantorId;
 
 		/*
 		 * The asymmetry in the conditions here comes from the spec.  In
@@ -166,12 +150,11 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
 		 * and its grant option, while REVOKE GRANT OPTION revokes only
 		 * the option.
 		 */
-		ACLITEM_SET_PRIVS_IDTYPE(aclitem,
+		ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
 				(is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
-				(!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS,
-								 idtype);
+				(!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
 
-		newer_acl = aclupdate(new_acl, &aclitem, modechg, owner_uid, behavior);
+		newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
 
 		/* avoid memory leak when there are many grantees */
 		pfree(new_acl);
@@ -261,8 +244,8 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
 		AclMode		this_privileges;
 		Acl		   *old_acl;
 		Acl		   *new_acl;
-		AclId		grantorId;
-		AclId		ownerId;
+		Oid		grantorId;
+		Oid		ownerId;
 		HeapTuple	newtuple;
 		Datum		values[Natts_pg_class];
 		char		nulls[Natts_pg_class];
@@ -430,8 +413,8 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
 		AclMode		this_privileges;
 		Acl		   *old_acl;
 		Acl		   *new_acl;
-		AclId		grantorId;
-		AclId		ownerId;
+		Oid		grantorId;
+		Oid		ownerId;
 		HeapTuple	newtuple;
 		Datum		values[Natts_pg_database];
 		char		nulls[Natts_pg_database];
@@ -587,8 +570,8 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
 		AclMode		this_privileges;
 		Acl		   *old_acl;
 		Acl		   *new_acl;
-		AclId		grantorId;
-		AclId		ownerId;
+		Oid		grantorId;
+		Oid		ownerId;
 		HeapTuple	newtuple;
 		Datum		values[Natts_pg_proc];
 		char		nulls[Natts_pg_proc];
@@ -740,8 +723,8 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
 		AclMode		this_privileges;
 		Acl		   *old_acl;
 		Acl		   *new_acl;
-		AclId		grantorId;
-		AclId		ownerId;
+		Oid		grantorId;
+		Oid		ownerId;
 		HeapTuple	newtuple;
 		Datum		values[Natts_pg_language];
 		char		nulls[Natts_pg_language];
@@ -767,7 +750,7 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
 		 * Note: for now, languages are treated as owned by the bootstrap
 		 * user.  We should add an owner column to pg_language instead.
 		 */
-		ownerId = BOOTSTRAP_USESYSID;
+		ownerId = BOOTSTRAP_SUPERUSERID;
 		grantorId = select_grantor(ownerId);
 
 		/*
@@ -903,8 +886,8 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
 		AclMode		this_privileges;
 		Acl		   *old_acl;
 		Acl		   *new_acl;
-		AclId		grantorId;
-		AclId		ownerId;
+		Oid		grantorId;
+		Oid		ownerId;
 		HeapTuple	newtuple;
 		Datum		values[Natts_pg_namespace];
 		char		nulls[Natts_pg_namespace];
@@ -1059,8 +1042,8 @@ ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
 		AclMode		this_privileges;
 		Acl		   *old_acl;
 		Acl		   *new_acl;
-		AclId		grantorId;
-		AclId		ownerId;
+		Oid		grantorId;
+		Oid		ownerId;
 		HeapTuple	newtuple;
 		Datum		values[Natts_pg_tablespace];
 		char		nulls[Natts_pg_tablespace];
@@ -1207,27 +1190,6 @@ privilege_to_string(AclMode privilege)
 	return NULL;				/* appease compiler */
 }
 
-/*
- * Convert group ID to name, or return NULL if group can't be found
- */
-char *
-get_groname(AclId grosysid)
-{
-	HeapTuple	tuple;
-	char	   *name = NULL;
-
-	tuple = SearchSysCache(GROSYSID,
-						   ObjectIdGetDatum(grosysid),
-						   0, 0, 0);
-	if (HeapTupleIsValid(tuple))
-	{
-		name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname));
-		ReleaseSysCache(tuple);
-	}
-	return name;
-}
-
-
 /*
  * Standardized reporting of aclcheck permissions failures.
  *
@@ -1310,26 +1272,26 @@ aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
 }
 
 
-/* Check if given userid has usecatupd privilege according to pg_shadow */
+/* Check if given user has rolcatupdate privilege according to pg_authid */
 static bool
-has_usecatupd(AclId userid)
+has_rolcatupdate(Oid roleid)
 {
-	bool		usecatupd;
+	bool		rolcatupdate;
 	HeapTuple	tuple;
 
-	tuple = SearchSysCache(SHADOWSYSID,
-						   ObjectIdGetDatum(userid),
+	tuple = SearchSysCache(AUTHOID,
+						   ObjectIdGetDatum(roleid),
 						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("user with ID %u does not exist", userid)));
+				 errmsg("role with OID %u does not exist", roleid)));
 
-	usecatupd = ((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd;
+	rolcatupdate = ((Form_pg_authid) GETSTRUCT(tuple))->rolcatupdate;
 
 	ReleaseSysCache(tuple);
 
-	return usecatupd;
+	return rolcatupdate;
 }
 
 
@@ -1344,7 +1306,7 @@ has_usecatupd(AclId userid)
  * below.
  */
 AclMode
-pg_class_aclmask(Oid table_oid, AclId userid,
+pg_class_aclmask(Oid table_oid, Oid roleid,
 				 AclMode mask, AclMaskHow how)
 {
 	AclMode		result;
@@ -1353,7 +1315,7 @@ pg_class_aclmask(Oid table_oid, AclId userid,
 	Datum		aclDatum;
 	bool		isNull;
 	Acl		   *acl;
-	AclId		ownerId;
+	Oid		ownerId;
 
 	/*
 	 * Must get the relation's tuple from pg_class
@@ -1370,7 +1332,7 @@ pg_class_aclmask(Oid table_oid, AclId userid,
 
 	/*
 	 * Deny anyone permission to update a system catalog unless
-	 * pg_shadow.usecatupd is set.	(This is to let superusers protect
+	 * pg_authid.rolcatupdate is set.	(This is to let superusers protect
 	 * themselves from themselves.)  Also allow it if
 	 * allowSystemTableMods.
 	 *
@@ -1381,7 +1343,7 @@ pg_class_aclmask(Oid table_oid, AclId userid,
 	if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
 		IsSystemClass(classForm) &&
 		classForm->relkind != RELKIND_VIEW &&
-		!has_usecatupd(userid) &&
+		!has_rolcatupdate(roleid) &&
 		!allowSystemTableMods)
 	{
 #ifdef ACLDEBUG
@@ -1393,10 +1355,10 @@ pg_class_aclmask(Oid table_oid, AclId userid,
 	/*
 	 * Otherwise, superusers bypass all permission-checking.
 	 */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 	{
 #ifdef ACLDEBUG
-		elog(DEBUG2, "%u is superuser, home free", userid);
+		elog(DEBUG2, "OID %u is superuser, home free", roleid);
 #endif
 		ReleaseSysCache(tuple);
 		return mask;
@@ -1421,7 +1383,7 @@ pg_class_aclmask(Oid table_oid, AclId userid,
 		acl = DatumGetAclP(aclDatum);
 	}
 
-	result = aclmask(acl, userid, ownerId, mask, how);
+	result = aclmask(acl, roleid, ownerId, mask, how);
 
 	/* if we have a detoasted copy, free it */
 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
@@ -1436,7 +1398,7 @@ pg_class_aclmask(Oid table_oid, AclId userid,
  * Exported routine for examining a user's privileges for a database
  */
 AclMode
-pg_database_aclmask(Oid db_oid, AclId userid,
+pg_database_aclmask(Oid db_oid, Oid roleid,
 					AclMode mask, AclMaskHow how)
 {
 	AclMode		result;
@@ -1447,10 +1409,10 @@ pg_database_aclmask(Oid db_oid, AclId userid,
 	Datum		aclDatum;
 	bool		isNull;
 	Acl		   *acl;
-	AclId		ownerId;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return mask;
 
 	/*
@@ -1487,7 +1449,7 @@ pg_database_aclmask(Oid db_oid, AclId userid,
 		acl = DatumGetAclP(aclDatum);
 	}
 
-	result = aclmask(acl, userid, ownerId, mask, how);
+	result = aclmask(acl, roleid, ownerId, mask, how);
 
 	/* if we have a detoasted copy, free it */
 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
@@ -1503,7 +1465,7 @@ pg_database_aclmask(Oid db_oid, AclId userid,
  * Exported routine for examining a user's privileges for a function
  */
 AclMode
-pg_proc_aclmask(Oid proc_oid, AclId userid,
+pg_proc_aclmask(Oid proc_oid, Oid roleid,
 				AclMode mask, AclMaskHow how)
 {
 	AclMode		result;
@@ -1511,10 +1473,10 @@ pg_proc_aclmask(Oid proc_oid, AclId userid,
 	Datum		aclDatum;
 	bool		isNull;
 	Acl		   *acl;
-	AclId		ownerId;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return mask;
 
 	/*
@@ -1544,7 +1506,7 @@ pg_proc_aclmask(Oid proc_oid, AclId userid,
 		acl = DatumGetAclP(aclDatum);
 	}
 
-	result = aclmask(acl, userid, ownerId, mask, how);
+	result = aclmask(acl, roleid, ownerId, mask, how);
 
 	/* if we have a detoasted copy, free it */
 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
@@ -1559,7 +1521,7 @@ pg_proc_aclmask(Oid proc_oid, AclId userid,
  * Exported routine for examining a user's privileges for a language
  */
 AclMode
-pg_language_aclmask(Oid lang_oid, AclId userid,
+pg_language_aclmask(Oid lang_oid, Oid roleid,
 					AclMode mask, AclMaskHow how)
 {
 	AclMode		result;
@@ -1567,10 +1529,10 @@ pg_language_aclmask(Oid lang_oid, AclId userid,
 	Datum		aclDatum;
 	bool		isNull;
 	Acl		   *acl;
-	AclId		ownerId;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return mask;
 
 	/*
@@ -1585,7 +1547,7 @@ pg_language_aclmask(Oid lang_oid, AclId userid,
 			   errmsg("language with OID %u does not exist", lang_oid)));
 
 	/* XXX pg_language should have an owner column, but doesn't */
-	ownerId = BOOTSTRAP_USESYSID;
+	ownerId = BOOTSTRAP_SUPERUSERID;
 
 	aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
 							   &isNull);
@@ -1601,7 +1563,7 @@ pg_language_aclmask(Oid lang_oid, AclId userid,
 		acl = DatumGetAclP(aclDatum);
 	}
 
-	result = aclmask(acl, userid, ownerId, mask, how);
+	result = aclmask(acl, roleid, ownerId, mask, how);
 
 	/* if we have a detoasted copy, free it */
 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
@@ -1616,7 +1578,7 @@ pg_language_aclmask(Oid lang_oid, AclId userid,
  * Exported routine for examining a user's privileges for a namespace
  */
 AclMode
-pg_namespace_aclmask(Oid nsp_oid, AclId userid,
+pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
 					 AclMode mask, AclMaskHow how)
 {
 	AclMode		result;
@@ -1624,10 +1586,10 @@ pg_namespace_aclmask(Oid nsp_oid, AclId userid,
 	Datum		aclDatum;
 	bool		isNull;
 	Acl		   *acl;
-	AclId		ownerId;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return mask;
 
 	/*
@@ -1685,7 +1647,7 @@ pg_namespace_aclmask(Oid nsp_oid, AclId userid,
 		acl = DatumGetAclP(aclDatum);
 	}
 
-	result = aclmask(acl, userid, ownerId, mask, how);
+	result = aclmask(acl, roleid, ownerId, mask, how);
 
 	/* if we have a detoasted copy, free it */
 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
@@ -1700,7 +1662,7 @@ pg_namespace_aclmask(Oid nsp_oid, AclId userid,
  * Exported routine for examining a user's privileges for a tablespace
  */
 AclMode
-pg_tablespace_aclmask(Oid spc_oid, AclId userid,
+pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
 					  AclMode mask, AclMaskHow how)
 {
 	AclMode		result;
@@ -1711,7 +1673,7 @@ pg_tablespace_aclmask(Oid spc_oid, AclId userid,
 	Datum		aclDatum;
 	bool		isNull;
 	Acl		   *acl;
-	AclId		ownerId;
+	Oid		ownerId;
 
 	/*
 	 * Only shared relations can be stored in global space; don't let even
@@ -1721,7 +1683,7 @@ pg_tablespace_aclmask(Oid spc_oid, AclId userid,
 		return 0;
 
 	/* Otherwise, superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return mask;
 
 	/*
@@ -1758,7 +1720,7 @@ pg_tablespace_aclmask(Oid spc_oid, AclId userid,
 		acl = DatumGetAclP(aclDatum);
 	}
 
-	result = aclmask(acl, userid, ownerId, mask, how);
+	result = aclmask(acl, roleid, ownerId, mask, how);
 
 	/* if we have a detoasted copy, free it */
 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
@@ -1779,9 +1741,9 @@ pg_tablespace_aclmask(Oid spc_oid, AclId userid,
  * ACLCHECK_NO_PRIV).
  */
 AclResult
-pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode)
+pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
 {
-	if (pg_class_aclmask(table_oid, userid, mode, ACLMASK_ANY) != 0)
+	if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0)
 		return ACLCHECK_OK;
 	else
 		return ACLCHECK_NO_PRIV;
@@ -1791,9 +1753,9 @@ pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode)
  * Exported routine for checking a user's access privileges to a database
  */
 AclResult
-pg_database_aclcheck(Oid db_oid, AclId userid, AclMode mode)
+pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
 {
-	if (pg_database_aclmask(db_oid, userid, mode, ACLMASK_ANY) != 0)
+	if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
 		return ACLCHECK_OK;
 	else
 		return ACLCHECK_NO_PRIV;
@@ -1803,9 +1765,9 @@ pg_database_aclcheck(Oid db_oid, AclId userid, AclMode mode)
  * Exported routine for checking a user's access privileges to a function
  */
 AclResult
-pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode)
+pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
 {
-	if (pg_proc_aclmask(proc_oid, userid, mode, ACLMASK_ANY) != 0)
+	if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
 		return ACLCHECK_OK;
 	else
 		return ACLCHECK_NO_PRIV;
@@ -1815,9 +1777,9 @@ pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode)
  * Exported routine for checking a user's access privileges to a language
  */
 AclResult
-pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode)
+pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode)
 {
-	if (pg_language_aclmask(lang_oid, userid, mode, ACLMASK_ANY) != 0)
+	if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
 		return ACLCHECK_OK;
 	else
 		return ACLCHECK_NO_PRIV;
@@ -1827,9 +1789,9 @@ pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode)
  * Exported routine for checking a user's access privileges to a namespace
  */
 AclResult
-pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode)
+pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
 {
-	if (pg_namespace_aclmask(nsp_oid, userid, mode, ACLMASK_ANY) != 0)
+	if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
 		return ACLCHECK_OK;
 	else
 		return ACLCHECK_NO_PRIV;
@@ -1839,9 +1801,9 @@ pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode)
  * Exported routine for checking a user's access privileges to a tablespace
  */
 AclResult
-pg_tablespace_aclcheck(Oid spc_oid, AclId userid, AclMode mode)
+pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
 {
-	if (pg_tablespace_aclmask(spc_oid, userid, mode, ACLMASK_ANY) != 0)
+	if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
 		return ACLCHECK_OK;
 	else
 		return ACLCHECK_NO_PRIV;
@@ -1852,13 +1814,13 @@ pg_tablespace_aclcheck(Oid spc_oid, AclId userid, AclMode mode)
  * Ownership check for a relation (specified by OID).
  */
 bool
-pg_class_ownercheck(Oid class_oid, AclId userid)
+pg_class_ownercheck(Oid class_oid, Oid roleid)
 {
 	HeapTuple	tuple;
-	AclId		owner_id;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return true;
 
 	tuple = SearchSysCache(RELOID,
@@ -1869,24 +1831,24 @@ pg_class_ownercheck(Oid class_oid, AclId userid)
 				(errcode(ERRCODE_UNDEFINED_TABLE),
 			  errmsg("relation with OID %u does not exist", class_oid)));
 
-	owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
+	ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
 
 	ReleaseSysCache(tuple);
 
-	return userid == owner_id;
+	return is_member_of_role(roleid, ownerId);
 }
 
 /*
  * Ownership check for a type (specified by OID).
  */
 bool
-pg_type_ownercheck(Oid type_oid, AclId userid)
+pg_type_ownercheck(Oid type_oid, Oid roleid)
 {
 	HeapTuple	tuple;
-	AclId		owner_id;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return true;
 
 	tuple = SearchSysCache(TYPEOID,
@@ -1897,24 +1859,24 @@ pg_type_ownercheck(Oid type_oid, AclId userid)
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("type with OID %u does not exist", type_oid)));
 
-	owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
+	ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
 
 	ReleaseSysCache(tuple);
 
-	return userid == owner_id;
+	return is_member_of_role(roleid, ownerId);
 }
 
 /*
  * Ownership check for an operator (specified by OID).
  */
 bool
-pg_oper_ownercheck(Oid oper_oid, AclId userid)
+pg_oper_ownercheck(Oid oper_oid, Oid roleid)
 {
 	HeapTuple	tuple;
-	AclId		owner_id;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return true;
 
 	tuple = SearchSysCache(OPEROID,
@@ -1925,24 +1887,24 @@ pg_oper_ownercheck(Oid oper_oid, AclId userid)
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 			   errmsg("operator with OID %u does not exist", oper_oid)));
 
-	owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
+	ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
 
 	ReleaseSysCache(tuple);
 
-	return userid == owner_id;
+	return is_member_of_role(roleid, ownerId);
 }
 
 /*
  * Ownership check for a function (specified by OID).
  */
 bool
-pg_proc_ownercheck(Oid proc_oid, AclId userid)
+pg_proc_ownercheck(Oid proc_oid, Oid roleid)
 {
 	HeapTuple	tuple;
-	AclId		owner_id;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return true;
 
 	tuple = SearchSysCache(PROCOID,
@@ -1953,24 +1915,24 @@ pg_proc_ownercheck(Oid proc_oid, AclId userid)
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 			   errmsg("function with OID %u does not exist", proc_oid)));
 
-	owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
+	ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
 
 	ReleaseSysCache(tuple);
 
-	return userid == owner_id;
+	return is_member_of_role(roleid, ownerId);
 }
 
 /*
  * Ownership check for a namespace (specified by OID).
  */
 bool
-pg_namespace_ownercheck(Oid nsp_oid, AclId userid)
+pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
 {
 	HeapTuple	tuple;
-	AclId		owner_id;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return true;
 
 	tuple = SearchSysCache(NAMESPACEOID,
@@ -1981,27 +1943,27 @@ pg_namespace_ownercheck(Oid nsp_oid, AclId userid)
 				(errcode(ERRCODE_UNDEFINED_SCHEMA),
 				 errmsg("schema with OID %u does not exist", nsp_oid)));
 
-	owner_id = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
+	ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
 
 	ReleaseSysCache(tuple);
 
-	return userid == owner_id;
+	return is_member_of_role(roleid, ownerId);
 }
 
 /*
  * Ownership check for a tablespace (specified by OID).
  */
 bool
-pg_tablespace_ownercheck(Oid spc_oid, AclId userid)
+pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
 {
 	Relation	pg_tablespace;
 	ScanKeyData entry[1];
 	HeapScanDesc scan;
 	HeapTuple	spctuple;
-	int32		spcowner;
+	Oid		spcowner;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return true;
 
 	/* There's no syscache for pg_tablespace, so must look the hard way */
@@ -2024,20 +1986,20 @@ pg_tablespace_ownercheck(Oid spc_oid, AclId userid)
 	heap_endscan(scan);
 	heap_close(pg_tablespace, AccessShareLock);
 
-	return userid == spcowner;
+	return is_member_of_role(roleid, spcowner);
 }
 
 /*
  * Ownership check for an operator class (specified by OID).
  */
 bool
-pg_opclass_ownercheck(Oid opc_oid, AclId userid)
+pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
 {
 	HeapTuple	tuple;
-	AclId		owner_id;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return true;
 
 	tuple = SearchSysCache(CLAOID,
@@ -2049,27 +2011,27 @@ pg_opclass_ownercheck(Oid opc_oid, AclId userid)
 				 errmsg("operator class with OID %u does not exist",
 						opc_oid)));
 
-	owner_id = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
+	ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
 
 	ReleaseSysCache(tuple);
 
-	return userid == owner_id;
+	return is_member_of_role(roleid, ownerId);
 }
 
 /*
  * Ownership check for a database (specified by OID).
  */
 bool
-pg_database_ownercheck(Oid db_oid, AclId userid)
+pg_database_ownercheck(Oid db_oid, Oid roleid)
 {
 	Relation	pg_database;
 	ScanKeyData entry[1];
 	HeapScanDesc scan;
 	HeapTuple	dbtuple;
-	int32		dba;
+	Oid		dba;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return true;
 
 	/* There's no syscache for pg_database, so must look the hard way */
@@ -2092,20 +2054,20 @@ pg_database_ownercheck(Oid db_oid, AclId userid)
 	heap_endscan(scan);
 	heap_close(pg_database, AccessShareLock);
 
-	return userid == dba;
+	return is_member_of_role(roleid, dba);
 }
 
 /*
  * Ownership check for a conversion (specified by OID).
  */
 bool
-pg_conversion_ownercheck(Oid conv_oid, AclId userid)
+pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
 {
 	HeapTuple	tuple;
-	AclId		owner_id;
+	Oid		ownerId;
 
 	/* Superusers bypass all permission checking. */
-	if (superuser_arg(userid))
+	if (superuser_arg(roleid))
 		return true;
 
 	tuple = SearchSysCache(CONOID,
@@ -2116,9 +2078,9 @@ pg_conversion_ownercheck(Oid conv_oid, AclId userid)
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 			 errmsg("conversion with OID %u does not exist", conv_oid)));
 
-	owner_id = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
+	ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
 
 	ReleaseSysCache(tuple);
 
-	return userid == owner_id;
+	return is_member_of_role(roleid, ownerId);
 }
diff --git a/src/backend/catalog/genbki.sh b/src/backend/catalog/genbki.sh
index 92a3ac5eeccca31c364c33a88ce7c22ae0ad3afa..9d9b75bde58aadc4af39c123b44fa962df302549 100644
--- a/src/backend/catalog/genbki.sh
+++ b/src/backend/catalog/genbki.sh
@@ -11,7 +11,7 @@
 #
 #
 # IDENTIFICATION
-#    $PostgreSQL: pgsql/src/backend/catalog/genbki.sh,v 1.36 2005/04/14 20:03:23 tgl Exp $
+#    $PostgreSQL: pgsql/src/backend/catalog/genbki.sh,v 1.37 2005/06/28 05:08:52 tgl Exp $
 #
 # NOTES
 #    non-essential whitespace is removed from the generated file.
@@ -114,6 +114,14 @@ for dir in $INCLUDE_DIRS; do
     fi
 done
 
+# Get BOOTSTRAP_SUPERUSERID from catalog/pg_authid.h
+for dir in $INCLUDE_DIRS; do
+    if [ -f "$dir/catalog/pg_authid.h" ]; then
+        BOOTSTRAP_SUPERUSERID=`grep '^#define[ 	]*BOOTSTRAP_SUPERUSERID' $dir/catalog/pg_authid.h | $AWK '{ print $3 }'`
+        break
+    fi
+done
+
 # Get PG_CATALOG_NAMESPACE from catalog/pg_namespace.h
 for dir in $INCLUDE_DIRS; do
     if [ -f "$dir/catalog/pg_namespace.h" ]; then
@@ -153,7 +161,7 @@ sed -e "s/;[ 	]*$//g" \
     -e "s/[ 	]TransactionId/ xid/g" \
     -e "s/^TransactionId/xid/g" \
     -e "s/(TransactionId/(xid/g" \
-    -e "s/PGUID/1/g" \
+    -e "s/PGUID/$BOOTSTRAP_SUPERUSERID/g" \
     -e "s/NAMEDATALEN/$NAMEDATALEN/g" \
     -e "s/PGNSP/$PG_CATALOG_NAMESPACE/g" \
 | $AWK '
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index 83e6fa82b0f2976c449fd23d37e3866dcfd5b39a..6d90887ba6c2a8391a3c952103bf8a47358d558f 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2003-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.28 2005/05/31 03:36:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.29 2005/06/28 05:08:52 tgl Exp $
  */
 
 /*
@@ -210,13 +210,13 @@ CREATE DOMAIN time_stamp AS timestamp(2)
 
 CREATE VIEW applicable_roles AS
     SELECT CAST(current_user AS sql_identifier) AS grantee,
-           CAST(g.groname AS sql_identifier) AS role_name,
-           CAST('NO' AS character_data) AS is_grantable
+           CAST(a.rolname AS sql_identifier) AS role_name,
+           CAST(CASE WHEN m.admin_option = 'true' THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
 
-    FROM pg_group g, pg_user u
+    FROM ((pg_auth_members m join pg_authid a ON (m.roleid = a.oid))
+    			     join pg_authid b ON (m.member = b.oid))
 
-    WHERE u.usesysid = ANY (g.grolist)
-          AND u.usename = current_user;
+    WHERE b.rolname = current_user;
 
 GRANT SELECT ON applicable_roles TO PUBLIC;
 
@@ -282,7 +282,7 @@ GRANT SELECT ON column_domain_usage TO PUBLIC;
  */
 
 CREATE VIEW column_privileges AS
-    SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
+    SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
            CAST(grantee.name AS sql_identifier) AS grantee,
            CAST(current_database() AS sql_identifier) AS table_catalog,
            CAST(nc.nspname AS sql_identifier) AS table_schema,
@@ -291,20 +291,18 @@ CREATE VIEW column_privileges AS
            CAST(pr.type AS character_data) AS privilege_type,
            CAST(
              CASE WHEN aclcontains(c.relacl,
-                                   makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, pr.type, true))
+                                   makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
                   THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
 
     FROM pg_attribute a,
          pg_class c,
          pg_namespace nc,
-         pg_user u_grantor,
+         pg_authid u_grantor,
          (
-           SELECT usesysid, 0, usename FROM pg_user
-           UNION ALL
-           SELECT 0, grosysid, groname FROM pg_group
+           SELECT oid, rolname FROM pg_authid
            UNION ALL
-           SELECT 0, 0, 'PUBLIC'
-         ) AS grantee (usesysid, grosysid, name),
+           SELECT 0, 'PUBLIC'
+         ) AS grantee (oid, name),
          (SELECT 'SELECT' UNION ALL
           SELECT 'INSERT' UNION ALL
           SELECT 'UPDATE' UNION ALL
@@ -316,8 +314,8 @@ CREATE VIEW column_privileges AS
           AND NOT a.attisdropped
           AND c.relkind IN ('r', 'v')
           AND aclcontains(c.relacl,
-                          makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, pr.type, false))
-          AND (u_grantor.usename = current_user
+                          makeaclitem(grantee.oid, u_grantor.oid, pr.type, false))
+          AND (u_grantor.rolname = current_user
                OR grantee.name = current_user
                OR grantee.name = 'PUBLIC');
 
@@ -693,10 +691,10 @@ GRANT SELECT ON domains TO PUBLIC;
  */
 
 CREATE VIEW enabled_roles AS
-    SELECT CAST(g.groname AS sql_identifier) AS role_name
-    FROM pg_group g, pg_user u
-    WHERE u.usesysid = ANY (g.grolist)
-          AND u.usename = current_user;
+    SELECT CAST(a.rolname AS sql_identifier) AS role_name
+    FROM ((pg_auth_members m join pg_authid a ON (m.roleid = a.oid))
+    			     join pg_authid b ON (m.member = b.oid))
+    WHERE b.rolname = current_user;
 
 GRANT SELECT ON enabled_roles TO PUBLIC;
 
@@ -865,7 +863,7 @@ CREATE VIEW role_column_grants AS
            CAST(pr.type AS character_data) AS privilege_type,
            CAST(
              CASE WHEN aclcontains(c.relacl,
-                                   makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, pr.type, true))
+                                   makeaclitem(g_grantee.grosysid, u_grantor.usesysid, pr.type, true))
                   THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
 
     FROM pg_attribute a,
@@ -884,7 +882,7 @@ CREATE VIEW role_column_grants AS
           AND NOT a.attisdropped
           AND c.relkind IN ('r', 'v')
           AND aclcontains(c.relacl,
-                          makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, pr.type, false))
+                          makeaclitem(g_grantee.grosysid, u_grantor.usesysid, pr.type, false))
           AND g_grantee.groname IN (SELECT role_name FROM enabled_roles);
 
 GRANT SELECT ON role_column_grants TO PUBLIC;
@@ -907,7 +905,7 @@ CREATE VIEW role_routine_grants AS
            CAST('EXECUTE' AS character_data) AS privilege_type,
            CAST(
              CASE WHEN aclcontains(p.proacl,
-                                   makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, 'EXECUTE', true))
+                                   makeaclitem(g_grantee.grosysid, u_grantor.usesysid, 'EXECUTE', true))
                   THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
 
     FROM pg_proc p,
@@ -917,7 +915,7 @@ CREATE VIEW role_routine_grants AS
 
     WHERE p.pronamespace = n.oid
           AND aclcontains(p.proacl,
-                          makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, 'EXECUTE', false))
+                          makeaclitem(g_grantee.grosysid, u_grantor.usesysid, 'EXECUTE', false))
           AND g_grantee.groname IN (SELECT role_name FROM enabled_roles);
 
 GRANT SELECT ON role_routine_grants TO PUBLIC;
@@ -937,7 +935,7 @@ CREATE VIEW role_table_grants AS
            CAST(pr.type AS character_data) AS privilege_type,
            CAST(
              CASE WHEN aclcontains(c.relacl,
-                                   makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, pr.type, true))
+                                   makeaclitem(g_grantee.grosysid, u_grantor.usesysid, pr.type, true))
                   THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable,
            CAST('NO' AS character_data) AS with_hierarchy
 
@@ -956,7 +954,7 @@ CREATE VIEW role_table_grants AS
     WHERE c.relnamespace = nc.oid
           AND c.relkind IN ('r', 'v')
           AND aclcontains(c.relacl,
-                          makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, pr.type, false))
+                          makeaclitem(g_grantee.grosysid, u_grantor.usesysid, pr.type, false))
           AND g_grantee.groname IN (SELECT role_name FROM enabled_roles);
 
 GRANT SELECT ON role_table_grants TO PUBLIC;
@@ -990,7 +988,7 @@ GRANT SELECT ON role_usage_grants TO PUBLIC;
  */
 
 CREATE VIEW routine_privileges AS
-    SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
+    SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
            CAST(grantee.name AS sql_identifier) AS grantee,
            CAST(current_database() AS sql_identifier) AS specific_catalog,
            CAST(n.nspname AS sql_identifier) AS specific_schema,
@@ -1001,24 +999,22 @@ CREATE VIEW routine_privileges AS
            CAST('EXECUTE' AS character_data) AS privilege_type,
            CAST(
              CASE WHEN aclcontains(p.proacl,
-                                   makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, 'EXECUTE', true))
+                                   makeaclitem(grantee.oid, u_grantor.oid, 'EXECUTE', true))
                   THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
 
     FROM pg_proc p,
          pg_namespace n,
-         pg_user u_grantor,
+         pg_authid u_grantor,
          (
-           SELECT usesysid, 0, usename FROM pg_user
-           UNION ALL
-           SELECT 0, grosysid, groname FROM pg_group
+           SELECT oid, rolname FROM pg_authid
            UNION ALL
-           SELECT 0, 0, 'PUBLIC'
-         ) AS grantee (usesysid, grosysid, name)
+           SELECT 0, 'PUBLIC'
+         ) AS grantee (oid, name)
 
     WHERE p.pronamespace = n.oid
           AND aclcontains(p.proacl,
-                          makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, 'EXECUTE', false))
-          AND (u_grantor.usename = current_user
+                          makeaclitem(grantee.oid, u_grantor.oid, 'EXECUTE', false))
+          AND (u_grantor.rolname = current_user
                OR grantee.name = current_user
                OR grantee.name = 'PUBLIC');
 
@@ -1338,7 +1334,7 @@ GRANT SELECT ON table_constraints TO PUBLIC;
  */
 
 CREATE VIEW table_privileges AS
-    SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
+    SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
            CAST(grantee.name AS sql_identifier) AS grantee,
            CAST(current_database() AS sql_identifier) AS table_catalog,
            CAST(nc.nspname AS sql_identifier) AS table_schema,
@@ -1346,20 +1342,18 @@ CREATE VIEW table_privileges AS
            CAST(pr.type AS character_data) AS privilege_type,
            CAST(
              CASE WHEN aclcontains(c.relacl,
-                                   makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, pr.type, true))
+                                   makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
                   THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable,
            CAST('NO' AS character_data) AS with_hierarchy
 
     FROM pg_class c,
          pg_namespace nc,
-         pg_user u_grantor,
+         pg_authid u_grantor,
          (
-           SELECT usesysid, 0, usename FROM pg_user
-           UNION ALL
-           SELECT 0, grosysid, groname FROM pg_group
+           SELECT oid, rolname FROM pg_authid
            UNION ALL
-           SELECT 0, 0, 'PUBLIC'
-         ) AS grantee (usesysid, grosysid, name),
+           SELECT 0, 'PUBLIC'
+         ) AS grantee (oid, name),
          (SELECT 'SELECT' UNION ALL
           SELECT 'DELETE' UNION ALL
           SELECT 'INSERT' UNION ALL
@@ -1371,8 +1365,8 @@ CREATE VIEW table_privileges AS
     WHERE c.relnamespace = nc.oid
           AND c.relkind IN ('r', 'v')
           AND aclcontains(c.relacl,
-                          makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, pr.type, false))
-          AND (u_grantor.usename = current_user
+                          makeaclitem(grantee.oid, u_grantor.oid, pr.type, false))
+          AND (u_grantor.rolname = current_user
                OR grantee.name = current_user
                OR grantee.name = 'PUBLIC');
 
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 3cfcc6f9b46b97f2e8d5b7aeb5e49b0a52d5d925..6b12bda661548e6f59e72866a6a07627788823eb 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.75 2005/04/14 20:03:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.76 2005/06/28 05:08:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,12 +22,12 @@
 #include "access/xact.h"
 #include "catalog/dependency.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
 #include "catalog/pg_conversion.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
-#include "catalog/pg_shadow.h"
 #include "catalog/pg_type.h"
 #include "commands/dbcommands.h"
 #include "lib/stringinfo.h"
@@ -1499,7 +1499,7 @@ FindDefaultConversionProc(int4 for_encoding, int4 to_encoding)
 static void
 recomputeNamespacePath(void)
 {
-	AclId		userId = GetUserId();
+	Oid		roleid = GetUserId();
 	char	   *rawname;
 	List	   *namelist;
 	List	   *oidlist;
@@ -1511,7 +1511,7 @@ recomputeNamespacePath(void)
 	/*
 	 * Do nothing if path is already valid.
 	 */
-	if (namespaceSearchPathValid && namespaceUser == userId)
+	if (namespaceSearchPathValid && namespaceUser == roleid)
 		return;
 
 	/* Need a modifiable copy of namespace_search_path string */
@@ -1542,21 +1542,21 @@ recomputeNamespacePath(void)
 			/* $user --- substitute namespace matching user name, if any */
 			HeapTuple	tuple;
 
-			tuple = SearchSysCache(SHADOWSYSID,
-								   ObjectIdGetDatum(userId),
+			tuple = SearchSysCache(AUTHOID,
+								   ObjectIdGetDatum(roleid),
 								   0, 0, 0);
 			if (HeapTupleIsValid(tuple))
 			{
-				char	   *uname;
+				char	   *rname;
 
-				uname = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
+				rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
 				namespaceId = GetSysCacheOid(NAMESPACENAME,
-											 CStringGetDatum(uname),
+											 CStringGetDatum(rname),
 											 0, 0, 0);
 				ReleaseSysCache(tuple);
 				if (OidIsValid(namespaceId) &&
 					!list_member_oid(oidlist, namespaceId) &&
-					pg_namespace_aclcheck(namespaceId, userId,
+					pg_namespace_aclcheck(namespaceId, roleid,
 										  ACL_USAGE) == ACLCHECK_OK)
 					oidlist = lappend_oid(oidlist, namespaceId);
 			}
@@ -1569,7 +1569,7 @@ recomputeNamespacePath(void)
 										 0, 0, 0);
 			if (OidIsValid(namespaceId) &&
 				!list_member_oid(oidlist, namespaceId) &&
-				pg_namespace_aclcheck(namespaceId, userId,
+				pg_namespace_aclcheck(namespaceId, roleid,
 									  ACL_USAGE) == ACLCHECK_OK)
 				oidlist = lappend_oid(oidlist, namespaceId);
 		}
@@ -1622,7 +1622,7 @@ recomputeNamespacePath(void)
 
 	/* Mark the path valid. */
 	namespaceSearchPathValid = true;
-	namespaceUser = userId;
+	namespaceUser = roleid;
 
 	/* Clean up. */
 	pfree(rawname);
@@ -1674,7 +1674,7 @@ InitTempTableNamespace(void)
 		 * that access the temp namespace for my own backend skip
 		 * permissions checks on it.
 		 */
-		namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID);
+		namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID);
 		/* Advance command counter to make namespace visible */
 		CommandCounterIncrement();
 	}
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 797583f6c04a51701857651fe1742e3c07e0d500..61a1a53902ab998e6eef43b77165e883b64b0fff 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/pg_conversion.c,v 1.23 2005/05/27 00:57:49 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/pg_conversion.c,v 1.24 2005/06/28 05:08:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@
  */
 Oid
 ConversionCreate(const char *conname, Oid connamespace,
-				 AclId conowner,
+				 Oid conowner,
 				 int32 conforencoding, int32 contoencoding,
 				 Oid conproc, bool def)
 {
@@ -95,7 +95,7 @@ ConversionCreate(const char *conname, Oid connamespace,
 	namestrcpy(&cname, conname);
 	values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname);
 	values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace);
-	values[Anum_pg_conversion_conowner - 1] = Int32GetDatum(conowner);
+	values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner);
 	values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
 	values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
 	values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
index c2266f22d4dfa4fbbcd9d331dc2d138527aded4f..8144d64136b5c2bef83fe94294353ec02f91239c 100644
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/pg_namespace.c,v 1.13 2005/04/14 20:03:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/pg_namespace.c,v 1.14 2005/06/28 05:08:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,7 +26,7 @@
  * ---------------
  */
 Oid
-NamespaceCreate(const char *nspName, int32 ownerSysId)
+NamespaceCreate(const char *nspName, Oid ownerId)
 {
 	Relation	nspdesc;
 	HeapTuple	tup;
@@ -57,7 +57,7 @@ NamespaceCreate(const char *nspName, int32 ownerSysId)
 	}
 	namestrcpy(&nname, nspName);
 	values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
-	values[Anum_pg_namespace_nspowner - 1] = Int32GetDatum(ownerSysId);
+	values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
 	nulls[Anum_pg_namespace_nspacl - 1] = 'n';
 
 	nspdesc = heap_open(NamespaceRelationId, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 6f50e4dabddb969fa3b5a9836cbbf437896e9887..55fa9e127cf14d2d7e91456ef8cd1a718663a0c6 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.91 2005/04/14 20:03:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.92 2005/06/28 05:08:52 tgl Exp $
  *
  * NOTES
  *	  these routines moved here from commands/define.c and somewhat cleaned up.
@@ -235,7 +235,7 @@ OperatorShellMake(const char *operatorName,
 	namestrcpy(&oname, operatorName);
 	values[i++] = NameGetDatum(&oname); /* oprname */
 	values[i++] = ObjectIdGetDatum(operatorNamespace);	/* oprnamespace */
-	values[i++] = Int32GetDatum(GetUserId());	/* oprowner */
+	values[i++] = ObjectIdGetDatum(GetUserId());	/* oprowner */
 	values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');	/* oprkind */
 	values[i++] = BoolGetDatum(false);	/* oprcanhash */
 	values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
@@ -519,7 +519,7 @@ OperatorCreate(const char *operatorName,
 	namestrcpy(&oname, operatorName);
 	values[i++] = NameGetDatum(&oname); /* oprname */
 	values[i++] = ObjectIdGetDatum(operatorNamespace);	/* oprnamespace */
-	values[i++] = Int32GetDatum(GetUserId());	/* oprowner */
+	values[i++] = ObjectIdGetDatum(GetUserId());	/* oprowner */
 	values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');	/* oprkind */
 	values[i++] = BoolGetDatum(canHash);		/* oprcanhash */
 	values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 12f6c64634f0e874a00e3d17f34939c99e146a6e..7d1384ed382be8530fb1e9a3fa66073e1edab905 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.129 2005/05/03 16:51:00 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.130 2005/06/28 05:08:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -217,7 +217,7 @@ ProcedureCreate(const char *procedureName,
 	namestrcpy(&procname, procedureName);
 	values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname);
 	values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace);
-	values[Anum_pg_proc_proowner - 1] = Int32GetDatum(GetUserId());
+	values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(GetUserId());
 	values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
 	values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
 	values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index acadded40d782de1006cf62477726233dc57fdee..fa4068bf9f60b6cdf6f165cdae0c113935fc0929 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.100 2005/04/14 20:03:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.101 2005/06/28 05:08:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -227,7 +227,7 @@ TypeCreate(const char *typeName,
 	namestrcpy(&name, typeName);
 	values[i++] = NameGetDatum(&name);	/* typname */
 	values[i++] = ObjectIdGetDatum(typeNamespace);		/* typnamespace */
-	values[i++] = Int32GetDatum(GetUserId());	/* typowner */
+	values[i++] = ObjectIdGetDatum(GetUserId());	/* typowner */
 	values[i++] = Int16GetDatum(internalSize);	/* typlen */
 	values[i++] = BoolGetDatum(passedByValue);	/* typbyval */
 	values[i++] = CharGetDatum(typeType);		/* typtype */
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index f757e21039d716e0a5aaef9739355e3e754868f2..d20a3b6d7f21c673620757d25d816a2bdaf448ae 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -3,9 +3,45 @@
  *
  * Copyright (c) 1996-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.15 2005/06/18 19:33:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.16 2005/06/28 05:08:52 tgl Exp $
  */
 
+CREATE VIEW pg_roles AS 
+    SELECT 
+        rolname,
+        rolsuper,
+        rolcreaterole,
+        rolcreatedb,
+        rolcatupdate,
+        rolcanlogin,
+        '********'::text as rolpassword,
+        rolvaliduntil,
+        rolconfig
+    FROM pg_authid;
+
+CREATE VIEW pg_shadow AS
+    SELECT
+        rolname AS usename,
+        oid AS usesysid,
+        rolcreatedb AS usecreatedb,
+        rolsuper AS usesuper,
+        rolcatupdate AS usecatupd,
+        rolpassword AS passwd,
+        rolvaliduntil::abstime AS valuntil,
+        rolconfig AS useconfig
+    FROM pg_authid
+    WHERE rolcanlogin;
+
+REVOKE ALL on pg_shadow FROM public;
+
+CREATE VIEW pg_group AS
+    SELECT
+        rolname AS groname,
+        oid AS grosysid,
+        ARRAY(SELECT member FROM pg_auth_members WHERE roleid = oid) AS grolist
+    FROM pg_authid
+    WHERE NOT rolcanlogin;
+
 CREATE VIEW pg_user AS 
     SELECT 
         usename, 
@@ -111,10 +147,10 @@ CREATE VIEW pg_locks AS
 
 CREATE VIEW pg_prepared_xacts AS
     SELECT P.transaction, P.gid, P.prepared,
-           U.usename AS owner, D.datname AS database
+           U.rolname AS owner, D.datname AS database
     FROM pg_prepared_xact() AS P
-    (transaction xid, gid text, prepared timestamptz, ownerid int4, dbid oid)
-         LEFT JOIN pg_shadow U ON P.ownerid = U.usesysid
+    (transaction xid, gid text, prepared timestamptz, ownerid oid, dbid oid)
+         LEFT JOIN pg_authid U ON P.ownerid = U.oid
          LEFT JOIN pg_database D ON P.dbid = D.oid;
 
 CREATE VIEW pg_settings AS 
@@ -269,7 +305,7 @@ CREATE VIEW pg_stat_activity AS
             D.datname AS datname, 
             pg_stat_get_backend_pid(S.backendid) AS procpid, 
             pg_stat_get_backend_userid(S.backendid) AS usesysid, 
-            U.usename AS usename, 
+            U.rolname AS usename, 
             pg_stat_get_backend_activity(S.backendid) AS current_query, 
             pg_stat_get_backend_activity_start(S.backendid) AS query_start,
             pg_stat_get_backend_start(S.backendid) AS backend_start,
@@ -277,9 +313,9 @@ CREATE VIEW pg_stat_activity AS
             pg_stat_get_backend_client_port(S.backendid) AS client_port
     FROM pg_database D, 
             (SELECT pg_stat_get_backend_idset() AS backendid) AS S, 
-            pg_shadow U 
+            pg_authid U 
     WHERE pg_stat_get_backend_dbid(S.backendid) = D.oid AND 
-            pg_stat_get_backend_userid(S.backendid) = U.usesysid;
+            pg_stat_get_backend_userid(S.backendid) = U.oid;
 
 CREATE VIEW pg_stat_database AS 
     SELECT 
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 9833937b705ec6189d2d744cdd000abd4bc78598..6335757981ec32eb50cee43498cab6e56393ebf1 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.26 2005/04/14 20:03:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.27 2005/06/28 05:08:53 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -295,7 +295,7 @@ RenameAggregate(List *name, TypeName *basetype, const char *newname)
  * Change aggregate owner
  */
 void
-AlterAggregateOwner(List *name, TypeName *basetype, AclId newOwnerSysId)
+AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId)
 {
 	Oid			basetypeOid;
 	Oid			procOid;
@@ -329,7 +329,7 @@ AlterAggregateOwner(List *name, TypeName *basetype, AclId newOwnerSysId)
 	 * If the new owner is the same as the existing owner, consider the
 	 * command to have succeeded.  This is for dump restoration purposes.
 	 */
-	if (procForm->proowner != newOwnerSysId)
+	if (procForm->proowner != newOwnerId)
 	{
 		/* Otherwise, must be superuser to change object ownership */
 		if (!superuser())
@@ -341,7 +341,7 @@ AlterAggregateOwner(List *name, TypeName *basetype, AclId newOwnerSysId)
 		 * Modify the owner --- okay to scribble on tup because it's a
 		 * copy
 		 */
-		procForm->proowner = newOwnerSysId;
+		procForm->proowner = newOwnerId;
 
 		simple_heap_update(rel, &tup->t_self, tup);
 		CatalogUpdateIndexes(rel, tup);
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 9bb40f351649531450827925231dc0d3b1220745..a19b500152da82fb2666c0f1964da076a75fae8e 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.12 2004/12/31 21:59:41 pgsql Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.13 2005/06/28 05:08:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,10 +64,6 @@ ExecRenameStmt(RenameStmt *stmt)
 			RenameFunction(stmt->object, stmt->objarg, stmt->newname);
 			break;
 
-		case OBJECT_GROUP:
-			RenameGroup(stmt->subname, stmt->newname);
-			break;
-
 		case OBJECT_LANGUAGE:
 			RenameLanguage(stmt->subname, stmt->newname);
 			break;
@@ -76,6 +72,10 @@ ExecRenameStmt(RenameStmt *stmt)
 			RenameOpClass(stmt->object, stmt->subname, stmt->newname);
 			break;
 
+		case OBJECT_ROLE:
+			RenameRole(stmt->subname, stmt->newname);
+			break;
+
 		case OBJECT_SCHEMA:
 			RenameSchema(stmt->subname, stmt->newname);
 			break;
@@ -84,10 +84,6 @@ ExecRenameStmt(RenameStmt *stmt)
 			RenameTableSpace(stmt->subname, stmt->newname);
 			break;
 
-		case OBJECT_USER:
-			RenameUser(stmt->subname, stmt->newname);
-			break;
-
 		case OBJECT_TABLE:
 		case OBJECT_INDEX:
 		case OBJECT_COLUMN:
@@ -153,7 +149,7 @@ ExecRenameStmt(RenameStmt *stmt)
 void
 ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
 {
-	AclId		newowner = get_usesysid(stmt->newowner);
+	Oid		newowner = get_roleid_checked(stmt->newowner);
 
 	switch (stmt->objectType)
 	{
diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c
index fb71bf59f92f6660910d49f6105390d7d7656fa5..c2aa48614e6afbab43ae6febb0963db42f42149a 100644
--- a/src/backend/commands/conversioncmds.c
+++ b/src/backend/commands/conversioncmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.18 2005/05/03 19:17:59 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.19 2005/06/28 05:08:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -175,7 +175,7 @@ RenameConversion(List *name, const char *newname)
  * Change conversion owner
  */
 void
-AlterConversionOwner(List *name, AclId newOwnerSysId)
+AlterConversionOwner(List *name, Oid newOwnerId)
 {
 	Oid			conversionOid;
 	HeapTuple	tup;
@@ -203,7 +203,7 @@ AlterConversionOwner(List *name, AclId newOwnerSysId)
 	 * If the new owner is the same as the existing owner, consider the
 	 * command to have succeeded.  This is for dump restoration purposes.
 	 */
-	if (convForm->conowner != newOwnerSysId)
+	if (convForm->conowner != newOwnerId)
 	{
 		/* Otherwise, must be superuser to change object ownership */
 		if (!superuser())
@@ -215,7 +215,7 @@ AlterConversionOwner(List *name, AclId newOwnerSysId)
 		 * Modify the owner --- okay to scribble on tup because it's a
 		 * copy
 		 */
-		convForm->conowner = newOwnerSysId;
+		convForm->conowner = newOwnerId;
 
 		simple_heap_update(rel, &tup->t_self, tup);
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 30eeefded8e4e1d6deeafb72a59208e64d644ecf..10e68684b8e6e62f3e141b6a05da72f4eb8e1637 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.245 2005/06/02 01:21:22 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.246 2005/06/28 05:08:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,7 +25,6 @@
 #include "catalog/index.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_index.h"
-#include "catalog/pg_shadow.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/trigger.h"
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 6fa6aa5b44bacc07063b7772b7ae73952c7a70bd..1dac14ead2e6ad0285ca51adc84d8c8907adae9a 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.161 2005/06/25 22:47:29 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.162 2005/06/28 05:08:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,10 +28,10 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "catalog/catalog.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_authid.h"
 #include "catalog/pg_database.h"
-#include "catalog/pg_shadow.h"
 #include "catalog/pg_tablespace.h"
-#include "catalog/indexing.h"
 #include "commands/comment.h"
 #include "commands/dbcommands.h"
 #include "commands/tablespace.h"
@@ -52,7 +52,7 @@
 
 
 /* non-export function prototypes */
-static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
+static bool get_db_info(const char *name, Oid *dbIdP, Oid *ownerIdP,
 			int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
 			Oid *dbLastSysOidP,
 			TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
@@ -70,7 +70,7 @@ createdb(const CreatedbStmt *stmt)
 	HeapScanDesc scan;
 	Relation	rel;
 	Oid			src_dboid;
-	AclId		src_owner;
+	Oid			src_owner;
 	int			src_encoding;
 	bool		src_istemplate;
 	bool		src_allowconn;
@@ -85,7 +85,7 @@ createdb(const CreatedbStmt *stmt)
 	Datum		new_record[Natts_pg_database];
 	char		new_record_nulls[Natts_pg_database];
 	Oid			dboid;
-	AclId		datdba;
+	Oid			datdba;
 	ListCell   *option;
 	DefElem    *dtablespacename = NULL;
 	DefElem    *downer = NULL;
@@ -186,13 +186,13 @@ createdb(const CreatedbStmt *stmt)
 				 nodeTag(dencoding->arg));
 	}
 
-	/* obtain sysid of proposed owner */
+	/* obtain OID of proposed owner */
 	if (dbowner)
-		datdba = get_usesysid(dbowner); /* will ereport if no such user */
+		datdba = get_roleid_checked(dbowner);
 	else
 		datdba = GetUserId();
 
-	if (datdba == GetUserId())
+	if (is_member_of_role(GetUserId(), datdba))
 	{
 		/* creating database for self: can be superuser or createdb */
 		if (!superuser() && !have_createdb_privilege())
@@ -243,7 +243,7 @@ createdb(const CreatedbStmt *stmt)
 	 */
 	if (!src_istemplate)
 	{
-		if (!superuser() && GetUserId() != src_owner)
+		if (!pg_database_ownercheck(src_dboid, GetUserId()))
 			ereport(ERROR,
 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 					 errmsg("permission denied to copy database \"%s\"",
@@ -483,7 +483,7 @@ createdb(const CreatedbStmt *stmt)
 
 	new_record[Anum_pg_database_datname - 1] =
 		DirectFunctionCall1(namein, CStringGetDatum(dbname));
-	new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(datdba);
+	new_record[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(datdba);
 	new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
 	new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
 	new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
@@ -557,9 +557,8 @@ createdb(const CreatedbStmt *stmt)
 void
 dropdb(const char *dbname)
 {
-	int4		db_owner;
-	bool		db_istemplate;
 	Oid			db_id;
+	bool		db_istemplate;
 	Relation	pgdbrel;
 	SysScanDesc pgdbscan;
 	ScanKeyData key;
@@ -588,13 +587,13 @@ dropdb(const char *dbname)
 	 */
 	pgdbrel = heap_open(DatabaseRelationId, ExclusiveLock);
 
-	if (!get_db_info(dbname, &db_id, &db_owner, NULL,
+	if (!get_db_info(dbname, &db_id, NULL, NULL,
 					 &db_istemplate, NULL, NULL, NULL, NULL, NULL))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_DATABASE),
 				 errmsg("database \"%s\" does not exist", dbname)));
 
-	if (GetUserId() != db_owner && !superuser())
+	if (!pg_database_ownercheck(db_id, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
 					   dbname);
 
@@ -818,8 +817,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
 				(errcode(ERRCODE_UNDEFINED_DATABASE),
 				 errmsg("database \"%s\" does not exist", stmt->dbname)));
 
-	if (!(superuser()
-		|| ((Form_pg_database) GETSTRUCT(tuple))->datdba == GetUserId()))
+	if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
 					   stmt->dbname);
 
@@ -878,7 +876,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
  * ALTER DATABASE name OWNER TO newowner
  */
 void
-AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
+AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
 {
 	HeapTuple	tuple;
 	Relation	rel;
@@ -910,7 +908,7 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
 	 * command to have succeeded.  This is to be consistent with other
 	 * objects.
 	 */
-	if (datForm->datdba != newOwnerSysId)
+	if (datForm->datdba != newOwnerId)
 	{
 		Datum		repl_val[Natts_pg_database];
 		char		repl_null[Natts_pg_database];
@@ -930,7 +928,7 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
 		memset(repl_repl, ' ', sizeof(repl_repl));
 
 		repl_repl[Anum_pg_database_datdba - 1] = 'r';
-		repl_val[Anum_pg_database_datdba - 1] = Int32GetDatum(newOwnerSysId);
+		repl_val[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(newOwnerId);
 
 		/*
 		 * Determine the modified ACL for the new owner.  This is only
@@ -943,7 +941,7 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
 		if (!isNull)
 		{
 			newAcl = aclnewowner(DatumGetAclP(aclDatum),
-								 datForm->datdba, newOwnerSysId);
+								 datForm->datdba, newOwnerId);
 			repl_repl[Anum_pg_database_datacl - 1] = 'r';
 			repl_val[Anum_pg_database_datacl - 1] = PointerGetDatum(newAcl);
 		}
@@ -972,7 +970,7 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
  */
 
 static bool
-get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
+get_db_info(const char *name, Oid *dbIdP, Oid *ownerIdP,
 			int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
 			Oid *dbLastSysOidP,
 			TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
@@ -1007,7 +1005,7 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
 		/* oid of the database */
 		if (dbIdP)
 			*dbIdP = HeapTupleGetOid(tuple);
-		/* sysid of the owner */
+		/* oid of the owner */
 		if (ownerIdP)
 			*ownerIdP = dbform->datdba;
 		/* character encoding */
@@ -1046,12 +1044,12 @@ have_createdb_privilege(void)
 	bool		result = false;
 	HeapTuple	utup;
 
-	utup = SearchSysCache(SHADOWSYSID,
-						  Int32GetDatum(GetUserId()),
+	utup = SearchSysCache(AUTHOID,
+						  ObjectIdGetDatum(GetUserId()),
 						  0, 0, 0);
 	if (HeapTupleIsValid(utup))
 	{
-		result = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb;
+		result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb;
 		ReleaseSysCache(utup);
 	}
 	return result;
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index ea3c381183713a8745a50cbe0567dbd0f32f46e1..3329822fe623e6a8df678a264d0f86c07d1fc62e 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.61 2005/04/14 20:03:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.62 2005/06/28 05:08:53 tgl Exp $
  *
  * DESCRIPTION
  *	  These routines take the parse tree and pick out the
@@ -853,7 +853,7 @@ RenameFunction(List *name, List *argtypes, const char *newname)
  * Change function owner
  */
 void
-AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId)
+AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
 {
 	Oid			procOid;
 	HeapTuple	tup;
@@ -882,7 +882,7 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId)
 	 * If the new owner is the same as the existing owner, consider the
 	 * command to have succeeded.  This is for dump restoration purposes.
 	 */
-	if (procForm->proowner != newOwnerSysId)
+	if (procForm->proowner != newOwnerId)
 	{
 		Datum		repl_val[Natts_pg_proc];
 		char		repl_null[Natts_pg_proc];
@@ -902,7 +902,7 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId)
 		memset(repl_repl, ' ', sizeof(repl_repl));
 
 		repl_repl[Anum_pg_proc_proowner - 1] = 'r';
-		repl_val[Anum_pg_proc_proowner - 1] = Int32GetDatum(newOwnerSysId);
+		repl_val[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(newOwnerId);
 
 		/*
 		 * Determine the modified ACL for the new owner.  This is only
@@ -914,7 +914,7 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId)
 		if (!isNull)
 		{
 			newAcl = aclnewowner(DatumGetAclP(aclDatum),
-								 procForm->proowner, newOwnerSysId);
+								 procForm->proowner, newOwnerId);
 			repl_repl[Anum_pg_proc_proacl - 1] = 'r';
 			repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl);
 		}
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index e64924c43a7385b31fc54fcd9e6c368d4bc7f9f9..3610269644a47eebede50bff8072a749b7194771 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.32 2005/04/14 20:03:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.33 2005/06/28 05:08:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -321,7 +321,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
 	namestrcpy(&opcName, opcname);
 	values[i++] = NameGetDatum(&opcName);		/* opcname */
 	values[i++] = ObjectIdGetDatum(namespaceoid);		/* opcnamespace */
-	values[i++] = Int32GetDatum(GetUserId());	/* opcowner */
+	values[i++] = ObjectIdGetDatum(GetUserId());	/* opcowner */
 	values[i++] = ObjectIdGetDatum(typeoid);	/* opcintype */
 	values[i++] = BoolGetDatum(stmt->isDefault);		/* opcdefault */
 	values[i++] = ObjectIdGetDatum(storageoid); /* opckeytype */
@@ -880,7 +880,7 @@ RenameOpClass(List *name, const char *access_method, const char *newname)
  * Change opclass owner
  */
 void
-AlterOpClassOwner(List *name, const char *access_method, AclId newOwnerSysId)
+AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
 {
 	Oid			opcOid;
 	Oid			amOid;
@@ -945,7 +945,7 @@ AlterOpClassOwner(List *name, const char *access_method, AclId newOwnerSysId)
 	 * If the new owner is the same as the existing owner, consider the
 	 * command to have succeeded.  This is for dump restoration purposes.
 	 */
-	if (opcForm->opcowner != newOwnerSysId)
+	if (opcForm->opcowner != newOwnerId)
 	{
 		/* Otherwise, must be superuser to change object ownership */
 		if (!superuser())
@@ -957,7 +957,7 @@ AlterOpClassOwner(List *name, const char *access_method, AclId newOwnerSysId)
 		 * Modify the owner --- okay to scribble on tup because it's a
 		 * copy
 		 */
-		opcForm->opcowner = newOwnerSysId;
+		opcForm->opcowner = newOwnerId;
 
 		simple_heap_update(rel, &tup->t_self, tup);
 
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 45dc1eafeaa427a58f7f60b89a0e2cc53cf3baf4..adea1b2b5d737a41694b1ecb1c7ca9e60304bfb2 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.21 2005/04/14 20:03:24 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.22 2005/06/28 05:08:54 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -269,7 +269,7 @@ RemoveOperatorById(Oid operOid)
  */
 void
 AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
-				   AclId newOwnerSysId)
+				   Oid newOwnerId)
 {
 	Oid			operOid;
 	HeapTuple	tup;
@@ -293,7 +293,7 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
 	 * If the new owner is the same as the existing owner, consider the
 	 * command to have succeeded.  This is for dump restoration purposes.
 	 */
-	if (oprForm->oprowner != newOwnerSysId)
+	if (oprForm->oprowner != newOwnerId)
 	{
 		/* Otherwise, must be superuser to change object ownership */
 		if (!superuser())
@@ -305,7 +305,7 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
 		 * Modify the owner --- okay to scribble on tup because it's a
 		 * copy
 		 */
-		oprForm->oprowner = newOwnerSysId;
+		oprForm->oprowner = newOwnerId;
 
 		simple_heap_update(rel, &tup->t_self, tup);
 
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 5754c1dfcb4f8da5d3d0baf87d9908b89d15c8cf..d92812f1fcfc4994a8170795799fc5ffcebd0fb9 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.30 2005/06/21 00:58:15 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.31 2005/06/28 05:08:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,11 +42,11 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
 	Oid			namespaceId;
 	List	   *parsetree_list;
 	ListCell   *parsetree_item;
-	AclId		owner_userid;
-	AclId		saved_userid;
+	Oid		owner_uid;
+	Oid		saved_uid;
 	AclResult	aclresult;
 
-	saved_userid = GetUserId();
+	saved_uid = GetUserId();
 
 	/*
 	 * Figure out user identities.
@@ -54,12 +54,11 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
 
 	if (!authId)
 	{
-		owner_userid = saved_userid;
+		owner_uid = saved_uid;
 	}
 	else if (superuser())
 	{
-		/* The following will error out if user does not exist */
-		owner_userid = get_usesysid(authId);
+		owner_uid = get_roleid_checked(authId);
 
 		/*
 		 * Set the current user to the requested authorization so that
@@ -67,15 +66,15 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
 		 * (This will revert to session user on error or at the end of
 		 * this routine.)
 		 */
-		SetUserId(owner_userid);
+		SetUserId(owner_uid);
 	}
 	else
 	{
 		const char *owner_name;
 
 		/* not superuser */
-		owner_userid = saved_userid;
-		owner_name = GetUserNameFromId(owner_userid);
+		owner_uid = saved_uid;
+		owner_name = GetUserNameFromId(owner_uid);
 		if (strcmp(authId, owner_name) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@@ -87,7 +86,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
 	/*
 	 * Permissions checks.
 	 */
-	aclresult = pg_database_aclcheck(MyDatabaseId, saved_userid, ACL_CREATE);
+	aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_DATABASE,
 					   get_database_name(MyDatabaseId));
@@ -99,7 +98,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
 		errdetail("The prefix \"pg_\" is reserved for system schemas.")));
 
 	/* Create the schema's namespace */
-	namespaceId = NamespaceCreate(schemaName, owner_userid);
+	namespaceId = NamespaceCreate(schemaName, owner_uid);
 
 	/* Advance cmd counter to make the namespace visible */
 	CommandCounterIncrement();
@@ -149,7 +148,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
 	PopSpecialNamespace(namespaceId);
 
 	/* Reset current user */
-	SetUserId(saved_userid);
+	SetUserId(saved_uid);
 }
 
 
@@ -279,7 +278,7 @@ RenameSchema(const char *oldname, const char *newname)
  * Change schema owner
  */
 void
-AlterSchemaOwner(const char *name, AclId newOwnerSysId)
+AlterSchemaOwner(const char *name, Oid newOwnerId)
 {
 	HeapTuple	tup;
 	Relation	rel;
@@ -300,7 +299,7 @@ AlterSchemaOwner(const char *name, AclId newOwnerSysId)
 	 * If the new owner is the same as the existing owner, consider the
 	 * command to have succeeded.  This is for dump restoration purposes.
 	 */
-	if (nspForm->nspowner != newOwnerSysId)
+	if (nspForm->nspowner != newOwnerId)
 	{
 		Datum		repl_val[Natts_pg_namespace];
 		char		repl_null[Natts_pg_namespace];
@@ -320,7 +319,7 @@ AlterSchemaOwner(const char *name, AclId newOwnerSysId)
 		memset(repl_repl, ' ', sizeof(repl_repl));
 
 		repl_repl[Anum_pg_namespace_nspowner - 1] = 'r';
-		repl_val[Anum_pg_namespace_nspowner - 1] = Int32GetDatum(newOwnerSysId);
+		repl_val[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(newOwnerId);
 
 		/*
 		 * Determine the modified ACL for the new owner.  This is only
@@ -332,7 +331,7 @@ AlterSchemaOwner(const char *name, AclId newOwnerSysId)
 		if (!isNull)
 		{
 			newAcl = aclnewowner(DatumGetAclP(aclDatum),
-								 nspForm->nspowner, newOwnerSysId);
+								 nspForm->nspowner, newOwnerId);
 			repl_repl[Anum_pg_namespace_nspacl - 1] = 'r';
 			repl_val[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(newAcl);
 		}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 9981129c0ebf579b7d3441c77aab25e39b30ca4a..dda9532baf857b6721cafcecdc6581f75bd9488c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.161 2005/06/06 20:22:57 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.162 2005/06/28 05:08:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -231,9 +231,9 @@ static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 					  const char *colName, TypeName *typename);
 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab);
 static void ATPostAlterTypeParse(char *cmd, List **wqueue);
-static void ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId);
+static void ATExecChangeOwner(Oid relationOid, Oid newOwnerId);
 static void change_owner_recurse_to_sequences(Oid relationOid,
-											  int32 newOwnerSysId);
+											  Oid newOwnerId);
 static void ATExecClusterOn(Relation rel, const char *indexName);
 static void ATExecDropCluster(Relation rel);
 static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
@@ -2133,8 +2133,8 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd)
 			AlterTableCreateToastTable(RelationGetRelid(rel), false);
 			break;
 		case AT_ChangeOwner:	/* ALTER OWNER */
-			/* get_usesysid raises an error if no such user */
-			ATExecChangeOwner(RelationGetRelid(rel), get_usesysid(cmd->name));
+			ATExecChangeOwner(RelationGetRelid(rel),
+							  get_roleid_checked(cmd->name));
 			break;
 		case AT_ClusterOn:		/* CLUSTER ON */
 			ATExecClusterOn(rel, cmd->name);
@@ -5233,7 +5233,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
  * ALTER TABLE OWNER
  */
 static void
-ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
+ATExecChangeOwner(Oid relationOid, Oid newOwnerId)
 {
 	Relation	target_rel;
 	Relation	class_rel;
@@ -5277,7 +5277,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
 	 * If the new owner is the same as the existing owner, consider the
 	 * command to have succeeded.  This is for dump restoration purposes.
 	 */
-	if (tuple_class->relowner != newOwnerSysId)
+	if (tuple_class->relowner != newOwnerId)
 	{
 		Datum		repl_val[Natts_pg_class];
 		char		repl_null[Natts_pg_class];
@@ -5297,7 +5297,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
 		memset(repl_repl, ' ', sizeof(repl_repl));
 
 		repl_repl[Anum_pg_class_relowner - 1] = 'r';
-		repl_val[Anum_pg_class_relowner - 1] = Int32GetDatum(newOwnerSysId);
+		repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
 
 		/*
 		 * Determine the modified ACL for the new owner.  This is only
@@ -5309,7 +5309,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
 		if (!isNull)
 		{
 			newAcl = aclnewowner(DatumGetAclP(aclDatum),
-								 tuple_class->relowner, newOwnerSysId);
+								 tuple_class->relowner, newOwnerId);
 			repl_repl[Anum_pg_class_relacl - 1] = 'r';
 			repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
 		}
@@ -5337,7 +5337,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
 
 			/* For each index, recursively change its ownership */
 			foreach(i, index_oid_list)
-				ATExecChangeOwner(lfirst_oid(i), newOwnerSysId);
+				ATExecChangeOwner(lfirst_oid(i), newOwnerId);
 
 			list_free(index_oid_list);
 		}
@@ -5346,10 +5346,10 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
 		{
 			/* If it has a toast table, recurse to change its ownership */
 			if (tuple_class->reltoastrelid != InvalidOid)
-				ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerSysId);
+				ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId);
 
 			/* If it has dependent sequences, recurse to change them too */
-			change_owner_recurse_to_sequences(relationOid, newOwnerSysId);
+			change_owner_recurse_to_sequences(relationOid, newOwnerId);
 		}
 	}
 
@@ -5366,7 +5366,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
  * ownership.
  */
 static void
-change_owner_recurse_to_sequences(Oid relationOid, int32 newOwnerSysId)
+change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId)
 {
 	Relation	depRel;
 	SysScanDesc scan;
@@ -5416,7 +5416,7 @@ change_owner_recurse_to_sequences(Oid relationOid, int32 newOwnerSysId)
 		}
 
 		/* We don't need to close the sequence while we alter it. */
-		ATExecChangeOwner(depForm->objid, newOwnerSysId);
+		ATExecChangeOwner(depForm->objid, newOwnerId);
 
 		/* Now we can close it.  Keep the lock till end of transaction. */
 		relation_close(seqRel, NoLock);
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index a469a8fa349ff43bb726eb19625b22aa7964bb9d..15a263b8efd2a7aaad5718979d4b0ce54719e66a 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.22 2005/06/19 21:34:01 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.23 2005/06/28 05:08:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -208,7 +208,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 	Oid			tablespaceoid;
 	char	   *location;
 	char	   *linkloc;
-	AclId		ownerid;
+	Oid		ownerId;
 
 	/* validate */
 
@@ -225,12 +225,9 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 
 	/* However, the eventual owner of the tablespace need not be */
 	if (stmt->owner)
-	{
-		/* No need to check result, get_usesysid() does that */
-		ownerid = get_usesysid(stmt->owner);
-	}
+		ownerId = get_roleid_checked(stmt->owner);
 	else
-		ownerid = GetUserId();
+		ownerId = GetUserId();
 
 	/* Unix-ify the offered path, and strip any trailing slashes */
 	location = pstrdup(stmt->location);
@@ -297,7 +294,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 	values[Anum_pg_tablespace_spcname - 1] =
 		DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename));
 	values[Anum_pg_tablespace_spcowner - 1] =
-		Int32GetDatum(ownerid);
+		ObjectIdGetDatum(ownerId);
 	values[Anum_pg_tablespace_spclocation - 1] =
 		DirectFunctionCall1(textin, CStringGetDatum(location));
 	nulls[Anum_pg_tablespace_spcacl - 1] = 'n';
@@ -426,9 +423,8 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 
 	tablespaceoid = HeapTupleGetOid(tuple);
 
-	/* Must be superuser or owner */
-	if (GetUserId() != ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner &&
-		!superuser())
+	/* Must be tablespace owner */
+	if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
 					   tablespacename);
 
@@ -711,8 +707,8 @@ RenameTableSpace(const char *oldname, const char *newname)
 
 	heap_endscan(scan);
 
-	/* Must be owner or superuser */
-	if (newform->spcowner != GetUserId() && !superuser())
+	/* Must be owner */
+	if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId()))
 		aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname);
 
 	/* Validate new name */
@@ -750,7 +746,7 @@ RenameTableSpace(const char *oldname, const char *newname)
  * Change tablespace owner
  */
 void
-AlterTableSpaceOwner(const char *name, AclId newOwnerSysId)
+AlterTableSpaceOwner(const char *name, Oid newOwnerId)
 {
 	Relation	rel;
 	ScanKeyData entry[1];
@@ -778,7 +774,7 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId)
 	 * If the new owner is the same as the existing owner, consider the
 	 * command to have succeeded.  This is for dump restoration purposes.
 	 */
-	if (spcForm->spcowner != newOwnerSysId)
+	if (spcForm->spcowner != newOwnerId)
 	{
 		Datum		repl_val[Natts_pg_tablespace];
 		char		repl_null[Natts_pg_tablespace];
@@ -798,7 +794,7 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId)
 		memset(repl_repl, ' ', sizeof(repl_repl));
 
 		repl_repl[Anum_pg_tablespace_spcowner - 1] = 'r';
-		repl_val[Anum_pg_tablespace_spcowner - 1] = Int32GetDatum(newOwnerSysId);
+		repl_val[Anum_pg_tablespace_spcowner - 1] = ObjectIdGetDatum(newOwnerId);
 
 		/*
 		 * Determine the modified ACL for the new owner.  This is only
@@ -811,7 +807,7 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId)
 		if (!isNull)
 		{
 			newAcl = aclnewowner(DatumGetAclP(aclDatum),
-								 spcForm->spcowner, newOwnerSysId);
+								 spcForm->spcowner, newOwnerId);
 			repl_repl[Anum_pg_tablespace_spcacl - 1] = 'r';
 			repl_val[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(newAcl);
 		}
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 280022feaa1e45e6902f61123ca5e029e1770187..53570c77409bc13498d80b6e1de73678dc266a92 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.72 2005/05/06 17:24:53 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.73 2005/06/28 05:08:54 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -2016,7 +2016,7 @@ GetDomainConstraints(Oid typeOid)
  * Change the owner of a type.
  */
 void
-AlterTypeOwner(List *names, AclId newOwnerSysId)
+AlterTypeOwner(List *names, Oid newOwnerId)
 {
 	TypeName   *typename;
 	Oid			typeOid;
@@ -2063,7 +2063,7 @@ AlterTypeOwner(List *names, AclId newOwnerSysId)
 	 * If the new owner is the same as the existing owner, consider the
 	 * command to have succeeded.  This is for dump restoration purposes.
 	 */
-	if (typTup->typowner != newOwnerSysId)
+	if (typTup->typowner != newOwnerId)
 	{
 		/* Otherwise, must be superuser to change object ownership */
 		if (!superuser())
@@ -2075,7 +2075,7 @@ AlterTypeOwner(List *names, AclId newOwnerSysId)
 		 * Modify the owner --- okay to scribble on typTup because it's a
 		 * copy
 		 */
-		typTup->typowner = newOwnerSysId;
+		typTup->typowner = newOwnerId;
 
 		simple_heap_update(rel, &tup->t_self, tup);
 
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 3c70c579785e6fb27b905313e6cfe4dd3da2fa77..131f1896f928c563d39e4ddae58693eff2803799 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -1,12 +1,12 @@
 /*-------------------------------------------------------------------------
  *
  * user.c
- *	  Commands for manipulating users and groups.
+ *	  Commands for manipulating roles (formerly called users).
  *
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.151 2005/04/14 20:03:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.152 2005/06/28 05:08:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -14,15 +14,14 @@
 
 #include "access/heapam.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_auth_members.h"
+#include "catalog/pg_authid.h"
 #include "catalog/pg_database.h"
-#include "catalog/pg_group.h"
-#include "catalog/pg_shadow.h"
-#include "catalog/pg_type.h"
 #include "commands/user.h"
 #include "libpq/crypt.h"
 #include "miscadmin.h"
-#include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/catcache.h"
 #include "utils/flatfiles.h"
 #include "utils/fmgroids.h"
 #include "utils/guc.h"
@@ -32,46 +31,46 @@
 
 extern bool Password_encryption;
 
-
-static void CheckPgUserAclNotNull(void);
-static void UpdateGroupMembership(Relation group_rel, HeapTuple group_tuple,
-					  List *members);
-static IdList *IdListToArray(List *members);
-static List *IdArrayToList(IdList *oldarray);
+static List *roleNamesToIds(List *memberNames);
+static void AddRoleMems(const char *rolename, Oid roleid,
+						List *memberNames, List *memberIds,
+						Oid grantorId, bool admin_opt);
+static void DelRoleMems(const char *rolename, Oid roleid,
+						List *memberNames, List *memberIds,
+						bool admin_opt);
 
 
 /*
- * CREATE USER
+ * CREATE ROLE
  */
 void
-CreateUser(CreateUserStmt *stmt)
+CreateRole(CreateRoleStmt *stmt)
 {
-	Relation	pg_shadow_rel;
-	TupleDesc	pg_shadow_dsc;
-	HeapScanDesc scan;
+	Relation	pg_authid_rel;
+	TupleDesc	pg_authid_dsc;
 	HeapTuple	tuple;
-	Datum		new_record[Natts_pg_shadow];
-	char		new_record_nulls[Natts_pg_shadow];
-	bool		user_exists = false,
-				sysid_exists = false,
-				havesysid = false;
-	int			max_id;
+	Datum		new_record[Natts_pg_authid];
+	char		new_record_nulls[Natts_pg_authid];
+	Oid			roleid;
 	ListCell   *item;
 	ListCell   *option;
-	char	   *password = NULL;	/* PostgreSQL user password */
+	char	   *password = NULL;		/* user password */
 	bool		encrypt_password = Password_encryption; /* encrypt password? */
 	char		encrypted_password[MD5_PASSWD_LEN + 1];
-	int			sysid = 0;		/* PgSQL system id (valid if havesysid) */
+	bool		issuper = false;		/* Make the user a superuser? */
+	bool		createrole = false;		/* Can this user create roles? */
 	bool		createdb = false;		/* Can the user create databases? */
-	bool		createuser = false;		/* Can this user create users? */
-	List	   *groupElts = NIL;	/* The groups the user is a member of */
+	bool		canlogin = false;		/* Can this user login? */
+	List	   *roleElts = NIL;			/* roles the user is a member of */
+	List	   *rolememElts = NIL;	/* roles which will be members of this role */
 	char	   *validUntil = NULL;		/* The time the login is valid
 										 * until */
 	DefElem    *dpassword = NULL;
-	DefElem    *dsysid = NULL;
 	DefElem    *dcreatedb = NULL;
-	DefElem    *dcreateuser = NULL;
-	DefElem    *dgroupElts = NULL;
+	DefElem    *dcreaterole = NULL;
+	DefElem    *dcanlogin = NULL;
+	DefElem    *droleElts = NULL;
+	DefElem    *drolememElts = NULL;
 	DefElem    *dvalidUntil = NULL;
 
 	/* Extract options from the statement node tree */
@@ -95,11 +94,16 @@ CreateUser(CreateUserStmt *stmt)
 		}
 		else if (strcmp(defel->defname, "sysid") == 0)
 		{
-			if (dsysid)
+			ereport(WARNING,
+					(errmsg("SYSID can no longer be specified")));
+		}
+		else if (strcmp(defel->defname, "createrole") == 0)
+		{
+			if (dcreaterole)
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 						 errmsg("conflicting or redundant options")));
-			dsysid = defel;
+			dcreaterole = defel;
 		}
 		else if (strcmp(defel->defname, "createdb") == 0)
 		{
@@ -109,21 +113,29 @@ CreateUser(CreateUserStmt *stmt)
 						 errmsg("conflicting or redundant options")));
 			dcreatedb = defel;
 		}
-		else if (strcmp(defel->defname, "createuser") == 0)
+		else if (strcmp(defel->defname, "canlogin") == 0)
 		{
-			if (dcreateuser)
+			if (dcanlogin)
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 						 errmsg("conflicting or redundant options")));
-			dcreateuser = defel;
+			dcanlogin = defel;
 		}
-		else if (strcmp(defel->defname, "groupElts") == 0)
+		else if (strcmp(defel->defname, "roleElts") == 0)
 		{
-			if (dgroupElts)
+			if (droleElts)
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 						 errmsg("conflicting or redundant options")));
-			dgroupElts = defel;
+			droleElts = defel;
+		}
+		else if (strcmp(defel->defname, "rolememElts") == 0)
+		{
+			if (drolememElts)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options")));
+			drolememElts = defel;
 		}
 		else if (strcmp(defel->defname, "validUntil") == 0)
 		{
@@ -140,83 +152,51 @@ CreateUser(CreateUserStmt *stmt)
 
 	if (dcreatedb)
 		createdb = intVal(dcreatedb->arg) != 0;
-	if (dcreateuser)
-		createuser = intVal(dcreateuser->arg) != 0;
-	if (dsysid)
+	if (dcreaterole)
 	{
-		sysid = intVal(dsysid->arg);
-		if (sysid <= 0)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("user ID must be positive")));
-		havesysid = true;
+		createrole = intVal(dcreaterole->arg) != 0;
+		/* XXX issuper is implied by createrole for now */
+		issuper = createrole;
 	}
+	if (dcanlogin)
+		canlogin = intVal(dcanlogin->arg) != 0;
 	if (dvalidUntil)
 		validUntil = strVal(dvalidUntil->arg);
 	if (dpassword)
 		password = strVal(dpassword->arg);
-	if (dgroupElts)
-		groupElts = (List *) dgroupElts->arg;
+	if (droleElts)
+		roleElts = (List *) droleElts->arg;
+	if (drolememElts)
+		rolememElts = (List *) drolememElts->arg;
 
 	/* Check some permissions first */
-	if (password)
-		CheckPgUserAclNotNull();
-
 	if (!superuser())
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to create users")));
+				 errmsg("must be superuser to create roles")));
 
-	if (strcmp(stmt->user, "public") == 0)
+	if (strcmp(stmt->role, "public") == 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_RESERVED_NAME),
-				 errmsg("user name \"%s\" is reserved",
-						stmt->user)));
+				 errmsg("role name \"%s\" is reserved",
+						stmt->role)));
 
 	/*
-	 * Scan the pg_shadow relation to be certain the user or id doesn't
-	 * already exist.  Note we secure exclusive lock, because we also need
-	 * to be sure of what the next usesysid should be, and we need to
-	 * protect our eventual update of the flat password file.
+	 * Check the pg_authid relation to be certain the role doesn't
+	 * already exist.  Note we secure exclusive lock because
+	 * we need to protect our eventual update of the flat auth file.
 	 */
-	pg_shadow_rel = heap_open(ShadowRelationId, ExclusiveLock);
-	pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
-
-	scan = heap_beginscan(pg_shadow_rel, SnapshotNow, 0, NULL);
-	max_id = 99;				/* start auto-assigned ids at 100 */
-	while (!user_exists && !sysid_exists &&
-		   (tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
-	{
-		Form_pg_shadow shadow_form = (Form_pg_shadow) GETSTRUCT(tuple);
-		int32		this_sysid;
-
-		user_exists = (strcmp(NameStr(shadow_form->usename), stmt->user) == 0);
-
-		this_sysid = shadow_form->usesysid;
-		if (havesysid)			/* customized id wanted */
-			sysid_exists = (this_sysid == sysid);
-		else
-		{
-			/* pick 1 + max */
-			if (this_sysid > max_id)
-				max_id = this_sysid;
-		}
-	}
-	heap_endscan(scan);
+	pg_authid_rel = heap_open(AuthIdRelationId, ExclusiveLock);
+	pg_authid_dsc = RelationGetDescr(pg_authid_rel);
 
-	if (user_exists)
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("user \"%s\" already exists",
-						stmt->user)));
-	if (sysid_exists)
+	tuple = SearchSysCache(AUTHNAME,
+						   PointerGetDatum(stmt->role),
+						   0, 0, 0);
+	if (HeapTupleIsValid(tuple))
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("user ID %d is already assigned", sysid)));
-
-	/* If no sysid given, use max existing id + 1 */
-	if (!havesysid)
-		sysid = max_id + 1;
+				 errmsg("role \"%s\" already exists",
+						stmt->role)));
 
 	/*
 	 * Build a tuple to insert
@@ -224,105 +204,123 @@ CreateUser(CreateUserStmt *stmt)
 	MemSet(new_record, 0, sizeof(new_record));
 	MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
 
-	new_record[Anum_pg_shadow_usename - 1] =
-		DirectFunctionCall1(namein, CStringGetDatum(stmt->user));
-	new_record[Anum_pg_shadow_usesysid - 1] = Int32GetDatum(sysid);
-	AssertState(BoolIsValid(createdb));
-	new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb);
-	AssertState(BoolIsValid(createuser));
-	new_record[Anum_pg_shadow_usesuper - 1] = BoolGetDatum(createuser);
-	/* superuser gets catupd right by default */
-	new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(createuser);
+	new_record[Anum_pg_authid_rolname - 1] =
+		DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
+
+	new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
+	new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
+	new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
+	/* superuser gets catupdate right by default */
+	new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
+	new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
 
 	if (password)
 	{
 		if (!encrypt_password || isMD5(password))
-			new_record[Anum_pg_shadow_passwd - 1] =
+			new_record[Anum_pg_authid_rolpassword - 1] =
 				DirectFunctionCall1(textin, CStringGetDatum(password));
 		else
 		{
-			if (!EncryptMD5(password, stmt->user, strlen(stmt->user),
+			if (!EncryptMD5(password, stmt->role, strlen(stmt->role),
 							encrypted_password))
 				elog(ERROR, "password encryption failed");
-			new_record[Anum_pg_shadow_passwd - 1] =
+			new_record[Anum_pg_authid_rolpassword - 1] =
 				DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
 		}
 	}
 	else
-		new_record_nulls[Anum_pg_shadow_passwd - 1] = 'n';
+		new_record_nulls[Anum_pg_authid_rolpassword - 1] = 'n';
 
 	if (validUntil)
-		new_record[Anum_pg_shadow_valuntil - 1] =
-			DirectFunctionCall1(abstimein, CStringGetDatum(validUntil));
+		new_record[Anum_pg_authid_rolvaliduntil - 1] =
+			DirectFunctionCall3(timestamptz_in,
+								CStringGetDatum(validUntil),
+								ObjectIdGetDatum(InvalidOid),
+								Int32GetDatum(-1));
+
 	else
-		new_record_nulls[Anum_pg_shadow_valuntil - 1] = 'n';
+		new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = 'n';
 
-	new_record_nulls[Anum_pg_shadow_useconfig - 1] = 'n';
+	new_record_nulls[Anum_pg_authid_rolconfig - 1] = 'n';
 
-	tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls);
+	tuple = heap_formtuple(pg_authid_dsc, new_record, new_record_nulls);
 
 	/*
-	 * Insert new record in the pg_shadow table
+	 * Insert new record in the pg_authid table
 	 */
-	simple_heap_insert(pg_shadow_rel, tuple);
+	roleid = simple_heap_insert(pg_authid_rel, tuple);
+	Assert(OidIsValid(roleid));
 
 	/* Update indexes */
-	CatalogUpdateIndexes(pg_shadow_rel, tuple);
+	CatalogUpdateIndexes(pg_authid_rel, tuple);
 
 	/*
-	 * Add the user to the groups specified. We'll just call the below
-	 * AlterGroup for this.
+	 * Add the new role to the specified existing roles.
 	 */
-	foreach(item, groupElts)
+	foreach(item, roleElts)
 	{
-		AlterGroupStmt ags;
+		char   *oldrolename = strVal(lfirst(item));
+		Oid		oldroleid = get_roleid_checked(oldrolename);
 
-		ags.name = strVal(lfirst(item));		/* the group name to add
-												 * this in */
-		ags.action = +1;
-		ags.listUsers = list_make1(makeInteger(sysid));
-		AlterGroup(&ags, "CREATE USER");
+		AddRoleMems(oldrolename, oldroleid,
+					list_make1(makeString(stmt->role)),
+					list_make1_oid(roleid),
+					GetUserId(), false);
 	}
 
+	/*
+	 * Add the specified members to this new role.
+	 */
+	AddRoleMems(stmt->role, roleid,
+				rolememElts, roleNamesToIds(rolememElts),
+				GetUserId(), false);
+
 	/*
 	 * Now we can clean up; but keep lock until commit (to avoid possible
 	 * deadlock when commit code tries to acquire lock).
 	 */
-	heap_close(pg_shadow_rel, NoLock);
+	heap_close(pg_authid_rel, NoLock);
 
 	/*
-	 * Set flag to update flat password file at commit.
+	 * Set flag to update flat auth file at commit.
 	 */
-	user_file_update_needed();
+	auth_file_update_needed();
 }
 
 
-
 /*
- * ALTER USER
+ * ALTER ROLE
  */
 void
-AlterUser(AlterUserStmt *stmt)
+AlterRole(AlterRoleStmt *stmt)
 {
-	Datum		new_record[Natts_pg_shadow];
-	char		new_record_nulls[Natts_pg_shadow];
-	char		new_record_repl[Natts_pg_shadow];
-	Relation	pg_shadow_rel;
-	TupleDesc	pg_shadow_dsc;
+	Datum		new_record[Natts_pg_authid];
+	char		new_record_nulls[Natts_pg_authid];
+	char		new_record_repl[Natts_pg_authid];
+	Relation	pg_authid_rel;
+	TupleDesc	pg_authid_dsc;
 	HeapTuple	tuple,
 				new_tuple;
 	ListCell   *option;
-	char	   *password = NULL;	/* PostgreSQL user password */
+	char	   *password = NULL;		/* user password */
 	bool		encrypt_password = Password_encryption; /* encrypt password? */
 	char		encrypted_password[MD5_PASSWD_LEN + 1];
-	int			createdb = -1;	/* Can the user create databases? */
-	int			createuser = -1;	/* Can this user create users? */
+	int			issuper = -1;			/* Make the user a superuser? */
+	int			createrole = -1;		/* Can this user create roles? */
+	int			createdb = -1;			/* Can the user create databases? */
+	int			canlogin = -1;			/* Can this user login? */
+	int			adminopt = 0;	/* Can this user grant this role to others? */
+	List	   *rolememElts = NIL;	/* The roles which will be added/removed to this role */
 	char	   *validUntil = NULL;		/* The time the login is valid
 										 * until */
 	DefElem    *dpassword = NULL;
 	DefElem    *dcreatedb = NULL;
-	DefElem    *dcreateuser = NULL;
+	DefElem    *dcreaterole = NULL;
+	DefElem    *dcanlogin = NULL;
+	DefElem    *dadminopt = NULL;
 	DefElem    *dvalidUntil = NULL;
+	DefElem    *drolememElts = NULL;
+	Oid			roleid;
 
 	/* Extract options from the statement node tree */
 	foreach(option, stmt->options)
@@ -351,13 +349,29 @@ AlterUser(AlterUserStmt *stmt)
 						 errmsg("conflicting or redundant options")));
 			dcreatedb = defel;
 		}
-		else if (strcmp(defel->defname, "createuser") == 0)
+		else if (strcmp(defel->defname, "createrole") == 0)
 		{
-			if (dcreateuser)
+			if (dcreaterole)
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 						 errmsg("conflicting or redundant options")));
-			dcreateuser = defel;
+			dcreaterole = defel;
+		}
+		else if (strcmp(defel->defname, "canlogin") == 0)
+		{
+			if (dcanlogin)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options")));
+			dcanlogin = defel;
+		}
+		else if (strcmp(defel->defname, "adminopt") == 0)
+		{
+			if (dadminopt)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options")));
+			dadminopt = defel;
 		}
 		else if (strcmp(defel->defname, "validUntil") == 0)
 		{
@@ -367,6 +381,14 @@ AlterUser(AlterUserStmt *stmt)
 						 errmsg("conflicting or redundant options")));
 			dvalidUntil = defel;
 		}
+		else if (strcmp(defel->defname, "rolememElts") == 0 && stmt->action != 0)
+		{
+			if (drolememElts)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options")));
+			drolememElts = defel;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -374,42 +396,54 @@ AlterUser(AlterUserStmt *stmt)
 
 	if (dcreatedb)
 		createdb = intVal(dcreatedb->arg);
-	if (dcreateuser)
-		createuser = intVal(dcreateuser->arg);
+	if (dcreaterole)
+	{
+		createrole = intVal(dcreaterole->arg);
+		/* XXX createrole implies issuper for now */
+		issuper = createrole;
+	}
+	if (dcanlogin)
+		canlogin = intVal(dcanlogin->arg);
+	if (dadminopt)
+		adminopt = intVal(dadminopt->arg);
 	if (dvalidUntil)
 		validUntil = strVal(dvalidUntil->arg);
 	if (dpassword)
 		password = strVal(dpassword->arg);
-
-	if (password)
-		CheckPgUserAclNotNull();
+	if (drolememElts)
+		rolememElts = (List *) drolememElts->arg;
 
 	/* must be superuser or just want to change your own password */
 	if (!superuser() &&
-		!(createdb < 0 &&
-		  createuser < 0 &&
+		!(issuper < 0 &&
+		  createrole < 0 &&
+		  createdb < 0 &&
+		  canlogin < 0 &&
 		  !validUntil &&
+		  !rolememElts &&
+		  !adminopt &&
 		  password &&
-		  strcmp(GetUserNameFromId(GetUserId()), stmt->user) == 0))
+		  strcmp(GetUserNameFromId(GetUserId()), stmt->role) == 0))
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("permission denied")));
 
 	/*
-	 * Scan the pg_shadow relation to be certain the user exists. Note we
-	 * secure exclusive lock to protect our update of the flat password
-	 * file.
+	 * Scan the pg_authid relation to be certain the user exists. Note we
+	 * secure exclusive lock to protect our update of the flat auth file.
 	 */
-	pg_shadow_rel = heap_open(ShadowRelationId, ExclusiveLock);
-	pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
+	pg_authid_rel = heap_open(AuthIdRelationId, ExclusiveLock);
+	pg_authid_dsc = RelationGetDescr(pg_authid_rel);
 
-	tuple = SearchSysCache(SHADOWNAME,
-						   PointerGetDatum(stmt->user),
+	tuple = SearchSysCache(AUTHNAME,
+						   PointerGetDatum(stmt->role),
 						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("user \"%s\" does not exist", stmt->user)));
+				 errmsg("role \"%s\" does not exist", stmt->role)));
+
+	roleid = HeapTupleGetOid(tuple);
 
 	/*
 	 * Build an updated tuple, perusing the information just obtained
@@ -418,65 +452,79 @@ AlterUser(AlterUserStmt *stmt)
 	MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
 	MemSet(new_record_repl, ' ', sizeof(new_record_repl));
 
-	new_record[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein,
-											CStringGetDatum(stmt->user));
-	new_record_repl[Anum_pg_shadow_usename - 1] = 'r';
-
-	/* createdb */
-	if (createdb >= 0)
-	{
-		new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb > 0);
-		new_record_repl[Anum_pg_shadow_usecreatedb - 1] = 'r';
-	}
+	new_record[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
+											CStringGetDatum(stmt->role));
+	new_record_repl[Anum_pg_authid_rolname - 1] = 'r';
 
 	/*
-	 * createuser (superuser) and catupd
+	 * issuper/createrole/catupdate/etc
 	 *
-	 * XXX It's rather unclear how to handle catupd.  It's probably best to
+	 * XXX It's rather unclear how to handle catupdate.  It's probably best to
 	 * keep it equal to the superuser status, otherwise you could end up
 	 * with a situation where no existing superuser can alter the
-	 * catalogs, including pg_shadow!
+	 * catalogs, including pg_authid!
 	 */
-	if (createuser >= 0)
+	if (issuper >= 0)
 	{
-		new_record[Anum_pg_shadow_usesuper - 1] = BoolGetDatum(createuser > 0);
-		new_record_repl[Anum_pg_shadow_usesuper - 1] = 'r';
+		new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
+		new_record_repl[Anum_pg_authid_rolsuper - 1] = 'r';
 
-		new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(createuser > 0);
-		new_record_repl[Anum_pg_shadow_usecatupd - 1] = 'r';
+		new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0);
+		new_record_repl[Anum_pg_authid_rolcatupdate - 1] = 'r';
+	}
+
+	if (createrole >= 0)
+	{
+		new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
+		new_record_repl[Anum_pg_authid_rolcreaterole - 1] = 'r';
+	}
+
+	if (createdb >= 0)
+	{
+		new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0);
+		new_record_repl[Anum_pg_authid_rolcreatedb - 1] = 'r';
+	}
+
+	if (canlogin >= 0)
+	{
+		new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0);
+		new_record_repl[Anum_pg_authid_rolcanlogin - 1] = 'r';
 	}
 
 	/* password */
 	if (password)
 	{
 		if (!encrypt_password || isMD5(password))
-			new_record[Anum_pg_shadow_passwd - 1] =
+			new_record[Anum_pg_authid_rolpassword - 1] =
 				DirectFunctionCall1(textin, CStringGetDatum(password));
 		else
 		{
-			if (!EncryptMD5(password, stmt->user, strlen(stmt->user),
+			if (!EncryptMD5(password, stmt->role, strlen(stmt->role),
 							encrypted_password))
 				elog(ERROR, "password encryption failed");
-			new_record[Anum_pg_shadow_passwd - 1] =
+			new_record[Anum_pg_authid_rolpassword - 1] =
 				DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
 		}
-		new_record_repl[Anum_pg_shadow_passwd - 1] = 'r';
+		new_record_repl[Anum_pg_authid_rolpassword - 1] = 'r';
 	}
 
 	/* valid until */
 	if (validUntil)
 	{
-		new_record[Anum_pg_shadow_valuntil - 1] =
-			DirectFunctionCall1(abstimein, CStringGetDatum(validUntil));
-		new_record_repl[Anum_pg_shadow_valuntil - 1] = 'r';
+		new_record[Anum_pg_authid_rolvaliduntil - 1] =
+			DirectFunctionCall3(timestamptz_in,
+								CStringGetDatum(validUntil),
+								ObjectIdGetDatum(InvalidOid),
+								Int32GetDatum(-1));
+		new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = 'r';
 	}
 
-	new_tuple = heap_modifytuple(tuple, pg_shadow_dsc, new_record,
+	new_tuple = heap_modifytuple(tuple, pg_authid_dsc, new_record,
 								 new_record_nulls, new_record_repl);
-	simple_heap_update(pg_shadow_rel, &tuple->t_self, new_tuple);
+	simple_heap_update(pg_authid_rel, &tuple->t_self, new_tuple);
 
 	/* Update indexes */
-	CatalogUpdateIndexes(pg_shadow_rel, new_tuple);
+	CatalogUpdateIndexes(pg_authid_rel, new_tuple);
 
 	ReleaseSysCache(tuple);
 	heap_freetuple(new_tuple);
@@ -485,59 +533,68 @@ AlterUser(AlterUserStmt *stmt)
 	 * Now we can clean up; but keep lock until commit (to avoid possible
 	 * deadlock when commit code tries to acquire lock).
 	 */
-	heap_close(pg_shadow_rel, NoLock);
+	heap_close(pg_authid_rel, NoLock);
+
+	if (stmt->action == +1)		/* add members to role */
+		AddRoleMems(stmt->role, roleid,
+					rolememElts, roleNamesToIds(rolememElts),
+					GetUserId(), adminopt);
+	else if (stmt->action == -1)	/* drop members from role */
+		DelRoleMems(stmt->role, roleid,
+					rolememElts, roleNamesToIds(rolememElts),
+					adminopt);
 
 	/*
-	 * Set flag to update flat password file at commit.
+	 * Set flag to update flat auth file at commit.
 	 */
-	user_file_update_needed();
+	auth_file_update_needed();
 }
 
 
 /*
- * ALTER USER ... SET
+ * ALTER ROLE ... SET
  */
 void
-AlterUserSet(AlterUserSetStmt *stmt)
+AlterRoleSet(AlterRoleSetStmt *stmt)
 {
 	char	   *valuestr;
 	HeapTuple	oldtuple,
 				newtuple;
 	Relation	rel;
-	Datum		repl_val[Natts_pg_shadow];
-	char		repl_null[Natts_pg_shadow];
-	char		repl_repl[Natts_pg_shadow];
+	Datum		repl_val[Natts_pg_authid];
+	char		repl_null[Natts_pg_authid];
+	char		repl_repl[Natts_pg_authid];
 	int			i;
 
 	valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
 
 	/*
 	 * RowExclusiveLock is sufficient, because we don't need to update the
-	 * flat password file.
+	 * flat auth file.
 	 */
-	rel = heap_open(ShadowRelationId, RowExclusiveLock);
-	oldtuple = SearchSysCache(SHADOWNAME,
-							  PointerGetDatum(stmt->user),
+	rel = heap_open(AuthIdRelationId, RowExclusiveLock);
+	oldtuple = SearchSysCache(AUTHNAME,
+							  PointerGetDatum(stmt->role),
 							  0, 0, 0);
 	if (!HeapTupleIsValid(oldtuple))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("user \"%s\" does not exist", stmt->user)));
+				 errmsg("role \"%s\" does not exist", stmt->role)));
 
 	if (!(superuser() ||
-		((Form_pg_shadow) GETSTRUCT(oldtuple))->usesysid == GetUserId()))
+		(HeapTupleGetOid(oldtuple) == GetUserId())))
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("permission denied")));
 
-	for (i = 0; i < Natts_pg_shadow; i++)
+	for (i = 0; i < Natts_pg_authid; i++)
 		repl_repl[i] = ' ';
 
-	repl_repl[Anum_pg_shadow_useconfig - 1] = 'r';
+	repl_repl[Anum_pg_authid_rolconfig - 1] = 'r';
 	if (strcmp(stmt->variable, "all") == 0 && valuestr == NULL)
 	{
 		/* RESET ALL */
-		repl_null[Anum_pg_shadow_useconfig - 1] = 'n';
+		repl_null[Anum_pg_authid_rolconfig - 1] = 'n';
 	}
 	else
 	{
@@ -545,10 +602,10 @@ AlterUserSet(AlterUserSetStmt *stmt)
 		bool		isnull;
 		ArrayType  *array;
 
-		repl_null[Anum_pg_shadow_useconfig - 1] = ' ';
+		repl_null[Anum_pg_authid_rolconfig - 1] = ' ';
 
-		datum = SysCacheGetAttr(SHADOWNAME, oldtuple,
-								Anum_pg_shadow_useconfig, &isnull);
+		datum = SysCacheGetAttr(AUTHNAME, oldtuple,
+								Anum_pg_authid_rolconfig, &isnull);
 
 		array = isnull ? NULL : DatumGetArrayTypeP(datum);
 
@@ -558,9 +615,9 @@ AlterUserSet(AlterUserSetStmt *stmt)
 			array = GUCArrayDelete(array, stmt->variable);
 
 		if (array)
-			repl_val[Anum_pg_shadow_useconfig - 1] = PointerGetDatum(array);
+			repl_val[Anum_pg_authid_rolconfig - 1] = PointerGetDatum(array);
 		else
-			repl_null[Anum_pg_shadow_useconfig - 1] = 'n';
+			repl_null[Anum_pg_authid_rolconfig - 1] = 'n';
 	}
 
 	newtuple = heap_modifytuple(oldtuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
@@ -574,60 +631,61 @@ AlterUserSet(AlterUserSetStmt *stmt)
 
 
 /*
- * DROP USER
+ * DROP ROLE
  */
 void
-DropUser(DropUserStmt *stmt)
+DropRole(DropRoleStmt *stmt)
 {
-	Relation	pg_shadow_rel;
-	TupleDesc	pg_shadow_dsc;
+	Relation	pg_authid_rel, pg_auth_members_rel;
 	ListCell   *item;
 
 	if (!superuser())
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to drop users")));
+				 errmsg("must be superuser to drop roles")));
 
 	/*
-	 * Scan the pg_shadow relation to find the usesysid of the user to be
+	 * Scan the pg_authid relation to find the Oid of the role to be
 	 * deleted.  Note we secure exclusive lock, because we need to protect
-	 * our update of the flat password file.
+	 * our update of the flat auth file.
 	 */
-	pg_shadow_rel = heap_open(ShadowRelationId, ExclusiveLock);
-	pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
+	pg_authid_rel = heap_open(AuthIdRelationId, ExclusiveLock);
+	pg_auth_members_rel = heap_open(AuthMemRelationId, ExclusiveLock);
 
-	foreach(item, stmt->users)
+	foreach(item, stmt->roles)
 	{
-		const char *user = strVal(lfirst(item));
+		const char *role = strVal(lfirst(item));
 		HeapTuple	tuple,
 					tmp_tuple;
 		Relation	pg_rel;
 		TupleDesc	pg_dsc;
 		ScanKeyData scankey;
 		HeapScanDesc scan;
-		AclId		usesysid;
+		CatCList	*auth_mem_list;
+		Oid			roleid;
+		int			i;
 
-		tuple = SearchSysCache(SHADOWNAME,
-							   PointerGetDatum(user),
+		tuple = SearchSysCache(AUTHNAME,
+							   PointerGetDatum(role),
 							   0, 0, 0);
 		if (!HeapTupleIsValid(tuple))
 			ereport(ERROR,
 					(errcode(ERRCODE_UNDEFINED_OBJECT),
-					 errmsg("user \"%s\" does not exist", user)));
+					 errmsg("role \"%s\" does not exist", role)));
 
-		usesysid = ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid;
+		roleid = HeapTupleGetOid(tuple);
 
-		if (usesysid == GetUserId())
+		if (roleid == GetUserId())
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_IN_USE),
-					 errmsg("current user cannot be dropped")));
-		if (usesysid == GetSessionUserId())
+					 errmsg("current role cannot be dropped")));
+		if (roleid == GetSessionUserId())
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_IN_USE),
-					 errmsg("session user cannot be dropped")));
+					 errmsg("session role cannot be dropped")));
 
 		/*
-		 * Check if user still owns a database. If so, error out.
+		 * Check if role still owns a database. If so, error out.
 		 *
 		 * (It used to be that this function would drop the database
 		 * automatically. This is not only very dangerous for people that
@@ -639,8 +697,8 @@ DropUser(DropUserStmt *stmt)
 
 		ScanKeyInit(&scankey,
 					Anum_pg_database_datdba,
-					BTEqualStrategyNumber, F_INT4EQ,
-					Int32GetDatum(usesysid));
+					BTEqualStrategyNumber, F_OIDEQ,
+					roleid);
 
 		scan = heap_beginscan(pg_rel, SnapshotNow, 1, &scankey);
 
@@ -651,8 +709,8 @@ DropUser(DropUserStmt *stmt)
 			dbname = NameStr(((Form_pg_database) GETSTRUCT(tmp_tuple))->datname);
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_IN_USE),
-					 errmsg("user \"%s\" cannot be dropped", user),
-				   errdetail("The user owns database \"%s\".", dbname)));
+					 errmsg("role \"%s\" cannot be dropped", role),
+				   errdetail("The role owns database \"%s\".", dbname)));
 		}
 
 		heap_endscan(scan);
@@ -660,66 +718,64 @@ DropUser(DropUserStmt *stmt)
 
 		/*
 		 * Somehow we'd have to check for tables, views, etc. owned by the
-		 * user as well, but those could be spread out over all sorts of
+		 * role as well, but those could be spread out over all sorts of
 		 * databases which we don't have access to (easily).
 		 */
 
 		/*
-		 * Remove the user from the pg_shadow table
+		 * Remove the role from the pg_authid table
 		 */
-		simple_heap_delete(pg_shadow_rel, &tuple->t_self);
+		simple_heap_delete(pg_authid_rel, &tuple->t_self);
 
 		ReleaseSysCache(tuple);
 
 		/*
-		 * Remove user from groups
+		 * Remove role from roles
 		 *
-		 * try calling alter group drop user for every group
+		 * scan pg_auth_members and remove tuples which have 
+		 * roleid == member or roleid == role
 		 */
-		pg_rel = heap_open(GroupRelationId, ExclusiveLock);
-		pg_dsc = RelationGetDescr(pg_rel);
-		scan = heap_beginscan(pg_rel, SnapshotNow, 0, NULL);
-		while ((tmp_tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
-		{
-			AlterGroupStmt ags;
+		auth_mem_list = SearchSysCacheList(AUTHMEMROLEMEM, 1,
+											ObjectIdGetDatum(roleid),
+											0, 0, 0);
 
-			/* the group name from which to try to drop the user: */
-			ags.name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tmp_tuple))->groname));
-			ags.action = -1;
-			ags.listUsers = list_make1(makeInteger(usesysid));
-			AlterGroup(&ags, "DROP USER");
+		for (i = 0; i < auth_mem_list->n_members; i++)
+		{
+			HeapTuple	authmemtup = &auth_mem_list->members[i]->tuple;
+			simple_heap_delete(pg_auth_members_rel, &authmemtup->t_self);
 		}
-		heap_endscan(scan);
-		heap_close(pg_rel, ExclusiveLock);
+		ReleaseSysCacheList(auth_mem_list);
 
-		/*
-		 * Advance command counter so that later iterations of this loop
-		 * will see the changes already made.  This is essential if, for
-		 * example, we are trying to drop two users who are members of the
-		 * same group --- the AlterGroup for the second user had better
-		 * see the tuple updated from the first one.
-		 */
-		CommandCounterIncrement();
+		auth_mem_list = SearchSysCacheList(AUTHMEMMEMROLE, 1,
+											ObjectIdGetDatum(roleid),
+											0, 0, 0);
+
+		for (i = 0; i < auth_mem_list->n_members; i++)
+		{
+			HeapTuple	authmemtup = &auth_mem_list->members[i]->tuple;
+			simple_heap_delete(pg_auth_members_rel, &authmemtup->t_self);
+		}
+		ReleaseSysCacheList(auth_mem_list);
 	}
 
 	/*
 	 * Now we can clean up; but keep lock until commit (to avoid possible
 	 * deadlock when commit code tries to acquire lock).
 	 */
-	heap_close(pg_shadow_rel, NoLock);
+	heap_close(pg_auth_members_rel, NoLock);
+	heap_close(pg_authid_rel, NoLock);
 
 	/*
-	 * Set flag to update flat password file at commit.
+	 * Set flag to update flat auth file at commit.
 	 */
-	user_file_update_needed();
+	auth_file_update_needed();
 }
 
-
 /*
- * Rename user
+ * Rename role
  */
 void
-RenameUser(const char *oldname, const char *newname)
+RenameRole(const char *oldname, const char *newname)
 {
 	HeapTuple	oldtuple,
 				newtuple;
@@ -727,22 +783,23 @@ RenameUser(const char *oldname, const char *newname)
 	Relation	rel;
 	Datum		datum;
 	bool		isnull;
-	Datum		repl_val[Natts_pg_shadow];
-	char		repl_null[Natts_pg_shadow];
-	char		repl_repl[Natts_pg_shadow];
+	Datum		repl_val[Natts_pg_authid];
+	char		repl_null[Natts_pg_authid];
+	char		repl_repl[Natts_pg_authid];
 	int			i;
+	Oid			roleid;
 
 	/* ExclusiveLock because we need to update the password file */
-	rel = heap_open(ShadowRelationId, ExclusiveLock);
+	rel = heap_open(AuthIdRelationId, ExclusiveLock);
 	dsc = RelationGetDescr(rel);
 
-	oldtuple = SearchSysCache(SHADOWNAME,
+	oldtuple = SearchSysCache(AUTHNAME,
 							  CStringGetDatum(oldname),
 							  0, 0, 0);
 	if (!HeapTupleIsValid(oldtuple))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("user \"%s\" does not exist", oldname)));
+				 errmsg("role \"%s\" does not exist", oldname)));
 
 	/*
 	 * XXX Client applications probably store the session user somewhere,
@@ -750,43 +807,46 @@ RenameUser(const char *oldname, const char *newname)
 	 * not be an actual problem besides a little confusion, so think about
 	 * this and decide.
 	 */
-	if (((Form_pg_shadow) GETSTRUCT(oldtuple))->usesysid == GetSessionUserId())
+
+	roleid = HeapTupleGetOid(oldtuple);
+
+	if (roleid == GetSessionUserId())
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("session user may not be renamed")));
+				 errmsg("session role may not be renamed")));
 
 	/* make sure the new name doesn't exist */
-	if (SearchSysCacheExists(SHADOWNAME,
+	if (SearchSysCacheExists(AUTHNAME,
 							 CStringGetDatum(newname),
 							 0, 0, 0))
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("user \"%s\" already exists", newname)));
+				 errmsg("role \"%s\" already exists", newname)));
 
 	/* must be superuser */
 	if (!superuser())
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to rename users")));
+				 errmsg("must be superuser to rename roles")));
 
-	for (i = 0; i < Natts_pg_shadow; i++)
+	for (i = 0; i < Natts_pg_authid; i++)
 		repl_repl[i] = ' ';
 
-	repl_repl[Anum_pg_shadow_usename - 1] = 'r';
-	repl_val[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein,
+	repl_repl[Anum_pg_authid_rolname - 1] = 'r';
+	repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
 											   CStringGetDatum(newname));
-	repl_null[Anum_pg_shadow_usename - 1] = ' ';
+	repl_null[Anum_pg_authid_rolname - 1] = ' ';
 
-	datum = heap_getattr(oldtuple, Anum_pg_shadow_passwd, dsc, &isnull);
+	datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
 
 	if (!isnull && isMD5(DatumGetCString(DirectFunctionCall1(textout, datum))))
 	{
 		/* MD5 uses the username as salt, so just clear it on a rename */
-		repl_repl[Anum_pg_shadow_passwd - 1] = 'r';
-		repl_null[Anum_pg_shadow_passwd - 1] = 'n';
+		repl_repl[Anum_pg_authid_rolpassword - 1] = 'r';
+		repl_null[Anum_pg_authid_rolpassword - 1] = 'n';
 
 		ereport(NOTICE,
-				(errmsg("MD5 password cleared because of user rename")));
+				(errmsg("MD5 password cleared because of role rename")));
 	}
 
 	newtuple = heap_modifytuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
@@ -797,551 +857,322 @@ RenameUser(const char *oldname, const char *newname)
 	ReleaseSysCache(oldtuple);
 	heap_close(rel, NoLock);
 
-	user_file_update_needed();
+	auth_file_update_needed();
 }
 
-
 /*
- * CheckPgUserAclNotNull
+ * GrantRoleStmt
  *
- * check to see if there is an ACL on pg_shadow
- */
-static void
-CheckPgUserAclNotNull(void)
-{
-	HeapTuple	htup;
-
-	htup = SearchSysCache(RELOID,
-						  ObjectIdGetDatum(ShadowRelationId),
-						  0, 0, 0);
-	if (!HeapTupleIsValid(htup))	/* should not happen, we hope */
-		elog(ERROR, "cache lookup failed for relation %u", ShadowRelationId);
-
-	if (heap_attisnull(htup, Anum_pg_class_relacl))
-	{
-		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(htup);
-
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("before using passwords you must revoke privileges on %s",
-						NameStr(classForm->relname)),
-				 errdetail("This restriction is to prevent unprivileged users from reading the passwords."),
-				 errhint("Try REVOKE ALL ON \"%s\" FROM PUBLIC.",
-						 NameStr(classForm->relname))));
-	}
-
-	ReleaseSysCache(htup);
-}
-
-
-/*
- * CREATE GROUP
+ * Grant/Revoke roles to/from roles
  */
 void
-CreateGroup(CreateGroupStmt *stmt)
+GrantRole(GrantRoleStmt *stmt)
 {
-	Relation	pg_group_rel;
-	HeapScanDesc scan;
-	HeapTuple	tuple;
-	TupleDesc	pg_group_dsc;
-	bool		group_exists = false,
-				sysid_exists = false,
-				havesysid = false;
-	int			max_id;
-	Datum		new_record[Natts_pg_group];
-	char		new_record_nulls[Natts_pg_group];
+	Oid			grantor;
+	List	   *grantee_ids;
 	ListCell   *item;
-	ListCell   *option;
-	List	   *newlist = NIL;
-	IdList	   *grolist;
-	int			sysid = 0;
-	List	   *userElts = NIL;
-	DefElem    *dsysid = NULL;
-	DefElem    *duserElts = NULL;
-
-	foreach(option, stmt->options)
-	{
-		DefElem    *defel = (DefElem *) lfirst(option);
 
-		if (strcmp(defel->defname, "sysid") == 0)
-		{
-			if (dsysid)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
-			dsysid = defel;
-		}
-		else if (strcmp(defel->defname, "userElts") == 0)
-		{
-			if (duserElts)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
-			duserElts = defel;
-		}
-		else
-			elog(ERROR, "option \"%s\" not recognized",
-				 defel->defname);
-	}
-
-	if (dsysid)
-	{
-		sysid = intVal(dsysid->arg);
-		if (sysid <= 0)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("group ID must be positive")));
-		havesysid = true;
-	}
+	if (stmt->grantor)
+		grantor = get_roleid_checked(stmt->grantor);
+	else
+		grantor = GetUserId();
 
-	if (duserElts)
-		userElts = (List *) duserElts->arg;
+	grantee_ids = roleNamesToIds(stmt->grantee_roles);
 
 	/*
-	 * Make sure the user can do this.
-	 */
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to create groups")));
-
-	if (strcmp(stmt->name, "public") == 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_RESERVED_NAME),
-				 errmsg("group name \"%s\" is reserved",
-						stmt->name)));
-
-	/*
-	 * Scan the pg_group relation to be certain the group or id doesn't
-	 * already exist.  Note we secure exclusive lock, because we also need
-	 * to be sure of what the next grosysid should be, and we need to
-	 * protect our eventual update of the flat group file.
+	 * Step through all of the granted roles and add/remove
+	 * entries for the grantees, or, if admin_opt is set, then
+	 * just add/remove the admin option.
+	 *
+	 * Note: Permissions checking is done by AddRoleMems/DelRoleMems
 	 */
-	pg_group_rel = heap_open(GroupRelationId, ExclusiveLock);
-	pg_group_dsc = RelationGetDescr(pg_group_rel);
-
-	scan = heap_beginscan(pg_group_rel, SnapshotNow, 0, NULL);
-	max_id = 99;				/* start auto-assigned ids at 100 */
-	while (!group_exists && !sysid_exists &&
-		   (tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	foreach(item, stmt->granted_roles)
 	{
-		Form_pg_group group_form = (Form_pg_group) GETSTRUCT(tuple);
-		int32		this_sysid;
+		char   *rolename = strVal(lfirst(item));
+		Oid		roleid = get_roleid_checked(rolename);
 
-		group_exists = (strcmp(NameStr(group_form->groname), stmt->name) == 0);
-
-		this_sysid = group_form->grosysid;
-		if (havesysid)			/* customized id wanted */
-			sysid_exists = (this_sysid == sysid);
+		if (stmt->is_grant)
+			AddRoleMems(rolename, roleid,
+						stmt->grantee_roles, grantee_ids,
+						grantor, stmt->admin_opt);
 		else
-		{
-			/* pick 1 + max */
-			if (this_sysid > max_id)
-				max_id = this_sysid;
-		}
+			DelRoleMems(rolename, roleid,
+						stmt->grantee_roles, grantee_ids,
+						stmt->admin_opt);
 	}
-	heap_endscan(scan);
-
-	if (group_exists)
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("group \"%s\" already exists",
-						stmt->name)));
-	if (sysid_exists)
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("group ID %d is already assigned", sysid)));
+}
 
-	/* If no sysid given, use max existing id + 1 */
-	if (!havesysid)
-		sysid = max_id + 1;
+/*
+ * roleNamesToIds
+ *
+ * Given a list of role names (as String nodes), generate a list of role OIDs
+ * in the same order.
+ */
+static List *
+roleNamesToIds(List *memberNames)
+{
+	List	   *result = NIL;
+	ListCell   *l;
 
-	/*
-	 * Translate the given user names to ids
-	 */
-	foreach(item, userElts)
+	foreach(l, memberNames)
 	{
-		const char *groupuser = strVal(lfirst(item));
-		int32		userid = get_usesysid(groupuser);
+		char   *rolename = strVal(lfirst(l));
+		Oid		roleid = get_roleid_checked(rolename);
 
-		if (!list_member_int(newlist, userid))
-			newlist = lappend_int(newlist, userid);
+		result = lappend_oid(result, roleid);
 	}
-
-	/* build an array to insert */
-	if (newlist)
-		grolist = IdListToArray(newlist);
-	else
-		grolist = NULL;
-
-	/*
-	 * Form a tuple to insert
-	 */
-	new_record[Anum_pg_group_groname - 1] =
-		DirectFunctionCall1(namein, CStringGetDatum(stmt->name));
-	new_record[Anum_pg_group_grosysid - 1] = Int32GetDatum(sysid);
-	new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(grolist);
-
-	new_record_nulls[Anum_pg_group_groname - 1] = ' ';
-	new_record_nulls[Anum_pg_group_grosysid - 1] = ' ';
-	new_record_nulls[Anum_pg_group_grolist - 1] = grolist ? ' ' : 'n';
-
-	tuple = heap_formtuple(pg_group_dsc, new_record, new_record_nulls);
-
-	/*
-	 * Insert a new record in the pg_group table
-	 */
-	simple_heap_insert(pg_group_rel, tuple);
-
-	/* Update indexes */
-	CatalogUpdateIndexes(pg_group_rel, tuple);
-
-	/*
-	 * Now we can clean up; but keep lock until commit (to avoid possible
-	 * deadlock when commit code tries to acquire lock).
-	 */
-	heap_close(pg_group_rel, NoLock);
-
-	/*
-	 * Set flag to update flat group file at commit.
-	 */
-	group_file_update_needed();
+	return result;
 }
 
-
 /*
- * ALTER GROUP
+ * AddRoleMems -- Add given members to the specified role
+ *
+ * rolename: name of role to add to (used only for error messages)
+ * roleid: OID of role to add to
+ * memberNames: list of names of roles to add (used only for error messages)
+ * memberIds: OIDs of roles to add
+ * grantorId: who is granting the membership
+ * admin_opt: granting admin option?
  */
-void
-AlterGroup(AlterGroupStmt *stmt, const char *tag)
+static void
+AddRoleMems(const char *rolename, Oid roleid,
+			List *memberNames, List *memberIds,
+			Oid grantorId, bool admin_opt)
 {
-	Relation	pg_group_rel;
-	TupleDesc	pg_group_dsc;
-	HeapTuple	group_tuple;
-	IdList	   *oldarray;
-	Datum		datum;
-	bool		null;
-	List	   *newlist;
-	ListCell   *item;
+	Relation	pg_authmem_rel;
+	TupleDesc	pg_authmem_dsc;
+	ListCell	*nameitem;
+	ListCell	*iditem;
 
-	/*
-	 * Make sure the user can do this.
-	 */
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to alter groups")));
+	Assert(list_length(memberNames) == list_length(memberIds));
 
-	/*
-	 * Secure exclusive lock to protect our update of the flat group file.
-	 */
-	pg_group_rel = heap_open(GroupRelationId, ExclusiveLock);
-	pg_group_dsc = RelationGetDescr(pg_group_rel);
+	/* Skip permission check if nothing to do */
+	if (!memberIds)
+		return;
 
 	/*
-	 * Fetch existing tuple for group.
+	 * Check permissions: must be superuser or have admin option on the
+	 * role to be changed.
+	 *
+	 * XXX: The admin option is not considered to be inherited through
+	 * multiple roles, unlike normal 'is_member_of_role' privilege checks.
 	 */
-	group_tuple = SearchSysCache(GRONAME,
-								 PointerGetDatum(stmt->name),
-								 0, 0, 0);
-	if (!HeapTupleIsValid(group_tuple))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("group \"%s\" does not exist", stmt->name)));
+	if (!superuser()) 
+	{
+		HeapTuple authmem_chk_tuple;
+		Form_pg_auth_members authmem_chk;
 
-	/* Fetch old group membership. */
-	datum = heap_getattr(group_tuple, Anum_pg_group_grolist,
-						 pg_group_dsc, &null);
-	oldarray = null ? NULL : DatumGetIdListP(datum);
+		if (grantorId != GetUserId())
+			ereport(ERROR,
+					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+					 errmsg("must be superuser to set grantor ID")));
+
+		authmem_chk_tuple = SearchSysCache(AUTHMEMROLEMEM,
+										   ObjectIdGetDatum(roleid),
+										   ObjectIdGetDatum(grantorId),
+										   0, 0);
+		if (!HeapTupleIsValid(authmem_chk_tuple))
+			ereport(ERROR,
+					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+					 errmsg("must be superuser or have admin option on role \"%s\"",
+							rolename)));
 
-	/* initialize list with old array contents */
-	newlist = IdArrayToList(oldarray);
+		authmem_chk = (Form_pg_auth_members) GETSTRUCT(authmem_chk_tuple);
+		if (!authmem_chk->admin_option)
+			ereport(ERROR,
+					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+					 errmsg("must be superuser or have admin option on role \"%s\"",
+							rolename)));
+		ReleaseSysCache(authmem_chk_tuple);
+	}
 
 	/*
-	 * Now decide what to do.
+	 * Secure exclusive lock to protect our update of the flat auth file.
 	 */
-	AssertState(stmt->action == +1 || stmt->action == -1);
+	pg_authmem_rel = heap_open(AuthMemRelationId, ExclusiveLock);
+	pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
 
-	if (stmt->action == +1)		/* add users, might also be invoked by
-								 * create user */
+	forboth(nameitem, memberNames, iditem, memberIds)
 	{
+		const char *membername = strVal(lfirst(nameitem));
+		Oid			memberid = lfirst_oid(iditem);
+		HeapTuple	authmem_tuple;
+		HeapTuple	tuple;
+		Datum   new_record[Natts_pg_auth_members];
+		char    new_record_nulls[Natts_pg_auth_members];
+		char    new_record_repl[Natts_pg_auth_members];
+
 		/*
-		 * convert the to be added usernames to sysids and add them to the
-		 * list
+		 * Check if entry for this role/member already exists;
+		 * if so, give warning unless we are adding admin option.
 		 */
-		foreach(item, stmt->listUsers)
+		authmem_tuple = SearchSysCache(AUTHMEMROLEMEM,
+									   ObjectIdGetDatum(roleid),
+									   ObjectIdGetDatum(memberid),
+									   0, 0);
+		if (HeapTupleIsValid(authmem_tuple) && !admin_opt)
 		{
-			int32		sysid;
-
-			if (strcmp(tag, "ALTER GROUP") == 0)
-			{
-				/* Get the uid of the proposed user to add. */
-				sysid = get_usesysid(strVal(lfirst(item)));
-			}
-			else if (strcmp(tag, "CREATE USER") == 0)
-			{
-				/*
-				 * in this case we already know the uid and it wouldn't be
-				 * in the cache anyway yet
-				 */
-				sysid = intVal(lfirst(item));
-			}
-			else
-			{
-				elog(ERROR, "unexpected tag: \"%s\"", tag);
-				sysid = 0;		/* keep compiler quiet */
-			}
-
-			if (!list_member_int(newlist, sysid))
-				newlist = lappend_int(newlist, sysid);
+			ereport(NOTICE,
+					(errmsg("role \"%s\" is already a member of role \"%s\"",
+							membername, rolename)));
+			ReleaseSysCache(authmem_tuple);
+			continue;
 		}
 
-		/* Do the update */
-		UpdateGroupMembership(pg_group_rel, group_tuple, newlist);
-	}							/* endif alter group add user */
+		/* Build a tuple to insert or update */
+		MemSet(new_record, 0, sizeof(new_record));
+		MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
+		MemSet(new_record_repl, ' ', sizeof(new_record_repl));
 
-	else if (stmt->action == -1)	/* drop users from group */
-	{
-		bool		is_dropuser = strcmp(tag, "DROP USER") == 0;
+		new_record[Anum_pg_auth_members_roleid - 1] = ObjectIdGetDatum(roleid);
+		new_record[Anum_pg_auth_members_member - 1] = ObjectIdGetDatum(memberid);
+		new_record[Anum_pg_auth_members_grantor - 1] = ObjectIdGetDatum(grantorId);
+		new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(admin_opt);
 
-		if (newlist == NIL)
+		if (HeapTupleIsValid(authmem_tuple))
 		{
-			if (!is_dropuser)
-				ereport(WARNING,
-						(errcode(ERRCODE_WARNING),
-						 errmsg("group \"%s\" does not have any members",
-								stmt->name)));
+			new_record_repl[Anum_pg_auth_members_grantor - 1] = 'r';
+			new_record_repl[Anum_pg_auth_members_admin_option - 1] = 'r';
+			tuple = heap_modifytuple(authmem_tuple, pg_authmem_dsc,
+									 new_record,
+									 new_record_nulls, new_record_repl);
+			simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);
+			CatalogUpdateIndexes(pg_authmem_rel, tuple);
+			ReleaseSysCache(authmem_tuple);
 		}
 		else
 		{
-			/*
-			 * convert the to be dropped usernames to sysids and remove
-			 * them from the list
-			 */
-			foreach(item, stmt->listUsers)
-			{
-				int32		sysid;
-
-				if (!is_dropuser)
-				{
-					/* Get the uid of the proposed user to drop. */
-					sysid = get_usesysid(strVal(lfirst(item)));
-				}
-				else
-				{
-					/* for dropuser we already know the uid */
-					sysid = intVal(lfirst(item));
-				}
-				if (list_member_int(newlist, sysid))
-					newlist = list_delete_int(newlist, sysid);
-				else if (!is_dropuser)
-					ereport(WARNING,
-							(errcode(ERRCODE_WARNING),
-							 errmsg("user \"%s\" is not in group \"%s\"",
-									strVal(lfirst(item)), stmt->name)));
-			}
-
-			/* Do the update */
-			UpdateGroupMembership(pg_group_rel, group_tuple, newlist);
-		}						/* endif group not null */
-	}							/* endif alter group drop user */
-
-	ReleaseSysCache(group_tuple);
+			tuple = heap_formtuple(pg_authmem_dsc,
+								   new_record, new_record_nulls);
+			simple_heap_insert(pg_authmem_rel, tuple);
+			CatalogUpdateIndexes(pg_authmem_rel, tuple);
+		}
+	}
 
 	/*
 	 * Now we can clean up; but keep lock until commit (to avoid possible
 	 * deadlock when commit code tries to acquire lock).
 	 */
-	heap_close(pg_group_rel, NoLock);
-
-	/*
-	 * Set flag to update flat group file at commit.
-	 */
-	group_file_update_needed();
+	heap_close(pg_authmem_rel, NoLock);
 }
 
 /*
- * Subroutine for AlterGroup: given a pg_group tuple and a desired new
- * membership (expressed as an integer list), form and write an updated tuple.
- * The pg_group relation must be open and locked already.
+ * DelRoleMems -- Remove given members from the specified role
+ *
+ * rolename: name of role to del from (used only for error messages)
+ * roleid: OID of role to del from
+ * memberNames: list of names of roles to del (used only for error messages)
+ * memberIds: OIDs of roles to del
+ * admin_opt: remove admin option only?
  */
 static void
-UpdateGroupMembership(Relation group_rel, HeapTuple group_tuple,
-					  List *members)
+DelRoleMems(const char *rolename, Oid roleid,
+			List *memberNames, List *memberIds,
+			bool admin_opt)
 {
-	IdList	   *newarray;
-	Datum		new_record[Natts_pg_group];
-	char		new_record_nulls[Natts_pg_group];
-	char		new_record_repl[Natts_pg_group];
-	HeapTuple	tuple;
+	Relation	pg_authmem_rel;
+	TupleDesc	pg_authmem_dsc;
+	ListCell	*nameitem;
+	ListCell	*iditem;
 
-	newarray = IdListToArray(members);
+	Assert(list_length(memberNames) == list_length(memberIds));
+
+	/* Skip permission check if nothing to do */
+	if (!memberIds)
+		return;
 
 	/*
-	 * Form an updated tuple with the new array and write it back.
+	 * Check permissions: must be superuser or have admin option on the
+	 * role to be changed.
+	 *
+	 * XXX: The admin option is not considered to be inherited through
+	 * multiple roles, unlike normal 'is_member_of_role' privilege checks.
 	 */
-	MemSet(new_record, 0, sizeof(new_record));
-	MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
-	MemSet(new_record_repl, ' ', sizeof(new_record_repl));
-
-	new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(newarray);
-	new_record_repl[Anum_pg_group_grolist - 1] = 'r';
-
-	tuple = heap_modifytuple(group_tuple, RelationGetDescr(group_rel),
-						  new_record, new_record_nulls, new_record_repl);
-
-	simple_heap_update(group_rel, &group_tuple->t_self, tuple);
-
-	/* Update indexes */
-	CatalogUpdateIndexes(group_rel, tuple);
-}
-
-
-/*
- * Convert an integer list of sysids to an array.
- */
-static IdList *
-IdListToArray(List *members)
-{
-	int			nmembers = list_length(members);
-	IdList	   *newarray;
-	ListCell   *item;
-	int			i;
-
-	newarray = palloc(ARR_OVERHEAD(1) + nmembers * sizeof(int32));
-	newarray->size = ARR_OVERHEAD(1) + nmembers * sizeof(int32);
-	newarray->flags = 0;
-	newarray->elemtype = INT4OID;
-	ARR_NDIM(newarray) = 1;		/* one dimensional array */
-	ARR_LBOUND(newarray)[0] = 1;	/* axis starts at one */
-	ARR_DIMS(newarray)[0] = nmembers;	/* axis is this long */
-	i = 0;
-	foreach(item, members)
-		((int *) ARR_DATA_PTR(newarray))[i++] = lfirst_int(item);
-
-	return newarray;
-}
-
-/*
- * Convert an array of sysids to an integer list.
- */
-static List *
-IdArrayToList(IdList *oldarray)
-{
-	List	   *newlist = NIL;
-	int			hibound,
-				i;
-
-	if (oldarray == NULL)
-		return NIL;
-
-	Assert(ARR_NDIM(oldarray) == 1);
-	Assert(ARR_ELEMTYPE(oldarray) == INT4OID);
-
-	hibound = ARR_DIMS(oldarray)[0];
-
-	for (i = 0; i < hibound; i++)
+	if (!superuser()) 
 	{
-		int32		sysid;
+		HeapTuple authmem_chk_tuple;
+		Form_pg_auth_members authmem_chk;
+
+		authmem_chk_tuple = SearchSysCache(AUTHMEMROLEMEM,
+										   ObjectIdGetDatum(roleid),
+										   ObjectIdGetDatum(GetUserId()),
+										   0, 0);
+		if (!HeapTupleIsValid(authmem_chk_tuple))
+			ereport(ERROR,
+					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+					 errmsg("must be superuser or have admin option on role \"%s\"",
+							rolename)));
 
-		sysid = ((int32 *) ARR_DATA_PTR(oldarray))[i];
-		/* filter out any duplicates --- probably a waste of time */
-		if (!list_member_int(newlist, sysid))
-			newlist = lappend_int(newlist, sysid);
+		authmem_chk = (Form_pg_auth_members) GETSTRUCT(authmem_chk_tuple);
+		if (!authmem_chk->admin_option)
+			ereport(ERROR,
+					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+					 errmsg("must be superuser or have admin option on role \"%s\"",
+							rolename)));
+		ReleaseSysCache(authmem_chk_tuple);
 	}
 
-	return newlist;
-}
-
-
-/*
- * DROP GROUP
- */
-void
-DropGroup(DropGroupStmt *stmt)
-{
-	Relation	pg_group_rel;
-	HeapTuple	tuple;
-
 	/*
-	 * Make sure the user can do this.
+	 * Secure exclusive lock to protect our update of the flat auth file.
 	 */
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to drop groups")));
+	pg_authmem_rel = heap_open(AuthMemRelationId, ExclusiveLock);
+	pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
 
-	/*
-	 * Secure exclusive lock to protect our update of the flat group file.
-	 */
-	pg_group_rel = heap_open(GroupRelationId, ExclusiveLock);
+	forboth(nameitem, memberNames, iditem, memberIds)
+	{
+		const char *membername = strVal(lfirst(nameitem));
+		Oid			memberid = lfirst_oid(iditem);
+		HeapTuple	authmem_tuple;
 
-	/* Find and delete the group. */
+		/*
+		 * Find entry for this role/member
+		 */
+		authmem_tuple = SearchSysCache(AUTHMEMROLEMEM,
+									   ObjectIdGetDatum(roleid),
+									   ObjectIdGetDatum(memberid),
+									   0, 0);
+		if (!HeapTupleIsValid(authmem_tuple))
+		{
+			ereport(WARNING,
+					(errmsg("role \"%s\" is not a member of role \"%s\"",
+							membername, rolename)));
+			continue;
+		}
 
-	tuple = SearchSysCacheCopy(GRONAME,
-							   PointerGetDatum(stmt->name),
-							   0, 0, 0);
-	if (!HeapTupleIsValid(tuple))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("group \"%s\" does not exist", stmt->name)));
+		if (!admin_opt)
+		{
+			/* Remove the entry altogether */
+			simple_heap_delete(pg_authmem_rel, &authmem_tuple->t_self);
+		}
+		else
+		{
+			/* Just turn off the admin option */
+			HeapTuple	tuple;
+			Datum   new_record[Natts_pg_auth_members];
+			char    new_record_nulls[Natts_pg_auth_members];
+			char    new_record_repl[Natts_pg_auth_members];
+
+			/* Build a tuple to update with */
+			MemSet(new_record, 0, sizeof(new_record));
+			MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
+			MemSet(new_record_repl, ' ', sizeof(new_record_repl));
+
+			new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(false);
+			new_record_repl[Anum_pg_auth_members_admin_option - 1] = 'r';
+
+			tuple = heap_modifytuple(authmem_tuple, pg_authmem_dsc,
+									 new_record,
+									 new_record_nulls, new_record_repl);
+			simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);
+			CatalogUpdateIndexes(pg_authmem_rel, tuple);
+		}
 
-	simple_heap_delete(pg_group_rel, &tuple->t_self);
+		ReleaseSysCache(authmem_tuple);
+	}
 
 	/*
 	 * Now we can clean up; but keep lock until commit (to avoid possible
 	 * deadlock when commit code tries to acquire lock).
 	 */
-	heap_close(pg_group_rel, NoLock);
-
-	/*
-	 * Set flag to update flat group file at commit.
-	 */
-	group_file_update_needed();
-}
-
-
-/*
- * Rename group
- */
-void
-RenameGroup(const char *oldname, const char *newname)
-{
-	HeapTuple	tup;
-	Relation	rel;
-
-	/* ExclusiveLock because we need to update the flat group file */
-	rel = heap_open(GroupRelationId, ExclusiveLock);
-
-	tup = SearchSysCacheCopy(GRONAME,
-							 CStringGetDatum(oldname),
-							 0, 0, 0);
-	if (!HeapTupleIsValid(tup))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("group \"%s\" does not exist", oldname)));
-
-	/* make sure the new name doesn't exist */
-	if (SearchSysCacheExists(GRONAME,
-							 CStringGetDatum(newname),
-							 0, 0, 0))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("group \"%s\" already exists", newname)));
-
-	/* must be superuser */
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to rename groups")));
-
-	/* rename */
-	namestrcpy(&(((Form_pg_group) GETSTRUCT(tup))->groname), newname);
-	simple_heap_update(rel, &tup->t_self, tup);
-	CatalogUpdateIndexes(rel, tup);
-
-	heap_close(rel, NoLock);
-	heap_freetuple(tup);
-
-	group_file_update_needed();
+	heap_close(pg_authmem_rel, NoLock);
 }
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 048a3e41562f70b001388389b74fb75ef454c7fb..7df2a92a6c6c32f575c6b3cb877104dc427c072e 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.108 2005/06/09 21:52:07 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.109 2005/06/28 05:08:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,7 +19,7 @@
 #include <ctype.h>
 
 #include "access/xact.h"
-#include "catalog/pg_shadow.h"
+#include "catalog/pg_authid.h"
 #include "commands/variable.h"
 #include "miscadmin.h"
 #include "parser/scansup.h"
@@ -567,46 +567,46 @@ assign_client_encoding(const char *value, bool doit, GucSource source)
  * SET SESSION AUTHORIZATION
  *
  * 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 userid
+ * 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 userid, followed by a comma, followed by the user name.
- * This cannot be confused with a plain user name because of the NAMEDATALEN
+ * 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
- * username or a saved/restored value.
+ * role name or a saved/restored value.
  */
 extern char *session_authorization_string;		/* in guc.c */
 
 const char *
 assign_session_authorization(const char *value, bool doit, GucSource source)
 {
-	AclId		usesysid = 0;
+	Oid		roleid = InvalidOid;
 	bool		is_superuser = false;
-	const char *actual_username = NULL;
+	const char *actual_rolename = NULL;
 	char	   *result;
 
 	if (strspn(value, "x") == NAMEDATALEN &&
 		(value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'))
 	{
 		/* might be a saved userid string */
-		AclId		savedsysid;
+		Oid		savedoid;
 		char	   *endptr;
 
-		savedsysid = (AclId) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
+		savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
 
 		if (endptr != value + NAMEDATALEN + 1 && *endptr == ',')
 		{
 			/* syntactically valid, so break out the data */
-			usesysid = savedsysid;
+			roleid = savedoid;
 			is_superuser = (value[NAMEDATALEN] == 'T');
-			actual_username = endptr + 1;
+			actual_rolename = endptr + 1;
 		}
 	}
 
-	if (usesysid == 0)
+	if (roleid == InvalidOid)
 	{
 		/* not a saved ID, so look it up */
-		HeapTuple	userTup;
+		HeapTuple	roleTup;
 
 		if (!IsTransactionState())
 		{
@@ -618,38 +618,38 @@ assign_session_authorization(const char *value, bool doit, GucSource source)
 			return NULL;
 		}
 
-		userTup = SearchSysCache(SHADOWNAME,
+		roleTup = SearchSysCache(AUTHNAME,
 								 PointerGetDatum(value),
 								 0, 0, 0);
-		if (!HeapTupleIsValid(userTup))
+		if (!HeapTupleIsValid(roleTup))
 		{
 			if (source >= PGC_S_INTERACTIVE)
 				ereport(ERROR,
 						(errcode(ERRCODE_UNDEFINED_OBJECT),
-						 errmsg("user \"%s\" does not exist", value)));
+						 errmsg("role \"%s\" does not exist", value)));
 			return NULL;
 		}
 
-		usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
-		is_superuser = ((Form_pg_shadow) GETSTRUCT(userTup))->usesuper;
-		actual_username = value;
+		roleid = HeapTupleGetOid(roleTup);
+		is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
+		actual_rolename = value;
 
-		ReleaseSysCache(userTup);
+		ReleaseSysCache(roleTup);
 	}
 
 	if (doit)
-		SetSessionAuthorization(usesysid, is_superuser);
+		SetSessionAuthorization(roleid, is_superuser);
 
-	result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_username));
+	result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_rolename));
 	if (!result)
 		return NULL;
 
 	memset(result, 'x', NAMEDATALEN);
 
-	sprintf(result + NAMEDATALEN, "%c%lu,%s",
+	sprintf(result + NAMEDATALEN, "%c%u,%s",
 			is_superuser ? 'T' : 'F',
-			(unsigned long) usesysid,
-			actual_username);
+			roleid,
+			actual_rolename);
 
 	return result;
 }
@@ -662,13 +662,13 @@ show_session_authorization(void)
 	 * assign_session_authorization
 	 */
 	const char *value = session_authorization_string;
-	AclId		savedsysid;
+	Oid		savedoid;
 	char	   *endptr;
 
 	Assert(strspn(value, "x") == NAMEDATALEN &&
 		   (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'));
 
-	savedsysid = (AclId) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
+	savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
 
 	Assert(endptr != value + NAMEDATALEN + 1 && *endptr == ',');
 
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 938474610ae80df3fcb45d2ac22118d6a2248481..3ef33cfd39fc8278fcf20d0512a601014352e1d4 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.250 2005/06/20 18:37:01 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.251 2005/06/28 05:08:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -352,7 +352,7 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
 {
 	AclMode		requiredPerms;
 	Oid			relOid;
-	AclId		userid;
+	Oid		userid;
 
 	/*
 	 * Only plain-relation RTEs need to be checked here.  Subquery RTEs
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 5b5499454b81627774e00b7822adaeeacee94f76..b7a0bc344ffe932208452767be1fe203cabb78b4 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -61,7 +61,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.133 2005/05/06 17:24:53 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.134 2005/06/28 05:08:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1270,7 +1270,7 @@ ExecInitAgg(Agg *node, EState *estate)
 		/* Check that aggregate owner has permission to call component fns */
 		{
 			HeapTuple	procTuple;
-			AclId		aggOwner;
+			Oid		aggOwner;
 
 			procTuple = SearchSysCache(PROCOID,
 									   ObjectIdGetDatum(aggref->aggfnoid),
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index 58e80334f6100afa7bec00a891f799ea8c4f460a..d9c95d1b9ac8567b1da3768e3851464af56a1951 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/libpq/crypt.c,v 1.62 2005/02/20 04:45:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/crypt.c,v 1.63 2005/06/28 05:08:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,7 +29,7 @@
 
 
 int
-md5_crypt_verify(const Port *port, const char *user, char *client_pass)
+md5_crypt_verify(const Port *port, const char *role, char *client_pass)
 {
 	char	   *shadow_pass = NULL,
 			   *valuntil = NULL,
@@ -39,13 +39,11 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass)
 	ListCell   *token;
 	char	   *crypt_client_pass = client_pass;
 
-	if ((line = get_user_line(user)) == NULL)
+	if ((line = get_role_line(role)) == NULL)
 		return STATUS_ERROR;
 
-	/* Skip over username and usesysid */
+	/* Skip over rolename */
 	token = list_head(*line);
-	if (token)
-		token = lnext(token);
 	if (token)
 		token = lnext(token);
 	if (token)
@@ -146,17 +144,28 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass)
 		/*
 		 * Password OK, now check to be sure we are not past valuntil
 		 */
-		AbsoluteTime vuntil;
-
 		if (valuntil == NULL || *valuntil == '\0')
-			vuntil = INVALID_ABSTIME;
-		else
-			vuntil = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
-											 CStringGetDatum(valuntil)));
-		if (vuntil != INVALID_ABSTIME && vuntil < GetCurrentAbsoluteTime())
-			retval = STATUS_ERROR;
-		else
 			retval = STATUS_OK;
+		else
+		{
+			TimestampTz vuntil;
+			AbsoluteTime sec;
+			int			usec;
+			TimestampTz curtime;
+
+			vuntil = DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+								CStringGetDatum(valuntil),
+								ObjectIdGetDatum(InvalidOid),
+								Int32GetDatum(-1)));
+
+			sec = GetCurrentAbsoluteTimeUsec(&usec);
+			curtime = AbsoluteTimeUsecToTimestampTz(sec, usec);
+
+			if (vuntil < curtime)
+				retval = STATUS_ERROR;
+			else
+				retval = STATUS_OK;
+		}
 	}
 
 	if (port->auth_method == uaMD5)
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index ab5d7e41674f9d9370b554966dca53a0dd65a0f3..52608eb45371af4c37b9b46a12b712573500604e 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.142 2005/06/27 02:04:25 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.143 2005/06/28 05:08:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,7 +53,8 @@
 
 /*
  * These variables hold the pre-parsed contents of the hba and ident
- * configuration files.  Each is a list of sublists, one sublist for
+ * configuration files, as well as the flat auth file.
+ * Each is a list of sublists, one sublist for
  * each (non-empty, non-comment) line of the file.	Each sublist's
  * first item is an integer line number (so we can give somewhat-useful
  * location info in error messages).  Remaining items are palloc'd strings,
@@ -69,20 +70,13 @@ static List *hba_line_nums = NIL;
 static List *ident_lines = NIL;
 static List *ident_line_nums = NIL;
 
-/* pre-parsed content of group file and corresponding line #s */
-static List *group_lines = NIL;
-static List *group_line_nums = NIL;
-
-/* pre-parsed content of user passwd file and corresponding line #s */
-static List *user_lines = NIL;
-static List *user_line_nums = NIL;
+/* pre-parsed content of flat auth file and corresponding line #s */
+static List *role_lines = NIL;
+static List *role_line_nums = NIL;
 
 /* sorted entries so we can do binary search lookups */
-static List **user_sorted = NULL;		/* sorted user list, for bsearch() */
-static List **group_sorted = NULL;		/* sorted group list, for
-										 * bsearch() */
-static int	user_length;
-static int	group_length;
+static List **role_sorted = NULL;		/* sorted role list, for bsearch() */
+static int	role_length;
 
 static void tokenize_file(const char *filename, FILE *file,
 						  List **lines, List **line_nums);
@@ -109,7 +103,7 @@ pg_isblank(const char c)
  * return empty string as *buf and position the file to the beginning
  * of the next line or EOF, whichever comes first. Allow spaces in
  * quoted strings. Terminate on unquoted commas. Handle
- * comments. Treat unquoted keywords that might be user names or
+ * comments. Treat unquoted keywords that might be role names or
  * database names specially, by appending a newline to them.
  */
 static void
@@ -199,7 +193,8 @@ next_token(FILE *fp, char *buf, int bufsz)
 	if (!saw_quote &&
 		(strcmp(start_buf, "all") == 0 ||
 		 strcmp(start_buf, "sameuser") == 0 ||
-		 strcmp(start_buf, "samegroup") == 0))
+		 strcmp(start_buf, "samegroup") == 0 ||
+		 strcmp(start_buf, "samerole") == 0))
 	{
 		/* append newline to a magical keyword */
 		*buf++ = '\n';
@@ -434,94 +429,58 @@ tokenize_file(const char *filename, FILE *file,
 	}
 }
 
-
 /*
- * Compare two lines based on their user/group names.
- *
- * Used for qsort() sorting.
- */
-static int
-user_group_qsort_cmp(const void *list1, const void *list2)
-{
-	char	   *user1 = linitial(*(List **) list1);
-	char	   *user2 = linitial(*(List **) list2);
-
-	return strcmp(user1, user2);
-}
-
-
-/*
- * Compare two lines based on their user/group names.
+ * Compare two lines based on their role/member names.
  *
  * Used for bsearch() lookup.
  */
 static int
-user_group_bsearch_cmp(const void *user, const void *list)
+role_bsearch_cmp(const void *role, const void *list)
 {
-	char	   *user2 = linitial(*(List **) list);
+	char	   *role2 = linitial(*(List **) list);
 
-	return strcmp(user, user2);
+	return strcmp(role, role2);
 }
 
 
 /*
- * Lookup a group name in the pg_group file
+ * Lookup a role name in the pg_auth file
  */
-static List **
-get_group_line(const char *group)
+List **
+get_role_line(const char *role)
 {
 	/* On some versions of Solaris, bsearch of zero items dumps core */
-	if (group_length == 0)
+	if (role_length == 0)
 		return NULL;
 
-	return (List **) bsearch((void *) group,
-							 (void *) group_sorted,
-							 group_length,
+	return (List **) bsearch((void *) role,
+							 (void *) role_sorted,
+							 role_length,
 							 sizeof(List *),
-							 user_group_bsearch_cmp);
+							 role_bsearch_cmp);
 }
 
 
 /*
- * Lookup a user name in the pg_shadow file
- */
-List	  **
-get_user_line(const char *user)
-{
-	/* On some versions of Solaris, bsearch of zero items dumps core */
-	if (user_length == 0)
-		return NULL;
-
-	return (List **) bsearch((void *) user,
-							 (void *) user_sorted,
-							 user_length,
-							 sizeof(List *),
-							 user_group_bsearch_cmp);
-}
-
-
-/*
- * Does user belong to group?
+ * Does member belong to role?
  */
 static bool
-check_group(char *group, char *user)
+check_member(const char *role, const char *member)
 {
 	List	  **line;
+	List    **line2;
 	ListCell   *line_item;
-	char	   *usesysid;
 
-	if ((line = get_user_line(user)) == NULL)
-		return false;			/* if user not exist, say "no" */
-	/* Skip over username to get usesysid */
-	usesysid = (char *) lsecond(*line);
+	if ((line = get_role_line(member)) == NULL)
+		return false;			/* if member not exist, say "no" */
 
-	if ((line = get_group_line(group)) == NULL)
-		return false;			/* if group not exist, say "no" */
+	if ((line2 = get_role_line(role)) == NULL)
+		return false;			/* if role not exist, say "no" */
 
-	/* skip over the group name, examine all the member usesysid's */
-	for_each_cell(line_item, lnext(list_head(*line)))
+	/* skip over the role name, password, valuntil, examine all the members */
+	for_each_cell(line_item, lfourth(*line2))
 	{
-		if (strcmp((char *) lfirst(line_item), usesysid) == 0)
+		if (strcmp((char *) lfirst(line_item), member) == 0)
 			return true;
 	}
 
@@ -529,10 +488,10 @@ check_group(char *group, char *user)
 }
 
 /*
- * Check comma user list for a specific user, handle group names.
+ * Check comma member list for a specific role, handle role names.
  */
 static bool
-check_user(char *user, char *param_str)
+check_role(char *role, char *param_str)
 {
 	char	   *tok;
 
@@ -540,10 +499,10 @@ check_user(char *user, char *param_str)
 	{
 		if (tok[0] == '+')
 		{
-			if (check_group(tok + 1, user))
+			if (check_member(tok + 1, role))
 				return true;
 		}
-		else if (strcmp(tok, user) == 0 ||
+		else if (strcmp(tok, role) == 0 ||
 				 strcmp(tok, "all\n") == 0)
 			return true;
 	}
@@ -552,10 +511,10 @@ check_user(char *user, char *param_str)
 }
 
 /*
- * Check to see if db/user combination matches param string.
+ * Check to see if db/role combination matches param string.
  */
 static bool
-check_db(char *dbname, char *user, char *param_str)
+check_db(char *dbname, char *role, char *param_str)
 {
 	char	   *tok;
 
@@ -565,12 +524,13 @@ check_db(char *dbname, char *user, char *param_str)
 			return true;
 		else if (strcmp(tok, "sameuser\n") == 0)
 		{
-			if (strcmp(dbname, user) == 0)
+			if (strcmp(dbname, role) == 0)
 				return true;
 		}
-		else if (strcmp(tok, "samegroup\n") == 0)
+		else if (strcmp(tok, "samegroup\n") == 0 ||
+				 strcmp(tok, "samerole\n") == 0)
 		{
-			if (check_group(dbname, user))
+			if (check_member(dbname, role))
 				return true;
 		}
 		else if (strcmp(tok, dbname) == 0)
@@ -655,7 +615,7 @@ parse_hba(List *line, int line_num, hbaPort *port,
 {
 	char	   *token;
 	char	   *db;
-	char	   *user;
+	char	   *role;
 	struct addrinfo *gai_result;
 	struct addrinfo hints;
 	int			ret;
@@ -675,11 +635,11 @@ parse_hba(List *line, int line_num, hbaPort *port,
 			goto hba_syntax;
 		db = lfirst(line_item);
 
-		/* Get the user. */
+		/* Get the role. */
 		line_item = lnext(line_item);
 		if (!line_item)
 			goto hba_syntax;
-		user = lfirst(line_item);
+		role = lfirst(line_item);
 
 		line_item = lnext(line_item);
 		if (!line_item)
@@ -735,11 +695,11 @@ parse_hba(List *line, int line_num, hbaPort *port,
 			goto hba_syntax;
 		db = lfirst(line_item);
 
-		/* Get the user. */
+		/* Get the role. */
 		line_item = lnext(line_item);
 		if (!line_item)
 			goto hba_syntax;
-		user = lfirst(line_item);
+		role = lfirst(line_item);
 
 		/* Read the IP address field. (with or without CIDR netmask) */
 		line_item = lnext(line_item);
@@ -861,10 +821,10 @@ parse_hba(List *line, int line_num, hbaPort *port,
 	else
 		goto hba_syntax;
 
-	/* Does the entry match database and user? */
+	/* Does the entry match database and role? */
 	if (!check_db(port->database_name, port->user_name, db))
 		return;
-	if (!check_user(port->user_name, user))
+	if (!check_role(port->user_name, role))
 		return;
 
 	/* Success */
@@ -923,27 +883,27 @@ check_hba(hbaPort *port)
 
 
 /*
- *	 Load group/user name mapping file
+ *	 Load role/password mapping file
  */
 void
-load_group(void)
+load_role(void)
 {
 	char	   *filename;
-	FILE	   *group_file;
+	FILE	   *role_file;
 
 	/* Discard any old data */
-	if (group_lines || group_line_nums)
-		free_lines(&group_lines, &group_line_nums);
-	if (group_sorted)
-		pfree(group_sorted);
-	group_sorted = NULL;
-	group_length = 0;
+	if (role_lines || role_line_nums)
+		free_lines(&role_lines, &role_line_nums);
+	if (role_sorted) 
+		pfree(role_sorted);
+	role_sorted = NULL;
+	role_length = 0;
 
 	/* Read in the file contents */
-	filename = group_getflatfilename();
-	group_file = AllocateFile(filename, "r");
+	filename = auth_getflatfilename();
+	role_file = AllocateFile(filename, "r");
 
-	if (group_file == NULL)
+	if (role_file == NULL)
 	{
 		/* no complaint if not there */
 		if (errno != ENOENT)
@@ -954,84 +914,25 @@ load_group(void)
 		return;
 	}
 
-	tokenize_file(filename, group_file, &group_lines, &group_line_nums);
+	tokenize_file(filename, role_file, &role_lines, &role_line_nums);
 
-	FreeFile(group_file);
+	FreeFile(role_file);
 	pfree(filename);
 
-	/* create sorted lines for binary searching */
-	group_length = list_length(group_lines);
-	if (group_length)
+	/* create array for binary searching */
+	role_length = list_length(role_lines);
+	if (role_length)
 	{
-		int			i = 0;
-		ListCell   *line;
+		int		i = 0;
+		ListCell	*line;
 
-		group_sorted = palloc(group_length * sizeof(List *));
-
-		foreach(line, group_lines)
-			group_sorted[i++] = lfirst(line);
-
-		qsort((void *) group_sorted,
-			  group_length,
-			  sizeof(List *),
-			  user_group_qsort_cmp);
-	}
-}
-
-
-/*
- *	 Load user/password mapping file
- */
-void
-load_user(void)
-{
-	char	   *filename;
-	FILE	   *user_file;
-
-	/* Discard any old data */
-	if (user_lines || user_line_nums)
-		free_lines(&user_lines, &user_line_nums);
-	if (user_sorted)
-		pfree(user_sorted);
-	user_sorted = NULL;
-	user_length = 0;
-
-	/* Read in the file contents */
-	filename = user_getflatfilename();
-	user_file = AllocateFile(filename, "r");
-
-	if (user_file == NULL)
-	{
-		/* no complaint if not there */
-		if (errno != ENOENT)
-			ereport(LOG,
-					(errcode_for_file_access(),
-					 errmsg("could not open file \"%s\": %m", filename)));
-		pfree(filename);
-		return;
-	}
-
-	tokenize_file(filename, user_file, &user_lines, &user_line_nums);
-
-	FreeFile(user_file);
-	pfree(filename);
-
-	/* create sorted lines for binary searching */
-	user_length = list_length(user_lines);
-	if (user_length)
-	{
-		int			i = 0;
-		ListCell   *line;
-
-		user_sorted = palloc(user_length * sizeof(List *));
-
-		foreach(line, user_lines)
-			user_sorted[i++] = lfirst(line);
+		role_sorted = palloc(role_length * sizeof(List *));
+		foreach(line, role_lines)
+		{
+			role_sorted[i++] = lfirst(line);
+		}
 
-		qsort((void *) user_sorted,
-			  user_length,
-			  sizeof(List *),
-			  user_group_qsort_cmp);
+		/* We assume the flat file was written already-sorted */
 	}
 }
 
@@ -1108,18 +1009,18 @@ read_pg_database_line(FILE *fp, char *dbname,
 /*
  *	Process one line from the ident config file.
  *
- *	Take the line and compare it to the needed map, pg_user and ident_user.
+ *	Take the line and compare it to the needed map, pg_role and ident_user.
  *	*found_p and *error_p are set according to our results.
  */
 static void
 parse_ident_usermap(List *line, int line_number, const char *usermap_name,
-					const char *pg_user, const char *ident_user,
+					const char *pg_role, const char *ident_user,
 					bool *found_p, bool *error_p)
 {
 	ListCell   *line_item;
 	char	   *token;
 	char	   *file_map;
-	char	   *file_pguser;
+	char	   *file_pgrole;
 	char	   *file_ident_user;
 
 	*found_p = false;
@@ -1139,16 +1040,16 @@ parse_ident_usermap(List *line, int line_number, const char *usermap_name,
 	token = lfirst(line_item);
 	file_ident_user = token;
 
-	/* Get the PG username token */
+	/* Get the PG rolename token */
 	line_item = lnext(line_item);
 	if (!line_item)
 		goto ident_syntax;
 	token = lfirst(line_item);
-	file_pguser = token;
+	file_pgrole = token;
 
 	/* Match? */
 	if (strcmp(file_map, usermap_name) == 0 &&
-		strcmp(file_pguser, pg_user) == 0 &&
+		strcmp(file_pgrole, pg_role) == 0 &&
 		strcmp(file_ident_user, ident_user) == 0)
 		*found_p = true;
 
@@ -1167,17 +1068,17 @@ ident_syntax:
  *	Scan the (pre-parsed) ident usermap file line by line, looking for a match
  *
  *	See if the user with ident username "ident_user" is allowed to act
- *	as Postgres user "pguser" according to usermap "usermap_name".
+ *	as Postgres user "pgrole" according to usermap "usermap_name".
  *
- *	Special case: For usermap "sameuser", don't look in the usermap
- *	file.  That's an implied map where "pguser" must be identical to
+ *	Special case: For usermap "samerole", don't look in the usermap
+ *	file.  That's an implied map where "pgrole" must be identical to
  *	"ident_user" in order to be authorized.
  *
  *	Iff authorized, return true.
  */
 static bool
 check_ident_usermap(const char *usermap_name,
-					const char *pg_user,
+					const char *pg_role,
 					const char *ident_user)
 {
 	bool		found_entry = false,
@@ -1190,9 +1091,10 @@ check_ident_usermap(const char *usermap_name,
 		errmsg("cannot use Ident authentication without usermap field")));
 		found_entry = false;
 	}
-	else if (strcmp(usermap_name, "sameuser\n") == 0)
+	else if (strcmp(usermap_name, "sameuser\n") == 0 ||
+			 strcmp(usermap_name, "samerole\n") == 0)
 	{
-		if (strcmp(pg_user, ident_user) == 0)
+		if (strcmp(pg_role, ident_user) == 0)
 			found_entry = true;
 		else
 			found_entry = false;
@@ -1205,7 +1107,7 @@ check_ident_usermap(const char *usermap_name,
 		forboth(line_cell, ident_lines, num_cell, ident_line_nums)
 		{
 			parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),
-								usermap_name, pg_user, ident_user,
+								usermap_name, pg_role, ident_user,
 								&found_entry, &error);
 			if (found_entry || error)
 				break;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b6885f0d14932b0e74e2aa3a824b44aaf078ed18..ce16d2eba182fec697bfa0b626114839132495cf 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.309 2005/06/26 22:05:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.310 2005/06/28 05:08:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1761,8 +1761,7 @@ _copyPrivGrantee(PrivGrantee *from)
 {
 	PrivGrantee *newnode = makeNode(PrivGrantee);
 
-	COPY_STRING_FIELD(username);
-	COPY_STRING_FIELD(groupname);
+	COPY_STRING_FIELD(rolname);
 
 	return newnode;
 }
@@ -1778,6 +1777,21 @@ _copyFuncWithArgs(FuncWithArgs *from)
 	return newnode;
 }
 
+static GrantRoleStmt *
+_copyGrantRoleStmt(GrantRoleStmt *from)
+{
+	GrantRoleStmt  *newnode = makeNode(GrantRoleStmt);
+
+	COPY_NODE_FIELD(granted_roles);
+	COPY_NODE_FIELD(grantee_roles);
+	COPY_SCALAR_FIELD(is_grant);
+	COPY_SCALAR_FIELD(admin_opt);
+	COPY_STRING_FIELD(grantor);
+	COPY_SCALAR_FIELD(behavior);
+
+	return newnode;
+}
+
 static DeclareCursorStmt *
 _copyDeclareCursorStmt(DeclareCursorStmt *from)
 {
@@ -2374,46 +2388,47 @@ _copyDropPLangStmt(DropPLangStmt *from)
 	return newnode;
 }
 
-static CreateUserStmt *
-_copyCreateUserStmt(CreateUserStmt *from)
+static CreateRoleStmt *
+_copyCreateRoleStmt(CreateRoleStmt *from)
 {
-	CreateUserStmt *newnode = makeNode(CreateUserStmt);
+	CreateRoleStmt *newnode = makeNode(CreateRoleStmt);
 
-	COPY_STRING_FIELD(user);
+	COPY_STRING_FIELD(role);
 	COPY_NODE_FIELD(options);
 
 	return newnode;
 }
 
-static AlterUserStmt *
-_copyAlterUserStmt(AlterUserStmt *from)
+static AlterRoleStmt *
+_copyAlterRoleStmt(AlterRoleStmt *from)
 {
-	AlterUserStmt *newnode = makeNode(AlterUserStmt);
+	AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
 
-	COPY_STRING_FIELD(user);
+	COPY_STRING_FIELD(role);
 	COPY_NODE_FIELD(options);
+	COPY_SCALAR_FIELD(action);
 
 	return newnode;
 }
 
-static AlterUserSetStmt *
-_copyAlterUserSetStmt(AlterUserSetStmt *from)
+static AlterRoleSetStmt *
+_copyAlterRoleSetStmt(AlterRoleSetStmt *from)
 {
-	AlterUserSetStmt *newnode = makeNode(AlterUserSetStmt);
+	AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
 
-	COPY_STRING_FIELD(user);
+	COPY_STRING_FIELD(role);
 	COPY_STRING_FIELD(variable);
 	COPY_NODE_FIELD(value);
 
 	return newnode;
 }
 
-static DropUserStmt *
-_copyDropUserStmt(DropUserStmt *from)
+static DropRoleStmt *
+_copyDropRoleStmt(DropRoleStmt *from)
 {
-	DropUserStmt *newnode = makeNode(DropUserStmt);
+	DropRoleStmt *newnode = makeNode(DropRoleStmt);
 
-	COPY_NODE_FIELD(users);
+	COPY_NODE_FIELD(roles);
 
 	return newnode;
 }
@@ -2441,39 +2456,6 @@ _copyConstraintsSetStmt(ConstraintsSetStmt *from)
 	return newnode;
 }
 
-static CreateGroupStmt *
-_copyCreateGroupStmt(CreateGroupStmt *from)
-{
-	CreateGroupStmt *newnode = makeNode(CreateGroupStmt);
-
-	COPY_STRING_FIELD(name);
-	COPY_NODE_FIELD(options);
-
-	return newnode;
-}
-
-static AlterGroupStmt *
-_copyAlterGroupStmt(AlterGroupStmt *from)
-{
-	AlterGroupStmt *newnode = makeNode(AlterGroupStmt);
-
-	COPY_STRING_FIELD(name);
-	COPY_SCALAR_FIELD(action);
-	COPY_NODE_FIELD(listUsers);
-
-	return newnode;
-}
-
-static DropGroupStmt *
-_copyDropGroupStmt(DropGroupStmt *from)
-{
-	DropGroupStmt *newnode = makeNode(DropGroupStmt);
-
-	COPY_STRING_FIELD(name);
-
-	return newnode;
-}
-
 static ReindexStmt *
 _copyReindexStmt(ReindexStmt *from)
 {
@@ -2927,6 +2909,9 @@ copyObject(void *from)
 		case T_GrantStmt:
 			retval = _copyGrantStmt(from);
 			break;
+		case T_GrantRoleStmt:
+			retval = _copyGrantRoleStmt(from);
+			break;
 		case T_DeclareCursorStmt:
 			retval = _copyDeclareCursorStmt(from);
 			break;
@@ -3071,17 +3056,17 @@ copyObject(void *from)
 		case T_DropPLangStmt:
 			retval = _copyDropPLangStmt(from);
 			break;
-		case T_CreateUserStmt:
-			retval = _copyCreateUserStmt(from);
+		case T_CreateRoleStmt:
+			retval = _copyCreateRoleStmt(from);
 			break;
-		case T_AlterUserStmt:
-			retval = _copyAlterUserStmt(from);
+		case T_AlterRoleStmt:
+			retval = _copyAlterRoleStmt(from);
 			break;
-		case T_AlterUserSetStmt:
-			retval = _copyAlterUserSetStmt(from);
+		case T_AlterRoleSetStmt:
+			retval = _copyAlterRoleSetStmt(from);
 			break;
-		case T_DropUserStmt:
-			retval = _copyDropUserStmt(from);
+		case T_DropRoleStmt:
+			retval = _copyDropRoleStmt(from);
 			break;
 		case T_LockStmt:
 			retval = _copyLockStmt(from);
@@ -3089,15 +3074,6 @@ copyObject(void *from)
 		case T_ConstraintsSetStmt:
 			retval = _copyConstraintsSetStmt(from);
 			break;
-		case T_CreateGroupStmt:
-			retval = _copyCreateGroupStmt(from);
-			break;
-		case T_AlterGroupStmt:
-			retval = _copyAlterGroupStmt(from);
-			break;
-		case T_DropGroupStmt:
-			retval = _copyDropGroupStmt(from);
-			break;
 		case T_ReindexStmt:
 			retval = _copyReindexStmt(from);
 			break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 31a2c302244a20d8394b6e65a4865bdb31b71c9a..ade4f16a090885c880ed1e4ab42479aad84a5701 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.246 2005/06/26 22:05:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.247 2005/06/28 05:08:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -778,8 +778,7 @@ _equalGrantStmt(GrantStmt *a, GrantStmt *b)
 static bool
 _equalPrivGrantee(PrivGrantee *a, PrivGrantee *b)
 {
-	COMPARE_STRING_FIELD(username);
-	COMPARE_STRING_FIELD(groupname);
+	COMPARE_STRING_FIELD(rolname);
 
 	return true;
 }
@@ -793,6 +792,19 @@ _equalFuncWithArgs(FuncWithArgs *a, FuncWithArgs *b)
 	return true;
 }
 
+static bool
+_equalGrantRoleStmt(GrantRoleStmt *a, GrantRoleStmt *b)
+{
+	COMPARE_NODE_FIELD(granted_roles);
+	COMPARE_NODE_FIELD(grantee_roles);
+	COMPARE_SCALAR_FIELD(is_grant);
+	COMPARE_SCALAR_FIELD(admin_opt);
+	COMPARE_STRING_FIELD(grantor);
+	COMPARE_SCALAR_FIELD(behavior);
+
+	return true;
+}
+
 static bool
 _equalDeclareCursorStmt(DeclareCursorStmt *a, DeclareCursorStmt *b)
 {
@@ -1295,27 +1307,28 @@ _equalDropPLangStmt(DropPLangStmt *a, DropPLangStmt *b)
 }
 
 static bool
-_equalCreateUserStmt(CreateUserStmt *a, CreateUserStmt *b)
+_equalCreateRoleStmt(CreateRoleStmt *a, CreateRoleStmt *b)
 {
-	COMPARE_STRING_FIELD(user);
+	COMPARE_STRING_FIELD(role);
 	COMPARE_NODE_FIELD(options);
 
 	return true;
 }
 
 static bool
-_equalAlterUserStmt(AlterUserStmt *a, AlterUserStmt *b)
+_equalAlterRoleStmt(AlterRoleStmt *a, AlterRoleStmt *b)
 {
-	COMPARE_STRING_FIELD(user);
+	COMPARE_STRING_FIELD(role);
 	COMPARE_NODE_FIELD(options);
+	COMPARE_SCALAR_FIELD(action);
 
 	return true;
 }
 
 static bool
-_equalAlterUserSetStmt(AlterUserSetStmt *a, AlterUserSetStmt *b)
+_equalAlterRoleSetStmt(AlterRoleSetStmt *a, AlterRoleSetStmt *b)
 {
-	COMPARE_STRING_FIELD(user);
+	COMPARE_STRING_FIELD(role);
 	COMPARE_STRING_FIELD(variable);
 	COMPARE_NODE_FIELD(value);
 
@@ -1323,9 +1336,9 @@ _equalAlterUserSetStmt(AlterUserSetStmt *a, AlterUserSetStmt *b)
 }
 
 static bool
-_equalDropUserStmt(DropUserStmt *a, DropUserStmt *b)
+_equalDropRoleStmt(DropRoleStmt *a, DropRoleStmt *b)
 {
-	COMPARE_NODE_FIELD(users);
+	COMPARE_NODE_FIELD(roles);
 
 	return true;
 }
@@ -1349,33 +1362,6 @@ _equalConstraintsSetStmt(ConstraintsSetStmt *a, ConstraintsSetStmt *b)
 	return true;
 }
 
-static bool
-_equalCreateGroupStmt(CreateGroupStmt *a, CreateGroupStmt *b)
-{
-	COMPARE_STRING_FIELD(name);
-	COMPARE_NODE_FIELD(options);
-
-	return true;
-}
-
-static bool
-_equalAlterGroupStmt(AlterGroupStmt *a, AlterGroupStmt *b)
-{
-	COMPARE_STRING_FIELD(name);
-	COMPARE_SCALAR_FIELD(action);
-	COMPARE_NODE_FIELD(listUsers);
-
-	return true;
-}
-
-static bool
-_equalDropGroupStmt(DropGroupStmt *a, DropGroupStmt *b)
-{
-	COMPARE_STRING_FIELD(name);
-
-	return true;
-}
-
 static bool
 _equalReindexStmt(ReindexStmt *a, ReindexStmt *b)
 {
@@ -1971,6 +1957,9 @@ equal(void *a, void *b)
 		case T_GrantStmt:
 			retval = _equalGrantStmt(a, b);
 			break;
+		case T_GrantRoleStmt:
+			retval = _equalGrantRoleStmt(a, b);
+			break;
 		case T_DeclareCursorStmt:
 			retval = _equalDeclareCursorStmt(a, b);
 			break;
@@ -2115,17 +2104,17 @@ equal(void *a, void *b)
 		case T_DropPLangStmt:
 			retval = _equalDropPLangStmt(a, b);
 			break;
-		case T_CreateUserStmt:
-			retval = _equalCreateUserStmt(a, b);
+		case T_CreateRoleStmt:
+			retval = _equalCreateRoleStmt(a, b);
 			break;
-		case T_AlterUserStmt:
-			retval = _equalAlterUserStmt(a, b);
+		case T_AlterRoleStmt:
+			retval = _equalAlterRoleStmt(a, b);
 			break;
-		case T_AlterUserSetStmt:
-			retval = _equalAlterUserSetStmt(a, b);
+		case T_AlterRoleSetStmt:
+			retval = _equalAlterRoleSetStmt(a, b);
 			break;
-		case T_DropUserStmt:
-			retval = _equalDropUserStmt(a, b);
+		case T_DropRoleStmt:
+			retval = _equalDropRoleStmt(a, b);
 			break;
 		case T_LockStmt:
 			retval = _equalLockStmt(a, b);
@@ -2133,15 +2122,6 @@ equal(void *a, void *b)
 		case T_ConstraintsSetStmt:
 			retval = _equalConstraintsSetStmt(a, b);
 			break;
-		case T_CreateGroupStmt:
-			retval = _equalCreateGroupStmt(a, b);
-			break;
-		case T_AlterGroupStmt:
-			retval = _equalAlterGroupStmt(a, b);
-			break;
-		case T_DropGroupStmt:
-			retval = _equalDropGroupStmt(a, b);
-			break;
 		case T_ReindexStmt:
 			retval = _equalReindexStmt(a, b);
 			break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 91705123bd7959c8db8f0e8a4950a674c3716972..81fb9c88fa6d2bff3402fff4bc4917e90c7373ce 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.256 2005/06/26 22:05:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.257 2005/06/28 05:08:57 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -1535,7 +1535,7 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
 	WRITE_BOOL_FIELD(inh);
 	WRITE_BOOL_FIELD(inFromCl);
 	WRITE_UINT_FIELD(requiredPerms);
-	WRITE_UINT_FIELD(checkAsUser);
+	WRITE_OID_FIELD(checkAsUser);
 }
 
 static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 9b27dc478ef8c42268104ccc177ad0300c23d7f1..2e9c842051a39e4c92ca38295abeef86d1f19b62 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.179 2005/06/26 22:05:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.180 2005/06/28 05:08:57 tgl Exp $
  *
  * NOTES
  *	  Path and Plan nodes do not have any readfuncs support, because we
@@ -917,7 +917,7 @@ _readRangeTblEntry(void)
 	READ_BOOL_FIELD(inh);
 	READ_BOOL_FIELD(inFromCl);
 	READ_UINT_FIELD(requiredPerms);
-	READ_UINT_FIELD(checkAsUser);
+	READ_OID_FIELD(checkAsUser);
 
 	READ_DONE();
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 28e1ac0264d1642344004743960a6e8f68b09836..d822a7176a72cc9a32af4d9ac1e2cab5564a35b0 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.498 2005/06/26 22:05:38 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.499 2005/06/28 05:08:57 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -133,19 +133,20 @@ static void doNegateFloat(Value *v);
 %type <node>	stmt schema_stmt
 		AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt AlterOwnerStmt
 		AlterSeqStmt AlterTableStmt AlterUserStmt AlterUserSetStmt
+		AlterRoleStmt AlterRoleSetStmt
 		AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
 		ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
 		CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt
 		CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
-		CreateAssertStmt CreateTrigStmt CreateUserStmt
+		CreateAssertStmt CreateTrigStmt CreateUserStmt CreateRoleStmt
 		CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt
 		DropGroupStmt DropOpClassStmt DropPLangStmt DropStmt
-		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt
+		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
 		DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt
-		GrantStmt IndexStmt InsertStmt ListenStmt LoadStmt
+		GrantRoleStmt GrantStmt IndexStmt InsertStmt ListenStmt LoadStmt
 		LockStmt NotifyStmt ExplainableStmt PreparableStmt
 		CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
-		RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt
+		RemoveFuncStmt RemoveOperStmt RenameStmt RevokeRoleStmt RevokeStmt
 		RuleActionStmt RuleActionStmtOrEmpty RuleStmt
 		SelectStmt TransactionStmt TruncateStmt
 		UnlistenStmt UpdateStmt VacuumStmt
@@ -170,17 +171,16 @@ static void doNegateFloat(Value *v);
 %type <ival>	opt_lock lock_type cast_context
 %type <boolean>	opt_force opt_or_replace
 				opt_grant_grant_option opt_revoke_grant_option
+				opt_alter_admin_option 
+				opt_grant_admin_option opt_revoke_admin_option
 				opt_nowait
 
 %type <boolean>	like_including_defaults
 
-%type <list>	user_list
+%type <list>	role_list
 
-%type <list>	OptGroupList
-%type <defelt>	OptGroupElem
-
-%type <list>	OptUserList
-%type <defelt>	OptUserElem
+%type <list>	OptRoleList
+%type <defelt>	OptRoleElem
 
 %type <str>		OptSchemaName
 %type <list>	OptSchemaEltList
@@ -308,7 +308,7 @@ static void doNegateFloat(Value *v);
 
 %type <ival>	Iconst
 %type <str>		Sconst comment_text
-%type <str>		UserId opt_boolean ColId_or_Sconst
+%type <str>		RoleId opt_granted_by opt_boolean ColId_or_Sconst
 %type <list>	var_list var_list_or_default
 %type <str>		ColId ColLabel var_name type_name param_name
 %type <node>	var_value zone_value
@@ -336,7 +336,7 @@ static void doNegateFloat(Value *v);
  */
 
 /* ordinary key words in alphabetical order */
-%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD AFTER
+%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD ADMIN AFTER
 	AGGREGATE ALL ALSO ALTER ANALYSE ANALYZE AND ANY ARRAY AS ASC
 	ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION
 
@@ -347,8 +347,8 @@ static void doNegateFloat(Value *v);
 	CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
 	CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
 	COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB
-	CREATEUSER CROSS CSV CURRENT_DATE CURRENT_TIME
-	CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
+	CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_TIME
+	CURRENT_TIMESTAMP CURRENT_ROLE CURRENT_USER CURSOR CYCLE
 
 	DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
 	DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
@@ -360,7 +360,7 @@ static void doNegateFloat(Value *v);
 	FALSE_P FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
 	FREEZE FROM FULL FUNCTION
 
-	GLOBAL GRANT GREATEST GROUP_P
+	GLOBAL GRANT GRANTED GREATEST GROUP_P
 
 	HANDLER HAVING HEADER HOLD HOUR_P
 
@@ -375,13 +375,13 @@ static void doNegateFloat(Value *v);
 
 	LANCOMPILER LANGUAGE LARGE_P  LAST_P LEADING LEAST LEFT LEVEL
 	LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
-	LOCK_P
+	LOCK_P LOGIN
 
 	MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
 
 	NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
-	NOCREATEUSER NONE NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P
-	NULLIF NUMERIC
+	NOCREATEROLE NOCREATEUSER NONE NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P
+	NULLIF NUMERIC NOLOGIN
 
 	OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR
 	ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNER
@@ -394,10 +394,10 @@ static void doNegateFloat(Value *v);
 
 	READ REAL RECHECK REFERENCES REINDEX RELATIVE_P RELEASE RENAME
 	REPEATABLE REPLACE RESET RESTART RESTRICT RETURNS REVOKE RIGHT
-	ROLLBACK ROW ROWS RULE
+	ROLE ROLLBACK ROW ROWS RULE
 
 	SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
-	SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
+	SERIALIZABLE SESSION SESSION_ROLE SESSION_USER SET SETOF SHARE
 	SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT
 	STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SYMMETRIC
 	SYSID SYSTEM_P
@@ -497,6 +497,8 @@ stmt :
 			| AlterOwnerStmt
 			| AlterSeqStmt
 			| AlterTableStmt
+			| AlterRoleSetStmt
+			| AlterRoleStmt
 			| AlterUserSetStmt
 			| AlterUserStmt
 			| AnalyzeStmt
@@ -520,6 +522,7 @@ stmt :
 			| CreateStmt
 			| CreateTableSpaceStmt
 			| CreateTrigStmt
+			| CreateRoleStmt
 			| CreateUserStmt
 			| CreatedbStmt
 			| DeallocateStmt
@@ -535,11 +538,13 @@ stmt :
 			| DropStmt
 			| DropTableSpaceStmt
 			| DropTrigStmt
+			| DropRoleStmt
 			| DropUserStmt
 			| DropdbStmt
 			| ExecuteStmt
 			| ExplainStmt
 			| FetchStmt
+			| GrantRoleStmt
 			| GrantStmt
 			| IndexStmt
 			| InsertStmt
@@ -553,6 +558,7 @@ stmt :
 			| RemoveFuncStmt
 			| RemoveOperStmt
 			| RenameStmt
+			| RevokeRoleStmt
 			| RevokeStmt
 			| RuleStmt
 			| SelectStmt
@@ -571,16 +577,16 @@ stmt :
 
 /*****************************************************************************
  *
- * Create a new Postgres DBMS user
+ * Create a new Postgres DBMS role
  *
  *
  *****************************************************************************/
 
-CreateUserStmt:
-			CREATE USER UserId opt_with OptUserList
+CreateRoleStmt:
+			CREATE ROLE RoleId opt_with OptRoleList
 				{
-					CreateUserStmt *n = makeNode(CreateUserStmt);
-					n->user = $3;
+					CreateRoleStmt *n = makeNode(CreateRoleStmt);
+					n->role = $3;
 					n->options = $5;
 					$$ = (Node *)n;
 				}
@@ -591,6 +597,80 @@ opt_with:	WITH									{}
 			| /*EMPTY*/								{}
 		;
 
+/*****************************************************************************
+ *
+ * Create a new Postgres DBMS user (role with implied login ability)
+ *
+ *
+ *****************************************************************************/
+
+CreateUserStmt:
+			CREATE USER RoleId opt_with OptRoleList
+				{
+					CreateRoleStmt *n = makeNode(CreateRoleStmt);
+					n->role = $3;
+					n->options = $5;
+					n->options = lappend(n->options,makeDefElem("canlogin", (Node *)makeInteger(TRUE)));
+					$$ = (Node *)n;
+				}
+		;
+
+
+/*****************************************************************************
+ *
+ * Alter a postgresql DBMS role
+ *
+ *
+ *****************************************************************************/
+
+AlterRoleStmt:
+			ALTER ROLE RoleId opt_with OptRoleList
+				 {
+					AlterRoleStmt *n = makeNode(AlterRoleStmt);
+					n->role = $3;
+					n->options = $5;
+					$$ = (Node *)n;
+				 }
+			| ALTER ROLE RoleId add_drop ROLE role_list opt_alter_admin_option
+				{
+					AlterRoleStmt *n = makeNode(AlterRoleStmt);
+					n->role = $3;
+					n->action = $4;
+					n->options = lappend(n->options,makeDefElem("rolememElts", (Node *)$6));
+					n->options = lappend(n->options,makeDefElem("adminopt", (Node *)makeInteger($7)));
+					$$ = (Node *)n;
+				}
+		;
+
+add_drop:	ADD										{ $$ = +1; }
+			| DROP									{ $$ = -1; }
+		;
+
+opt_alter_admin_option:
+			ADMIN OPTION { $$ = TRUE; }
+			| /*EMPTY*/ { $$ = FALSE; }
+		;
+
+AlterRoleSetStmt:
+			ALTER ROLE RoleId SET set_rest
+				{
+					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
+					n->role = $3;
+					n->variable = $5->name;
+					n->value = $5->args;
+					$$ = (Node *)n;
+				}
+			| ALTER ROLE RoleId VariableResetStmt
+				{
+					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
+					n->role = $3;
+					n->variable = ((VariableResetStmt *)$4)->name;
+					n->value = NIL;
+					$$ = (Node *)n;
+				}
+			;
+
+
 /*****************************************************************************
  *
  * Alter a postgresql DBMS user
@@ -599,10 +679,10 @@ opt_with:	WITH									{}
  *****************************************************************************/
 
 AlterUserStmt:
-			ALTER USER UserId opt_with OptUserList
+			ALTER USER RoleId opt_with OptRoleList
 				 {
-					AlterUserStmt *n = makeNode(AlterUserStmt);
-					n->user = $3;
+					AlterRoleStmt *n = makeNode(AlterRoleStmt);
+					n->role = $3;
 					n->options = $5;
 					$$ = (Node *)n;
 				 }
@@ -610,18 +690,18 @@ AlterUserStmt:
 
 
 AlterUserSetStmt:
-			ALTER USER UserId SET set_rest
+			ALTER USER RoleId SET set_rest
 				{
-					AlterUserSetStmt *n = makeNode(AlterUserSetStmt);
-					n->user = $3;
+					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
+					n->role = $3;
 					n->variable = $5->name;
 					n->value = $5->args;
 					$$ = (Node *)n;
 				}
-			| ALTER USER UserId VariableResetStmt
+			| ALTER USER RoleId VariableResetStmt
 				{
-					AlterUserSetStmt *n = makeNode(AlterUserSetStmt);
-					n->user = $3;
+					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
+					n->role = $3;
 					n->variable = ((VariableResetStmt *)$4)->name;
 					n->value = NIL;
 					$$ = (Node *)n;
@@ -629,6 +709,24 @@ AlterUserSetStmt:
 			;
 
 
+/*****************************************************************************
+ *
+ * Drop a postgresql DBMS role
+ *
+ * XXX Ideally this would have CASCADE/RESTRICT options, but since a role
+ * might own objects in multiple databases, there is presently no way to
+ * implement either cascading or restricting.  Caveat DBA.
+ *****************************************************************************/
+
+DropRoleStmt:
+			DROP ROLE role_list
+				{
+					DropRoleStmt *n = makeNode(DropRoleStmt);
+					n->roles = $3;
+					$$ = (Node *)n;
+				}
+			;
+
 /*****************************************************************************
  *
  * Drop a postgresql DBMS user
@@ -639,23 +737,23 @@ AlterUserSetStmt:
  *****************************************************************************/
 
 DropUserStmt:
-			DROP USER user_list
+			DROP USER role_list
 				{
-					DropUserStmt *n = makeNode(DropUserStmt);
-					n->users = $3;
+					DropRoleStmt *n = makeNode(DropRoleStmt);
+					n->roles = $3;
 					$$ = (Node *)n;
 				}
 			;
 
 /*
- * Options for CREATE USER and ALTER USER
+ * Options for CREATE ROLE and ALTER ROLE (also used by CREATE/ALTER USER for backwards compat)
  */
-OptUserList:
-			OptUserList OptUserElem					{ $$ = lappend($1, $2); }
+OptRoleList:
+			OptRoleList OptRoleElem					{ $$ = lappend($1, $2); }
 			| /* EMPTY */							{ $$ = NIL; }
 		;
 
-OptUserElem:
+OptRoleElem:
 			PASSWORD Sconst
 				{
 					$$ = makeDefElem("password", (Node *)makeString($2));
@@ -680,66 +778,75 @@ OptUserElem:
 				{
 					$$ = makeDefElem("createdb", (Node *)makeInteger(FALSE));
 				}
+			| CREATEROLE
+				{
+					$$ = makeDefElem("createrole", (Node *)makeInteger(TRUE));
+				}
 			| CREATEUSER
 				{
-					$$ = makeDefElem("createuser", (Node *)makeInteger(TRUE));
+					$$ = makeDefElem("createrole", (Node *)makeInteger(TRUE));
+				}
+			| LOGIN
+				{
+					$$ = makeDefElem("canlogin", (Node *)makeInteger(TRUE));
+				}
+			| NOCREATEROLE
+				{
+					$$ = makeDefElem("createrole", (Node *)makeInteger(FALSE));
 				}
 			| NOCREATEUSER
 				{
-					$$ = makeDefElem("createuser", (Node *)makeInteger(FALSE));
+					$$ = makeDefElem("createrole", (Node *)makeInteger(FALSE));
 				}
-			| IN_P GROUP_P user_list
+			| NOLOGIN
 				{
-					$$ = makeDefElem("groupElts", (Node *)$3);
+					$$ = makeDefElem("canlogin", (Node *)makeInteger(FALSE));
+				}
+			| IN_P ROLE role_list
+				{
+					$$ = makeDefElem("roleElts", (Node *)$3);
+				}
+			| IN_P GROUP_P role_list
+				{
+					$$ = makeDefElem("roleElts", (Node *)$3);
 				}
 			| VALID UNTIL Sconst
 				{
 					$$ = makeDefElem("validUntil", (Node *)makeString($3));
 				}
+			| ROLE role_list
+				{
+					$$ = makeDefElem("rolememElts", (Node *)$2);
+				}
+			| USER role_list
+				{
+					$$ = makeDefElem("rolememElts", (Node *)$2);
+				}
 		;
 
-user_list:	user_list ',' UserId		{ $$ = lappend($1, makeString($3)); }
-			| UserId					{ $$ = list_make1(makeString($1)); }
+role_list:	role_list ',' RoleId		{ $$ = lappend($1, makeString($3)); }
+			| RoleId					{ $$ = list_make1(makeString($1)); }
 		;
 
 
 
 /*****************************************************************************
  *
- * Create a postgresql group
+ * Create a postgresql group (role without login ability)
  *
  *
  *****************************************************************************/
 
 CreateGroupStmt:
-			CREATE GROUP_P UserId opt_with OptGroupList
+			CREATE GROUP_P RoleId opt_with OptRoleList
 				{
-					CreateGroupStmt *n = makeNode(CreateGroupStmt);
-					n->name = $3;
+					CreateRoleStmt *n = makeNode(CreateRoleStmt);
+					n->role = $3;
 					n->options = $5;
 					$$ = (Node *)n;
 				}
 		;
 
-/*
- * Options for CREATE GROUP
- */
-OptGroupList:
-			OptGroupList OptGroupElem				{ $$ = lappend($1, $2); }
-			| /* EMPTY */							{ $$ = NIL; }
-		;
-
-OptGroupElem:
-			USER user_list
-				{
-					$$ = makeDefElem("userElts", (Node *)$2);
-				}
-			| SYSID Iconst
-				{
-					$$ = makeDefElem("sysid", (Node *)makeInteger($2));
-				}
-		;
-
 
 /*****************************************************************************
  *
@@ -749,20 +856,16 @@ OptGroupElem:
  *****************************************************************************/
 
 AlterGroupStmt:
-			ALTER GROUP_P UserId add_drop USER user_list
+			ALTER GROUP_P RoleId add_drop USER role_list
 				{
-					AlterGroupStmt *n = makeNode(AlterGroupStmt);
-					n->name = $3;
+					AlterRoleStmt *n = makeNode(AlterRoleStmt);
+					n->role = $3;
 					n->action = $4;
-					n->listUsers = $6;
+					n->options = lappend(n->options,makeDefElem("rolememElts", (Node *)$6));
 					$$ = (Node *)n;
 				}
 		;
 
-add_drop:	ADD										{ $$ = +1; }
-			| DROP									{ $$ = -1; }
-		;
-
 
 /*****************************************************************************
  *
@@ -772,10 +875,10 @@ add_drop:	ADD										{ $$ = +1; }
  *****************************************************************************/
 
 DropGroupStmt:
-			DROP GROUP_P UserId
+			DROP GROUP_P role_list
 				{
-					DropGroupStmt *n = makeNode(DropGroupStmt);
-					n->name = $3;
+					DropRoleStmt *n = makeNode(DropRoleStmt);
+					n->roles = $3;
 					$$ = (Node *)n;
 				}
 		;
@@ -788,7 +891,7 @@ DropGroupStmt:
  *****************************************************************************/
 
 CreateSchemaStmt:
-			CREATE SCHEMA OptSchemaName AUTHORIZATION UserId OptSchemaEltList
+			CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
 				{
 					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
 					/* One can omit the schema name or the authorization id. */
@@ -1307,8 +1410,8 @@ alter_rel_cmds:
 
 /* Subcommands that are for ALTER TABLE or ALTER INDEX */
 alter_rel_cmd:
-			/* ALTER [TABLE|INDEX] <name> OWNER TO UserId */
-			OWNER TO UserId
+			/* ALTER [TABLE|INDEX] <name> OWNER TO RoleId */
+			OWNER TO RoleId
 				{
 					AlterTableCmd *n = makeNode(AlterTableCmd);
 					n->subtype = AT_ChangeOwner;
@@ -3013,6 +3116,36 @@ from_in:	FROM									{}
 		;
 
 
+/*****************************************************************************
+ *
+ * GRANT and REVOKE ROLE statements
+ *
+ *****************************************************************************/
+
+GrantRoleStmt:	GRANT ROLE role_list TO role_list opt_grant_admin_option
+			opt_granted_by
+				{
+					GrantRoleStmt *n = makeNode(GrantRoleStmt);
+					n->granted_roles = $3;
+					n->grantee_roles = $5;
+					n->is_grant = true;
+					n->admin_opt = $6;
+					n->grantor = $7;
+					$$ = (Node*)n;
+				}
+
+RevokeRoleStmt:	REVOKE ROLE opt_revoke_admin_option role_list FROM role_list
+			opt_drop_behavior
+				{
+					GrantRoleStmt *n = makeNode(GrantRoleStmt);
+					n->granted_roles = $4;
+					n->grantee_roles = $6;
+					n->is_grant = false;
+					n->admin_opt = $3;
+					n->behavior = $7;
+					$$ = (Node*)n;
+				}
+
 /*****************************************************************************
  *
  * GRANT and REVOKE statements
@@ -3139,26 +3272,24 @@ grantee_list:
 			| grantee_list ',' grantee				{ $$ = lappend($1, $3); }
 		;
 
-grantee:	ColId
+grantee:	RoleId
 				{
 					PrivGrantee *n = makeNode(PrivGrantee);
 					/* This hack lets us avoid reserving PUBLIC as a keyword*/
 					if (strcmp($1, "public") == 0)
-						n->username = NULL;
+						n->rolname = NULL;
 					else
-						n->username = $1;
-					n->groupname = NULL;
+						n->rolname = $1;
 					$$ = (Node *)n;
 				}
-			| GROUP_P ColId
+			| GROUP_P RoleId
 				{
 					PrivGrantee *n = makeNode(PrivGrantee);
 					/* Treat GROUP PUBLIC as a synonym for PUBLIC */
 					if (strcmp($2, "public") == 0)
-						n->groupname = NULL;
+						n->rolname = NULL;
 					else
-						n->groupname = $2;
-					n->username = NULL;
+						n->rolname = $2;
 					$$ = (Node *)n;
 				}
 		;
@@ -3169,11 +3300,26 @@ opt_grant_grant_option:
 			| /*EMPTY*/ { $$ = FALSE; }
 		;
 
+opt_grant_admin_option:
+			WITH ADMIN OPTION { $$ = TRUE; }
+			| /*EMPTY*/ { $$ = FALSE; }
+		;
+
+opt_granted_by:
+			GRANTED BY RoleId { $$ = $3; }
+			| /*EMPTY*/ { $$ = NULL; }
+		;
+
 opt_revoke_grant_option:
 			GRANT OPTION FOR { $$ = TRUE; }
 			| /*EMPTY*/ { $$ = FALSE; }
 		;
 
+opt_revoke_admin_option:
+			ADMIN OPTION FOR { $$ = TRUE; }
+			| /*EMPTY*/ { $$ = FALSE; }
+		;
+
 
 function_with_argtypes_list:
 			function_with_argtypes					{ $$ = list_make1($1); }
@@ -3727,10 +3873,10 @@ RenameStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' RENAME TO name
 					n->newname = $7;
 					$$ = (Node *)n;
 				}
-			| ALTER GROUP_P UserId RENAME TO UserId
+			| ALTER GROUP_P RoleId RENAME TO RoleId
 				{
 					RenameStmt *n = makeNode(RenameStmt);
-					n->renameType = OBJECT_GROUP;
+					n->renameType = OBJECT_ROLE;
 					n->subname = $3;
 					n->newname = $6;
 					$$ = (Node *)n;
@@ -3796,10 +3942,18 @@ RenameStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' RENAME TO name
 					n->renameType = OBJECT_TRIGGER;
 					$$ = (Node *)n;
 				}
-			| ALTER USER UserId RENAME TO UserId
+			| ALTER ROLE RoleId RENAME TO RoleId
 				{
 					RenameStmt *n = makeNode(RenameStmt);
-					n->renameType = OBJECT_USER;
+					n->renameType = OBJECT_ROLE;
+					n->subname = $3;
+					n->newname = $6;
+					$$ = (Node *)n;
+				}
+			| ALTER USER RoleId RENAME TO RoleId
+				{
+					RenameStmt *n = makeNode(RenameStmt);
+					n->renameType = OBJECT_ROLE;
 					n->subname = $3;
 					n->newname = $6;
 					$$ = (Node *)n;
@@ -3825,7 +3979,7 @@ opt_column: COLUMN									{ $$ = COLUMN; }
  *
  *****************************************************************************/
 
-AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
+AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_AGGREGATE;
@@ -3834,7 +3988,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
 					n->newowner = $9;
 					$$ = (Node *)n;
 				}
-			| ALTER CONVERSION_P any_name OWNER TO UserId
+			| ALTER CONVERSION_P any_name OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_CONVERSION;
@@ -3842,7 +3996,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
 					n->newowner = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER DATABASE database_name OWNER TO UserId
+			| ALTER DATABASE database_name OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_DATABASE;
@@ -3850,7 +4004,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
 					n->newowner = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER DOMAIN_P any_name OWNER TO UserId
+			| ALTER DOMAIN_P any_name OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_DOMAIN;
@@ -3858,7 +4012,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
 					n->newowner = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER FUNCTION func_name func_args OWNER TO UserId
+			| ALTER FUNCTION func_name func_args OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_FUNCTION;
@@ -3867,7 +4021,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
 					n->newowner = $7;
 					$$ = (Node *)n;
 				}
-			| ALTER OPERATOR any_operator '(' oper_argtypes ')' OWNER TO UserId
+			| ALTER OPERATOR any_operator '(' oper_argtypes ')' OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_OPERATOR;
@@ -3876,7 +4030,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
 					n->newowner = $9;
 					$$ = (Node *)n;
 				}
-			| ALTER OPERATOR CLASS any_name USING access_method OWNER TO UserId
+			| ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_OPCLASS;
@@ -3885,7 +4039,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
 					n->newowner = $9;
 					$$ = (Node *)n;
 				}
-			| ALTER SCHEMA name OWNER TO UserId
+			| ALTER SCHEMA name OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_SCHEMA;
@@ -3893,7 +4047,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
 					n->newowner = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER TYPE_P any_name OWNER TO UserId
+			| ALTER TYPE_P any_name OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_TYPE;
@@ -3901,7 +4055,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO UserId
 					n->newowner = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER TABLESPACE name OWNER TO UserId
+			| ALTER TABLESPACE name OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
 					n->objectType = OBJECT_TABLESPACE;
@@ -6903,6 +7057,33 @@ func_expr:	func_name '(' ')'
 
 					$$ = (Node *)makeTypeCast((Node *)s, d);
 				}
+			| CURRENT_ROLE
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = SystemFuncName("current_user");
+					n->args = NIL;
+					n->agg_star = FALSE;
+					n->agg_distinct = FALSE;
+					$$ = (Node *)n;
+				}
+			| SESSION_ROLE
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = SystemFuncName("session_user");
+					n->args = NIL;
+					n->agg_star = FALSE;
+					n->agg_distinct = FALSE;
+					$$ = (Node *)n;
+				}
+			| ROLE
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = SystemFuncName("current_user");
+					n->args = NIL;
+					n->agg_star = FALSE;
+					n->agg_distinct = FALSE;
+					$$ = (Node *)n;
+				}
 			| CURRENT_USER
 				{
 					FuncCall *n = makeNode(FuncCall);
@@ -7685,7 +7866,7 @@ AexprConst: Iconst
 
 Iconst:		ICONST									{ $$ = $1; };
 Sconst:		SCONST									{ $$ = $1; };
-UserId:		ColId									{ $$ = $1; };
+RoleId:		ColId									{ $$ = $1; };
 
 /*
  * Name classification hierarchy.
@@ -7774,6 +7955,7 @@ unreserved_keyword:
 			| CONVERSION_P
 			| COPY
 			| CREATEDB
+			| CREATEROLE
 			| CREATEUSER
 			| CSV
 			| CURSOR
@@ -7834,6 +8016,7 @@ unreserved_keyword:
 			| LOCAL
 			| LOCATION
 			| LOCK_P
+			| LOGIN
 			| MATCH
 			| MAXVALUE
 			| MINUTE_P
@@ -7845,7 +8028,9 @@ unreserved_keyword:
 			| NEXT
 			| NO
 			| NOCREATEDB
+			| NOCREATEROLE
 			| NOCREATEUSER
+			| NOLOGIN
 			| NOTHING
 			| NOTIFY
 			| NOWAIT
@@ -8045,6 +8230,7 @@ reserved_keyword:
 			| CURRENT_DATE
 			| CURRENT_TIME
 			| CURRENT_TIMESTAMP
+			| CURRENT_ROLE
 			| CURRENT_USER
 			| DEFAULT
 			| DEFERRABLE
@@ -8083,6 +8269,7 @@ reserved_keyword:
 			| PRIMARY
 			| REFERENCES
 			| SELECT
+			| SESSION_ROLE
 			| SESSION_USER
 			| SOME
 			| SYMMETRIC
@@ -8093,6 +8280,7 @@ reserved_keyword:
 			| TRUE_P
 			| UNION
 			| UNIQUE
+			| ROLE
 			| USER
 			| USING
 			| WHEN
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 41e45bc7475d71489acf085c871581ec743c05eb..a11d4affc1df3ea385f0e476d6d8b06353589d6a 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.159 2005/06/26 22:05:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.160 2005/06/28 05:08:58 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -269,6 +269,7 @@ static const ScanKeyword ScanKeywords[] = {
 	{"returns", RETURNS},
 	{"revoke", REVOKE},
 	{"right", RIGHT},
+	{"role", ROLE},
 	{"rollback", ROLLBACK},
 	{"row", ROW},
 	{"rows", ROWS},
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 5786ac44d0709fb6c54559e3537be849d9e3b67f..51d200736b08ef46a909804e8daacb35b836ab37 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.111 2005/06/05 00:38:09 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.112 2005/06/28 05:08:58 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -567,7 +567,7 @@ addRangeTableEntry(ParseState *pstate,
 	rte->inFromCl = inFromCl;
 
 	rte->requiredPerms = ACL_SELECT;
-	rte->checkAsUser = 0;		/* not set-uid by default, either */
+	rte->checkAsUser = InvalidOid;		/* not set-uid by default, either */
 
 	/*
 	 * Add completed RTE to pstate's range table list, but not to join
@@ -620,7 +620,7 @@ addRangeTableEntryForRelation(ParseState *pstate,
 	rte->inFromCl = inFromCl;
 
 	rte->requiredPerms = ACL_SELECT;
-	rte->checkAsUser = 0;		/* not set-uid by default, either */
+	rte->checkAsUser = InvalidOid;		/* not set-uid by default, either */
 
 	/*
 	 * Add completed RTE to pstate's range table list, but not to join
@@ -698,7 +698,7 @@ addRangeTableEntryForSubquery(ParseState *pstate,
 	rte->inFromCl = inFromCl;
 
 	rte->requiredPerms = 0;
-	rte->checkAsUser = 0;
+	rte->checkAsUser = InvalidOid;
 
 	/*
 	 * Add completed RTE to pstate's range table list, but not to join
@@ -823,7 +823,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
 	rte->inFromCl = inFromCl;
 
 	rte->requiredPerms = 0;
-	rte->checkAsUser = 0;
+	rte->checkAsUser = InvalidOid;
 
 	/*
 	 * Add completed RTE to pstate's range table list, but not to join
@@ -882,7 +882,7 @@ addRangeTableEntryForJoin(ParseState *pstate,
 	rte->inFromCl = inFromCl;
 
 	rte->requiredPerms = 0;
-	rte->checkAsUser = 0;
+	rte->checkAsUser = InvalidOid;
 
 	/*
 	 * Add completed RTE to pstate's range table list, but not to join
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 8366bdb8b4cec4aa9bbdcaa5a8e526d2b7dd14b6..b429275d9f65041ece7982b49c0e4769019771e4 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -13,7 +13,7 @@
  *
  *	Copyright (c) 2001-2005, PostgreSQL Global Development Group
  *
- *	$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.96 2005/06/25 23:58:57 tgl Exp $
+ *	$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.97 2005/06/28 05:08:59 tgl Exp $
  * ----------
  */
 #include "postgres.h"
@@ -34,7 +34,6 @@
 #include "access/heapam.h"
 #include "access/xact.h"
 #include "catalog/pg_database.h"
-#include "catalog/pg_shadow.h"
 #include "libpq/libpq.h"
 #include "libpq/pqsignal.h"
 #include "mb/pg_wchar.h"
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 6ca13944f8aca04833869659a80a9a437cdf0710..27b28b89f544e6e9259d21df47619220694d6535 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.454 2005/06/17 22:32:44 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.455 2005/06/28 05:08:59 tgl Exp $
  *
  * NOTES
  *
@@ -2032,12 +2032,11 @@ reaper(SIGNAL_ARGS)
 			FatalError = false;
 
 			/*
-			 * Load the flat user/group files into postmaster's caches.
-			 * The startup process has recomputed these from the database
-			 * contents, so we wait till it finishes before loading them.
+			 * Load the flat authorization file into postmaster's cache.
+			 * The startup process has recomputed this from the database
+			 * contents, so we wait till it finishes before loading it.
 			 */
-			load_user();
-			load_group();
+			load_role();
 
 			/*
 			 * Crank up the background writer.	It doesn't matter if this
@@ -2664,8 +2663,7 @@ BackendRun(Port *port)
 
 	load_hba();
 	load_ident();
-	load_user();
-	load_group();
+	load_role();
 #endif
 
 	/*
@@ -3290,10 +3288,9 @@ sigusr1_handler(SIGNAL_ARGS)
 	if (CheckPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE))
 	{
 		/*
-		 * Password or group file has changed.
+		 * Authorization file has changed.
 		 */
-		load_user();
-		load_group();
+		load_role();
 	}
 
 	if (CheckPostmasterSignal(PMSIGNAL_WAKEN_CHILDREN))
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index c793cabd2a9afc107c6045e6a2bec39c88c4d6a6..c28ea627e507d5822e7861fb463bc927b2a0f2dd 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.104 2005/04/14 20:03:25 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.105 2005/06/28 05:08:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,9 +33,9 @@
 #include "utils/syscache.h"
 
 
-static void setRuleCheckAsUser_Query(Query *qry, AclId userid);
-static void setRuleCheckAsUser_Expr(Node *node, AclId userid);
-static bool setRuleCheckAsUser_walker(Node *node, AclId *context);
+static void setRuleCheckAsUser_Query(Query *qry, Oid userid);
+static void setRuleCheckAsUser_Expr(Node *node, Oid userid);
+static bool setRuleCheckAsUser_walker(Node *node, Oid *context);
 
 
 /*
@@ -505,7 +505,7 @@ DefineQueryRewrite(RuleStmt *stmt)
  * them always.
  */
 static void
-setRuleCheckAsUser_Query(Query *qry, AclId userid)
+setRuleCheckAsUser_Query(Query *qry, Oid userid)
 {
 	ListCell   *l;
 
@@ -534,13 +534,13 @@ setRuleCheckAsUser_Query(Query *qry, AclId userid)
  * Expression-tree walker to find sublink queries
  */
 static void
-setRuleCheckAsUser_Expr(Node *node, AclId userid)
+setRuleCheckAsUser_Expr(Node *node, Oid userid)
 {
 	(void) setRuleCheckAsUser_walker(node, &userid);
 }
 
 static bool
-setRuleCheckAsUser_walker(Node *node, AclId *context)
+setRuleCheckAsUser_walker(Node *node, Oid *context)
 {
 	if (node == NULL)
 		return false;
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index b7a96922e9481a1589508464277f8ba467c8dba0..3677fd2ebac17312c101e6822ed7cd6a100e3941 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.154 2005/06/04 19:19:42 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.155 2005/06/28 05:08:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -945,7 +945,7 @@ ApplyRetrieveRule(Query *parsetree,
 	subrte->checkAsUser = rte->checkAsUser;
 
 	rte->requiredPerms = 0;		/* no permission check on subquery itself */
-	rte->checkAsUser = 0;
+	rte->checkAsUser = InvalidOid;
 
 	/*
 	 * FOR UPDATE/SHARE of view?
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 82bd8eafc1185ba8b91f0b58483379bdb0bc341f..40d5e7d7ce6cf9b20b2ca889203c0dc544b25924 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.238 2005/06/22 21:14:30 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.239 2005/06/28 05:09:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,7 +20,6 @@
 #include "access/twophase.h"
 #include "catalog/catalog.h"
 #include "catalog/namespace.h"
-#include "catalog/pg_shadow.h"
 #include "commands/alter.h"
 #include "commands/async.h"
 #include "commands/cluster.h"
@@ -279,12 +278,11 @@ check_xact_readonly(Node *parsetree)
 		case T_AlterDatabaseSetStmt:
 		case T_AlterDomainStmt:
 		case T_AlterFunctionStmt:
-		case T_AlterGroupStmt:
+		case T_AlterRoleStmt:
+		case T_AlterRoleSetStmt:
 		case T_AlterOwnerStmt:
 		case T_AlterSeqStmt:
 		case T_AlterTableStmt:
-		case T_AlterUserStmt:
-		case T_AlterUserSetStmt:
 		case T_RenameStmt:
 		case T_CommentStmt:
 		case T_DefineStmt:
@@ -293,7 +291,7 @@ check_xact_readonly(Node *parsetree)
 		case T_CreatedbStmt:
 		case T_CreateDomainStmt:
 		case T_CreateFunctionStmt:
-		case T_CreateGroupStmt:
+		case T_CreateRoleStmt:
 		case T_IndexStmt:
 		case T_CreatePLangStmt:
 		case T_CreateOpClassStmt:
@@ -304,7 +302,6 @@ check_xact_readonly(Node *parsetree)
 		case T_CreateTableSpaceStmt:
 		case T_CreateTrigStmt:
 		case T_CompositeTypeStmt:
-		case T_CreateUserStmt:
 		case T_ViewStmt:
 		case T_RemoveAggrStmt:
 		case T_DropCastStmt:
@@ -312,13 +309,13 @@ check_xact_readonly(Node *parsetree)
 		case T_DropdbStmt:
 		case T_DropTableSpaceStmt:
 		case T_RemoveFuncStmt:
-		case T_DropGroupStmt:
+		case T_DropRoleStmt:
 		case T_DropPLangStmt:
 		case T_RemoveOperStmt:
 		case T_RemoveOpClassStmt:
 		case T_DropPropertyStmt:
-		case T_DropUserStmt:
 		case T_GrantStmt:
+		case T_GrantRoleStmt:
 		case T_TruncateStmt:
 			ereport(ERROR,
 					(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
@@ -679,11 +676,14 @@ ProcessUtility(Node *parsetree,
 			}
 			break;
 
-
 		case T_GrantStmt:
 			ExecuteGrantStmt((GrantStmt *) parsetree);
 			break;
 
+		case T_GrantRoleStmt:
+			GrantRole((GrantRoleStmt *) parsetree);
+			break;
+
 			/*
 			 * ******************************** object creation /
 			 * destruction ********************************
@@ -958,22 +958,22 @@ ProcessUtility(Node *parsetree,
 			break;
 
 			/*
-			 * ******************************** USER statements ****
+			 * ******************************** ROLE statements ****
 			 */
-		case T_CreateUserStmt:
-			CreateUser((CreateUserStmt *) parsetree);
+		case T_CreateRoleStmt:
+			CreateRole((CreateRoleStmt *) parsetree);
 			break;
 
-		case T_AlterUserStmt:
-			AlterUser((AlterUserStmt *) parsetree);
+		case T_AlterRoleStmt:
+			AlterRole((AlterRoleStmt *) parsetree);
 			break;
 
-		case T_AlterUserSetStmt:
-			AlterUserSet((AlterUserSetStmt *) parsetree);
+		case T_AlterRoleSetStmt:
+			AlterRoleSet((AlterRoleSetStmt *) parsetree);
 			break;
 
-		case T_DropUserStmt:
-			DropUser((DropUserStmt *) parsetree);
+		case T_DropRoleStmt:
+			DropRole((DropRoleStmt *) parsetree);
 			break;
 
 		case T_LockStmt:
@@ -984,18 +984,6 @@ ProcessUtility(Node *parsetree,
 			AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
 			break;
 
-		case T_CreateGroupStmt:
-			CreateGroup((CreateGroupStmt *) parsetree);
-			break;
-
-		case T_AlterGroupStmt:
-			AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
-			break;
-
-		case T_DropGroupStmt:
-			DropGroup((DropGroupStmt *) parsetree);
-			break;
-
 		case T_CheckPointStmt:
 			if (!superuser())
 				ereport(ERROR,
@@ -1350,9 +1338,6 @@ CreateCommandTag(Node *parsetree)
 				case OBJECT_FUNCTION:
 					tag = "ALTER FUNCTION";
 					break;
-				case OBJECT_GROUP:
-					tag = "ALTER GROUP";
-					break;
 				case OBJECT_INDEX:
 					tag = "ALTER INDEX";
 					break;
@@ -1362,6 +1347,9 @@ CreateCommandTag(Node *parsetree)
 				case OBJECT_OPCLASS:
 					tag = "ALTER OPERATOR CLASS";
 					break;
+				case OBJECT_ROLE:
+					tag = "ALTER ROLE";
+					break;
 				case OBJECT_SCHEMA:
 					tag = "ALTER SCHEMA";
 					break;
@@ -1371,9 +1359,6 @@ CreateCommandTag(Node *parsetree)
 				case OBJECT_TRIGGER:
 					tag = "ALTER TRIGGER";
 					break;
-				case OBJECT_USER:
-					tag = "ALTER USER";
-					break;
 				default:
 					tag = "ALTER TABLE";
 			}
@@ -1450,6 +1435,14 @@ CreateCommandTag(Node *parsetree)
 			}
 			break;
 
+		case T_GrantRoleStmt:
+			{
+				GrantRoleStmt  *stmt = (GrantRoleStmt *) parsetree;
+
+				tag = (stmt->is_grant) ? "GRANT ROLE" : "REVOKE ROLE";
+			}
+			break;
+
 		case T_DefineStmt:
 			switch (((DefineStmt *) parsetree)->kind)
 			{
@@ -1588,20 +1581,20 @@ CreateCommandTag(Node *parsetree)
 			tag = "DROP LANGUAGE";
 			break;
 
-		case T_CreateUserStmt:
-			tag = "CREATE USER";
+		case T_CreateRoleStmt:
+			tag = "CREATE ROLE";
 			break;
 
-		case T_AlterUserStmt:
-			tag = "ALTER USER";
+		case T_AlterRoleStmt:
+			tag = "ALTER ROLE";
 			break;
 
-		case T_AlterUserSetStmt:
-			tag = "ALTER USER";
+		case T_AlterRoleSetStmt:
+			tag = "ALTER ROLE";
 			break;
 
-		case T_DropUserStmt:
-			tag = "DROP USER";
+		case T_DropRoleStmt:
+			tag = "DROP ROLE";
 			break;
 
 		case T_LockStmt:
@@ -1612,18 +1605,6 @@ CreateCommandTag(Node *parsetree)
 			tag = "SET CONSTRAINTS";
 			break;
 
-		case T_CreateGroupStmt:
-			tag = "CREATE GROUP";
-			break;
-
-		case T_AlterGroupStmt:
-			tag = "ALTER GROUP";
-			break;
-
-		case T_DropGroupStmt:
-			tag = "DROP GROUP";
-			break;
-
 		case T_CheckPointStmt:
 			tag = "CHECKPOINT";
 			break;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 68b34f3dce58bc747fe014678057ad317fc74a16..4d5904b76901dc4526a9d88feff36291ad1a7f63 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.114 2005/05/27 00:57:49 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.115 2005/06/28 05:09:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,20 +17,33 @@
 #include <ctype.h>
 
 #include "catalog/namespace.h"
-#include "catalog/pg_group.h"
-#include "catalog/pg_shadow.h"
+#include "catalog/pg_authid.h"
+#include "catalog/pg_auth_members.h"
 #include "catalog/pg_type.h"
 #include "commands/dbcommands.h"
 #include "commands/tablespace.h"
 #include "miscadmin.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/catcache.h"
+#include "utils/inval.h"
 #include "utils/lsyscache.h"
+#include "utils/memutils.h"
 #include "utils/syscache.h"
 
 
-#define ACL_IDTYPE_GID_KEYWORD	"group"
-#define ACL_IDTYPE_UID_KEYWORD	"user"
+#define ACL_IDTYPE_ROLE_KEYWORD	"role"
+
+/* The rolmemcache is a possibly-empty list of role OIDs.
+ * rolmemRole is the Role for which the cache was generated.
+ * In the event of a Role change the cache will be regenerated.
+ */
+static List	*rolmemcache = NIL;
+static Oid	rolmemRole = InvalidOid;
+
+/* rolmemcache and rolmemRole only valid when 
+ * rolmemcacheValid is true */
+static bool rolmemcacheValid = false;
 
 static const char *getid(const char *s, char *n);
 static void putid(char *p, const char *s);
@@ -38,10 +51,9 @@ static Acl *allocacl(int n);
 static const char *aclparse(const char *s, AclItem *aip);
 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
-				  AclId ownerid);
-static Acl *recursive_revoke(Acl *acl, AclId grantee, AclMode revoke_privs,
-				 AclId ownerid, DropBehavior behavior);
-static bool in_group(AclId uid, AclId gid);
+				  Oid ownerId);
+static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
+				 Oid ownerId, DropBehavior behavior);
 
 static AclMode convert_priv_string(text *priv_type_text);
 
@@ -58,6 +70,9 @@ static AclMode convert_schema_priv_string(text *priv_type_text);
 static Oid	convert_tablespace_name(text *tablespacename);
 static AclMode convert_tablespace_priv_string(text *priv_type_text);
 
+static void RolMemCacheCallback(Datum arg, Oid relid);
+static void recomputeRolMemCache(Oid roleid);
+
 
 /*
  * getid
@@ -175,7 +190,6 @@ aclparse(const char *s, AclItem *aip)
 	AclMode		privs,
 				goption,
 				read;
-	uint32		idtype;
 	char		name[NAMEDATALEN];
 	char		name2[NAMEDATALEN];
 
@@ -184,27 +198,22 @@ aclparse(const char *s, AclItem *aip)
 #ifdef ACLDEBUG
 	elog(LOG, "aclparse: input = \"%s\"", s);
 #endif
-	idtype = ACL_IDTYPE_UID;
 	s = getid(s, name);
 	if (*s != '=')
 	{
 		/* we just read a keyword, not a name */
-		if (strcmp(name, ACL_IDTYPE_GID_KEYWORD) == 0)
-			idtype = ACL_IDTYPE_GID;
-		else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD) != 0)
+		if (strcmp(name, ACL_IDTYPE_ROLE_KEYWORD) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("unrecognized key word: \"%s\"", name),
-				errhint("ACL key word must be \"group\" or \"user\".")));
+				errhint("ACL key word must be \"role\".")));
 		s = getid(s, name);		/* move s to the name beyond the keyword */
 		if (name[0] == '\0')
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("missing name"),
-					 errhint("A name must follow the \"group\" or \"user\" key word.")));
+					 errhint("A name must follow the \"role\" key word.")));
 	}
-	if (name[0] == '\0')
-		idtype = ACL_IDTYPE_WORLD;
 
 	if (*s != '=')
 		ereport(ERROR,
@@ -263,18 +272,10 @@ aclparse(const char *s, AclItem *aip)
 		privs |= read;
 	}
 
-	switch (idtype)
-	{
-		case ACL_IDTYPE_UID:
-			aip->ai_grantee = get_usesysid(name);
-			break;
-		case ACL_IDTYPE_GID:
-			aip->ai_grantee = get_grosysid(name);
-			break;
-		case ACL_IDTYPE_WORLD:
-			aip->ai_grantee = ACL_ID_WORLD;
-			break;
-	}
+	if (name[0] == '\0')
+		aip->ai_grantee = ACL_ID_PUBLIC;
+	else
+		aip->ai_grantee = get_roleid_checked(name);
 
 	/*
 	 * XXX Allow a degree of backward compatibility by defaulting the
@@ -287,23 +288,24 @@ aclparse(const char *s, AclItem *aip)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("a name must follow the \"/\" sign")));
-
-		aip->ai_grantor = get_usesysid(name2);
+		aip->ai_grantor = get_roleid_checked(name2);
 	}
 	else
 	{
-		aip->ai_grantor = BOOTSTRAP_USESYSID;
+		aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
 		ereport(WARNING,
 				(errcode(ERRCODE_INVALID_GRANTOR),
-		errmsg("defaulting grantor to user ID %u", BOOTSTRAP_USESYSID)));
+				 errmsg("defaulting grantor to user ID %u",
+						BOOTSTRAP_SUPERUSERID)));
 	}
 
-	ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, goption, idtype);
+	ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
 
 #ifdef ACLDEBUG
-	elog(LOG, "aclparse: correctly read [%x %d %x]",
-		 idtype, aip->ai_grantee, privs);
+	elog(LOG, "aclparse: correctly read [%u %x %x]",
+		 aip->ai_grantee, privs, goption);
 #endif
+
 	return s;
 }
 
@@ -375,7 +377,6 @@ aclitemout(PG_FUNCTION_ARGS)
 	char	   *out;
 	HeapTuple	htup;
 	unsigned	i;
-	char	   *tmpname;
 
 	out = palloc(strlen("group =/") +
 				 2 * N_ACL_RIGHTS +
@@ -385,41 +386,21 @@ aclitemout(PG_FUNCTION_ARGS)
 	p = out;
 	*p = '\0';
 
-	switch (ACLITEM_GET_IDTYPE(*aip))
+	if (aip->ai_grantee != ACL_ID_PUBLIC)
 	{
-		case ACL_IDTYPE_UID:
-			htup = SearchSysCache(SHADOWSYSID,
-								  ObjectIdGetDatum(aip->ai_grantee),
-								  0, 0, 0);
-			if (HeapTupleIsValid(htup))
-			{
-				putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename));
-				ReleaseSysCache(htup);
-			}
-			else
-			{
-				/* Generate numeric UID if we don't find an entry */
-				sprintf(p, "%d", aip->ai_grantee);
-			}
-			break;
-		case ACL_IDTYPE_GID:
-			strcpy(p, "group ");
-			p += strlen(p);
-			tmpname = get_groname(aip->ai_grantee);
-			if (tmpname != NULL)
-				putid(p, tmpname);
-			else
-			{
-				/* Generate numeric GID if we don't find an entry */
-				sprintf(p, "%d", aip->ai_grantee);
-			}
-			break;
-		case ACL_IDTYPE_WORLD:
-			break;
-		default:
-			elog(ERROR, "unrecognized idtype: %d",
-				 (int) ACLITEM_GET_IDTYPE(*aip));
-			break;
+		htup = SearchSysCache(AUTHOID,
+							  ObjectIdGetDatum(aip->ai_grantee),
+							  0, 0, 0);
+		if (HeapTupleIsValid(htup))
+		{
+			putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
+			ReleaseSysCache(htup);
+		}
+		else
+		{
+			/* Generate numeric OID if we don't find an entry */
+			sprintf(p, "%u", aip->ai_grantee);
+		}
 	}
 	while (*p)
 		++p;
@@ -437,18 +418,18 @@ aclitemout(PG_FUNCTION_ARGS)
 	*p++ = '/';
 	*p = '\0';
 
-	htup = SearchSysCache(SHADOWSYSID,
+	htup = SearchSysCache(AUTHOID,
 						  ObjectIdGetDatum(aip->ai_grantor),
 						  0, 0, 0);
 	if (HeapTupleIsValid(htup))
 	{
-		putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename));
+		putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
 		ReleaseSysCache(htup);
 	}
 	else
 	{
-		/* Generate numeric UID if we don't find an entry */
-		sprintf(p, "%d", aip->ai_grantor);
+		/* Generate numeric OID if we don't find an entry */
+		sprintf(p, "%u", aip->ai_grantor);
 	}
 
 	while (*p)
@@ -466,8 +447,7 @@ aclitemout(PG_FUNCTION_ARGS)
 static bool
 aclitem_match(const AclItem *a1, const AclItem *a2)
 {
-	return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
-		a1->ai_grantee == a2->ai_grantee &&
+	return a1->ai_grantee == a2->ai_grantee &&
 		a1->ai_grantor == a2->ai_grantor;
 }
 
@@ -511,7 +491,7 @@ hash_aclitem(PG_FUNCTION_ARGS)
  * newly-created objects (or any object with a NULL acl entry).
  */
 Acl *
-acldefault(GrantObjectType objtype, AclId ownerid)
+acldefault(GrantObjectType objtype, Oid ownerId)
 {
 	AclMode		world_default;
 	AclMode		owner_default;
@@ -558,10 +538,9 @@ acldefault(GrantObjectType objtype, AclId ownerid)
 
 	if (world_default != ACL_NO_RIGHTS)
 	{
-		aip->ai_grantee = ACL_ID_WORLD;
-		aip->ai_grantor = ownerid;
-		ACLITEM_SET_PRIVS_IDTYPE(*aip, world_default, ACL_NO_RIGHTS,
-								 ACL_IDTYPE_WORLD);
+		aip->ai_grantee = ACL_ID_PUBLIC;
+		aip->ai_grantor = ownerId;
+		ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
 		aip++;
 	}
 
@@ -575,10 +554,9 @@ acldefault(GrantObjectType objtype, AclId ownerid)
 	 * without any explicit "_SYSTEM"-like ACL entry, by internally
 	 * special-casing the owner whereever we are testing grant options.
 	 */
-	aip->ai_grantee = ownerid;
-	aip->ai_grantor = ownerid;
-	ACLITEM_SET_PRIVS_IDTYPE(*aip, owner_default, ACL_NO_RIGHTS,
-							 ACL_IDTYPE_UID);
+	aip->ai_grantee = ownerId;
+	aip->ai_grantor = ownerId;
+	ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
 
 	return acl;
 }
@@ -590,7 +568,7 @@ acldefault(GrantObjectType objtype, AclId ownerid)
  *	old_acl: the input ACL array
  *	mod_aip: defines the privileges to be added, removed, or substituted
  *	modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
- *	ownerid: AclId of object owner
+ *	ownerId: Oid of object owner
  *	behavior: RESTRICT or CASCADE behavior for recursive removal
  *
  * ownerid and behavior are only relevant when the update operation specifies
@@ -602,7 +580,7 @@ acldefault(GrantObjectType objtype, AclId ownerid)
  */
 Acl *
 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
-		  int modechg, AclId ownerid, DropBehavior behavior)
+		  int modechg, Oid ownerId, DropBehavior behavior)
 {
 	Acl		   *new_acl = NULL;
 	AclItem    *old_aip,
@@ -627,7 +605,7 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip,
 	/* If granting grant options, check for circularity */
 	if (modechg != ACL_MODECHG_DEL &&
 		ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
-		check_circularity(old_acl, mod_aip, ownerid);
+		check_circularity(old_acl, mod_aip, ownerId);
 
 	num = ACL_NUM(old_acl);
 	old_aip = ACL_DAT(old_acl);
@@ -661,9 +639,8 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip,
 		/* initialize the new entry with no permissions */
 		new_aip[dst].ai_grantee = mod_aip->ai_grantee;
 		new_aip[dst].ai_grantor = mod_aip->ai_grantor;
-		ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
-								 ACL_NO_RIGHTS, ACL_NO_RIGHTS,
-								 ACLITEM_GET_IDTYPE(*mod_aip));
+		ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
+								   ACL_NO_RIGHTS, ACL_NO_RIGHTS);
 		num++;					/* set num to the size of new_acl */
 	}
 
@@ -704,14 +681,14 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip,
 
 	/*
 	 * Remove abandoned privileges (cascading revoke).	Currently we can
-	 * only handle this when the grantee is a user.
+	 * only handle this when the grantee is not PUBLIC.
 	 */
 	if ((old_goptions & ~new_goptions) != 0)
 	{
-		Assert(ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID);
+		Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
 		new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
 								   (old_goptions & ~new_goptions),
-								   ownerid, behavior);
+								   ownerId, behavior);
 	}
 
 	return new_acl;
@@ -721,15 +698,15 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip,
  * Update an ACL array to reflect a change of owner to the parent object
  *
  *	old_acl: the input ACL array (must not be NULL)
- *	oldownerid: AclId of the old object owner
- *	newownerid: AclId of the new object owner
+ *	oldOwnerId: Oid of the old object owner
+ *	newOwnerId: Oid of the new object owner
  *
  * The result is a modified copy; the input object is not changed.
  *
  * NB: caller is responsible for having detoasted the input ACL, if needed.
  */
 Acl *
-aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid)
+aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
 {
 	Acl		   *new_acl;
 	AclItem    *new_aip;
@@ -755,18 +732,14 @@ aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid)
 	memcpy(new_aip, old_aip, num * sizeof(AclItem));
 	for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
 	{
-		/* grantor is always a UID, but grantee might not be */
-		if (dst_aip->ai_grantor == oldownerid)
-			dst_aip->ai_grantor = newownerid;
-		else if (dst_aip->ai_grantor == newownerid)
+		if (dst_aip->ai_grantor == oldOwnerId)
+			dst_aip->ai_grantor = newOwnerId;
+		else if (dst_aip->ai_grantor == newOwnerId)
+			newpresent = true;
+		if (dst_aip->ai_grantee == oldOwnerId)
+			dst_aip->ai_grantee = newOwnerId;
+		else if (dst_aip->ai_grantee == newOwnerId)
 			newpresent = true;
-		if (ACLITEM_GET_IDTYPE(*dst_aip) == ACL_IDTYPE_UID)
-		{
-			if (dst_aip->ai_grantee == oldownerid)
-				dst_aip->ai_grantee = newownerid;
-			else if (dst_aip->ai_grantee == newownerid)
-				newpresent = true;
-		}
 	}
 
 	/*
@@ -836,7 +809,7 @@ aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid)
  */
 static void
 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
-				  AclId ownerid)
+				  Oid ownerId)
 {
 	Acl		   *acl;
 	AclItem    *aip;
@@ -845,13 +818,13 @@ check_circularity(const Acl *old_acl, const AclItem *mod_aip,
 	AclMode		own_privs;
 
 	/*
-	 * For now, grant options can only be granted to users, not groups or
-	 * PUBLIC.	Otherwise we'd have to work a bit harder here.
+	 * For now, grant options can only be granted to roles, not PUBLIC.
+	 * Otherwise we'd have to work a bit harder here.
 	 */
-	Assert(ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID);
+	Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
 
 	/* The owner always has grant options, no need to check */
-	if (mod_aip->ai_grantor == ownerid)
+	if (mod_aip->ai_grantor == ownerId)
 		return;
 
 	/* Make a working copy */
@@ -864,15 +837,14 @@ cc_restart:
 	aip = ACL_DAT(acl);
 	for (i = 0; i < num; i++)
 	{
-		if (ACLITEM_GET_IDTYPE(aip[i]) == ACL_IDTYPE_UID &&
-			aip[i].ai_grantee == mod_aip->ai_grantee &&
+		if (aip[i].ai_grantee == mod_aip->ai_grantee &&
 			ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
 		{
 			Acl		   *new_acl;
 
 			/* We'll actually zap ordinary privs too, but no matter */
 			new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
-								ownerid, DROP_CASCADE);
+								ownerId, DROP_CASCADE);
 
 			pfree(acl);
 			acl = new_acl;
@@ -884,7 +856,7 @@ cc_restart:
 	/* Now we can compute grantor's independently-derived privileges */
 	own_privs = aclmask(acl,
 						mod_aip->ai_grantor,
-						ownerid,
+						ownerId,
 					ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
 						ACLMASK_ALL);
 	own_privs = ACL_OPTION_TO_PRIVS(own_privs);
@@ -908,16 +880,16 @@ cc_restart:
  *	acl: the input ACL list
  *	grantee: the user from whom some grant options have been revoked
  *	revoke_privs: the grant options being revoked
- *	ownerid: AclId of object owner
+ *	ownerId: Oid of object owner
  *	behavior: RESTRICT or CASCADE behavior for recursive removal
  *
  * The input Acl object is pfree'd if replaced.
  */
 static Acl *
 recursive_revoke(Acl *acl,
-				 AclId grantee,
+				 Oid grantee,
 				 AclMode revoke_privs,
-				 AclId ownerid,
+				 Oid ownerId,
 				 DropBehavior behavior)
 {
 	AclMode		still_has;
@@ -926,11 +898,11 @@ recursive_revoke(Acl *acl,
 				num;
 
 	/* The owner can never truly lose grant options, so short-circuit */
-	if (grantee == ownerid)
+	if (grantee == ownerId)
 		return acl;
 
 	/* The grantee might still have the privileges via another grantor */
-	still_has = aclmask(acl, grantee, ownerid,
+	still_has = aclmask(acl, grantee, ownerId,
 						ACL_GRANT_OPTION_FOR(revoke_privs),
 						ACLMASK_ALL);
 	revoke_privs &= ~still_has;
@@ -956,13 +928,12 @@ restart:
 
 			mod_acl.ai_grantor = grantee;
 			mod_acl.ai_grantee = aip[i].ai_grantee;
-			ACLITEM_SET_PRIVS_IDTYPE(mod_acl,
-									 revoke_privs,
-									 revoke_privs,
-									 ACLITEM_GET_IDTYPE(aip[i]));
+			ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
+									   revoke_privs,
+									   revoke_privs);
 
 			new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
-								ownerid, behavior);
+								ownerId, behavior);
 
 			pfree(acl);
 			acl = new_acl;
@@ -976,10 +947,10 @@ restart:
 
 
 /*
- * aclmask --- compute bitmask of all privileges held by userid.
+ * aclmask --- compute bitmask of all privileges held by roleid.
  *
  * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
- * held by the given userid according to the given ACL list, ANDed
+ * held by the given roleid according to the given ACL list, ANDed
  * with 'mask'.  (The point of passing 'mask' is to let the routine
  * exit early if all privileges of interest have been found.)
  *
@@ -990,20 +961,20 @@ restart:
  * Usage patterns:
  *
  * To see if any of a set of privileges are held:
- *		if (aclmask(acl, userid, ownerid, privs, ACLMASK_ANY) != 0)
+ *		if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
  *
  * To see if all of a set of privileges are held:
- *		if (aclmask(acl, userid, ownerid, privs, ACLMASK_ALL) == privs)
+ *		if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
  *
  * To determine exactly which of a set of privileges are held:
- *		heldprivs = aclmask(acl, userid, ownerid, privs, ACLMASK_ALL);
+ *		heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
+ *
  */
 AclMode
-aclmask(const Acl *acl, AclId userid, AclId ownerid,
+aclmask(const Acl *acl, Oid roleid, Oid ownerId,
 		AclMode mask, AclMaskHow how)
 {
 	AclMode		result;
-	AclMode		remaining;
 	AclItem    *aidat;
 	int			i,
 				num;
@@ -1022,7 +993,7 @@ aclmask(const Acl *acl, AclId userid, AclId ownerid,
 	result = 0;
 
 	/* Owner always implicitly has all grant options */
-	if (userid == ownerid)
+	if (is_member_of_role(roleid,ownerId))
 	{
 		result = mask & ACLITEM_ALL_GOPTION_BITS;
 		if (result == mask)
@@ -1033,39 +1004,19 @@ aclmask(const Acl *acl, AclId userid, AclId ownerid,
 	aidat = ACL_DAT(acl);
 
 	/*
-	 * Check privileges granted directly to user or to public
-	 */
-	for (i = 0; i < num; i++)
-	{
-		AclItem    *aidata = &aidat[i];
-
-		if (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_WORLD
-			|| (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_UID
-				&& aidata->ai_grantee == userid))
-		{
-			result |= (aidata->ai_privs & mask);
-			if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
-				return result;
-		}
-	}
-
-	/*
-	 * Check privileges granted via groups.  We do this in a separate pass
-	 * to minimize expensive lookups in pg_group.
+	 * Check privileges granted directly to role, indirectly
+	 * via role membership or to public
 	 */
-	remaining = (mask & ~result);
 	for (i = 0; i < num; i++)
 	{
 		AclItem    *aidata = &aidat[i];
 
-		if (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_GID
-			&& (aidata->ai_privs & remaining)
-			&& in_group(userid, aidata->ai_grantee))
+		if (aidata->ai_grantee == ACL_ID_PUBLIC ||
+			is_member_of_role(roleid, aidata->ai_grantee))
 		{
 			result |= (aidata->ai_privs & mask);
 			if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
 				return result;
-			remaining = (mask & ~result);
 		}
 	}
 
@@ -1074,55 +1025,19 @@ aclmask(const Acl *acl, AclId userid, AclId ownerid,
 
 
 /*
- * Is user a member of group?
+ * Is member a member of role?
+ * relmemcache includes the role itself too
  */
-static bool
-in_group(AclId uid, AclId gid)
-{
-	bool		result = false;
-	HeapTuple	tuple;
-	Datum		att;
-	bool		isNull;
-	IdList	   *glist;
-	AclId	   *aidp;
-	int			i,
-				num;
+bool
+is_member_of_role(Oid member, Oid role)
+{
+	/* Fast path for simple case */
+	if (member == role)
+		return true;
 
-	tuple = SearchSysCache(GROSYSID,
-						   ObjectIdGetDatum(gid),
-						   0, 0, 0);
-	if (HeapTupleIsValid(tuple))
-	{
-		att = SysCacheGetAttr(GROSYSID,
-							  tuple,
-							  Anum_pg_group_grolist,
-							  &isNull);
-		if (!isNull)
-		{
-			/* be sure the IdList is not toasted */
-			glist = DatumGetIdListP(att);
-			/* scan it */
-			num = IDLIST_NUM(glist);
-			aidp = IDLIST_DAT(glist);
-			for (i = 0; i < num; ++i)
-			{
-				if (aidp[i] == uid)
-				{
-					result = true;
-					break;
-				}
-			}
-			/* if IdList was toasted, free detoasted copy */
-			if ((Pointer) glist != DatumGetPointer(att))
-				pfree(glist);
-		}
-		ReleaseSysCache(tuple);
-	}
-	else
-		ereport(WARNING,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("group with ID %u does not exist", gid)));
-	return result;
+	recomputeRolMemCache(member);
+
+	return list_member_oid(rolmemcache, role);
 }
 
 
@@ -1162,10 +1077,9 @@ aclcontains(PG_FUNCTION_ARGS)
 	aidat = ACL_DAT(acl);
 	for (i = 0; i < num; ++i)
 	{
-		if (aip->ai_grantee == aidat[i].ai_grantee
-			&& ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i])
-			&& aip->ai_grantor == aidat[i].ai_grantor
-			&& (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
+		if (aip->ai_grantee == aidat[i].ai_grantee &&
+			aip->ai_grantor == aidat[i].ai_grantor &&
+			(ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
 			PG_RETURN_BOOL(true);
 	}
 	PG_RETURN_BOOL(false);
@@ -1174,51 +1088,22 @@ aclcontains(PG_FUNCTION_ARGS)
 Datum
 makeaclitem(PG_FUNCTION_ARGS)
 {
-	int32		u_grantee = PG_GETARG_INT32(0);
-	int32		g_grantee = PG_GETARG_INT32(1);
-	int32		grantor = PG_GETARG_INT32(2);
-	text	   *privtext = PG_GETARG_TEXT_P(3);
-	bool		goption = PG_GETARG_BOOL(4);
+	Oid			grantee = PG_GETARG_OID(0);
+	Oid 		grantor = PG_GETARG_OID(1);
+	text	   *privtext = PG_GETARG_TEXT_P(2);
+	bool		goption = PG_GETARG_BOOL(3);
 	AclItem    *aclitem;
 	AclMode		priv;
 
 	priv = convert_priv_string(privtext);
 
-	aclitem = (AclItem *) palloc(sizeof(*aclitem));
+	aclitem = (AclItem *) palloc(sizeof(AclItem));
 
-	if (u_grantee == 0 && g_grantee == 0)
-	{
-		aclitem   ->ai_grantee = ACL_ID_WORLD;
+	aclitem->ai_grantee = grantee;
+	aclitem->ai_grantor = grantor;
 
-		ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
-	}
-	else if (u_grantee != 0 && g_grantee != 0)
-	{
-		ereport(ERROR,
-				(errcode(ERRCODE_DATA_EXCEPTION),
-				 errmsg("cannot specify both user and group")));
-	}
-	else if (u_grantee != 0)
-	{
-		aclitem   ->ai_grantee = u_grantee;
-
-		ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
-	}
-	else
-	/* (g_grantee != 0) */
-	{
-		aclitem   ->ai_grantee = g_grantee;
-
-		ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
-	}
-
-	aclitem   ->ai_grantor = grantor;
-
-	ACLITEM_SET_PRIVS(*aclitem, priv);
-	if (goption)
-		ACLITEM_SET_GOPTIONS(*aclitem, priv);
-	else
-		ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS);
+	ACLITEM_SET_PRIVS_GOPTIONS(*aclitem, priv,
+							   (goption ? priv : ACL_NO_RIGHTS));
 
 	PG_RETURN_ACLITEM_P(aclitem);
 }
@@ -1267,7 +1152,7 @@ convert_priv_string(text *priv_type_text)
  * has_table_privilege variants
  *		These are all named "has_table_privilege" at the SQL level.
  *		They take various combinations of relation name, relation OID,
- *		user name, user sysid, or implicit user = current_user.
+ *		user name, user OID, or implicit user = current_user.
  *
  *		The result is a boolean value: true if user has the indicated
  *		privilege, false if not.
@@ -1281,19 +1166,20 @@ convert_priv_string(text *priv_type_text)
 Datum
 has_table_privilege_name_name(PG_FUNCTION_ARGS)
 {
-	Name		username = PG_GETARG_NAME(0);
+	Name		rolename = PG_GETARG_NAME(0);
 	text	   *tablename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	Oid			tableoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*rolename));
+
 	tableoid = convert_table_name(tablename);
 	mode = convert_table_priv_string(priv_type_text);
 
-	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1309,16 +1195,16 @@ has_table_privilege_name(PG_FUNCTION_ARGS)
 {
 	text	   *tablename = PG_GETARG_TEXT_P(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	Oid			tableoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	tableoid = convert_table_name(tablename);
 	mode = convert_table_priv_string(priv_type_text);
 
-	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1334,14 +1220,15 @@ has_table_privilege_name_id(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	Oid			tableoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	mode = convert_table_priv_string(priv_type_text);
 
-	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1357,14 +1244,14 @@ has_table_privilege_id(PG_FUNCTION_ARGS)
 {
 	Oid			tableoid = PG_GETARG_OID(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid		roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	mode = convert_table_priv_string(priv_type_text);
 
-	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1372,12 +1259,12 @@ has_table_privilege_id(PG_FUNCTION_ARGS)
 /*
  * has_table_privilege_id_name
  *		Check user privileges on a table given
- *		usesysid, text tablename, and text priv name.
+ *		roleid, text tablename, and text priv name.
  */
 Datum
 has_table_privilege_id_name(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	text	   *tablename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	Oid			tableoid;
@@ -1387,7 +1274,7 @@ has_table_privilege_id_name(PG_FUNCTION_ARGS)
 	tableoid = convert_table_name(tablename);
 	mode = convert_table_priv_string(priv_type_text);
 
-	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1395,12 +1282,12 @@ has_table_privilege_id_name(PG_FUNCTION_ARGS)
 /*
  * has_table_privilege_id_id
  *		Check user privileges on a table given
- *		usesysid, table oid, and text priv name.
+ *		roleid, table oid, and text priv name.
  */
 Datum
 has_table_privilege_id_id(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	Oid			tableoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	AclMode		mode;
@@ -1408,7 +1295,7 @@ has_table_privilege_id_id(PG_FUNCTION_ARGS)
 
 	mode = convert_table_priv_string(priv_type_text);
 
-	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1491,7 +1378,7 @@ convert_table_priv_string(text *priv_type_text)
  * has_database_privilege variants
  *		These are all named "has_database_privilege" at the SQL level.
  *		They take various combinations of database name, database OID,
- *		user name, user sysid, or implicit user = current_user.
+ *		user name, user OID, or implicit user = current_user.
  *
  *		The result is a boolean value: true if user has the indicated
  *		privilege, false if not.
@@ -1508,16 +1395,17 @@ has_database_privilege_name_name(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	text	   *databasename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	Oid			databaseoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	databaseoid = convert_database_name(databasename);
 	mode = convert_database_priv_string(priv_type_text);
 
-	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+	aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1533,16 +1421,16 @@ has_database_privilege_name(PG_FUNCTION_ARGS)
 {
 	text	   *databasename = PG_GETARG_TEXT_P(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	Oid			databaseoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	databaseoid = convert_database_name(databasename);
 	mode = convert_database_priv_string(priv_type_text);
 
-	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+	aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1558,14 +1446,15 @@ has_database_privilege_name_id(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	Oid			databaseoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	mode = convert_database_priv_string(priv_type_text);
 
-	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+	aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1581,14 +1470,14 @@ has_database_privilege_id(PG_FUNCTION_ARGS)
 {
 	Oid			databaseoid = PG_GETARG_OID(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	mode = convert_database_priv_string(priv_type_text);
 
-	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+	aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1596,12 +1485,12 @@ has_database_privilege_id(PG_FUNCTION_ARGS)
 /*
  * has_database_privilege_id_name
  *		Check user privileges on a database given
- *		usesysid, text databasename, and text priv name.
+ *		roleid, text databasename, and text priv name.
  */
 Datum
 has_database_privilege_id_name(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	text	   *databasename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	Oid			databaseoid;
@@ -1611,7 +1500,7 @@ has_database_privilege_id_name(PG_FUNCTION_ARGS)
 	databaseoid = convert_database_name(databasename);
 	mode = convert_database_priv_string(priv_type_text);
 
-	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+	aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1619,12 +1508,12 @@ has_database_privilege_id_name(PG_FUNCTION_ARGS)
 /*
  * has_database_privilege_id_id
  *		Check user privileges on a database given
- *		usesysid, database oid, and text priv name.
+ *		roleid, database oid, and text priv name.
  */
 Datum
 has_database_privilege_id_id(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	Oid			databaseoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	AclMode		mode;
@@ -1632,7 +1521,7 @@ has_database_privilege_id_id(PG_FUNCTION_ARGS)
 
 	mode = convert_database_priv_string(priv_type_text);
 
-	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+	aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1703,7 +1592,7 @@ convert_database_priv_string(text *priv_type_text)
  * has_function_privilege variants
  *		These are all named "has_function_privilege" at the SQL level.
  *		They take various combinations of function name, function OID,
- *		user name, user sysid, or implicit user = current_user.
+ *		user name, user OID, or implicit user = current_user.
  *
  *		The result is a boolean value: true if user has the indicated
  *		privilege, false if not.
@@ -1720,16 +1609,17 @@ has_function_privilege_name_name(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	text	   *functionname = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	Oid			functionoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	functionoid = convert_function_name(functionname);
 	mode = convert_function_priv_string(priv_type_text);
 
-	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+	aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1745,16 +1635,16 @@ has_function_privilege_name(PG_FUNCTION_ARGS)
 {
 	text	   *functionname = PG_GETARG_TEXT_P(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	Oid			functionoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	functionoid = convert_function_name(functionname);
 	mode = convert_function_priv_string(priv_type_text);
 
-	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+	aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1770,14 +1660,15 @@ has_function_privilege_name_id(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	Oid			functionoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	mode = convert_function_priv_string(priv_type_text);
 
-	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+	aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1793,14 +1684,14 @@ has_function_privilege_id(PG_FUNCTION_ARGS)
 {
 	Oid			functionoid = PG_GETARG_OID(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	mode = convert_function_priv_string(priv_type_text);
 
-	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+	aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1808,12 +1699,12 @@ has_function_privilege_id(PG_FUNCTION_ARGS)
 /*
  * has_function_privilege_id_name
  *		Check user privileges on a function given
- *		usesysid, text functionname, and text priv name.
+ *		roleid, text functionname, and text priv name.
  */
 Datum
 has_function_privilege_id_name(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	text	   *functionname = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	Oid			functionoid;
@@ -1823,7 +1714,7 @@ has_function_privilege_id_name(PG_FUNCTION_ARGS)
 	functionoid = convert_function_name(functionname);
 	mode = convert_function_priv_string(priv_type_text);
 
-	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+	aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1831,12 +1722,12 @@ has_function_privilege_id_name(PG_FUNCTION_ARGS)
 /*
  * has_function_privilege_id_id
  *		Check user privileges on a function given
- *		usesysid, function oid, and text priv name.
+ *		roleid, function oid, and text priv name.
  */
 Datum
 has_function_privilege_id_id(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	Oid			functionoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	AclMode		mode;
@@ -1844,7 +1735,7 @@ has_function_privilege_id_id(PG_FUNCTION_ARGS)
 
 	mode = convert_function_priv_string(priv_type_text);
 
-	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+	aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1907,7 +1798,7 @@ convert_function_priv_string(text *priv_type_text)
  * has_language_privilege variants
  *		These are all named "has_language_privilege" at the SQL level.
  *		They take various combinations of language name, language OID,
- *		user name, user sysid, or implicit user = current_user.
+ *		user name, user OID, or implicit user = current_user.
  *
  *		The result is a boolean value: true if user has the indicated
  *		privilege, false if not.
@@ -1924,16 +1815,17 @@ has_language_privilege_name_name(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	text	   *languagename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	Oid			languageoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	languageoid = convert_language_name(languagename);
 	mode = convert_language_priv_string(priv_type_text);
 
-	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+	aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1949,16 +1841,16 @@ has_language_privilege_name(PG_FUNCTION_ARGS)
 {
 	text	   *languagename = PG_GETARG_TEXT_P(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	Oid			languageoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	languageoid = convert_language_name(languagename);
 	mode = convert_language_priv_string(priv_type_text);
 
-	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+	aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1974,14 +1866,15 @@ has_language_privilege_name_id(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	Oid			languageoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	mode = convert_language_priv_string(priv_type_text);
 
-	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+	aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -1997,14 +1890,14 @@ has_language_privilege_id(PG_FUNCTION_ARGS)
 {
 	Oid			languageoid = PG_GETARG_OID(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	mode = convert_language_priv_string(priv_type_text);
 
-	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+	aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2012,12 +1905,12 @@ has_language_privilege_id(PG_FUNCTION_ARGS)
 /*
  * has_language_privilege_id_name
  *		Check user privileges on a language given
- *		usesysid, text languagename, and text priv name.
+ *		roleid, text languagename, and text priv name.
  */
 Datum
 has_language_privilege_id_name(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	text	   *languagename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	Oid			languageoid;
@@ -2027,7 +1920,7 @@ has_language_privilege_id_name(PG_FUNCTION_ARGS)
 	languageoid = convert_language_name(languagename);
 	mode = convert_language_priv_string(priv_type_text);
 
-	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+	aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2035,12 +1928,12 @@ has_language_privilege_id_name(PG_FUNCTION_ARGS)
 /*
  * has_language_privilege_id_id
  *		Check user privileges on a language given
- *		usesysid, language oid, and text priv name.
+ *		roleid, language oid, and text priv name.
  */
 Datum
 has_language_privilege_id_id(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	Oid			languageoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	AclMode		mode;
@@ -2048,7 +1941,7 @@ has_language_privilege_id_id(PG_FUNCTION_ARGS)
 
 	mode = convert_language_priv_string(priv_type_text);
 
-	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+	aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2111,7 +2004,7 @@ convert_language_priv_string(text *priv_type_text)
  * has_schema_privilege variants
  *		These are all named "has_schema_privilege" at the SQL level.
  *		They take various combinations of schema name, schema OID,
- *		user name, user sysid, or implicit user = current_user.
+ *		user name, user OID, or implicit user = current_user.
  *
  *		The result is a boolean value: true if user has the indicated
  *		privilege, false if not.
@@ -2128,16 +2021,17 @@ has_schema_privilege_name_name(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	text	   *schemaname = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	Oid			schemaoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	schemaoid = convert_schema_name(schemaname);
 	mode = convert_schema_priv_string(priv_type_text);
 
-	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+	aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2153,16 +2047,16 @@ has_schema_privilege_name(PG_FUNCTION_ARGS)
 {
 	text	   *schemaname = PG_GETARG_TEXT_P(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	Oid			schemaoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	schemaoid = convert_schema_name(schemaname);
 	mode = convert_schema_priv_string(priv_type_text);
 
-	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+	aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2178,14 +2072,15 @@ has_schema_privilege_name_id(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	Oid			schemaoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	mode = convert_schema_priv_string(priv_type_text);
 
-	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+	aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2201,14 +2096,14 @@ has_schema_privilege_id(PG_FUNCTION_ARGS)
 {
 	Oid			schemaoid = PG_GETARG_OID(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	mode = convert_schema_priv_string(priv_type_text);
 
-	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+	aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2216,12 +2111,12 @@ has_schema_privilege_id(PG_FUNCTION_ARGS)
 /*
  * has_schema_privilege_id_name
  *		Check user privileges on a schema given
- *		usesysid, text schemaname, and text priv name.
+ *		roleid, text schemaname, and text priv name.
  */
 Datum
 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	text	   *schemaname = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	Oid			schemaoid;
@@ -2231,7 +2126,7 @@ has_schema_privilege_id_name(PG_FUNCTION_ARGS)
 	schemaoid = convert_schema_name(schemaname);
 	mode = convert_schema_priv_string(priv_type_text);
 
-	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+	aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2239,12 +2134,12 @@ has_schema_privilege_id_name(PG_FUNCTION_ARGS)
 /*
  * has_schema_privilege_id_id
  *		Check user privileges on a schema given
- *		usesysid, schema oid, and text priv name.
+ *		roleid, schema oid, and text priv name.
  */
 Datum
 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	Oid			schemaoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	AclMode		mode;
@@ -2252,7 +2147,7 @@ has_schema_privilege_id_id(PG_FUNCTION_ARGS)
 
 	mode = convert_schema_priv_string(priv_type_text);
 
-	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+	aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2319,7 +2214,7 @@ convert_schema_priv_string(text *priv_type_text)
  * has_tablespace_privilege variants
  *		These are all named "has_tablespace_privilege" at the SQL level.
  *		They take various combinations of tablespace name, tablespace OID,
- *		user name, user sysid, or implicit user = current_user.
+ *		user name, user OID, or implicit user = current_user.
  *
  *		The result is a boolean value: true if user has the indicated
  *		privilege, false if not.
@@ -2336,16 +2231,17 @@ has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	text	   *tablespacename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	Oid			tablespaceoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	tablespaceoid = convert_tablespace_name(tablespacename);
 	mode = convert_tablespace_priv_string(priv_type_text);
 
-	aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
+	aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2361,16 +2257,16 @@ has_tablespace_privilege_name(PG_FUNCTION_ARGS)
 {
 	text	   *tablespacename = PG_GETARG_TEXT_P(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid			roleid;
 	Oid			tablespaceoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	tablespaceoid = convert_tablespace_name(tablespacename);
 	mode = convert_tablespace_priv_string(priv_type_text);
 
-	aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
+	aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2386,14 +2282,15 @@ has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
 	Name		username = PG_GETARG_NAME(0);
 	Oid			tablespaceoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	int32		usesysid;
+	Oid			roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = get_usesysid(NameStr(*username));
+	roleid = get_roleid_checked(NameStr(*username));
+
 	mode = convert_tablespace_priv_string(priv_type_text);
 
-	aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
+	aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2409,14 +2306,14 @@ has_tablespace_privilege_id(PG_FUNCTION_ARGS)
 {
 	Oid			tablespaceoid = PG_GETARG_OID(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
-	AclId		usesysid;
+	Oid				roleid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	usesysid = GetUserId();
+	roleid = GetUserId();
 	mode = convert_tablespace_priv_string(priv_type_text);
 
-	aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
+	aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2424,12 +2321,12 @@ has_tablespace_privilege_id(PG_FUNCTION_ARGS)
 /*
  * has_tablespace_privilege_id_name
  *		Check user privileges on a tablespace given
- *		usesysid, text tablespacename, and text priv name.
+ *		roleid, text tablespacename, and text priv name.
  */
 Datum
 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	text	   *tablespacename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	Oid			tablespaceoid;
@@ -2439,7 +2336,7 @@ has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
 	tablespaceoid = convert_tablespace_name(tablespacename);
 	mode = convert_tablespace_priv_string(priv_type_text);
 
-	aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
+	aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2447,12 +2344,12 @@ has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
 /*
  * has_tablespace_privilege_id_id
  *		Check user privileges on a tablespace given
- *		usesysid, tablespace oid, and text priv name.
+ *		roleid, tablespace oid, and text priv name.
  */
 Datum
 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
 {
-	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	Oid			tablespaceoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	AclMode		mode;
@@ -2460,7 +2357,7 @@ has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
 
 	mode = convert_tablespace_priv_string(priv_type_text);
 
-	aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
+	aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
@@ -2515,3 +2412,110 @@ convert_tablespace_priv_string(text *priv_type_text)
 			 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
 	return ACL_NO_RIGHTS;		/* keep compiler quiet */
 }
+
+void
+InitializeAcl(void)
+{
+	if (!IsBootstrapProcessingMode())
+	{
+		/*
+		 * In normal mode, set a callback on any syscache
+		 * invalidation of pg_auth_members rows
+		 */
+		CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
+									  RolMemCacheCallback,
+									  (Datum) 0);
+
+	    /* Force role/member cache to be recomputed on next use */
+	    rolmemcacheValid = false;
+	}
+}
+
+/*
+ * RolMemCacheCallback
+ * 		Syscache inval callback function
+ */
+static void
+RolMemCacheCallback(Datum arg, Oid relid)
+{
+	    /* Force role/member cache to be recomputed on next use */
+	    rolmemcacheValid = false;
+}
+
+
+/* 
+ * recomputeRolMemCache - recompute the role/member cache if needed 
+ */
+static void
+recomputeRolMemCache(Oid roleid)
+{
+	int 		i;
+	Oid			memberOid;
+	List 		*roles_list_hunt = NIL;
+	List		*roles_list = NIL;
+	List		*newrolmemcache;
+	CatCList	*memlist;
+	MemoryContext	oldctx;
+
+	/* Do nothing if rolmemcache is already valid */
+	if (rolmemcacheValid && rolmemRole == roleid)
+		return;
+
+	if (rolmemRole != roleid)
+		rolmemcacheValid = false;
+
+	/* 
+	 * Find all the roles which this role is a member of,
+	 * including multi-level recursion
+	 */
+
+	/*
+	 * Include the current role itself to simplify checks
+	 * later on, also should be at the head so lookup should
+	 * be fast.
+	 */
+	roles_list = lappend_oid(roles_list, roleid);
+	roles_list_hunt = lappend_oid(roles_list_hunt, roleid);
+	
+	while (roles_list_hunt)
+	{
+		memberOid = linitial_oid(roles_list_hunt);
+		memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
+									 ObjectIdGetDatum(memberOid),
+									 0, 0, 0);
+		for (i = 0; i < memlist->n_members; i++) {
+			HeapTuple roletup = &memlist->members[i]->tuple;
+			Form_pg_auth_members rolemem = (Form_pg_auth_members) GETSTRUCT(roletup);
+
+			if (!list_member_oid(roles_list,rolemem->roleid)) {
+				roles_list = lappend_oid(roles_list,rolemem->roleid);
+				roles_list_hunt = lappend_oid(roles_list_hunt,rolemem->roleid);
+			}
+		}
+		roles_list_hunt = list_delete_oid(roles_list_hunt, memberOid);
+		ReleaseSysCacheList(memlist);
+	}
+
+	/*
+	 * Now that we've built the list of role Oids this
+	 * role is a member of, save it in permanent storage
+	 */
+	oldctx = MemoryContextSwitchTo(TopMemoryContext);
+	newrolmemcache = list_copy(roles_list);
+	MemoryContextSwitchTo(oldctx);
+
+	/*
+	 * Now safe to assign to state variable
+	 */
+	list_free(rolmemcache);
+	rolmemcache = newrolmemcache;
+
+	/*
+	 * Mark as valid
+	 */
+	rolmemRole = roleid;
+	rolmemcacheValid = true;
+
+	/* Clean up */
+	list_free(roles_list);
+}
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 90c8ea695bb532ddf78ae52692c55a22a5b17a64..870513fb9d512a98f413406f2a64e0b05614ce2b 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -8,14 +8,13 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.22 2005/05/11 01:41:41 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.23 2005/06/28 05:09:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/xact.h"
-#include "catalog/pg_shadow.h"
 #include "fmgr.h"
 #include "funcapi.h"
 #include "miscadmin.h"
@@ -306,7 +305,7 @@ pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
 	if (!OidIsValid(beentry->userid))
 		PG_RETURN_NULL();
 
-	PG_RETURN_INT32(beentry->userid);
+	PG_RETURN_OID(beentry->userid);
 }
 
 
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index a0d561f1f0f53ecd9a0a67b5944185f9ef537cd5..8de31643a68a93916c91a79aa4af3d957b8913fa 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -17,7 +17,7 @@
  *
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.79 2005/05/30 07:20:58 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.80 2005/06/28 05:09:00 tgl Exp $
  *
  * ----------
  */
@@ -3036,7 +3036,7 @@ ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
 {
 	void	   *qplan;
 	Relation	query_rel;
-	AclId		save_uid;
+	Oid			save_uid;
 
 	/*
 	 * The query is always run against the FK table except when this is an
@@ -3089,7 +3089,7 @@ ri_PerformCheck(RI_QueryKey *qkey, void *qplan,
 	Snapshot	crosscheck_snapshot;
 	int			limit;
 	int			spi_result;
-	AclId		save_uid;
+	Oid			save_uid;
 	Datum		vals[RI_MAX_NUMKEYS * 2];
 	char		nulls[RI_MAX_NUMKEYS * 2];
 
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 0bd1d73eae10512edb9a13c78a1ac41debfe81ef..cbebd5495c0b16a88a796c722b146c172fae0b21 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *				back to source text
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.201 2005/06/26 22:05:40 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.202 2005/06/28 05:09:01 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -46,13 +46,13 @@
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
 #include "catalog/pg_cast.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_depend.h"
 #include "catalog/pg_index.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
-#include "catalog/pg_shadow.h"
 #include "catalog/pg_trigger.h"
 #include "executor/spi.h"
 #include "funcapi.h"
@@ -1194,17 +1194,17 @@ pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags)
 
 
 /* ----------
- * get_userbyid			- Get a user name by usesysid and
- *				  fallback to 'unknown (UID=n)'
+ * get_userbyid			- Get a user name by roleid and
+ *				  fallback to 'unknown (OID=n)'
  * ----------
  */
 Datum
 pg_get_userbyid(PG_FUNCTION_ARGS)
 {
-	int32		uid = PG_GETARG_INT32(0);
+	Oid			roleid = PG_GETARG_OID(0);
 	Name		result;
-	HeapTuple	usertup;
-	Form_pg_shadow user_rec;
+	HeapTuple	roletup;
+	Form_pg_authid role_rec;
 
 	/*
 	 * Allocate space for the result
@@ -1213,19 +1213,19 @@ pg_get_userbyid(PG_FUNCTION_ARGS)
 	memset(NameStr(*result), 0, NAMEDATALEN);
 
 	/*
-	 * Get the pg_shadow entry and print the result
+	 * Get the pg_authid entry and print the result
 	 */
-	usertup = SearchSysCache(SHADOWSYSID,
-							 ObjectIdGetDatum(uid),
+	roletup = SearchSysCache(AUTHOID,
+							 ObjectIdGetDatum(roleid),
 							 0, 0, 0);
-	if (HeapTupleIsValid(usertup))
+	if (HeapTupleIsValid(roletup))
 	{
-		user_rec = (Form_pg_shadow) GETSTRUCT(usertup);
-		StrNCpy(NameStr(*result), NameStr(user_rec->usename), NAMEDATALEN);
-		ReleaseSysCache(usertup);
+		role_rec = (Form_pg_authid) GETSTRUCT(roletup);
+		StrNCpy(NameStr(*result), NameStr(role_rec->rolname), NAMEDATALEN);
+		ReleaseSysCache(roletup);
 	}
 	else
-		sprintf(NameStr(*result), "unknown (UID=%d)", uid);
+		sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
 
 	PG_RETURN_NAME(result);
 }
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 5390d94462acdf9ceb6c4fd46c29a14a0641a4ee..ea10f8c8cd3d36a6129623ebd70d02523f328e11 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.125 2005/05/01 18:56:19 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.126 2005/06/28 05:09:01 tgl Exp $
  *
  * NOTES
  *	  Eventually, the index information should go through here, too.
@@ -24,8 +24,6 @@
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
-#include "catalog/pg_shadow.h"
-#include "catalog/pg_group.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
@@ -2010,66 +2008,35 @@ get_namespace_name(Oid nspid)
 		return NULL;
 }
 
-/*				---------- PG_SHADOW CACHE ----------					 */
+/*				---------- PG_AUTHID CACHE ----------					 */
 
 /*
- * get_usesysid
- *
- *	  Given a user name, look up the user's sysid.
- *	  Raises an error if no such user (rather than returning zero,
- *	  which might possibly be a valid usesysid).
- *
- * Note: the type of usesysid is currently int4, but may change to Oid
- * someday.  It'd be reasonable to return zero on failure if we were
- * using Oid ...
+ * get_roleid
+ *	  Given a role name, look up the role's OID.
+ *	  Returns InvalidOid if no such role.
  */
-AclId
-get_usesysid(const char *username)
+Oid
+get_roleid(const char *rolname)
 {
-	AclId		userId;
-	HeapTuple	userTup;
-
-	userTup = SearchSysCache(SHADOWNAME,
-							 PointerGetDatum(username),
-							 0, 0, 0);
-	if (!HeapTupleIsValid(userTup))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("user \"%s\" does not exist", username)));
-
-	userId = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
-
-	ReleaseSysCache(userTup);
-
-	return userId;
+	return GetSysCacheOid(AUTHNAME,
+						  PointerGetDatum(rolname),
+						  0, 0, 0);
 }
 
 /*
- * get_grosysid
- *
- *	  Given a group name, look up the group's sysid.
- *	  Raises an error if no such group (rather than returning zero,
- *	  which might possibly be a valid grosysid).
- *
+ * get_roleid_checked
+ *	  Given a role name, look up the role's OID.
+ *	  ereports if no such role.
  */
-AclId
-get_grosysid(char *groname)
+Oid
+get_roleid_checked(const char *rolname)
 {
-	AclId		groupId;
-	HeapTuple	groupTup;
+	Oid		roleid;
 
-	groupTup = SearchSysCache(GRONAME,
-						   PointerGetDatum(groname),
-						   0, 0, 0);
-	if (!HeapTupleIsValid(groupTup))
+	roleid = get_roleid(rolname);
+	if (!OidIsValid(roleid))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("group \"%s\" does not exist", groname)));
-
-	groupId = ((Form_pg_group) GETSTRUCT(groupTup))->grosysid;
-
-	ReleaseSysCache(groupTup);
-
-	return groupId;
+				 errmsg("role \"%s\" does not exist", rolname)));
+	return roleid;
 }
-
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index c6cfbc5be240037a68c04fc60457f0139b2b02cb..cd24460857fb9ff2927c10028a2313c5ecc3dfb2 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.99 2005/05/11 01:26:02 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.100 2005/06/28 05:09:01 tgl Exp $
  *
  * NOTES
  *	  These routines allow the parser/planner/executor to perform
@@ -27,9 +27,10 @@
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_amop.h"
 #include "catalog/pg_amproc.h"
+#include "catalog/pg_authid.h"
+#include "catalog/pg_auth_members.h"
 #include "catalog/pg_cast.h"
 #include "catalog/pg_conversion.h"
-#include "catalog/pg_group.h"
 #include "catalog/pg_index.h"
 #include "catalog/pg_inherits.h"
 #include "catalog/pg_language.h"
@@ -38,7 +39,6 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_rewrite.h"
-#include "catalog/pg_shadow.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
 #include "utils/catcache.h"
@@ -172,6 +172,46 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0
 	}},
+	{AuthMemRelationId,				/* AUTHMEMMEMROLE */
+		AuthMemMemRoleIndexId,
+		0,
+		2,
+		{
+			Anum_pg_auth_members_member,
+			Anum_pg_auth_members_roleid,
+			0,
+			0
+	}},
+	{AuthMemRelationId,				/* AUTHMEMROLEMEM */
+		AuthMemRoleMemIndexId,
+		0,
+		2,
+		{
+			Anum_pg_auth_members_roleid,
+			Anum_pg_auth_members_member,
+			0,
+			0
+	}},
+	{AuthIdRelationId,				/* AUTHNAME */
+		AuthIdRolnameIndexId,
+		0,
+		1,
+		{
+			Anum_pg_authid_rolname,
+			0,
+			0,
+			0
+	}},
+	{AuthIdRelationId,				/* AUTHOID */
+		AuthIdOidIndexId,
+		0,
+		1,
+		{
+			ObjectIdAttributeNumber,
+			0,
+			0,
+			0
+	}},
 	{
 		CastRelationId,					/* CASTSOURCETARGET */
 		CastSourceTargetIndexId,
@@ -233,26 +273,6 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0
 	}},
-	{GroupRelationId,					/* GRONAME */
-		GroupNameIndexId,
-		0,
-		1,
-		{
-			Anum_pg_group_groname,
-			0,
-			0,
-			0
-	}},
-	{GroupRelationId,					/* GROSYSID */
-		GroupSysidIndexId,
-		0,
-		1,
-		{
-			Anum_pg_group_grosysid,
-			0,
-			0,
-			0
-	}},
 	{IndexRelationId,					/* INDEXRELID */
 		IndexRelidIndexId,
 		Anum_pg_index_indrelid,
@@ -383,26 +403,6 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0
 	}},
-	{ShadowRelationId,					/* SHADOWNAME */
-		ShadowNameIndexId,
-		0,
-		1,
-		{
-			Anum_pg_shadow_usename,
-			0,
-			0,
-			0
-	}},
-	{ShadowRelationId,					/* SHADOWSYSID */
-		ShadowSysidIndexId,
-		0,
-		1,
-		{
-			Anum_pg_shadow_usesysid,
-			0,
-			0,
-			0
-	}},
 	{StatisticRelationId,				/* STATRELATT */
 		StatisticRelidAttnumIndexId,
 		Anum_pg_statistic_starelid,
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 0733f190c2bff8e32a2540986db1a0e811b70be1..dd6134ccfd00aa57d7c6b753e1272bdc271fa245 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.95 2005/05/29 04:23:06 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.96 2005/06/28 05:09:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -769,7 +769,7 @@ fmgr_oldstyle(PG_FUNCTION_ARGS)
 struct fmgr_security_definer_cache
 {
 	FmgrInfo	flinfo;
-	AclId		userid;
+	Oid		userid;
 };
 
 /*
@@ -786,7 +786,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
 	Datum		result;
 	FmgrInfo   *save_flinfo;
 	struct fmgr_security_definer_cache * volatile fcache;
-	AclId		save_userid;
+	Oid		save_userid;
 	HeapTuple	tuple;
 
 	if (!fcinfo->flinfo->fn_extra)
diff --git a/src/backend/utils/init/flatfiles.c b/src/backend/utils/init/flatfiles.c
index fcbc99189ffd7768b2f7f5341165cc9f8ee76371..8b129692f45e6ee3513dd1504f5b4be8f0d6c8fe 100644
--- a/src/backend/utils/init/flatfiles.c
+++ b/src/backend/utils/init/flatfiles.c
@@ -4,9 +4,10 @@
  *	  Routines for maintaining "flat file" images of the shared catalogs.
  *
  * We use flat files so that the postmaster and not-yet-fully-started
- * backends can look at the contents of pg_database, pg_shadow, and pg_group
- * for authentication purposes.  This module is responsible for keeping the
- * flat-file images as nearly in sync with database reality as possible.
+ * backends can look at the contents of pg_database, pg_authid, and 
+ * pg_auth_members for authentication purposes.  This module is 
+ * responsible for keeping the flat-file images as nearly in sync with 
+ * database reality as possible.
  *
  * The tricky part of the write_xxx_file() routines in this module is that
  * they need to be able to operate in the context of the database startup
@@ -22,7 +23,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.8 2005/06/17 22:32:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.9 2005/06/28 05:09:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,12 +32,14 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "access/genam.h"
 #include "access/heapam.h"
 #include "access/twophase_rmgr.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_auth_members.h"
+#include "catalog/pg_authid.h"
 #include "catalog/pg_database.h"
-#include "catalog/pg_group.h"
 #include "catalog/pg_namespace.h"
-#include "catalog/pg_shadow.h"
 #include "catalog/pg_tablespace.h"
 #include "commands/trigger.h"
 #include "miscadmin.h"
@@ -45,19 +48,18 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/flatfiles.h"
+#include "utils/fmgroids.h"
 #include "utils/resowner.h"
 #include "utils/syscache.h"
 
 
 /* Actual names of the flat files (within $PGDATA/global/) */
 #define DATABASE_FLAT_FILE	"pg_database"
-#define GROUP_FLAT_FILE		"pg_group"
-#define USER_FLAT_FILE		"pg_pwd"
+#define AUTH_FLAT_FILE		"pg_auth"
 
 /* Info bits in a flatfiles 2PC record */
 #define FF_BIT_DATABASE	1
-#define FF_BIT_GROUP	2
-#define FF_BIT_USER		4
+#define FF_BIT_AUTH		2
 
 
 /*
@@ -73,8 +75,7 @@
  * SubTransactionId is seen at top-level commit.
  */
 static SubTransactionId database_file_update_subid = InvalidSubTransactionId;
-static SubTransactionId group_file_update_subid = InvalidSubTransactionId;
-static SubTransactionId user_file_update_subid = InvalidSubTransactionId;
+static SubTransactionId auth_file_update_subid = InvalidSubTransactionId;
 
 
 /*
@@ -88,23 +89,13 @@ database_file_update_needed(void)
 }
 
 /*
- * Mark flat group file as needing an update (because pg_group changed)
+ * Mark flat auth file as needing an update (because pg_auth changed)
  */
 void
-group_file_update_needed(void)
+auth_file_update_needed(void)
 {
-	if (group_file_update_subid == InvalidSubTransactionId)
-		group_file_update_subid = GetCurrentSubTransactionId();
-}
-
-/*
- * Mark flat user file as needing an update (because pg_shadow changed)
- */
-void
-user_file_update_needed(void)
-{
-	if (user_file_update_subid == InvalidSubTransactionId)
-		user_file_update_subid = GetCurrentSubTransactionId();
+	if (auth_file_update_subid == InvalidSubTransactionId)
+		auth_file_update_subid = GetCurrentSubTransactionId();
 }
 
 
@@ -128,39 +119,20 @@ database_getflatfilename(void)
 }
 
 /*
- * group_getflatfilename --- get full pathname of group file
- *
- * Note that result string is palloc'd, and should be freed by the caller.
- */
-char *
-group_getflatfilename(void)
-{
-	int			bufsize;
-	char	   *pfnam;
-
-	bufsize = strlen(DataDir) + strlen("/global/") +
-		strlen(GROUP_FLAT_FILE) + 1;
-	pfnam = (char *) palloc(bufsize);
-	snprintf(pfnam, bufsize, "%s/global/%s", DataDir, GROUP_FLAT_FILE);
-
-	return pfnam;
-}
-
-/*
- * Get full pathname of password file.
+ * Get full pathname of auth file.
  *
  * Note that result string is palloc'd, and should be freed by the caller.
  */
 char *
-user_getflatfilename(void)
+auth_getflatfilename(void)
 {
 	int			bufsize;
 	char	   *pfnam;
 
 	bufsize = strlen(DataDir) + strlen("/global/") +
-		strlen(USER_FLAT_FILE) + 1;
+		strlen(AUTH_FLAT_FILE) + 1;
 	pfnam = (char *) palloc(bufsize);
-	snprintf(pfnam, bufsize, "%s/global/%s", DataDir, USER_FLAT_FILE);
+	snprintf(pfnam, bufsize, "%s/global/%s", DataDir, AUTH_FLAT_FILE);
 
 	return pfnam;
 }
@@ -189,7 +161,7 @@ fputs_quote(const char *str, FILE *fp)
 /*
  * name_okay
  *
- * We must disallow newlines in user and group names because
+ * We must disallow newlines in role names because
  * hba.c's parser won't handle fields split across lines, even if quoted.
  */
 static bool
@@ -322,165 +294,81 @@ write_database_file(Relation drel)
 
 
 /*
- * write_group_file: update the flat group file
+ * Support for write_auth_file
  */
-static void
-write_group_file(Relation grel)
-{
-	char	   *filename,
-			   *tempname;
-	int			bufsize;
-	FILE	   *fp;
-	mode_t		oumask;
-	HeapScanDesc scan;
-	HeapTuple	tuple;
-
-	/*
-	 * Create a temporary filename to be renamed later.  This prevents the
-	 * backend from clobbering the flat file while the postmaster
-	 * might be reading from it.
-	 */
-	filename = group_getflatfilename();
-	bufsize = strlen(filename) + 12;
-	tempname = (char *) palloc(bufsize);
-	snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid);
-
-	oumask = umask((mode_t) 077);
-	fp = AllocateFile(tempname, "w");
-	umask(oumask);
-	if (fp == NULL)
-		ereport(ERROR,
-				(errcode_for_file_access(),
-				 errmsg("could not write to temporary file \"%s\": %m",
-						tempname)));
-
-	/*
-	 * Read pg_group and write the file.
-	 */
-	scan = heap_beginscan(grel, SnapshotNow, 0, NULL);
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
-	{
-		Form_pg_group grpform = (Form_pg_group) GETSTRUCT(tuple);
-		HeapTupleHeader tup = tuple->t_data;
-		char	   *tp;				/* ptr to tuple data */
-		long		off;			/* offset in tuple data */
-		bits8	   *bp = tup->t_bits;	/* ptr to null bitmask in tuple */
-		Datum		datum;
-		char	   *groname;
-		IdList	   *grolist_p;
-		AclId	   *aidp;
-		int			i,
-					num;
-
-		groname = NameStr(grpform->groname);
-
-		/*
-		 * Check for illegal characters in the group name.
-		 */
-		if (!name_okay(groname))
-		{
-			ereport(LOG,
-					(errmsg("invalid group name \"%s\"", groname)));
-			continue;
-		}
-
-		/*
-		 * We can't use heap_getattr() here because during startup we will
-		 * not have any tupdesc for pg_group.  Fortunately it's not too
-		 * hard to work around this.  grolist is the first possibly-null
-		 * field so we can compute its offset directly.
-		 */
-		tp = (char *) tup + tup->t_hoff;
-		off = offsetof(FormData_pg_group, grolist);
-
-		if (HeapTupleHasNulls(tuple) &&
-			att_isnull(Anum_pg_group_grolist - 1, bp))
-		{
-			/* grolist is null, so we can ignore this group */
-			continue;
-		}
-
-		/* assume grolist is pass-by-ref */
-		datum = PointerGetDatum(tp + off);
-
-		/*
-		 * We can't currently support out-of-line toasted group lists in
-		 * startup mode (the tuptoaster won't work).  This sucks, but it
-		 * should be something of a corner case.  Live with it until we
-		 * can redesign pg_group.
-		 *
-		 * Detect startup mode by noting whether we got a tupdesc.
-		 */
-		if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)) &&
-			RelationGetDescr(grel) == NULL)
-			continue;
 
-		/* be sure the IdList is not toasted */
-		grolist_p = DatumGetIdListP(datum);
+typedef struct {
+	Oid			roleid;
+	char*		rolname;
+	char*		rolpassword;
+	char*		rolvaliduntil;
+	List*		roles_names;
+} auth_entry;
+
+typedef struct {
+	Oid			roleid;
+	Oid			memberid;
+} authmem_entry;
+
+static int
+oid_compar(const void *a, const void *b)
+{
+	const auth_entry *a_auth = (const auth_entry*) a;
+	const auth_entry *b_auth = (const auth_entry*) b;
 
-		/*
-		 * The file format is: "groupname"    usesysid1 usesysid2 ...
-		 *
-		 * We ignore groups that have no members.
-		 */
-		aidp = IDLIST_DAT(grolist_p);
-		num = IDLIST_NUM(grolist_p);
-		if (num > 0)
-		{
-			fputs_quote(groname, fp);
-			fprintf(fp, "\t%u", aidp[0]);
-			for (i = 1; i < num; ++i)
-				fprintf(fp, " %u", aidp[i]);
-			fputs("\n", fp);
-		}
+	if (a_auth->roleid < b_auth->roleid) return -1;
+	if (a_auth->roleid > b_auth->roleid) return 1;
+	return 0;
+}
 
-		/* if IdList was toasted, free detoasted copy */
-		if ((Pointer) grolist_p != DatumGetPointer(datum))
-			pfree(grolist_p);
-	}
-	heap_endscan(scan);
+static int
+name_compar(const void *a, const void *b)
+{
+	const auth_entry *a_auth = (const auth_entry*) a;
+	const auth_entry *b_auth = (const auth_entry*) b;
 
-	if (FreeFile(fp))
-		ereport(ERROR,
-				(errcode_for_file_access(),
-				 errmsg("could not write to temporary file \"%s\": %m",
-						tempname)));
+	return strcmp(a_auth->rolname,b_auth->rolname);
+}
 
-	/*
-	 * Rename the temp file to its final name, deleting the old flat file.
-	 * We expect that rename(2) is an atomic action.
-	 */
-	if (rename(tempname, filename))
-		ereport(ERROR,
-				(errcode_for_file_access(),
-				 errmsg("could not rename file \"%s\" to \"%s\": %m",
-						tempname, filename)));
+static int
+mem_compar(const void *a, const void *b)
+{
+	const authmem_entry *a_auth = (const authmem_entry*) a;
+	const authmem_entry *b_auth = (const authmem_entry*) b;
 
-	pfree(tempname);
-	pfree(filename);
+	if (a_auth->memberid < b_auth->memberid) return -1;
+	if (a_auth->memberid > b_auth->memberid) return 1;
+	return 0;
 }
 
-
 /*
- * write_user_file: update the flat password file
+ * write_auth_file: update the flat auth file
  */
 static void
-write_user_file(Relation urel)
+write_auth_file(Relation rel_auth, Relation rel_authmem, bool startup)
 {
 	char	   *filename,
 			   *tempname;
 	int			bufsize;
+	BlockNumber	totalblocks;
 	FILE	   *fp;
 	mode_t		oumask;
 	HeapScanDesc scan;
 	HeapTuple	tuple;
+	int			curr_role = 0;
+	int			total_roles = 0;
+	int			curr_mem = 0;
+	int			total_mem = 0;
+	int			est_rows;
+	auth_entry  *auth_info;
+	authmem_entry  *authmem_info = NULL;
 
 	/*
 	 * Create a temporary filename to be renamed later.  This prevents the
-	 * backend from clobbering the flat file while the postmaster might
+	 * backend from clobbering the pg_auth file while the postmaster might
 	 * be reading from it.
 	 */
-	filename = user_getflatfilename();
+	filename = auth_getflatfilename();
 	bufsize = strlen(filename) + 12;
 	tempname = (char *) palloc(bufsize);
 	snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid);
@@ -495,39 +383,41 @@ write_user_file(Relation urel)
 						tempname)));
 
 	/*
-	 * Read pg_shadow and write the file.
+	 * Read pg_authid and fill temporary data structures.
 	 */
-	scan = heap_beginscan(urel, SnapshotNow, 0, NULL);
+	totalblocks = RelationGetNumberOfBlocks(rel_auth);
+	totalblocks = totalblocks ? totalblocks : 1;
+	est_rows = totalblocks * (BLCKSZ / (sizeof(HeapTupleHeaderData)+sizeof(FormData_pg_authid)));
+	auth_info = (auth_entry*) palloc(est_rows*sizeof(auth_entry));
+
+	scan = heap_beginscan(rel_auth, SnapshotNow, 0, NULL);
 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
 	{
-		Form_pg_shadow pwform = (Form_pg_shadow) GETSTRUCT(tuple);
+		Form_pg_authid pwform = (Form_pg_authid) GETSTRUCT(tuple);
 		HeapTupleHeader tup = tuple->t_data;
 		char	   *tp;				/* ptr to tuple data */
 		long		off;			/* offset in tuple data */
 		bits8	   *bp = tup->t_bits;	/* ptr to null bitmask in tuple */
 		Datum		datum;
-		char	   *usename,
-				   *passwd,
-				   *valuntil;
-		AclId		usesysid;
 
-		usename = NameStr(pwform->usename);
-		usesysid = pwform->usesysid;
+		auth_info[curr_role].roleid = HeapTupleGetOid(tuple);
+		auth_info[curr_role].rolname = pstrdup(NameStr(pwform->rolname));
+		auth_info[curr_role].roles_names = NIL;
 
 		/*
 		 * We can't use heap_getattr() here because during startup we will
-		 * not have any tupdesc for pg_shadow.  Fortunately it's not too
-		 * hard to work around this.  passwd is the first possibly-null
+		 * not have any tupdesc for pg_authid.  Fortunately it's not too
+		 * hard to work around this.  rolpassword is the first possibly-null
 		 * field so we can compute its offset directly.
 		 */
 		tp = (char *) tup + tup->t_hoff;
-		off = offsetof(FormData_pg_shadow, passwd);
+		off = offsetof(FormData_pg_authid, rolpassword);
 
 		if (HeapTupleHasNulls(tuple) &&
-			att_isnull(Anum_pg_shadow_passwd - 1, bp))
+			att_isnull(Anum_pg_authid_rolpassword - 1, bp))
 		{
 			/* passwd is null, emit as an empty string */
-			passwd = pstrdup("");
+			auth_info[curr_role].rolpassword = pstrdup("");
 		}
 		else
 		{
@@ -539,59 +429,175 @@ write_user_file(Relation urel)
 			 * if it is, ignore it, since we can't handle that in startup mode.
 			 */
 			if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)))
-				passwd = pstrdup("");
+				auth_info[curr_role].rolpassword = pstrdup("");
 			else
-				passwd = DatumGetCString(DirectFunctionCall1(textout, datum));
+				auth_info[curr_role].rolpassword = DatumGetCString(DirectFunctionCall1(textout, datum));
 
 			/* assume passwd has attlen -1 */
 			off = att_addlength(off, -1, tp + off);
 		}
 
 		if (HeapTupleHasNulls(tuple) &&
-			att_isnull(Anum_pg_shadow_valuntil - 1, bp))
+			att_isnull(Anum_pg_authid_rolvaliduntil - 1, bp))
 		{
-			/* valuntil is null, emit as an empty string */
-			valuntil = pstrdup("");
+			/* rolvaliduntil is null, emit as an empty string */
+			auth_info[curr_role].rolvaliduntil = pstrdup("");
 		}
 		else
 		{
-			/* assume valuntil has attalign 'i' */
-			off = att_align(off, 'i');
-			/* assume valuntil is pass-by-value, integer size */
-			datum = Int32GetDatum(*((int32 *) (tp + off)));
-			valuntil = DatumGetCString(DirectFunctionCall1(abstimeout, datum));
+			/*
+			 * rolvaliduntil is timestamptz, which we assume is double
+			 * alignment and pass-by-reference.
+			 */
+			off = att_align(off, 'd');
+			datum = PointerGetDatum(tp + off);
+			auth_info[curr_role].rolvaliduntil = DatumGetCString(DirectFunctionCall1(timestamptz_out, datum));
 		}
 
 		/*
 		 * Check for illegal characters in the user name and password.
 		 */
-		if (!name_okay(usename))
+		if (!name_okay(auth_info[curr_role].rolname))
 		{
 			ereport(LOG,
-					(errmsg("invalid user name \"%s\"", usename)));
+					(errmsg("invalid role name \"%s\"",
+							auth_info[curr_role].rolname)));
+			pfree(auth_info[curr_role].rolname);
+			pfree(auth_info[curr_role].rolpassword);
+			pfree(auth_info[curr_role].rolvaliduntil);
 			continue;
 		}
-		if (!name_okay(passwd))
+		if (!name_okay(auth_info[curr_role].rolpassword))
 		{
 			ereport(LOG,
-					(errmsg("invalid user password \"%s\"", passwd)));
+					(errmsg("invalid role password \"%s\"",
+							auth_info[curr_role].rolpassword)));
+			pfree(auth_info[curr_role].rolname);
+			pfree(auth_info[curr_role].rolpassword);
+			pfree(auth_info[curr_role].rolvaliduntil);
 			continue;
 		}
 
-		/*
-		 * The file format is: "usename" usesysid "passwd" "valuntil"
+		curr_role++;
+		total_roles++;
+	}
+	heap_endscan(scan);
+
+	Assert(total_roles <= est_rows);
+
+	qsort(auth_info, total_roles, sizeof(auth_entry), oid_compar);
+
+	/*
+	 * Read pg_auth_members into temporary data structure, too
+	 */
+	totalblocks = RelationGetNumberOfBlocks(rel_authmem);
+	totalblocks = totalblocks ? totalblocks : 1;
+	est_rows = totalblocks * (BLCKSZ / (sizeof(HeapTupleHeaderData)+sizeof(FormData_pg_auth_members)));
+	authmem_info = (authmem_entry*) palloc(est_rows*sizeof(authmem_entry));
+
+	scan = heap_beginscan(rel_authmem, SnapshotNow, 0, NULL);
+	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	{
+		Form_pg_auth_members memform = (Form_pg_auth_members) GETSTRUCT(tuple);
+
+		authmem_info[curr_mem].roleid = memform->roleid;
+		authmem_info[curr_mem].memberid = memform->member;
+		curr_mem++;
+		total_mem++;
+	}
+	heap_endscan(scan);
+
+	Assert(total_mem <= est_rows);
+
+	qsort(authmem_info, total_mem, sizeof(authmem_entry), mem_compar);
+
+	for (curr_role = 0; curr_role < total_roles; curr_role++)
+	{
+		int		first_found, last_found, curr_mem;
+		List	*roles_list_hunt = NIL;
+		List	*roles_list = NIL;
+		ListCell *mem = NULL;
+		auth_entry *found_role = NULL, key_auth;
+		authmem_entry key;
+		authmem_entry *found_mem = NULL;
+
+		roles_list_hunt = lappend_oid(roles_list_hunt,
+									  auth_info[curr_role].roleid);
+
+		while (roles_list_hunt)
+		{
+			key.memberid = linitial_oid(roles_list_hunt);
+			roles_list_hunt = list_delete_first(roles_list_hunt);
+			if (total_mem)
+				found_mem = bsearch(&key, authmem_info, total_mem,
+									sizeof(authmem_entry), mem_compar);
+			if (found_mem)
+			{
+				/*
+				 * bsearch found a match for us; but if there were multiple
+				 * matches it could have found any one of them.
+				 */
+				first_found = last_found = (found_mem - authmem_info);
+				while (first_found > 0 &&
+					   mem_compar(&key, &authmem_info[first_found - 1]) == 0)
+					first_found--;
+				while (last_found + 1 < total_mem &&
+					   mem_compar(&key, &authmem_info[last_found + 1]) == 0)
+					last_found++;
+
+				for (curr_mem = first_found; curr_mem <= last_found; curr_mem++)
+				{
+					Oid	otherrole = authmem_info[curr_mem].roleid;
+
+					if (!list_member_oid(roles_list, otherrole))
+					{
+						roles_list = lappend_oid(roles_list,
+												 otherrole);
+						roles_list_hunt = lappend_oid(roles_list_hunt,
+													  otherrole);
+					}
+				}
+			}
+		}
+
+		foreach(mem, roles_list)
+		{
+			key_auth.roleid = lfirst_oid(mem);
+			found_role = bsearch(&key_auth, auth_info, total_roles, sizeof(auth_entry), oid_compar);
+			auth_info[curr_role].roles_names = lappend(auth_info[curr_role].roles_names,found_role->rolname);
+		}
+	}
+
+	qsort(auth_info, total_roles, sizeof(auth_entry), name_compar);
+
+	for (curr_role = 0; curr_role < total_roles; curr_role++)
+	{
+		ListCell *mem = NULL;
+
+		/*----------
+		 * The file format is:
+		 *	"rolename" "password" "validuntil" "member" "member" ...
+		 * where lines are expected to be in order by rolename
+		 *----------
 		 */
-		fputs_quote(usename, fp);
-		fprintf(fp, " %u ", usesysid);
-		fputs_quote(passwd, fp);
+		fputs_quote(auth_info[curr_role].rolname, fp);
+		fputs(" ", fp);
+		fputs_quote(auth_info[curr_role].rolpassword, fp);
 		fputs(" ", fp);
-		fputs_quote(valuntil, fp);
+		fputs_quote(auth_info[curr_role].rolvaliduntil, fp);
+
+		foreach(mem, auth_info[curr_role].roles_names)
+		{
+			fputs(" ", fp);
+			fputs_quote(lfirst(mem), fp);
+		}
+
 		fputs("\n", fp);
 
-		pfree(passwd);
-		pfree(valuntil);
+		pfree(auth_info[curr_role].rolname);
+		pfree(auth_info[curr_role].rolpassword);
+		pfree(auth_info[curr_role].rolvaliduntil);
 	}
-	heap_endscan(scan);
 
 	if (FreeFile(fp))
 		ereport(ERROR,
@@ -609,6 +615,8 @@ write_user_file(Relation urel)
 				 errmsg("could not rename file \"%s\" to \"%s\": %m",
 						tempname, filename)));
 
+	pfree(auth_info);
+	pfree(authmem_info);
 	pfree(tempname);
 	pfree(filename);
 }
@@ -634,7 +642,7 @@ BuildFlatFiles(bool database_only)
 {
 	ResourceOwner owner;
 	RelFileNode rnode;
-	Relation	rel;
+	Relation	rel, rel_auth, rel_authmem;
 
 	/*
 	 * We don't have any hope of running a real relcache, but we can use
@@ -657,21 +665,16 @@ BuildFlatFiles(bool database_only)
 
 	if (!database_only)
 	{
-		/* hard-wired path to pg_group */
+		/* hard-wired path to pg_auth */
 		rnode.spcNode = GLOBALTABLESPACE_OID;
 		rnode.dbNode = 0;
-		rnode.relNode = GroupRelationId;
+		rnode.relNode = AuthIdRelationId;
+		rel_auth = XLogOpenRelation(rnode);
 
-		rel = XLogOpenRelation(rnode);
-		write_group_file(rel);
-
-		/* hard-wired path to pg_shadow */
 		rnode.spcNode = GLOBALTABLESPACE_OID;
 		rnode.dbNode = 0;
-		rnode.relNode = ShadowRelationId;
-
-		rel = XLogOpenRelation(rnode);
-		write_user_file(rel);
+		rnode.relNode = AuthMemRelationId;
+		rel_authmem = XLogOpenRelation(rnode);
 	}
 
 	CurrentResourceOwner = NULL;
@@ -699,19 +702,17 @@ void
 AtEOXact_UpdateFlatFiles(bool isCommit)
 {
 	Relation	drel = NULL;
-	Relation	grel = NULL;
-	Relation	urel = NULL;
+	Relation	arel = NULL;
+	Relation	mrel = NULL;
 
 	if (database_file_update_subid == InvalidSubTransactionId &&
-		group_file_update_subid == InvalidSubTransactionId &&
-		user_file_update_subid == InvalidSubTransactionId)
+		auth_file_update_subid == InvalidSubTransactionId)
 		return;					/* nothing to do */
 
 	if (!isCommit)
 	{
 		database_file_update_subid = InvalidSubTransactionId;
-		group_file_update_subid = InvalidSubTransactionId;
-		user_file_update_subid = InvalidSubTransactionId;
+		auth_file_update_subid = InvalidSubTransactionId;
 		return;
 	}
 
@@ -731,10 +732,10 @@ AtEOXact_UpdateFlatFiles(bool isCommit)
 	 */
 	if (database_file_update_subid != InvalidSubTransactionId)
 		drel = heap_open(DatabaseRelationId, ExclusiveLock);
-	if (group_file_update_subid != InvalidSubTransactionId)
-		grel = heap_open(GroupRelationId, ExclusiveLock);
-	if (user_file_update_subid != InvalidSubTransactionId)
-		urel = heap_open(ShadowRelationId, ExclusiveLock);
+	if (auth_file_update_subid != InvalidSubTransactionId) {
+		arel = heap_open(AuthIdRelationId, ExclusiveLock);
+		mrel = heap_open(AuthMemRelationId, ExclusiveLock);
+	}
 
 	/* Okay to write the files */
 	if (database_file_update_subid != InvalidSubTransactionId)
@@ -744,18 +745,12 @@ AtEOXact_UpdateFlatFiles(bool isCommit)
 		heap_close(drel, NoLock);
 	}
 
-	if (group_file_update_subid != InvalidSubTransactionId)
-	{
-		group_file_update_subid = InvalidSubTransactionId;
-		write_group_file(grel);
-		heap_close(grel, NoLock);
-	}
-
-	if (user_file_update_subid != InvalidSubTransactionId)
+	if (auth_file_update_subid != InvalidSubTransactionId)
 	{
-		user_file_update_subid = InvalidSubTransactionId;
-		write_user_file(urel);
-		heap_close(urel, NoLock);
+		auth_file_update_subid = InvalidSubTransactionId;
+		write_auth_file(arel, mrel, false);
+		heap_close(arel, NoLock);
+		heap_close(mrel, NoLock);
 	}
 
 	/*
@@ -785,15 +780,10 @@ AtPrepare_UpdateFlatFiles(void)
 		database_file_update_subid = InvalidSubTransactionId;
 		info |= FF_BIT_DATABASE;
 	}
-	if (group_file_update_subid != InvalidSubTransactionId)
-	{
-		group_file_update_subid = InvalidSubTransactionId;
-		info |= FF_BIT_GROUP;
-	}
-	if (user_file_update_subid != InvalidSubTransactionId)
+	if (auth_file_update_subid != InvalidSubTransactionId)
 	{
-		user_file_update_subid = InvalidSubTransactionId;
-		info |= FF_BIT_USER;
+		auth_file_update_subid = InvalidSubTransactionId;
+		info |= FF_BIT_AUTH;
 	}
 	if (info != 0)
 		RegisterTwoPhaseRecord(TWOPHASE_RM_FLATFILES_ID, info,
@@ -817,29 +807,23 @@ AtEOSubXact_UpdateFlatFiles(bool isCommit,
 		if (database_file_update_subid == mySubid)
 			database_file_update_subid = parentSubid;
 
-		if (group_file_update_subid == mySubid)
-			group_file_update_subid = parentSubid;
-
-		if (user_file_update_subid == mySubid)
-			user_file_update_subid = parentSubid;
+		if (auth_file_update_subid == mySubid)
+			auth_file_update_subid = parentSubid;
 	}
 	else
 	{
 		if (database_file_update_subid == mySubid)
 			database_file_update_subid = InvalidSubTransactionId;
 
-		if (group_file_update_subid == mySubid)
-			group_file_update_subid = InvalidSubTransactionId;
-
-		if (user_file_update_subid == mySubid)
-			user_file_update_subid = InvalidSubTransactionId;
+		if (auth_file_update_subid == mySubid)
+			auth_file_update_subid = InvalidSubTransactionId;
 	}
 }
 
 
 /*
- * This trigger is fired whenever someone modifies pg_database, pg_shadow
- * or pg_group via general-purpose INSERT/UPDATE/DELETE commands.
+ * This trigger is fired whenever someone modifies pg_database, pg_authid
+ * or pg_auth_members via general-purpose INSERT/UPDATE/DELETE commands.
  *
  * It is sufficient for this to be a STATEMENT trigger since we don't
  * care which individual rows changed.  It doesn't much matter whether
@@ -862,11 +846,11 @@ flatfile_update_trigger(PG_FUNCTION_ARGS)
 		case DatabaseRelationId:
 			database_file_update_needed();
 			break;
-		case GroupRelationId:
-			group_file_update_needed();
+		case AuthIdRelationId:
+			auth_file_update_needed();
 			break;
-		case ShadowRelationId:
-			user_file_update_needed();
+		case AuthMemRelationId:
+			auth_file_update_needed();
 			break;
 		default:
 			elog(ERROR, "flatfile_update_trigger was called for wrong table");
@@ -895,8 +879,6 @@ flatfile_twophase_postcommit(TransactionId xid, uint16 info,
 	 */
 	if (info & FF_BIT_DATABASE)
 		database_file_update_needed();
-	if (info & FF_BIT_GROUP)
-		group_file_update_needed();
-	if (info & FF_BIT_USER)
-		user_file_update_needed();
+	if (info & FF_BIT_AUTH)
+		auth_file_update_needed();
 }
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 508c56e1e03c5f066a64898c8c723d495435b49d..1db2992899697a9d9a1e7be841f284d223e0cef0 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.142 2005/06/20 02:17:30 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.143 2005/06/28 05:09:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,7 +29,7 @@
 #include <utime.h>
 #endif
 
-#include "catalog/pg_shadow.h"
+#include "catalog/pg_authid.h"
 #include "libpq/libpq-be.h"
 #include "miscadmin.h"
 #include "storage/fd.h"
@@ -251,7 +251,7 @@ make_absolute_path(const char *path)
 
 
 /* ----------------------------------------------------------------
- *	User ID things
+ *	Role ID things
  *
  * The authenticated user is determined at connection start and never
  * changes.  The session user can be changed only by SET SESSION
@@ -261,60 +261,60 @@ make_absolute_path(const char *path)
  * restore the current user id if you need to change it.
  * ----------------------------------------------------------------
  */
-static AclId AuthenticatedUserId = 0;
-static AclId SessionUserId = 0;
-static AclId CurrentUserId = 0;
+static Oid AuthenticatedUserId = InvalidOid;
+static Oid SessionUserId = InvalidOid;
+static Oid CurrentUserId = InvalidOid;
 
 static bool AuthenticatedUserIsSuperuser = false;
 
 /*
  * This function is relevant for all privilege checks.
  */
-AclId
+Oid
 GetUserId(void)
 {
-	AssertState(AclIdIsValid(CurrentUserId));
+	AssertState(OidIsValid(CurrentUserId));
 	return CurrentUserId;
 }
 
 
 void
-SetUserId(AclId newid)
+SetUserId(Oid roleid)
 {
-	AssertArg(AclIdIsValid(newid));
-	CurrentUserId = newid;
+	AssertArg(OidIsValid(roleid));
+	CurrentUserId = roleid;
 }
 
 
 /*
  * This value is only relevant for informational purposes.
  */
-AclId
+Oid
 GetSessionUserId(void)
 {
-	AssertState(AclIdIsValid(SessionUserId));
+	AssertState(OidIsValid(SessionUserId));
 	return SessionUserId;
 }
 
 
 void
-SetSessionUserId(AclId newid)
+SetSessionUserId(Oid roleid)
 {
-	AssertArg(AclIdIsValid(newid));
-	SessionUserId = newid;
+	AssertArg(OidIsValid(roleid));
+	SessionUserId = roleid;
 	/* Current user defaults to session user. */
-	if (!AclIdIsValid(CurrentUserId))
-		CurrentUserId = newid;
+	if (!OidIsValid(CurrentUserId))
+		CurrentUserId = roleid;
 }
 
 
 void
-InitializeSessionUserId(const char *username)
+InitializeSessionUserId(const char *rolename)
 {
-	HeapTuple	userTup;
+	HeapTuple	roleTup;
 	Datum		datum;
 	bool		isnull;
-	AclId		usesysid;
+	Oid			roleid;
 
 	/*
 	 * Don't do scans if we're bootstrapping, none of the system catalogs
@@ -325,23 +325,23 @@ InitializeSessionUserId(const char *username)
 	/* call only once */
 	AssertState(!OidIsValid(AuthenticatedUserId));
 
-	userTup = SearchSysCache(SHADOWNAME,
-							 PointerGetDatum(username),
+	roleTup = SearchSysCache(AUTHNAME,
+							 PointerGetDatum(rolename),
 							 0, 0, 0);
-	if (!HeapTupleIsValid(userTup))
+	if (!HeapTupleIsValid(roleTup))
 		ereport(FATAL,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("user \"%s\" does not exist", username)));
+				 errmsg("role \"%s\" does not exist", rolename)));
 
-	usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
+	roleid = HeapTupleGetOid(roleTup);
 
-	AuthenticatedUserId = usesysid;
-	AuthenticatedUserIsSuperuser = ((Form_pg_shadow) GETSTRUCT(userTup))->usesuper;
+	AuthenticatedUserId = roleid;
+	AuthenticatedUserIsSuperuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
 
-	SetSessionUserId(usesysid); /* sets CurrentUserId too */
+	SetSessionUserId(roleid);	/* sets CurrentUserId too */
 
 	/* Record username and superuser status as GUC settings too */
-	SetConfigOption("session_authorization", username,
+	SetConfigOption("session_authorization", rolename,
 					PGC_BACKEND, PGC_S_OVERRIDE);
 	SetConfigOption("is_superuser",
 					AuthenticatedUserIsSuperuser ? "on" : "off",
@@ -349,11 +349,11 @@ InitializeSessionUserId(const char *username)
 
 	/*
 	 * 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 session
+	 * to do it so we don't have to read pg_authid twice during session
 	 * startup.
 	 */
-	datum = SysCacheGetAttr(SHADOWNAME, userTup,
-							Anum_pg_shadow_useconfig, &isnull);
+	datum = SysCacheGetAttr(AUTHNAME, roleTup,
+							Anum_pg_authid_rolconfig, &isnull);
 	if (!isnull)
 	{
 		ArrayType  *a = DatumGetArrayTypeP(datum);
@@ -361,7 +361,7 @@ InitializeSessionUserId(const char *username)
 		ProcessGUCArray(a, PGC_S_USER);
 	}
 
-	ReleaseSysCache(userTup);
+	ReleaseSysCache(roleTup);
 }
 
 
@@ -374,10 +374,10 @@ InitializeSessionUserIdStandalone(void)
 	/* call only once */
 	AssertState(!OidIsValid(AuthenticatedUserId));
 
-	AuthenticatedUserId = BOOTSTRAP_USESYSID;
+	AuthenticatedUserId = BOOTSTRAP_SUPERUSERID;
 	AuthenticatedUserIsSuperuser = true;
 
-	SetSessionUserId(BOOTSTRAP_USESYSID);
+	SetSessionUserId(BOOTSTRAP_SUPERUSERID);
 }
 
 
@@ -390,19 +390,19 @@ InitializeSessionUserIdStandalone(void)
  * to indicate whether the *current* session userid is a superuser.
  */
 void
-SetSessionAuthorization(AclId userid, bool is_superuser)
+SetSessionAuthorization(Oid roleid, bool is_superuser)
 {
 	/* Must have authenticated already, else can't make permission check */
-	AssertState(AclIdIsValid(AuthenticatedUserId));
+	AssertState(OidIsValid(AuthenticatedUserId));
 
-	if (userid != AuthenticatedUserId &&
+	if (roleid != AuthenticatedUserId &&
 		!AuthenticatedUserIsSuperuser)
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 			  errmsg("permission denied to set session authorization")));
 
-	SetSessionUserId(userid);
-	SetUserId(userid);
+	SetSessionUserId(roleid);
+	SetUserId(roleid);
 
 	SetConfigOption("is_superuser",
 					is_superuser ? "on" : "off",
@@ -411,30 +411,29 @@ SetSessionAuthorization(AclId userid, bool is_superuser)
 
 
 /*
- * Get user name from user id
+ * Get user name from user oid
  */
 char *
-GetUserNameFromId(AclId userid)
+GetUserNameFromId(Oid roleid)
 {
 	HeapTuple	tuple;
 	char	   *result;
 
-	tuple = SearchSysCache(SHADOWSYSID,
-						   ObjectIdGetDatum(userid),
+	tuple = SearchSysCache(AUTHOID,
+						   ObjectIdGetDatum(roleid),
 						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("invalid user ID: %d", userid)));
+				 errmsg("invalid role OID: %u", roleid)));
 
-	result = pstrdup(NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename));
+	result = pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
 
 	ReleaseSysCache(tuple);
 	return result;
 }
 
 
-
 /*-------------------------------------------------------------------------
  *				Interlock-file support
  *
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 1836aee81d7f0881df05febf174c62df25ad808e..9baacacfffd9400341ead1dbb5869bcab58f23c5 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.149 2005/06/24 01:06:26 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.150 2005/06/28 05:09:02 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -20,11 +20,11 @@
 #include <math.h>
 #include <unistd.h>
 
-#include "catalog/catalog.h"
 #include "access/heapam.h"
+#include "catalog/catalog.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
 #include "catalog/pg_database.h"
-#include "catalog/pg_shadow.h"
 #include "catalog/pg_tablespace.h"
 #include "libpq/hba.h"
 #include "mb/pg_wchar.h"
@@ -37,6 +37,7 @@
 #include "storage/procarray.h"
 #include "storage/sinval.h"
 #include "storage/smgr.h"
+#include "utils/acl.h"
 #include "utils/flatfiles.h"
 #include "utils/fmgroids.h"
 #include "utils/guc.h"
@@ -49,7 +50,7 @@ static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);
 static void ReverifyMyDatabase(const char *name);
 static void InitCommunication(void);
 static void ShutdownPostgres(int code, Datum arg);
-static bool ThereIsAtLeastOneUser(void);
+static bool ThereIsAtLeastOneRole(void);
 
 
 /*** InitPostgres support ***/
@@ -415,12 +416,12 @@ InitPostgres(const char *dbname, const char *username)
 	else if (!IsUnderPostmaster)
 	{
 		InitializeSessionUserIdStandalone();
-		if (!ThereIsAtLeastOneUser())
+		if (!ThereIsAtLeastOneRole())
 			ereport(WARNING,
 					(errcode(ERRCODE_UNDEFINED_OBJECT),
-				  errmsg("no users are defined in this database system"),
-					 errhint("You should immediately run CREATE USER \"%s\" WITH SYSID %d CREATEUSER;.",
-							 username, BOOTSTRAP_USESYSID)));
+					 errmsg("no roles are defined in this database system"),
+					 errhint("You should immediately run CREATE USER \"%s\" CREATEUSER;.",
+							 username)));
 	}
 	else
 	{
@@ -469,6 +470,9 @@ InitPostgres(const char *dbname, const char *username)
 	/* set default namespace search path */
 	InitializeSearchPath();
 
+	/* set up ACL framework (currently just sets RolMemCache callback) */
+	InitializeAcl();
+
 	/* initialize client encoding */
 	InitializeClientEncoding();
 
@@ -530,22 +534,22 @@ ShutdownPostgres(int code, Datum arg)
 
 
 /*
- * Returns true if at least one user is defined in this database cluster.
+ * Returns true if at least one role is defined in this database cluster.
  */
 static bool
-ThereIsAtLeastOneUser(void)
+ThereIsAtLeastOneRole(void)
 {
-	Relation	pg_shadow_rel;
+	Relation	pg_authid_rel;
 	HeapScanDesc scan;
 	bool		result;
 
-	pg_shadow_rel = heap_open(ShadowRelationId, AccessExclusiveLock);
+	pg_authid_rel = heap_open(AuthIdRelationId, AccessExclusiveLock);
 
-	scan = heap_beginscan(pg_shadow_rel, SnapshotNow, 0, NULL);
+	scan = heap_beginscan(pg_authid_rel, SnapshotNow, 0, NULL);
 	result = (heap_getnext(scan, ForwardScanDirection) != NULL);
 
 	heap_endscan(scan);
-	heap_close(pg_shadow_rel, AccessExclusiveLock);
+	heap_close(pg_authid_rel, AccessExclusiveLock);
 
 	return result;
 }
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0ab8e742336ae1eabdf6b16d313ea40a41856e09..84d8085503a7603df2a2588a98fbcbc64ee0259b 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.270 2005/06/26 19:16:06 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.271 2005/06/28 05:09:02 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -5108,7 +5108,7 @@ ParseLongOption(const char *string, char **name, char **value)
 
 
 /*
- * Handle options fetched from pg_database.datconfig or pg_shadow.useconfig.
+ * Handle options fetched from pg_database.datconfig or pg_authid.rolconfig.
  * The array parameter must be an array of TEXT (it must not be NULL).
  */
 void
@@ -5154,7 +5154,7 @@ ProcessGUCArray(ArrayType *array, GucSource source)
 
 		/*
 		 * We process all these options at SUSET level.  We assume that
-		 * the right to insert an option into pg_database or pg_shadow was
+		 * the right to insert an option into pg_database or pg_authid was
 		 * checked when it was inserted.
 		 */
 		SetConfigOption(name, value, PGC_SUSET, source);
diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c
index 520dc470cdcef7e6cab563bdc86a3e8425b1466b..9e965b8107f72420c88b87e8478d6655f281b574 100644
--- a/src/backend/utils/misc/superuser.c
+++ b/src/backend/utils/misc/superuser.c
@@ -14,29 +14,29 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.31 2005/05/29 20:38:06 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.32 2005/06/28 05:09:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include "catalog/pg_shadow.h"
+#include "catalog/pg_authid.h"
 #include "utils/inval.h"
 #include "utils/syscache.h"
 #include "miscadmin.h"
 
 
 /*
- * In common cases the same userid (ie, the session or current ID) will
+ * In common cases the same roleid (ie, the session or current ID) will
  * be queried repeatedly.  So we maintain a simple one-entry cache for
- * the status of the last requested userid.  The cache can be flushed
- * at need by watching for cache update events on pg_shadow.
+ * the status of the last requested roleid.  The cache can be flushed
+ * at need by watching for cache update events on pg_authid.
  */
-static AclId	last_userid = 0;		/* 0 == cache not valid */
-static bool		last_userid_is_super = false;
-static bool		userid_callback_registered = false;
+static Oid		last_roleid = InvalidOid;	/* InvalidOid == cache not valid */
+static bool		last_roleid_is_super = false;
+static bool		roleid_callback_registered = false;
 
-static void UseridCallback(Datum arg, Oid relid);
+static void RoleidCallback(Datum arg, Oid relid);
 
 
 /*
@@ -50,49 +50,49 @@ superuser(void)
 
 
 /*
- * The specified userid has Postgres superuser privileges
+ * The specified role has Postgres superuser privileges
  */
 bool
-superuser_arg(AclId userid)
+superuser_arg(Oid roleid)
 {
 	bool		result;
-	HeapTuple	utup;
+	HeapTuple	rtup;
 
 	/* Quick out for cache hit */
-	if (AclIdIsValid(last_userid) && last_userid == userid)
-		return last_userid_is_super;
+	if (OidIsValid(last_roleid) && last_roleid == roleid)
+		return last_roleid_is_super;
 
 	/* Special escape path in case you deleted all your users. */
-	if (!IsUnderPostmaster && userid == BOOTSTRAP_USESYSID)
+	if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID)
 		return true;
 
-	/* OK, look up the information in pg_shadow */
-	utup = SearchSysCache(SHADOWSYSID,
-						  Int32GetDatum(userid),
+	/* OK, look up the information in pg_authid */
+	rtup = SearchSysCache(AUTHOID,
+						  ObjectIdGetDatum(roleid),
 						  0, 0, 0);
-	if (HeapTupleIsValid(utup))
+	if (HeapTupleIsValid(rtup))
 	{
-		result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
-		ReleaseSysCache(utup);
+		result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper;
+		ReleaseSysCache(rtup);
 	}
 	else
 	{
-		/* Report "not superuser" for invalid userids */
+		/* Report "not superuser" for invalid roleids */
 		result = false;
 	}
 
 	/* If first time through, set up callback for cache flushes */
-	if (!userid_callback_registered)
+	if (!roleid_callback_registered)
 	{
-		CacheRegisterSyscacheCallback(SHADOWSYSID,
-									  UseridCallback,
+		CacheRegisterSyscacheCallback(AUTHOID,
+									  RoleidCallback,
 									  (Datum) 0);
-		userid_callback_registered = true;
+		roleid_callback_registered = true;
 	}
 
 	/* Cache the result for next time */
-	last_userid = userid;
-	last_userid_is_super = result;
+	last_roleid = roleid;
+	last_roleid_is_super = result;
 
 	return result;
 }
@@ -102,8 +102,8 @@ superuser_arg(AclId userid)
  *		Syscache inval callback function
  */
 static void
-UseridCallback(Datum arg, Oid relid)
+RoleidCallback(Datum arg, Oid relid)
 {
-	/* Invalidate our local cache in case user's superuserness changed */
-	last_userid = 0;
+	/* Invalidate our local cache in case role's superuserness changed */
+	last_roleid = InvalidOid;
 }
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 2442f43ddcf583e1a34b048b8014b56f462913c0..58fb04860aead46de8fd63fda2bcd8af06ac8349 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -42,7 +42,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  * Portions taken from FreeBSD.
  *
- * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.86 2005/06/26 03:03:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.87 2005/06/28 05:09:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -169,7 +169,7 @@ static void test_connections(void);
 static void test_buffers(void);
 static void setup_config(void);
 static void bootstrap_template1(char *short_version);
-static void setup_shadow(void);
+static void setup_auth(void);
 static void get_set_pwd(void);
 static void unlimit_systables(void);
 static void setup_depend(void);
@@ -1316,11 +1316,11 @@ bootstrap_template1(char *short_version)
  * set up the shadow password table
  */
 static void
-setup_shadow(void)
+setup_auth(void)
 {
 	PG_CMD_DECL;
 	char	  **line;
-	static char *pg_shadow_setup[] = {
+	static char *pg_authid_setup[] = {
 		/*
 		 * Create triggers to ensure manual updates to shared catalogs
 		 * will be reflected into their "flat file" copies.
@@ -1328,22 +1328,22 @@ setup_shadow(void)
 		"CREATE TRIGGER pg_sync_pg_database "
 		"  AFTER INSERT OR UPDATE OR DELETE ON pg_database "
 		"  FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
-		"CREATE TRIGGER pg_sync_pg_group "
-		"  AFTER INSERT OR UPDATE OR DELETE ON pg_group "
+		"CREATE TRIGGER pg_sync_pg_authid "
+		"  AFTER INSERT OR UPDATE OR DELETE ON pg_authid "
 		"  FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
-		"CREATE TRIGGER pg_sync_pg_pwd "
-		"  AFTER INSERT OR UPDATE OR DELETE ON pg_shadow "
+		"CREATE TRIGGER pg_sync_pg_auth_members "
+		"  AFTER INSERT OR UPDATE OR DELETE ON pg_auth_members "
 		"  FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
 
 		/*
-		 * needs to be done before alter user, because alter user checks
-		 * that pg_shadow is secure ...
+		 * The authid table shouldn't be readable except through views,
+		 * to ensure passwords are not publicly visible.
 		 */
-		"REVOKE ALL on pg_shadow FROM public;\n",
+		"REVOKE ALL on pg_authid FROM public;\n",
 		NULL
 	};
 
-	fputs(_("initializing pg_shadow ... "), stdout);
+	fputs(_("initializing pg_authid ... "), stdout);
 	fflush(stdout);
 
 	snprintf(cmd, sizeof(cmd),
@@ -1353,7 +1353,7 @@ setup_shadow(void)
 
 	PG_CMD_OPEN;
 
-	for (line = pg_shadow_setup; *line != NULL; line++)
+	for (line = pg_authid_setup; *line != NULL; line++)
 		PG_CMD_PUTS(*line);
 
 	PG_CMD_CLOSE;
@@ -1461,13 +1461,12 @@ unlimit_systables(void)
 	char	  **line;
 	static char *systables_setup[] = {
 		"ALTER TABLE pg_attrdef CREATE TOAST TABLE;\n",
+		"ALTER TABLE pg_authid CREATE TOAST TABLE;\n",
 		"ALTER TABLE pg_constraint CREATE TOAST TABLE;\n",
 		"ALTER TABLE pg_database CREATE TOAST TABLE;\n",
 		"ALTER TABLE pg_description CREATE TOAST TABLE;\n",
-		"ALTER TABLE pg_group CREATE TOAST TABLE;\n",
 		"ALTER TABLE pg_proc CREATE TOAST TABLE;\n",
 		"ALTER TABLE pg_rewrite CREATE TOAST TABLE;\n",
-		"ALTER TABLE pg_shadow CREATE TOAST TABLE;\n",
 		"ALTER TABLE pg_statistic CREATE TOAST TABLE;\n",
 		NULL
 	};
@@ -2624,7 +2623,7 @@ main(int argc, char *argv[])
 
 	/* Create the stuff we don't need to use bootstrap mode for */
 
-	setup_shadow();
+	setup_auth();
 	if (pwprompt || pwfilename)
 		get_set_pwd();
 
diff --git a/src/include/access/twophase.h b/src/include/access/twophase.h
index 08f1f9bd9fef10ae941ee3a8a2f2ff7ad4377856..e90b9e304db18be4528381d57ba87a2792bb7304 100644
--- a/src/include/access/twophase.h
+++ b/src/include/access/twophase.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/twophase.h,v 1.3 2005/06/19 20:00:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/twophase.h,v 1.4 2005/06/28 05:09:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,7 +34,7 @@ extern PGPROC *TwoPhaseGetDummyProc(TransactionId xid);
 
 extern GlobalTransaction MarkAsPreparing(TransactionId xid, const char *gid,
 										 TimestampTz prepared_at,
-										 AclId owner, Oid databaseid);
+										 Oid owner, Oid databaseid);
 
 extern void StartPrepare(GlobalTransaction gxact);
 extern void EndPrepare(GlobalTransaction gxact);
diff --git a/src/include/c.h b/src/include/c.h
index 1a92038774748a9f2a95b441073136f1b96ca80f..202e45271e5bb32622c308e3ede81891b3d07fb9 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/c.h,v 1.185 2005/06/08 15:50:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/c.h,v 1.186 2005/06/28 05:09:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -366,7 +366,7 @@ typedef double float8;
 
 /*
  * Oid, RegProcedure, TransactionId, SubTransactionId, MultiXactId,
- * CommandId, AclId
+ * CommandId
  */
 
 /* typedef Oid is in postgres_ext.h */
@@ -394,8 +394,6 @@ typedef uint32 CommandId;
 
 #define FirstCommandId	((CommandId) 0)
 
-typedef int32 AclId;			/* user and group identifiers */
-
 /*
  * Array indexing support
  */
@@ -507,8 +505,6 @@ typedef NameData *Name;
 
 #define OidIsValid(objectId)  ((bool) ((objectId) != InvalidOid))
 
-#define AclIdIsValid(aclId)  ((bool) ((aclId) != 0))
-
 #define RegProcedureIsValid(p)	OidIsValid(p)
 
 
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 1e5c7ce0fa0f6c2ab460e17a223a9cea8428e1df..5a1943723dc9561b8cb9c12865761aaf98af4bac 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.282 2005/06/27 12:45:22 teodor Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.283 2005/06/28 05:09:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200506271
+#define CATALOG_VERSION_NO	200506272
 
 #endif
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 8be3527be2c53752aca535fde627218eb81d69b9..757a2095792f6bbde753916e4977a851927d0892 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.87 2005/04/14 20:03:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.88 2005/06/28 05:09:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -83,6 +83,16 @@ DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnam_index,2658, on pg_attribute using
 DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnum_index,2659, on pg_attribute using btree(attrelid oid_ops, attnum int2_ops));
 #define AttributeRelidNumIndexId  2659
 
+DECLARE_UNIQUE_INDEX(pg_authid_rolname_index,2676, on pg_authid using btree(rolname name_ops));
+#define AuthIdRolnameIndexId	2676
+DECLARE_UNIQUE_INDEX(pg_authid_oid_index,2677, on pg_authid using btree(oid oid_ops));
+#define AuthIdOidIndexId	2677
+
+DECLARE_UNIQUE_INDEX(pg_auth_members_role_member_index,2694, on pg_auth_members using btree(roleid oid_ops, member oid_ops));
+#define AuthMemRoleMemIndexId	2694
+DECLARE_UNIQUE_INDEX(pg_auth_members_member_role_index,2695, on pg_auth_members using btree(member oid_ops, roleid oid_ops));
+#define AuthMemMemRoleIndexId	2695
+
 DECLARE_UNIQUE_INDEX(pg_cast_oid_index,2660, on pg_cast using btree(oid oid_ops));
 #define CastOidIndexId  2660
 DECLARE_UNIQUE_INDEX(pg_cast_source_target_index,2661, on pg_cast using btree(castsource oid_ops, casttarget oid_ops));
@@ -127,11 +137,6 @@ DECLARE_INDEX(pg_depend_reference_index,2674, on pg_depend using btree(refclassi
 DECLARE_UNIQUE_INDEX(pg_description_o_c_o_index,2675, on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops));
 #define DescriptionObjIndexId  2675
 
-DECLARE_UNIQUE_INDEX(pg_group_name_index,2676, on pg_group using btree(groname name_ops));
-#define GroupNameIndexId  2676
-DECLARE_UNIQUE_INDEX(pg_group_sysid_index,2677, on pg_group using btree(grosysid int4_ops));
-#define GroupSysidIndexId  2677
-
 /* This following index is not used for a cache and is not unique */
 DECLARE_INDEX(pg_index_indrelid_index,2678, on pg_index using btree(indrelid oid_ops));
 #define IndexIndrelidIndexId  2678
@@ -174,11 +179,6 @@ DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index,2692, on pg_rewrite using btree(oid oi
 DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index,2693, on pg_rewrite using btree(ev_class oid_ops, rulename name_ops));
 #define RewriteRelRulenameIndexId  2693
 
-DECLARE_UNIQUE_INDEX(pg_shadow_usename_index,2694, on pg_shadow using btree(usename name_ops));
-#define ShadowNameIndexId  2694
-DECLARE_UNIQUE_INDEX(pg_shadow_usesysid_index,2695, on pg_shadow using btree(usesysid int4_ops));
-#define ShadowSysidIndexId  2695
-
 DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_index,2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops));
 #define StatisticRelidAttnumIndexId  2696
 
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index ddca993a68a2f68a1c6362c3dd9c39110fc44138..bda89f440541ae4a3873a58ee6f10034ebaaad81 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.117 2005/04/29 22:28:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.118 2005/06/28 05:09:04 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -226,7 +226,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
 #define Schema_pg_type \
 { 1247, {"typname"},	   19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
 { 1247, {"typnamespace"},  26, -1,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
-{ 1247, {"typowner"},	   23, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
+{ 1247, {"typowner"},	   26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
 { 1247, {"typlen"},		   21, -1,	2,	4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
 { 1247, {"typbyval"},	   16, -1,	1,	5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
 { 1247, {"typtype"},	   18, -1,	1,	6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
@@ -250,7 +250,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
 
 DATA(insert ( 1247 typname			19 -1 NAMEDATALEN	1 0 -1 -1 f p i t f f t 0));
 DATA(insert ( 1247 typnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0));
-DATA(insert ( 1247 typowner			23 -1 4   3 0 -1 -1 t p i t f f t 0));
+DATA(insert ( 1247 typowner			26 -1 4   3 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1247 typlen			21 -1 2   4 0 -1 -1 t p s t f f t 0));
 DATA(insert ( 1247 typbyval			16 -1 1   5 0 -1 -1 t p c t f f t 0));
 DATA(insert ( 1247 typtype			18 -1 1   6 0 -1 -1 t p c t f f t 0));
@@ -286,7 +286,7 @@ DATA(insert ( 1247 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0));
 #define Schema_pg_proc \
 { 1255, {"proname"},			19, -1, NAMEDATALEN,  1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
 { 1255, {"pronamespace"},		26, -1, 4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
-{ 1255, {"proowner"},			23, -1, 4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
+{ 1255, {"proowner"},			26, -1, 4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
 { 1255, {"prolang"},			26, -1, 4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
 { 1255, {"proisagg"},			16, -1, 1,	5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
 { 1255, {"prosecdef"},			16, -1, 1,	6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
@@ -305,7 +305,7 @@ DATA(insert ( 1247 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0));
 
 DATA(insert ( 1255 proname			19 -1 NAMEDATALEN	1 0 -1 -1 f p i t f f t 0));
 DATA(insert ( 1255 pronamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0));
-DATA(insert ( 1255 proowner			23 -1 4   3 0 -1 -1 t p i t f f t 0));
+DATA(insert ( 1255 proowner			26 -1 4   3 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1255 prolang			26 -1 4   4 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1255 proisagg			16 -1 1   5 0 -1 -1 t p c t f f t 0));
 DATA(insert ( 1255 prosecdef		16 -1 1   6 0 -1 -1 t p c t f f t 0));
@@ -385,7 +385,7 @@ DATA(insert ( 1249 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0));
 { 1259, {"relname"},	   19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
 { 1259, {"relnamespace"},  26, -1,	4,	2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
 { 1259, {"reltype"},	   26, -1,	4,	3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
-{ 1259, {"relowner"},	   23, -1,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
+{ 1259, {"relowner"},	   26, -1,	4,	4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
 { 1259, {"relam"},		   26, -1,	4,	5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
 { 1259, {"relfilenode"},   26, -1,	4,	6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
 { 1259, {"reltablespace"}, 26, -1,	4,	7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
@@ -411,7 +411,7 @@ DATA(insert ( 1249 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1259 relname			19 -1 NAMEDATALEN	1 0 -1 -1 f p i t f f t 0));
 DATA(insert ( 1259 relnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1259 reltype			26 -1 4   3 0 -1 -1 t p i t f f t 0));
-DATA(insert ( 1259 relowner			23 -1 4   4 0 -1 -1 t p i t f f t 0));
+DATA(insert ( 1259 relowner			26 -1 4   4 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1259 relam			26 -1 4   5 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1259 relfilenode		26 -1 4   6 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1259 reltablespace	26 -1 4   7 0 -1 -1 t p i t f f t 0));
diff --git a/src/include/catalog/pg_auth_members.h b/src/include/catalog/pg_auth_members.h
new file mode 100644
index 0000000000000000000000000000000000000000..e08fd2e6ae1cd352bc164d4a2735d950ec264989
--- /dev/null
+++ b/src/include/catalog/pg_auth_members.h
@@ -0,0 +1,54 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_auth_members.h
+ *	  definition of the system "authorization identifier members" relation
+ *	  (pg_auth_members) along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/catalog/pg_auth_members.h,v 1.1 2005/06/28 05:09:04 tgl Exp $
+ *
+ * NOTES
+ *	  the genbki.sh script reads this file and generates .bki
+ *	  information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_AUTH_MEMBERS_H
+#define PG_AUTH_MEMBERS_H
+
+/* ----------------
+ *		pg_auth_members definition.  cpp turns this into
+ *		typedef struct FormData_pg_auth_members
+ * ----------------
+ */
+#define AuthMemRelationId	1261
+
+CATALOG(pg_auth_members,1261) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
+{
+	Oid			roleid;			/* ID of a role */
+	Oid			member;			/* ID of a member of that role */
+	Oid			grantor;		/* who granted the membership */
+	bool		admin_option;	/* granted with admin option? */
+} FormData_pg_auth_members;
+
+/* ----------------
+ *		Form_pg_auth_members corresponds to a pointer to a tuple with
+ *		the format of pg_auth_members relation.
+ * ----------------
+ */
+typedef FormData_pg_auth_members *Form_pg_auth_members;
+
+/* ----------------
+ *		compiler constants for pg_auth_members
+ * ----------------
+ */
+#define Natts_pg_auth_members				4
+#define Anum_pg_auth_members_roleid			1
+#define Anum_pg_auth_members_member			2
+#define Anum_pg_auth_members_grantor		3
+#define Anum_pg_auth_members_admin_option	4
+
+#endif   /* PG_AUTH_MEMBERS_H */
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ea15fea8a1a7cb8702a00585bc8aabf731a90aa
--- /dev/null
+++ b/src/include/catalog/pg_authid.h
@@ -0,0 +1,94 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_authid.h
+ *	  definition of the system "authorization identifier" relation (pg_authid)
+ *	  along with the relation's initial contents.
+ *
+ *	  pg_shadow and pg_group are now publicly accessible views on pg_authid.
+ *
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/catalog/pg_authid.h,v 1.1 2005/06/28 05:09:05 tgl Exp $
+ *
+ * NOTES
+ *	  the genbki.sh script reads this file and generates .bki
+ *	  information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_AUTHID_H
+#define PG_AUTHID_H
+
+/*
+ * The CATALOG definition has to refer to the type of rolvaliduntil as
+ * "timestamptz" (lower case) so that bootstrap mode recognizes it.  But
+ * the C header files define this type as TimestampTz.  Since the field is
+ * potentially-null and therefore can't be accessed directly from C code,
+ * there is no particular need for the C struct definition to show the
+ * field type as TimestampTz --- instead we just make it Datum.
+ */
+
+#define timestamptz Datum
+
+
+/* ----------------
+ *		pg_authid definition.  cpp turns this into
+ *		typedef struct FormData_pg_authid
+ * ----------------
+ */
+#define AuthIdRelationId    1260
+
+CATALOG(pg_authid,1260) BKI_SHARED_RELATION
+{
+	NameData	rolname;		/* name of role */
+	bool		rolsuper;		/* read this field via superuser() only! */
+	bool		rolcreaterole;	/* allowed to create more roles? */
+	bool		rolcreatedb;	/* allowed to create databases? */
+	bool		rolcatupdate;	/* allowed to alter catalogs manually? */
+	bool		rolcanlogin;	/* allowed to log in as session user? */
+
+	/* remaining fields may be null; use heap_getattr to read them! */
+	text		rolpassword;	/* password, if any */
+	timestamptz	rolvaliduntil;	/* password expiration time, if any */
+	text		rolconfig[1];	/* GUC settings to apply at login */
+} FormData_pg_authid;
+
+#undef timestamptz
+
+
+/* ----------------
+ *		Form_pg_authid corresponds to a pointer to a tuple with
+ *		the format of pg_authid relation.
+ * ----------------
+ */
+typedef FormData_pg_authid *Form_pg_authid;
+
+/* ----------------
+ *		compiler constants for pg_authid
+ * ----------------
+ */
+#define Natts_pg_authid					9
+#define Anum_pg_authid_rolname			1
+#define Anum_pg_authid_rolsuper			2
+#define Anum_pg_authid_rolcreaterole	3
+#define Anum_pg_authid_rolcreatedb		4
+#define Anum_pg_authid_rolcatupdate		5
+#define Anum_pg_authid_rolcanlogin		6
+#define Anum_pg_authid_rolpassword		7
+#define Anum_pg_authid_rolvaliduntil	8
+#define Anum_pg_authid_rolconfig		9
+
+/* ----------------
+ *		initial contents of pg_authid
+ *
+ * The uppercase quantities will be replaced at initdb time with
+ * user choices.
+ * ----------------
+ */
+DATA(insert OID = 10 ( "POSTGRES" t t t t t _null_ _null_ _null_ ));
+
+#define BOOTSTRAP_SUPERUSERID 10
+
+#endif   /* PG_AUTHID_H */
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index e08d6d60d338df3e53f54c43cc21e60a373f9c82..b6d8f556b4899c280da3fce1a41a24e96c5356e6 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.88 2005/04/29 22:28:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.89 2005/06/28 05:09:05 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -47,7 +47,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP
 	NameData	relname;		/* class name */
 	Oid			relnamespace;	/* OID of namespace containing this class */
 	Oid			reltype;		/* OID of associated entry in pg_type */
-	int4		relowner;		/* class owner */
+	Oid			relowner;		/* class owner */
 	Oid			relam;			/* index access method; 0 if not an index */
 	Oid			relfilenode;	/* identifier of physical storage file */
 	Oid			reltablespace;	/* identifier of table space for relation */
diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h
index e9cd3ccca24fff1857af1a34adeb288a60123b41..eb874446455d276b7cc07bb0153c5c48e4142d0c 100644
--- a/src/include/catalog/pg_conversion.h
+++ b/src/include/catalog/pg_conversion.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_conversion.h,v 1.15 2005/04/14 01:38:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_conversion.h,v 1.16 2005/06/28 05:09:05 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -46,7 +46,7 @@ CATALOG(pg_conversion,2607)
 {
 	NameData	conname;
 	Oid			connamespace;
-	int4		conowner;
+	Oid			conowner;
 	int4		conforencoding;
 	int4		contoencoding;
 	regproc		conproc;
@@ -86,7 +86,7 @@ typedef FormData_pg_conversion *Form_pg_conversion;
 #include "nodes/parsenodes.h"
 
 extern Oid ConversionCreate(const char *conname, Oid connamespace,
-				 AclId conowner,
+				 Oid conowner,
 				 int32 conforencoding, int32 contoencoding,
 				 Oid conproc, bool def);
 extern void ConversionDrop(Oid conversionOid, DropBehavior behavior);
diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h
index 69b41e317206b13e5339703b98d52f2ff09fb580..37c57f8508c8b154eb436d91c18dca002acb6723 100644
--- a/src/include/catalog/pg_database.h
+++ b/src/include/catalog/pg_database.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.35 2005/04/14 01:38:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.36 2005/06/28 05:09:06 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -36,7 +36,7 @@
 CATALOG(pg_database,1262) BKI_SHARED_RELATION
 {
 	NameData	datname;		/* database name */
-	int4		datdba;			/* sysid of owner */
+	Oid			datdba;			/* owner of database */
 	int4		encoding;		/* character encoding */
 	bool		datistemplate;	/* allowed as CREATE DATABASE template? */
 	bool		datallowconn;	/* new connections allowed? */
diff --git a/src/include/catalog/pg_group.h b/src/include/catalog/pg_group.h
deleted file mode 100644
index 216d51a6660eeedfbb573ebf4686bf547332943a..0000000000000000000000000000000000000000
--- a/src/include/catalog/pg_group.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pg_group.h
- *
- *
- *
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $PostgreSQL: pgsql/src/include/catalog/pg_group.h,v 1.21 2005/04/14 01:38:20 tgl Exp $
- *
- * NOTES
- *	  the genbki.sh script reads this file and generates .bki
- *	  information from the DATA() statements.
- *
- *-------------------------------------------------------------------------
- */
-#ifndef PG_GROUP_H
-#define PG_GROUP_H
-
-/* ----------------
- *		postgres.h contains the system type definitions and the
- *		CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file
- *		can be read by both genbki.sh and the C compiler.
- * ----------------
- */
-#define GroupRelationId  1261
-
-CATALOG(pg_group,1261) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
-{
-	NameData	groname;
-	int4		grosysid;
-	int4		grolist[1];
-} FormData_pg_group;
-
-/* VARIABLE LENGTH STRUCTURE */
-
-typedef FormData_pg_group *Form_pg_group;
-
-#define Natts_pg_group			3
-#define Anum_pg_group_groname	1
-#define Anum_pg_group_grosysid	2
-#define Anum_pg_group_grolist	3
-
-#endif   /* PG_GROUP_H */
diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h
index f6cb4cf8e5bd9a423bb8ba9b46ee9468363f5b1f..c460500578c94318c9db6d9fa2850dfa73054acf 100644
--- a/src/include/catalog/pg_namespace.h
+++ b/src/include/catalog/pg_namespace.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_namespace.h,v 1.17 2005/04/14 01:38:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_namespace.h,v 1.18 2005/06/28 05:09:06 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -41,7 +41,7 @@
 CATALOG(pg_namespace,2615)
 {
 	NameData	nspname;
-	int4		nspowner;
+	Oid			nspowner;
 	aclitem		nspacl[1];		/* VARIABLE LENGTH FIELD */
 } FormData_pg_namespace;
 
@@ -82,6 +82,6 @@ DESCR("Standard public schema");
 /*
  * prototypes for functions in pg_namespace.c
  */
-extern Oid NamespaceCreate(const char *nspName, int32 ownerSysId);
+extern Oid NamespaceCreate(const char *nspName, Oid ownerId);
 
 #endif   /* PG_NAMESPACE_H */
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 6043fec22d0baa6ce41e0aa3bbd787fb93ceab9d..23485ff0ebbd4a56c7d3aa6749e701ac0e95997f 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -27,7 +27,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.64 2005/04/14 01:38:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.65 2005/06/28 05:09:07 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -57,7 +57,7 @@ CATALOG(pg_opclass,2616)
 	Oid			opcamid;		/* index access method opclass is for */
 	NameData	opcname;		/* name of this opclass */
 	Oid			opcnamespace;	/* namespace of this opclass */
-	int4		opcowner;		/* opclass owner */
+	Oid			opcowner;		/* opclass owner */
 	Oid			opcintype;		/* type of data indexed by opclass */
 	bool		opcdefault;		/* T if opclass is default for opcintype */
 	Oid			opckeytype;		/* type of data in index, or InvalidOid */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index f87b6a07383ef40d747a8548600301aa6e988b23..9de43736eae27e953f1d78b56361f9e39a99a10f 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.134 2005/06/24 20:53:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.135 2005/06/28 05:09:07 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -42,7 +42,7 @@ CATALOG(pg_operator,2617)
 {
 	NameData	oprname;		/* name of operator */
 	Oid			oprnamespace;	/* OID of namespace containing this oper */
-	int4		oprowner;		/* oper owner */
+	Oid			oprowner;		/* operator owner */
 	char		oprkind;		/* 'l', 'r', or 'b' */
 	bool		oprcanhash;		/* can be used in hash join? */
 	Oid			oprleft;		/* left arg type, or 0 if 'l' oprkind */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 049024ae40c0ccc9d20bc0d919dec4b3d9f1f0c3..5326a770592d7b0b6c8a9fb08bdc41bf09dc62da 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.371 2005/06/26 03:04:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.372 2005/06/28 05:09:09 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -41,7 +41,7 @@ CATALOG(pg_proc,1255) BKI_BOOTSTRAP
 {
 	NameData	proname;		/* procedure name */
 	Oid			pronamespace;	/* OID of namespace containing this proc */
-	int4		proowner;		/* proc owner */
+	Oid			proowner;		/* procedure owner */
 	Oid			prolang;		/* OID of pg_language entry */
 	bool		proisagg;		/* is it an aggregate? */
 	bool		prosecdef;		/* security definer */
@@ -1355,7 +1355,7 @@ DATA(insert OID = 1037 (  aclcontains	   PGNSP PGUID 12 f f t f i 2 16 "1034 103
 DESCR("does ACL contain item?");
 DATA(insert OID = 1062 (  aclitemeq		   PGNSP PGUID 12 f f t f i 2 16 "1033 1033" _null_ _null_ _null_ aclitem_eq - _null_ ));
 DESCR("equality operator for ACL items");
-DATA(insert OID = 1365 (  makeaclitem	   PGNSP PGUID 12 f f t f i 5 1033 "23 23 23 25 16" _null_ _null_ _null_ makeaclitem - _null_ ));
+DATA(insert OID = 1365 (  makeaclitem	   PGNSP PGUID 12 f f t f i 4 1033 "26 26 25 16" _null_ _null_ _null_ makeaclitem - _null_ ));
 DESCR("make ACL item");
 DATA(insert OID = 1044 (  bpcharin		   PGNSP PGUID 12 f f t f i 3 1042 "2275 26 23" _null_ _null_ _null_ bpcharin - _null_ ));
 DESCR("I/O");
@@ -2251,8 +2251,8 @@ DATA(insert OID = 1640 (  pg_get_viewdef	   PGNSP PGUID 12 f f t f s 1 25 "25" _
 DESCR("select statement of a view");
 DATA(insert OID = 1641 (  pg_get_viewdef	   PGNSP PGUID 12 f f t f s 1 25 "26" _null_ _null_ _null_  pg_get_viewdef - _null_ ));
 DESCR("select statement of a view");
-DATA(insert OID = 1642 (  pg_get_userbyid	   PGNSP PGUID 12 f f t f s 1 19 "23" _null_ _null_ _null_  pg_get_userbyid - _null_ ));
-DESCR("user name by UID (with fallback)");
+DATA(insert OID = 1642 (  pg_get_userbyid	   PGNSP PGUID 12 f f t f s 1 19 "26" _null_ _null_ _null_  pg_get_userbyid - _null_ ));
+DESCR("role name by OID (with fallback)");
 DATA(insert OID = 1643 (  pg_get_indexdef	   PGNSP PGUID 12 f f t f s 1 25 "26" _null_ _null_ _null_  pg_get_indexdef - _null_ ));
 DESCR("index description");
 DATA(insert OID = 1662 (  pg_get_triggerdef    PGNSP PGUID 12 f f t f s 1 25 "26" _null_ _null_ _null_  pg_get_triggerdef - _null_ ));
@@ -2785,10 +2785,10 @@ DATA(insert OID = 1922 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16
 DESCR("user privilege on relation by username, rel name");
 DATA(insert OID = 1923 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25" _null_ _null_ _null_	has_table_privilege_name_id - _null_ ));
 DESCR("user privilege on relation by username, rel oid");
-DATA(insert OID = 1924 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25" _null_ _null_ _null_	has_table_privilege_id_name - _null_ ));
-DESCR("user privilege on relation by usesysid, rel name");
-DATA(insert OID = 1925 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25" _null_ _null_ _null_	has_table_privilege_id_id - _null_ ));
-DESCR("user privilege on relation by usesysid, rel oid");
+DATA(insert OID = 1924 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 25 25" _null_ _null_ _null_	has_table_privilege_id_name - _null_ ));
+DESCR("user privilege on relation by user oid, rel name");
+DATA(insert OID = 1925 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 26 25" _null_ _null_ _null_	has_table_privilege_id_id - _null_ ));
+DESCR("user privilege on relation by user oid, rel oid");
 DATA(insert OID = 1926 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25" _null_ _null_ _null_ has_table_privilege_name - _null_ ));
 DESCR("current user privilege on relation by rel name");
 DATA(insert OID = 1927 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25" _null_ _null_ _null_ has_table_privilege_id - _null_ ));
@@ -2821,7 +2821,7 @@ DATA(insert OID = 1937 (  pg_stat_get_backend_pid		PGNSP PGUID 12 f f t f s 1 23
 DESCR("Statistics: PID of backend");
 DATA(insert OID = 1938 (  pg_stat_get_backend_dbid		PGNSP PGUID 12 f f t f s 1 26 "23" _null_ _null_ _null_	pg_stat_get_backend_dbid - _null_ ));
 DESCR("Statistics: Database ID of backend");
-DATA(insert OID = 1939 (  pg_stat_get_backend_userid	PGNSP PGUID 12 f f t f s 1 23 "23" _null_ _null_ _null_	pg_stat_get_backend_userid - _null_ ));
+DATA(insert OID = 1939 (  pg_stat_get_backend_userid	PGNSP PGUID 12 f f t f s 1 26 "23" _null_ _null_ _null_	pg_stat_get_backend_userid - _null_ ));
 DESCR("Statistics: User ID of backend");
 DATA(insert OID = 1940 (  pg_stat_get_backend_activity	PGNSP PGUID 12 f f t f s 1 25 "23" _null_ _null_ _null_	pg_stat_get_backend_activity - _null_ ));
 DESCR("Statistics: Current query of backend");
@@ -3171,10 +3171,10 @@ DATA(insert OID = 2250 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3
 DESCR("user privilege on database by username, database name");
 DATA(insert OID = 2251 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25" _null_ _null_ _null_	has_database_privilege_name_id - _null_ ));
 DESCR("user privilege on database by username, database oid");
-DATA(insert OID = 2252 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25" _null_ _null_ _null_	has_database_privilege_id_name - _null_ ));
-DESCR("user privilege on database by usesysid, database name");
-DATA(insert OID = 2253 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25" _null_ _null_ _null_	has_database_privilege_id_id - _null_ ));
-DESCR("user privilege on database by usesysid, database oid");
+DATA(insert OID = 2252 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 25 25" _null_ _null_ _null_	has_database_privilege_id_name - _null_ ));
+DESCR("user privilege on database by user oid, database name");
+DATA(insert OID = 2253 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 26 25" _null_ _null_ _null_	has_database_privilege_id_id - _null_ ));
+DESCR("user privilege on database by user oid, database oid");
 DATA(insert OID = 2254 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25" _null_ _null_ _null_ has_database_privilege_name - _null_ ));
 DESCR("current user privilege on database by database name");
 DATA(insert OID = 2255 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25" _null_ _null_ _null_ has_database_privilege_id - _null_ ));
@@ -3184,10 +3184,10 @@ DATA(insert OID = 2256 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3
 DESCR("user privilege on function by username, function name");
 DATA(insert OID = 2257 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25" _null_ _null_ _null_	has_function_privilege_name_id - _null_ ));
 DESCR("user privilege on function by username, function oid");
-DATA(insert OID = 2258 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25" _null_ _null_ _null_	has_function_privilege_id_name - _null_ ));
-DESCR("user privilege on function by usesysid, function name");
-DATA(insert OID = 2259 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25" _null_ _null_ _null_	has_function_privilege_id_id - _null_ ));
-DESCR("user privilege on function by usesysid, function oid");
+DATA(insert OID = 2258 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 25 25" _null_ _null_ _null_	has_function_privilege_id_name - _null_ ));
+DESCR("user privilege on function by user oid, function name");
+DATA(insert OID = 2259 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 26 25" _null_ _null_ _null_	has_function_privilege_id_id - _null_ ));
+DESCR("user privilege on function by user oid, function oid");
 DATA(insert OID = 2260 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25" _null_ _null_ _null_ has_function_privilege_name - _null_ ));
 DESCR("current user privilege on function by function name");
 DATA(insert OID = 2261 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25" _null_ _null_ _null_ has_function_privilege_id - _null_ ));
@@ -3197,10 +3197,10 @@ DATA(insert OID = 2262 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3
 DESCR("user privilege on language by username, language name");
 DATA(insert OID = 2263 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25" _null_ _null_ _null_	has_language_privilege_name_id - _null_ ));
 DESCR("user privilege on language by username, language oid");
-DATA(insert OID = 2264 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25" _null_ _null_ _null_	has_language_privilege_id_name - _null_ ));
-DESCR("user privilege on language by usesysid, language name");
-DATA(insert OID = 2265 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25" _null_ _null_ _null_	has_language_privilege_id_id - _null_ ));
-DESCR("user privilege on language by usesysid, language oid");
+DATA(insert OID = 2264 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 25 25" _null_ _null_ _null_	has_language_privilege_id_name - _null_ ));
+DESCR("user privilege on language by user oid, language name");
+DATA(insert OID = 2265 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 26 25" _null_ _null_ _null_	has_language_privilege_id_id - _null_ ));
+DESCR("user privilege on language by user oid, language oid");
 DATA(insert OID = 2266 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25" _null_ _null_ _null_ has_language_privilege_name - _null_ ));
 DESCR("current user privilege on language by language name");
 DATA(insert OID = 2267 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25" _null_ _null_ _null_ has_language_privilege_id - _null_ ));
@@ -3210,10 +3210,10 @@ DATA(insert OID = 2268 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16
 DESCR("user privilege on schema by username, schema name");
 DATA(insert OID = 2269 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25" _null_ _null_ _null_	has_schema_privilege_name_id - _null_ ));
 DESCR("user privilege on schema by username, schema oid");
-DATA(insert OID = 2270 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25" _null_ _null_ _null_	has_schema_privilege_id_name - _null_ ));
-DESCR("user privilege on schema by usesysid, schema name");
-DATA(insert OID = 2271 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25" _null_ _null_ _null_	has_schema_privilege_id_id - _null_ ));
-DESCR("user privilege on schema by usesysid, schema oid");
+DATA(insert OID = 2270 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 25 25" _null_ _null_ _null_	has_schema_privilege_id_name - _null_ ));
+DESCR("user privilege on schema by user oid, schema name");
+DATA(insert OID = 2271 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 26 25" _null_ _null_ _null_	has_schema_privilege_id_id - _null_ ));
+DESCR("user privilege on schema by user oid, schema oid");
 DATA(insert OID = 2272 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25" _null_ _null_ _null_ has_schema_privilege_name - _null_ ));
 DESCR("current user privilege on schema by schema name");
 DATA(insert OID = 2273 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25" _null_ _null_ _null_ has_schema_privilege_id - _null_ ));
@@ -3223,10 +3223,10 @@ DATA(insert OID = 2390 (  has_tablespace_privilege		   PGNSP PGUID 12 f f t f s
 DESCR("user privilege on tablespace by username, tablespace name");
 DATA(insert OID = 2391 (  has_tablespace_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25" _null_ _null_ _null_	has_tablespace_privilege_name_id - _null_ ));
 DESCR("user privilege on tablespace by username, tablespace oid");
-DATA(insert OID = 2392 (  has_tablespace_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25" _null_ _null_ _null_	has_tablespace_privilege_id_name - _null_ ));
-DESCR("user privilege on tablespace by usesysid, tablespace name");
-DATA(insert OID = 2393 (  has_tablespace_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25" _null_ _null_ _null_	has_tablespace_privilege_id_id - _null_ ));
-DESCR("user privilege on tablespace by usesysid, tablespace oid");
+DATA(insert OID = 2392 (  has_tablespace_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 25 25" _null_ _null_ _null_	has_tablespace_privilege_id_name - _null_ ));
+DESCR("user privilege on tablespace by user oid, tablespace name");
+DATA(insert OID = 2393 (  has_tablespace_privilege		   PGNSP PGUID 12 f f t f s 3 16 "26 26 25" _null_ _null_ _null_	has_tablespace_privilege_id_id - _null_ ));
+DESCR("user privilege on tablespace by user oid, tablespace oid");
 DATA(insert OID = 2394 (  has_tablespace_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25" _null_ _null_ _null_ has_tablespace_privilege_name - _null_ ));
 DESCR("current user privilege on tablespace by tablespace name");
 DATA(insert OID = 2395 (  has_tablespace_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25" _null_ _null_ _null_ has_tablespace_privilege_id - _null_ ));
diff --git a/src/include/catalog/pg_shadow.h b/src/include/catalog/pg_shadow.h
deleted file mode 100644
index 3c24d82d450f766a02ad4a03045e6b87004b1b05..0000000000000000000000000000000000000000
--- a/src/include/catalog/pg_shadow.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pg_shadow.h
- *	  definition of the system "shadow" relation (pg_shadow)
- *	  along with the relation's initial contents.
- *
- *	  pg_user is now a publicly accessible view on pg_shadow.
- *
- *
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $PostgreSQL: pgsql/src/include/catalog/pg_shadow.h,v 1.28 2005/04/14 01:38:21 tgl Exp $
- *
- * NOTES
- *	  the genbki.sh script reads this file and generates .bki
- *	  information from the DATA() statements.
- *
- *-------------------------------------------------------------------------
- */
-#ifndef PG_SHADOW_H
-#define PG_SHADOW_H
-
-
-/* ----------------
- *		pg_shadow definition.  cpp turns this into
- *		typedef struct FormData_pg_shadow
- * ----------------
- */
-#define ShadowRelationId  1260
-
-CATALOG(pg_shadow,1260) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
-{
-	NameData	usename;
-	int4		usesysid;
-	bool		usecreatedb;
-	bool		usesuper;		/* read this field via superuser() only */
-	bool		usecatupd;
-
-	/* remaining fields may be null; use heap_getattr to read them! */
-	text		passwd;
-	int4		valuntil;		/* actually abstime */
-	text		useconfig[1];
-} FormData_pg_shadow;
-
-/* ----------------
- *		Form_pg_shadow corresponds to a pointer to a tuple with
- *		the format of pg_shadow relation.
- * ----------------
- */
-typedef FormData_pg_shadow *Form_pg_shadow;
-
-/* ----------------
- *		compiler constants for pg_shadow
- * ----------------
- */
-#define Natts_pg_shadow					8
-#define Anum_pg_shadow_usename			1
-#define Anum_pg_shadow_usesysid			2
-#define Anum_pg_shadow_usecreatedb		3
-#define Anum_pg_shadow_usesuper			4
-#define Anum_pg_shadow_usecatupd		5
-#define Anum_pg_shadow_passwd			6
-#define Anum_pg_shadow_valuntil			7
-#define Anum_pg_shadow_useconfig		8
-
-/* ----------------
- *		initial contents of pg_shadow
- *
- * The uppercase quantities will be replaced at initdb time with
- * user choices.
- * ----------------
- */
-DATA(insert ( "POSTGRES" PGUID t t t _null_ _null_ _null_ ));
-
-#define BOOTSTRAP_USESYSID 1
-
-#endif   /* PG_SHADOW_H */
diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h
index 7c440042746d277c940ebcc11c7f1b53a5f95cc3..831e5753d129f90db9f16b363ef4d76f15868c9a 100644
--- a/src/include/catalog/pg_tablespace.h
+++ b/src/include/catalog/pg_tablespace.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_tablespace.h,v 1.6 2005/04/14 01:38:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_tablespace.h,v 1.7 2005/06/28 05:09:12 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -36,7 +36,7 @@
 CATALOG(pg_tablespace,1213) BKI_SHARED_RELATION
 {
 	NameData	spcname;		/* tablespace name */
-	int4		spcowner;		/* sysid of owner */
+	Oid			spcowner;		/* owner of tablespace */
 	text		spclocation;	/* physical location (VAR LENGTH) */
 	aclitem		spcacl[1];		/* access permissions (VAR LENGTH) */
 } FormData_pg_tablespace;
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 8a4207e9ea6bce9cf7db2b1d45dac15559981a49..44b8cf0cedb430ebaff43f9d523640a7a7cfd98a 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.161 2005/05/30 01:20:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.162 2005/06/28 05:09:12 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -44,7 +44,7 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP
 {
 	NameData	typname;		/* type name */
 	Oid			typnamespace;	/* OID of namespace containing this type */
-	int4		typowner;		/* type owner */
+	Oid			typowner;		/* type owner */
 
 	/*
 	 * For a fixed-size type, typlen is the number of bytes we use to
diff --git a/src/include/commands/conversioncmds.h b/src/include/commands/conversioncmds.h
index 47224831aad905e1028a4bdd9f2c266217db0474..b64b361d27aa4b16a7ab5c16791579de984152cf 100644
--- a/src/include/commands/conversioncmds.h
+++ b/src/include/commands/conversioncmds.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/conversioncmds.h,v 1.9 2004/12/31 22:03:28 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/commands/conversioncmds.h,v 1.10 2005/06/28 05:09:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,6 @@
 extern void CreateConversionCommand(CreateConversionStmt *parsetree);
 extern void DropConversionCommand(List *conversion_name, DropBehavior behavior);
 extern void RenameConversion(List *name, const char *newname);
-extern void AlterConversionOwner(List *name, AclId newOwnerSysId);
+extern void AlterConversionOwner(List *name, Oid newOwnerId);
 
 #endif   /* CONVERSIONCMDS_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index 7ffd7abeb0305fada248c51b711b90c18d48a533..1a4fd5123c29cc8cd8ba32b390e17f2793160fdb 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/dbcommands.h,v 1.38 2005/06/06 17:01:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/dbcommands.h,v 1.39 2005/06/28 05:09:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,7 +65,7 @@ extern void createdb(const CreatedbStmt *stmt);
 extern void dropdb(const char *dbname);
 extern void RenameDatabase(const char *oldname, const char *newname);
 extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt);
-extern void AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId);
+extern void AlterDatabaseOwner(const char *dbname, Oid newOwnerId);
 
 extern Oid	get_database_oid(const char *dbname);
 extern char *get_database_name(Oid dbid);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 1ae5649c137c5606d4b0735621985a5daf87129b..10c3438065a76282927f09ab0e5c0926a5529eed 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.65 2005/06/22 21:14:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.66 2005/06/28 05:09:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,7 +50,7 @@ extern void RemoveFunctionById(Oid funcOid);
 extern void SetFunctionReturnType(Oid funcOid, Oid newRetType);
 extern void SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType);
 extern void RenameFunction(List *name, List *argtypes, const char *newname);
-extern void AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId);
+extern void AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId);
 extern void AlterFunction(AlterFunctionStmt *stmt);
 extern void CreateCast(CreateCastStmt *stmt);
 extern void DropCast(DropCastStmt *stmt);
@@ -61,20 +61,20 @@ extern void DefineOperator(List *names, List *parameters);
 extern void RemoveOperator(RemoveOperStmt *stmt);
 extern void RemoveOperatorById(Oid operOid);
 extern void AlterOperatorOwner(List *name, TypeName *typeName1,
-				   TypeName *typename2, AclId newOwnerSysId);
+				   TypeName *typename2, Oid newOwnerId);
 
 /* commands/aggregatecmds.c */
 extern void DefineAggregate(List *names, List *parameters);
 extern void RemoveAggregate(RemoveAggrStmt *stmt);
 extern void RenameAggregate(List *name, TypeName *basetype, const char *newname);
-extern void AlterAggregateOwner(List *name, TypeName *basetype, AclId newOwnerSysId);
+extern void AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId);
 
 /* commands/opclasscmds.c */
 extern void DefineOpClass(CreateOpClassStmt *stmt);
 extern void RemoveOpClass(RemoveOpClassStmt *stmt);
 extern void RemoveOpClassById(Oid opclassOid);
 extern void RenameOpClass(List *name, const char *access_method, const char *newname);
-extern void AlterOpClassOwner(List *name, const char *access_method, AclId newOwnerSysId);
+extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
 
 /* support routines in commands/define.c */
 
diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h
index 54edffa986c206012728835a784e5e20ea93fc17..4528591b3cbd5c0fdb2f0d1a8646ba57f09771a2 100644
--- a/src/include/commands/schemacmds.h
+++ b/src/include/commands/schemacmds.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/schemacmds.h,v 1.9 2004/12/31 22:03:28 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/commands/schemacmds.h,v 1.10 2005/06/28 05:09:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,6 @@ extern void RemoveSchema(List *names, DropBehavior behavior);
 extern void RemoveSchemaById(Oid schemaOid);
 
 extern void RenameSchema(const char *oldname, const char *newname);
-extern void AlterSchemaOwner(const char *name, AclId newOwnerSysId);
+extern void AlterSchemaOwner(const char *name, Oid newOwnerId);
 
 #endif   /* SCHEMACMDS_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index fe99a191a3390c74fc873bbb137e4a7757115c34..f6c83c952b6212b296af12f800eeb93d7db3e150 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.9 2005/06/06 17:01:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.10 2005/06/28 05:09:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@ typedef struct xl_tblspc_drop_rec
 extern void CreateTableSpace(CreateTableSpaceStmt *stmt);
 extern void DropTableSpace(DropTableSpaceStmt *stmt);
 extern void RenameTableSpace(const char *oldname, const char *newname);
-extern void AlterTableSpaceOwner(const char *name, AclId newOwnerSysId);
+extern void AlterTableSpaceOwner(const char *name, Oid newOwnerId);
 
 extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo);
 
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index ad5e04cc37ae10eaf098adb0b3d69e6f39bce8c3..a940a78f483a7a0ff1c87bb1512af8361eba2803 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.10 2004/12/31 22:03:28 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.11 2005/06/28 05:09:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,6 +34,6 @@ extern void AlterDomainDropConstraint(List *names, const char *constrName,
 
 extern List *GetDomainConstraints(Oid typeOid);
 
-extern void AlterTypeOwner(List *names, AclId newOwnerSysId);
+extern void AlterTypeOwner(List *names, Oid newOwnerId);
 
 #endif   /* TYPECMDS_H */
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index a37f94940a9ba846ba5d4b1fe1b28b29fae4209e..ab2829a266bba88730e1ff4892103fd6784ec878 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -1,10 +1,10 @@
 /*-------------------------------------------------------------------------
  *
  * user.h
- *	  Commands for manipulating users and groups.
+ *	  Commands for manipulating roles (formerly called users).
  *
  *
- * $PostgreSQL: pgsql/src/include/commands/user.h,v 1.26 2005/02/20 02:22:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/user.h,v 1.27 2005/06/28 05:09:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -14,15 +14,11 @@
 #include "nodes/parsenodes.h"
 
 
-extern void CreateUser(CreateUserStmt *stmt);
-extern void AlterUser(AlterUserStmt *stmt);
-extern void AlterUserSet(AlterUserSetStmt *stmt);
-extern void DropUser(DropUserStmt *stmt);
-extern void RenameUser(const char *oldname, const char *newname);
-
-extern void CreateGroup(CreateGroupStmt *stmt);
-extern void AlterGroup(AlterGroupStmt *stmt, const char *tag);
-extern void DropGroup(DropGroupStmt *stmt);
-extern void RenameGroup(const char *oldname, const char *newname);
+extern void CreateRole(CreateRoleStmt *stmt);
+extern void AlterRole(AlterRoleStmt *stmt);
+extern void AlterRoleSet(AlterRoleSetStmt *stmt);
+extern void DropRole(DropRoleStmt *stmt);
+extern void GrantRole(GrantRoleStmt *stmt);
+extern void RenameRole(const char *oldname, const char *newname);
 
 #endif   /* USER_H */
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 6798a09ad988a90d1999cebc98c3c263e1941ab6..d170f303a4376bee0287805fc7ab2af24b57e92d 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -4,7 +4,7 @@
  *	  Interface to hba.c
  *
  *
- * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.37 2005/06/27 02:04:25 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.38 2005/06/28 05:09:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,11 +30,10 @@ typedef enum UserAuth
 
 typedef struct Port hbaPort;
 
-extern List **get_user_line(const char *user);
+extern List **get_role_line(const char *role);
 extern void load_hba(void);
 extern void load_ident(void);
-extern void load_user(void);
-extern void load_group(void);
+extern void load_role(void);
 extern int	hba_getauthmethod(hbaPort *port);
 extern int	authident(hbaPort *port);
 extern bool	read_pg_database_line(FILE *fp, char *dbname,
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 3e9b7d912a4b89ac9ed7526c5a8aff6b4aa949b1..8f6930cd1319ac1ccf24ed83dde8e4bd0d525be3 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.175 2005/02/26 18:43:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.176 2005/06/28 05:09:04 tgl Exp $
  *
  * NOTES
  *	  some of the information in this file should be moved to other files.
@@ -228,21 +228,21 @@ extern char *DatabasePath;
 /* now in utils/init/miscinit.c */
 extern void SetDatabasePath(const char *path);
 
-extern char *GetUserNameFromId(AclId userid);
-extern AclId GetUserId(void);
-extern void SetUserId(AclId userid);
-extern AclId GetSessionUserId(void);
-extern void SetSessionUserId(AclId userid);
-extern void InitializeSessionUserId(const char *username);
+extern char *GetUserNameFromId(Oid roleid);
+extern Oid GetUserId(void);
+extern void SetUserId(Oid roleid);
+extern Oid GetSessionUserId(void);
+extern void SetSessionUserId(Oid roleid);
+extern void InitializeSessionUserId(const char *rolename);
 extern void InitializeSessionUserIdStandalone(void);
-extern void SetSessionAuthorization(AclId userid, bool is_superuser);
+extern void SetSessionAuthorization(Oid roleid, bool is_superuser);
 
 extern void SetDataDir(const char *dir);
 extern char *make_absolute_path(const char *path);
 
 /* in utils/misc/superuser.c */
 extern bool superuser(void);	/* current user is superuser */
-extern bool superuser_arg(AclId userid);		/* given user is superuser */
+extern bool superuser_arg(Oid roleid);		/* given user is superuser */
 
 
 /*****************************************************************************
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index fd923f72af4d75fa1a31aed2ac2321c8f45b0844..3e623911c7011df68a5143d9d069b689d30dd428 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.171 2005/06/26 22:05:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.172 2005/06/28 05:09:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -224,6 +224,7 @@ typedef enum NodeTag
 	T_AlterDomainStmt,
 	T_SetOperationStmt,
 	T_GrantStmt,
+	T_GrantRoleStmt,
 	T_ClosePortalStmt,
 	T_ClusterStmt,
 	T_CopyStmt,
@@ -261,19 +262,16 @@ typedef enum NodeTag
 	T_DropPropertyStmt,
 	T_CreatePLangStmt,
 	T_DropPLangStmt,
-	T_CreateUserStmt,
-	T_AlterUserStmt,
-	T_DropUserStmt,
+	T_CreateRoleStmt,
+	T_AlterRoleStmt,
+	T_DropRoleStmt,
 	T_LockStmt,
 	T_ConstraintsSetStmt,
-	T_CreateGroupStmt,
-	T_AlterGroupStmt,
-	T_DropGroupStmt,
 	T_ReindexStmt,
 	T_CheckPointStmt,
 	T_CreateSchemaStmt,
 	T_AlterDatabaseSetStmt,
-	T_AlterUserSetStmt,
+	T_AlterRoleSetStmt,
 	T_CreateConversionStmt,
 	T_CreateCastStmt,
 	T_DropCastStmt,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index e011bb9f97855435cb4ffd1e719571644db70219..64acaa72e57f5e169a7a0bcd395637c2dc649f82 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.283 2005/06/22 21:14:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.284 2005/06/28 05:09:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -544,7 +544,7 @@ typedef struct RangeTblEntry
 	bool		inh;			/* inheritance requested? */
 	bool		inFromCl;		/* present in FROM clause? */
 	AclMode		requiredPerms;	/* bitmask of required access permissions */
-	AclId		checkAsUser;	/* if not zero, check access as this user */
+	Oid			checkAsUser;	/* if valid, check access as this role */
 } RangeTblEntry;
 
 /*
@@ -749,12 +749,12 @@ typedef enum ObjectType
 	OBJECT_DATABASE,
 	OBJECT_DOMAIN,
 	OBJECT_FUNCTION,
-	OBJECT_GROUP,
 	OBJECT_INDEX,
 	OBJECT_LANGUAGE,
 	OBJECT_LARGEOBJECT,
 	OBJECT_OPCLASS,
 	OBJECT_OPERATOR,
+	OBJECT_ROLE,
 	OBJECT_RULE,
 	OBJECT_SCHEMA,
 	OBJECT_SEQUENCE,
@@ -762,7 +762,6 @@ typedef enum ObjectType
 	OBJECT_TABLESPACE,
 	OBJECT_TRIGGER,
 	OBJECT_TYPE,
-	OBJECT_USER,
 	OBJECT_VIEW
 } ObjectType;
 
@@ -896,8 +895,7 @@ typedef struct GrantStmt
 typedef struct PrivGrantee
 {
 	NodeTag		type;
-	char	   *username;		/* if both are NULL then PUBLIC */
-	char	   *groupname;
+	char	   *rolname;		/* if NULL then PUBLIC */
 } PrivGrantee;
 
 /*
@@ -920,6 +918,23 @@ typedef struct PrivTarget
 	List	   *objs;
 } PrivTarget;
 
+/* ----------------------
+ *		Grant/Revoke Role Statement
+ *
+ * Note: the lists of roles are lists of names, as Value strings
+ * ----------------------
+ */
+typedef struct GrantRoleStmt
+{
+	NodeTag		type;
+	List	   *granted_roles;	/* list of roles to be granted/revoked */
+	List	   *grantee_roles;	/* list of member roles to add/delete */
+	bool		is_grant;		/* true = GRANT, false = REVOKE */
+	bool		admin_opt;		/* with admin option */
+	char	   *grantor;		/* set grantor to other than current role */
+	DropBehavior behavior;		/* drop behavior (for REVOKE) */
+} GrantRoleStmt;
+
 /* ----------------------
  *		Copy Statement
  * ----------------------
@@ -1123,61 +1138,37 @@ typedef struct DropPLangStmt
 } DropPLangStmt;
 
 /* ----------------------
- *	Create/Alter/Drop User Statements
+ *	Create/Alter/Drop Role Statements
  * ----------------------
  */
-typedef struct CreateUserStmt
+typedef struct CreateRoleStmt
 {
 	NodeTag		type;
-	char	   *user;			/* PostgreSQL user login name */
+	char	   *role;			/* role name */
 	List	   *options;		/* List of DefElem nodes */
-} CreateUserStmt;
+} CreateRoleStmt;
 
-typedef struct AlterUserStmt
+typedef struct AlterRoleStmt
 {
 	NodeTag		type;
-	char	   *user;			/* PostgreSQL user login name */
+	char	   *role;			/* role name */
 	List	   *options;		/* List of DefElem nodes */
-} AlterUserStmt;
+	int			action;			/* +1 = add members, -1 = drop members */
+} AlterRoleStmt;
 
-typedef struct AlterUserSetStmt
+typedef struct AlterRoleSetStmt
 {
 	NodeTag		type;
-	char	   *user;
-	char	   *variable;
-	List	   *value;
-} AlterUserSetStmt;
+	char	   *role;			/* role name */
+	char	   *variable;		/* GUC variable name */
+	List	   *value;			/* value for variable, or NIL for Reset */
+} AlterRoleSetStmt;
 
-typedef struct DropUserStmt
+typedef struct DropRoleStmt
 {
 	NodeTag		type;
-	List	   *users;			/* List of users to remove */
-} DropUserStmt;
-
-/* ----------------------
- *		Create/Alter/Drop Group Statements
- * ----------------------
- */
-typedef struct CreateGroupStmt
-{
-	NodeTag		type;
-	char	   *name;			/* name of the new group */
-	List	   *options;		/* List of DefElem nodes */
-} CreateGroupStmt;
-
-typedef struct AlterGroupStmt
-{
-	NodeTag		type;
-	char	   *name;			/* name of group to alter */
-	int			action;			/* +1 = add, -1 = drop user */
-	List	   *listUsers;		/* list of users to add/drop */
-} AlterGroupStmt;
-
-typedef struct DropGroupStmt
-{
-	NodeTag		type;
-	char	   *name;
-} DropGroupStmt;
+	List	   *roles;			/* List of roles to remove */
+} DropRoleStmt;
 
 /* ----------------------
  *		{Create|Alter} SEQUENCE Statement
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 2382ceae936047c18d2531fd69d5445f1bb57559..b6015f536c0c5282c8c90c71d32d531e7f3e36a5 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -5,7 +5,7 @@
  *
  *	Copyright (c) 2001-2005, PostgreSQL Global Development Group
  *
- *	$PostgreSQL: pgsql/src/include/pgstat.h,v 1.30 2005/06/25 23:58:58 tgl Exp $
+ *	$PostgreSQL: pgsql/src/include/pgstat.h,v 1.31 2005/06/28 05:09:04 tgl Exp $
  * ----------
  */
 #ifndef PGSTAT_H
@@ -101,7 +101,7 @@ typedef struct PgStat_MsgBestart
 {
 	PgStat_MsgHdr	m_hdr;
 	Oid				m_databaseid;
-	AclId			m_userid;
+	Oid 			m_userid;
 	SockAddr		m_clientaddr;
 } PgStat_MsgBestart;
 
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index ac04945bcd086576274ada19c284a82084ed5778..f055ac93aa30c64650232c1777affda4676e1af1 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.77 2005/01/27 23:36:14 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.78 2005/06/28 05:09:13 tgl Exp $
  *
  * NOTES
  *	  An ACL array is simply an array of AclItems, representing the union
@@ -29,84 +29,64 @@
 
 
 /*
- * typedef AclId is declared in c.h
- *
  * typedef AclMode is declared in parsenodes.h, also the individual privilege
  * bit meanings are defined there
  */
 
-#define ACL_ID_WORLD	0		/* placeholder for id in a WORLD acl item */
-
-/*
- * AclIdType	tag that describes if the AclId is a user, group, etc.
- */
-#define ACL_IDTYPE_WORLD		0x00	/* PUBLIC */
-#define ACL_IDTYPE_UID			0x01	/* user id - from pg_shadow */
-#define ACL_IDTYPE_GID			0x02	/* group id - from pg_group */
+#define ACL_ID_PUBLIC	0		/* placeholder for id in a PUBLIC acl item */
 
 /*
  * AclItem
  *
- * The IDTYPE included in ai_privs identifies the type of the grantee ID.
- * The grantor ID currently must always be a user, never a group.  (FIXME)
- *
  * Note: must be same size on all platforms, because the size is hardcoded
  * in the pg_type.h entry for aclitem.
  */
 typedef struct AclItem
 {
-	AclId		ai_grantee;		/* ID that this item grants privs to */
-	AclId		ai_grantor;		/* grantor of privs (always a user id) */
-	AclMode		ai_privs;		/* AclIdType plus privilege bits */
+	Oid			ai_grantee;		/* ID that this item grants privs to */
+	Oid			ai_grantor;		/* grantor of privs */
+	AclMode		ai_privs;		/* privilege bits */
 } AclItem;
 
 /*
- * The AclIdType is stored in the top two bits of the ai_privs field
- * of an AclItem.  The middle 15 bits are the grant option markers,
- * and the lower 15 bits are the actual privileges.  We use "rights"
+ * The upper 16 bits of the ai_privs field of an AclItem are the grant option
+ * bits, and the lower 16 bits are the actual privileges.  We use "rights"
  * to mean the combined grant option and privilege bits fields.
  */
-#define ACLITEM_GET_PRIVS(item)    ((item).ai_privs & 0x7FFF)
-#define ACLITEM_GET_GOPTIONS(item) (((item).ai_privs >> 15) & 0x7FFF)
-#define ACLITEM_GET_RIGHTS(item)   ((item).ai_privs & 0x3FFFFFFF)
-#define ACLITEM_GET_IDTYPE(item)   ((item).ai_privs >> 30)
+#define ACLITEM_GET_PRIVS(item)    ((item).ai_privs & 0xFFFF)
+#define ACLITEM_GET_GOPTIONS(item) (((item).ai_privs >> 16) & 0xFFFF)
+#define ACLITEM_GET_RIGHTS(item)   ((item).ai_privs)
 
-#define ACL_GRANT_OPTION_FOR(privs) (((AclMode) (privs) & 0x7FFF) << 15)
-#define ACL_OPTION_TO_PRIVS(privs)	(((AclMode) (privs) >> 15) & 0x7FFF)
+#define ACL_GRANT_OPTION_FOR(privs) (((AclMode) (privs) & 0xFFFF) << 16)
+#define ACL_OPTION_TO_PRIVS(privs)	(((AclMode) (privs) >> 16) & 0xFFFF)
 
 #define ACLITEM_SET_PRIVS(item,privs) \
-  ((item).ai_privs = ((item).ai_privs & ~((AclMode) 0x7FFF)) | \
-					 ((AclMode) (privs) & 0x7FFF))
+  ((item).ai_privs = ((item).ai_privs & ~((AclMode) 0xFFFF)) | \
+					 ((AclMode) (privs) & 0xFFFF))
 #define ACLITEM_SET_GOPTIONS(item,goptions) \
-  ((item).ai_privs = ((item).ai_privs & ~(((AclMode) 0x7FFF) << 15)) | \
-					 (((AclMode) (goptions) & 0x7FFF) << 15))
+  ((item).ai_privs = ((item).ai_privs & ~(((AclMode) 0xFFFF) << 16)) | \
+					 (((AclMode) (goptions) & 0xFFFF) << 16))
 #define ACLITEM_SET_RIGHTS(item,rights) \
-  ((item).ai_privs = ((item).ai_privs & ~((AclMode) 0x3FFFFFFF)) | \
-					 ((AclMode) (rights) & 0x3FFFFFFF))
-#define ACLITEM_SET_IDTYPE(item,idtype) \
-  ((item).ai_privs = ((item).ai_privs & ~(((AclMode) 0x03) << 30)) | \
-					 (((AclMode) (idtype) & 0x03) << 30))
+  ((item).ai_privs = (AclMode) (rights))
+
+#define ACLITEM_SET_PRIVS_GOPTIONS(item,privs,goptions) \
+  ((item).ai_privs = ((AclMode) (privs) & 0xFFFF) | \
+					 (((AclMode) (goptions) & 0xFFFF) << 16))
 
-#define ACLITEM_SET_PRIVS_IDTYPE(item,privs,goption,idtype) \
-  ((item).ai_privs = ((AclMode) (privs) & 0x7FFF) | \
-					 (((AclMode) (goption) & 0x7FFF) << 15) | \
-					 ((AclMode) (idtype) << 30))
 
-#define ACLITEM_ALL_PRIV_BITS		((AclMode) 0x7FFF)
-#define ACLITEM_ALL_GOPTION_BITS	((AclMode) 0x7FFF << 15)
+#define ACLITEM_ALL_PRIV_BITS		((AclMode) 0xFFFF)
+#define ACLITEM_ALL_GOPTION_BITS	((AclMode) 0xFFFF << 16)
 
 /*
  * Definitions for convenient access to Acl (array of AclItem) and IdList
- * (array of AclId).  These are standard PostgreSQL arrays, but are restricted
+ * (array of Oid).  These are standard PostgreSQL arrays, but are restricted
  * to have one dimension.  We also ignore the lower bound when reading,
  * and set it to one when writing.
  *
  * CAUTION: as of PostgreSQL 7.1, these arrays are toastable (just like all
  * other array types).	Therefore, be careful to detoast them with the
  * macros provided, unless you know for certain that a particular array
- * can't have been toasted.  Presently, we do not provide toast tables for
- * pg_class or pg_group, so the entries in those tables won't have been
- * stored externally --- but they could have been compressed!
+ * can't have been toasted.
  */
 
 
@@ -121,13 +101,13 @@ typedef ArrayType Acl;
 #define ACL_SIZE(ACL)			ARR_SIZE(ACL)
 
 /*
- * IdList		a one-dimensional array of AclId
+ * IdList		a one-dimensional array of Oid
  */
 typedef ArrayType IdList;
 
 #define IDLIST_NUM(IDL)			(ARR_DIMS(IDL)[0])
-#define IDLIST_DAT(IDL)			((AclId *) ARR_DATA_PTR(IDL))
-#define IDLIST_N_SIZE(N)		(ARR_OVERHEAD(1) + ((N) * sizeof(AclId)))
+#define IDLIST_DAT(IDL)			((Oid *) ARR_DATA_PTR(IDL))
+#define IDLIST_N_SIZE(N)		(ARR_OVERHEAD(1) + ((N) * sizeof(Oid)))
 #define IDLIST_SIZE(IDL)		ARR_SIZE(IDL)
 
 /*
@@ -221,14 +201,18 @@ typedef enum AclObjectKind
 /*
  * routines used internally
  */
-extern Acl *acldefault(GrantObjectType objtype, AclId ownerid);
+extern Acl *acldefault(GrantObjectType objtype, Oid ownerId);
 extern Acl *aclupdate(const Acl *old_acl, const AclItem *mod_aip,
-		  int modechg, AclId ownerid, DropBehavior behavior);
-extern Acl *aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid);
+		  int modechg, Oid ownerId, DropBehavior behavior);
+extern Acl *aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId);
 
-extern AclMode aclmask(const Acl *acl, AclId userid, AclId ownerid,
+extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId,
 		AclMode mask, AclMaskHow how);
 
+extern bool is_member_of_role(Oid member, Oid role);
+
+extern void InitializeAcl(void);
+
 /*
  * SQL functions (from acl.c)
  */
@@ -245,40 +229,39 @@ extern Datum hash_aclitem(PG_FUNCTION_ARGS);
  * prototypes for functions in aclchk.c
  */
 extern void ExecuteGrantStmt(GrantStmt *stmt);
-extern char *get_groname(AclId grosysid);
 
-extern AclMode pg_class_aclmask(Oid table_oid, AclId userid,
+extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
 				 AclMode mask, AclMaskHow how);
-extern AclMode pg_database_aclmask(Oid db_oid, AclId userid,
+extern AclMode pg_database_aclmask(Oid db_oid, Oid roleid,
 					AclMode mask, AclMaskHow how);
-extern AclMode pg_proc_aclmask(Oid proc_oid, AclId userid,
+extern AclMode pg_proc_aclmask(Oid proc_oid, Oid roleid,
 				AclMode mask, AclMaskHow how);
-extern AclMode pg_language_aclmask(Oid lang_oid, AclId userid,
+extern AclMode pg_language_aclmask(Oid lang_oid, Oid roleid,
 					AclMode mask, AclMaskHow how);
-extern AclMode pg_namespace_aclmask(Oid nsp_oid, AclId userid,
+extern AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
 					 AclMode mask, AclMaskHow how);
-extern AclMode pg_tablespace_aclmask(Oid spc_oid, AclId userid,
+extern AclMode pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
 					  AclMode mask, AclMaskHow how);
 
-extern AclResult pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode);
-extern AclResult pg_database_aclcheck(Oid db_oid, AclId userid, AclMode mode);
-extern AclResult pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode);
-extern AclResult pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode);
-extern AclResult pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode);
-extern AclResult pg_tablespace_aclcheck(Oid spc_oid, AclId userid, AclMode mode);
+extern AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode);
+extern AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode);
+extern AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode);
+extern AclResult pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode);
+extern AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode);
+extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode);
 
 extern void aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
 			   const char *objectname);
 
 /* ownercheck routines just return true (owner) or false (not) */
-extern bool pg_class_ownercheck(Oid class_oid, AclId userid);
-extern bool pg_type_ownercheck(Oid type_oid, AclId userid);
-extern bool pg_oper_ownercheck(Oid oper_oid, AclId userid);
-extern bool pg_proc_ownercheck(Oid proc_oid, AclId userid);
-extern bool pg_namespace_ownercheck(Oid nsp_oid, AclId userid);
-extern bool pg_tablespace_ownercheck(Oid spc_oid, AclId userid);
-extern bool pg_opclass_ownercheck(Oid opc_oid, AclId userid);
-extern bool pg_database_ownercheck(Oid db_oid, AclId userid);
-extern bool pg_conversion_ownercheck(Oid conv_oid, AclId userid);
+extern bool pg_class_ownercheck(Oid class_oid, Oid roleid);
+extern bool pg_type_ownercheck(Oid type_oid, Oid roleid);
+extern bool pg_oper_ownercheck(Oid oper_oid, Oid roleid);
+extern bool pg_proc_ownercheck(Oid proc_oid, Oid roleid);
+extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid);
+extern bool pg_tablespace_ownercheck(Oid spc_oid, Oid roleid);
+extern bool pg_opclass_ownercheck(Oid opc_oid, Oid roleid);
+extern bool pg_database_ownercheck(Oid db_oid, Oid roleid);
+extern bool pg_conversion_ownercheck(Oid conv_oid, Oid roleid);
 
 #endif   /* ACL_H */
diff --git a/src/include/utils/flatfiles.h b/src/include/utils/flatfiles.h
index 939239aa1b94c45c5912ca9a99abad9d48e43552..5faf35db57bf7f6eab43bd09692f8b389d912720 100644
--- a/src/include/utils/flatfiles.h
+++ b/src/include/utils/flatfiles.h
@@ -4,7 +4,7 @@
  *	  Routines for maintaining "flat file" images of the shared catalogs.
  *
  *
- * $PostgreSQL: pgsql/src/include/utils/flatfiles.h,v 1.4 2005/06/17 22:32:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/flatfiles.h,v 1.5 2005/06/28 05:09:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -14,12 +14,10 @@
 #include "fmgr.h"
 
 extern void database_file_update_needed(void);
-extern void group_file_update_needed(void);
-extern void user_file_update_needed(void);
+extern void auth_file_update_needed(void);
 
 extern char *database_getflatfilename(void);
-extern char *group_getflatfilename(void);
-extern char *user_getflatfilename(void);
+extern char *auth_getflatfilename(void);
 
 extern void BuildFlatFiles(bool database_only);
 
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index b0967edca57c83bac4cd09b823c4960c67d4d5b0..dfd785d5d10a4d745394b0e0e94b12d53255702f 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.99 2005/05/01 18:56:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.100 2005/06/28 05:09:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -104,8 +104,8 @@ extern void free_attstatsslot(Oid atttype,
 				  Datum *values, int nvalues,
 				  float4 *numbers, int nnumbers);
 extern char *get_namespace_name(Oid nspid);
-extern AclId get_usesysid(const char *username);
-extern AclId get_grosysid(char *groname);
+extern Oid get_roleid(const char *rolname);
+extern Oid get_roleid_checked(const char *rolname);
 
 #define is_array_type(typid)  (get_element_type(typid) != InvalidOid)
 
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 976788f40578d37ed420d60dba979b101702d151..8a30e08e184a6d1a278179917d84ea0da5e912d5 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.59 2005/03/29 00:17:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.60 2005/06/28 05:09:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,29 +36,29 @@
 #define AMPROCNUM		5
 #define ATTNAME			6
 #define ATTNUM			7
-#define CASTSOURCETARGET 8
-#define CLAAMNAMENSP	9
-#define CLAOID			10
-#define CONDEFAULT		11
-#define CONNAMENSP		12
-#define CONOID			13
-#define GRONAME			14
-#define GROSYSID		15
-#define INDEXRELID		16
-#define INHRELID		17
-#define LANGNAME		18
-#define LANGOID			19
-#define NAMESPACENAME	20
-#define NAMESPACEOID	21
-#define OPERNAMENSP		22
-#define OPEROID			23
-#define PROCNAMEARGSNSP	24
-#define PROCOID			25
-#define RELNAMENSP		26
-#define RELOID			27
-#define RULERELNAME		28
-#define SHADOWNAME		29
-#define SHADOWSYSID		30
+#define AUTHMEMMEMROLE	8
+#define AUTHMEMROLEMEM	9
+#define AUTHNAME		10
+#define AUTHOID			11
+#define CASTSOURCETARGET 12
+#define CLAAMNAMENSP	13
+#define CLAOID			14
+#define CONDEFAULT		15
+#define CONNAMENSP		16
+#define CONOID			17
+#define INDEXRELID		18
+#define INHRELID		19
+#define LANGNAME		20
+#define LANGOID			21
+#define NAMESPACENAME	22
+#define NAMESPACEOID	23
+#define OPERNAMENSP		24
+#define OPEROID			25
+#define PROCNAMEARGSNSP	26
+#define PROCOID			27
+#define RELNAMENSP		28
+#define RELOID			29
+#define RULERELNAME		30
 #define STATRELATT		31
 #define TYPENAMENSP		32
 #define TYPEOID			33
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 8ac111b5e18dc6db8f05444ba9ebd965815870a3..8fa8bb18ce38bbbd4631c91db64f69a1dff12d81 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -6,11 +6,12 @@ CREATE USER regressuser2;
 CREATE USER regressuser3;
 CREATE USER regressuser4;
 CREATE USER regressuser4;	-- duplicate
-ERROR:  user "regressuser4" already exists
+ERROR:  role "regressuser4" already exists
 CREATE GROUP regressgroup1;
 CREATE GROUP regressgroup2 WITH USER regressuser1, regressuser2;
 ALTER GROUP regressgroup1 ADD USER regressuser4;
 ALTER GROUP regressgroup2 ADD USER regressuser2;	-- duplicate
+NOTICE:  role "regressuser2" is already a member of role "regressgroup2"
 ALTER GROUP regressgroup2 DROP USER regressuser2;
 ALTER GROUP regressgroup2 ADD USER regressuser4;
 -- test owner privileges
@@ -275,7 +276,7 @@ DROP FUNCTION testfunc1(int); -- ok
 GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC;
 -- has_table_privilege function
 -- bad-input checks
-select has_table_privilege(NULL,'pg_shadow','select');
+select has_table_privilege(NULL,'pg_authid','select');
  has_table_privilege 
 ---------------------
  
@@ -283,36 +284,36 @@ select has_table_privilege(NULL,'pg_shadow','select');
 
 select has_table_privilege('pg_shad','select');
 ERROR:  relation "pg_shad" does not exist
-select has_table_privilege('nosuchuser','pg_shadow','select');
-ERROR:  user "nosuchuser" does not exist
-select has_table_privilege('pg_shadow','sel');
+select has_table_privilege('nosuchuser','pg_authid','select');
+ERROR:  role "nosuchuser" does not exist
+select has_table_privilege('pg_authid','sel');
 ERROR:  unrecognized privilege type: "sel"
-select has_table_privilege(-999999,'pg_shadow','update');
-ERROR:  user with ID 4293967297 does not exist
+select has_table_privilege(-999999,'pg_authid','update');
+ERROR:  role with OID 4293967297 does not exist
 select has_table_privilege(1,'rule');
 ERROR:  relation with OID 1 does not exist
 -- superuser
 \c -
-select has_table_privilege(current_user,'pg_shadow','select');
+select has_table_privilege(current_user,'pg_authid','select');
  has_table_privilege 
 ---------------------
  t
 (1 row)
 
-select has_table_privilege(current_user,'pg_shadow','insert');
+select has_table_privilege(current_user,'pg_authid','insert');
  has_table_privilege 
 ---------------------
  t
 (1 row)
 
-select has_table_privilege(t2.usesysid,'pg_shadow','update')
+select has_table_privilege(t2.usesysid,'pg_authid','update')
 from (select usesysid from pg_user where usename = current_user) as t2;
  has_table_privilege 
 ---------------------
  t
 (1 row)
 
-select has_table_privilege(t2.usesysid,'pg_shadow','delete')
+select has_table_privilege(t2.usesysid,'pg_authid','delete')
 from (select usesysid from pg_user where usename = current_user) as t2;
  has_table_privilege 
 ---------------------
@@ -320,21 +321,21 @@ from (select usesysid from pg_user where usename = current_user) as t2;
 (1 row)
 
 select has_table_privilege(current_user,t1.oid,'rule')
-from (select oid from pg_class where relname = 'pg_shadow') as t1;
+from (select oid from pg_class where relname = 'pg_authid') as t1;
  has_table_privilege 
 ---------------------
  t
 (1 row)
 
 select has_table_privilege(current_user,t1.oid,'references')
-from (select oid from pg_class where relname = 'pg_shadow') as t1;
+from (select oid from pg_class where relname = 'pg_authid') as t1;
  has_table_privilege 
 ---------------------
  t
 (1 row)
 
 select has_table_privilege(t2.usesysid,t1.oid,'select')
-from (select oid from pg_class where relname = 'pg_shadow') as t1,
+from (select oid from pg_class where relname = 'pg_authid') as t1,
   (select usesysid from pg_user where usename = current_user) as t2;
  has_table_privilege 
 ---------------------
@@ -342,34 +343,34 @@ from (select oid from pg_class where relname = 'pg_shadow') as t1,
 (1 row)
 
 select has_table_privilege(t2.usesysid,t1.oid,'insert')
-from (select oid from pg_class where relname = 'pg_shadow') as t1,
+from (select oid from pg_class where relname = 'pg_authid') as t1,
   (select usesysid from pg_user where usename = current_user) as t2;
  has_table_privilege 
 ---------------------
  t
 (1 row)
 
-select has_table_privilege('pg_shadow','update');
+select has_table_privilege('pg_authid','update');
  has_table_privilege 
 ---------------------
  t
 (1 row)
 
-select has_table_privilege('pg_shadow','delete');
+select has_table_privilege('pg_authid','delete');
  has_table_privilege 
 ---------------------
  t
 (1 row)
 
 select has_table_privilege(t1.oid,'select')
-from (select oid from pg_class where relname = 'pg_shadow') as t1;
+from (select oid from pg_class where relname = 'pg_authid') as t1;
  has_table_privilege 
 ---------------------
  t
 (1 row)
 
 select has_table_privilege(t1.oid,'trigger')
-from (select oid from pg_class where relname = 'pg_shadow') as t1;
+from (select oid from pg_class where relname = 'pg_authid') as t1;
  has_table_privilege 
 ---------------------
  t
@@ -546,8 +547,7 @@ SET SESSION AUTHORIZATION regressuser1;
 CREATE TABLE atest4 (a int);
 GRANT SELECT ON atest4 TO regressuser2 WITH GRANT OPTION;
 GRANT UPDATE ON atest4 TO regressuser2;
-GRANT SELECT ON atest4 TO GROUP regressgroup1 WITH GRANT OPTION; -- fail
-ERROR:  grant options can only be granted to individual users
+GRANT SELECT ON atest4 TO GROUP regressgroup1 WITH GRANT OPTION;
 SET SESSION AUTHORIZATION regressuser2;
 GRANT SELECT ON atest4 TO regressuser3;
 GRANT UPDATE ON atest4 TO regressuser3; -- fail
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 384ce37d9c29046d988155906723cb202daf9eda..47fc262c31569a4bc8898ac3f3e27ea10ba67ce4 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1277,12 +1277,15 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
          viewname         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
 --------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  iexit                    | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
+ pg_group                 | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
  pg_indexes               | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS "tablespace", pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
  pg_locks                 | SELECT l.locktype, l."database", l.relation, l.page, l.tuple, l.transactionid, l.classid, l.objid, l.objsubid, l."transaction", l.pid, l."mode", l.granted FROM pg_lock_status() l(locktype text, "database" oid, relation oid, page integer, tuple smallint, transactionid xid, classid oid, objid oid, objsubid smallint, "transaction" xid, pid integer, "mode" text, granted boolean);
- pg_prepared_xacts        | SELECT p."transaction", p.gid, p."prepared", u.usename AS "owner", d.datname AS "database" FROM ((pg_prepared_xact() p("transaction" xid, gid text, "prepared" timestamp with time zone, ownerid integer, dbid oid) LEFT JOIN pg_shadow u ON ((p.ownerid = u.usesysid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid)));
+ pg_prepared_xacts        | SELECT p."transaction", p.gid, p."prepared", u.rolname AS "owner", d.datname AS "database" FROM ((pg_prepared_xact() p("transaction" xid, gid text, "prepared" timestamp with time zone, ownerid oid, dbid oid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid)));
+ pg_roles                 | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, '********'::text AS rolpassword, pg_authid.rolvaliduntil, pg_authid.rolconfig FROM pg_authid;
  pg_rules                 | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
  pg_settings              | SELECT a.name, a.setting, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a(name text, setting text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text);
- pg_stat_activity         | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_activity_start(s.backendid) AS query_start, pg_stat_get_backend_start(s.backendid) AS backend_start, pg_stat_get_backend_client_addr(s.backendid) AS client_addr, pg_stat_get_backend_client_port(s.backendid) AS client_port FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_shadow u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.usesysid));
+ pg_shadow                | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, pg_authid.rolconfig AS useconfig FROM pg_authid WHERE pg_authid.rolcanlogin;
+ pg_stat_activity         | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.rolname AS usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_activity_start(s.backendid) AS query_start, pg_stat_get_backend_start(s.backendid) AS backend_start, pg_stat_get_backend_client_addr(s.backendid) AS client_addr, pg_stat_get_backend_client_port(s.backendid) AS client_port FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_authid u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.oid));
  pg_stat_all_indexes      | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'r'::"char");
  pg_stat_all_tables       | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, sum(pg_stat_get_numscans(i.indexrelid)) AS idx_scan, sum(pg_stat_get_tuples_fetched(i.indexrelid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'r'::"char") GROUP BY c.oid, n.nspname, c.relname;
  pg_stat_database         | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit FROM pg_database d;
@@ -1317,7 +1320,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
  shoelace_obsolete        | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
  street                   | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
  toyemp                   | SELECT emp.name, emp.age, emp."location", (12 * emp.salary) AS annualsal FROM emp;
-(41 rows)
+(44 rows)
 
 SELECT tablename, rulename, definition FROM pg_rules 
 	ORDER BY tablename, rulename;
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 00abd941ccfdf6119cb2bed9b58c88ffa974ded8..581146bbd70b48a937e9ac6e13656c45a87351fb 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -37,6 +37,8 @@ SELECT relname, relhasindex
  pg_amproc           | t
  pg_attrdef          | t
  pg_attribute        | t
+ pg_auth_members     | t
+ pg_authid           | t
  pg_cast             | t
  pg_class            | t
  pg_constraint       | t
@@ -44,7 +46,6 @@ SELECT relname, relhasindex
  pg_database         | t
  pg_depend           | t
  pg_description      | t
- pg_group            | t
  pg_index            | t
  pg_inherits         | t
  pg_language         | t
@@ -54,7 +55,6 @@ SELECT relname, relhasindex
  pg_operator         | t
  pg_proc             | t
  pg_rewrite          | t
- pg_shadow           | t
  pg_statistic        | t
  pg_tablespace       | t
  pg_trigger          | t
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 3e224c556a205f8a1acb5171b200743f7b10fb78..aa65bf599d24700fc17511747a3551e79f3673b0 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -192,43 +192,43 @@ GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC;
 -- has_table_privilege function
 
 -- bad-input checks
-select has_table_privilege(NULL,'pg_shadow','select');
+select has_table_privilege(NULL,'pg_authid','select');
 select has_table_privilege('pg_shad','select');
-select has_table_privilege('nosuchuser','pg_shadow','select');
-select has_table_privilege('pg_shadow','sel');
-select has_table_privilege(-999999,'pg_shadow','update');
+select has_table_privilege('nosuchuser','pg_authid','select');
+select has_table_privilege('pg_authid','sel');
+select has_table_privilege(-999999,'pg_authid','update');
 select has_table_privilege(1,'rule');
 
 -- superuser
 \c -
 
-select has_table_privilege(current_user,'pg_shadow','select');
-select has_table_privilege(current_user,'pg_shadow','insert');
+select has_table_privilege(current_user,'pg_authid','select');
+select has_table_privilege(current_user,'pg_authid','insert');
 
-select has_table_privilege(t2.usesysid,'pg_shadow','update')
+select has_table_privilege(t2.usesysid,'pg_authid','update')
 from (select usesysid from pg_user where usename = current_user) as t2;
-select has_table_privilege(t2.usesysid,'pg_shadow','delete')
+select has_table_privilege(t2.usesysid,'pg_authid','delete')
 from (select usesysid from pg_user where usename = current_user) as t2;
 
 select has_table_privilege(current_user,t1.oid,'rule')
-from (select oid from pg_class where relname = 'pg_shadow') as t1;
+from (select oid from pg_class where relname = 'pg_authid') as t1;
 select has_table_privilege(current_user,t1.oid,'references')
-from (select oid from pg_class where relname = 'pg_shadow') as t1;
+from (select oid from pg_class where relname = 'pg_authid') as t1;
 
 select has_table_privilege(t2.usesysid,t1.oid,'select')
-from (select oid from pg_class where relname = 'pg_shadow') as t1,
+from (select oid from pg_class where relname = 'pg_authid') as t1,
   (select usesysid from pg_user where usename = current_user) as t2;
 select has_table_privilege(t2.usesysid,t1.oid,'insert')
-from (select oid from pg_class where relname = 'pg_shadow') as t1,
+from (select oid from pg_class where relname = 'pg_authid') as t1,
   (select usesysid from pg_user where usename = current_user) as t2;
 
-select has_table_privilege('pg_shadow','update');
-select has_table_privilege('pg_shadow','delete');
+select has_table_privilege('pg_authid','update');
+select has_table_privilege('pg_authid','delete');
 
 select has_table_privilege(t1.oid,'select')
-from (select oid from pg_class where relname = 'pg_shadow') as t1;
+from (select oid from pg_class where relname = 'pg_authid') as t1;
 select has_table_privilege(t1.oid,'trigger')
-from (select oid from pg_class where relname = 'pg_shadow') as t1;
+from (select oid from pg_class where relname = 'pg_authid') as t1;
 
 -- non-superuser
 SET SESSION AUTHORIZATION regressuser3;
@@ -298,7 +298,7 @@ CREATE TABLE atest4 (a int);
 
 GRANT SELECT ON atest4 TO regressuser2 WITH GRANT OPTION;
 GRANT UPDATE ON atest4 TO regressuser2;
-GRANT SELECT ON atest4 TO GROUP regressgroup1 WITH GRANT OPTION; -- fail
+GRANT SELECT ON atest4 TO GROUP regressgroup1 WITH GRANT OPTION;
 
 SET SESSION AUTHORIZATION regressuser2;