Replace pg_shadow and pg_group by new role-capable catalogs pg_authid
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 28 Jun 2005 05:09:14 +0000 (05:09 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 28 Jun 2005 05:09:14 +0000 (05:09 +0000)
and pg_auth_members.  There are still many loose ends to finish in this
patch (no documentation, no regression tests, no pg_dump support for
instance).  But I'm going to commit it now anyway so that Alvaro can
make some progress on shared dependencies.  The catalog changes should
be pretty much done.

96 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/func.sgml
src/backend/access/transam/twophase.c
src/backend/access/transam/xact.c
src/backend/catalog/Makefile
src/backend/catalog/aclchk.c
src/backend/catalog/genbki.sh
src/backend/catalog/information_schema.sql
src/backend/catalog/namespace.c
src/backend/catalog/pg_conversion.c
src/backend/catalog/pg_namespace.c
src/backend/catalog/pg_operator.c
src/backend/catalog/pg_proc.c
src/backend/catalog/pg_type.c
src/backend/catalog/system_views.sql
src/backend/commands/aggregatecmds.c
src/backend/commands/alter.c
src/backend/commands/conversioncmds.c
src/backend/commands/copy.c
src/backend/commands/dbcommands.c
src/backend/commands/functioncmds.c
src/backend/commands/opclasscmds.c
src/backend/commands/operatorcmds.c
src/backend/commands/schemacmds.c
src/backend/commands/tablecmds.c
src/backend/commands/tablespace.c
src/backend/commands/typecmds.c
src/backend/commands/user.c
src/backend/commands/variable.c
src/backend/executor/execMain.c
src/backend/executor/nodeAgg.c
src/backend/libpq/crypt.c
src/backend/libpq/hba.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/parser/parse_relation.c
src/backend/postmaster/pgstat.c
src/backend/postmaster/postmaster.c
src/backend/rewrite/rewriteDefine.c
src/backend/rewrite/rewriteHandler.c
src/backend/tcop/utility.c
src/backend/utils/adt/acl.c
src/backend/utils/adt/pgstatfuncs.c
src/backend/utils/adt/ri_triggers.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/lsyscache.c
src/backend/utils/cache/syscache.c
src/backend/utils/fmgr/fmgr.c
src/backend/utils/init/flatfiles.c
src/backend/utils/init/miscinit.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/superuser.c
src/bin/initdb/initdb.c
src/include/access/twophase.h
src/include/c.h
src/include/catalog/catversion.h
src/include/catalog/indexing.h
src/include/catalog/pg_attribute.h
src/include/catalog/pg_auth_members.h [new file with mode: 0644]
src/include/catalog/pg_authid.h [new file with mode: 0644]
src/include/catalog/pg_class.h
src/include/catalog/pg_conversion.h
src/include/catalog/pg_database.h
src/include/catalog/pg_group.h [deleted file]
src/include/catalog/pg_namespace.h
src/include/catalog/pg_opclass.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/catalog/pg_shadow.h [deleted file]
src/include/catalog/pg_tablespace.h
src/include/catalog/pg_type.h
src/include/commands/conversioncmds.h
src/include/commands/dbcommands.h
src/include/commands/defrem.h
src/include/commands/schemacmds.h
src/include/commands/tablespace.h
src/include/commands/typecmds.h
src/include/commands/user.h
src/include/libpq/hba.h
src/include/miscadmin.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/pgstat.h
src/include/utils/acl.h
src/include/utils/flatfiles.h
src/include/utils/lsyscache.h
src/include/utils/syscache.h
src/test/regress/expected/privileges.out
src/test/regress/expected/rules.out
src/test/regress/expected/sanity_check.out
src/test/regress/sql/privileges.sql

index 2b1318b05e4f87b6832063ff1ae491e3ae200696..7358dfb5122e3b44d6c01635bb10df404cb1d792 100644 (file)
@@ -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">
       <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>
       <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>
       <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>
  </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>
 
 
      <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>
 
 
      <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>
 
 
      <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>
 
  </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>
 
 
      <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>
 
 
      <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>
 
      <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>
 
 
      <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>
 
  </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>
 
      <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>
 
 
      <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>
 
     </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>
       <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>
       <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>
   </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>
 
      <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>
 
  </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>
 
 
  </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>
 
      <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>
    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>
 
      <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>
index d7430f1ccf8053623d8d15eecfabd4e42b31e051..734686bf4a4317e50e5beb14c40874cbd3679f0c 100644 (file)
@@ -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
index 7c8102d87c92d4db9ff825074233442f5d0dd6db..ccd8b802157ad16bebd4a067fab19cf72a755fe9 100644 (file)
@@ -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 */
index 98e56c400202c45514c291f659a47470df1360b0..a5d53d3e1457381b140677ead6d89cadc6b646a0 100644 (file)
@@ -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
index a77b41b441ff6b6ba4acb7768e9fb1589a8f8ee1..09addc4af1cb3968404c52af58ad290b6b5cd93e 100644 (file)
@@ -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)
index 5eba84f995fddcd497abc477c622e756334afc9e..6ff89eb0425b52c87eed91aa6cc7fbfb1fe781ca 100644 (file)
@@ -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.
 #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);
 }
index 92a3ac5eeccca31c364c33a88ce7c22ae0ad3afa..9d9b75bde58aadc4af39c123b44fa962df302549 100644 (file)
@@ -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 '
index 83e6fa82b0f2976c449fd23d37e3866dcfd5b39a..6d90887ba6c2a8391a3c952103bf8a47358d558f 100644 (file)
@@ -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');
 
index 3cfcc6f9b46b97f2e8d5b7aeb5e49b0a52d5d925..6b12bda661548e6f59e72866a6a07627788823eb 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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();
    }
index 797583f6c04a51701857651fe1742e3c07e0d500..61a1a53902ab998e6eef43b77165e883b64b0fff 100644 (file)
@@ -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);
index c2266f22d4dfa4fbbcd9d331dc2d138527aded4f..8144d64136b5c2bef83fe94294353ec02f91239c 100644 (file)
@@ -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);
index 6f50e4dabddb969fa3b5a9836cbbf437896e9887..55fa9e127cf14d2d7e91456ef8cd1a718663a0c6 100644 (file)
@@ -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 */
index 12f6c64634f0e874a00e3d17f34939c99e146a6e..7d1384ed382be8530fb1e9a3fa66073e1edab905 100644 (file)
@@ -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);
index acadded40d782de1006cf62477726233dc57fdee..fa4068bf9f60b6cdf6f165cdae0c113935fc0929 100644 (file)
@@ -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 */
index f757e21039d716e0a5aaef9739355e3e754868f2..d20a3b6d7f21c673620757d25d816a2bdaf448ae 100644 (file)
@@ -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 
index 9833937b705ec6189d2d744cdd000abd4bc78598..6335757981ec32eb50cee43498cab6e56393ebf1 100644 (file)
@@ -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);
index 9bb40f351649531450827925231dc0d3b1220745..a19b500152da82fb2666c0f1964da076a75fae8e 100644 (file)
@@ -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)
    {
index fb71bf59f92f6660910d49f6105390d7d7656fa5..c2aa48614e6afbab43ae6febb0963db42f42149a 100644 (file)
@@ -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);
 
index 30eeefded8e4e1d6deeafb72a59208e64d644ecf..10e68684b8e6e62f3e141b6a05da72f4eb8e1637 100644 (file)
@@ -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"
index 6fa6aa5b44bacc07063b7772b7ae73952c7a70bd..1dac14ead2e6ad0285ca51adc84d8c8907adae9a 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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;
index ea3c381183713a8745a50cbe0567dbd0f32f46e1..3329822fe623e6a8df678a264d0f86c07d1fc62e 100644 (file)
@@ -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);
        }
index e64924c43a7385b31fc54fcd9e6c368d4bc7f9f9..3610269644a47eebede50bff8072a749b7194771 100644 (file)
@@ -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);
 
index 45dc1eafeaa427a58f7f60b89a0e2cc53cf3baf4..adea1b2b5d737a41694b1ecb1c7ca9e60304bfb2 100644 (file)
@@ -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);
 
index 5754c1dfcb4f8da5d3d0baf87d9908b89d15c8cf..d92812f1fcfc4994a8170795799fc5ffcebd0fb9 100644 (file)
@@ -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);
        }
index 9981129c0ebf579b7d3441c77aab25e39b30ca4a..dda9532baf857b6721cafcecdc6581f75bd9488c 100644 (file)
@@ -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);
index a469a8fa349ff43bb726eb19625b22aa7964bb9d..15a263b8efd2a7aaad5718979d4b0ce54719e66a 100644 (file)
@@ -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);
        }
index 280022feaa1e45e6902f61123ca5e029e1770187..53570c77409bc13498d80b6e1de73678dc266a92 100644 (file)
@@ -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);
 
index 3c70c579785e6fb27b905313e6cfe4dd3da2fa77..131f1896f928c563d39e4ddae58693eff2803799 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 #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"
 
 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);
 }
index 048a3e41562f70b001388389b74fb75ef454c7fb..7df2a92a6c6c32f575c6b3cb877104dc427c072e 100644 (file)
@@ -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 == ',');
 
index 938474610ae80df3fcb45d2ac22118d6a2248481..3ef33cfd39fc8278fcf20d0512a601014352e1d4 100644 (file)
@@ -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
index 5b5499454b81627774e00b7822adaeeacee94f76..b7a0bc344ffe932208452767be1fe203cabb78b4 100644 (file)
@@ -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),
index 58e80334f6100afa7bec00a891f799ea8c4f460a..d9c95d1b9ac8567b1da3768e3851464af56a1951 100644 (file)
@@ -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)
index ab5d7e41674f9d9370b554966dca53a0dd65a0f3..52608eb45371af4c37b9b46a12b712573500604e 100644 (file)
@@ -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;
index b6885f0d14932b0e74e2aa3a824b44aaf078ed18..ce16d2eba182fec697bfa0b626114839132495cf 100644 (file)
@@ -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;
index 31a2c302244a20d8394b6e65a4865bdb31b71c9a..ade4f16a090885c880ed1e4ab42479aad84a5701 100644 (file)
@@ -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;
index 91705123bd7959c8db8f0e8a4950a674c3716972..81fb9c88fa6d2bff3402fff4bc4917e90c7373ce 100644 (file)
@@ -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
index 9b27dc478ef8c42268104ccc177ad0300c23d7f1..2e9c842051a39e4c92ca38295abeef86d1f19b62 100644 (file)
@@ -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();
 }
index 28e1ac0264d1642344004743960a6e8f68b09836..d822a7176a72cc9a32af4d9ac1e2cab5564a35b0 100644 (file)
@@ -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
index 41e45bc7475d71489acf085c871581ec743c05eb..a11d4affc1df3ea385f0e476d6d8b06353589d6a 100644 (file)
@@ -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},
index 5786ac44d0709fb6c54559e3537be849d9e3b67f..51d200736b08ef46a909804e8daacb35b836ab37 100644 (file)
@@ -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
index 8366bdb8b4cec4aa9bbdcaa5a8e526d2b7dd14b6..b429275d9f65041ece7982b49c0e4769019771e4 100644 (file)
@@ -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"
index 6ca13944f8aca04833869659a80a9a437cdf0710..27b28b89f544e6e9259d21df47619220694d6535 100644 (file)
@@ -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))
index c793cabd2a9afc107c6045e6a2bec39c88c4d6a6..c28ea627e507d5822e7861fb463bc927b2a0f2dd 100644 (file)
@@ -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;
index b7a96922e9481a1589508464277f8ba467c8dba0..3677fd2ebac17312c101e6822ed7cd6a100e3941 100644 (file)
@@ -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?
index 82bd8eafc1185ba8b91f0b58483379bdb0bc341f..40d5e7d7ce6cf9b20b2ca889203c0dc544b25924 100644 (file)
@@ -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;
index 68b34f3dce58bc747fe014678057ad317fc74a16..4d5904b76901dc4526a9d88feff36291ad1a7f63 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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,&n