diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index 5f3f724b7c622172fe187efa400c4b4750f099d1..f21a4797bdb5e5813b9f8f605402d65c1c6558e9 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.60 2006/07/14 00:13:05 neilc Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.61 2006/09/05 21:08:33 tgl Exp $ -->
 
 <chapter id="ddl">
  <title>Data Definition</title>
@@ -1342,7 +1342,7 @@ ALTER TABLE products RENAME TO items;
   <para>
    There are several different privileges: <literal>SELECT</>,
    <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
-   <literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
+   <literal>REFERENCES</>, <literal>TRIGGER</>,
    <literal>CREATE</>, <literal>CONNECT</>, <literal>TEMPORARY</>,
    <literal>EXECUTE</>, and <literal>USAGE</>.
    The privileges applicable to a particular
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index ebf793ae55e749acd9e448bc0326927d5628ced6..13209c87a29145e1989b69f426a3a293bf0ee3ef 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.333 2006/09/04 21:47:25 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.334 2006/09/05 21:08:33 tgl Exp $ -->
 
  <chapter id="functions">
   <title>Functions and Operators</title>
@@ -9543,9 +9543,10 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
     the name can be schema-qualified if necessary.
     The desired access privilege type
     is specified by a text string, which must evaluate to one of the
-    values <literal>SELECT</literal>, <literal>INSERT</literal>, <literal>UPDATE</literal>,
-    <literal>DELETE</literal>, <literal>RULE</literal>, <literal>REFERENCES</literal>, or
-    <literal>TRIGGER</literal>.  (Case of the string is not significant, however.)
+    values <literal>SELECT</literal>, <literal>INSERT</literal>,
+    <literal>UPDATE</literal>, <literal>DELETE</literal>,
+    <literal>REFERENCES</literal>, or <literal>TRIGGER</literal>.
+    (Case of the string is not significant, however.)
     An example is:
 <programlisting>
 SELECT has_table_privilege('myschema.mytable', 'select');
diff --git a/doc/src/sgml/information_schema.sgml b/doc/src/sgml/information_schema.sgml
index 1ce808463df3e7088ed7e078461f6caa63709268..544b811c546a6bff245534a40c3b34f7a6768468 100644
--- a/doc/src/sgml/information_schema.sgml
+++ b/doc/src/sgml/information_schema.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/information_schema.sgml,v 1.26 2006/05/02 18:07:51 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/information_schema.sgml,v 1.27 2006/09/05 21:08:34 tgl Exp $ -->
 
 <chapter id="information-schema">
  <title>The Information Schema</title>
@@ -2832,7 +2832,7 @@ ORDER BY c.ordinal_position;
        Type of the privilege: <literal>SELECT</literal>,
        <literal>DELETE</literal>, <literal>INSERT</literal>,
        <literal>UPDATE</literal>, <literal>REFERENCES</literal>,
-       <literal>RULE</literal>, or <literal>TRIGGER</literal>
+       or <literal>TRIGGER</literal>
       </entry>
      </row>
 
@@ -4418,7 +4418,7 @@ ORDER BY c.ordinal_position;
        Type of the privilege: <literal>SELECT</literal>,
        <literal>DELETE</literal>, <literal>INSERT</literal>,
        <literal>UPDATE</literal>, <literal>REFERENCES</literal>,
-       <literal>RULE</literal>, or <literal>TRIGGER</literal>
+       or <literal>TRIGGER</literal>
       </entry>
      </row>
 
diff --git a/doc/src/sgml/ref/create_rule.sgml b/doc/src/sgml/ref/create_rule.sgml
index 9380ab5a184627c7507fcc96f5ad6662da195967..1c9cf0b91a8819abb0dc3584603106fa759ed6d0 100644
--- a/doc/src/sgml/ref/create_rule.sgml
+++ b/doc/src/sgml/ref/create_rule.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_rule.sgml,v 1.46 2006/09/02 17:06:52 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_rule.sgml,v 1.47 2006/09/05 21:08:35 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -200,8 +200,7 @@ CREATE [ OR REPLACE ] RULE <replaceable class="parameter">name</replaceable> AS
   <title>Notes</title>
 
   <para>
-   You must have the privilege <literal>RULE</literal> on a table to
-   be allowed to define a rule on it.
+   You must be the owner of a table to create or change rules for it.
   </para>
 
   <para>
diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index d846cd07fde4118f4ccdbeca066b431237b2c1d0..e00ea521e931d6b4b0941dbb8ebb76738d4be7ad 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.60 2006/08/02 16:29:49 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.61 2006/09/05 21:08:35 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -20,7 +20,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER }
+GRANT { { SELECT | INSERT | UPDATE | DELETE | REFERENCES | TRIGGER }
     [,...] | ALL [ PRIVILEGES ] }
     ON [ TABLE ] <replaceable class="PARAMETER">tablename</replaceable> [, ...]
     TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
@@ -178,16 +178,6 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...] TO <replaceable
      </listitem>
     </varlistentry>
 
-    <varlistentry>
-     <term>RULE</term>
-     <listitem>
-      <para>
-       Allows the creation of a rule on the table/view.  (See the <xref
-       linkend="sql-createrule" endterm="sql-createrule-title"> statement.)
-      </para>
-     </listitem>
-    </varlistentry>
-
     <varlistentry>
      <term>REFERENCES</term>
      <listitem>
@@ -418,8 +408,8 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...] TO <replaceable
 
                         Access privileges for database "lusitania"
  Schema |  Name   | Type  |                     Access privileges
---------+---------+-------+------------------------------------------------------------
- public | mytable | table | {miriam=arwdRxt/miriam,=r/miriam,"group todos=arw/miriam"}
+--------+---------+-------+-----------------------------------------------------------
+ public | mytable | table | {miriam=arwdxt/miriam,=r/miriam,"group todos=arw/miriam"}
 (1 row)
 </programlisting>
     The entries shown by <command>\z</command> are interpreted thus:
@@ -432,7 +422,6 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...] TO <replaceable
                   w -- UPDATE ("write")
                   a -- INSERT ("append")
                   d -- DELETE
-                  R -- RULE
                   x -- REFERENCES
                   t -- TRIGGER
                   X -- EXECUTE
@@ -440,7 +429,7 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...] TO <replaceable
                   C -- CREATE
                   c -- CONNECT
                   T -- TEMPORARY
-            arwdRxt -- ALL PRIVILEGES (for tables)
+             arwdxt -- ALL PRIVILEGES (for tables)
                   * -- grant option for preceding privilege
 
               /yyyy -- user who granted this privilege
@@ -463,7 +452,7 @@ and may include some privileges for <literal>PUBLIC</> depending on the
 object type, as explained above.  The first <command>GRANT</> or
 <command>REVOKE</> on an object
 will instantiate the default privileges (producing, for example,
-<literal>{miriam=arwdRxt/miriam}</>) and then modify them per the
+<literal>{miriam=arwdxt/miriam}</>) and then modify them per the
 specified request.
    </para>
 
@@ -548,8 +537,7 @@ GRANT <replaceable class="PARAMETER">privileges</replaceable>
    </para>
 
    <para>
-    The <literal>RULE</literal> privilege, and privileges on
-    databases, tablespaces, schemas, and languages are
+    Privileges on databases, tablespaces, schemas, and languages are
     <productname>PostgreSQL</productname> extensions.
    </para>
  </refsect1>
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index df38437436fe3324a36fc2b1672e7c6a237b8a55..03746d5622955e11feabd2af43d9bfbf50cd0506 100644
--- a/doc/src/sgml/ref/revoke.sgml
+++ b/doc/src/sgml/ref/revoke.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.39 2006/08/02 16:29:49 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.40 2006/09/05 21:08:35 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
  <refsynopsisdiv>
 <synopsis>
 REVOKE [ GRANT OPTION FOR ]
-    { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER }
+    { { SELECT | INSERT | UPDATE | DELETE | REFERENCES | TRIGGER }
     [,...] | ALL [ PRIVILEGES ] }
     ON [ TABLE ] <replaceable class="PARAMETER">tablename</replaceable> [, ...]
     FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml
index c86837d1f7a84b4a7ed815e1c7c577cff56353fb..ec5c6e43c4dd68a35e5ae841e7644b6f2020108b 100644
--- a/doc/src/sgml/user-manag.sgml
+++ b/doc/src/sgml/user-manag.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/user-manag.sgml,v 1.36 2006/08/02 16:29:49 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/user-manag.sgml,v 1.37 2006/09/05 21:08:34 tgl Exp $ -->
 
 <chapter id="user-manag">
  <title>Database Roles and Privileges</title>
@@ -293,7 +293,7 @@ ALTER ROLE myname SET enable_indexscan TO off;
    granted.
    There are several different kinds of privilege: <literal>SELECT</>,
    <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
-   <literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
+   <literal>REFERENCES</>, <literal>TRIGGER</>,
    <literal>CREATE</>, <literal>CONNECT</>, <literal>TEMPORARY</>,
    <literal>EXECUTE</>, and <literal>USAGE</>.
    For more information on the different types of privileges supported by
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 73b9ef6e9d94a75817e1b531f3e85cee8360ee40..e74c9b4410e7c0f1a427b3b16b679fda83eb7b4b 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.130 2006/07/14 14:52:17 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.131 2006/09/05 21:08:35 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -1328,8 +1328,6 @@ string_to_privilege(const char *privname)
 		return ACL_UPDATE;
 	if (strcmp(privname, "delete") == 0)
 		return ACL_DELETE;
-	if (strcmp(privname, "rule") == 0)
-		return ACL_RULE;
 	if (strcmp(privname, "references") == 0)
 		return ACL_REFERENCES;
 	if (strcmp(privname, "trigger") == 0)
@@ -1346,6 +1344,8 @@ string_to_privilege(const char *privname)
 		return ACL_CREATE_TEMP;
 	if (strcmp(privname, "connect") == 0)
 		return ACL_CONNECT;
+	if (strcmp(privname, "rule") == 0)
+		return 0;				/* ignore old RULE privileges */
 	ereport(ERROR,
 			(errcode(ERRCODE_SYNTAX_ERROR),
 			 errmsg("unrecognized privilege type \"%s\"", privname)));
@@ -1365,8 +1365,6 @@ privilege_to_string(AclMode privilege)
 			return "UPDATE";
 		case ACL_DELETE:
 			return "DELETE";
-		case ACL_RULE:
-			return "RULE";
 		case ACL_REFERENCES:
 			return "REFERENCES";
 		case ACL_TRIGGER:
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index a30cddd2878941eeed64270a0ba442fcb68c31c5..a735fa3081f818effbed1290a3f8e1e27d366040 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2003-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.35 2006/09/04 23:13:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.36 2006/09/05 21:08:35 tgl Exp $
  */
 
 /*
@@ -1194,7 +1194,6 @@ CREATE VIEW role_table_grants AS
           SELECT 'INSERT' UNION ALL
           SELECT 'UPDATE' UNION ALL
           SELECT 'REFERENCES' UNION ALL
-          SELECT 'RULE' UNION ALL
           SELECT 'TRIGGER') AS pr (type)
 
     WHERE c.relnamespace = nc.oid
@@ -1705,7 +1704,6 @@ CREATE VIEW table_constraints AS
                OR has_table_privilege(r.oid, 'INSERT')
                OR has_table_privilege(r.oid, 'UPDATE')
                OR has_table_privilege(r.oid, 'DELETE')
-               OR has_table_privilege(r.oid, 'RULE')
                OR has_table_privilege(r.oid, 'REFERENCES')
                OR has_table_privilege(r.oid, 'TRIGGER') )
 
@@ -1739,7 +1737,6 @@ CREATE VIEW table_constraints AS
                OR has_table_privilege(r.oid, 'INSERT')
                OR has_table_privilege(r.oid, 'UPDATE')
                OR has_table_privilege(r.oid, 'DELETE')
-               OR has_table_privilege(r.oid, 'RULE')
                OR has_table_privilege(r.oid, 'REFERENCES')
                OR has_table_privilege(r.oid, 'TRIGGER') );
 
@@ -1785,7 +1782,6 @@ CREATE VIEW table_privileges AS
           SELECT 'INSERT' UNION ALL
           SELECT 'UPDATE' UNION ALL
           SELECT 'REFERENCES' UNION ALL
-          SELECT 'RULE' UNION ALL
           SELECT 'TRIGGER') AS pr (type)
 
     WHERE c.relnamespace = nc.oid
@@ -1841,7 +1837,6 @@ CREATE VIEW tables AS
                OR has_table_privilege(c.oid, 'INSERT')
                OR has_table_privilege(c.oid, 'UPDATE')
                OR has_table_privilege(c.oid, 'DELETE')
-               OR has_table_privilege(c.oid, 'RULE')
                OR has_table_privilege(c.oid, 'REFERENCES')
                OR has_table_privilege(c.oid, 'TRIGGER') );
 
@@ -1963,7 +1958,6 @@ CREATE VIEW triggers AS
                OR has_table_privilege(c.oid, 'INSERT')
                OR has_table_privilege(c.oid, 'UPDATE')
                OR has_table_privilege(c.oid, 'DELETE')
-               OR has_table_privilege(c.oid, 'RULE')
                OR has_table_privilege(c.oid, 'REFERENCES')
                OR has_table_privilege(c.oid, 'TRIGGER') );
 
@@ -2162,7 +2156,6 @@ CREATE VIEW views AS
                OR has_table_privilege(c.oid, 'INSERT')
                OR has_table_privilege(c.oid, 'UPDATE')
                OR has_table_privilege(c.oid, 'DELETE')
-               OR has_table_privilege(c.oid, 'RULE')
                OR has_table_privilege(c.oid, 'REFERENCES')
                OR has_table_privilege(c.oid, 'TRIGGER') );
 
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 2e29535c4e7b4960bfbfed05425675c4a5749f7d..f54243a49554f3ae828b02000070c3f94f60162e 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -7,7 +7,7 @@
  * Copyright (c) 1996-2006, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.90 2006/07/14 14:52:18 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.91 2006/09/05 21:08:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -741,7 +741,6 @@ CommentRule(List *qualname, char *comment)
 	HeapTuple	tuple;
 	Oid			reloid;
 	Oid			ruleoid;
-	AclResult	aclcheck;
 
 	/* Separate relname and trig name */
 	nnames = list_length(qualname);
@@ -819,9 +818,8 @@ CommentRule(List *qualname, char *comment)
 	}
 
 	/* Check object security */
-	aclcheck = pg_class_aclcheck(reloid, GetUserId(), ACL_RULE);
-	if (aclcheck != ACLCHECK_OK)
-		aclcheck_error(aclcheck, ACL_KIND_CLASS,
+	if (!pg_class_ownercheck(reloid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
 					   get_rel_name(reloid));
 
 	/* Call CreateComments() to create/drop the comments */
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index a961f49d9b1b16915f488c5343a37d2cfac3f79f..17f437c385597f3e003c307870aa449e211446d7 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.113 2006/09/02 17:06:52 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.114 2006/09/05 21:08:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,9 +33,8 @@
 
 static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
 								bool isSelect);
-static void setRuleCheckAsUser_Query(Query *qry, Oid userid);
-static void setRuleCheckAsUser_Expr(Node *node, Oid userid);
 static bool setRuleCheckAsUser_walker(Node *node, Oid *context);
+static void setRuleCheckAsUser_Query(Query *qry, Oid userid);
 
 
 /*
@@ -193,7 +192,6 @@ DefineQueryRewrite(RuleStmt *stmt)
 	int			event_attno;
 	ListCell   *l;
 	Query	   *query;
-	AclResult	aclresult;
 	bool		RelisBecomingView = false;
 
 	/*
@@ -209,9 +207,8 @@ DefineQueryRewrite(RuleStmt *stmt)
 	/*
 	 * Check user has permission to apply rules to this relation.
 	 */
-	aclresult = pg_class_aclcheck(ev_relid, GetUserId(), ACL_RULE);
-	if (aclresult != ACLCHECK_OK)
-		aclcheck_error(aclresult, ACL_KIND_CLASS,
+	if (!pg_class_ownercheck(ev_relid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
 					   RelationGetRelationName(event_relation));
 
 	/*
@@ -411,19 +408,6 @@ DefineQueryRewrite(RuleStmt *stmt)
 	 */
 	event_attno = -1;
 
-	/*
-	 * We want the rule's table references to be checked as though by the rule
-	 * owner, not the user referencing the rule.  Therefore, scan through the
-	 * rule's rtables and set the checkAsUser field on all rtable entries.  We
-	 * have to look at event_qual as well, in case it contains sublinks.
-	 */
-	foreach(l, action)
-	{
-		query = (Query *) lfirst(l);
-		setRuleCheckAsUser_Query(query, GetUserId());
-	}
-	setRuleCheckAsUser_Expr(event_qual, GetUserId());
-
 	/* discard rule if it's null action and not INSTEAD; it's a no-op */
 	if (action != NIL || is_instead)
 	{
@@ -554,9 +538,9 @@ checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect)
 }
 
 /*
- * setRuleCheckAsUser_Query
- *		Recursively scan a query and set the checkAsUser field to the
- *		given userid in all rtable entries.
+ * setRuleCheckAsUser
+ *		Recursively scan a query or expression tree and set the checkAsUser
+ *		field to the given userid in all rtable entries.
  *
  * Note: for a view (ON SELECT rule), the checkAsUser field of the *OLD*
  * RTE entry will be overridden when the view rule is expanded, and the
@@ -565,6 +549,26 @@ checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect)
  * it's important to set these fields to match the rule owner.  So we just set
  * them always.
  */
+void
+setRuleCheckAsUser(Node *node, Oid userid)
+{
+	(void) setRuleCheckAsUser_walker(node, &userid);
+}
+
+static bool
+setRuleCheckAsUser_walker(Node *node, Oid *context)
+{
+	if (node == NULL)
+		return false;
+	if (IsA(node, Query))
+	{
+		setRuleCheckAsUser_Query((Query *) node, *context);
+		return false;
+	}
+	return expression_tree_walker(node, setRuleCheckAsUser_walker,
+								  (void *) context);
+}
+
 static void
 setRuleCheckAsUser_Query(Query *qry, Oid userid)
 {
@@ -591,31 +595,6 @@ setRuleCheckAsUser_Query(Query *qry, Oid userid)
 						  QTW_IGNORE_RT_SUBQUERIES);
 }
 
-/*
- * Expression-tree walker to find sublink queries
- */
-static void
-setRuleCheckAsUser_Expr(Node *node, Oid userid)
-{
-	(void) setRuleCheckAsUser_walker(node, &userid);
-}
-
-static bool
-setRuleCheckAsUser_walker(Node *node, Oid *context)
-{
-	if (node == NULL)
-		return false;
-	if (IsA(node, Query))
-	{
-		Query	   *qry = (Query *) node;
-
-		setRuleCheckAsUser_Query(qry, *context);
-		return false;
-	}
-	return expression_tree_walker(node, setRuleCheckAsUser_walker,
-								  (void *) context);
-}
-
 
 /*
  * Rename an existing rewrite rule.
diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c
index b0acc01f8273289936f33c4afc99cf1c1247a1f1..e57724af4d7ce90de616feff51d50d05e3482c5f 100644
--- a/src/backend/rewrite/rewriteRemove.c
+++ b/src/backend/rewrite/rewriteRemove.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteRemove.c,v 1.65 2006/06/16 20:23:44 adunstan Exp $
+ *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteRemove.c,v 1.66 2006/09/05 21:08:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,7 +39,6 @@ RemoveRewriteRule(Oid owningRel, const char *ruleName, DropBehavior behavior,
 {
 	HeapTuple	tuple;
 	Oid			eventRelationOid;
-	AclResult	aclresult;
 	ObjectAddress object;
 
 	/*
@@ -72,9 +71,8 @@ RemoveRewriteRule(Oid owningRel, const char *ruleName, DropBehavior behavior,
 	 */
 	eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class;
 	Assert(eventRelationOid == owningRel);
-	aclresult = pg_class_aclcheck(eventRelationOid, GetUserId(), ACL_RULE);
-	if (aclresult != ACLCHECK_OK)
-		aclcheck_error(aclresult, ACL_KIND_CLASS,
+	if (!pg_class_ownercheck(eventRelationOid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
 					   get_rel_name(eventRelationOid));
 
 	/*
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c3ac26dce4aa47e0accb3fa58f77ed20d2ce3a51..509c6dea92af9d1a79207a3e2fad6590548725df 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.134 2006/07/14 14:52:23 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.135 2006/09/05 21:08:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -265,9 +265,6 @@ aclparse(const char *s, AclItem *aip)
 			case ACL_DELETE_CHR:
 				read = ACL_DELETE;
 				break;
-			case ACL_RULE_CHR:
-				read = ACL_RULE;
-				break;
 			case ACL_REFERENCES_CHR:
 				read = ACL_REFERENCES;
 				break;
@@ -289,6 +286,9 @@ aclparse(const char *s, AclItem *aip)
 			case ACL_CONNECT_CHR:
 				read = ACL_CONNECT;
 				break;
+			case 'R':			/* ignore old RULE privileges */
+				read = 0;
+				break;
 			default:
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
@@ -1325,8 +1325,6 @@ convert_priv_string(text *priv_type_text)
 		return ACL_UPDATE;
 	if (pg_strcasecmp(priv_type, "DELETE") == 0)
 		return ACL_DELETE;
-	if (pg_strcasecmp(priv_type, "RULE") == 0)
-		return ACL_RULE;
 	if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
 		return ACL_REFERENCES;
 	if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
@@ -1343,6 +1341,8 @@ convert_priv_string(text *priv_type_text)
 		return ACL_CREATE_TEMP;
 	if (pg_strcasecmp(priv_type, "CONNECT") == 0)
 		return ACL_CONNECT;
+	if (pg_strcasecmp(priv_type, "RULE") == 0)
+		return 0;				/* ignore old RULE privileges */
 
 	ereport(ERROR,
 			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -1553,11 +1553,6 @@ convert_table_priv_string(text *priv_type_text)
 	if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
 		return ACL_GRANT_OPTION_FOR(ACL_DELETE);
 
-	if (pg_strcasecmp(priv_type, "RULE") == 0)
-		return ACL_RULE;
-	if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
-		return ACL_GRANT_OPTION_FOR(ACL_RULE);
-
 	if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
 		return ACL_REFERENCES;
 	if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
@@ -1568,6 +1563,11 @@ convert_table_priv_string(text *priv_type_text)
 	if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
 		return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
 
+	if (pg_strcasecmp(priv_type, "RULE") == 0)
+		return 0;				/* ignore old RULE privileges */
+	if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
+		return 0;
+
 	ereport(ERROR,
 			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 			 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 08697d503667c6cc5956f0891288da101b7f1399..190543e2bd712eeab57ee0b25115195cd08c281a 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.247 2006/07/31 20:09:05 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.248 2006/09/05 21:08:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,6 +51,7 @@
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
 #include "optimizer/prep.h"
+#include "rewrite/rewriteDefine.h"
 #include "storage/fd.h"
 #include "storage/smgr.h"
 #include "utils/builtins.h"
@@ -683,6 +684,22 @@ RelationBuildRuleLock(Relation relation)
 		if ((Pointer) rule_text != DatumGetPointer(rule_datum))
 			pfree(rule_text);
 
+		/*
+		 * We want the rule's table references to be checked as though by the
+		 * table owner, not the user referencing the rule.  Therefore, scan
+		 * through the rule's actions and set the checkAsUser field on all
+		 * rtable entries.  We have to look at the qual as well, in case it
+		 * contains sublinks.
+		 *
+		 * The reason for doing this when the rule is loaded, rather than
+		 * when it is stored, is that otherwise ALTER TABLE OWNER would have
+		 * to grovel through stored rules to update checkAsUser fields.
+		 * Scanning the rule tree during load is relatively cheap (compared
+		 * to constructing it in the first place), so we do it here.
+		 */
+		setRuleCheckAsUser((Node *) rule->actions, relation->rd_rel->relowner);
+		setRuleCheckAsUser(rule->qual, relation->rd_rel->relowner);
+
 		if (numlocks >= maxlocks)
 		{
 			maxlocks *= 2;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 6266b591cab463e1dea362bb0c8478a31d94294a..7e207a8ee2d6635c4bd8a958fb96a328afc87b66 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.353 2006/08/25 04:06:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.354 2006/09/05 21:08:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200608211
+#define CATALOG_VERSION_NO	200609051
 
 #endif
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 40708404fccd555b7c92dd4cfda576b4a0588621..0b9de4905d10c85fc0477ed771fc2839f6ab66bb 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.329 2006/09/03 03:19:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.330 2006/09/05 21:08:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,7 +50,7 @@ typedef uint32 AclMode;			/* a bitmask of privilege bits */
 #define ACL_SELECT		(1<<1)
 #define ACL_UPDATE		(1<<2)
 #define ACL_DELETE		(1<<3)
-#define ACL_RULE		(1<<4)
+/* #define ACL_RULE		(1<<4)	unused, available */
 #define ACL_REFERENCES	(1<<5)
 #define ACL_TRIGGER		(1<<6)
 #define ACL_EXECUTE		(1<<7)	/* for functions */
diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h
index 3d284894e3aaeb90f3dac13269e4aeefc0341888..e404ac526a82c389052bd22ce9a6ef857fc92fd3 100644
--- a/src/include/rewrite/rewriteDefine.h
+++ b/src/include/rewrite/rewriteDefine.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.21 2006/03/05 15:58:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.22 2006/09/05 21:08:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,4 +21,6 @@ extern void DefineQueryRewrite(RuleStmt *args);
 extern void RenameRewriteRule(Oid owningRel, const char *oldName,
 				  const char *newName);
 
+extern void setRuleCheckAsUser(Node *node, Oid userid);
+
 #endif   /* REWRITEDEFINE_H */
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 27aaf0dfbf7e01de6f9f1dc81cbad43905598e0c..56226b42162473e2b10423beb3cac9b78c73257e 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.96 2006/05/03 22:45:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.97 2006/09/05 21:08:36 tgl Exp $
  *
  * NOTES
  *	  An ACL array is simply an array of AclItems, representing the union
@@ -128,7 +128,6 @@ typedef ArrayType Acl;
 #define ACL_SELECT_CHR			'r'		/* formerly known as "read" */
 #define ACL_UPDATE_CHR			'w'		/* formerly known as "write" */
 #define ACL_DELETE_CHR			'd'
-#define ACL_RULE_CHR			'R'
 #define ACL_REFERENCES_CHR		'x'
 #define ACL_TRIGGER_CHR			't'
 #define ACL_EXECUTE_CHR			'X'
@@ -143,7 +142,7 @@ typedef ArrayType Acl;
 /*
  * Bitmasks defining "all rights" for each supported object type
  */
-#define ACL_ALL_RIGHTS_RELATION		(ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER)
+#define ACL_ALL_RIGHTS_RELATION		(ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_REFERENCES|ACL_TRIGGER)
 #define ACL_ALL_RIGHTS_SEQUENCE		(ACL_USAGE|ACL_SELECT|ACL_UPDATE)
 #define ACL_ALL_RIGHTS_DATABASE		(ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT)
 #define ACL_ALL_RIGHTS_FUNCTION		(ACL_EXECUTE)
diff --git a/src/test/regress/expected/dependency.out b/src/test/regress/expected/dependency.out
index ba65a351bc8c41cd74d2452d3739a2ee6499014d..82c1bf01383da4b1ecf6477d0d19969e5dab6ebe 100644
--- a/src/test/regress/expected/dependency.out
+++ b/src/test/regress/expected/dependency.out
@@ -68,19 +68,19 @@ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "deptest_pkey" fo
 GRANT ALL ON deptest1 TO regression_user2;
 RESET SESSION AUTHORIZATION;
 \z deptest1
-                                                            Access privileges for database "regression"
- Schema |   Name   | Type  |                                                           Access privileges                                                            
---------+----------+-------+----------------------------------------------------------------------------------------------------------------------------------------
- public | deptest1 | table | {regression_user0=arwdRxt/regression_user0,regression_user1=a*r*w*d*R*x*t*/regression_user0,regression_user2=arwdRxt/regression_user1}
+                                                          Access privileges for database "regression"
+ Schema |   Name   | Type  |                                                         Access privileges                                                          
+--------+----------+-------+------------------------------------------------------------------------------------------------------------------------------------
+ public | deptest1 | table | {regression_user0=arwdxt/regression_user0,regression_user1=a*r*w*d*x*t*/regression_user0,regression_user2=arwdxt/regression_user1}
 (1 row)
 
 DROP OWNED BY regression_user1;
 -- all grants revoked
 \z deptest1
-               Access privileges for database "regression"
- Schema |   Name   | Type  |              Access privileges              
---------+----------+-------+---------------------------------------------
- public | deptest1 | table | {regression_user0=arwdRxt/regression_user0}
+              Access privileges for database "regression"
+ Schema |   Name   | Type  |             Access privileges              
+--------+----------+-------+--------------------------------------------
+ public | deptest1 | table | {regression_user0=arwdxt/regression_user0}
 (1 row)
 
 -- table was dropped
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 201e8a11d313e3bb465b2a13f2be2bd551c19cf6..5404969c6089813c415a5cc048add3816d9c76fb 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -301,7 +301,7 @@ select has_table_privilege('pg_authid','sel');
 ERROR:  unrecognized privilege type: "sel"
 select has_table_privilege(-999999,'pg_authid','update');
 ERROR:  role with OID 4293967297 does not exist
-select has_table_privilege(1,'rule');
+select has_table_privilege(1,'select');
 ERROR:  relation with OID 1 does not exist
 -- superuser
 \c -
@@ -331,11 +331,13 @@ from (select oid from pg_roles where rolname = current_user) as t2;
  t
 (1 row)
 
+-- 'rule' privilege no longer exists, but for backwards compatibility
+-- has_table_privilege still recognizes the keyword and says FALSE
 select has_table_privilege(current_user,t1.oid,'rule')
 from (select oid from pg_class where relname = 'pg_authid') as t1;
  has_table_privilege 
 ---------------------
- t
+ f
 (1 row)
 
 select has_table_privilege(current_user,t1.oid,'references')
@@ -415,13 +417,6 @@ from (select oid from pg_roles where rolname = current_user) as t2;
  f
 (1 row)
 
-select has_table_privilege(current_user,t1.oid,'rule')
-from (select oid from pg_class where relname = 'pg_class') as t1;
- has_table_privilege 
----------------------
- f
-(1 row)
-
 select has_table_privilege(current_user,t1.oid,'references')
 from (select oid from pg_class where relname = 'pg_class') as t1;
  has_table_privilege 
@@ -497,13 +492,6 @@ from (select oid from pg_roles where rolname = current_user) as t2;
  f
 (1 row)
 
-select has_table_privilege(current_user,t1.oid,'rule')
-from (select oid from pg_class where relname = 'atest1') as t1;
- has_table_privilege 
----------------------
- f
-(1 row)
-
 select has_table_privilege(current_user,t1.oid,'references')
 from (select oid from pg_class where relname = 'atest1') as t1;
  has_table_privilege 
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 3b96abe87ea739f10b917c50c97ea59aaf4c4e7c..4c0d9c43f2783a31e7f6f3a6c5a41275a3450578 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -214,7 +214,7 @@ select has_table_privilege('pg_shad','select');
 select has_table_privilege('nosuchuser','pg_authid','select');
 select has_table_privilege('pg_authid','sel');
 select has_table_privilege(-999999,'pg_authid','update');
-select has_table_privilege(1,'rule');
+select has_table_privilege(1,'select');
 
 -- superuser
 \c -
@@ -227,6 +227,8 @@ from (select oid from pg_roles where rolname = current_user) as t2;
 select has_table_privilege(t2.oid,'pg_authid','delete')
 from (select oid from pg_roles where rolname = current_user) as t2;
 
+-- 'rule' privilege no longer exists, but for backwards compatibility
+-- has_table_privilege still recognizes the keyword and says FALSE
 select has_table_privilege(current_user,t1.oid,'rule')
 from (select oid from pg_class where relname = 'pg_authid') as t1;
 select has_table_privilege(current_user,t1.oid,'references')
@@ -258,8 +260,6 @@ from (select oid from pg_roles where rolname = current_user) as t2;
 select has_table_privilege(t2.oid,'pg_class','delete')
 from (select oid from pg_roles where rolname = current_user) as t2;
 
-select has_table_privilege(current_user,t1.oid,'rule')
-from (select oid from pg_class where relname = 'pg_class') as t1;
 select has_table_privilege(current_user,t1.oid,'references')
 from (select oid from pg_class where relname = 'pg_class') as t1;
 
@@ -286,8 +286,6 @@ from (select oid from pg_roles where rolname = current_user) as t2;
 select has_table_privilege(t2.oid,'atest1','delete')
 from (select oid from pg_roles where rolname = current_user) as t2;
 
-select has_table_privilege(current_user,t1.oid,'rule')
-from (select oid from pg_class where relname = 'atest1') as t1;
 select has_table_privilege(current_user,t1.oid,'references')
 from (select oid from pg_class where relname = 'atest1') as t1;