Disallow LOCK TABLE outside a transaction block (or function), since this case
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 4 Nov 2008 00:57:19 +0000 (00:57 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 4 Nov 2008 00:57:19 +0000 (00:57 +0000)
almost certainly represents user error.  Per a gripe from Sebastian Böhm
and subsequent discussion.

doc/src/sgml/ref/declare.sgml
doc/src/sgml/ref/lock.sgml
src/backend/tcop/utility.c
src/test/regress/expected/privileges.out
src/test/regress/sql/privileges.sql

index 01d24bebce7aaa606c987eaa58ed015fceb341fe..3743198d838e7c63af13a0349e6edc50fea2b6bc 100644 (file)
@@ -175,10 +175,9 @@ DECLARE <replaceable class="parameter">name</replaceable> [ BINARY ] [ INSENSITI
     <productname>PostgreSQL</productname> reports an error if such a
     command is used outside a transaction block.
     Use
-    <xref linkend="sql-begin" endterm="sql-begin-title">,
+    <xref linkend="sql-begin" endterm="sql-begin-title"> and
     <xref linkend="sql-commit" endterm="sql-commit-title">
-    and
-    <xref linkend="sql-rollback" endterm="sql-rollback-title">
+    (or <xref linkend="sql-rollback" endterm="sql-rollback-title">)
     to define a transaction block.
    </para>
 
index a0a61cf687370e45a8c9d09180c5da39a547e5fd..f85ed0d86920ad5fe24f2b669305cb190286ef42 100644 (file)
@@ -160,12 +160,15 @@ where <replaceable class="PARAMETER">lockmode</replaceable> is one of:
    </para>
 
    <para>
-    <command>LOCK TABLE</command> is useful only inside a transaction
-    block (<command>BEGIN</>/<command>COMMIT</> pair), since the lock
-    is dropped as soon as the transaction ends.  A <command>LOCK
-    TABLE</> command appearing outside any transaction block forms a
-    self-contained transaction, so the lock will be dropped as soon as
-    it is obtained.
+    <command>LOCK TABLE</> is useless outside a transaction block: the lock
+    would remain held only to the completion of the statement.  Therefore
+    <productname>PostgreSQL</productname> reports an error if <command>LOCK</>
+    is used outside a transaction block.
+    Use
+    <xref linkend="sql-begin" endterm="sql-begin-title"> and
+    <xref linkend="sql-commit" endterm="sql-commit-title">
+    (or <xref linkend="sql-rollback" endterm="sql-rollback-title">)
+    to define a transaction block.
    </para>
 
   <para>
index f082b1078a619bc4342d9d83b3a0a7e2e67a811d..c2a3b2eff22781d5b9f077f222a03be425cb2bb2 100644 (file)
@@ -938,6 +938,11 @@ ProcessUtility(Node *parsetree,
                        break;
 
                case T_LockStmt:
+                       /*
+                        * Since the lock would just get dropped immediately, LOCK TABLE
+                        * outside a transaction block is presumed to be user error.
+                        */
+                       RequireTransactionChain(isTopLevel, "LOCK TABLE");
                        LockTableCommand((LockStmt *) parsetree);
                        break;
 
index 21f9fc26fd9128ab374cd60e6fa77f7d681500e6..d1767e95ad4cdab702466aaf5e18e3d5842246d4 100644 (file)
@@ -45,7 +45,9 @@ INSERT INTO atest1 VALUES (1, 'one');
 DELETE FROM atest1;
 UPDATE atest1 SET a = 1 WHERE b = 'blech';
 TRUNCATE atest1;
+BEGIN;
 LOCK atest1 IN ACCESS EXCLUSIVE MODE;
+COMMIT;
 REVOKE ALL ON atest1 FROM PUBLIC;
 SELECT * FROM atest1;
  a | b 
@@ -102,8 +104,10 @@ DELETE FROM atest2; -- fail
 ERROR:  permission denied for relation atest2
 TRUNCATE atest2; -- fail
 ERROR:  permission denied for relation atest2
+BEGIN;
 LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- fail
 ERROR:  permission denied for relation atest2
+COMMIT;
 COPY atest2 FROM stdin; -- fail
 ERROR:  permission denied for relation atest2
 GRANT ALL ON atest1 TO PUBLIC; -- fail
@@ -155,7 +159,9 @@ DELETE FROM atest2; -- fail
 ERROR:  permission denied for relation atest2
 TRUNCATE atest2; -- fail
 ERROR:  permission denied for relation atest2
+BEGIN;
 LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- ok
+COMMIT;
 COPY atest2 FROM stdin; -- fail
 ERROR:  permission denied for relation atest2
 -- checks in subquery, both fail
index 450d5d9d68da1102b3355c25f78d91129e6794c4..63532f7e095702e7d6df93e0bc962dd53003544d 100644 (file)
@@ -48,7 +48,9 @@ INSERT INTO atest1 VALUES (1, 'one');
 DELETE FROM atest1;
 UPDATE atest1 SET a = 1 WHERE b = 'blech';
 TRUNCATE atest1;
+BEGIN;
 LOCK atest1 IN ACCESS EXCLUSIVE MODE;
+COMMIT;
 
 REVOKE ALL ON atest1 FROM PUBLIC;
 SELECT * FROM atest1;
@@ -80,7 +82,9 @@ SELECT * FROM atest1 FOR UPDATE; -- ok
 SELECT * FROM atest2 FOR UPDATE; -- fail
 DELETE FROM atest2; -- fail
 TRUNCATE atest2; -- fail
+BEGIN;
 LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- fail
+COMMIT;
 COPY atest2 FROM stdin; -- fail
 GRANT ALL ON atest1 TO PUBLIC; -- fail
 
@@ -105,7 +109,9 @@ SELECT * FROM atest1 FOR UPDATE; -- fail
 SELECT * FROM atest2 FOR UPDATE; -- fail
 DELETE FROM atest2; -- fail
 TRUNCATE atest2; -- fail
+BEGIN;
 LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- ok
+COMMIT;
 COPY atest2 FROM stdin; -- fail
 
 -- checks in subquery, both fail