-C More\schanges\sto\stake\sadvantage\sof\sthe\sTK_\sand\sOP_\salignments\sto\savoid\nunnecessary\stranslations.\s(CVS\s1999)
-D 2004-10-04T13:38:09
+C Add\ssupport\sfor\sDEFERRED,\sIMMEDIATE,\sand\sEXCLUSIVE\stransactions.\s(CVS\s2000)
+D 2004-10-05T02:41:42
F Makefile.in 78ddc9fca09ab6e3b75a79ecf8d490e34cd0519c
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
-F src/btree.c 014d3c9d31136050f3b3294c0c5dc0c7615557bf
+F src/btree.c bb3f8cadf65cc0752d07e219733a496c1aebe020
F src/btree.h 94dfec0a1722d33359b23e7e310f2b64ffedf029
-F src/build.c 2ed6d9c26ad736142012bc99898869db17337121
+F src/build.c 73bd4219c1cb6fb09a05b7d4a6ed3ae1d0ecb8db
F src/date.c 93927e2d1ffbd833fc220644896cfdc8f8d4af34
-F src/delete.c d862b383a9abc0b79f4588783c2619fe52d74ea7
+F src/delete.c 7a9543ed784bd51ded17c805ff6a4fe864c1676c
F src/expr.c 2f492bf532d700bd2c38e16caa49048535e8ed27
F src/func.c 1fbc5256639586573fd0e70814d6dcd8bc10afc1
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
-F src/insert.c 2c10c001f62cde92e9517ec7516b6584519754d1
+F src/insert.c 7e8ce8834c3716a313694e5340dbf28ff828677a
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
F src/main.c 2a1b9623fde3fe5e22fe726cdae4e10f33671caa
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13
F src/os_win.c 9482dfc92f289b68205bb2c9315757c7e3946bfb
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c d3688828d314135ef0cd87b4d892805136c4168f
-F src/pager.h 67739fe649f33be55dba522ca8a9cc4e42d14f71
-F src/parse.y 3616bdde17fd9be9c235e40cd732a831a3e8fa61
-F src/pragma.c 45978cc82fdf91f00d024a8e875c2b679fbce488
+F src/pager.c dc0ffab9941393b072e0b1f1f3de54830727cec9
+F src/pager.h 774d1973acbda341827d21b0da0150575d69f7d9
+F src/parse.y e03d7d7f712ad2b5be61e9a024820c0a8ffdf36d
+F src/pragma.c ba7fdd19c1680bb9bfc8bc5230278f6ae6b1c8ff
F src/printf.c 40770e1f553612d13dfc86d236086e69baa62fe1
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
F src/select.c 96b1489111abe9b584be2f2cce26ad6f2d425b4e
F src/shell.c 0856973c2b94e22664bc43f398ba3fc22d5e080c
F src/sqlite.h.in 9bb76ff9e79ee72e6d529ff6ab1c252d513c3864
-F src/sqliteInt.h bfb12f1da75b2a8f5c88c9c3050343571def65b9
+F src/sqliteInt.h 610f25a92c0ce5edf40d12087c643c310e1d7d05
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
F src/tclsqlite.c 0302e3f42f015d132d1291f3388c06e86c24a008
F src/test1.c 3d78e5d827bf5d037f697c233c5934d45af46cb5
F src/test3.c 5b5b0f3d11b097399c1054fff73d8f3711092301
F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1
-F src/tokenize.c d4619367d9ba17c6bd4e018fb7e91015ae8562aa
-F src/trigger.c d1f770ee37a80391dd6d0948ee821b0272f99ae7
-F src/update.c 7157084216c4b02a23cdb23eb6d246aa9034fa4d
+F src/tokenize.c 449843c85c8118b9718f3935f4b5d18586c8cee2
+F src/trigger.c b983f8d763d2c253535947e543c3386dc1117ca1
+F src/update.c 174c3b593b8f4928e510a51ec309e8ce69d2371c
F src/utf.c f4f83acd73389090e32d6589d307fc55d794c7ed
F src/util.c f4ab796b9def353feed2191d7ce8e39a0f5059cd
F src/vacuum.c 257de36230cb988842f66eb08dc6c0250b8e05f3
-F src/vdbe.c 49d4bda66884b1017e11962c7fb7eaf15b436be8
+F src/vdbe.c f7ebf1a20a5fdca27e80cb96e06e988da2426379
F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181
F src/vdbeInt.h 6017100adff362b8dfa37a69e3f1431f084bfa5b
F src/vdbeapi.c 81ab9e84c55f5762f552904e6e5d309269b02017
F test/limit.test f7c06fccd76755e8d083b61c06bc31cf461b9c35
F test/lock.test 7cb9395919a0986ee4dd08bd49d34df93c8fc4fe
F test/lock2.test 2213590d442147d09fd2334c905a755586c1c398
+F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9
F test/main.test 1430a4b5bd3a6d5e0294966b742d80a551f87211
F test/malloc.test 769b240d89a7ef3320d88919fdb6765f9395a51f
F test/memdb.test b8a13fa79f006bd087bbcf135ce8eb62056a6027
F test/notnull.test 7a08117a71e74b0321aaa937dbeb41a09d6eb1d0
F test/null.test 642428b6a5408cc5b954b49e1b6e5025e4458b2b
F test/pager.test 394455707a079804e8a4e431d12edce831a065f0
-F test/pager2.test 2b505eca6bf214dfff412cf615678a835c83ca74
+F test/pager2.test c7e731ac56a2984a605b032ffd19b9deee820377
F test/pager3.test 16f546293bb751b8151dc17df613fca938bbec8b
F test/pagesize.test f8b46ec46b9fe9f708a8d757dda232588dfb7217
F test/pragma.test 66a66b7f3b273b93325c9a5794acb418f52fdcbf
F www/fileformat.tcl f71a06a0d533c7df408539c64113b4adeaf29764
F www/formatchng.tcl d1dfecedfb25e122ab513a1e0948b15cb4f0be46
F www/index.tcl 3bf50fdac2f5df49cf4f6f76a7f312b5fd4725b8
-F www/lang.tcl 604683def6e987db1703faf580d9b2150905fda1
+F www/lang.tcl dde78c1415ee2d19fc30360808ca6f0e2ea71c30
F www/lockingv3.tcl afcd22f0f063989cff2f4d57bbc38d719b4c6e75
F www/mingw.tcl d96b451568c5d28545fefe0c80bee3431c73f69c
F www/nulls.tcl ede975a29def48838c606d4a0c0185d44f90a789
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 4c817e3f293a9c1365e632f7dc13ae440263332a
-R baa88e3ccdeca2bd21538a311420eedc
+P e8e972ba65fc36171f6b685e8a8f67f93452e031
+R d2fc50e21e7b6df513c30d8cad94f529
U drh
-Z f63cffc592cc58b47f0dd722884db290
+Z d7255f319d142e01096c8a1787a44a2e
-e8e972ba65fc36171f6b685e8a8f67f93452e031
\ No newline at end of file
+81ff8107ad63113782cf5a9ba7a512496114ba08
\ No newline at end of file
** 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.
** For a detailed discussion of BTrees, refer to
/*
** Attempt to start a new transaction. A write-transaction
-** is started if the second argument is true, otherwise a read-
-** transaction.
+** is started if the second argument is nonzero, otherwise a read-
+** 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
** changes to the database. None of the following routines
}
if( rc==SQLITE_OK && wrflag ){
- rc = sqlite3pager_begin(pBt->pPage1->aData);
+ rc = sqlite3pager_begin(pBt->pPage1->aData, wrflag>1);
if( rc==SQLITE_OK ){
rc = newDatabase(pBt);
}
** ROLLBACK
** 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 <ctype.h>
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0,
sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC);
-
- sqlite3EndWriteOperation(pParse);
}
/* Add the table to the in-memory representation of the database.
}
}
sqlite3VdbeOp3(v, OP_DropTable, pTab->iDb, 0, pTab->zName, 0);
- sqlite3EndWriteOperation(pParse);
}
sqliteViewResetAll(db, iDb);
sqlite3VdbeAddOp(v, OP_Close, 1, 0);
sqlite3ChangeCookie(db, v, iDb);
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3EndWriteOperation(pParse);
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC);
}
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
sqlite3VdbeOp3(v, OP_DropIndex, pIndex->iDb, 0, pIndex->zName, 0);
- sqlite3EndWriteOperation(pParse);
}
exit_drop_index:
/*
** Begin a transaction
*/
-void sqlite3BeginTransaction(Parse *pParse){
+void sqlite3BeginTransaction(Parse *pParse, int type){
sqlite3 *db;
Vdbe *v;
+ int i;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
if( pParse->nErr || sqlite3_malloc_failed ) return;
v = sqlite3GetVdbe(pParse);
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);
}
}
}
-/*
-** 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
** during SQL compilation.
** This file contains C code routines that are called by the parser
** 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"
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
}
- sqlite3EndWriteOperation(pParse);
/*
** Return the number of rows that were deleted.
** This file contains C code routines that are called by the parser
** 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"
}
}
- sqlite3EndWriteOperation(pParse);
-
/*
** Return the number of rows inserted.
*/
** file simultaneously, or one process from reading the database while
** 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 "os.h"
** or sqlite_pager_commit(), the state goes back to PAGER_SHARED.
*/
#define PAGER_UNLOCK 0
-#define PAGER_SHARED 1
-#define PAGER_RESERVED 2
-#define PAGER_EXCLUSIVE 3
-#define PAGER_SYNCED 4
+#define PAGER_SHARED 1 /* same as SHARED_LOCK */
+#define PAGER_RESERVED 2 /* same as RESERVED_LOCK */
+#define PAGER_EXCLUSIVE 4 /* same as EXCLUSIVE_LOCK */
+#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.
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
** every one of those pages out to the database file and mark them all
static int pager_write_pagelist(PgHdr *pList){
Pager *pPager;
int rc;
- int busy = 1;
if( pList==0 ) return SQLITE_OK;
pPager = pList->pPager;
** EXCLUSIVE, it means the database file has been changed and any rollback
** will require a journal playback.
*/
- do {
- rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK);
- }while( rc==SQLITE_BUSY &&
- pPager->pBusyHandler &&
- pPager->pBusyHandler->xFunc &&
- pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
- );
+ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
return rc;
}
- pPager->state = PAGER_EXCLUSIVE;
while( pList ){
assert( pList->dirty );
** on the database file.
*/
if( pPager->nRef==0 && !pPager->memDb ){
- int busy = 1;
- do {
- rc = sqlite3OsLock(&pPager->fd, SHARED_LOCK);
- }while( rc==SQLITE_BUSY &&
- pPager->pBusyHandler &&
- pPager->pBusyHandler->xFunc &&
- pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
- );
+ rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
return rc;
}
- pPager->state = PAGER_SHARED;
/* 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.
** actual need to write to the journal.
**
** 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);
Pager *pPager = pPg->pPager;
int rc = SQLITE_OK;
pPager->state = PAGER_EXCLUSIVE;
pPager->origDbSize = pPager->dbSize;
}else{
-#ifdef SQLITE_BUSY_RESERVED_LOCK
- int busy = 1;
- do {
+ if( SQLITE_BUSY_RESERVED_LOCK || exFlag ){
+ rc = pager_wait_on_lock(pPager, RESERVED_LOCK);
+ }else{
rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
- }while( rc==SQLITE_BUSY &&
- pPager->pBusyHandler &&
- pPager->pBusyHandler->xFunc &&
- pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
- );
-#else
- rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
-#endif
+ }
+ if( rc==SQLITE_OK ){
+ pPager->state = PAGER_RESERVED;
+ if( exFlag ){
+ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+ }
+ }
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;
}
- pPager->state = PAGER_RESERVED;
pPager->dirtyCache = 0;
TRACE2("TRANSACTION %d\n", pPager->fd.h);
if( pPager->useJournal && !pPager->tempFile ){
** create it if it does not.
*/
assert( pPager->state!=PAGER_UNLOCK );
- rc = sqlite3pager_begin(pData);
+ rc = sqlite3pager_begin(pData, 0);
if( rc!=SQLITE_OK ){
return rc;
}
** subsystem. The page cache subsystem reads and writes a file a page
** 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 $
*/
/*
int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*);
int sqlite3pager_pagecount(Pager*);
int sqlite3pager_truncate(Pager*,Pgno);
-int sqlite3pager_begin(void*);
+int sqlite3pager_begin(void*, int exFlag);
int sqlite3pager_commit(Pager*);
int sqlite3pager_sync(Pager*,const char *zMaster);
int sqlite3pager_rollback(Pager*);
** the parser. Lemon will also generate a header file containing
** 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_type {Token}
///////////////////// Begin and end transactions. ////////////////////////////
//
-cmd ::= BEGIN trans_opt. {sqlite3BeginTransaction(pParse);}
+cmd ::= BEGIN transtype(Y) trans_opt. {sqlite3BeginTransaction(pParse, Y);}
trans_opt ::= .
trans_opt ::= TRANSACTION.
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 ::= END trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
//
%fallback ID
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
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
TEMP TRIGGER VACUUM VIEW.
*************************************************************************
** 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 <ctype.h>
sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
- sqlite3EndWriteOperation(pParse);
pDb->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
}
*************************************************************************
** 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_
#define _SQLITEINT_H_
void sqlite3Randomness(int, void*);
void sqlite3RollbackAll(sqlite3*);
void sqlite3CodeVerifySchema(Parse*, int);
-void sqlite3BeginTransaction(Parse*);
+void sqlite3BeginTransaction(Parse*, int);
void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*);
int sqlite3ExprIsConstant(Expr*);
void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int);
void sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int);
-void sqlite3EndWriteOperation(Parse*);
Expr *sqlite3ExprDup(Expr*);
void sqlite3TokenCopy(Token*, Token*);
ExprList *sqlite3ExprListDup(ExprList*);
** individual tokens and sends those tokens one-by-one over to the
** 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 "os.h"
{ "EACH", TK_EACH, },
{ "ELSE", TK_ELSE, },
{ "EXCEPT", TK_EXCEPT, },
+ { "EXCLUSIVE", TK_EXCLUSIVE, },
{ "EXPLAIN", TK_EXPLAIN, },
{ "FAIL", TK_FAIL, },
{ "FOR", TK_FOR, },
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0,
sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC);
- sqlite3EndWriteOperation(pParse);
}
if( db->init.busy ){
** This file contains C code routines that are called by the parser
** 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"
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
}
- sqlite3EndWriteOperation(pParse);
-
/*
** Return the number of rows that were changed.
*/
** in this file for details. If in doubt, do not deviate from existing
** 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 "os.h"
** other process can start another write transaction while this transaction is
** underway. Starting a write transaction also creates a rollback journal. A
** 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.
*/
--- /dev/null
+# 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
# This file implements regression tests for SQLite library. The
# 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]
} {0 {}}
do_test pager2-2.15 {
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 {
page_read $::g1
} {Page-One}
do_test pager2-4.5.$i.1 {
page_write $g1 "Page-1 v$i"
lrange [pager_stats $p1] 8 9
- } {state 3}
+ } {state 4}
do_test pager2-4.5.$i.2 {
for {set j 2} {$j<=20} {incr j} {
set gx [page_get $p1 $j]
do_test pager2-4.5.$i.5 {
page_write $g1 "Page-1 v$i"
lrange [pager_stats $p1] 8 9
- } {state 3}
+ } {state 4}
do_test pager2-4.5.$i.6 {
for {set j 2} {$j<=20} {incr j} {
set gx [page_get $p1 $j]
#
# 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
header {Query Language Understood by SQLite}
puts {
Section {BEGIN TRANSACTION} transaction
Syntax {sql-statement} {
-BEGIN [TRANSACTION [<name>]]
+BEGIN [ DEFERRED | IMMEDIATE | EXCLUSIVE ] [TRANSACTION [<name>]]
}
Syntax {sql-statement} {
END [TRANSACTION [<name>]]
conflict resolution algorithm.
</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>
The COMMIT command does not actually perform a commit until all
pending SQL commands finish. Thus if two or more SELECT statements