aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/ref/lock.sgml25
-rw-r--r--src/backend/commands/lockcmds.c18
-rw-r--r--src/test/regress/expected/privileges.out66
-rw-r--r--src/test/regress/sql/privileges.sql61
4 files changed, 79 insertions, 91 deletions
diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml
index d9c5bf9a1d4..8524182211d 100644
--- a/doc/src/sgml/ref/lock.sgml
+++ b/doc/src/sgml/ref/lock.sgml
@@ -165,18 +165,19 @@ LOCK [ TABLE ] [ ONLY ] <replaceable class="parameter">name</replaceable> [ * ]
<title>Notes</title>
<para>
- To lock a table, one must ordinarily have the <literal>MAINTAIN</literal>
- privilege on the table or be the table's owner, a superuser, or a role
- with privileges of the
- <link linkend="predefined-roles-table"><literal>pg_maintain</literal></link>
- role. <literal>LOCK TABLE ... IN ACCESS SHARE MODE</literal> is allowed
- with <literal>SELECT</literal> privileges on the target
- table. <literal>LOCK TABLE ... IN ROW EXCLUSIVE MODE</literal> is allowed
- with <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>,
- or <literal>TRUNCATE</literal> privileges on the target table. All other
- forms of <command>LOCK</command> are allowed with
- table-level <literal>UPDATE</literal>, <literal>DELETE</literal>,
- or <literal>TRUNCATE</literal> privileges.
+ To lock a table, the user must have the right privilege for the specified
+ <replaceable class="parameter">lockmode</replaceable>, or be the table's
+ owner, a superuser, or a role with privileges of the <link
+ linkend="predefined-roles-table"><literal>pg_maintain</literal></link>
+ role. If the user has <literal>MAINTAIN</literal>,
+ <literal>UPDATE</literal>, <literal>DELETE</literal>, or
+ <literal>TRUNCATE</literal> privileges on the table, any <replaceable
+ class="parameter">lockmode</replaceable> is permitted. If the user has
+ <literal>INSERT</literal> privileges on the table, <literal>ROW EXCLUSIVE
+ MODE</literal> (or a less-conflicting mode as described in <xref
+ linkend="explicit-locking"/>) is permitted. If a user has
+ <literal>SELECT</literal> privileges on the table, <literal>ACCESS SHARE
+ MODE</literal> is permitted.
</para>
<para>
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index 99e68bff85d..410d78b040f 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -292,16 +292,16 @@ LockTableAclCheck(Oid reloid, LOCKMODE lockmode, Oid userid)
AclResult aclresult;
AclMode aclmask;
- /* Verify adequate privilege */
- if (lockmode == AccessShareLock)
- aclmask = ACL_SELECT;
- else if (lockmode == RowExclusiveLock)
- aclmask = ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
- else
- aclmask = ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
+ /* any of these privileges permit any lock mode */
+ aclmask = ACL_MAINTAIN | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
+
+ /* SELECT privileges also permit ACCESS SHARE and below */
+ if (lockmode <= AccessShareLock)
+ aclmask |= ACL_SELECT;
- /* MAINTAIN privilege allows all lock modes */
- aclmask |= ACL_MAINTAIN;
+ /* INSERT privileges also permit ROW EXCLUSIVE and below */
+ if (lockmode <= RowExclusiveLock)
+ aclmask |= ACL_INSERT;
aclresult = pg_class_aclcheck(reloid, userid, aclmask);
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 34c26a804a7..95d1e5515fb 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -2706,13 +2706,13 @@ CREATE TABLE lock_table (a int);
GRANT SELECT ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+COMMIT;
+BEGIN;
LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should fail
ERROR: permission denied for table lock_table
ROLLBACK;
BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
-COMMIT;
-BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should fail
ERROR: permission denied for table lock_table
ROLLBACK;
@@ -2722,13 +2722,12 @@ REVOKE SELECT ON lock_table FROM regress_locktable_user;
GRANT INSERT ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+ROLLBACK;
+BEGIN;
LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
COMMIT;
BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
-ERROR: permission denied for table lock_table
-ROLLBACK;
-BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should fail
ERROR: permission denied for table lock_table
ROLLBACK;
@@ -2738,13 +2737,12 @@ REVOKE INSERT ON lock_table FROM regress_locktable_user;
GRANT UPDATE ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+ROLLBACK;
+BEGIN;
LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
COMMIT;
BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
-ERROR: permission denied for table lock_table
-ROLLBACK;
-BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
COMMIT;
\c
@@ -2753,13 +2751,12 @@ REVOKE UPDATE ON lock_table FROM regress_locktable_user;
GRANT DELETE ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+ROLLBACK;
+BEGIN;
LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
COMMIT;
BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
-ERROR: permission denied for table lock_table
-ROLLBACK;
-BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
COMMIT;
\c
@@ -2768,17 +2765,30 @@ REVOKE DELETE ON lock_table FROM regress_locktable_user;
GRANT TRUNCATE ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+ROLLBACK;
+BEGIN;
LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
COMMIT;
BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
-ERROR: permission denied for table lock_table
+LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
+COMMIT;
+\c
+REVOKE TRUNCATE ON lock_table FROM regress_locktable_user;
+-- LOCK TABLE and MAINTAIN permission
+GRANT MAINTAIN ON lock_table TO regress_locktable_user;
+SET SESSION AUTHORIZATION regress_locktable_user;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
ROLLBACK;
BEGIN;
+LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
+COMMIT;
+BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
COMMIT;
\c
-REVOKE TRUNCATE ON lock_table FROM regress_locktable_user;
+REVOKE MAINTAIN ON lock_table FROM regress_locktable_user;
-- clean up
DROP TABLE lock_table;
DROP USER regress_locktable_user;
@@ -2920,14 +2930,6 @@ REINDEX INDEX maintain_test_a_idx;
ERROR: must be owner of index maintain_test_a_idx
REINDEX SCHEMA reindex_test;
ERROR: must be owner of schema reindex_test
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS SHARE MODE;
-ERROR: permission denied for table maintain_test
-COMMIT;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS EXCLUSIVE MODE;
-ERROR: permission denied for table maintain_test
-COMMIT;
RESET ROLE;
SET ROLE regress_maintain;
VACUUM maintain_test;
@@ -2939,12 +2941,6 @@ REINDEX TABLE maintain_test;
REINDEX INDEX maintain_test_a_idx;
REINDEX SCHEMA reindex_test;
ERROR: must be owner of schema reindex_test
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS SHARE MODE;
-COMMIT;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS EXCLUSIVE MODE;
-COMMIT;
RESET ROLE;
SET ROLE regress_maintain_all;
VACUUM maintain_test;
@@ -2955,12 +2951,6 @@ REFRESH MATERIALIZED VIEW refresh_test;
REINDEX TABLE maintain_test;
REINDEX INDEX maintain_test_a_idx;
REINDEX SCHEMA reindex_test;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS SHARE MODE;
-COMMIT;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS EXCLUSIVE MODE;
-COMMIT;
RESET ROLE;
DROP TABLE maintain_test;
DROP MATERIALIZED VIEW refresh_test;
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 39aa0b4ecf7..0bcea77ff4e 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -1707,12 +1707,12 @@ CREATE TABLE lock_table (a int);
GRANT SELECT ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
-LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should fail
-ROLLBACK;
-BEGIN;
LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
COMMIT;
BEGIN;
+LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should fail
+ROLLBACK;
+BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should fail
ROLLBACK;
\c
@@ -1722,12 +1722,12 @@ REVOKE SELECT ON lock_table FROM regress_locktable_user;
GRANT INSERT ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+ROLLBACK;
+BEGIN;
LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
COMMIT;
BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
-ROLLBACK;
-BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should fail
ROLLBACK;
\c
@@ -1737,12 +1737,12 @@ REVOKE INSERT ON lock_table FROM regress_locktable_user;
GRANT UPDATE ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+ROLLBACK;
+BEGIN;
LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
COMMIT;
BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
-ROLLBACK;
-BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
COMMIT;
\c
@@ -1752,12 +1752,12 @@ REVOKE UPDATE ON lock_table FROM regress_locktable_user;
GRANT DELETE ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+ROLLBACK;
+BEGIN;
LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
COMMIT;
BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
-ROLLBACK;
-BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
COMMIT;
\c
@@ -1767,16 +1767,31 @@ REVOKE DELETE ON lock_table FROM regress_locktable_user;
GRANT TRUNCATE ON lock_table TO regress_locktable_user;
SET SESSION AUTHORIZATION regress_locktable_user;
BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+ROLLBACK;
+BEGIN;
LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
COMMIT;
BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
+LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
+COMMIT;
+\c
+REVOKE TRUNCATE ON lock_table FROM regress_locktable_user;
+
+-- LOCK TABLE and MAINTAIN permission
+GRANT MAINTAIN ON lock_table TO regress_locktable_user;
+SET SESSION AUTHORIZATION regress_locktable_user;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
ROLLBACK;
BEGIN;
+LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
+COMMIT;
+BEGIN;
LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
COMMIT;
\c
-REVOKE TRUNCATE ON lock_table FROM regress_locktable_user;
+REVOKE MAINTAIN ON lock_table FROM regress_locktable_user;
-- clean up
DROP TABLE lock_table;
@@ -1884,12 +1899,6 @@ REFRESH MATERIALIZED VIEW refresh_test;
REINDEX TABLE maintain_test;
REINDEX INDEX maintain_test_a_idx;
REINDEX SCHEMA reindex_test;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS SHARE MODE;
-COMMIT;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS EXCLUSIVE MODE;
-COMMIT;
RESET ROLE;
SET ROLE regress_maintain;
@@ -1901,12 +1910,6 @@ REFRESH MATERIALIZED VIEW refresh_test;
REINDEX TABLE maintain_test;
REINDEX INDEX maintain_test_a_idx;
REINDEX SCHEMA reindex_test;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS SHARE MODE;
-COMMIT;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS EXCLUSIVE MODE;
-COMMIT;
RESET ROLE;
SET ROLE regress_maintain_all;
@@ -1918,12 +1921,6 @@ REFRESH MATERIALIZED VIEW refresh_test;
REINDEX TABLE maintain_test;
REINDEX INDEX maintain_test_a_idx;
REINDEX SCHEMA reindex_test;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS SHARE MODE;
-COMMIT;
-BEGIN;
-LOCK TABLE maintain_test IN ACCESS EXCLUSIVE MODE;
-COMMIT;
RESET ROLE;
DROP TABLE maintain_test;