From a0b76dc662efde6e02921c2d16e06418483b7534 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 8 Sep 2008 00:47:41 +0000 Subject: [PATCH] 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 --- doc/src/sgml/ddl.sgml | 4 +-- doc/src/sgml/func.sgml | 4 +-- doc/src/sgml/information_schema.sgml | 14 ++++----- doc/src/sgml/ref/grant.sgml | 26 +++++++++++----- doc/src/sgml/ref/lock.sgml | 5 +-- doc/src/sgml/ref/revoke.sgml | 4 +-- doc/src/sgml/ref/truncate.sgml | 5 +-- doc/src/sgml/user-manag.sgml | 4 +-- src/backend/catalog/aclchk.c | 10 ++++-- src/backend/catalog/information_schema.sql | 13 ++++++-- src/backend/commands/lockcmds.c | 4 +-- src/backend/commands/tablecmds.c | 10 ++++-- src/backend/utils/adt/acl.c | 12 +++++++- src/bin/pg_dump/dumputils.c | 4 ++- src/bin/psql/tab-complete.c | 8 ++--- src/include/catalog/catversion.h | 4 +-- src/include/nodes/parsenodes.h | 4 +-- src/include/utils/acl.h | 7 +++-- src/test/regress/expected/dependency.out | 22 ++++++------- src/test/regress/expected/privileges.out | 36 ++++++++++++++++++++-- src/test/regress/sql/dependency.sql | 2 +- src/test/regress/sql/privileges.sql | 16 +++++++++- 22 files changed, 153 insertions(+), 65 deletions(-) diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index 183d1e89f5..94341df0f4 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -1,4 +1,4 @@ - + Data Definition @@ -1356,7 +1356,7 @@ ALTER TABLE products RENAME TO items; There are several different privileges: SELECT, INSERT, UPDATE, DELETE, - REFERENCES, TRIGGER, + TRUNCATE, REFERENCES, TRIGGER, CREATE, CONNECT, TEMPORARY, EXECUTE, and USAGE. The privileges applicable to a particular diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index c03863af99..cb4e6f991b 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,4 +1,4 @@ - + Functions and Operators @@ -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 SELECT, INSERT, - UPDATE, DELETE, + UPDATE, DELETE, TRUNCATE, REFERENCES, or TRIGGER. (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 d4d51a34a0..7289e0bd45 100644 --- a/doc/src/sgml/information_schema.sgml +++ b/doc/src/sgml/information_schema.sgml @@ -1,4 +1,4 @@ - + The Information Schema @@ -2820,9 +2820,9 @@ ORDER BY c.ordinal_position; character_data Type of the privilege: SELECT, - DELETE, INSERT, - UPDATE, REFERENCES, - or TRIGGER + INSERT, UPDATE, + DELETE, TRUNCATE, + REFERENCES, or TRIGGER @@ -4406,9 +4406,9 @@ ORDER BY c.ordinal_position; character_data Type of the privilege: SELECT, - DELETE, INSERT, - UPDATE, REFERENCES, - or TRIGGER + INSERT, UPDATE, + DELETE, TRUNCATE, + REFERENCES, or TRIGGER diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index c80a33c507..295a764657 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ PostgreSQL documentation -GRANT { { SELECT | INSERT | UPDATE | DELETE | REFERENCES | TRIGGER } +GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } ON [ TABLE ] tablename [, ...] TO { [ GROUP ] rolename | PUBLIC } [, ...] [ WITH GRANT OPTION ] @@ -192,6 +192,16 @@ GRANT role [, ...] TO + + TRUNCATE + + + Allows on + the specified table. + + + + REFERENCES @@ -421,8 +431,8 @@ GRANT role [, ...] TO role [, ...] TO role [, ...] TO GRANT or REVOKE on an object will instantiate the default privileges (producing, for example, - {miriam=arwdxt/miriam}) and then modify them per the + {miriam=arwdDxt/miriam}) and then modify them per the specified request. @@ -524,7 +535,8 @@ GRANT admins TO joe; PostgreSQL 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 INSERT, + UPDATE, DELETE, and TRUNCATE privileges. This is not possible according to the SQL standard. The reason is that PostgreSQL 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 0c2cb8fe2e..d32e6d364c 100644 --- a/doc/src/sgml/ref/lock.sgml +++ b/doc/src/sgml/ref/lock.sgml @@ -1,5 +1,5 @@ @@ -155,7 +155,8 @@ where lockmode is one of: LOCK TABLE ... IN ACCESS SHARE MODE requires SELECT privileges on the target table. All other forms of LOCK - require UPDATE and/or DELETE privileges. + require at least one of UPDATE, DELETE, or + TRUNCATE privileges. diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index 190300d533..86cee9d760 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -1,5 +1,5 @@ @@ -21,7 +21,7 @@ PostgreSQL documentation REVOKE [ GRANT OPTION FOR ] - { { SELECT | INSERT | UPDATE | DELETE | REFERENCES | TRIGGER } + { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } ON [ TABLE ] tablename [, ...] FROM { [ GROUP ] rolename | PUBLIC } [, ...] diff --git a/doc/src/sgml/ref/truncate.sgml b/doc/src/sgml/ref/truncate.sgml index 152b6640d8..f4ef810ce3 100644 --- a/doc/src/sgml/ref/truncate.sgml +++ b/doc/src/sgml/ref/truncate.sgml @@ -1,5 +1,5 @@ @@ -97,7 +97,8 @@ TRUNCATE [ TABLE ] name [, ... ] Notes - Only the owner of a table can TRUNCATE it. + You must have the TRUNCATE privilege on a table + to truncate it. diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml index 871aef702c..d4d9fcc515 100644 --- a/doc/src/sgml/user-manag.sgml +++ b/doc/src/sgml/user-manag.sgml @@ -1,4 +1,4 @@ - + Database Roles and Privileges @@ -293,7 +293,7 @@ ALTER ROLE myname SET enable_indexscan TO off; granted. There are several different kinds of privilege: SELECT, INSERT, UPDATE, DELETE, - REFERENCES, TRIGGER, + TRUNCATE, REFERENCES, TRIGGER, CREATE, CONNECT, TEMPORARY, EXECUTE, and 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 e71f944f1b..941ee62da7 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.147 2008/06/19 00:46:03 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.148 2008/09/08 00:47:40 tgl Exp $ * * NOTES * See acl.h. @@ -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 b10a2e8ea6..970b48b7df 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -4,7 +4,7 @@ * * Copyright (c) 2003-2008, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.45 2008/07/18 03:32:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.46 2008/09/08 00:47:40 tgl Exp $ */ /* @@ -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 bad0afc77b..c5edc2eefc 100644 --- a/src/backend/commands/lockcmds.c +++ b/src/backend/commands/lockcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.18 2008/06/19 00:46:04 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.19 2008/09/08 00:47:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 8b7b101595..62aeb2f3e6 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.265 2008/09/01 20:42:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.266 2008/09/08 00:47:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 3cf54e5875..d0d0775118 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.140 2008/03/25 22:42:43 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.141 2008/09/08 00:47:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 b750d1e900..bf6fa6e445 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.40 2008/01/01 19:45:55 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.41 2008/09/08 00:47:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 97d9f13d7a..fbccb2b0ae 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2008, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.171 2008/08/16 01:36:35 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.172 2008/09/08 00:47:40 tgl Exp $ */ /*---------------------------------------------------------------------- @@ -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 fd596bd52b..272093e5a0 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.483 2008/09/06 00:01:24 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.484 2008/09/08 00:47:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 2a4f6f1421..8b8757659b 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.374 2008/09/01 20:42:45 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.375 2008/09/08 00:47:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 f4940a8023..553ceabee3 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.103 2008/01/01 19:45:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.104 2008/09/08 00:47:41 tgl Exp $ * * NOTES * An ACL array is simply an array of AclItems, representing the union @@ -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;