mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
Add ONLY support to LOCK and TRUNCATE. By default, these commands are now
recursive. => Note this incompatibility in the release notes.
This commit is contained in:
parent
b7b8f0b609
commit
ca8100f9eb
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
/* 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)));
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_CLASS,
|
||||
get_rel_name(childreloid));
|
||||
|
||||
relation_close(rel, NoLock); /* close rel, keep lock */
|
||||
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",
|
||||
get_rel_name(childreloid))));
|
||||
|
||||
relation_close(rel, NoLock); /* close rel, keep lock */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user