]> granicus.if.org Git - postgresql/commitdiff
Add ONLY support to LOCK and TRUNCATE. By default, these commands are now
authorPeter Eisentraut <peter_e@gmx.net>
Mon, 12 Jan 2009 08:54:27 +0000 (08:54 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Mon, 12 Jan 2009 08:54:27 +0000 (08:54 +0000)
recursive.

=> Note this incompatibility in the release notes.

doc/src/sgml/ref/lock.sgml
doc/src/sgml/ref/truncate.sgml
src/backend/commands/lockcmds.c
src/backend/commands/tablecmds.c
src/backend/parser/gram.y
src/test/regress/expected/truncate.out
src/test/regress/sql/truncate.sql

index f49d18618c3b844bb0b439a338321786fcf193b5..567f36345115035951bcfd025790d1aecf29b452 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/lock.sgml,v 1.51 2008/11/14 10:22:47 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/lock.sgml,v 1.52 2009/01/12 08:54:25 petere Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-LOCK [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ IN <replaceable class="PARAMETER">lockmode</replaceable> MODE ] [ NOWAIT ]
+LOCK [ TABLE ] [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ IN <replaceable class="PARAMETER">lockmode</replaceable> MODE ] [ NOWAIT ]
 
 where <replaceable class="PARAMETER">lockmode</replaceable> is one of:
 
@@ -109,7 +109,9 @@ where <replaceable class="PARAMETER">lockmode</replaceable> is one of:
     <listitem>
      <para>
       The name (optionally schema-qualified) of an existing table to
-      lock.
+      lock.  If <literal>ONLY</> is specified, only that table is
+      locked.  If <literal>ONLY</> is not specified, the table and all
+      its descendant tables (if any) are locked.
      </para>
 
      <para>
index d765c1bd8c72a873e14e14c598ed86d2c48104ff..a512b9a52d2d3ccf85228ef6f023dd263f0a8b94 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/truncate.sgml,v 1.31 2008/12/18 10:45:00 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/truncate.sgml,v 1.32 2009/01/12 08:54:25 petere Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ... ]
+TRUNCATE [ TABLE ] [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [, ... ]
     [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
@@ -47,7 +47,10 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ... ]
     <term><replaceable class="PARAMETER">name</replaceable></term>
     <listitem>
      <para>
-      The name (optionally schema-qualified) of a table to be truncated.
+      The name (optionally schema-qualified) of a table to be
+      truncated.  If <literal>ONLY</> is specified, only that table is
+      truncated.  If <literal>ONLY</> is not specified, the table and
+      all its descendant tables (if any) are truncated.
      </para>
     </listitem>
    </varlistentry>
index 7d0879da552c346a302ef37544b41402205e1c30..27805be5d80b1c288872c5f56993593970c43146 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.20 2009/01/01 17:23:38 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.21 2009/01/12 08:54:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,8 @@
 #include "catalog/namespace.h"
 #include "commands/lockcmds.h"
 #include "miscadmin.h"
+#include "optimizer/prep.h"
+#include "parser/parse_clause.h"
 #include "utils/acl.h"
 #include "utils/lsyscache.h"
 #include "utils/rel.h"
@@ -40,38 +42,48 @@ LockTableCommand(LockStmt *lockstmt)
        {
                RangeVar   *relation = lfirst(p);
                Oid                     reloid;
-               AclResult       aclresult;
-               Relation        rel;
+               bool            recurse = interpretInhOption(relation->inhOpt);
+               List       *children_and_self;
+               ListCell   *child;
 
-               /*
-                * We don't want to open the relation until we've checked privilege.
-                * So, manually get the relation OID.
-                */
                reloid = RangeVarGetRelid(relation, false);
 
-               if (lockstmt->mode == AccessShareLock)
-                       aclresult = pg_class_aclcheck(reloid, GetUserId(),
-                                                                                 ACL_SELECT);
+               if (recurse)
+                       children_and_self = find_all_inheritors(reloid);
                else
-                       aclresult = pg_class_aclcheck(reloid, GetUserId(),
-                                                                                 ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE);
+                       children_and_self = list_make1_oid(reloid);
 
-               if (aclresult != ACLCHECK_OK)
-                       aclcheck_error(aclresult, ACL_KIND_CLASS,
-                                                  get_rel_name(reloid));
+               foreach(child, children_and_self)
+               {
+                       Oid                     childreloid = lfirst_oid(child);
+                       Relation        rel;
+                       AclResult       aclresult;
 
-               if (lockstmt->nowait)
-                       rel = relation_open_nowait(reloid, lockstmt->mode);
-               else
-                       rel = relation_open(reloid, lockstmt->mode);
+                       /* We don't want to open the relation until we've checked privilege. */
+                       if (lockstmt->mode == AccessShareLock)
+                               aclresult = pg_class_aclcheck(childreloid, GetUserId(),
+                                                                                         ACL_SELECT);
+                       else
+                               aclresult = pg_class_aclcheck(childreloid, GetUserId(),
+                                                                                         ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE);
+
+                       if (aclresult != ACLCHECK_OK)
+                               aclcheck_error(aclresult, ACL_KIND_CLASS,
+                                                          get_rel_name(childreloid));
+
+                       if (lockstmt->nowait)
+                               rel = relation_open_nowait(childreloid, lockstmt->mode);
+                       else
+                               rel = relation_open(childreloid, lockstmt->mode);
 
-               /* Currently, we only allow plain tables to be locked */
-               if (rel->rd_rel->relkind != RELKIND_RELATION)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                                        errmsg("\"%s\" is not a table",
-                                                       relation->relname)));
+                       /* Currently, we only allow plain tables to be locked */
+                       if (rel->rd_rel->relkind != RELKIND_RELATION)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                                errmsg("\"%s\" is not a table",
+                                                               get_rel_name(childreloid))));
 
-               relation_close(rel, NoLock);    /* close rel, keep lock */
+                       relation_close(rel, NoLock);    /* close rel, keep lock */
+               }
        }
 }
index f932b65e1f4c5f41a14332900920cf1b5d3d8f4c..061d45c30ac82c35da958515bb258d92fa840183 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.276 2009/01/01 17:23:39 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.277 2009/01/12 08:54:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -772,17 +772,41 @@ ExecuteTruncate(TruncateStmt *stmt)
        {
                RangeVar   *rv = lfirst(cell);
                Relation        rel;
+               bool            recurse = interpretInhOption(rv->inhOpt);
+               Oid                     myrelid;
 
                rel = heap_openrv(rv, AccessExclusiveLock);
+               myrelid = RelationGetRelid(rel);
                /* don't throw error for "TRUNCATE foo, foo" */
-               if (list_member_oid(relids, RelationGetRelid(rel)))
+               if (list_member_oid(relids, myrelid))
                {
                        heap_close(rel, AccessExclusiveLock);
                        continue;
                }
                truncate_check_rel(rel);
                rels = lappend(rels, rel);
-               relids = lappend_oid(relids, RelationGetRelid(rel));
+               relids = lappend_oid(relids, myrelid);
+
+               if (recurse)
+               {
+                       ListCell   *child;
+                       List       *children;
+
+                       children = find_all_inheritors(myrelid);
+
+                       foreach(child, children)
+                       {
+                               Oid                     childrelid = lfirst_oid(child);
+
+                               if (list_member_oid(relids, childrelid))
+                                       continue;
+
+                               rel = heap_open(childrelid, AccessExclusiveLock);
+                               truncate_check_rel(rel);
+                               rels = lappend(rels, rel);
+                               relids = lappend_oid(relids, childrelid);
+                       }
+               }
        }
 
        /*
index 21b74983410a876b6296a5d6ebe1df3c595acc5b..145e4aac5d35844d1f8739966679502ff8bf54ba 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.652 2009/01/07 22:54:45 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.653 2009/01/12 08:54:26 petere Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -284,6 +284,7 @@ static TypeName *TableFuncTypeName(List *columns);
                                execute_param_clause using_clause returning_clause
                                enum_val_list table_func_column_list
                                create_generic_options alter_generic_options
+                               relation_expr_list
 
 %type <range>  OptTempTableName
 %type <into>   into_clause create_as_target
@@ -3794,7 +3795,7 @@ attrs:            '.' attr_name
  *****************************************************************************/
 
 TruncateStmt:
-                       TRUNCATE opt_table qualified_name_list opt_restart_seqs opt_drop_behavior
+                       TRUNCATE opt_table relation_expr_list opt_restart_seqs opt_drop_behavior
                                {
                                        TruncateStmt *n = makeNode(TruncateStmt);
                                        n->relations = $3;
@@ -6558,7 +6559,15 @@ using_clause:
                        | /*EMPTY*/                                                             { $$ = NIL; }
                ;
 
-LockStmt:      LOCK_P opt_table qualified_name_list opt_lock opt_nowait
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             LOCK TABLE
+ *
+ *****************************************************************************/
+
+LockStmt:      LOCK_P opt_table relation_expr_list opt_lock opt_nowait
                                {
                                        LockStmt *n = makeNode(LockStmt);
 
@@ -7487,6 +7496,12 @@ relation_expr:
                ;
 
 
+relation_expr_list:
+                       relation_expr                                                   { $$ = list_make1($1); }
+                       | relation_expr_list ',' relation_expr  { $$ = lappend($1, $3); }
+               ;
+
+
 /*
  * Given "UPDATE foo set set ...", we have to decide without looking any
  * further ahead whether the first "set" is an alias or the UPDATE's SET
index 3055679f7ebe4c8249b74ad4a1583e50c77465d7..7f43df710c6736ac1e12c5d394e5433405ffd0bc 100644 (file)
@@ -141,6 +141,150 @@ SELECT * FROM trunc_e;
 (0 rows)
 
 DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE;
+-- Test TRUNCATE with inheritance
+CREATE TABLE trunc_f (col1 integer primary key);
+NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "trunc_f_pkey" for table "trunc_f"
+INSERT INTO trunc_f VALUES (1);
+INSERT INTO trunc_f VALUES (2);
+CREATE TABLE trunc_fa (col2a text) INHERITS (trunc_f);
+INSERT INTO trunc_fa VALUES (3, 'three');
+CREATE TABLE trunc_fb (col2b int) INHERITS (trunc_f);
+INSERT INTO trunc_fb VALUES (4, 444);
+CREATE TABLE trunc_faa (col3 text) INHERITS (trunc_fa);
+INSERT INTO trunc_faa VALUES (5, 'five', 'FIVE');
+BEGIN;
+SELECT * FROM trunc_f;
+ col1 
+------
+    1
+    2
+    3
+    4
+    5
+(5 rows)
+
+TRUNCATE trunc_f;
+SELECT * FROM trunc_f;
+ col1 
+------
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+SELECT * FROM trunc_f;
+ col1 
+------
+    1
+    2
+    3
+    4
+    5
+(5 rows)
+
+TRUNCATE ONLY trunc_f;
+SELECT * FROM trunc_f;
+ col1 
+------
+    3
+    4
+    5
+(3 rows)
+
+ROLLBACK;
+BEGIN;
+SELECT * FROM trunc_f;
+ col1 
+------
+    1
+    2
+    3
+    4
+    5
+(5 rows)
+
+SELECT * FROM trunc_fa;
+ col1 | col2a 
+------+-------
+    3 | three
+    5 | five
+(2 rows)
+
+SELECT * FROM trunc_faa;
+ col1 | col2a | col3 
+------+-------+------
+    5 | five  | FIVE
+(1 row)
+
+TRUNCATE ONLY trunc_fb, ONLY trunc_fa;
+SELECT * FROM trunc_f;
+ col1 
+------
+    1
+    2
+    5
+(3 rows)
+
+SELECT * FROM trunc_fa;
+ col1 | col2a 
+------+-------
+    5 | five
+(1 row)
+
+SELECT * FROM trunc_faa;
+ col1 | col2a | col3 
+------+-------+------
+    5 | five  | FIVE
+(1 row)
+
+ROLLBACK;
+BEGIN;
+SELECT * FROM trunc_f;
+ col1 
+------
+    1
+    2
+    3
+    4
+    5
+(5 rows)
+
+SELECT * FROM trunc_fa;
+ col1 | col2a 
+------+-------
+    3 | three
+    5 | five
+(2 rows)
+
+SELECT * FROM trunc_faa;
+ col1 | col2a | col3 
+------+-------+------
+    5 | five  | FIVE
+(1 row)
+
+TRUNCATE ONLY trunc_fb, trunc_fa;
+SELECT * FROM trunc_f;
+ col1 
+------
+    1
+    2
+(2 rows)
+
+SELECT * FROM trunc_fa;
+ col1 | col2a 
+------+-------
+(0 rows)
+
+SELECT * FROM trunc_faa;
+ col1 | col2a | col3 
+------+-------+------
+(0 rows)
+
+ROLLBACK;
+DROP TABLE trunc_f CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to table trunc_fa
+drop cascades to table trunc_faa
+drop cascades to table trunc_fb
 -- Test ON TRUNCATE triggers
 CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);
 CREATE TABLE trunc_trigger_log (tgop text, tglevel text, tgwhen text,
index 3cce3ee314b5fc2bee8c68c4693fb117310a045f..b348e94c48db2f3f68bfd68b643ab6925bd99a76 100644 (file)
@@ -78,6 +78,55 @@ SELECT * FROM trunc_e;
 
 DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE;
 
+-- Test TRUNCATE with inheritance
+
+CREATE TABLE trunc_f (col1 integer primary key);
+INSERT INTO trunc_f VALUES (1);
+INSERT INTO trunc_f VALUES (2);
+
+CREATE TABLE trunc_fa (col2a text) INHERITS (trunc_f);
+INSERT INTO trunc_fa VALUES (3, 'three');
+
+CREATE TABLE trunc_fb (col2b int) INHERITS (trunc_f);
+INSERT INTO trunc_fb VALUES (4, 444);
+
+CREATE TABLE trunc_faa (col3 text) INHERITS (trunc_fa);
+INSERT INTO trunc_faa VALUES (5, 'five', 'FIVE');
+
+BEGIN;
+SELECT * FROM trunc_f;
+TRUNCATE trunc_f;
+SELECT * FROM trunc_f;
+ROLLBACK;
+
+BEGIN;
+SELECT * FROM trunc_f;
+TRUNCATE ONLY trunc_f;
+SELECT * FROM trunc_f;
+ROLLBACK;
+
+BEGIN;
+SELECT * FROM trunc_f;
+SELECT * FROM trunc_fa;
+SELECT * FROM trunc_faa;
+TRUNCATE ONLY trunc_fb, ONLY trunc_fa;
+SELECT * FROM trunc_f;
+SELECT * FROM trunc_fa;
+SELECT * FROM trunc_faa;
+ROLLBACK;
+
+BEGIN;
+SELECT * FROM trunc_f;
+SELECT * FROM trunc_fa;
+SELECT * FROM trunc_faa;
+TRUNCATE ONLY trunc_fb, trunc_fa;
+SELECT * FROM trunc_f;
+SELECT * FROM trunc_fa;
+SELECT * FROM trunc_faa;
+ROLLBACK;
+
+DROP TABLE trunc_f CASCADE;
+
 -- Test ON TRUNCATE triggers
 
 CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);