From 96147a6d1c15b7604838dcd5de5ebd771f551d96 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Sun, 27 May 2001 09:59:30 +0000
Subject: [PATCH] Make UPDATE and DELETE privileges distinct.  Add REFERENCES
 and TRIGGER privileges.  INSERT and COPY FROM now require INSERT (only).  Add
 privileges regression test.

---
 doc/src/sgml/ref/copy.sgml               |   6 +-
 doc/src/sgml/ref/create_rule.sgml        |   6 +-
 doc/src/sgml/ref/create_trigger.sgml     |   6 +-
 doc/src/sgml/ref/delete.sgml             |   6 +-
 doc/src/sgml/ref/grant.sgml              | 555 ++++++++---------------
 doc/src/sgml/ref/insert.sgml             |   6 +-
 doc/src/sgml/ref/psql-ref.sgml           |   6 +-
 doc/src/sgml/ref/revoke.sgml             | 394 +++-------------
 doc/src/sgml/ref/select.sgml             |   6 +-
 doc/src/sgml/ref/update.sgml             |   6 +-
 src/backend/catalog/aclchk.c             |  28 +-
 src/backend/commands/command.c           |   7 +-
 src/backend/commands/comment.c           |   4 +-
 src/backend/commands/copy.c              |   4 +-
 src/backend/commands/sequence.c          |   8 +-
 src/backend/commands/trigger.c           |   8 +-
 src/backend/executor/execMain.c          |  15 +-
 src/backend/parser/gram.y                |  32 +-
 src/backend/tcop/utility.c               |   6 +-
 src/backend/utils/adt/acl.c              |  46 +-
 src/include/utils/acl.h                  |  33 +-
 src/test/regress/expected/privileges.out | 198 ++++++++
 src/test/regress/parallel_schedule       |   1 +
 src/test/regress/pg_regress.sh           |  14 +-
 src/test/regress/serial_schedule         |   3 +-
 src/test/regress/sql/privileges.sql      | 146 ++++++
 26 files changed, 724 insertions(+), 826 deletions(-)
 create mode 100644 src/test/regress/expected/privileges.out
 create mode 100644 src/test/regress/sql/privileges.sql

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 6019eb7a089..3c4dd31a5a2 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -1,13 +1,11 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/copy.sgml,v 1.20 2001/01/13 23:58:55 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/copy.sgml,v 1.21 2001/05/27 09:59:27 petere Exp $
 Postgres documentation
 -->
 
 <refentry id="SQL-COPY">
  <refmeta>
-  <refentrytitle id="sql-copy-title">
-   COPY
-  </refentrytitle>
+  <refentrytitle id="sql-copy-title">COPY</refentrytitle>
   <refmiscinfo>SQL - Language Statements</refmiscinfo>
  </refmeta>
  <refnamediv>
diff --git a/doc/src/sgml/ref/create_rule.sgml b/doc/src/sgml/ref/create_rule.sgml
index e6a1a7b1468..430026a7863 100644
--- a/doc/src/sgml/ref/create_rule.sgml
+++ b/doc/src/sgml/ref/create_rule.sgml
@@ -1,13 +1,11 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_rule.sgml,v 1.22 2001/01/13 23:58:55 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_rule.sgml,v 1.23 2001/05/27 09:59:27 petere Exp $
 Postgres documentation
 -->
 
 <refentry id="SQL-CREATERULE">
  <refmeta>
-  <refentrytitle id="sql-createrule-title">
-   CREATE RULE
-  </refentrytitle>
+  <refentrytitle id="sql-createrule-title">CREATE RULE</refentrytitle>
   <refmiscinfo>SQL - Language Statements</refmiscinfo>
  </refmeta>
  <refnamediv>
diff --git a/doc/src/sgml/ref/create_trigger.sgml b/doc/src/sgml/ref/create_trigger.sgml
index c4fbe0203bf..1dc633ce9d1 100644
--- a/doc/src/sgml/ref/create_trigger.sgml
+++ b/doc/src/sgml/ref/create_trigger.sgml
@@ -1,13 +1,11 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_trigger.sgml,v 1.12 2000/10/05 19:48:18 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_trigger.sgml,v 1.13 2001/05/27 09:59:28 petere Exp $
 Postgres documentation
 -->
 
 <refentry id="SQL-CREATETRIGGER">
  <refmeta>
-  <refentrytitle id="SQL-CREATETRIGGER-TITLE">
-   CREATE TRIGGER
-  </refentrytitle>
+  <refentrytitle id="SQL-CREATETRIGGER-TITLE">CREATE TRIGGER</refentrytitle>
   <refmiscinfo>SQL - Language Statements</refmiscinfo>
  </refmeta>
  <refnamediv>
diff --git a/doc/src/sgml/ref/delete.sgml b/doc/src/sgml/ref/delete.sgml
index 1f684b946f8..261ac327080 100644
--- a/doc/src/sgml/ref/delete.sgml
+++ b/doc/src/sgml/ref/delete.sgml
@@ -1,13 +1,11 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/delete.sgml,v 1.12 2001/01/13 23:58:55 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/delete.sgml,v 1.13 2001/05/27 09:59:28 petere Exp $
 Postgres documentation
 -->
 
 <refentry id="SQL-DELETE">
  <refmeta>
-  <refentrytitle id="SQL-DELETE-TITLE">
-   DELETE
-  </refentrytitle>
+  <refentrytitle id="SQL-DELETE-TITLE">DELETE</refentrytitle>
   <refmiscinfo>SQL - Language Statements</refmiscinfo>
  </refmeta>
  <refnamediv>
diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index 9770c3dd542..1399d049d77 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -1,444 +1,253 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.9 2000/10/05 19:48:18 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.10 2001/05/27 09:59:28 petere Exp $
 Postgres documentation
 -->
 
 <refentry id="SQL-GRANT">
  <refmeta>
-  <refentrytitle id="SQL-GRANT-TITLE">
-   GRANT
-  </refentrytitle>
+  <refentrytitle>GRANT</refentrytitle>
   <refmiscinfo>SQL - Language Statements</refmiscinfo>
  </refmeta>
+
  <refnamediv>
-  <refname>
-   GRANT
-  </refname>
-  <refpurpose>
-   Grants access privilege to a user, a group or all users
-  </refpurpose>
+  <refname>GRANT</refname>
+  <refpurpose>Grants access privileges to a user, a group, or all users</refpurpose>
  </refnamediv>
- <refsynopsisdiv>
-  <refsynopsisdivinfo>
-   <date>1999-07-20</date>
-  </refsynopsisdivinfo>
-  <synopsis>
-GRANT <replaceable class="PARAMETER">privilege</replaceable> [, ...] ON <replaceable class="PARAMETER">object</replaceable> [, ...]
-    TO { PUBLIC | GROUP <replaceable class="PARAMETER">group</replaceable> | <replaceable class="PARAMETER">username</replaceable> }
-  </synopsis>
-    
-  <refsect2 id="R2-SQL-GRANT-1">
-   <refsect2info>
-    <date>1998-09-23</date>
-   </refsect2info>
-   <title>
-    Inputs
-   </title>
-   <para>
-
-    <variablelist>
-     <varlistentry>
-      <term><replaceable class="PARAMETER">privilege</replaceable></term>
-      <listitem>
-       <para>
-	The possible privileges are:
-
-	<variablelist>
-	 <varlistentry>
-	  <term>SELECT</term>
-	  <listitem>
-	   <para>
-	    Access all of the columns of a specific
-	    table/view.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>INSERT</term>
-	  <listitem>
-	   <para>
-	    Insert data into all columns of a
-	    specific table.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>UPDATE</term>
-	  <listitem>
-	   <para>
-	    Update all columns of a specific
-	    table.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>DELETE</term>
-	  <listitem>
-	   <para>
-	    Delete rows from a specific table.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>RULE</term>
-	  <listitem>
-	   <para>
-	    Define rules on the table/view
-	    (See CREATE RULE statement).
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>ALL</term>
-	  <listitem>
-	   <para>
-	    Grant all privileges.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-	</variablelist>
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="PARAMETER">object</replaceable></term>
-      <listitem>
-       <para>
-	The name of an object to which to grant access.
-	The possible objects are:
-
-	<itemizedlist spacing="compact" mark="bullet">
-	 <listitem>
-	  <para>
-	   table 
-	  </para>
-	 </listitem>
-
-	 <listitem>
-	  <para>
-	   view 
-	  </para>
-	 </listitem>
-
-	 <listitem>
-	  <para>
-	   sequence
-	  </para>
-	 </listitem>
-
-	</itemizedlist>
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term>PUBLIC</term>
-      <listitem>
-       <para>
-	A short form representing all users.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term>GROUP <replaceable class="PARAMETER">group</replaceable></term>
-      <listitem>
-       <para>
-	A <replaceable class="PARAMETER">group</replaceable> to whom to grant privileges.
-       </para>
-      </listitem>
-     </varlistentry>	
-
-     <varlistentry>
-      <term>
-       <replaceable class="PARAMETER">username</replaceable>
-      </term>
-      <listitem>
-       <para>
-	The name of a user to whom to grant privileges. PUBLIC is a short form
-	representing all users.
-       </para>
-      </listitem>
-     </varlistentry>	
-    </variablelist>
-   </para>
-  </refsect2>
-
-  <refsect2 id="R2-SQL-GRANT-2">
-   <refsect2info>
-    <date>1998-09-23</date>
-   </refsect2info>
-   <title>
-    Outputs
-   </title>
-   <para>
 
-    <variablelist>
-     <varlistentry>
-      <term><computeroutput>
-CHANGE
-       </computeroutput></term>
-      <listitem>
-       <para>
-	Message returned if successful.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><computeroutput>
-ERROR:  ChangeAcl: class "<replaceable class="PARAMETER">object</replaceable>" not found
-       </computeroutput></term>
-      <listitem>
-       <para>
-	Message returned if the specified object is not available or 
-	if it is impossible
-	to give privileges to the specified group or users.
-       </para>
-      </listitem>
-     </varlistentry>	
-    </variablelist>
-   </para>
-  </refsect2>
+ <refsynopsisdiv>
+<synopsis>
+GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] }
+    ON [ TABLE ] <replaceable class="PARAMETER">objectname</replaceable> [, ...]
+    TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC }
+</synopsis>
  </refsynopsisdiv>
 
- <refsect1 id="R1-SQL-GRANT-1">
-  <refsect1info>
-   <date>1998-09-23</date>
-  </refsect1info>
-  <title>
-   Description
-  </title>
+ <refsect1 id="sql-grant-description">
+  <title>Description</title>
+
+  <para>
+   The <command>GRANT</command> command gives specific permissions on
+   an object (table, view, sequence) to a user or a group of users.
+   The special key word <literal>PUBLIC</literal> indicates that the
+   privileges are to be granted to all users, including those that may
+   be created later.
+  </para>
 
   <para>
-   <command>GRANT</command> allows the creator of an object to give specific permissions to
-   all users (PUBLIC) or to a certain user or group. 
-   Users other than the creator don't have any access permission 
-   unless the creator GRANTs permissions, after the object
-   is created.
+   Users other than the creator do not have any access privileges
+   unless the creator grants permissions, after the object is created.
+   There is no need to grant privileges to the creator of an object,
+   as the creator automatically holds all privileges, and can also
+   drop the object.
   </para>
 
   <para>
-   Once a user has a privilege on an object, he is enabled to exercise
-   that privilege.
-   There is no need to GRANT privileges to the creator of 
-   an object, the creator automatically holds ALL privileges, and can 
-   also drop the object. 
+   The possible privileges are:
+
+   <variablelist>
+    <varlistentry>
+     <term>SELECT</term>
+     <listitem>
+      <para>
+       Allows <xref linkend="sql-select"> from any column of the
+       specified table, view, or sequence.  Also allows the use of
+       <xref linkend="sql-copy"> FROM.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>INSERT</term>
+     <listitem>
+      <para>
+       Allows <xref linkend="sql-insert"> of a new row into the
+       specified table.  Also allows <xref linkend="sql-copy"> TO.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>UPDATE</term>
+     <listitem>
+      <para>
+       Allows <xref linkend="sql-update"> of any column of the
+       specified table.  <literal>SELECT ... FOR UPDATE</literal>
+       also requires this privilege (besides the
+       <literal>SELECT</literal> privilege).  For sequences, this
+       privilege allows the use of <function>currval</function> and
+       <function>nextval</function>.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>DELETE</term>
+     <listitem>
+      <para>
+       Allows the <xref linkend="sql-delete"> of a row from the
+       specified table.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>RULE</term>
+     <listitem>
+      <para>
+       Allows the creation of a rule on the table/view.  (See <xref
+       linkend="sql-createrule"> statement).
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>REFERENCES</term>
+     <listitem>
+      <para>
+       To create of a table with a foreign key constraint, it is
+       necessary to have this privilege on the table with the primary
+       key.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>TRIGGER</term>
+     <listitem>
+      <para>
+       Allows the creation of a trigger on the specified table.  (See
+       <xref linkend="sql-createtrigger"> statement).
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>ALL PRIVILEGES</term>
+     <listitem>
+      <para>
+       Grant all of the above privileges at once.  The
+       <literal>PRIVILEGES</literal> key word is optional, but it is
+       required by strict SQL.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+
+   The privileges required by other commands are listed on the
+   reference page of the respective command.
   </para>
+ </refsect1>
+
 
-  <refsect2 id="R2-SQL-GRANT-3">
-   <refsect2info>
-    <date>1998-09-23</date>
-   </refsect2info>
-   <title>
-    Notes
-   </title>
+ <refsect1 id="SQL-GRANT-notes">
+  <title>Notes</title>
 
    <para>
     Currently, to grant privileges in <productname>Postgres</productname>
     to only a few columns, you must
-    create a view having desired columns and then grant privileges
+    create a view having the desired columns and then grant privileges
     to that view.
    </para>
 
    <para>
-    Use <command>psql \z</command>
-    for further information about permissions 
+    Use <xref linkend="app-psql">'s <command>\z</command> command
+    to obtain information about privileges
     on existing objects:
-    <programlisting>
-	  Database    = lusitania
+<programlisting>
+          Database    = lusitania
    +------------------+---------------------------------------------+
    |  Relation        |        Grant/Revoke Permissions             |
    +------------------+---------------------------------------------+
-   | mytable          | {"=rw","miriam=arwR","group todos=rw"}      |
+   | mytable          | {"=rw","miriam=arwdRxt","group todos=rw"}   |
    +------------------+---------------------------------------------+
    Legend:
          uname=arwR -- privileges granted to a user
-   group gname=arwR -- privileges granted to a GROUP
+   group gname=arwR -- privileges granted to a group
               =arwR -- privileges granted to PUBLIC
 
-                  r -- SELECT
-                  w -- UPDATE/DELETE
-                  a -- INSERT
+                  r -- SELECT ("read")
+                  w -- UPDATE ("write")
+                  a -- INSERT ("append")
+                  d -- DELETE
                   R -- RULE
-               arwR -- ALL
-    </programlisting>
-
+                  x -- REFERENCES
+                  t -- TRIGGER
+            arwdRxt -- ALL PRIVILEGES
+</programlisting>
    </para>
 
    <para>
-    Refer to REVOKE statements to revoke access privileges.
+    The <xref linkend="sql-revoke"> command is used to revoke access
+    privileges.
    </para>
-  </refsect2>
  </refsect1>
 
- <refsect1 id="R1-SQL-GRANT-2">
-  <title>
-   Usage
-  </title>
+ <refsect1 id="sql-grant-examples">
+  <title>Examples</title>
+
   <para>
    Grant insert privilege to all users on table films:
 
-   <programlisting>
+<programlisting>
 GRANT INSERT ON films TO PUBLIC;
-   </programlisting>
+</programlisting>
   </para>
 
   <para>
    Grant all privileges to user manuel on view kinds:
 
-   <programlisting>
-GRANT ALL ON kinds TO manuel;
-   </programlisting>
+<programlisting>
+GRANT ALL PRIVILEGES ON kinds TO manuel;
+</programlisting>
   </para>
  </refsect1>
 
- <refsect1 id="R1-SQL-GRANT-3">
-  <title>
-   Compatibility
-  </title>
+ <refsect1 id="sql-grant-compatibility">
+  <title>Compatibility</title>
     
-  <refsect2 id="R2-SQL-GRANT-4">
-   <refsect2info>
-    <date>1998-09-23</date>
-   </refsect2info>
-   <title>
-    SQL92
-   </title>
+  <refsect2>
+   <title>SQL92</title>
+
    <para>
-    The <acronym>SQL92</acronym> syntax for GRANT allows setting privileges 
-    for individual columns
-    within a table, and allows setting a privilege to grant
-    the same privileges to others:
+    The <literal>PRIVILEGES</literal> key word in <literal>ALL
+    PRIVILEGES</literal> is required.  <acronym>SQL</acronym> does not
+    support setting the privileges on more than one table per command.
+   </para>
+
+   <para>
+    The <acronym>SQL92</acronym> syntax for GRANT allows setting
+    privileges for individual columns within a table, and allows
+    setting a privilege to grant the same privileges to others:
 
-    <synopsis>
+<synopsis>
 GRANT <replaceable class="PARAMETER">privilege</replaceable> [, ...]
     ON <replaceable class="PARAMETER">object</replaceable> [ ( <replaceable class="PARAMETER">column</replaceable> [, ...] ) ] [, ...]
     TO { PUBLIC | <replaceable class="PARAMETER">username</replaceable> [, ...] } [ WITH GRANT OPTION ]
-    </synopsis>
+</synopsis>
+   </para>
+
+   <para>
+    <acronym>SQL</acronym> allows to grant the USAGE privilege on
+    other kinds of objects:  CHARACTER SET, COLLATION, TRANSLATION, DOMAIN.
    </para>
 
    <para>
-    Fields are compatible with those in the <acronym>Postgres</acronym>
-    implementation, with the following additions:
-
-    <variablelist>
-     <varlistentry>
-      <term><replaceable class="PARAMETER">privilege</replaceable></term>
-      <listitem>
-       <para>
-	<acronym>SQL92</acronym> permits additional privileges to be specified:
-
-	<variablelist>
-	 <varlistentry>
-	  <term>SELECT</term>
-	  <listitem>
-	   <para>
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>REFERENCES</term>
-	  <listitem>
-	   <para>
-	    Allowed to reference some or all of the columns of a specific
-	    table/view in integrity constraints.
-	   </para>
-	  </listitem>
-	 </varlistentry>	
-
-	 <varlistentry>
-	  <term>USAGE</term>
-	  <listitem>
-	   <para>
-	    Allowed to use a domain, character set, collation
-	    or translation.
-	    If an object specifies anything other than a table/view,
-	    <replaceable class="PARAMETER">privilege</replaceable>
-	    must specify only USAGE.
-	   </para>
-	  </listitem>
-	 </varlistentry>	
-	</variablelist>
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="PARAMETER">object</replaceable></term>
-      <listitem>
-       <para>
-
-	<variablelist>
-	 <varlistentry>
-	  <term>[ TABLE ] <replaceable class="PARAMETER">table</replaceable></term>
-	  <listitem>
-	   <para>
-	    <acronym>SQL92</acronym> allows the additional
-	    non-functional keyword <literal>TABLE</literal>.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>CHARACTER SET</term>
-	  <listitem>
-	   <para>
-	    Allowed to use the specified character set.
-	   </para>
-	  </listitem>
-	 </varlistentry>	
-
-	 <varlistentry>
-	  <term>COLLATION</term>
-	  <listitem>
-	   <para>
-	    Allowed to use the specified collation sequence.
-	   </para>
-	  </listitem>
-	 </varlistentry>	
-
-	 <varlistentry>
-	  <term>TRANSLATION</term>
-	  <listitem>
-	   <para>
-	    Allowed to use the specified character set translation.
-	   </para>
-	  </listitem>
-	 </varlistentry>	
-
-	 <varlistentry>
-	  <term>DOMAIN</term>
-	  <listitem>
-	   <para>
-	    Allowed to use the specified domain.
-	   </para>
-	  </listitem>
-	 </varlistentry>	
-
-	 <varlistentry>
-	  <term>WITH GRANT OPTION</term>
-	  <listitem>
-	   <para>
-	    Allowed to grant the same privilege to others.
-	   </para>
-	  </listitem>
-	 </varlistentry>	
-	</variablelist>
-       </para>
-      </listitem>
-     </varlistentry>
-    </variablelist>
+    The TRIGGER privilege was introduced in SQL99.  The RULE privilege
+    is a PostgreSQL extension.
    </para>
   </refsect2>
+
+ </refsect1>
+
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simpara>
+   <xref linkend="sql-revoke">
+  </simpara>
  </refsect1>
+
 </refentry>
 
 <!-- Keep this comment at the end of the file
diff --git a/doc/src/sgml/ref/insert.sgml b/doc/src/sgml/ref/insert.sgml
index dc6fb14da83..f6ab93f9f59 100644
--- a/doc/src/sgml/ref/insert.sgml
+++ b/doc/src/sgml/ref/insert.sgml
@@ -1,13 +1,11 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/insert.sgml,v 1.13 2001/01/13 23:58:55 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/insert.sgml,v 1.14 2001/05/27 09:59:28 petere Exp $
 Postgres documentation
 -->
 
 <refentry id="SQL-INSERT">
  <refmeta>
-  <refentrytitle id="SQL-INSERT-TITLE">
-   INSERT
-  </refentrytitle>
+  <refentrytitle id="SQL-INSERT-TITLE">INSERT</refentrytitle>
   <refmiscinfo>SQL - Language Statements</refmiscinfo>
  </refmeta>
  <refnamediv>
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 3a1c8ab0e07..ac58fdb3843 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.53 2001/05/17 21:50:18 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.54 2001/05/27 09:59:28 petere Exp $
 Postgres documentation
 -->
 
@@ -1187,8 +1187,8 @@ Access permissions for database "test"
 	</para>
 
 	<para>
-	The commands <xref linkend="SQL-GRANT" endterm="SQL-GRANT-title"> and
-	<xref linkend="SQL-REVOKE" endterm="SQL-REVOKE-title">
+	The commands <xref linkend="SQL-GRANT"> and
+	<xref linkend="SQL-REVOKE">
 	are used to set access permissions.
 	</para>
 
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index d7e83c822d9..a9988fbc1ea 100644
--- a/doc/src/sgml/ref/revoke.sgml
+++ b/doc/src/sgml/ref/revoke.sgml
@@ -1,379 +1,96 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.13 2000/12/25 23:15:26 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.14 2001/05/27 09:59:28 petere Exp $
 Postgres documentation
 -->
 
 <refentry id="SQL-REVOKE">
  <refmeta>
-  <refentrytitle id="SQL-REVOKE-TITLE">
-   REVOKE
-  </refentrytitle>
+  <refentrytitle>REVOKE</refentrytitle>
   <refmiscinfo>SQL - Language Statements</refmiscinfo>
  </refmeta>
+
  <refnamediv>
-  <refname>
-   REVOKE
-  </refname>
-  <refpurpose>
-   Revokes access privilege from a user, a group or all users.
-  </refpurpose>
+  <refname>REVOKE</refname>
+  <refpurpose>Revokes access privilege from a user, a group, or all users.</refpurpose>
  </refnamediv>
- <refsynopsisdiv>
-  <refsynopsisdivinfo>
-   <date>1999-07-20</date>
-  </refsynopsisdivinfo>
-  <synopsis>
-REVOKE <replaceable class="PARAMETER">privilege</replaceable> [, ...]
-    ON <replaceable class="PARAMETER">object</replaceable> [, ...]
-    FROM { PUBLIC | GROUP <replaceable class="PARAMETER">groupname</replaceable> | <replaceable class="PARAMETER">username</replaceable> }
-  </synopsis>
-
-  <refsect2 id="R2-SQL-REVOKE-1">
-   <refsect2info>
-    <date>1998-09-24</date>
-   </refsect2info>
-   <title>
-    Inputs
-   </title>
-   <para>
-
-    <variablelist>
-     <varlistentry>
-      <term><replaceable class="PARAMETER">privilege</replaceable></term>
-      <listitem>
-       <para>
-	The possible privileges are:
-
-	<variablelist>
-	 <varlistentry>
-	  <term>SELECT</term>
-	  <listitem>
-	   <para>
-	    Privilege to access all of the columns of a specific
-	    table/view.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>INSERT</term>
-	  <listitem>
-	   <para>
-	    Privilege to insert data into all columns of a
-	    specific table.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>UPDATE</term>
-	  <listitem>
-	   <para>
-	    Privilege to update all columns of a specific
-	    table.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>DELETE</term>
-	  <listitem>
-	   <para>
-	    Privilege to delete rows from a specific table.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>RULE</term>
-	  <listitem>
-	   <para>
-	    Privilege to define rules on table/view.
-	    (See 
-	    <xref linkend="sql-createrule" endterm="sql-createrule-title">).
-	   </para>
-	  </listitem>
-	 </varlistentry>
-
-	 <varlistentry>
-	  <term>ALL</term>
-	  <listitem>
-	   <para>
-	    Rescind all privileges.
-	   </para>
-	  </listitem>
-	 </varlistentry>
-	</variablelist>
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="PARAMETER">object</replaceable></term>
-      <listitem>
-       <para>
-	The name of an object from which to revoke access.
-
-	The possible objects are:
-	<itemizedlist spacing="compact" mark="bullet">
-	 <listitem>
-	  <para>
-	   table 
-	  </para>
-	 </listitem>
 
-	 <listitem>
-	  <para>
-	   view 
-	  </para>
-	 </listitem>
-
-	 <listitem>
-	  <para>
-	   sequence
-	  </para>
-	 </listitem>
-
-	</itemizedlist>
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="PARAMETER">group</replaceable></term>
-      <listitem>
-       <para>
-	The name of a group from whom to revoke privileges.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="PARAMETER">username</replaceable></term>
-      <listitem>
-       <para>
-	The name of a user from whom revoke privileges. Use the PUBLIC keyword
-	to specify all users.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term>PUBLIC</term>
-      <listitem>
-       <para>
-	Rescind the specified privilege(s) for all users.
-       </para>
-      </listitem>
-     </varlistentry>
-    </variablelist>
-   </para>
-  </refsect2>
-
-  <refsect2 id="R2-SQL-REVOKE-2">
-   <refsect2info>
-    <date>1998-09-24</date>
-   </refsect2info>
-   <title>
-    Outputs
-   </title>
-   <para>
-
-    <variablelist>
-     <varlistentry>
-      <term><computeroutput>
-CHANGE
-       </computeroutput></term>
-      <listitem>
-       <para>
-	Message returned if successfully.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><computeroutput>
-ERROR
-       </computeroutput></term>
-      <listitem>
-       <para>
-	Message returned if object is not available or impossible
-	to revoke privileges from a group or users.
-       </para>
-      </listitem>
-     </varlistentry>		  
-    </variablelist>
-   </para>
-  </refsect2>
+ <refsynopsisdiv>
+<synopsis>
+REVOKE { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] }
+    ON [ TABLE ] <replaceable class="PARAMETER">object</replaceable> [, ...]
+    FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC }
+</synopsis>
  </refsynopsisdiv>
 
- <refsect1 id="R1-SQL-REVOKE-1">
-  <refsect1info>
-   <date>1998-09-24</date>
-  </refsect1info>
-  <title>
-   Description
-  </title>
+ <refsect1 id="SQL-REVOKE-description">
+  <title>Description</title>
+
   <para>
-   <command>REVOKE</command> allows creator of an object to revoke permissions granted
-   before, from all users (via PUBLIC) or a certain user or group.
+   <command>REVOKE</command> allows the creator of an object to revoke
+   permissions granted before, from a users or a group of users.  The
+   key word <literal>PUBLIC</literal> means to revoke this privilege
+   from all users.
   </para>
 
-  <refsect2 id="R2-SQL-REVOKE-3">
-   <refsect2info>
-    <date>1998-09-24</date>
-   </refsect2info>
-   <title>
-    Notes
-   </title>
-   <para>
-    Refer to psql \z command for further information about permissions 
-    on existing objects:
-
-    <programlisting>
-Database    = lusitania
-+------------------+---------------------------------------------+
-|  Relation        |        Grant/Revoke Permissions             |
-+------------------+---------------------------------------------+
-| mytable          | {"=rw","miriam=arwR","group todos=rw"}      |
-+------------------+---------------------------------------------+
-Legend:
-     uname=arwR -- privileges granted to a user
-     group gname=arwR -- privileges granted to a GROUP
-     =arwR -- privileges granted to PUBLIC
-		  
-     r -- SELECT
-     w -- UPDATE/DELETE
-     a -- INSERT
-     R -- RULE
-     arwR -- ALL
-    </programlisting>
-   </para>
-   <tip>
-    <para>
-     Currently, to create a GROUP you have to insert 
-     data manually into table pg_group as:
+  <para>
+   See the description of the <xref linkend="sql-grant"> command for
+   the meaning of the privilege types.
+  </para>
+ </refsect1>
 
-     <programlisting>
-INSERT INTO pg_group VALUES ('todos');
-CREATE USER miriam IN GROUP todos;
-     </programlisting>
-    </para>
-   </tip>
+ <refsect1 id="SQL-REVOKE-notes">
+  <title>Notes</title>
 
-  </refsect2>
+  <para>
+   Use <xref linkend="app-psql">'s <command>\z</command> command to
+   display the privileges granted on existing objects.  See also <xref
+   linkend="sql-grant"> for information about the format.
+  </para>
  </refsect1>
 
- <refsect1 id="R1-SQL-REVOKE-2">
-  <title>
-   Usage
-  </title>
+ <refsect1 id="SQL-REVOKE-examples">
+  <title>Examples</title>
+
   <para>
    Revoke insert privilege from all users on table
    <literal>films</literal>:
 
-   <programlisting>
+<programlisting>
 REVOKE INSERT ON films FROM PUBLIC;
-  </programlisting>
+</programlisting>
   </para>
 
   <para>
    Revoke all privileges from user <literal>manuel</literal> on view <literal>kinds</literal>:
 
-   <programlisting>  
-REVOKE ALL ON kinds FROM manuel;
-   </programlisting>
+<programlisting>  
+REVOKE ALL PRIVILEGES ON kinds FROM manuel;
+</programlisting>
   </para>
  </refsect1>
 
- <refsect1 id="R1-SQL-REVOKE-3">
-  <title>
-   Compatibility
-  </title>
+ <refsect1 id="SQL-REVOKE-compatibility">
+  <title>Compatibility</title>
 
-  <refsect2 id="R2-SQL-REVOKE-4">
-   <refsect2info>
-    <date>1998-09-01</date>
-   </refsect2info>
-   <title>
-    SQL92
-   </title>
+  <refsect2>
+   <title>SQL92</title>
 
    <para>
-    The SQL92 syntax for <command>REVOKE</command>
-    has additional capabilities for rescinding
-    privileges, including those on individual columns in tables:
-
-    <variablelist>
-     <varlistentry>
-      <term>
-       <synopsis>
-REVOKE { SELECT | DELETE | USAGE | ALL PRIVILEGES } [, ...]
-    ON <replaceable class="parameter">object</replaceable>
-    FROM { PUBLIC | <replaceable class="parameter">username</replaceable> [, ...] } { RESTRICT | CASCADE }
-REVOKE { INSERT | UPDATE | REFERENCES } [, ...] [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ]
-    ON <replaceable class="parameter">object</replaceable>
-    FROM { PUBLIC | <replaceable class="parameter">username</replaceable> [, ...] } { RESTRICT | CASCADE }
-       </synopsis>
-      </term>
-      <listitem>
-       <para>
-	Refer to
-	<xref linkend="sql-grant" endterm="sql-grant-title">
-	for details on individual fields.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term>
-       <synopsis>
-REVOKE GRANT OPTION FOR <replaceable class="parameter">privilege</replaceable> [, ...]
-    ON <replaceable class="parameter">object</replaceable>
-    FROM { PUBLIC | <replaceable class="parameter">username</replaceable> [, ...] } { RESTRICT | CASCADE }
-       </synopsis>
-      </term>
-      <listitem>
-       <para>
-	Rescinds authority for a user to grant the specified privilege
-	to others.
-	Refer to
-	<xref linkend="sql-grant" endterm="sql-grant-title">
-	for details on individual fields.
-       </para>
-      </listitem>
-     </varlistentry>
-    </variablelist>
-   </para>
-
-   <para>
-    The possible objects are:
-    <simplelist>
-     <member>
-      [ TABLE ] table/view
-     </member>
-     <member>
-      CHARACTER SET character-set
-     </member>
-     <member>
-      COLLATION collation
-     </member>
-     <member>
-      TRANSLATION translation
-     </member>
-     <member>
-      DOMAIN domain
-     </member>
-    </simplelist>
+    The compatibility notes of the <xref linkend="sql-grant"> command
+    apply analogously to <command>REVOKE</command>.  The syntax summary is:
+
+<synopsis>
+REVOKE [ GRANT OPTION FOR ] { SELECT | INSERT | UPDATE | DELETE | REFERENCES }
+    ON <replaceable class="parameter">object</replaceable> [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ]
+    FROM { PUBLIC | <replaceable class="parameter">username</replaceable> [, ...] }
+    { RESTRICT | CASCADE }
+</synopsis>
    </para>
 
    <para> 
     If user1 gives a privilege WITH GRANT OPTION to user2,
     and user2 gives it to user3 then user1 can revoke
     this privilege in cascade using the CASCADE keyword.
-   </para>
-
-   <para>
     If user1 gives a privilege WITH GRANT OPTION to user2,
     and user2 gives it to user3, then if user1 tries to revoke
     this privilege it fails if he specify the RESTRICT
@@ -381,6 +98,15 @@ REVOKE GRANT OPTION FOR <replaceable class="parameter">privilege</replaceable> [
    </para>
   </refsect2>
  </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simpara>
+   <xref linkend="sql-grant">
+  </simpara>
+ </refsect1>
+
 </refentry>
 
 <!-- Keep this comment at the end of the file
diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml
index d9311c95a07..1106798d4a2 100644
--- a/doc/src/sgml/ref/select.sgml
+++ b/doc/src/sgml/ref/select.sgml
@@ -1,13 +1,11 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/select.sgml,v 1.40 2001/03/24 23:03:26 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/select.sgml,v 1.41 2001/05/27 09:59:28 petere Exp $
 Postgres documentation
 -->
 
 <refentry id="SQL-SELECT">
  <refmeta>
-  <refentrytitle id="sql-select-title">
-   SELECT
-  </refentrytitle>
+  <refentrytitle id="sql-select-title">SELECT</refentrytitle>
   <refmiscinfo>SQL - Language Statements</refmiscinfo>
  </refmeta>
  <refnamediv>
diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml
index 58966c9b4ab..f47b2663ac3 100644
--- a/doc/src/sgml/ref/update.sgml
+++ b/doc/src/sgml/ref/update.sgml
@@ -1,13 +1,11 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/update.sgml,v 1.14 2001/01/13 23:58:55 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/update.sgml,v 1.15 2001/05/27 09:59:28 petere Exp $
 Postgres documentation
 -->
 
 <refentry id="SQL-UPDATE">
  <refmeta>
-  <refentrytitle id="SQL-UPDATE-TITLE">
-   UPDATE
-  </refentrytitle>
+  <refentrytitle id="SQL-UPDATE-TITLE">UPDATE</refentrytitle>
   <refmiscinfo>SQL - Language Statements</refmiscinfo>
  </refmeta>
  <refnamediv>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index bfc4cc2a454..5ef74cb1d55 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.47 2001/03/22 03:59:18 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.48 2001/05/27 09:59:28 petere Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -46,7 +46,7 @@ char	   *aclcheck_error_strings[] = {
 };
 
 
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 static
 dumpacl(Acl *acl)
 {
@@ -62,7 +62,7 @@ dumpacl(Acl *acl)
 											 PointerGetDatum(aip + i))));
 }
 
-#endif
+#endif /* ACLDEBUG */
 
 /*
  * ChangeAcl
@@ -116,13 +116,13 @@ ChangeAcl(char *relname,
 		old_acl = DatumGetAclPCopy(aclDatum);
 	}
 
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 	dumpacl(old_acl);
 #endif
 
 	new_acl = aclinsert3(old_acl, mod_aip, modechg);
 
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 	dumpacl(new_acl);
 #endif
 
@@ -285,7 +285,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
 			{
 				if (aip->ai_id == id)
 				{
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 					elog(DEBUG, "aclcheck: found user %u/%d",
 						 aip->ai_id, aip->ai_mode);
 #endif
@@ -301,7 +301,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
 				{
 					if (in_group(id, aip->ai_id))
 					{
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 						elog(DEBUG, "aclcheck: found group %u/%d",
 							 aip->ai_id, aip->ai_mode);
 #endif
@@ -324,7 +324,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
 			{
 				if (aip->ai_id == id)
 				{
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 					elog(DEBUG, "aclcheck: found group %u/%d",
 						 aip->ai_id, aip->ai_mode);
 #endif
@@ -341,7 +341,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
 			break;
 	}
 
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 	elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode);
 #endif
 	return (aidat->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
@@ -371,7 +371,7 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
 	 * pg_shadow.usecatupd is set.	(This is to let superusers protect
 	 * themselves from themselves.)
 	 */
-	if (((mode & ACL_WR) || (mode & ACL_AP)) &&
+	if (((mode & ACL_UPDATE) || (mode & ACL_INSERT) || (mode & ACL_DELETE)) &&
 		!allowSystemTableMods && IsSystemRelationName(relname) &&
 		strncmp(relname, "pg_temp.", strlen("pg_temp.")) != 0 &&
 		!((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd)
@@ -387,7 +387,7 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
 	 */
 	if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
 	{
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 		elog(DEBUG, "pg_aclcheck: \"%s\" is superuser",
 			 usename);
 #endif
@@ -454,7 +454,7 @@ pg_ownercheck(Oid userid,
 	 */
 	if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
 	{
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 		elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
 			 usename);
 #endif
@@ -528,7 +528,7 @@ pg_func_ownercheck(Oid userid,
 	 */
 	if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
 	{
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 		elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
 			 usename);
 #endif
@@ -576,7 +576,7 @@ pg_aggr_ownercheck(Oid userid,
 	 */
 	if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
 	{
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 		elog(DEBUG, "pg_aggr_ownercheck: user \"%s\" is superuser",
 			 usename);
 #endif
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index bc5153b8005..90cfba50be5 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.128 2001/05/21 14:22:11 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.129 2001/05/27 09:59:28 petere Exp $
  *
  * NOTES
  *	  The PerformAddAttribute() code, like most of the relation
@@ -1939,9 +1939,10 @@ LockTableCommand(LockStmt *lockstmt)
 		elog(ERROR, "LOCK TABLE: %s is not a table", lockstmt->relname);
 
 	if (lockstmt->mode == AccessShareLock)
-		aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), ACL_RD);
+		aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), ACL_SELECT);
 	else
-		aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), ACL_WR);
+		aclresult = pg_aclcheck(lockstmt->relname, GetUserId(),
+								ACL_UPDATE | ACL_DELETE);
 
 	if (aclresult != ACLCHECK_OK)
 		elog(ERROR, "LOCK TABLE: permission denied");
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 06397ab323f..7d3ba9b5618 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -7,7 +7,7 @@
  * Copyright (c) 1999, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.27 2001/03/22 03:59:21 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.28 2001/05/27 09:59:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -468,7 +468,7 @@ CommentRewrite(char *rule, char *comment)
 
 #ifndef NO_SECURITY
 	relation = RewriteGetRuleEventRel(rule);
-	aclcheck = pg_aclcheck(relation, GetUserId(), ACL_RU);
+	aclcheck = pg_aclcheck(relation, GetUserId(), ACL_RULE);
 	if (aclcheck != ACLCHECK_OK)
 	{
 		elog(ERROR, "you are not permitted to comment on rule '%s'",
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 0f249fa385c..fbbade10331 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.136 2001/03/22 06:16:11 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.137 2001/05/27 09:59:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -271,7 +271,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
 
 	FILE	   *fp;
 	Relation	rel;
-	const AclMode required_access = from ? ACL_WR : ACL_RD;
+	const AclMode required_access = from ? ACL_INSERT : ACL_SELECT;
 	int			result;
 
 	/*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index f1dbbf6d251..f37b6199b24 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.55 2001/05/10 20:38:49 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.56 2001/05/27 09:59:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -243,7 +243,7 @@ nextval(PG_FUNCTION_ARGS)
 				rescnt = 0;
 	bool		logit = false;
 
-	if (pg_aclcheck(seqname, GetUserId(), ACL_WR) != ACLCHECK_OK)
+	if (pg_aclcheck(seqname, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
 		elog(ERROR, "%s.nextval: you don't have permissions to set sequence %s",
 			 seqname, seqname);
 
@@ -390,7 +390,7 @@ currval(PG_FUNCTION_ARGS)
 	SeqTable	elm;
 	int32		result;
 
-	if (pg_aclcheck(seqname, GetUserId(), ACL_RD) != ACLCHECK_OK)
+	if (pg_aclcheck(seqname, GetUserId(), ACL_SELECT) != ACLCHECK_OK)
 		elog(ERROR, "%s.currval: you don't have permissions to read sequence %s",
 			 seqname, seqname);
 
@@ -428,7 +428,7 @@ do_setval(char *seqname, int32 next, bool iscalled)
 	Buffer		buf;
 	Form_pg_sequence seq;
 
-	if (pg_aclcheck(seqname, GetUserId(), ACL_WR) != ACLCHECK_OK)
+	if (pg_aclcheck(seqname, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
 		elog(ERROR, "%s.setval: you don't have permissions to set sequence %s",
 			 seqname, seqname);
 
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 70f2e1b2957..70c146530f1 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.90 2001/03/22 06:16:11 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.91 2001/05/27 09:59:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -69,8 +69,10 @@ CreateTrigger(CreateTrigStmt *stmt)
 	if (!allowSystemTableMods && IsSystemRelationName(stmt->relname))
 		elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
 
-	if (!pg_ownercheck(GetUserId(), stmt->relname, RELNAME))
-		elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+	if (pg_aclcheck(stmt->relname, GetUserId(),
+					stmt->isconstraint ? ACL_REFERENCES : ACL_TRIGGER)
+		!= ACLCHECK_OK)
+		elog(ERROR, "permission denied");
 
 	/*
 	 * If trigger is a constraint, user trigger name as constraint name
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index eda6ce518d2..f87b674b074 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.140 2001/05/15 00:33:36 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.141 2001/05/27 09:59:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -420,7 +420,7 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
 
 	if (rte->checkForRead)
 	{
-		aclcheck_result = CHECK(ACL_RD);
+		aclcheck_result = CHECK(ACL_SELECT);
 		if (aclcheck_result != ACLCHECK_OK)
 			elog(ERROR, "%s: %s",
 				 relName, aclcheck_error_strings[aclcheck_result]);
@@ -437,15 +437,14 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
 		switch (operation)
 		{
 			case CMD_INSERT:
-				/* Accept either APPEND or WRITE access for this */
-				aclcheck_result = CHECK(ACL_AP);
-				if (aclcheck_result != ACLCHECK_OK)
-					aclcheck_result = CHECK(ACL_WR);
+				aclcheck_result = CHECK(ACL_INSERT);
 				break;
 			case CMD_SELECT:
-			case CMD_DELETE:
 			case CMD_UPDATE:
-				aclcheck_result = CHECK(ACL_WR);
+				aclcheck_result = CHECK(ACL_UPDATE);
+				break;
+			case CMD_DELETE:
+				aclcheck_result = CHECK(ACL_DELETE);
 				break;
 			default:
 				elog(ERROR, "ExecCheckRTEPerms: bogus operation %d",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 5857f6ee642..37c28495e54 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.226 2001/05/14 20:30:20 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.227 2001/05/27 09:59:29 petere Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -2234,19 +2234,19 @@ from_in:  IN
  *
  *****************************************************************************/
 
-GrantStmt:  GRANT privileges ON relation_name_list TO grantee opt_with_grant
+GrantStmt:  GRANT privileges ON opt_table relation_name_list TO grantee opt_with_grant
 				{
-					$$ = (Node*)makeAclStmt($2,$4,$6,'+');
+					$$ = (Node*)makeAclStmt($2,$5,$7,'+');
 				}
 		;
 
 privileges:  ALL PRIVILEGES
 				{
-				 $$ = aclmakepriv("rwaR",0);
+				 $$ = aclmakepriv(ACL_MODE_STR,0);
 				}
 		| ALL
 				{
-				 $$ = aclmakepriv("rwaR",0);
+				 $$ = aclmakepriv(ACL_MODE_STR,0);
 				}
 		| operation_commalist
 				{
@@ -2266,23 +2266,31 @@ operation_commalist:  operation
 
 operation:  SELECT
 				{
-						$$ = ACL_MODE_RD_CHR;
+						$$ = ACL_MODE_SELECT_CHR;
 				}
 		| INSERT
 				{
-						$$ = ACL_MODE_AP_CHR;
+						$$ = ACL_MODE_INSERT_CHR;
 				}
 		| UPDATE
 				{
-						$$ = ACL_MODE_WR_CHR;
+						$$ = ACL_MODE_UPDATE_CHR;
 				}
 		| DELETE
 				{
-						$$ = ACL_MODE_WR_CHR;
+						$$ = ACL_MODE_DELETE_CHR;
 				}
 		| RULE
 				{
-						$$ = ACL_MODE_RU_CHR;
+						$$ = ACL_MODE_RULE_CHR;
+				}
+		| REFERENCES
+				{
+						$$ = ACL_MODE_REFERENCES_CHR;
+				}
+		| TRIGGER
+				{
+						$$ = ACL_MODE_TRIGGER_CHR;
 				}
 		;
 
@@ -2315,9 +2323,9 @@ opt_with_grant:  WITH GRANT OPTION
  *
  *****************************************************************************/
 
-RevokeStmt:  REVOKE privileges ON relation_name_list FROM grantee
+RevokeStmt:  REVOKE privileges ON opt_table relation_name_list FROM grantee
 				{
-					$$ = (Node*)makeAclStmt($2,$4,$6,'-');
+					$$ = (Node*)makeAclStmt($2,$5,$7,'-');
 				}
 		;
 
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index b616f7e68ef..dc569455b26 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.110 2001/05/07 00:43:23 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.111 2001/05/27 09:59:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -267,7 +267,7 @@ ProcessUtility(Node *parsetree,
 								int			aclcheck_result;
 
 								relationName = RewriteGetRuleEventRel(rulename);
-								aclcheck_result = pg_aclcheck(relationName, GetUserId(), ACL_RU);
+								aclcheck_result = pg_aclcheck(relationName, GetUserId(), ACL_RULE);
 								if (aclcheck_result != ACLCHECK_OK)
 									elog(ERROR, "%s: %s", relationName,
 										 aclcheck_error_strings[aclcheck_result]);
@@ -550,7 +550,7 @@ ProcessUtility(Node *parsetree,
 				int			aclcheck_result;
 
 				relname = stmt->object->relname;
-				aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RU);
+				aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RULE);
 				if (aclcheck_result != ACLCHECK_OK)
 					elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
 				set_ps_display(commandTag = "CREATE");
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 10e2f13bc32..f4e3fe9986d 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.58 2001/03/22 03:59:48 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.59 2001/05/27 09:59:30 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -113,8 +113,8 @@ aclparse(char *s, AclItem *aip, unsigned *modechg)
 
 	Assert(s && aip && modechg);
 
-#ifdef ACLDEBUG_TRACE
-	printf("aclparse: input = '%s'\n", s);
+#ifdef ACLDEBUG
+	elog(DEBUG, "aclparse: input = '%s'", s);
 #endif
 	aip->ai_idtype = ACL_IDTYPE_UID;
 	s = getid(s, name);
@@ -155,17 +155,26 @@ aclparse(char *s, AclItem *aip, unsigned *modechg)
 	{
 		switch (*s)
 		{
-			case ACL_MODE_AP_CHR:
-				aip->ai_mode |= ACL_AP;
+			case ACL_MODE_INSERT_CHR:
+				aip->ai_mode |= ACL_INSERT;
 				break;
-			case ACL_MODE_RD_CHR:
-				aip->ai_mode |= ACL_RD;
+			case ACL_MODE_SELECT_CHR:
+				aip->ai_mode |= ACL_SELECT;
 				break;
-			case ACL_MODE_WR_CHR:
-				aip->ai_mode |= ACL_WR;
+			case ACL_MODE_UPDATE_CHR:
+				aip->ai_mode |= ACL_UPDATE;
 				break;
-			case ACL_MODE_RU_CHR:
-				aip->ai_mode |= ACL_RU;
+			case ACL_MODE_DELETE_CHR:
+				aip->ai_mode |= ACL_DELETE;
+				break;
+			case ACL_MODE_RULE_CHR:
+				aip->ai_mode |= ACL_RULE;
+				break;
+			case ACL_MODE_REFERENCES_CHR:
+				aip->ai_mode |= ACL_REFERENCES;
+				break;
+			case ACL_MODE_TRIGGER_CHR:
+				aip->ai_mode |= ACL_TRIGGER;
 				break;
 			default:
 				elog(ERROR, "aclparse: mode flags must use \"%s\"",
@@ -192,7 +201,7 @@ aclparse(char *s, AclItem *aip, unsigned *modechg)
 			break;
 	}
 
-#ifdef ACLDEBUG_TRACE
+#ifdef ACLDEBUG
 	elog(DEBUG, "aclparse: correctly read [%x %d %x], modechg=%x",
 		 aip->ai_idtype, aip->ai_id, aip->ai_mode, *modechg);
 #endif
@@ -269,7 +278,7 @@ aclitemout(PG_FUNCTION_ARGS)
 	unsigned	i;
 	char	   *tmpname;
 
-	p = out = palloc(strlen("group =arwR ") + 1 + NAMEDATALEN);
+	p = out = palloc(strlen("group =" ACL_MODE_STR " ") + 1 + NAMEDATALEN);
 	*p = '\0';
 
 	switch (aip->ai_idtype)
@@ -368,14 +377,13 @@ acldefault(char *relname, AclId ownerid)
 	AclItem    *aip;
 
 #define ACL_WORLD_DEFAULT		(ACL_NO)
-/* #define		ACL_WORLD_DEFAULT		(ACL_RD|ACL_WR|ACL_AP|ACL_RU) */
-#define ACL_OWNER_DEFAULT		(ACL_RD|ACL_WR|ACL_AP|ACL_RU)
+#define ACL_OWNER_DEFAULT		(ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER)
 
 	acl = makeacl(2);
 	aip = ACL_DAT(acl);
 	aip[0].ai_idtype = ACL_IDTYPE_WORLD;
 	aip[0].ai_id = ACL_ID_WORLD;
-	aip[0].ai_mode = IsSystemRelationName(relname) ? ACL_RD : ACL_WORLD_DEFAULT;
+	aip[0].ai_mode = IsSystemRelationName(relname) ? ACL_SELECT : ACL_WORLD_DEFAULT;
 	aip[1].ai_idtype = ACL_IDTYPE_UID;
 	aip[1].ai_id = ownerid;
 	aip[1].ai_mode = ACL_OWNER_DEFAULT;
@@ -651,8 +659,8 @@ aclmakepriv(char *old_privlist, char new_priv)
 	int			i;
 	int			l;
 
-	Assert(strlen(old_privlist) < 5);
-	priv = palloc(5); /* at most "rwaR" */ ;
+	Assert(strlen(old_privlist) <= strlen(ACL_MODE_STR));
+	priv = palloc(strlen(ACL_MODE_STR)+1);
 
 	if (old_privlist == NULL || old_privlist[0] == '\0')
 	{
@@ -665,7 +673,7 @@ aclmakepriv(char *old_privlist, char new_priv)
 
 	l = strlen(old_privlist);
 
-	if (l == 4)
+	if (l == strlen(ACL_MODE_STR))
 	{							/* can't add any more privileges */
 		return priv;
 	}
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 7e09390c3ca..02e6094c51e 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: acl.h,v 1.31 2001/03/22 04:01:10 momjian Exp $
+ * $Id: acl.h,v 1.32 2001/05/27 09:59:30 petere Exp $
  *
  * NOTES
  *	  For backward-compatibility purposes we have to allow there
@@ -52,11 +52,14 @@ typedef uint8 AclIdType;
 typedef uint8 AclMode;
 
 #define ACL_NO			0		/* no permissions */
-#define ACL_AP			(1<<0)	/* append */
-#define ACL_RD			(1<<1)	/* read */
-#define ACL_WR			(1<<2)	/* write (append/delete/replace) */
-#define ACL_RU			(1<<3)	/* place rules */
-#define N_ACL_MODES		4
+#define ACL_INSERT		(1<<0)
+#define ACL_SELECT		(1<<1)
+#define ACL_UPDATE		(1<<2)
+#define ACL_DELETE		(1<<3)
+#define ACL_RULE		(1<<4)
+#define ACL_REFERENCES	(1<<5)
+#define ACL_TRIGGER		(1<<6)
+#define N_ACL_MODES		7		/* 1 plus the last 1<<x */
 
 /*
  * AclItem
@@ -146,11 +149,14 @@ typedef ArrayType IdList;
 #define ACL_MODECHG_ADD_CHR		'+'
 #define ACL_MODECHG_DEL_CHR		'-'
 #define ACL_MODECHG_EQL_CHR		'='
-#define ACL_MODE_STR			"arwR"	/* list of valid characters */
-#define ACL_MODE_AP_CHR			'a'
-#define ACL_MODE_RD_CHR			'r'
-#define ACL_MODE_WR_CHR			'w'
-#define ACL_MODE_RU_CHR			'R'
+#define ACL_MODE_STR			"arwdRxt"	/* list of valid characters */
+#define ACL_MODE_INSERT_CHR		'a'	/* formerly known as "append" */
+#define ACL_MODE_SELECT_CHR		'r'	/* formerly known as "read" */
+#define ACL_MODE_UPDATE_CHR		'w'	/* formerly known as "write" */
+#define ACL_MODE_DELETE_CHR		'd'
+#define ACL_MODE_RULE_CHR		'R'
+#define ACL_MODE_REFERENCES_CHR	'x'
+#define ACL_MODE_TRIGGER_CHR	't'
 
 /* result codes for pg_aclcheck */
 #define ACLCHECK_OK				  0
@@ -161,11 +167,6 @@ typedef ArrayType IdList;
 /* warning messages.  set these in aclchk.c. */
 extern char *aclcheck_error_strings[];
 
-/*
- * Enable ACL execution tracing and table dumps
- */
-/*#define ACLDEBUG_TRACE*/
-
 /*
  * routines used internally
  */
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
new file mode 100644
index 00000000000..cb376e0bbc8
--- /dev/null
+++ b/src/test/regress/expected/privileges.out
@@ -0,0 +1,198 @@
+--
+-- Test access privileges
+--
+CREATE USER regressuser1;
+CREATE USER regressuser2;
+CREATE USER regressuser3;
+CREATE USER regressuser4;
+CREATE USER regressuser4;	-- duplicate
+ERROR:  CREATE USER: user name "regressuser4" already exists
+CREATE GROUP regressgroup1;
+CREATE GROUP regressgroup2 WITH USER regressuser1, regressuser2;
+ALTER GROUP regressgroup1 ADD USER regressuser4;
+ALTER GROUP regressgroup2 ADD USER regressuser2;	-- duplicate
+NOTICE:  ALTER GROUP: user "regressuser2" is already in group "regressgroup2"
+ALTER GROUP regressgroup2 DROP USER regressuser2;
+ALTER GROUP regressgroup2 ADD USER regressuser4;
+-- test owner privileges
+SET SESSION AUTHORIZATION regressuser1;
+SELECT session_user, current_user;
+ session_user | current_user 
+--------------+--------------
+ regressuser1 | regressuser1
+(1 row)
+
+CREATE TABLE atest1 ( a int, b text );
+SELECT * FROM atest1;
+ a | b 
+---+---
+(0 rows)
+
+INSERT INTO atest1 VALUES (1, 'one');
+DELETE FROM atest1;
+UPDATE atest1 SET a = 1 WHERE b = 'blech';
+LOCK atest1 IN ACCESS EXCLUSIVE MODE;
+REVOKE ALL ON atest1 FROM PUBLIC;
+SELECT * FROM atest1;
+ a | b 
+---+---
+(0 rows)
+
+GRANT ALL ON atest1 TO regressuser2;
+GRANT SELECT ON atest1 TO regressuser3;
+SELECT * FROM atest1;
+ a | b 
+---+---
+(0 rows)
+
+CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
+GRANT SELECT ON atest2 TO regressuser2;
+GRANT UPDATE ON atest2 TO regressuser3;
+GRANT INSERT ON atest2 TO regressuser4;
+SET SESSION AUTHORIZATION regressuser2;
+SELECT session_user, current_user;
+ session_user | current_user 
+--------------+--------------
+ regressuser2 | regressuser2
+(1 row)
+
+-- try various combinations of queries on atest1 and atest2
+SELECT * FROM atest1; -- ok
+ a | b 
+---+---
+(0 rows)
+
+SELECT * FROM atest2; -- ok
+ col1 | col2 
+------+------
+(0 rows)
+
+INSERT INTO atest1 VALUES (2, 'two'); -- ok
+INSERT INTO atest2 VALUES ('foo', true); -- fail
+ERROR:  atest2: Permission denied.
+INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok
+UPDATE atest1 SET a = 1 WHERE a = 2; -- ok
+UPDATE atest2 SET col2 = NOT col2; -- fail
+ERROR:  atest2: Permission denied.
+SELECT * FROM atest1 FOR UPDATE; -- ok
+ a |  b  
+---+-----
+ 1 | two
+ 1 | two
+(2 rows)
+
+SELECT * FROM atest2 FOR UPDATE; -- fail
+ERROR:  atest2: Permission denied.
+DELETE FROM atest2; -- fail
+ERROR:  atest2: Permission denied.
+LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- fail
+ERROR:  LOCK TABLE: permission denied
+COPY atest2 FROM stdin; -- fail
+ERROR:  atest2: Permission denied.
+GRANT ALL ON atest1 TO PUBLIC; -- fail
+ERROR:  you do not own class "atest1"
+-- checks in subquery, both ok
+SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) );
+ a | b 
+---+---
+(0 rows)
+
+SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
+ col1 | col2 
+------+------
+(0 rows)
+
+SET SESSION AUTHORIZATION regressuser3;
+SELECT session_user, current_user;
+ session_user | current_user 
+--------------+--------------
+ regressuser3 | regressuser3
+(1 row)
+
+SELECT * FROM atest1; -- ok
+ a |  b  
+---+-----
+ 1 | two
+ 1 | two
+(2 rows)
+
+SELECT * FROM atest2; -- fail
+ERROR:  atest2: Permission denied.
+INSERT INTO atest1 VALUES (2, 'two'); -- fail
+ERROR:  atest1: Permission denied.
+INSERT INTO atest2 VALUES ('foo', true); -- fail
+ERROR:  atest2: Permission denied.
+INSERT INTO atest1 SELECT 1, b FROM atest1; -- fail
+ERROR:  atest1: Permission denied.
+UPDATE atest1 SET a = 1 WHERE a = 2; -- fail
+ERROR:  atest1: Permission denied.
+UPDATE atest2 SET col2 = NULL; -- ok
+UPDATE atest2 SET col2 = NOT col2; -- fails; requires SELECT on atest2
+ERROR:  atest2: Permission denied.
+UPDATE atest2 SET col2 = true WHERE atest1.a = 5; -- ok
+SELECT * FROM atest1 FOR UPDATE; -- fail
+ERROR:  atest1: Permission denied.
+SELECT * FROM atest2 FOR UPDATE; -- fail
+ERROR:  atest2: Permission denied.
+DELETE FROM atest2; -- fail
+ERROR:  atest2: Permission denied.
+LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- ok
+COPY atest2 FROM stdin; -- fail
+ERROR:  atest2: Permission denied.
+-- checks in subquery, both fail
+SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) );
+ERROR:  atest2: Permission denied.
+SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
+ERROR:  atest2: Permission denied.
+SET SESSION AUTHORIZATION regressuser4;
+COPY atest2 FROM stdin; -- ok
+-- groups
+SET SESSION AUTHORIZATION regressuser3;
+CREATE TABLE atest3 (one int, two int, three int);
+GRANT DELETE ON atest3 TO GROUP regressgroup2;
+SET SESSION AUTHORIZATION regressuser1;
+SELECT * FROM atest3; -- fail
+ERROR:  atest3: Permission denied.
+DELETE FROM atest3; -- ok
+-- views
+SET SESSION AUTHORIZATION regressuser3;
+CREATE VIEW atestv1 AS SELECT * FROM atest1; -- ok
+/* The next *should* fail, but it's not implemented that way yet. */
+CREATE VIEW atestv2 AS SELECT * FROM atest2;
+CREATE VIEW atestv3 AS SELECT * FROM atest3; -- ok
+SELECT * FROM atestv1; -- ok
+ a |  b  
+---+-----
+ 1 | two
+ 1 | two
+(2 rows)
+
+GRANT SELECT ON atestv1 TO regressuser4;
+GRANT SELECT ON atestv3 TO regressuser4;
+SET SESSION AUTHORIZATION regressuser4;
+SELECT * FROM atestv1; -- ok
+ a |  b  
+---+-----
+ 1 | two
+ 1 | two
+(2 rows)
+
+SELECT * FROM atestv3; -- ok
+ one | two | three 
+-----+-----+-------
+(0 rows)
+
+-- clean up
+\c regression
+DROP TABLE atest1;
+DROP TABLE atest2;
+DROP TABLE atest3;
+DROP VIEW atestv1;
+DROP VIEW atestv2;
+DROP VIEW atestv3;
+DROP GROUP regressgroup1;
+DROP GROUP regressgroup2;
+DROP USER regressuser1;
+DROP USER regressuser2;
+DROP USER regressuser3;
+DROP USER regressuser4;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index f37b2054e40..08e97511ac9 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -61,6 +61,7 @@ test: select
 ignore: random
 test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index
 
+test: privileges
 test: misc
 
 # ----------
diff --git a/src/test/regress/pg_regress.sh b/src/test/regress/pg_regress.sh
index 8eb74b28010..552724a10f1 100644
--- a/src/test/regress/pg_regress.sh
+++ b/src/test/regress/pg_regress.sh
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $Header: /cvsroot/pgsql/src/test/regress/Attic/pg_regress.sh,v 1.20 2001/03/24 23:32:25 petere Exp $
+# $Header: /cvsroot/pgsql/src/test/regress/Attic/pg_regress.sh,v 1.21 2001/05/27 09:59:30 petere Exp $
 
 me=`basename $0`
 : ${TMPDIR=/tmp}
@@ -432,6 +432,18 @@ if [ $? -ne 0 ]; then
 fi
 
 
+# ----------
+# Remove regressuser* and regressgroup* user accounts.
+# ----------
+
+message "dropping regression test user accounts"
+"$bindir/psql" $psql_options -c 'drop group regressgroup1; drop group regressgroup2; drop user regressuser1, regressuser2, regressuser3, regressuser4;' $dbname 2>/dev/null
+if [ $? -eq 2 ]; then
+    echo "$me: could not drop user accounts"
+    (exit 2); exit
+fi
+
+
 # ----------
 # Install the PL/pgSQL language in it
 # ----------
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 14ad6f505e0..afb0090cdad 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -1,4 +1,4 @@
-# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.3 2000/11/22 13:37:44 petere Exp $
+# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.4 2001/05/27 09:59:30 petere Exp $
 # This should probably be in an order similar to parallel_schedule.
 test: boolean
 test: char
@@ -68,6 +68,7 @@ test: portals
 test: arrays
 test: btree_index
 test: hash_index
+test: privileges
 test: misc
 test: select_views
 test: alter_table
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
new file mode 100644
index 00000000000..1558273f7b2
--- /dev/null
+++ b/src/test/regress/sql/privileges.sql
@@ -0,0 +1,146 @@
+--
+-- Test access privileges
+--
+
+CREATE USER regressuser1;
+CREATE USER regressuser2;
+CREATE USER regressuser3;
+CREATE USER regressuser4;
+CREATE USER regressuser4;	-- duplicate
+
+CREATE GROUP regressgroup1;
+CREATE GROUP regressgroup2 WITH USER regressuser1, regressuser2;
+
+ALTER GROUP regressgroup1 ADD USER regressuser4;
+
+ALTER GROUP regressgroup2 ADD USER regressuser2;	-- duplicate
+ALTER GROUP regressgroup2 DROP USER regressuser2;
+ALTER GROUP regressgroup2 ADD USER regressuser4;
+
+
+-- test owner privileges
+
+SET SESSION AUTHORIZATION regressuser1;
+SELECT session_user, current_user;
+
+CREATE TABLE atest1 ( a int, b text );
+SELECT * FROM atest1;
+INSERT INTO atest1 VALUES (1, 'one');
+DELETE FROM atest1;
+UPDATE atest1 SET a = 1 WHERE b = 'blech';
+LOCK atest1 IN ACCESS EXCLUSIVE MODE;
+
+REVOKE ALL ON atest1 FROM PUBLIC;
+SELECT * FROM atest1;
+
+GRANT ALL ON atest1 TO regressuser2;
+GRANT SELECT ON atest1 TO regressuser3;
+SELECT * FROM atest1;
+
+CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
+GRANT SELECT ON atest2 TO regressuser2;
+GRANT UPDATE ON atest2 TO regressuser3;
+GRANT INSERT ON atest2 TO regressuser4;
+
+
+SET SESSION AUTHORIZATION regressuser2;
+SELECT session_user, current_user;
+
+-- try various combinations of queries on atest1 and atest2
+
+SELECT * FROM atest1; -- ok
+SELECT * FROM atest2; -- ok
+INSERT INTO atest1 VALUES (2, 'two'); -- ok
+INSERT INTO atest2 VALUES ('foo', true); -- fail
+INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok
+UPDATE atest1 SET a = 1 WHERE a = 2; -- ok
+UPDATE atest2 SET col2 = NOT col2; -- fail
+SELECT * FROM atest1 FOR UPDATE; -- ok
+SELECT * FROM atest2 FOR UPDATE; -- fail
+DELETE FROM atest2; -- fail
+LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- fail
+COPY atest2 FROM stdin; -- fail
+GRANT ALL ON atest1 TO PUBLIC; -- fail
+
+-- checks in subquery, both ok
+SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) );
+SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
+
+
+SET SESSION AUTHORIZATION regressuser3;
+SELECT session_user, current_user;
+
+SELECT * FROM atest1; -- ok
+SELECT * FROM atest2; -- fail
+INSERT INTO atest1 VALUES (2, 'two'); -- fail
+INSERT INTO atest2 VALUES ('foo', true); -- fail
+INSERT INTO atest1 SELECT 1, b FROM atest1; -- fail
+UPDATE atest1 SET a = 1 WHERE a = 2; -- fail
+UPDATE atest2 SET col2 = NULL; -- ok
+UPDATE atest2 SET col2 = NOT col2; -- fails; requires SELECT on atest2
+UPDATE atest2 SET col2 = true WHERE atest1.a = 5; -- ok
+SELECT * FROM atest1 FOR UPDATE; -- fail
+SELECT * FROM atest2 FOR UPDATE; -- fail
+DELETE FROM atest2; -- fail
+LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- ok
+COPY atest2 FROM stdin; -- fail
+
+-- checks in subquery, both fail
+SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) );
+SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
+
+SET SESSION AUTHORIZATION regressuser4;
+COPY atest2 FROM stdin; -- ok
+bar	true
+\.
+
+
+-- groups
+
+SET SESSION AUTHORIZATION regressuser3;
+CREATE TABLE atest3 (one int, two int, three int);
+GRANT DELETE ON atest3 TO GROUP regressgroup2;
+
+SET SESSION AUTHORIZATION regressuser1;
+
+SELECT * FROM atest3; -- fail
+DELETE FROM atest3; -- ok
+
+
+-- views
+
+SET SESSION AUTHORIZATION regressuser3;
+
+CREATE VIEW atestv1 AS SELECT * FROM atest1; -- ok
+/* The next *should* fail, but it's not implemented that way yet. */
+CREATE VIEW atestv2 AS SELECT * FROM atest2;
+CREATE VIEW atestv3 AS SELECT * FROM atest3; -- ok
+
+SELECT * FROM atestv1; -- ok
+GRANT SELECT ON atestv1 TO regressuser4;
+GRANT SELECT ON atestv3 TO regressuser4;
+
+SET SESSION AUTHORIZATION regressuser4;
+
+SELECT * FROM atestv1; -- ok
+SELECT * FROM atestv3; -- ok
+
+
+-- clean up
+
+\c regression
+DROP TABLE atest1;
+DROP TABLE atest2;
+DROP TABLE atest3;
+
+DROP VIEW atestv1;
+DROP VIEW atestv2;
+DROP VIEW atestv3;
+
+DROP GROUP regressgroup1;
+DROP GROUP regressgroup2;
+
+DROP USER regressuser1;
+DROP USER regressuser2;
+DROP USER regressuser3;
+DROP USER regressuser4;
-- 
GitLab