Greetings,

  The following patch implements individual privileges for TRUNCATE,
  VACUUM and ANALYZE.  Includes documentation and regression test
  updates.  Resolves TODO item 'Add a separate TRUNCATE permission'.
  Created off of current (2005/01/03) CVS TIP.

  At least the 'no one interested has written a patch' argument is gone
  now, fire away with other comments/concerns. :)

        Thanks,

                Stephen
Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/func.sgml,v
retrieving revision 1.301
diff -c -r1.301 func.sgml
*** doc/src/sgml/func.sgml      28 Dec 2005 01:29:58 -0000      1.301
--- doc/src/sgml/func.sgml      4 Jan 2006 03:38:01 -0000
***************
*** 8961,8968 ****
      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.)
      An example is:
  <programlisting>
  SELECT has_table_privilege('myschema.mytable', 'select');
--- 8961,8969 ----
      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>,
!     <literal>TRIGGER</literal>, <literal>TRUNCATE</literal>, 
<literal>VACUUM</literal>, or
!     <literal>ANALYZE</literal>.  (Case of the string is not significant, 
however.)
      An example is:
  <programlisting>
  SELECT has_table_privilege('myschema.mytable', 'select');
Index: doc/src/sgml/information_schema.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/information_schema.sgml,v
retrieving revision 1.23
diff -c -r1.23 information_schema.sgml
*** doc/src/sgml/information_schema.sgml        8 Dec 2005 20:48:10 -0000       
1.23
--- doc/src/sgml/information_schema.sgml        4 Jan 2006 03:38:01 -0000
***************
*** 2395,2401 ****
         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>
        </entry>
       </row>
  
--- 2395,2403 ----
         Type of the privilege: <literal>SELECT</literal>,
         <literal>DELETE</literal>, <literal>INSERT</literal>,
         <literal>UPDATE</literal>, <literal>REFERENCES</literal>,
!        <literal>RULE</literal>, <literal>TRIGGER</literal>,
!        <literal>TRUNCATE</literal>, <literal>VACUUM</literal>, or
!        <literal>ANALYZE</literal>.
        </entry>
       </row>
  
***************
*** 3643,3649 ****
         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>
        </entry>
       </row>
  
--- 3645,3653 ----
         Type of the privilege: <literal>SELECT</literal>,
         <literal>DELETE</literal>, <literal>INSERT</literal>,
         <literal>UPDATE</literal>, <literal>REFERENCES</literal>,
!        <literal>RULE</literal>, <literal>TRIGGER</literal>,
!        <literal>TRUNCATE</literal>, <literal>VACUUM</literal>, or
!        <literal>ANALYZE</literal>.
        </entry>
       </row>
  
Index: doc/src/sgml/user-manag.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/user-manag.sgml,v
retrieving revision 1.33
diff -c -r1.33 user-manag.sgml
*** doc/src/sgml/user-manag.sgml        20 Oct 2005 19:18:00 -0000      1.33
--- doc/src/sgml/user-manag.sgml        4 Jan 2006 03:38:01 -0000
***************
*** 296,301 ****
--- 296,302 ----
     There are several different kinds of privilege: <literal>SELECT</>,
     <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
     <literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
+    <literal>TRUNCATE</>, <literal>VACUUM</>, <literal>ANALYZE</>,
     <literal>CREATE</>, <literal>TEMPORARY</>, <literal>EXECUTE</>,
     and <literal>USAGE</>. For more
     information on the different types of privileges supported by
Index: doc/src/sgml/ref/grant.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v
retrieving revision 1.50
diff -c -r1.50 grant.sgml
*** doc/src/sgml/ref/grant.sgml 20 Oct 2005 19:18:01 -0000      1.50
--- doc/src/sgml/ref/grant.sgml 4 Jan 2006 03:38:02 -0000
***************
*** 20,26 ****
  
   <refsynopsisdiv>
  <synopsis>
! GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | 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 ]
--- 20,26 ----
  
   <refsynopsisdiv>
  <synopsis>
! GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER | 
TRUNCATE | VACUUM | ANALYZE }
      [,...] | 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 ]
***************
*** 205,210 ****
--- 205,243 ----
      </varlistentry>
  
      <varlistentry>
+      <term>TRUNCATE</term>
+      <listitem>
+       <para>
+        Allows the truncation of the specified table.  NOTE: This will NOT 
execute
+        triggers defined on the table.  Additionally, this requires locking 
the table
+        exclusivly because it does not follow normal MVCC rules.  See the <xref
+        linkend="sql-truncate" endterm="sql-truncate-title"> statement.
+       </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
+      <term>VACUUM</term>
+      <listitem>
+       <para>
+        Allows the vacuuming of the specified table.  Note: This implies 
ANALYZE 
+        rights.  See the <xref linkend="sql-vacuum" 
endterm="sql-vacuum-title"> 
+        statement.
+       </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
+      <term>ANALYZE</term>
+      <listitem>
+       <para>
+        Allows the analyzing of the specified table.  See the <xref 
+        linkend="sql-analyze" endterm="sql-analyze-title"> statement.
+       </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
       <term>CREATE</term>
       <listitem>
        <para>
***************
*** 402,408 ****
                    U -- USAGE
                    C -- CREATE
                    T -- TEMPORARY
!             arwdRxt -- ALL PRIVILEGES (for tables)
                    * -- grant option for preceding privilege
  
                /yyyy -- user who granted this privilege
--- 435,444 ----
                    U -- USAGE
                    C -- CREATE
                    T -- TEMPORARY
!                 e -- TRUNCATE
!                 V -- VACUUM
!                 A -- ANALYZE
!          arwdRxteVA -- ALL PRIVILEGES (for tables)
                    * -- grant option for preceding privilege
  
                /yyyy -- user who granted this privilege
Index: doc/src/sgml/ref/revoke.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v
retrieving revision 1.35
diff -c -r1.35 revoke.sgml
*** doc/src/sgml/ref/revoke.sgml        20 Oct 2005 19:18:01 -0000      1.35
--- doc/src/sgml/ref/revoke.sgml        4 Jan 2006 03:38:02 -0000
***************
*** 21,27 ****
   <refsynopsisdiv>
  <synopsis>
  REVOKE [ GRANT OPTION FOR ]
!     { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER }
      [,...] | ALL [ PRIVILEGES ] }
      ON [ TABLE ] <replaceable class="PARAMETER">tablename</replaceable> [, 
...]
      FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP 
<replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
--- 21,27 ----
   <refsynopsisdiv>
  <synopsis>
  REVOKE [ GRANT OPTION FOR ]
!     { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER | 
TRUNCATE | VACUUM | ANALYZE }
      [,...] | ALL [ PRIVILEGES ] }
      ON [ TABLE ] <replaceable class="PARAMETER">tablename</replaceable> [, 
...]
      FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP 
<replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
Index: src/backend/catalog/aclchk.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/aclchk.c,v
retrieving revision 1.123
diff -c -r1.123 aclchk.c
*** src/backend/catalog/aclchk.c        1 Dec 2005 02:03:00 -0000       1.123
--- src/backend/catalog/aclchk.c        4 Jan 2006 03:38:02 -0000
***************
*** 1286,1291 ****
--- 1286,1297 ----
                return ACL_CREATE_TEMP;
        if (strcmp(privname, "temp") == 0)
                return ACL_CREATE_TEMP;
+       if (strcmp(privname, "truncate") == 0)
+               return ACL_TRUNCATE;
+       if (strcmp(privname, "vacuum") == 0)
+               return ACL_VACUUM;
+       if (strcmp(privname, "analyze") == 0)
+               return ACL_ANALYZE;
        ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("unrecognized privilege type \"%s\"", 
privname)));
***************
*** 1319,1324 ****
--- 1325,1336 ----
                        return "CREATE";
                case ACL_CREATE_TEMP:
                        return "TEMP";
+               case ACL_TRUNCATE:
+                       return "TRUNCATE";
+               case ACL_VACUUM:
+                       return "VACUUM";
+               case ACL_ANALYZE:
+                       return "ANALYZE";
                default:
                        elog(ERROR, "unrecognized privilege: %d", (int) 
privilege);
        }
***************
*** 1502,1508 ****
         * protected in this way.  Assume the view rules can take care of
         * themselves.
         */
!       if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
                IsSystemClass(classForm) &&
                classForm->relkind != RELKIND_VIEW &&
                !has_rolcatupdate(roleid) &&
--- 1514,1520 ----
         * protected in this way.  Assume the view rules can take care of
         * themselves.
         */
!       if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE)) &&
                IsSystemClass(classForm) &&
                classForm->relkind != RELKIND_VIEW &&
                !has_rolcatupdate(roleid) &&
***************
*** 1511,1517 ****
  #ifdef ACLDEBUG
                elog(DEBUG2, "permission denied for system catalog update");
  #endif
!               mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE);
        }
  
        /*
--- 1523,1529 ----
  #ifdef ACLDEBUG
                elog(DEBUG2, "permission denied for system catalog update");
  #endif
!               mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE);
        }
  
        /*
Index: src/backend/commands/analyze.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/analyze.c,v
retrieving revision 1.90
diff -c -r1.90 analyze.c
*** src/backend/commands/analyze.c      22 Nov 2005 18:17:08 -0000      1.90
--- src/backend/commands/analyze.c      4 Jan 2006 03:38:02 -0000
***************
*** 112,117 ****
--- 112,118 ----
        double          totalrows,
                                totaldeadrows;
        HeapTuple  *rows;
+       AclResult       aclresult;
  
        if (vacstmt->verbose)
                elevel = INFO;
***************
*** 146,158 ****
         */
        onerel = relation_open(relid, AccessShareLock);
  
!       if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
                  (pg_database_ownercheck(MyDatabaseId, GetUserId()) && 
!onerel->rd_rel->relisshared)))
        {
                /* No need for a WARNING if we already complained during VACUUM 
*/
                if (!vacstmt->vacuum)
                        ereport(WARNING,
!                                       (errmsg("skipping \"%s\" --- only table 
or database owner can analyze it",
                                                        
RelationGetRelationName(onerel))));
                relation_close(onerel, AccessShareLock);
                return;
--- 147,160 ----
         */
        onerel = relation_open(relid, AccessShareLock);
  
!       aclresult = pg_class_aclcheck(RelationGetRelid(onerel), GetUserId(), 
ACL_ANALYZE);
!       if (!((aclresult == ACLCHECK_OK) ||
                  (pg_database_ownercheck(MyDatabaseId, GetUserId()) && 
!onerel->rd_rel->relisshared)))
        {
                /* No need for a WARNING if we already complained during VACUUM 
*/
                if (!vacstmt->vacuum)
                        ereport(WARNING,
!                                       (errmsg("skipping \"%s\" --- only user 
with ANALYZE privilege or database owner can analyze it",
                                                        
RelationGetRelationName(onerel))));
                relation_close(onerel, AccessShareLock);
                return;
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.176
diff -c -r1.176 tablecmds.c
*** src/backend/commands/tablecmds.c    22 Nov 2005 18:17:09 -0000      1.176
--- src/backend/commands/tablecmds.c    4 Jan 2006 03:38:02 -0000
***************
*** 544,549 ****
--- 544,550 ----
        {
                RangeVar   *rv = lfirst(cell);
                Relation        rel;
+               AclResult       aclresult;
  
                /* Grab exclusive lock in preparation for truncate */
                rel = heap_openrv(rv, AccessExclusiveLock);
***************
*** 556,564 ****
                                                        
RelationGetRelationName(rel))));
  
                /* Permissions checks */
!               if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
!                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
!                                                  
RelationGetRelationName(rel));
  
                if (!allowSystemTableMods && IsSystemRelation(rel))
                        ereport(ERROR,
--- 557,565 ----
                                                        
RelationGetRelationName(rel))));
  
                /* Permissions checks */
!               aclresult = pg_class_aclcheck(RelationGetRelid(rel), 
GetUserId(), ACL_TRUNCATE);
!               if (aclresult != ACLCHECK_OK)
!                       aclcheck_error(aclresult, ACL_KIND_CLASS, 
RelationGetRelationName(rel));
  
                if (!allowSystemTableMods && IsSystemRelation(rel))
                        ereport(ERROR,
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.319
diff -c -r1.319 vacuum.c
*** src/backend/commands/vacuum.c       22 Nov 2005 18:17:09 -0000      1.319
--- src/backend/commands/vacuum.c       4 Jan 2006 03:38:02 -0000
***************
*** 948,953 ****
--- 948,954 ----
        LockRelId       onerelid;
        Oid                     toast_relid;
        bool            result;
+       AclResult       aclresult;
  
        /* Begin a transaction for vacuuming this relation */
        StartTransactionCommand();
***************
*** 989,1008 ****
        /*
         * Open the class, get an appropriate lock on it, and check permissions.
         *
!        * We allow the user to vacuum a table if he is superuser, the table
!        * owner, or the database owner (but in the latter case, only if it's 
not
!        * a shared relation).  pg_class_ownercheck includes the superuser case.
         *
         * Note we choose to treat permissions failure as a WARNING and keep
         * trying to vacuum the rest of the DB --- is this appropriate?
         */
        onerel = relation_open(relid, lmode);
  
!       if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
                  (pg_database_ownercheck(MyDatabaseId, GetUserId()) && 
!onerel->rd_rel->relisshared)))
        {
                ereport(WARNING,
!                               (errmsg("skipping \"%s\" --- only table or 
database owner can vacuum it",
                                                
RelationGetRelationName(onerel))));
                relation_close(onerel, lmode);
                StrategyHintVacuum(false);
--- 990,1011 ----
        /*
         * Open the class, get an appropriate lock on it, and check permissions.
         *
!        * We allow the user to vacuum a table if he is superuser, has the
!        * VACUUM permission on the table, or the database owner (but in the
!        * latter case, only if it's not a shared relation).
!        * pg_class_aclcheck includes the superuser case.
         *
         * Note we choose to treat permissions failure as a WARNING and keep
         * trying to vacuum the rest of the DB --- is this appropriate?
         */
        onerel = relation_open(relid, lmode);
  
!       aclresult = pg_class_aclcheck(RelationGetRelid(onerel), GetUserId(), 
ACL_VACUUM);
!       if (!((aclresult == ACLCHECK_OK) ||
                  (pg_database_ownercheck(MyDatabaseId, GetUserId()) && 
!onerel->rd_rel->relisshared)))
        {
                ereport(WARNING,
!                               (errmsg("skipping \"%s\" --- only user with 
VACUUM privilege or database owner can vacuum it",
                                                
RelationGetRelationName(onerel))));
                relation_close(onerel, lmode);
                StrategyHintVacuum(false);
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.521
diff -c -r2.521 gram.y
*** src/backend/parser/gram.y   29 Dec 2005 04:53:18 -0000      2.521
--- src/backend/parser/gram.y   4 Jan 2006 03:38:02 -0000
***************
*** 3300,3305 ****
--- 3300,3306 ----
  privilege:    SELECT                                                          
        { $$ = pstrdup($1); }
                        | REFERENCES                                            
        { $$ = pstrdup($1); }
                        | CREATE                                                
                { $$ = pstrdup($1); }
+                       | ANALYZE                                               
                { $$ = pstrdup($1); }
                        | ColId                                                 
                { $$ = $1; }
                ;
  
Index: src/backend/utils/adt/acl.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/acl.c,v
retrieving revision 1.129
diff -c -r1.129 acl.c
*** src/backend/utils/adt/acl.c 18 Nov 2005 02:38:23 -0000      1.129
--- src/backend/utils/adt/acl.c 4 Jan 2006 03:38:02 -0000
***************
*** 287,292 ****
--- 287,301 ----
                        case ACL_CREATE_TEMP_CHR:
                                read = ACL_CREATE_TEMP;
                                break;
+                       case ACL_TRUNCATE_CHR:
+                               read = ACL_TRUNCATE;
+                               break;
+                       case ACL_VACUUM_CHR:
+                               read = ACL_VACUUM;
+                               break;
+                       case ACL_ANALYZE_CHR:
+                               read = ACL_ANALYZE;
+                               break;
                        default:
                                ereport(ERROR,
                                                
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
***************
*** 1334,1339 ****
--- 1343,1354 ----
                return ACL_CREATE_TEMP;
        if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
                return ACL_CREATE_TEMP;
+       if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
+               return ACL_TRUNCATE;
+       if (pg_strcasecmp(priv_type, "VACUUM") == 0)
+               return ACL_VACUUM;
+       if (pg_strcasecmp(priv_type, "ANALYZE") == 0)
+               return ACL_ANALYZE;
  
        ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
***************
*** 1559,1564 ****
--- 1574,1594 ----
        if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
                return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
  
+       if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
+               return ACL_TRUNCATE;
+       if (pg_strcasecmp(priv_type, "TRUNCATE WITH GRANT OPTION") == 0)
+               return ACL_GRANT_OPTION_FOR(ACL_TRUNCATE);
+ 
+       if (pg_strcasecmp(priv_type, "VACUUM") == 0)
+               return ACL_VACUUM;
+       if (pg_strcasecmp(priv_type, "VACUUM WITH GRANT OPTION") == 0)
+               return ACL_GRANT_OPTION_FOR(ACL_VACUUM);
+ 
+       if (pg_strcasecmp(priv_type, "ANALYZE") == 0)
+               return ACL_ANALYZE;
+       if (pg_strcasecmp(priv_type, "ANALYZE WITH GRANT OPTION") == 0)
+               return ACL_GRANT_OPTION_FOR(ACL_ANALYZE);
+ 
        ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("unrecognized privilege type: \"%s\"", 
priv_type)));
Index: src/bin/pg_dump/dumputils.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_dump/dumputils.c,v
retrieving revision 1.23
diff -c -r1.23 dumputils.c
*** src/bin/pg_dump/dumputils.c 3 Dec 2005 21:06:18 -0000       1.23
--- src/bin/pg_dump/dumputils.c 4 Jan 2006 03:38:02 -0000
***************
*** 580,585 ****
--- 580,588 ----
                        CONVERT_PRIV('d', "DELETE");
                        CONVERT_PRIV('x', "REFERENCES");
                        CONVERT_PRIV('t', "TRIGGER");
+                       CONVERT_PRIV('e', "TRUNCATE");
+                       CONVERT_PRIV('V', "VACUUM");
+                       CONVERT_PRIV('A', "ANALYZE");
                }
                else
                {
Index: src/bin/psql/tab-complete.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/tab-complete.c,v
retrieving revision 1.143
diff -c -r1.143 tab-complete.c
*** src/bin/psql/tab-complete.c 18 Dec 2005 02:17:16 -0000      1.143
--- src/bin/psql/tab-complete.c 4 Jan 2006 03:38:02 -0000
***************
*** 1343,1349 ****
        {
                static const char *const list_privileg[] =
                {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
!               "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", 
NULL};
  
                COMPLETE_WITH_LIST(list_privileg);
        }
--- 1343,1350 ----
        {
                static const char *const list_privileg[] =
                {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
!               "TRIGGER", "TRUNCATE", "VACUUM", "ANALYZE", "CREATE", 
!               "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
  
                COMPLETE_WITH_LIST(list_privileg);
        }
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.298
diff -c -r1.298 parsenodes.h
*** src/include/nodes/parsenodes.h      7 Dec 2005 15:20:55 -0000       1.298
--- src/include/nodes/parsenodes.h      4 Jan 2006 03:38:02 -0000
***************
*** 47,53 ****
  #define ACL_USAGE             (1<<8)  /* for languages and namespaces */
  #define ACL_CREATE            (1<<9)  /* for namespaces and databases */
  #define ACL_CREATE_TEMP (1<<10) /* for databases */
! #define N_ACL_RIGHTS  11              /* 1 plus the last 1<<x */
  #define ACL_NO_RIGHTS 0
  /* Currently, SELECT ... FOR UPDATE/FOR SHARE requires UPDATE privileges */
  #define ACL_SELECT_FOR_UPDATE ACL_UPDATE
--- 47,56 ----
  #define ACL_USAGE             (1<<8)  /* for languages and namespaces */
  #define ACL_CREATE            (1<<9)  /* for namespaces and databases */
  #define ACL_CREATE_TEMP (1<<10) /* for databases */
! #define ACL_TRUNCATE          (1<<11) /* for relations */
! #define ACL_VACUUM            (1<<12) /* for relations */
! #define ACL_ANALYZE           (1<<13) /* for relations */
! #define N_ACL_RIGHTS  14              /* 1 plus the last 1<<x */
  #define ACL_NO_RIGHTS 0
  /* Currently, SELECT ... FOR UPDATE/FOR SHARE requires UPDATE privileges */
  #define ACL_SELECT_FOR_UPDATE ACL_UPDATE
Index: src/include/utils/acl.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/acl.h,v
retrieving revision 1.91
diff -c -r1.91 acl.h
*** src/include/utils/acl.h     1 Dec 2005 02:03:01 -0000       1.91
--- src/include/utils/acl.h     4 Jan 2006 03:38:02 -0000
***************
*** 135,148 ****
  #define ACL_USAGE_CHR                 'U'
  #define ACL_CREATE_CHR                        'C'
  #define ACL_CREATE_TEMP_CHR           'T'
  
  /* string holding all privilege code chars, in order by bitmask position */
! #define ACL_ALL_RIGHTS_STR    "arwdRxtXUCT"
  
  /*
   * 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_DATABASE               (ACL_CREATE|ACL_CREATE_TEMP)
  #define ACL_ALL_RIGHTS_FUNCTION               (ACL_EXECUTE)
  #define ACL_ALL_RIGHTS_LANGUAGE               (ACL_USAGE)
--- 135,151 ----
  #define ACL_USAGE_CHR                 'U'
  #define ACL_CREATE_CHR                        'C'
  #define ACL_CREATE_TEMP_CHR           'T'
+ #define ACL_TRUNCATE_CHR              'e'
+ #define ACL_VACUUM_CHR                        'V'
+ #define ACL_ANALYZE_CHR                       'A'
  
  /* string holding all privilege code chars, in order by bitmask position */
! #define ACL_ALL_RIGHTS_STR    "arwdRxtXUCTeVA"
  
  /*
   * 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|ACL_TRUNCATE|ACL_VACUUM|ACL_ANALYZE)
  #define ACL_ALL_RIGHTS_DATABASE               (ACL_CREATE|ACL_CREATE_TEMP)
  #define ACL_ALL_RIGHTS_FUNCTION               (ACL_EXECUTE)
  #define ACL_ALL_RIGHTS_LANGUAGE               (ACL_USAGE)
Index: src/test/regress/expected/dependency.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/dependency.out,v
retrieving revision 1.3
diff -c -r1.3 dependency.out
*** src/test/regress/expected/dependency.out    21 Nov 2005 12:49:33 -0000      
1.3
--- src/test/regress/expected/dependency.out    4 Jan 2006 03:38:02 -0000
***************
*** 26,32 ****
  ERROR:  role "regression_user" cannot be dropped because some objects depend 
on it
  DETAIL:  access to table deptest
  -- now we are OK to drop him
! REVOKE TRIGGER ON deptest FROM regression_user;
  DROP USER regression_user;
  -- we are OK too if we drop the privileges all at once
  REVOKE ALL ON deptest FROM regression_user2;
--- 26,32 ----
  ERROR:  role "regression_user" cannot be dropped because some objects depend 
on it
  DETAIL:  access to table deptest
  -- now we are OK to drop him
! REVOKE TRIGGER, TRUNCATE, VACUUM, ANALYZE ON deptest FROM regression_user;
  DROP USER regression_user;
  -- we are OK too if we drop the privileges all at once
  REVOKE ALL ON deptest FROM regression_user2;
***************
*** 69,76 ****
  \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}
  (1 row)
  
  DROP OWNED BY regression_user1;
--- 69,76 ----
  \z deptest1
                                                              Access privileges 
for database "regression"
   Schema |   Name   | Type  |                                                  
         Access privileges                                                      
      
! 
--------+----------+-------+----------------------------------------------------------------------------------------------------------------------------------------------------
!  public | deptest1 | table | 
{regression_user0=arwdRxteVA/regression_user0,regression_user1=a*r*w*d*R*x*t*e*V*A*/regression_user0,regression_user2=arwdRxteVA/regression_user1}
  (1 row)
  
  DROP OWNED BY regression_user1;
***************
*** 78,85 ****
  \z deptest1
                 Access privileges for database "regression"
   Schema |   Name   | Type  |              Access privileges              
! --------+----------+-------+---------------------------------------------
!  public | deptest1 | table | {regression_user0=arwdRxt/regression_user0}
  (1 row)
  
  -- table was dropped
--- 78,85 ----
  \z deptest1
                 Access privileges for database "regression"
   Schema |   Name   | Type  |              Access privileges              
! --------+----------+-------+------------------------------------------------
!  public | deptest1 | table | {regression_user0=arwdRxteVA/regression_user0}
  (1 row)
  
  -- table was dropped
Index: src/test/regress/expected/privileges.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/privileges.out,v
retrieving revision 1.32
diff -c -r1.32 privileges.out
*** src/test/regress/expected/privileges.out    15 Aug 2005 02:40:30 -0000      
1.32
--- src/test/regress/expected/privileges.out    4 Jan 2006 03:38:02 -0000
***************
*** 67,72 ****
--- 67,73 ----
  ------+------
  (0 rows)
  
+ TRUNCATE atest1; -- ok
  INSERT INTO atest1 VALUES (2, 'two'); -- ok
  INSERT INTO atest2 VALUES ('foo', true); -- fail
  ERROR:  permission denied for relation atest2
***************
*** 85,90 ****
--- 86,98 ----
  ERROR:  permission denied for relation atest2
  DELETE FROM atest2; -- fail
  ERROR:  permission denied for relation atest2
+ TRUNCATE atest2; -- fail
+ ERROR:  permission denied for relation atest2
+ VACUUM atest2; -- fail
+ WARNING:  skipping "atest2" --- only user with VACUUM privilege or database 
owner can vacuum it
+ ANALYZE atest1; -- ok
+ ANALYZE atest2; -- fail
+ WARNING:  skipping "atest2" --- only user with ANALYZE privilege or database 
owner can analyze it
  LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- fail
  ERROR:  permission denied for relation atest2
  COPY atest2 FROM stdin; -- fail
***************
*** 542,547 ****
--- 550,576 ----
   f
  (1 row)
  
+ select has_table_privilege(t1.oid,'truncate')
+ from (select oid from pg_class where relname = 'atest1') as t1;
+  has_table_privilege
+ ---------------------
+  f
+ (1 row)
+ 
+ select has_table_privilege(t1.oid,'vacuum')
+ from (select oid from pg_class where relname = 'atest1') as t1;
+  has_table_privilege
+ ---------------------
+  f
+ (1 row)
+ 
+ select has_table_privilege(t1.oid,'analyze')
+ from (select oid from pg_class where relname = 'atest1') as t1;
+  has_table_privilege
+ ---------------------
+  f
+ (1 row)
+ 
  -- Grant options
  SET SESSION AUTHORIZATION regressuser1;
  CREATE TABLE atest4 (a int);
Index: src/test/regress/sql/dependency.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/dependency.sql,v
retrieving revision 1.3
diff -c -r1.3 dependency.sql
*** src/test/regress/sql/dependency.sql 21 Nov 2005 12:49:33 -0000      1.3
--- src/test/regress/sql/dependency.sql 4 Jan 2006 03:38:02 -0000
***************
*** 25,31 ****
  DROP USER regression_user;
  
  -- now we are OK to drop him
! REVOKE TRIGGER ON deptest FROM regression_user;
  DROP USER regression_user;
  
  -- we are OK too if we drop the privileges all at once
--- 25,31 ----
  DROP USER regression_user;
  
  -- now we are OK to drop him
! REVOKE TRIGGER, TRUNCATE, VACUUM, ANALYZE ON deptest FROM regression_user;
  DROP USER regression_user;
  
  -- we are OK too if we drop the privileges all at once
Index: src/test/regress/sql/privileges.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/privileges.sql,v
retrieving revision 1.17
diff -c -r1.17 privileges.sql
*** src/test/regress/sql/privileges.sql 15 Aug 2005 02:40:32 -0000      1.17
--- src/test/regress/sql/privileges.sql 4 Jan 2006 03:38:02 -0000
***************
*** 50,55 ****
--- 50,56 ----
  
  SELECT * FROM atest1; -- ok
  SELECT * FROM atest2; -- ok
+ TRUNCATE atest1; -- ok
  INSERT INTO atest1 VALUES (2, 'two'); -- ok
  INSERT INTO atest2 VALUES ('foo', true); -- fail
  INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok
***************
*** 58,63 ****
--- 59,68 ----
  SELECT * FROM atest1 FOR UPDATE; -- ok
  SELECT * FROM atest2 FOR UPDATE; -- fail
  DELETE FROM atest2; -- fail
+ TRUNCATE atest2; -- fail
+ VACUUM atest2; -- fail
+ ANALYZE atest1; -- ok
+ ANALYZE atest2; -- fail
  LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- fail
  COPY atest2 FROM stdin; -- fail
  GRANT ALL ON atest1 TO PUBLIC; -- fail
***************
*** 288,293 ****
--- 293,304 ----
  from (select oid from pg_class where relname = 'atest1') as t1;
  select has_table_privilege(t1.oid,'trigger')
  from (select oid from pg_class where relname = 'atest1') as t1;
+ select has_table_privilege(t1.oid,'truncate')
+ from (select oid from pg_class where relname = 'atest1') as t1;
+ select has_table_privilege(t1.oid,'vacuum')
+ from (select oid from pg_class where relname = 'atest1') as t1;
+ select has_table_privilege(t1.oid,'analyze')
+ from (select oid from pg_class where relname = 'atest1') as t1;
  
  
  -- Grant options

Attachment: signature.asc
Description: Digital signature

Reply via email to