Changes for exclusive access mode. There are still some bugs. (CVS 3712)

FossilOrigin-Name: b6c700370be29db2b974f9abd719c3e56abf8058
This commit is contained in:
danielk1977 2007-03-24 16:45:04 +00:00
parent e277be0545
commit 414834686c
9 changed files with 489 additions and 56 deletions

View File

@ -1,5 +1,5 @@
C Discard\sthe\scontents\sof\sthe\spager-cache\sonly\swhen\sthe\schange-counter\sindicates\sthat\sit\sis\sstale.\s(CVS\s3711)
D 2007-03-23T18:12:07
C Changes\sfor\sexclusive\saccess\smode.\sThere\sare\sstill\ssome\sbugs.\s(CVS\s3712)
D 2007-03-24T16:45:05
F Makefile.in 1fe3d0b46e40fd684e1e61f8e8056cefed16de9f
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -56,7 +56,7 @@ F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a
F src/attach.c fd286a9140a2df84b1482f052b67ff5fad9569a1
F src/attach.c 9b5a9c50fb92883e3404353b225674142da826cd
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
F src/btree.c 4d94251b59fa33c888efc43881729f7d297899a4
F src/btree.h 066444ee25bd6e6accb997bfd2cf5ace14dbcd00
@ -86,10 +86,10 @@ F src/os_unix.c 4642f23ed0c1ae0f1440db1d2b4231348af69360
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
F src/os_win.c 1d1d0989b0f235751504292c2f28e81044be0d70
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c da3c5e90b2c99bdba6129f568102c24cbd438452
F src/pager.h 9f6b5ef42c761deec8a9b1966b32e9a9dc89a631
F src/pager.c 9023042d50d961cfcaad4e9211eea711abb2b7f4
F src/pager.h 3c16500c25051536e43fb19e246e58fc7cb51d9f
F src/parse.y bcfe366c1fd61cfc40e5344eb69a31997a821af0
F src/pragma.c a3fe1dacdbf320ad99d4125a60a5bce8f1808bc8
F src/pragma.c 9cb8b94e7d38ba35a86037bd517d07ba9870b4b2
F src/prepare.c 4e075fe28591b7d4ffbf818fb88a7e19bbe98065
F src/printf.c aade23a789d7cc88b397ec0d33a0a01a33a7a9c1
F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
@ -98,7 +98,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c 3ae4654560e91220a95738a73d135d91d937cda1
F src/sqlite.h.in 6b7383baf76070214f6381f603328ca9b22a7fae
F src/sqlite3ext.h 011c75fd6459a61454514af07c7a4f1f5c767f27
F src/sqliteInt.h 6e3ac7a1a8f51e24ce4784236aa957e9bd11217f
F src/sqliteInt.h 5451308c885e8620e0d4764ae162da2566520073
F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
F src/tclsqlite.c cd2b3b86ab07c0e0779f6c6e71e72c6c7dc1e704
F src/test1.c b4ff8f82f84d2ccdf07a2db5acae7b47c12f60d7
@ -199,6 +199,7 @@ F test/distinctagg.test 2b89d1c5220d966a30ba4b40430338669301188b
F test/enc.test 7a03417a1051fe8bc6c7641cf4c8c3f7e0066d52
F test/enc2.test 45710bacfa9df29720bc84c067dfdf8c8ddfb797
F test/enc3.test 890508efff6677345e93bf2a8adb0489b30df030
F test/exclusive.test 67a1bedd37b92785a0ba3b596401910713653b5e
F test/expr.test c78843f730ccbe973d0c2ad1c99978f936893131
F test/fkey1.test 153004438d51e6769fb1ce165f6313972d6263ce
F test/format4.test bf3bed3b13c63abfb3cfec232597a319a31d0bcc
@ -330,7 +331,7 @@ F test/tkt2192.test 480d0e017ddb01a46ee20809427370f343bb3c03
F test/tkt2213.test 8cf7c446e1fcd0627fffe7fc19046eb24ac7333b
F test/tkt2251.test 3f0549213386ed911715665a908ff2bb7a871002
F test/trace.test 75ffc1b992c780d054748a656e3e7fd674f18567
F test/trans.test 06bff0246886858793fca3748721936e2f65e3df
F test/trans.test f4577bbefe1fb49e6c13f32923a8891250a9d628
F test/trigger1.test 2c79e2bf76350811e362814e98779c120b6a9421
F test/trigger2.test 33bf8ae9b788013be194efe5f66c04a202facbb4
F test/trigger3.test 9102fd3933db294dc654b5aee9edfe9e94f2b9e2
@ -437,7 +438,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
P 0fd9983a98d8d61654f252f1708a4d7232a96b53
R ec284a76fe569250a4f6f20542fb07fe
P 07b56965f3227c9f78680728b955395295c4aa49
R 5306d65289bf66945a0a4cf7185afe17
U danielk1977
Z c13a7ab87a49cb94c1a31349a8579dca
Z 4da3e2ad8e93e75be905d9a01fa04929

View File

@ -1 +1 @@
07b56965f3227c9f78680728b955395295c4aa49
b6c700370be29db2b974f9abd719c3e56abf8058

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.54 2007/03/15 15:35:29 danielk1977 Exp $
** $Id: attach.c,v 1.55 2007/03/24 16:45:05 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -133,6 +133,7 @@ static void attachFunc(
"attached databases must use the same text encoding as main database");
goto attach_error;
}
sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode);
}
aNew->zName = sqliteStrDup(zName);
aNew->safety_level = 3;

View File

@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.293 2007/03/23 18:12:07 danielk1977 Exp $
** @(#) $Id: pager.c,v 1.294 2007/03/24 16:45:05 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
@ -285,8 +285,10 @@ struct Pager {
Pager *pNext; /* Linked list of pagers in this thread */
#endif
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
int doNotSync; /* While true, do not spill the cache */
u32 iChangeCount; /* Db change-counter for which cache is valid */
u8 doNotSync; /* Boolean. While true, do not spill the cache */
u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
u8 changeCountDone; /* Set after incrementing the change-counter */
};
/*
@ -854,12 +856,15 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
** Unlock the database file.
*/
static void pager_unlock(Pager *pPager){
if( !MEMDB ){
sqlite3OsUnlock(pPager->fd, NO_LOCK);
pPager->dbSize = -1;
IOTRACE(("UNLOCK %p\n", pPager))
if( !pPager->exclusiveMode ){
if( !MEMDB ){
sqlite3OsUnlock(pPager->fd, NO_LOCK);
pPager->dbSize = -1;
IOTRACE(("UNLOCK %p\n", pPager))
}
pPager->state = PAGER_UNLOCK;
pPager->changeCountDone = 0;
}
pPager->state = PAGER_UNLOCK;
}
/*
@ -873,7 +878,6 @@ static void pagerUnlockAndRollback(Pager *pPager){
sqlite3PagerRollback(pPager);
}
pager_unlock(pPager);
assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
}
@ -902,28 +906,6 @@ static void pager_reset(Pager *pPager){
pPager->nRef = 0;
}
/*
** This function resets the various pager flags to their initial
** state but does not discard the cached content.
*/
static void pagerSoftReset(Pager *pPager){
PgHdr *pPg;
assert(pPager->pStmt==0);
assert(pPager->nRef==0);
assert(pPager->pFirstSynced==pPager->pFirst);
assert(pPager->aInJournal==0);
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
assert( pPg->nRef==0 );
pPg->inJournal = 0;
pPg->inStmt = 0;
pPg->dirty = 0;
pPg->needSync = 0;
pPg->alwaysRollback = 0;
}
}
/*
** When this routine is called, the pager has the journal file open and
** a RESERVED or EXCLUSIVE lock on the database. This routine releases
@ -936,7 +918,7 @@ static void pagerSoftReset(Pager *pPager){
*/
static int pager_unwritelock(Pager *pPager){
PgHdr *pPg;
int rc;
int rc = SQLITE_OK;
assert( !MEMDB );
if( pPager->state<PAGER_RESERVED ){
return SQLITE_OK;
@ -947,15 +929,22 @@ static int pager_unwritelock(Pager *pPager){
pPager->stmtOpen = 0;
}
if( pPager->journalOpen ){
sqlite3OsClose(&pPager->jfd);
pPager->journalOpen = 0;
sqlite3OsDelete(pPager->zJournal);
if( pPager->exclusiveMode ){
sqlite3OsTruncate(pPager->jfd, 0);
sqlite3OsSeek(pPager->jfd, 0);
pPager->journalOff = 0;
}else{
sqlite3OsClose(&pPager->jfd);
pPager->journalOpen = 0;
sqlite3OsDelete(pPager->zJournal);
}
sqliteFree( pPager->aInJournal );
pPager->aInJournal = 0;
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
pPg->inJournal = 0;
pPg->dirty = 0;
pPg->needSync = 0;
pPg->alwaysRollback = 0;
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
@ -967,9 +956,18 @@ static int pager_unwritelock(Pager *pPager){
assert( pPager->aInJournal==0 );
assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
}
rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
pPager->state = PAGER_SHARED;
pPager->origDbSize = 0;
if( !pPager->exclusiveMode ){
rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
pPager->state = PAGER_SHARED;
pPager->origDbSize = 0;
}else{
sqlite3PagerPagecount(pPager);
pPager->origDbSize = pPager->dbSize;
pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
if( !pPager->aInJournal ){
rc = SQLITE_NOMEM;
}
}
pPager->setMaster = 0;
pPager->needSync = 0;
pPager->pFirstSynced = pPager->pFirst;
@ -1109,6 +1107,11 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
pPg->pageHash = pager_pagehash(pPg);
#endif
CODEC1(pPager, pData, pPg->pgno, 3);
/* If this was page 1, then restore the value of Pager.iChangeCount */
if( pgno==1 ){
pPager->iChangeCount = retrieve32bits(pPg, 24);
}
}
return rc;
}
@ -1199,6 +1202,7 @@ delmaster_out:
return rc;
}
#if 0
/*
** Make every page in the cache agree with what is on disk. In other words,
** reread the disk to reset the state of the cache.
@ -1242,6 +1246,7 @@ static int pager_reload_cache(Pager *pPager){
pPager->pDirty = 0;
return rc;
}
#endif
/*
** Truncate the main file of the given pager to the number of pages
@ -2126,6 +2131,7 @@ int sqlite3PagerClose(Pager *pPager){
disable_simulated_io_errors();
pPager->errCode = 0;
pPager->exclusiveMode = 0;
pager_reset(pPager);
pagerUnlockAndRollback(pPager);
enable_simulated_io_errors();
@ -2734,8 +2740,6 @@ static int pagerSharedLock(Pager *pPager){
pPager->nRef--;
if( iChangeCount!=pPager->iChangeCount ){
pager_reset(pPager);
}else{
pagerSoftReset(pPager);
}
pPager->iChangeCount = iChangeCount;
}
@ -3610,6 +3614,8 @@ int sqlite3PagerRollback(Pager *pPager){
PgHistory *pHist;
assert( !p->alwaysRollback );
if( !p->dirty ){
assert( p->inJournal==0 );
assert( p->inStmt==0 );
assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig );
assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt );
continue;
@ -3890,6 +3896,7 @@ static int pager_incr_changecounter(Pager *pPager){
/* Release the page reference. */
sqlite3PagerUnref(pPgHdr);
pPager->changeCountDone = 1;
return SQLITE_OK;
}
@ -4098,6 +4105,23 @@ void *sqlite3PagerGetExtra(DbPage *pPg){
return (pPager?PGHDR_TO_EXTRA(pPg, pPager):0);
}
/*
** Get/set the locking-mode for this pager. Parameter eMode must be one
** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then
** the locking-mode is set to the value specified.
**
** The returned value is either PAGER_LOCKINGMODE_NORMAL or
** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated)
** locking-mode.
*/
int sqlite3PagerLockingMode(Pager *pPager, int eMode){
if( eMode>=0 ){
pPager->exclusiveMode = eMode;
}
return (int)pPager->exclusiveMode;
}
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Return the current state of the file lock for the given pager.

View File

@ -13,7 +13,7 @@
** 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.54 2007/03/19 17:44:27 danielk1977 Exp $
** @(#) $Id: pager.h,v 1.55 2007/03/24 16:45:05 danielk1977 Exp $
*/
#ifndef _PAGER_H_
@ -69,6 +69,12 @@ typedef struct PgHdr DbPage;
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
/*
** Valid values for the second argument to sqlite3PagerLockingMode().
*/
#define PAGER_LOCKINGMODE_QUERY -1
#define PAGER_LOCKINGMODE_NORMAL 0
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
** See source code comments for a detailed description of the following
@ -119,6 +125,7 @@ int sqlite3PagerReleaseMemory(int);
void *sqlite3PagerGetData(DbPage *);
void *sqlite3PagerGetExtra(DbPage *);
int sqlite3PagerLockingMode(Pager *, int);
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
int sqlite3PagerLockstate(Pager*);

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.129 2007/03/19 17:44:28 danielk1977 Exp $
** $Id: pragma.c,v 1.130 2007/03/24 16:45:05 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -62,6 +62,17 @@ static int getBoolean(const char *z){
return getSafetyLevel(z)&1;
}
/*
** Interpret the given string as a locking mode value.
*/
static int getLockingMode(const char *z){
if( z ){
if( 0==sqlite3StrICmp(z, "exclusive") ) return PAGER_LOCKINGMODE_EXCLUSIVE;
if( 0==sqlite3StrICmp(z, "normal") ) return PAGER_LOCKINGMODE_NORMAL;
}
return PAGER_LOCKINGMODE_QUERY;
}
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Interpret the given string as a temp db location. Return 1 for file
@ -315,6 +326,53 @@ void sqlite3Pragma(
sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1);
}
}else
/*
** PRAGMA [database.]locking_mode
** PRAGMA [database.]locking_mode = (normal|exclusive)
*/
if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){
const char *zRet = "normal";
int eMode = getLockingMode(zRight);
if( pId2->n==0 && eMode==PAGER_LOCKINGMODE_QUERY ){
/* Simple "PRAGMA locking_mode;" statement. This is a query for
** the current default locking mode (which may be different to
** the locking-mode of the main database).
*/
eMode = db->dfltLockMode;
}else{
Pager *pPager;
if( pId2->n==0 ){
/* This indicates that no database name was specified as part
** of the PRAGMA command. In this case the locking-mode must be
** set on all attached databases, as well as the main db file.
**
** Also, the sqlite3.dfltLockMode variable is set so that
** any subsequently attached databases also use the specified
** locking mode.
*/
int ii;
assert(pDb==&db->aDb[0]);
for(ii=2; ii<db->nDb; ii++){
pPager = sqlite3BtreePager(db->aDb[ii].pBt);
sqlite3PagerLockingMode(pPager, eMode);
}
db->dfltLockMode = eMode;
}
pPager = sqlite3BtreePager(pDb->pBt);
eMode = sqlite3PagerLockingMode(pPager, eMode);
}
assert(eMode==PAGER_LOCKINGMODE_NORMAL||eMode==PAGER_LOCKINGMODE_EXCLUSIVE);
if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
zRet = "exclusive";
}
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P3_STATIC);
sqlite3VdbeOp3(v, OP_String8, 0, 0, zRet, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
}else
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
/*

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.542 2007/03/14 15:37:04 danielk1977 Exp $
** @(#) $Id: sqliteInt.h,v 1.543 2007/03/24 16:45:05 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -510,6 +510,7 @@ struct sqlite3 {
#ifdef SQLITE_SSE
sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */
#endif
u8 dfltLockMode; /* Default locking-mode for attached dbs */
};
/*

340
test/exclusive.test Normal file
View File

@ -0,0 +1,340 @@
# 2007 March 24
#
# 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.
#
# $Id: exclusive.test,v 1.1 2007/03/24 16:45:05 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!pager_pragmas} {
finish_test
return
}
file delete -force test2.db-journal
file delete -force test2.db
file delete -force test3.db-journal
file delete -force test3.db
file delete -force test4.db-journal
file delete -force test4.db
#----------------------------------------------------------------------
# Test cases exclusive-1.X test the PRAGMA logic.
#
do_test exclusive-1.0 {
execsql {
pragma locking_mode;
pragma main.locking_mode;
}
} {normal normal}
do_test exclusive-1.1 {
execsql {
pragma locking_mode = exclusive;
}
} {exclusive}
do_test exclusive-1.2 {
execsql {
pragma locking_mode;
pragma main.locking_mode;
}
} {exclusive exclusive}
do_test exclusive-1.3 {
execsql {
pragma locking_mode = normal;
}
} {normal}
do_test exclusive-1.4 {
execsql {
pragma locking_mode;
pragma main.locking_mode;
}
} {normal normal}
do_test exclusive-1.5 {
execsql {
pragma locking_mode = invalid;
}
} {normal}
do_test exclusive-1.6 {
execsql {
pragma locking_mode;
pragma main.locking_mode;
}
} {normal normal}
do_test exclusive-1.7 {
execsql {
pragma locking_mode = exclusive;
ATTACH 'test2.db' as aux;
}
execsql {
pragma main.locking_mode;
pragma aux.locking_mode;
}
} {exclusive exclusive}
do_test exclusive-1.8 {
execsql {
pragma main.locking_mode = normal;
}
execsql {
pragma main.locking_mode;
pragma aux.locking_mode;
}
} {normal exclusive}
do_test exclusive-1.9 {
execsql {
pragma locking_mode;
}
} {exclusive}
do_test exclusive-1.10 {
execsql {
ATTACH 'test3.db' as aux2;
}
execsql {
pragma main.locking_mode;
pragma aux.locking_mode;
pragma aux2.locking_mode;
}
} {normal exclusive exclusive}
do_test exclusive-1.11 {
execsql {
pragma aux.locking_mode = normal;
}
execsql {
pragma main.locking_mode;
pragma aux.locking_mode;
pragma aux2.locking_mode;
}
} {normal normal exclusive}
do_test exclusive-1.12 {
execsql {
pragma locking_mode = normal;
}
execsql {
pragma main.locking_mode;
pragma aux.locking_mode;
pragma aux2.locking_mode;
}
} {normal normal normal}
do_test exclusive-1.13 {
execsql {
ATTACH 'test4.db' as aux3;
}
execsql {
pragma main.locking_mode;
pragma aux.locking_mode;
pragma aux2.locking_mode;
pragma aux3.locking_mode;
}
} {normal normal normal normal}
do_test exclusive-1.99 {
execsql {
DETACH aux;
DETACH aux2;
DETACH aux3;
}
} {}
#----------------------------------------------------------------------
# Test cases exclusive-2.X verify that connections in exclusive
# locking_mode do not relinquish locks.
#
do_test exclusive-2.0 {
execsql {
CREATE TABLE abc(a, b, c);
INSERT INTO abc VALUES(1, 2, 3);
PRAGMA locking_mode = exclusive;
}
} {exclusive}
do_test exclusive-2.1 {
sqlite3 db2 test.db
execsql {
INSERT INTO abc VALUES(4, 5, 6);
SELECT * FROM abc;
} db2
} {1 2 3 4 5 6}
do_test exclusive-2.2 {
# This causes connection 'db' (in exclusive mode) to establish
# a shared-lock on the db. The other connection should now be
# locked out as a writer.
execsql {
SELECT * FROM abc;
} db
} {1 2 3 4 5 6}
do_test exclusive-2.4 {
execsql {
SELECT * FROM abc;
} db2
} {1 2 3 4 5 6}
do_test exclusive-2.5 {
catchsql {
INSERT INTO abc VALUES(7, 8, 9);
} db2
} {1 {database is locked}}
do_test exclusive-2.6 {
# Because connection 'db' only has a shared-lock, the other connection
# will be able to get a RESERVED, but will fail to upgrade to EXCLUSIVE.
execsql {
BEGIN;
INSERT INTO abc VALUES(7, 8, 9);
} db2
catchsql {
COMMIT
} db2
} {1 {database is locked}}
do_test exclusive-2.7 {
catchsql {
COMMIT
} db2
} {1 {database is locked}}
do_test exclusive-2.8 {
execsql {
ROLLBACK;
} db2
} {}
do_test exclusive-2.9 {
# Write the database to establish the exclusive lock with connection 'db.
execsql {
INSERT INTO abc VALUES(7, 8, 9);
} db
catchsql {
SELECT * FROM abc;
} db2
} {1 {database is locked}}
do_test exclusive-2.10 {
# Changing the locking-mode does not release any locks.
execsql {
PRAGMA locking_mode = normal;
} db
catchsql {
SELECT * FROM abc;
} db2
} {1 {database is locked}}
do_test exclusive-2.11 {
# After changing the locking mode, accessing the db releases locks.
execsql {
SELECT * FROM abc;
} db
execsql {
SELECT * FROM abc;
} db2
} {1 2 3 4 5 6 7 8 9}
db2 close
#----------------------------------------------------------------------
# Tests exclusive-3.X - test that a connection in exclusive mode
# truncates instead of deletes the journal file when committing
# a transaction.
#
proc filestate {fname} {
set exists 0
set content 0
if {[file exists $fname]} {
set exists 1
set content [expr {[file size $fname] > 0}]
}
list $exists $content
}
do_test exclusive-3.0 {
filestate test.db-journal
} {0 0}
do_test exclusive-3.1 {
execsql {
PRAGMA locking_mode = exclusive;
BEGIN;
DELETE FROM abc;
}
filestate test.db-journal
} {1 1}
do_test exclusive-3.2 {
execsql {
COMMIT;
}
filestate test.db-journal
} {1 0}
do_test exclusive-3.3 {
execsql {
INSERT INTO abc VALUES('A', 'B', 'C');
SELECT * FROM abc;
}
} {A B C}
do_test exclusive-3.4 {
execsql {
BEGIN;
UPDATE abc SET a = 1, b = 2, c = 3;
ROLLBACK;
SELECT * FROM abc;
}
} {1 2 3}
do_test exclusive-3.5 {
filestate test.db-journal
} {1 0}
do_test exclusive-3.6 {
execsql {
PRAGMA locking_mode = normal;
SELECT * FROM abc;
}
filestate test.db-journal
} {0 0}
# The following procedure computes a "signature" for table "t3". If
# T3 changes in any way, the signature should change.
#
# This is used to test ROLLBACK. We gather a signature for t3, then
# make lots of changes to t3, then rollback and take another signature.
# The two signatures should be the same.
#
proc signature {} {
return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}
if 0 {
do_test exclusive-4.0 {
execsql { PRAGMA default_cache_size=10; }
db close
sqlite3 db test.db
execsql { PRAGMA locking_mode = exclusive; }
execsql {
BEGIN;
CREATE TABLE t3(x TEXT);
INSERT INTO t3 VALUES(randstr(10,400));
INSERT INTO t3 VALUES(randstr(10,400));
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
COMMIT;
SELECT count(*) FROM t3;
}
} {1024}
set sig [signature]
do_test exclusive-4.1 {
execsql {
BEGIN;
DELETE FROM t3 WHERE random()%10!=0;
INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
ROLLBACK;
}
signature
} $sig
}
finish_test

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script is database locks.
#
# $Id: trans.test,v 1.32 2006/06/20 11:01:09 danielk1977 Exp $
# $Id: trans.test,v 1.33 2007/03/24 16:45:05 danielk1977 Exp $
set testdir [file dirname $argv0]
@ -815,6 +815,7 @@ do_test trans-9.1 {
}
db close
sqlite3 db test.db
# execsql { PRAGMA locking_mode = exclusive; }
execsql {
BEGIN;
CREATE TABLE t3(x TEXT);