1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Add support for DEFERRED, IMMEDIATE, and EXCLUSIVE transactions. (CVS 2000)

FossilOrigin-Name: 81ff8107ad63113782cf5a9ba7a512496114ba08
This commit is contained in:
drh
2004-10-05 02:41:42 +00:00
parent 9a43267ba2
commit 684917c269
18 changed files with 249 additions and 119 deletions

View File

@@ -1,5 +1,5 @@
C More\schanges\sto\stake\sadvantage\sof\sthe\sTK_\sand\sOP_\salignments\sto\savoid\nunnecessary\stranslations.\s(CVS\s1999) C Add\ssupport\sfor\sDEFERRED,\sIMMEDIATE,\sand\sEXCLUSIVE\stransactions.\s(CVS\s2000)
D 2004-10-04T13:38:09 D 2004-10-05T02:41:42
F Makefile.in 78ddc9fca09ab6e3b75a79ecf8d490e34cd0519c F Makefile.in 78ddc9fca09ab6e3b75a79ecf8d490e34cd0519c
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -29,16 +29,16 @@ F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689 F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
F src/btree.c 014d3c9d31136050f3b3294c0c5dc0c7615557bf F src/btree.c bb3f8cadf65cc0752d07e219733a496c1aebe020
F src/btree.h 94dfec0a1722d33359b23e7e310f2b64ffedf029 F src/btree.h 94dfec0a1722d33359b23e7e310f2b64ffedf029
F src/build.c 2ed6d9c26ad736142012bc99898869db17337121 F src/build.c 73bd4219c1cb6fb09a05b7d4a6ed3ae1d0ecb8db
F src/date.c 93927e2d1ffbd833fc220644896cfdc8f8d4af34 F src/date.c 93927e2d1ffbd833fc220644896cfdc8f8d4af34
F src/delete.c d862b383a9abc0b79f4588783c2619fe52d74ea7 F src/delete.c 7a9543ed784bd51ded17c805ff6a4fe864c1676c
F src/expr.c 2f492bf532d700bd2c38e16caa49048535e8ed27 F src/expr.c 2f492bf532d700bd2c38e16caa49048535e8ed27
F src/func.c 1fbc5256639586573fd0e70814d6dcd8bc10afc1 F src/func.c 1fbc5256639586573fd0e70814d6dcd8bc10afc1
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
F src/insert.c 2c10c001f62cde92e9517ec7516b6584519754d1 F src/insert.c 7e8ce8834c3716a313694e5340dbf28ff828677a
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
F src/main.c 2a1b9623fde3fe5e22fe726cdae4e10f33671caa F src/main.c 2a1b9623fde3fe5e22fe726cdae4e10f33671caa
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
@@ -52,16 +52,16 @@ F src/os_unix.c 5c1f362846afec4232c2291b9f1564f0487e91f4
F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13 F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13
F src/os_win.c 9482dfc92f289b68205bb2c9315757c7e3946bfb F src/os_win.c 9482dfc92f289b68205bb2c9315757c7e3946bfb
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c d3688828d314135ef0cd87b4d892805136c4168f F src/pager.c dc0ffab9941393b072e0b1f1f3de54830727cec9
F src/pager.h 67739fe649f33be55dba522ca8a9cc4e42d14f71 F src/pager.h 774d1973acbda341827d21b0da0150575d69f7d9
F src/parse.y 3616bdde17fd9be9c235e40cd732a831a3e8fa61 F src/parse.y e03d7d7f712ad2b5be61e9a024820c0a8ffdf36d
F src/pragma.c 45978cc82fdf91f00d024a8e875c2b679fbce488 F src/pragma.c ba7fdd19c1680bb9bfc8bc5230278f6ae6b1c8ff
F src/printf.c 40770e1f553612d13dfc86d236086e69baa62fe1 F src/printf.c 40770e1f553612d13dfc86d236086e69baa62fe1
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
F src/select.c 96b1489111abe9b584be2f2cce26ad6f2d425b4e F src/select.c 96b1489111abe9b584be2f2cce26ad6f2d425b4e
F src/shell.c 0856973c2b94e22664bc43f398ba3fc22d5e080c F src/shell.c 0856973c2b94e22664bc43f398ba3fc22d5e080c
F src/sqlite.h.in 9bb76ff9e79ee72e6d529ff6ab1c252d513c3864 F src/sqlite.h.in 9bb76ff9e79ee72e6d529ff6ab1c252d513c3864
F src/sqliteInt.h bfb12f1da75b2a8f5c88c9c3050343571def65b9 F src/sqliteInt.h 610f25a92c0ce5edf40d12087c643c310e1d7d05
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
F src/tclsqlite.c 0302e3f42f015d132d1291f3388c06e86c24a008 F src/tclsqlite.c 0302e3f42f015d132d1291f3388c06e86c24a008
F src/test1.c 3d78e5d827bf5d037f697c233c5934d45af46cb5 F src/test1.c 3d78e5d827bf5d037f697c233c5934d45af46cb5
@@ -69,13 +69,13 @@ F src/test2.c b11fa244fff02190707dd0879987c37c75e61fc8
F src/test3.c 5b5b0f3d11b097399c1054fff73d8f3711092301 F src/test3.c 5b5b0f3d11b097399c1054fff73d8f3711092301
F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1 F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1
F src/tokenize.c d4619367d9ba17c6bd4e018fb7e91015ae8562aa F src/tokenize.c 449843c85c8118b9718f3935f4b5d18586c8cee2
F src/trigger.c d1f770ee37a80391dd6d0948ee821b0272f99ae7 F src/trigger.c b983f8d763d2c253535947e543c3386dc1117ca1
F src/update.c 7157084216c4b02a23cdb23eb6d246aa9034fa4d F src/update.c 174c3b593b8f4928e510a51ec309e8ce69d2371c
F src/utf.c f4f83acd73389090e32d6589d307fc55d794c7ed F src/utf.c f4f83acd73389090e32d6589d307fc55d794c7ed
F src/util.c f4ab796b9def353feed2191d7ce8e39a0f5059cd F src/util.c f4ab796b9def353feed2191d7ce8e39a0f5059cd
F src/vacuum.c 257de36230cb988842f66eb08dc6c0250b8e05f3 F src/vacuum.c 257de36230cb988842f66eb08dc6c0250b8e05f3
F src/vdbe.c 49d4bda66884b1017e11962c7fb7eaf15b436be8 F src/vdbe.c f7ebf1a20a5fdca27e80cb96e06e988da2426379
F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181 F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181
F src/vdbeInt.h 6017100adff362b8dfa37a69e3f1431f084bfa5b F src/vdbeInt.h 6017100adff362b8dfa37a69e3f1431f084bfa5b
F src/vdbeapi.c 81ab9e84c55f5762f552904e6e5d309269b02017 F src/vdbeapi.c 81ab9e84c55f5762f552904e6e5d309269b02017
@@ -137,6 +137,7 @@ F test/laststmtchanges.test 417aa27eb2b5cdfafb46e390e2c9ddd0a20eba43
F test/limit.test f7c06fccd76755e8d083b61c06bc31cf461b9c35 F test/limit.test f7c06fccd76755e8d083b61c06bc31cf461b9c35
F test/lock.test 7cb9395919a0986ee4dd08bd49d34df93c8fc4fe F test/lock.test 7cb9395919a0986ee4dd08bd49d34df93c8fc4fe
F test/lock2.test 2213590d442147d09fd2334c905a755586c1c398 F test/lock2.test 2213590d442147d09fd2334c905a755586c1c398
F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9
F test/main.test 1430a4b5bd3a6d5e0294966b742d80a551f87211 F test/main.test 1430a4b5bd3a6d5e0294966b742d80a551f87211
F test/malloc.test 769b240d89a7ef3320d88919fdb6765f9395a51f F test/malloc.test 769b240d89a7ef3320d88919fdb6765f9395a51f
F test/memdb.test b8a13fa79f006bd087bbcf135ce8eb62056a6027 F test/memdb.test b8a13fa79f006bd087bbcf135ce8eb62056a6027
@@ -150,7 +151,7 @@ F test/misuse.test fcd9e7cec6ecccc34822584aec6b4e31f13629e1
F test/notnull.test 7a08117a71e74b0321aaa937dbeb41a09d6eb1d0 F test/notnull.test 7a08117a71e74b0321aaa937dbeb41a09d6eb1d0
F test/null.test 642428b6a5408cc5b954b49e1b6e5025e4458b2b F test/null.test 642428b6a5408cc5b954b49e1b6e5025e4458b2b
F test/pager.test 394455707a079804e8a4e431d12edce831a065f0 F test/pager.test 394455707a079804e8a4e431d12edce831a065f0
F test/pager2.test 2b505eca6bf214dfff412cf615678a835c83ca74 F test/pager2.test c7e731ac56a2984a605b032ffd19b9deee820377
F test/pager3.test 16f546293bb751b8151dc17df613fca938bbec8b F test/pager3.test 16f546293bb751b8151dc17df613fca938bbec8b
F test/pagesize.test f8b46ec46b9fe9f708a8d757dda232588dfb7217 F test/pagesize.test f8b46ec46b9fe9f708a8d757dda232588dfb7217
F test/pragma.test 66a66b7f3b273b93325c9a5794acb418f52fdcbf F test/pragma.test 66a66b7f3b273b93325c9a5794acb418f52fdcbf
@@ -234,7 +235,7 @@ F www/faq.tcl 8cf9f59fd93868c9954223a99db244c9975fa43b
F www/fileformat.tcl f71a06a0d533c7df408539c64113b4adeaf29764 F www/fileformat.tcl f71a06a0d533c7df408539c64113b4adeaf29764
F www/formatchng.tcl d1dfecedfb25e122ab513a1e0948b15cb4f0be46 F www/formatchng.tcl d1dfecedfb25e122ab513a1e0948b15cb4f0be46
F www/index.tcl 3bf50fdac2f5df49cf4f6f76a7f312b5fd4725b8 F www/index.tcl 3bf50fdac2f5df49cf4f6f76a7f312b5fd4725b8
F www/lang.tcl 604683def6e987db1703faf580d9b2150905fda1 F www/lang.tcl dde78c1415ee2d19fc30360808ca6f0e2ea71c30
F www/lockingv3.tcl afcd22f0f063989cff2f4d57bbc38d719b4c6e75 F www/lockingv3.tcl afcd22f0f063989cff2f4d57bbc38d719b4c6e75
F www/mingw.tcl d96b451568c5d28545fefe0c80bee3431c73f69c F www/mingw.tcl d96b451568c5d28545fefe0c80bee3431c73f69c
F www/nulls.tcl ede975a29def48838c606d4a0c0185d44f90a789 F www/nulls.tcl ede975a29def48838c606d4a0c0185d44f90a789
@@ -249,7 +250,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P 4c817e3f293a9c1365e632f7dc13ae440263332a P e8e972ba65fc36171f6b685e8a8f67f93452e031
R baa88e3ccdeca2bd21538a311420eedc R d2fc50e21e7b6df513c30d8cad94f529
U drh U drh
Z f63cffc592cc58b47f0dd722884db290 Z d7255f319d142e01096c8a1787a44a2e

View File

@@ -1 +1 @@
e8e972ba65fc36171f6b685e8a8f67f93452e031 81ff8107ad63113782cf5a9ba7a512496114ba08

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
** $Id: btree.c,v 1.191 2004/09/27 13:19:52 drh Exp $ ** $Id: btree.c,v 1.192 2004/10/05 02:41:42 drh Exp $
** **
** This file implements a external (disk-based) database using BTrees. ** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to ** For a detailed discussion of BTrees, refer to
@@ -1289,8 +1289,12 @@ static int newDatabase(Btree *pBt){
/* /*
** Attempt to start a new transaction. A write-transaction ** Attempt to start a new transaction. A write-transaction
** is started if the second argument is true, otherwise a read- ** is started if the second argument is nonzero, otherwise a read-
** transaction. ** transaction. If the second argument is 2 or more and exclusive
** transaction is started, meaning that no other process is allowed
** to access the database. A preexisting transaction may not be
** upgrade to exclusive by calling this routine a second time - the
** exclusivity flag only works for a new transaction.
** **
** A write-transaction must be started before attempting any ** A write-transaction must be started before attempting any
** changes to the database. None of the following routines ** changes to the database. None of the following routines
@@ -1329,7 +1333,7 @@ int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){
} }
if( rc==SQLITE_OK && wrflag ){ if( rc==SQLITE_OK && wrflag ){
rc = sqlite3pager_begin(pBt->pPage1->aData); rc = sqlite3pager_begin(pBt->pPage1->aData, wrflag>1);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = newDatabase(pBt); rc = newDatabase(pBt);
} }

View File

@@ -23,7 +23,7 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** PRAGMA
** **
** $Id: build.c,v 1.255 2004/09/30 14:22:47 drh Exp $ ** $Id: build.c,v 1.256 2004/10/05 02:41:42 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -1376,8 +1376,6 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0, sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0,
sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC); sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC);
sqlite3EndWriteOperation(pParse);
} }
/* Add the table to the in-memory representation of the database. /* Add the table to the in-memory representation of the database.
@@ -1663,7 +1661,6 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
} }
} }
sqlite3VdbeOp3(v, OP_DropTable, pTab->iDb, 0, pTab->zName, 0); sqlite3VdbeOp3(v, OP_DropTable, pTab->iDb, 0, pTab->zName, 0);
sqlite3EndWriteOperation(pParse);
} }
sqliteViewResetAll(db, iDb); sqliteViewResetAll(db, iDb);
@@ -2131,7 +2128,6 @@ void sqlite3CreateIndex(
sqlite3VdbeAddOp(v, OP_Close, 1, 0); sqlite3VdbeAddOp(v, OP_Close, 1, 0);
sqlite3ChangeCookie(db, v, iDb); sqlite3ChangeCookie(db, v, iDb);
sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3EndWriteOperation(pParse);
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC); sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC);
} }
@@ -2232,7 +2228,6 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){
sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb); sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
sqlite3VdbeOp3(v, OP_DropIndex, pIndex->iDb, 0, pIndex->zName, 0); sqlite3VdbeOp3(v, OP_DropIndex, pIndex->iDb, 0, pIndex->zName, 0);
sqlite3EndWriteOperation(pParse);
} }
exit_drop_index: exit_drop_index:
@@ -2398,9 +2393,10 @@ void sqlite3SrcListDelete(SrcList *pList){
/* /*
** Begin a transaction ** Begin a transaction
*/ */
void sqlite3BeginTransaction(Parse *pParse){ void sqlite3BeginTransaction(Parse *pParse, int type){
sqlite3 *db; sqlite3 *db;
Vdbe *v; Vdbe *v;
int i;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
if( pParse->nErr || sqlite3_malloc_failed ) return; if( pParse->nErr || sqlite3_malloc_failed ) return;
@@ -2408,6 +2404,11 @@ void sqlite3BeginTransaction(Parse *pParse){
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
if( !v ) return; if( !v ) return;
if( type!=TK_DEFERRED ){
for(i=0; i<db->nDb; i++){
sqlite3VdbeAddOp(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
}
}
sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0); sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0);
} }
@@ -2551,21 +2552,6 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
} }
} }
/*
** Generate code that concludes an operation that may have changed
** the database. If a statement transaction was started, then emit
** an OP_Commit that will cause the changes to be committed to disk.
**
** Note that checkpoints are automatically committed at the end of
** a statement. Note also that there can be multiple calls to
** sqlite3BeginWriteOperation() but there should only be a single
** call to sqlite3EndWriteOperation() at the conclusion of the statement.
*/
void sqlite3EndWriteOperation(Parse *pParse){
/* Delete me! */
return;
}
/* /*
** Return the transient sqlite3_value object used for encoding conversions ** Return the transient sqlite3_value object used for encoding conversions
** during SQL compilation. ** during SQL compilation.

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements. ** to handle DELETE FROM statements.
** **
** $Id: delete.c,v 1.81 2004/09/19 02:15:25 drh Exp $ ** $Id: delete.c,v 1.82 2004/10/05 02:41:42 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -307,7 +307,6 @@ void sqlite3DeleteFrom(
sqlite3VdbeAddOp(v, OP_Close, iCur, 0); sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
} }
} }
sqlite3EndWriteOperation(pParse);
/* /*
** Return the number of rows that were deleted. ** Return the number of rows that were deleted.

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite. ** to handle INSERT statements in SQLite.
** **
** $Id: insert.c,v 1.118 2004/09/19 02:15:26 drh Exp $ ** $Id: insert.c,v 1.119 2004/10/05 02:41:42 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -616,8 +616,6 @@ void sqlite3Insert(
} }
} }
sqlite3EndWriteOperation(pParse);
/* /*
** Return the number of rows inserted. ** Return the number of rows inserted.
*/ */

View File

@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while ** file simultaneously, or one process from reading the database while
** another is writing. ** another is writing.
** **
** @(#) $Id: pager.c,v 1.166 2004/10/02 20:38:28 drh Exp $ ** @(#) $Id: pager.c,v 1.167 2004/10/05 02:41:43 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -88,11 +88,27 @@
** or sqlite_pager_commit(), the state goes back to PAGER_SHARED. ** or sqlite_pager_commit(), the state goes back to PAGER_SHARED.
*/ */
#define PAGER_UNLOCK 0 #define PAGER_UNLOCK 0
#define PAGER_SHARED 1 #define PAGER_SHARED 1 /* same as SHARED_LOCK */
#define PAGER_RESERVED 2 #define PAGER_RESERVED 2 /* same as RESERVED_LOCK */
#define PAGER_EXCLUSIVE 3 #define PAGER_EXCLUSIVE 4 /* same as EXCLUSIVE_LOCK */
#define PAGER_SYNCED 4 #define PAGER_SYNCED 5
/*
** If the SQLITE_BUSY_RESERVED_LOCK macro is set to true at compile-time,
** then failed attempts to get a reserved lock will invoke the busy callback.
** This is off by default. To see why, consider the following scenario:
**
** Suppose thread A already has a shared lock and wants a reserved lock.
** Thread B already has a reserved lock and wants an exclusive lock. If
** both threads are using their busy callbacks, it might be a long time
** be for one of the threads give up and allows the other to proceed.
** But if the thread trying to get the reserved lock gives up quickly
** (if it never invokes its busy callback) then the contention will be
** resolved quickly.
*/
#ifndef SQLITE_BUSY_RESERVED_LOCK
# define SQLITE_BUSY_RESERVED_LOCK 0
#endif
/* /*
** Each in-memory image of a page begins with the following header. ** Each in-memory image of a page begins with the following header.
@@ -1907,6 +1923,37 @@ static int syncJournal(Pager *pPager){
return rc; return rc;
} }
/*
** Try to obtain a lock on a file. Invoke the busy callback if the lock
** is currently not available. Repeate until the busy callback returns
** false or until the lock succeeds.
**
** Return SQLITE_OK on success and an error code if we cannot obtain
** the lock.
*/
static int pager_wait_on_lock(Pager *pPager, int locktype){
int rc;
assert( PAGER_SHARED==SHARED_LOCK );
assert( PAGER_RESERVED==RESERVED_LOCK );
assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK );
if( pPager->state>=locktype ){
rc = SQLITE_OK;
}else{
int busy = 1;
do {
rc = sqlite3OsLock(&pPager->fd, locktype);
}while( rc==SQLITE_BUSY &&
pPager->pBusyHandler &&
pPager->pBusyHandler->xFunc &&
pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
);
if( rc==SQLITE_OK ){
pPager->state = locktype;
}
}
return rc;
}
/* /*
** Given a list of pages (connected by the PgHdr.pDirty pointer) write ** Given a list of pages (connected by the PgHdr.pDirty pointer) write
** every one of those pages out to the database file and mark them all ** every one of those pages out to the database file and mark them all
@@ -1915,7 +1962,6 @@ static int syncJournal(Pager *pPager){
static int pager_write_pagelist(PgHdr *pList){ static int pager_write_pagelist(PgHdr *pList){
Pager *pPager; Pager *pPager;
int rc; int rc;
int busy = 1;
if( pList==0 ) return SQLITE_OK; if( pList==0 ) return SQLITE_OK;
pPager = pList->pPager; pPager = pList->pPager;
@@ -1936,17 +1982,10 @@ static int pager_write_pagelist(PgHdr *pList){
** EXCLUSIVE, it means the database file has been changed and any rollback ** EXCLUSIVE, it means the database file has been changed and any rollback
** will require a journal playback. ** will require a journal playback.
*/ */
do { rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK);
}while( rc==SQLITE_BUSY &&
pPager->pBusyHandler &&
pPager->pBusyHandler->xFunc &&
pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
pPager->state = PAGER_EXCLUSIVE;
while( pList ){ while( pList ){
assert( pList->dirty ); assert( pList->dirty );
@@ -2019,18 +2058,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
** on the database file. ** on the database file.
*/ */
if( pPager->nRef==0 && !pPager->memDb ){ if( pPager->nRef==0 && !pPager->memDb ){
int busy = 1; rc = pager_wait_on_lock(pPager, SHARED_LOCK);
do {
rc = sqlite3OsLock(&pPager->fd, SHARED_LOCK);
}while( rc==SQLITE_BUSY &&
pPager->pBusyHandler &&
pPager->pBusyHandler->xFunc &&
pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
pPager->state = PAGER_SHARED;
/* If a journal file exists, and there is no RESERVED lock on the /* If a journal file exists, and there is no RESERVED lock on the
** database file, then it either needs to be played back or deleted. ** database file, then it either needs to be played back or deleted.
@@ -2408,8 +2439,12 @@ failed_to_open_journal:
** actual need to write to the journal. ** actual need to write to the journal.
** **
** If the database is already reserved for writing, this routine is a no-op. ** If the database is already reserved for writing, this routine is a no-op.
**
** If exFlag is true, go ahead and get an EXCLUSIVE lock on the file
** immediately instead of waiting until we try to flush the cache. The
** exFlag is ignored if a transaction is already active.
*/ */
int sqlite3pager_begin(void *pData){ int sqlite3pager_begin(void *pData, int exFlag){
PgHdr *pPg = DATA_TO_PGHDR(pData); PgHdr *pPg = DATA_TO_PGHDR(pData);
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
int rc = SQLITE_OK; int rc = SQLITE_OK;
@@ -2421,29 +2456,20 @@ int sqlite3pager_begin(void *pData){
pPager->state = PAGER_EXCLUSIVE; pPager->state = PAGER_EXCLUSIVE;
pPager->origDbSize = pPager->dbSize; pPager->origDbSize = pPager->dbSize;
}else{ }else{
#ifdef SQLITE_BUSY_RESERVED_LOCK if( SQLITE_BUSY_RESERVED_LOCK || exFlag ){
int busy = 1; rc = pager_wait_on_lock(pPager, RESERVED_LOCK);
do { }else{
rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK); rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
}while( rc==SQLITE_BUSY && }
pPager->pBusyHandler && if( rc==SQLITE_OK ){
pPager->pBusyHandler->xFunc && pPager->state = PAGER_RESERVED;
pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++) if( exFlag ){
); rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
#else }
rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK); }
#endif
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
/* We do not call the busy handler when we fail to get a reserved lock.
** The only reason we might fail is because another process is holding
** the reserved lock. But the other process will not be able to
** release its reserved lock until this process releases its shared
** lock. So we might as well fail in this process, let it release
** its shared lock so that the other process can commit.
*/
return rc; return rc;
} }
pPager->state = PAGER_RESERVED;
pPager->dirtyCache = 0; pPager->dirtyCache = 0;
TRACE2("TRANSACTION %d\n", pPager->fd.h); TRACE2("TRANSACTION %d\n", pPager->fd.h);
if( pPager->useJournal && !pPager->tempFile ){ if( pPager->useJournal && !pPager->tempFile ){
@@ -2504,7 +2530,7 @@ int sqlite3pager_write(void *pData){
** create it if it does not. ** create it if it does not.
*/ */
assert( pPager->state!=PAGER_UNLOCK ); assert( pPager->state!=PAGER_UNLOCK );
rc = sqlite3pager_begin(pData); rc = sqlite3pager_begin(pData, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }

View File

@@ -13,7 +13,7 @@
** subsystem. The page cache subsystem reads and writes a file a page ** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback. ** at a time and provides a journal for rollback.
** **
** @(#) $Id: pager.h,v 1.37 2004/07/22 01:19:35 drh Exp $ ** @(#) $Id: pager.h,v 1.38 2004/10/05 02:41:43 drh Exp $
*/ */
/* /*
@@ -74,7 +74,7 @@ int sqlite3pager_iswriteable(void*);
int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*); int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*);
int sqlite3pager_pagecount(Pager*); int sqlite3pager_pagecount(Pager*);
int sqlite3pager_truncate(Pager*,Pgno); int sqlite3pager_truncate(Pager*,Pgno);
int sqlite3pager_begin(void*); int sqlite3pager_begin(void*, int exFlag);
int sqlite3pager_commit(Pager*); int sqlite3pager_commit(Pager*);
int sqlite3pager_sync(Pager*,const char *zMaster); int sqlite3pager_sync(Pager*,const char *zMaster);
int sqlite3pager_rollback(Pager*); int sqlite3pager_rollback(Pager*);

View File

@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing ** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens. ** numeric codes for all of the tokens.
** **
** @(#) $Id: parse.y,v 1.141 2004/10/04 13:38:09 drh Exp $ ** @(#) $Id: parse.y,v 1.142 2004/10/05 02:41:43 drh Exp $
*/ */
%token_prefix TK_ %token_prefix TK_
%token_type {Token} %token_type {Token}
@@ -81,10 +81,15 @@ explain ::= . { sqlite3BeginParse(pParse, 0); }
///////////////////// Begin and end transactions. //////////////////////////// ///////////////////// Begin and end transactions. ////////////////////////////
// //
cmd ::= BEGIN trans_opt. {sqlite3BeginTransaction(pParse);} cmd ::= BEGIN transtype(Y) trans_opt. {sqlite3BeginTransaction(pParse, Y);}
trans_opt ::= . trans_opt ::= .
trans_opt ::= TRANSACTION. trans_opt ::= TRANSACTION.
trans_opt ::= TRANSACTION nm. trans_opt ::= TRANSACTION nm.
%type transtype {int}
transtype(A) ::= . {A = TK_DEFERRED;}
transtype(A) ::= DEFERRED(X). {A = @X;}
transtype(A) ::= IMMEDIATE(X). {A = @X;}
transtype(A) ::= EXCLUSIVE(X). {A = @X;}
cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);} cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);} cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);} cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
@@ -127,7 +132,7 @@ id(A) ::= ID(X). {A = X;}
// //
%fallback ID %fallback ID
ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CONFLICT ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CONFLICT
DATABASE DEFERRED DESC DETACH EACH END EXPLAIN FAIL FOR DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
TEMP TRIGGER VACUUM VIEW. TEMP TRIGGER VACUUM VIEW.

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code used to implement the PRAGMA command. ** This file contains code used to implement the PRAGMA command.
** **
** $Id: pragma.c,v 1.67 2004/09/25 14:39:19 drh Exp $ ** $Id: pragma.c,v 1.68 2004/10/05 02:41:43 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -261,7 +261,6 @@ void sqlite3Pragma(
sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3); sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
sqlite3VdbeAddOp(v, OP_Negative, 0, 0); sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
sqlite3EndWriteOperation(pParse);
pDb->cache_size = size; pDb->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size); sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
} }

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.326 2004/10/04 13:19:24 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.327 2004/10/05 02:41:43 drh Exp $
*/ */
#ifndef _SQLITEINT_H_ #ifndef _SQLITEINT_H_
#define _SQLITEINT_H_ #define _SQLITEINT_H_
@@ -1310,7 +1310,7 @@ Vdbe *sqlite3GetVdbe(Parse*);
void sqlite3Randomness(int, void*); void sqlite3Randomness(int, void*);
void sqlite3RollbackAll(sqlite3*); void sqlite3RollbackAll(sqlite3*);
void sqlite3CodeVerifySchema(Parse*, int); void sqlite3CodeVerifySchema(Parse*, int);
void sqlite3BeginTransaction(Parse*); void sqlite3BeginTransaction(Parse*, int);
void sqlite3CommitTransaction(Parse*); void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*); void sqlite3RollbackTransaction(Parse*);
int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstant(Expr*);
@@ -1323,7 +1323,6 @@ void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int); void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int);
void sqlite3OpenTableAndIndices(Parse*, Table*, int, int); void sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int); void sqlite3BeginWriteOperation(Parse*, int, int);
void sqlite3EndWriteOperation(Parse*);
Expr *sqlite3ExprDup(Expr*); Expr *sqlite3ExprDup(Expr*);
void sqlite3TokenCopy(Token*, Token*); void sqlite3TokenCopy(Token*, Token*);
ExprList *sqlite3ExprListDup(ExprList*); ExprList *sqlite3ExprListDup(ExprList*);

View File

@@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the ** individual tokens and sends those tokens one-by-one over to the
** parser for analysis. ** parser for analysis.
** **
** $Id: tokenize.c,v 1.89 2004/09/25 15:25:26 drh Exp $ ** $Id: tokenize.c,v 1.90 2004/10/05 02:41:43 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -71,6 +71,7 @@ static Keyword aKeywordTable[] = {
{ "EACH", TK_EACH, }, { "EACH", TK_EACH, },
{ "ELSE", TK_ELSE, }, { "ELSE", TK_ELSE, },
{ "EXCEPT", TK_EXCEPT, }, { "EXCEPT", TK_EXCEPT, },
{ "EXCLUSIVE", TK_EXCLUSIVE, },
{ "EXPLAIN", TK_EXPLAIN, }, { "EXPLAIN", TK_EXPLAIN, },
{ "FAIL", TK_FAIL, }, { "FAIL", TK_FAIL, },
{ "FOR", TK_FOR, }, { "FOR", TK_FOR, },

View File

@@ -241,7 +241,6 @@ void sqlite3FinishTrigger(
sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0, sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0,
sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC); sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC);
sqlite3EndWriteOperation(pParse);
} }
if( db->init.busy ){ if( db->init.busy ){

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle UPDATE statements. ** to handle UPDATE statements.
** **
** $Id: update.c,v 1.89 2004/09/19 02:15:26 drh Exp $ ** $Id: update.c,v 1.90 2004/10/05 02:41:43 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -430,8 +430,6 @@ void sqlite3Update(
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0); sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
} }
sqlite3EndWriteOperation(pParse);
/* /*
** Return the number of rows that were changed. ** Return the number of rows that were changed.
*/ */

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** commenting and indentation practices when changing or adding code.
** **
** $Id: vdbe.c,v 1.416 2004/10/04 13:19:24 drh Exp $ ** $Id: vdbe.c,v 1.417 2004/10/05 02:41:43 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -2157,7 +2157,8 @@ case OP_AutoCommit: {
** other process can start another write transaction while this transaction is ** other process can start another write transaction while this transaction is
** underway. Starting a write transaction also creates a rollback journal. A ** underway. Starting a write transaction also creates a rollback journal. A
** write transaction must be started before any changes can be made to the ** write transaction must be started before any changes can be made to the
** database. ** database. If P2 is 2 or greater then an EXCLUSIVE lock is also obtained
** on the file.
** **
** If P2 is zero, then a read-lock is obtained on the database file. ** If P2 is zero, then a read-lock is obtained on the database file.
*/ */

78
test/lock3.test Normal file
View File

@@ -0,0 +1,78 @@
# 2001 September 15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this script is database locks and the operation of the
# DEFERRED, IMMEDIATE, and EXCLUSIVE keywords as modifiers to the
# BEGIN command.
#
# $Id: lock3.test,v 1.1 2004/10/05 02:41:43 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Establish two connections to the same database. Put some
# sample data into the database.
#
do_test lock3-1.1 {
sqlite3 db2 test.db
execsql {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1);
}
execsql {
SELECT * FROM t1
} db2
} 1
# Get a deferred lock on the database using one connection. The
# other connection should still be able to write.
#
do_test lock3-2.1 {
execsql {BEGIN DEFERRED TRANSACTION}
execsql {INSERT INTO t1 VALUES(2)} db2
execsql {END TRANSACTION}
execsql {SELECT * FROM t1}
} {1 2}
# Get an immediate lock on the database using one connection. The
# other connection should be able to read the database but not write
# it.
#
do_test lock3-3.1 {
execsql {BEGIN IMMEDIATE TRANSACTION}
catchsql {SELECT * FROM t1} db2
} {0 {1 2}}
do_test lock3-3.2 {
catchsql {INSERT INTO t1 VALUES(3)} db2
} {1 {database is locked}}
do_test lock3-3.3 {
execsql {END TRANSACTION}
} {}
# Get an exclusive lock on the database using one connection. The
# other connection should be unable to read or write the database.
#
do_test lock3-4.1 {
execsql {BEGIN EXCLUSIVE TRANSACTION}
catchsql {SELECT * FROM t1} db2
} {1 {database is locked}}
do_test lock3-4.2 {
catchsql {INSERT INTO t1 VALUES(3)} db2
} {1 {database is locked}}
do_test lock3-4.3 {
execsql {END TRANSACTION}
} {}
catch {db2 close}
finish_test

View File

@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is page cache subsystem. # focus of this script is page cache subsystem.
# #
# $Id: pager2.test,v 1.3 2004/09/08 20:13:06 drh Exp $ # $Id: pager2.test,v 1.4 2004/10/05 02:41:43 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
@@ -122,7 +122,7 @@ do_test pager2-2.14 {
} {0 {}} } {0 {}}
do_test pager2-2.15 { do_test pager2-2.15 {
pager_stats $::p1 pager_stats $::p1
} {ref 1 page 1 max 10 size 1 state 3 err 0 hit 1 miss 1 ovfl 0} } {ref 1 page 1 max 10 size 1 state 4 err 0 hit 1 miss 1 ovfl 0}
do_test pager2-2.16 { do_test pager2-2.16 {
page_read $::g1 page_read $::g1
} {Page-One} } {Page-One}
@@ -295,7 +295,7 @@ for {set i 1} {$i<20} {incr i} {
do_test pager2-4.5.$i.1 { do_test pager2-4.5.$i.1 {
page_write $g1 "Page-1 v$i" page_write $g1 "Page-1 v$i"
lrange [pager_stats $p1] 8 9 lrange [pager_stats $p1] 8 9
} {state 3} } {state 4}
do_test pager2-4.5.$i.2 { do_test pager2-4.5.$i.2 {
for {set j 2} {$j<=20} {incr j} { for {set j 2} {$j<=20} {incr j} {
set gx [page_get $p1 $j] set gx [page_get $p1 $j]
@@ -336,7 +336,7 @@ for {set i 1} {$i<20} {incr i} {
do_test pager2-4.5.$i.5 { do_test pager2-4.5.$i.5 {
page_write $g1 "Page-1 v$i" page_write $g1 "Page-1 v$i"
lrange [pager_stats $p1] 8 9 lrange [pager_stats $p1] 8 9
} {state 3} } {state 4}
do_test pager2-4.5.$i.6 { do_test pager2-4.5.$i.6 {
for {set j 2} {$j<=20} {incr j} { for {set j 2} {$j<=20} {incr j} {
set gx [page_get $p1 $j] set gx [page_get $p1 $j]

View File

@@ -1,7 +1,7 @@
# #
# Run this Tcl script to generate the sqlite.html file. # Run this Tcl script to generate the sqlite.html file.
# #
set rcsid {$Id: lang.tcl,v 1.72 2004/09/08 13:06:21 drh Exp $} set rcsid {$Id: lang.tcl,v 1.73 2004/10/05 02:41:43 drh Exp $}
source common.tcl source common.tcl
header {Query Language Understood by SQLite} header {Query Language Understood by SQLite}
puts { puts {
@@ -169,7 +169,7 @@ the main database were ":memory:".
Section {BEGIN TRANSACTION} transaction Section {BEGIN TRANSACTION} transaction
Syntax {sql-statement} { Syntax {sql-statement} {
BEGIN [TRANSACTION [<name>]] BEGIN [ DEFERRED | IMMEDIATE | EXCLUSIVE ] [TRANSACTION [<name>]]
} }
Syntax {sql-statement} { Syntax {sql-statement} {
END [TRANSACTION [<name>]] END [TRANSACTION [<name>]]
@@ -207,6 +207,42 @@ clause for additional information about the ROLLBACK
conflict resolution algorithm. conflict resolution algorithm.
</p> </p>
<p>
In SQLite version 3.0.8 and later, transactions can be deferred,
immediate, or exclusive. Deferred means that no locks are acquired
on the database until the database is first accessed. Thus with a
deferred transaction, the BEGIN statement itself does nothing. Locks
are not acquired until the first read or write operation. The first read
operation against a database creates a SHARED lock and the first
write operation creates a RESERVED lock. Because the acquisition of
locks is deferred until they are needed, it is possible that another
thread or process could create a separate transaction and write to
the database after the BEGIN on the current thread has executed.
If the transation is immediate, then RESERVED locks
are acquired on all databases as soon as the BEGIN command is
executed, without waiting for the
database to be used. After a BEGIN IMMEDIATE, you are guaranteed that
no other thread or process will be able to write to the database or
do a BEGIN IMMEDIATE or BEGIN EXCLUSIVE. Other processes can continue
to read from the database, however. An exclusive transaction causes
EXCLUSIVE locks to be acquired on all databases. After a BEGIN
EXCLUSIVE, you are guaranteed that no other thread or process will
be able to read or write the database until the transaction is
complete.
</p>
<p>
A description of the meaning of SHARED, RESERVED, and EXCLUSIVE locks
is available <a href="lockingv3.html">separately</a>.
</p>
<p>
The default behavior for SQLite version 3.0.8 is a
deferred transaction. For SQLite version 3.0.0 through 3.0.7,
deferred is the only kind of transaction available. For SQLite
version 2.8 and earlier, all transactions are exclusive.
</p>
<p> <p>
The COMMIT command does not actually perform a commit until all The COMMIT command does not actually perform a commit until all
pending SQL commands finish. Thus if two or more SELECT statements pending SQL commands finish. Thus if two or more SELECT statements