summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2008-09-08 00:47:41 +0000
committerTom Lane2008-09-08 00:47:41 +0000
commit8e65a0cfd2a062485719e6e9fa8926fad3ba48ca (patch)
treec67237a9aaa03d0bbcb079702f5182d1a8b3ca42
parent5d937da86f8fe74048336a997b77a7bbfa3e7434 (diff)
Create a separate grantable privilege for TRUNCATE, rather than having it be
always owner-only. The TRUNCATE privilege works identically to the DELETE privilege so far as interactions with the rest of the system go. Robert Haas
-rw-r--r--doc/src/sgml/ddl.sgml2
-rw-r--r--doc/src/sgml/func.sgml2
-rw-r--r--doc/src/sgml/information_schema.sgml12
-rw-r--r--doc/src/sgml/ref/grant.sgml24
-rw-r--r--doc/src/sgml/ref/lock.sgml3
-rw-r--r--doc/src/sgml/ref/revoke.sgml2
-rw-r--r--doc/src/sgml/ref/truncate.sgml3
-rw-r--r--doc/src/sgml/user-manag.sgml2
-rw-r--r--src/backend/catalog/aclchk.c8
-rw-r--r--src/backend/catalog/information_schema.sql11
-rw-r--r--src/backend/commands/lockcmds.c2
-rw-r--r--src/backend/commands/tablecmds.c8
-rw-r--r--src/backend/utils/adt/acl.c10
-rw-r--r--src/bin/pg_dump/dumputils.c2
-rw-r--r--src/bin/psql/tab-complete.c6
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/nodes/parsenodes.h2
-rw-r--r--src/include/utils/acl.h5
-rw-r--r--src/test/regress/expected/dependency.out22
-rw-r--r--src/test/regress/expected/privileges.out36
-rw-r--r--src/test/regress/sql/dependency.sql2
-rw-r--r--src/test/regress/sql/privileges.sql16
22 files changed, 135 insertions, 47 deletions
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index 94bb026b80..a9d5f97212 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -1356,7 +1356,7 @@ ALTER TABLE products RENAME TO items;
<para>
There are several different privileges: <literal>SELECT</>,
<literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
- <literal>REFERENCES</>, <literal>TRIGGER</>,
+ <literal>TRUNCATE</>, <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 edc1e37346..e4820f8c8d 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -11369,7 +11369,7 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
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>UPDATE</literal>, <literal>DELETE</literal>, <literal>TRUNCATE</>,
<literal>REFERENCES</literal>, or <literal>TRIGGER</literal>.
(Case of the string is not significant, however.)
An example is:
diff --git a/doc/src/sgml/information_schema.sgml b/doc/src/sgml/information_schema.sgml
index 999bb3a865..62ce85ae71 100644
--- a/doc/src/sgml/information_schema.sgml
+++ b/doc/src/sgml/information_schema.sgml
@@ -2820,9 +2820,9 @@ ORDER BY c.ordinal_position;
<entry><type>character_data</type></entry>
<entry>
Type of the privilege: <literal>SELECT</literal>,
- <literal>DELETE</literal>, <literal>INSERT</literal>,
- <literal>UPDATE</literal>, <literal>REFERENCES</literal>,
- or <literal>TRIGGER</literal>
+ <literal>INSERT</literal>, <literal>UPDATE</literal>,
+ <literal>DELETE</literal>, <literal>TRUNCATE</literal>,
+ <literal>REFERENCES</literal>, or <literal>TRIGGER</literal>
</entry>
</row>
@@ -4406,9 +4406,9 @@ ORDER BY c.ordinal_position;
<entry><type>character_data</type></entry>
<entry>
Type of the privilege: <literal>SELECT</literal>,
- <literal>DELETE</literal>, <literal>INSERT</literal>,
- <literal>UPDATE</literal>, <literal>REFERENCES</literal>,
- or <literal>TRIGGER</literal>
+ <literal>INSERT</literal>, <literal>UPDATE</literal>,
+ <literal>DELETE</literal>, <literal>TRUNCATE</literal>,
+ <literal>REFERENCES</literal>, or <literal>TRIGGER</literal>
</entry>
</row>
diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index 415afc9953..8a9fde3018 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -20,7 +20,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-GRANT { { SELECT | INSERT | UPDATE | DELETE | REFERENCES | TRIGGER }
+GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] <replaceable class="PARAMETER">tablename</replaceable> [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">rolename</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
@@ -193,6 +193,16 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...] TO <replaceable
</varlistentry>
<varlistentry>
+ <term>TRUNCATE</term>
+ <listitem>
+ <para>
+ Allows <xref linkend="sql-truncate" endterm="sql-truncate-title"> on
+ the specified table.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>REFERENCES</term>
<listitem>
<para>
@@ -421,8 +431,8 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...] TO <replaceable
=&gt; \z mytable
Access privileges
Schema | Name | Type | Access privileges
---------+---------+-------+----------------------
- public | mytable | table | miriam=arwdxt/miriam
+--------+---------+-------+-----------------------
+ public | mytable | table | miriam=arwdDxt/miriam
: =r/miriam
: admin=arw/miriam
(1 row)
@@ -436,6 +446,7 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...] TO <replaceable
w -- UPDATE ("write")
a -- INSERT ("append")
d -- DELETE
+ D -- TRUNCATE
x -- REFERENCES
t -- TRIGGER
X -- EXECUTE
@@ -443,7 +454,7 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...] TO <replaceable
C -- CREATE
c -- CONNECT
T -- TEMPORARY
- arwdxt -- ALL PRIVILEGES (for tables)
+ arwdDxt -- ALL PRIVILEGES (for tables)
* -- grant option for preceding privilege
/yyyy -- role that granted this privilege
@@ -466,7 +477,7 @@ GRANT SELECT, UPDATE, INSERT ON mytable TO admin;
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=arwdxt/miriam}</>) and then modify them per the
+ <literal>{miriam=arwdDxt/miriam}</>) and then modify them per the
specified request.
</para>
@@ -524,7 +535,8 @@ GRANT admins TO joe;
<para>
<productname>PostgreSQL</productname> allows an object owner to revoke his
own ordinary privileges: for example, a table owner can make the table
- read-only to himself by revoking his own INSERT, UPDATE, and DELETE
+ read-only to himself by revoking his own <literal>INSERT</>,
+ <literal>UPDATE</>, <literal>DELETE</>, and <literal>TRUNCATE</>
privileges. This is not possible according to the SQL standard. The
reason is that <productname>PostgreSQL</productname> treats the owner's
privileges as having been granted by the owner to himself; therefore he
diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml
index 5223152f06..a0a61cf687 100644
--- a/doc/src/sgml/ref/lock.sgml
+++ b/doc/src/sgml/ref/lock.sgml
@@ -155,7 +155,8 @@ where <replaceable class="PARAMETER">lockmode</replaceable> is one of:
<para>
<literal>LOCK TABLE ... IN ACCESS SHARE MODE</> requires <literal>SELECT</>
privileges on the target table. All other forms of <command>LOCK</>
- require <literal>UPDATE</> and/or <literal>DELETE</> privileges.
+ require at least one of <literal>UPDATE</>, <literal>DELETE</>, or
+ <literal>TRUNCATE</> privileges.
</para>
<para>
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index 00b12bddab..1da44f200d 100644
--- a/doc/src/sgml/ref/revoke.sgml
+++ b/doc/src/sgml/ref/revoke.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
REVOKE [ GRANT OPTION FOR ]
- { { SELECT | INSERT | UPDATE | DELETE | REFERENCES | TRIGGER }
+ { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] <replaceable class="PARAMETER">tablename</replaceable> [, ...]
FROM { [ GROUP ] <replaceable class="PARAMETER">rolename</replaceable> | PUBLIC } [, ...]
diff --git a/doc/src/sgml/ref/truncate.sgml b/doc/src/sgml/ref/truncate.sgml
index 4675a1c286..2e9acfc810 100644
--- a/doc/src/sgml/ref/truncate.sgml
+++ b/doc/src/sgml/ref/truncate.sgml
@@ -97,7 +97,8 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ... ]
<title>Notes</title>
<para>
- Only the owner of a table can <command>TRUNCATE</> it.
+ You must have the <literal>TRUNCATE</literal> privilege on a table
+ to truncate it.
</para>
<para>
diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml
index 1afb221903..357e00c352 100644
--- a/doc/src/sgml/user-manag.sgml
+++ b/doc/src/sgml/user-manag.sgml
@@ -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>REFERENCES</>, <literal>TRIGGER</>,
+ <literal>TRUNCATE</>, <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 15f5af0b96..c57f7196d9 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -1331,6 +1331,8 @@ string_to_privilege(const char *privname)
return ACL_UPDATE;
if (strcmp(privname, "delete") == 0)
return ACL_DELETE;
+ if (strcmp(privname, "truncate") == 0)
+ return ACL_TRUNCATE;
if (strcmp(privname, "references") == 0)
return ACL_REFERENCES;
if (strcmp(privname, "trigger") == 0)
@@ -1368,6 +1370,8 @@ privilege_to_string(AclMode privilege)
return "UPDATE";
case ACL_DELETE:
return "DELETE";
+ case ACL_TRUNCATE:
+ return "TRUNCATE";
case ACL_REFERENCES:
return "REFERENCES";
case ACL_TRIGGER:
@@ -1582,7 +1586,7 @@ pg_class_aclmask(Oid table_oid, Oid roleid,
* protected in this way. Assume the view rules can take care of
* themselves. ACL_USAGE is if we ever have system sequences.
*/
- if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE)) &&
+ if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
IsSystemClass(classForm) &&
classForm->relkind != RELKIND_VIEW &&
!has_rolcatupdate(roleid) &&
@@ -1591,7 +1595,7 @@ pg_class_aclmask(Oid table_oid, Oid roleid,
#ifdef ACLDEBUG
elog(DEBUG2, "permission denied for system catalog update");
#endif
- mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE);
+ mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
}
/*
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index c910efcd4a..fc9765702b 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -1214,9 +1214,10 @@ CREATE VIEW role_table_grants AS
pg_authid u_grantor,
pg_authid g_grantee,
(SELECT 'SELECT' UNION ALL
- SELECT 'DELETE' UNION ALL
SELECT 'INSERT' UNION ALL
SELECT 'UPDATE' UNION ALL
+ SELECT 'DELETE' UNION ALL
+ SELECT 'TRUNCATE' UNION ALL
SELECT 'REFERENCES' UNION ALL
SELECT 'TRIGGER') AS pr (type)
@@ -1728,6 +1729,7 @@ 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, 'TRUNCATE')
OR has_table_privilege(r.oid, 'REFERENCES')
OR has_table_privilege(r.oid, 'TRIGGER') )
@@ -1761,6 +1763,7 @@ 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, 'TRUNCATE')
OR has_table_privilege(r.oid, 'REFERENCES')
OR has_table_privilege(r.oid, 'TRIGGER') );
@@ -1802,9 +1805,10 @@ CREATE VIEW table_privileges AS
SELECT 0::oid, 'PUBLIC'
) AS grantee (oid, rolname),
(SELECT 'SELECT' UNION ALL
- SELECT 'DELETE' UNION ALL
SELECT 'INSERT' UNION ALL
SELECT 'UPDATE' UNION ALL
+ SELECT 'DELETE' UNION ALL
+ SELECT 'TRUNCATE' UNION ALL
SELECT 'REFERENCES' UNION ALL
SELECT 'TRIGGER') AS pr (type)
@@ -1861,6 +1865,7 @@ 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, 'TRUNCATE')
OR has_table_privilege(c.oid, 'REFERENCES')
OR has_table_privilege(c.oid, 'TRIGGER') );
@@ -1982,6 +1987,7 @@ 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, 'TRUNCATE')
OR has_table_privilege(c.oid, 'REFERENCES')
OR has_table_privilege(c.oid, 'TRIGGER') );
@@ -2180,6 +2186,7 @@ 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, 'TRUNCATE')
OR has_table_privilege(c.oid, 'REFERENCES')
OR has_table_privilege(c.oid, 'TRIGGER') );
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index b93bcbeb3c..7bd07c1795 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -54,7 +54,7 @@ LockTableCommand(LockStmt *lockstmt)
ACL_SELECT);
else
aclresult = pg_class_aclcheck(reloid, GetUserId(),
- ACL_UPDATE | ACL_DELETE);
+ ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_CLASS,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2c41c53dfe..890aa297fe 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -989,6 +989,8 @@ ExecuteTruncate(TruncateStmt *stmt)
static void
truncate_check_rel(Relation rel)
{
+ AclResult aclresult;
+
/* Only allow truncate on regular tables */
if (rel->rd_rel->relkind != RELKIND_RELATION)
ereport(ERROR,
@@ -997,8 +999,10 @@ truncate_check_rel(Relation rel)
RelationGetRelationName(rel))));
/* Permissions checks */
- if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+ 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))
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 1659366633..02a7999eb5 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -265,6 +265,9 @@ aclparse(const char *s, AclItem *aip)
case ACL_DELETE_CHR:
read = ACL_DELETE;
break;
+ case ACL_TRUNCATE_CHR:
+ read = ACL_TRUNCATE;
+ break;
case ACL_REFERENCES_CHR:
read = ACL_REFERENCES;
break;
@@ -1323,6 +1326,8 @@ 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, "TRUNCATE") == 0)
+ return ACL_TRUNCATE;
if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
return ACL_REFERENCES;
if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
@@ -1548,6 +1553,11 @@ 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, "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, "REFERENCES") == 0)
return ACL_REFERENCES;
if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 074a56d206..9926caea42 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -659,6 +659,8 @@ do { \
CONVERT_PRIV('x', "REFERENCES");
CONVERT_PRIV('t', "TRIGGER");
}
+ if (remoteVersion >= 80400)
+ CONVERT_PRIV('D', "TRUNCATE");
}
/* UPDATE */
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 25f5735156..7bb2d164b5 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1610,9 +1610,9 @@ psql_completion(char *text, int start, int end)
pg_strcasecmp(prev_wd, "REVOKE") == 0)
{
static const char *const list_privileg[] =
- {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
- "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
- "ALL", NULL};
+ {"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES",
+ "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
+ "ALL", NULL};
COMPLETE_WITH_LIST(list_privileg);
}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 3213d28710..e07e7db779 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200809051
+#define CATALOG_VERSION_NO 200809071
#endif
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index e4e14299b7..b9b396eef4 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -63,7 +63,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) unused, available */
+#define ACL_TRUNCATE (1<<4)
#define ACL_REFERENCES (1<<5)
#define ACL_TRIGGER (1<<6)
#define ACL_EXECUTE (1<<7) /* for functions */
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index ed89d96f4e..466dc7d2a5 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -128,6 +128,7 @@ 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_TRUNCATE_CHR 'D' /* super-delete, as it were */
#define ACL_REFERENCES_CHR 'x'
#define ACL_TRIGGER_CHR 't'
#define ACL_EXECUTE_CHR 'X'
@@ -137,12 +138,12 @@ typedef ArrayType Acl;
#define ACL_CONNECT_CHR 'c'
/* string holding all privilege code chars, in order by bitmask position */
-#define ACL_ALL_RIGHTS_STR "arwdRxtXUCTc"
+#define ACL_ALL_RIGHTS_STR "arwdDxtXUCTc"
/*
* Bitmasks defining "all rights" for each supported object type
*/
-#define ACL_ALL_RIGHTS_RELATION (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_REFERENCES|ACL_TRIGGER)
+#define ACL_ALL_RIGHTS_RELATION (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_TRUNCATE|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 4c6a6af304..178f4221fc 100644
--- a/src/test/regress/expected/dependency.out
+++ b/src/test/regress/expected/dependency.out
@@ -21,7 +21,7 @@ DETAIL: access to table deptest
REVOKE SELECT ON deptest FROM GROUP regression_group;
DROP GROUP regression_group;
-- can't drop the user if we revoke the privileges partially
-REVOKE SELECT, INSERT, UPDATE, DELETE, RULE, REFERENCES ON deptest FROM regression_user;
+REVOKE SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES ON deptest FROM regression_user;
DROP USER regression_user;
ERROR: role "regression_user" cannot be dropped because some objects depend on it
DETAIL: access to table deptest
@@ -68,21 +68,21 @@ 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
- 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
+ Access privileges
+ Schema | Name | Type | Access privileges
+--------+----------+-------+--------------------------------------------------
+ public | deptest1 | table | regression_user0=arwdDxt/regression_user0
+ : regression_user1=a*r*w*d*D*x*t*/regression_user0
+ : regression_user2=arwdDxt/regression_user1
(1 row)
DROP OWNED BY regression_user1;
-- all grants revoked
\z deptest1
- Access privileges
- Schema | Name | Type | Access privileges
---------+----------+-------+------------------------------------------
- public | deptest1 | table | regression_user0=arwdxt/regression_user0
+ Access privileges
+ Schema | Name | Type | Access privileges
+--------+----------+-------+-------------------------------------------
+ public | deptest1 | table | regression_user0=arwdDxt/regression_user0
(1 row)
-- table was dropped
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 32dd625f9b..21f9fc26fd 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -10,14 +10,16 @@ DROP ROLE IF EXISTS regressuser1;
DROP ROLE IF EXISTS regressuser2;
DROP ROLE IF EXISTS regressuser3;
DROP ROLE IF EXISTS regressuser4;
+DROP ROLE IF EXISTS regressuser5;
RESET client_min_messages;
-- test proper begins here
CREATE USER regressuser1;
CREATE USER regressuser2;
CREATE USER regressuser3;
CREATE USER regressuser4;
-CREATE USER regressuser4; -- duplicate
-ERROR: role "regressuser4" already exists
+CREATE USER regressuser5;
+CREATE USER regressuser5; -- duplicate
+ERROR: role "regressuser5" already exists
CREATE GROUP regressgroup1;
CREATE GROUP regressgroup2 WITH USER regressuser1, regressuser2;
ALTER GROUP regressgroup1 ADD USER regressuser4;
@@ -42,6 +44,7 @@ SELECT * FROM atest1;
INSERT INTO atest1 VALUES (1, 'one');
DELETE FROM atest1;
UPDATE atest1 SET a = 1 WHERE b = 'blech';
+TRUNCATE atest1;
LOCK atest1 IN ACCESS EXCLUSIVE MODE;
REVOKE ALL ON atest1 FROM PUBLIC;
SELECT * FROM atest1;
@@ -60,6 +63,7 @@ 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;
+GRANT TRUNCATE ON atest2 TO regressuser5;
SET SESSION AUTHORIZATION regressuser2;
SELECT session_user, current_user;
session_user | current_user
@@ -96,6 +100,8 @@ SELECT * FROM atest2 FOR UPDATE; -- fail
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
LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- fail
ERROR: permission denied for relation atest2
COPY atest2 FROM stdin; -- fail
@@ -147,6 +153,8 @@ SELECT * FROM atest2 FOR UPDATE; -- fail
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
LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- ok
COPY atest2 FROM stdin; -- fail
ERROR: permission denied for relation atest2
@@ -285,6 +293,11 @@ ERROR: must be owner of function testfunc1
DROP FUNCTION testfunc1(int); -- ok
-- restore to sanity
GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC;
+-- truncate
+SET SESSION AUTHORIZATION regressuser5;
+TRUNCATE atest2; -- ok
+TRUNCATE atest3; -- fail
+ERROR: permission denied for relation atest3
-- has_table_privilege function
-- bad-input checks
select has_table_privilege(NULL,'pg_authid','select');
@@ -375,6 +388,12 @@ select has_table_privilege('pg_authid','delete');
t
(1 row)
+select has_table_privilege('pg_authid','truncate');
+ has_table_privilege
+---------------------
+ t
+(1 row)
+
select has_table_privilege(t1.oid,'select')
from (select oid from pg_class where relname = 'pg_authid') as t1;
has_table_privilege
@@ -452,6 +471,12 @@ select has_table_privilege('pg_class','delete');
f
(1 row)
+select has_table_privilege('pg_class','truncate');
+ has_table_privilege
+---------------------
+ f
+(1 row)
+
select has_table_privilege(t1.oid,'select')
from (select oid from pg_class where relname = 'pg_class') as t1;
has_table_privilege
@@ -527,6 +552,12 @@ select has_table_privilege('atest1','delete');
f
(1 row)
+select has_table_privilege('atest1','truncate');
+ has_table_privilege
+---------------------
+ f
+(1 row)
+
select has_table_privilege(t1.oid,'select')
from (select oid from pg_class where relname = 'atest1') as t1;
has_table_privilege
@@ -604,3 +635,4 @@ DROP USER regressuser1;
DROP USER regressuser2;
DROP USER regressuser3;
DROP USER regressuser4;
+DROP USER regressuser5;
diff --git a/src/test/regress/sql/dependency.sql b/src/test/regress/sql/dependency.sql
index 6f8e0e84d5..c1d81569c6 100644
--- a/src/test/regress/sql/dependency.sql
+++ b/src/test/regress/sql/dependency.sql
@@ -21,7 +21,7 @@ REVOKE SELECT ON deptest FROM GROUP regression_group;
DROP GROUP regression_group;
-- can't drop the user if we revoke the privileges partially
-REVOKE SELECT, INSERT, UPDATE, DELETE, RULE, REFERENCES ON deptest FROM regression_user;
+REVOKE SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES ON deptest FROM regression_user;
DROP USER regression_user;
-- now we are OK to drop him
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 90b4781f72..450d5d9d68 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -14,6 +14,7 @@ DROP ROLE IF EXISTS regressuser1;
DROP ROLE IF EXISTS regressuser2;
DROP ROLE IF EXISTS regressuser3;
DROP ROLE IF EXISTS regressuser4;
+DROP ROLE IF EXISTS regressuser5;
RESET client_min_messages;
@@ -23,7 +24,8 @@ CREATE USER regressuser1;
CREATE USER regressuser2;
CREATE USER regressuser3;
CREATE USER regressuser4;
-CREATE USER regressuser4; -- duplicate
+CREATE USER regressuser5;
+CREATE USER regressuser5; -- duplicate
CREATE GROUP regressgroup1;
CREATE GROUP regressgroup2 WITH USER regressuser1, regressuser2;
@@ -45,6 +47,7 @@ SELECT * FROM atest1;
INSERT INTO atest1 VALUES (1, 'one');
DELETE FROM atest1;
UPDATE atest1 SET a = 1 WHERE b = 'blech';
+TRUNCATE atest1;
LOCK atest1 IN ACCESS EXCLUSIVE MODE;
REVOKE ALL ON atest1 FROM PUBLIC;
@@ -58,6 +61,7 @@ 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;
+GRANT TRUNCATE ON atest2 TO regressuser5;
SET SESSION AUTHORIZATION regressuser2;
@@ -75,6 +79,7 @@ UPDATE atest2 SET col2 = NOT col2; -- fail
SELECT * FROM atest1 FOR UPDATE; -- ok
SELECT * FROM atest2 FOR UPDATE; -- fail
DELETE FROM atest2; -- fail
+TRUNCATE atest2; -- fail
LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- fail
COPY atest2 FROM stdin; -- fail
GRANT ALL ON atest1 TO PUBLIC; -- fail
@@ -99,6 +104,7 @@ UPDATE atest2 SET col2 = true FROM atest1 WHERE atest1.a = 5; -- ok
SELECT * FROM atest1 FOR UPDATE; -- fail
SELECT * FROM atest2 FOR UPDATE; -- fail
DELETE FROM atest2; -- fail
+TRUNCATE atest2; -- fail
LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- ok
COPY atest2 FROM stdin; -- fail
@@ -205,6 +211,10 @@ DROP FUNCTION testfunc1(int); -- ok
-- restore to sanity
GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC;
+-- truncate
+SET SESSION AUTHORIZATION regressuser5;
+TRUNCATE atest2; -- ok
+TRUNCATE atest3; -- fail
-- has_table_privilege function
@@ -243,6 +253,7 @@ from (select oid from pg_class where relname = 'pg_authid') as t1,
select has_table_privilege('pg_authid','update');
select has_table_privilege('pg_authid','delete');
+select has_table_privilege('pg_authid','truncate');
select has_table_privilege(t1.oid,'select')
from (select oid from pg_class where relname = 'pg_authid') as t1;
@@ -272,6 +283,7 @@ from (select oid from pg_class where relname = 'pg_class') as t1,
select has_table_privilege('pg_class','update');
select has_table_privilege('pg_class','delete');
+select has_table_privilege('pg_class','truncate');
select has_table_privilege(t1.oid,'select')
from (select oid from pg_class where relname = 'pg_class') as t1;
@@ -298,6 +310,7 @@ from (select oid from pg_class where relname = 'atest1') as t1,
select has_table_privilege('atest1','update');
select has_table_privilege('atest1','delete');
+select has_table_privilege('atest1','truncate');
select has_table_privilege(t1.oid,'select')
from (select oid from pg_class where relname = 'atest1') as t1;
@@ -359,3 +372,4 @@ DROP USER regressuser1;
DROP USER regressuser2;
DROP USER regressuser3;
DROP USER regressuser4;
+DROP USER regressuser5;