recursive.
=> Note this incompatibility in the release notes.
<!--
-$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
-->
<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:
<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>
<!--
-$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
-->
<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>
<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>
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
{
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 */
+ }
}
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
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);
+ }
+ }
}
/*
*
*
* 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
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
*****************************************************************************/
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;
| /*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);
;
+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
(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,
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);