diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml index d576890acb96797078a8e1b18b7080435eb14b42..58e53371c94488d14598d9a1fa210764ff35cf66 100644 --- a/doc/src/sgml/ref/lock.sgml +++ b/doc/src/sgml/ref/lock.sgml @@ -1,5 +1,5 @@ @@ -15,7 +15,7 @@ Postgres documentation LOCK - Explicitly lock a table inside a transaction + Explicitly lock a table / tables inside a transaction @@ -23,8 +23,8 @@ Postgres documentation 2001-07-09 -LOCK [ TABLE ] name -LOCK [ TABLE ] name IN lockmode MODE +LOCK [ TABLE ] name [,...] +LOCK [ TABLE ] name [,...] IN lockmode MODE where lockmode is one of: @@ -373,6 +373,7 @@ ERROR name: Table does not exist. An example for this rule was given previously when discussing the use of SHARE ROW EXCLUSIVE mode rather than SHARE mode. + @@ -383,6 +384,12 @@ ERROR name: Table does not exist. + + When locking multiple tables, the command LOCK a, b; is equivalent to LOCK + a; LOCK b;. The tables are locked one-by-one in the order specified in the + LOCK command. + + 1999-06-08 @@ -406,6 +413,7 @@ ERROR name: Table does not exist. LOCK works only inside transactions. + diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 744129f726fd57f2c3e04fb92112a9b9e0a98543..827608363cb314c5fd38e6565fdd97876f32da25 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.136 2001/07/16 05:06:57 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.137 2001/08/04 19:38:59 momjian Exp $ * * NOTES * The PerformAddAttribute() code, like most of the relation @@ -1984,8 +1984,7 @@ needs_toast_table(Relation rel) MAXALIGN(data_length); return (tuple_length > TOAST_TUPLE_THRESHOLD); } - - + /* * * LOCK TABLE @@ -1994,26 +1993,104 @@ needs_toast_table(Relation rel) void LockTableCommand(LockStmt *lockstmt) { - Relation rel; - int aclresult; + int relCnt; - rel = heap_openr(lockstmt->relname, NoLock); + relCnt = length(lockstmt -> rellist); - if (rel->rd_rel->relkind != RELKIND_RELATION) - elog(ERROR, "LOCK TABLE: %s is not a table", lockstmt->relname); + /* Handle a single relation lock specially to avoid overhead on likely the + most common case */ - if (lockstmt->mode == AccessShareLock) - aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), ACL_SELECT); - else - aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), - ACL_UPDATE | ACL_DELETE); + if(relCnt == 1) + { + + /* Locking a single table */ + + Relation rel; + int aclresult; + char *relname; + + relname = strVal(lfirst(lockstmt->rellist)); + + freeList(lockstmt->rellist); + + rel = heap_openr(relname, NoLock); + + if (rel->rd_rel->relkind != RELKIND_RELATION) + elog(ERROR, "LOCK TABLE: %s is not a table", relname); + + if (lockstmt->mode == AccessShareLock) + aclresult = pg_aclcheck(relname, GetUserId(), + ACL_SELECT); + else + aclresult = pg_aclcheck(relname, GetUserId(), + ACL_UPDATE | ACL_DELETE); + + if (aclresult != ACLCHECK_OK) + elog(ERROR, "LOCK TABLE: permission denied"); + + LockRelation(rel, lockstmt->mode); + + pfree(relname); + + heap_close(rel, NoLock); /* close rel, keep lock */ + } + else + { + List *p; + Relation *RelationArray; + Relation *pRel; - if (aclresult != ACLCHECK_OK) - elog(ERROR, "LOCK TABLE: permission denied"); + /* Locking multiple tables */ - LockRelation(rel, lockstmt->mode); + /* Create an array of relations */ - heap_close(rel, NoLock); /* close rel, keep lock */ + RelationArray = palloc(relCnt * sizeof(Relation)); + pRel = RelationArray; + + /* Iterate over the list and populate the relation array */ + + foreach(p, lockstmt->rellist) + { + char* relname = strVal(lfirst(p)); + int aclresult; + + *pRel = heap_openr(relname, NoLock); + + if ((*pRel)->rd_rel->relkind != RELKIND_RELATION) + elog(ERROR, "LOCK TABLE: %s is not a table", + relname); + + if (lockstmt->mode == AccessShareLock) + aclresult = pg_aclcheck(relname, GetUserId(), + ACL_SELECT); + else + aclresult = pg_aclcheck(relname, GetUserId(), + ACL_UPDATE | ACL_DELETE); + + if (aclresult != ACLCHECK_OK) + elog(ERROR, "LOCK TABLE: permission denied"); + + pRel++; + pfree(relname); + } + + /* Now, lock all the relations, closing each after it is locked + (Keeping the locks) + */ + + for(pRel = RelationArray; + pRel < RelationArray + relCnt; + pRel++) + { + LockRelation(*pRel, lockstmt->mode); + + heap_close(*pRel, NoLock); + } + + /* Free the relation array */ + + pfree(RelationArray); + } } diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 2ea063f336fccb7a7e125e43721e0c1c2a8b7983..65bd5f27e9e1c487a21c4c32ace2820c6b02eb18 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.148 2001/07/16 19:07:37 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.149 2001/08/04 19:38:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -2425,8 +2425,8 @@ _copyLockStmt(LockStmt *from) { LockStmt *newnode = makeNode(LockStmt); - if (from->relname) - newnode->relname = pstrdup(from->relname); + Node_Copy(from, newnode, rellist); + newnode->mode = from->mode; return newnode; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index eb194f667f49769137915d64fc7f788ab39740c9..3a9629cde381ee617c4a838ef456d7702e4622c6 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -20,7 +20,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.96 2001/07/16 19:07:38 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.97 2001/08/04 19:38:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1283,7 +1283,7 @@ _equalDropUserStmt(DropUserStmt *a, DropUserStmt *b) static bool _equalLockStmt(LockStmt *a, LockStmt *b) { - if (!equalstr(a->relname, b->relname)) + if (!equal(a->rellist, b->rellist)) return false; if (a->mode != b->mode) return false; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 00c66246ff96aea1c99bc47b3c38258c84328a46..130d259aaadf99a6444a8a9ee3ef2e4ffbad9277 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.238 2001/07/16 19:07:40 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.239 2001/08/04 19:38:59 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -3280,11 +3280,11 @@ DeleteStmt: DELETE FROM relation_expr where_clause } ; -LockStmt: LOCK_P opt_table relation_name opt_lock +LockStmt: LOCK_P opt_table relation_name_list opt_lock { LockStmt *n = makeNode(LockStmt); - n->relname = $3; + n->rellist = $3; n->mode = $4; $$ = (Node *)n; } diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 9fa703454f8c39df69abe85aba6d157effd1472d..ed379ab02e45a4f7a8b702a71617db095e934152 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.136 2001/07/16 19:07:40 momjian Exp $ + * $Id: parsenodes.h,v 1.137 2001/08/04 19:38:59 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -760,7 +760,7 @@ typedef struct VariableResetStmt typedef struct LockStmt { NodeTag type; - char *relname; /* relation to lock */ + List *rellist; /* relations to lock */ int mode; /* lock mode */ } LockStmt; diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 88330ad3c1de5a9d5af76a53b01ed43e8ca6f059..09180f85c9c28b38ae68378f4f0e392a08295277 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -2421,7 +2421,7 @@ DeleteStmt: DELETE FROM relation_expr where_clause } ; -LockStmt: LOCK_P opt_table relation_name opt_lock +LockStmt: LOCK_P opt_table relation_name_list opt_lock { $$ = cat_str(4, make_str("lock"), $2, $3, $4); }