Fix for #2854. "BEGIN EXCLUSIVE" excludes other shared cache users from using the database. (CVS 4642)
FossilOrigin-Name: 2e59b1d07ee422bd799b5b7aeea44ebc998d9481
This commit is contained in:
parent
9892c5d1f4
commit
641b0f4ffa
17
manifest
17
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\ssome\sissues\swith\slemon.\s\sTickets\s#2852\sand\s#2835.\s(CVS\s4641)
|
||||
D 2007-12-21T00:02:11
|
||||
C Fix\sfor\s#2854.\s"BEGIN\sEXCLUSIVE"\sexcludes\sother\sshared\scache\susers\sfrom\susing\sthe\sdatabase.\s(CVS\s4642)
|
||||
D 2007-12-21T04:47:26
|
||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@ -83,9 +83,9 @@ F src/analyze.c fd1a3d756c1a20fca3c505bed0398f4cdca83cb8
|
||||
F src/attach.c a01d55157d46a1234909f3a7f21fb09549c947bd
|
||||
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
||||
F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff
|
||||
F src/btree.c 10cc24011d5602ad332fa8c579a036e678274ee8
|
||||
F src/btree.c bef8ceec858b167bd0ce0863fe0bdd527126c213
|
||||
F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb
|
||||
F src/btreeInt.h 68ec997e34e426093f706da965c147ece75185b9
|
||||
F src/btreeInt.h 1c5a9da165718ef7de81e35ce9ab5d9ba9283f76
|
||||
F src/build.c 580561a0d9e070ff2741f3b115cae51c1ef08260
|
||||
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||
@ -482,6 +482,7 @@ F test/tkt2817.test 709a2201a5590bf56cb97f6fb168a62282203fd1
|
||||
F test/tkt2820.test 017fdee33aaef7abc092beab6088816f1942304b
|
||||
F test/tkt2822.test 8b1526b1e5b0d38a1a993f7828fbb81759093686
|
||||
F test/tkt2832.test cd56dc66bb31898b7eb2146baa5bde2eb80f96fe
|
||||
F test/tkt2854.test aebd5a9904d36d1ef7a074fc5e7c7da3ab00c32a
|
||||
F test/trace.test 75ffc1b992c780d054748a656e3e7fd674f18567
|
||||
F test/trans.test b73289992b46d38d9479ecc4fdc03d8edb2413dc
|
||||
F test/trigger1.test 7c13f39ca36f529bf856e05c7d004fc0531d48b4
|
||||
@ -601,7 +602,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||
P d3efec148968538e225f5716359a6a25e8941362
|
||||
R 85004d42a22e2eebf7a2858fba477cd5
|
||||
U drh
|
||||
Z ad03768828df010e4ad9480b93fc71b4
|
||||
P 5283e0d1467e0fc0ebbd1be553b5a8762e9c7975
|
||||
R e37b64edde771d68293d63348dff6a3a
|
||||
U danielk1977
|
||||
Z 9a8d28eb42d02907bda6dd836ef8b3b4
|
||||
|
@ -1 +1 @@
|
||||
5283e0d1467e0fc0ebbd1be553b5a8762e9c7975
|
||||
2e59b1d07ee422bd799b5b7aeea44ebc998d9481
|
35
src/btree.c
35
src/btree.c
@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.433 2007/12/13 21:54:11 drh Exp $
|
||||
** $Id: btree.c,v 1.434 2007/12/21 04:47:26 danielk1977 Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** See the header comment on "btreeInt.h" for additional information.
|
||||
@ -103,6 +103,13 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* If some other connection is holding an exclusive lock, the
|
||||
** requested lock may not be obtained.
|
||||
*/
|
||||
if( pBt->pExclusive && pBt->pExclusive!=p ){
|
||||
return SQLITE_LOCKED;
|
||||
}
|
||||
|
||||
/* This (along with lockTable()) is where the ReadUncommitted flag is
|
||||
** dealt with. If the caller is querying for a read-lock and the flag is
|
||||
** set, it is unconditionally granted - even if there are write-locks
|
||||
@ -212,13 +219,15 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
|
||||
** procedure) held by Btree handle p.
|
||||
*/
|
||||
static void unlockAllTables(Btree *p){
|
||||
BtLock **ppIter = &p->pBt->pLock;
|
||||
BtShared *pBt = p->pBt;
|
||||
BtLock **ppIter = &pBt->pLock;
|
||||
|
||||
assert( sqlite3BtreeHoldsMutex(p) );
|
||||
assert( p->sharable || 0==*ppIter );
|
||||
|
||||
while( *ppIter ){
|
||||
BtLock *pLock = *ppIter;
|
||||
assert( pBt->pExclusive==0 || pBt->pExclusive==pLock->pBtree );
|
||||
if( pLock->pBtree==p ){
|
||||
*ppIter = pLock->pNext;
|
||||
sqlite3_free(pLock);
|
||||
@ -226,6 +235,10 @@ static void unlockAllTables(Btree *p){
|
||||
ppIter = &pLock->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
if( pBt->pExclusive==p ){
|
||||
pBt->pExclusive = 0;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SHARED_CACHE */
|
||||
|
||||
@ -1850,6 +1863,18 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
|
||||
goto trans_begun;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
if( wrflag>1 ){
|
||||
BtLock *pIter;
|
||||
for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
|
||||
if( pIter->pBtree!=p ){
|
||||
rc = SQLITE_BUSY;
|
||||
goto trans_begun;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
do {
|
||||
if( pBt->pPage1==0 ){
|
||||
rc = lockBtree(pBt);
|
||||
@ -1882,6 +1907,12 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
|
||||
if( p->inTrans>pBt->inTransaction ){
|
||||
pBt->inTransaction = p->inTrans;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
if( wrflag>1 ){
|
||||
assert( !pBt->pExclusive );
|
||||
pBt->pExclusive = p;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btreeInt.h,v 1.14 2007/12/07 18:55:28 drh Exp $
|
||||
** $Id: btreeInt.h,v 1.15 2007/12/21 04:47:26 danielk1977 Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@ -395,6 +395,7 @@ struct BtShared {
|
||||
int nRef; /* Number of references to this structure */
|
||||
BtShared *pNext; /* Next on a list of sharable BtShared structs */
|
||||
BtLock *pLock; /* List of locks held on this shared-btree struct */
|
||||
Btree *pExclusive; /* Btree with an EXCLUSIVE lock on the whole db */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
140
test/tkt2854.test
Normal file
140
test/tkt2854.test
Normal file
@ -0,0 +1,140 @@
|
||||
# 2007 December 20
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# $Id: tkt2854.test,v 1.1 2007/12/21 04:47:27 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
db close
|
||||
|
||||
ifcapable !shared_cache {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
|
||||
# Open 3 database connections. Connection "db" and "db2" share a cache.
|
||||
# Connection "db3" has its own cache.
|
||||
#
|
||||
do_test tkt2854-1.1 {
|
||||
sqlite3 db test.db
|
||||
sqlite3 db2 test.db
|
||||
sqlite3 db3 ./test.db
|
||||
|
||||
db eval {
|
||||
CREATE TABLE abc(a, b, c);
|
||||
}
|
||||
} {}
|
||||
|
||||
# Check that an exclusive lock cannot be obtained if some other
|
||||
# shared-cache connection has a read-lock on a table.
|
||||
#
|
||||
do_test tkt2854-1.2 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM abc;
|
||||
} db2
|
||||
} {}
|
||||
do_test tkt2854-1.3 {
|
||||
catchsql { BEGIN EXCLUSIVE } db
|
||||
} {1 {database is locked}}
|
||||
do_test tkt2854-1.4 {
|
||||
execsql { SELECT * FROM abc } db3
|
||||
} {}
|
||||
do_test tkt2854-1.5 {
|
||||
catchsql { INSERT INTO abc VALUES(1, 2, 3) } db3
|
||||
} {1 {database is locked}}
|
||||
do_test tkt2854-1.6 {
|
||||
execsql { COMMIT } db2
|
||||
} {}
|
||||
|
||||
# Check that an exclusive lock prevents other shared-cache users from
|
||||
# starting a transaction.
|
||||
#
|
||||
do_test tkt2854-1.7 {
|
||||
set ::DB2 [sqlite3_connection_pointer db2]
|
||||
set ::STMT1 [sqlite3_prepare $DB2 "SELECT * FROM abc" -1 TAIL]
|
||||
set ::STMT2 [sqlite3_prepare $DB2 "BEGIN EXCLUSIVE" -1 TAIL]
|
||||
set ::STMT3 [sqlite3_prepare $DB2 "BEGIN IMMEDIATE" -1 TAIL]
|
||||
set ::STMT4 [sqlite3_prepare $DB2 "BEGIN" -1 TAIL]
|
||||
set ::STMT5 [sqlite3_prepare $DB2 "COMMIT" -1 TAIL]
|
||||
execsql { BEGIN EXCLUSIVE } db
|
||||
} {}
|
||||
do_test tkt2854-1.8 {
|
||||
catchsql { BEGIN EXCLUSIVE } db2
|
||||
} {1 {database schema is locked: main}}
|
||||
do_test tkt2854-1.9 {
|
||||
catchsql { BEGIN IMMEDIATE } db2
|
||||
} {1 {database schema is locked: main}}
|
||||
do_test tkt2854-1.10 {
|
||||
# This fails because the schema of main cannot be verified.
|
||||
catchsql { BEGIN } db2
|
||||
} {1 {database schema is locked: main}}
|
||||
|
||||
# Check that an exclusive lock prevents other shared-cache users from
|
||||
# reading the database. Use stored statements so that the error occurs
|
||||
# at the b-tree level, not the schema level.
|
||||
#
|
||||
do_test tkt2854-1.11 {
|
||||
list [sqlite3_step $::STMT1] [sqlite3_finalize $::STMT1]
|
||||
} {SQLITE_ERROR SQLITE_LOCKED}
|
||||
do_test tkt2854-1.12 {
|
||||
list [sqlite3_step $::STMT2] [sqlite3_finalize $::STMT2]
|
||||
} {SQLITE_BUSY SQLITE_BUSY}
|
||||
do_test tkt2854-1.13 {
|
||||
list [sqlite3_step $::STMT3] [sqlite3_finalize $::STMT3]
|
||||
} {SQLITE_BUSY SQLITE_BUSY}
|
||||
do_test tkt2854-1.14 {
|
||||
# A regular "BEGIN" doesn't touch any databases. So it succeeds.
|
||||
list [sqlite3_step $::STMT4] [sqlite3_finalize $::STMT4]
|
||||
} {SQLITE_DONE SQLITE_OK}
|
||||
do_test tkt2854-1.15 {
|
||||
# As does a COMMIT.
|
||||
list [sqlite3_step $::STMT5] [sqlite3_finalize $::STMT5]
|
||||
} {SQLITE_DONE SQLITE_OK}
|
||||
|
||||
# Try to read the database using connection "db3" (which does not share
|
||||
# a cache with "db"). The database should be locked.
|
||||
do_test tkt2854-1.16 {
|
||||
catchsql { SELECT * FROM abc } db3
|
||||
} {1 {database is locked}}
|
||||
do_test tkt2854-1.17 {
|
||||
execsql { COMMIT } db
|
||||
} {}
|
||||
do_test tkt2854-1.18 {
|
||||
execsql { SELECT * FROM abc } db2
|
||||
} {}
|
||||
|
||||
# Check that if an attempt to obtain an exclusive lock fails because an
|
||||
# attached db cannot be locked, the internal exclusive flag used by
|
||||
# shared-cache users is correctly cleared.
|
||||
do_test tkt2854-1.19 {
|
||||
file delete -force test2.db test2.db-journal
|
||||
sqlite3 db4 test2.db
|
||||
execsql { CREATE TABLE def(d, e, f) } db4
|
||||
execsql { ATTACH 'test2.db' AS aux } db
|
||||
} {}
|
||||
do_test tkt2854-1.20 {
|
||||
execsql {BEGIN IMMEDIATE} db4
|
||||
catchsql {BEGIN EXCLUSIVE} db
|
||||
} {1 {database is locked}}
|
||||
do_test tkt2854-1.21 {
|
||||
execsql {SELECT * FROM abc} db2
|
||||
} {}
|
||||
|
||||
db close
|
||||
db2 close
|
||||
db3 close
|
||||
db4 close
|
||||
sqlite3_enable_shared_cache $::enable_shared_cache
|
||||
finish_test
|
||||
|
Loading…
x
Reference in New Issue
Block a user