diff --git a/manifest b/manifest index b03446390d..32b602d228 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Website\schanges\sfor\sversion\s2.8.14.\s(CVS\s1553) -D 2004-06-09T23:15:22 +C Check\sfor\sschema\supdates\sif\sthe\sparser\sfails\sto\sfind\sa\stable.\s\sMore\slocking\ntest\supdates.\s(CVS\s1555) +D 2004-06-10T00:29:09 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -27,7 +27,7 @@ F src/attach.c 93b8ecec4a8d7b4e9f2479e2327d90c9d01765e8 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 F src/btree.c 281af87aa117de024f5b6c2728a2339cba9ef584 F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa -F src/build.c 4ea78aba171f02b96254dd7a312e4266d3693bfe +F src/build.c 9ee417777c8d1be293773482c28adbf5cd59981b F src/date.c 8e6fa3173386fb29fdef012ee08a853c1e9908b2 F src/delete.c b30f08250c9ed53a25a13c7c04599c1e8753992d F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 @@ -37,7 +37,7 @@ F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb F src/insert.c 4268d9e3959cc845ea243fb4ec7507269404dad9 F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f -F src/main.c 3df17ac486ff1772af8b537cf0bbd0aabba6e863 +F src/main.c 185b7bbac8bbc341b7b6028625c569a651a7fdd6 F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481 F src/os.h 23c69c5084e71b5fe199ff1c4e35a4aded0f1380 F src/os_common.h 6393ac67a3a7b4aea19ff17529980ecf77eb2348 @@ -56,7 +56,7 @@ F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c 1f8355e702f109f6771f82a9bfe7aac4c82cbaf2 F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469 F src/sqlite.h.in 6ad05abc7fd72da74691e1eb45f0eff4117eba4e -F src/sqliteInt.h f384e81fa635b6323aa6297011d9dc2d976868fb +F src/sqliteInt.h 52b73ec6ebd5fe342cc15007771c63ccaf767cbe F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/tclsqlite.c f5c5116720baefb7de5d6acf18baedf1e42756cc F src/test1.c f78d6ac0675bc5db48dac9c5379c965bdadb9113 @@ -119,7 +119,7 @@ F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8 F test/lastinsert.test 31382f88b9b0270333ac9e4a17f2c2f4732da718 F test/laststmtchanges.test cabd11bdfbaf73a4486c50b58297d9c2038ccc18 F test/limit.test 60d7f856ee7846f7130dee67f10f0e726cd70b5d -F test/lock.test bf3beb32eb792dd328c499c57b81a7fc15024d53 +F test/lock.test 65b98e8812489e157a2bd51fb44c520f6bc76e32 F test/main.test 6a851b5992c4881a725a3d9647e629199df8de9d F test/malloc.test 4e19b96d9cd7d61f4826e6fce03849ad5ad526dd F test/memdb.test befe8f26d430d07ba65692243a893a0e82a0b866 @@ -218,7 +218,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248 F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 39b4ba95c4a16b28b5e8c7a3331e09cb5796e258 -R 44b229b6f9f8c0c03939e9b1fc2349f9 +P 73afa14a04e8aa22de71aac7d08abc0ec68dc327 +R 4a457b2bb951374d999015f4602a5043 U drh -Z 46184513a3c8accdddcddf8998ee3516 +Z 0642bdc31cc4198c64ee7082ebf04a73 diff --git a/manifest.uuid b/manifest.uuid index 390537de40..ff03c08d75 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -73afa14a04e8aa22de71aac7d08abc0ec68dc327 \ No newline at end of file +a22283512afe2df09d5783d189fbd7389ed313ad \ No newline at end of file diff --git a/src/build.c b/src/build.c index 25cbb93fb5..afb1fb47e9 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.212 2004/06/09 12:30:05 danielk1977 Exp $ +** $Id: build.c,v 1.213 2004/06/10 00:29:09 drh Exp $ */ #include "sqliteInt.h" #include @@ -164,6 +164,7 @@ Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){ }else{ sqlite3ErrorMsg(pParse, "no such table: %s", zName); } + pParse->checkSchema = 1; } return p; } @@ -1385,6 +1386,7 @@ Table *sqlite3TableFromToken(Parse *pParse, Token *pTok){ sqliteFree(zName); if( pTab==0 ){ sqlite3ErrorMsg(pParse, "no such table: %T", pTok); + pParse->checkSchema = 1; } return pTab; } @@ -1985,6 +1987,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){ pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); + pParse->checkSchema = 1; goto exit_drop_index; } if( pIndex->autoIndex ){ diff --git a/src/main.c b/src/main.c index 53b5c4472a..2e15479d12 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.210 2004/06/09 20:03:09 drh Exp $ +** $Id: main.c,v 1.211 2004/06/10 00:29:09 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -855,6 +855,34 @@ int sqlite3_errcode(sqlite3 *db){ return db->errCode; } +/* +** Check schema cookies in all databases except TEMP. If any cookie is out +** of date, return 0. If all schema cookies are current, return 1. +*/ +static int schemaIsValid(sqlite *db){ + int iDb; + int rc; + BtCursor *curTemp; + int cookie; + int allOk = 1; + + for(iDb=0; allOk && iDbnDb; iDb++){ + Btree *pBt; + if( iDb==1 ) continue; + pBt = db->aDb[iDb].pBt; + if( pBt==0 ) continue; + rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeGetMeta(pBt, 1, &cookie); + if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){ + allOk = 0; + } + sqlite3BtreeCloseCursor(curTemp); + } + } + return allOk; +} + /* ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. */ @@ -911,6 +939,9 @@ int sqlite3_prepare( goto prepare_out; } if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; + if( sParse.checkSchema && !schemaIsValid(db) ){ + sParse.rc = SQLITE_SCHEMA; + } if( sParse.rc==SQLITE_SCHEMA ){ sqlite3ResetInternalSchema(db, 0); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 61998e9e3d..18fa040718 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.276 2004/06/09 20:03:09 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.277 2004/06/10 00:29:10 drh Exp $ */ #include "config.h" #include "sqlite3.h" @@ -1010,6 +1010,7 @@ struct Parse { u8 nameClash; /* A permanent table name clashes with temp table name */ u8 useAgg; /* If true, extract field values from the aggregator ** while generating expressions. Normally false */ + u8 checkSchema; /* Causes schema cookie check after an error */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ diff --git a/test/lock.test b/test/lock.test index b135e8a0f1..4e7d48fa3c 100644 --- a/test/lock.test +++ b/test/lock.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is database locks. # -# $Id: lock.test,v 1.22 2004/06/09 23:15:22 drh Exp $ +# $Id: lock.test,v 1.23 2004/06/10 00:29:12 drh Exp $ set testdir [file dirname $argv0] @@ -47,7 +47,6 @@ do_test lock-1.7.1 { catchsql {SELECT * FROM t1} db2 } {1 {no such table: t1}} do_test lock-1.7.2 { - execsql {SELECT * FROM sqlite_master LIMIT 1} db2 catchsql {SELECT * FROM t1} db2 } {0 {1 2}} do_test lock-1.8 { @@ -64,7 +63,7 @@ do_test lock-1.10 { } {2 1} do_test lock-1.11 { catchsql {SELECT * FROM t1} db2 -} {1 {database is locked}} +} {0 {2 1}} do_test lock-1.12 { execsql {ROLLBACK} catchsql {SELECT * FROM t1} @@ -151,7 +150,8 @@ if {$::tcl_platform(platform)=="unix"} { integrity_check lock-1.23 # If one thread has a transaction another thread cannot start -# a transaction. +# a transaction. -> Not true in version 3.0. But if one thread +# as a RESERVED lock another thread cannot acquire one. # do_test lock-2.1 { execsql {BEGIN TRANSACTION} @@ -162,15 +162,14 @@ do_test lock-2.1 { lappend r $msg } {1 {database is locked}} -# Nor can the other thread do a query. +# A thread can read when another has a RESERVED lock. # do_test lock-2.2 { - set r [catch {execsql {SELECT * FROM t2} db2} msg] - lappend r $msg -} {1 {database is locked}} + catchsql {SELECT * FROM t2} db2 +} {0 {9 8}} -# If the other thread (the one that does not hold the transaction) -# tries to start a transaction, we get a busy callback. +# If the other thread (the one that does not hold the transaction with +# a RESERVED lock) tries to get a RESERVED lock, we get a busy callback. # do_test lock-2.3 { proc callback {args} { @@ -179,7 +178,7 @@ do_test lock-2.3 { } set ::callback_value {} db2 busy callback - set r [catch {execsql {BEGIN TRANSACTION} db2} msg] + set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg] lappend r $msg lappend r $::callback_value } {1 {database is locked} {{} 1}} @@ -190,7 +189,7 @@ do_test lock-2.4 { } set ::callback_value {} db2 busy callback - set r [catch {execsql {BEGIN TRANSACTION} db2} msg] + set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg] lappend r $msg lappend r $::callback_value } {1 {database is locked} {1 2 3 4 5}} @@ -204,7 +203,7 @@ do_test lock-2.5 { set r [catch {execsql {SELECT * FROM t1} db2} msg] lappend r $msg lappend r $::callback_value -} {1 {database is locked} {1 2 3 4 5}} +} {0 {2 1} {}} # In this test, the 3rd invocation of the busy callback causes # the first thread to release its transaction. That allows the @@ -222,10 +221,8 @@ do_test lock-2.6 { set r [catch {execsql {SELECT * FROM t2} db2} msg] lappend r $msg lappend r $::callback_value -} {0 {9 8} {1 2 3}} +} {0 {9 8} {}} do_test lock-2.7 { - execsql {BEGIN TRANSACTION} - execsql {UPDATE t1 SET a = 0 WHERE 0} proc callback {file count} { lappend ::callback_value $count if {$count>2} { @@ -276,12 +273,11 @@ do_test lock-4.1 { db eval BEGIN db eval {UPDATE t1 SET a=0 WHERE 0} sqlite db2 ./test.db - set rc [catch {db2 eval {SELECT * FROM t1}} msg] - lappend rc $msg + catchsql {UPDATE t1 SET a=0} db2 } {1 {database is locked}} do_test lock-4.2 { set ::callback_value {} - set rc [catch {db2 eval {SELECT * FROM t1}} msg] + set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg] lappend rc $msg $::callback_value } {1 {database is locked} {}} do_test lock-4.3 { @@ -290,14 +286,15 @@ do_test lock-4.3 { if {$count>4} break } db2 busy callback - set rc [catch {db2 eval {SELECT * FROM t1}} msg] + set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg] lappend rc $msg $::callback_value } {1 {database is locked} {1 2 3 4 5}} execsql {ROLLBACK} # When one thread is writing, other threads cannot read. Except if the # writing thread is writing to its temporary tables, the other threads -# can still read. +# can still read. -> Not so in 3.0. One thread can read while another +# holds a RESERVED lock. # proc tx_exec {sql} { db2 eval $sql @@ -312,7 +309,7 @@ do_test lock-5.2 { catchsql { INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1'); } -} {1 {database is locked}} +} {0 {}} do_test lock-5.3 { execsql { CREATE TEMP TABLE t3(x); @@ -333,12 +330,12 @@ do_test lock-5.6 { catchsql { UPDATE t1 SET a=tx_exec('SELECT x FROM t2'); } -} {1 {database is locked}} +} {0 {}} do_test lock-5.7 { execsql { SELECT * FROM t1; } -} {2 1} +} {9 1 9 8} do_test lock-5.8 { catchsql { UPDATE t3 SET x=tx_exec('SELECT x FROM t2');