Index: ext/session/sessionfault.test ================================================================== --- ext/session/sessionfault.test +++ ext/session/sessionfault.test @@ -15,10 +15,11 @@ if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl +ifcapable !session {finish_test; return} set testprefix sessionfault forcedelete test.db2 sqlite3 db2 test.db2 Index: ext/session/sessionfault2.test ================================================================== --- ext/session/sessionfault2.test +++ ext/session/sessionfault2.test @@ -15,10 +15,11 @@ if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl +ifcapable !session {finish_test; return} set testprefix sessionfault2 do_execsql_test 1.0.0 { CREATE TABLE t1(a PRIMARY KEY, b UNIQUE); INSERT INTO t1 VALUES(1, 1); Index: ext/session/sqlite3session.c ================================================================== --- ext/session/sqlite3session.c +++ ext/session/sqlite3session.c @@ -590,18 +590,23 @@ u8 *a1 = aLeft; /* Cursor to iterate through aLeft */ u8 *a2 = aRight; /* Cursor to iterate through aRight */ int iCol; /* Used to iterate through table columns */ for(iCol=0; iColnCol; iCol++){ - int n1 = sessionSerialLen(a1); - int n2 = sessionSerialLen(a2); - - if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){ - return 0; - } - if( pTab->abPK[iCol] || bLeftPkOnly==0 ) a1 += n1; - if( pTab->abPK[iCol] || bRightPkOnly==0 ) a2 += n2; + if( pTab->abPK[iCol] ){ + int n1 = sessionSerialLen(a1); + int n2 = sessionSerialLen(a2); + + if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){ + return 0; + } + a1 += n1; + a2 += n2; + }else{ + if( bLeftPkOnly==0 ) a1 += sessionSerialLen(a1); + if( bRightPkOnly==0 ) a2 += sessionSerialLen(a2); + } } return 1; } Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -5211,21 +5211,23 @@ return TCL_OK; } /* ** tclcmd: vfs_reregister_all ** -** Restore all VFSes that were removed using vfs_unregister_all +** Restore all VFSes that were removed using vfs_unregister_all. Taking +** care to put the linked list back together in the same order as it was +** in before vfs_unregister_all was invoked. */ static int vfs_reregister_all( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int i; - for(i=0; i=0; i--){ + sqlite3_vfs_register(apVfs[i], 1); } return TCL_OK; } Index: src/test6.c ================================================================== --- src/test6.c +++ src/test6.c @@ -699,10 +699,14 @@ } static int cfCurrentTime(sqlite3_vfs *pCfVfs, double *pTimeOut){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; return pVfs->xCurrentTime(pVfs, pTimeOut); } +static int cfGetLastError(sqlite3_vfs *pCfVfs, int n, char *z){ + sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; + return pVfs->xGetLastError(pVfs, n, z); +} static int processDevSymArgs( Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], @@ -825,11 +829,11 @@ cfDlSym, /* xDlSym */ cfDlClose, /* xDlClose */ cfRandomness, /* xRandomness */ cfSleep, /* xSleep */ cfCurrentTime, /* xCurrentTime */ - 0, /* xGetlastError */ + cfGetLastError, /* xGetLastError */ 0, /* xCurrentTimeInt64 */ }; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "ENABLE"); @@ -938,10 +942,31 @@ return TCL_ERROR; } devsym_register(iDc, iSectorSize); return TCL_OK; + +} + +/* +** tclcmd: unregister_devsim +*/ +static int dsUnregisterObjCmd( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + void devsym_unregister(void); + + if( objc!=1 ){ + Tcl_WrongNumArgs(interp, 1, objv, ""); + return TCL_ERROR; + } + + devsym_unregister(); + return TCL_OK; } /* ** tclcmd: register_jt_vfs ?-default? PARENT-VFS */ @@ -1008,12 +1033,13 @@ int Sqlitetest6_Init(Tcl_Interp *interp){ #ifndef SQLITE_OMIT_DISKIO Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0); + Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0); #endif return TCL_OK; } #endif /* SQLITE_TEST */ Index: src/test_devsym.c ================================================================== --- src/test_devsym.c +++ src/test_devsym.c @@ -393,7 +393,14 @@ g.iSectorSize = iSectorSize; }else{ g.iSectorSize = 512; } } + +void devsym_unregister(){ + sqlite3_vfs_unregister(&devsym_vfs); + g.pVfs = 0; + g.iDeviceChar = 0; + g.iSectorSize = 0; +} #endif Index: src/test_journal.c ================================================================== --- src/test_journal.c +++ src/test_journal.c @@ -158,10 +158,11 @@ static void jtDlClose(sqlite3_vfs*, void*); static int jtRandomness(sqlite3_vfs*, int nByte, char *zOut); static int jtSleep(sqlite3_vfs*, int microseconds); static int jtCurrentTime(sqlite3_vfs*, double*); static int jtCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); +static int jtGetLastError(sqlite3_vfs*, int, char*); static sqlite3_vfs jt_vfs = { 2, /* iVersion */ sizeof(jt_file), /* szOsFile */ JT_MAX_PATHNAME, /* mxPathname */ @@ -177,11 +178,11 @@ jtDlSym, /* xDlSym */ jtDlClose, /* xDlClose */ jtRandomness, /* xRandomness */ jtSleep, /* xSleep */ jtCurrentTime, /* xCurrentTime */ - 0, /* xGetLastError */ + jtGetLastError, /* xGetLastError */ jtCurrentTimeInt64 /* xCurrentTimeInt64 */ }; static sqlite3_io_methods jt_io_methods = { 1, /* iVersion */ @@ -283,21 +284,22 @@ ** a) SQLITE_OPEN_MAIN_DB was specified when the file was opened. ** ** b) The file-name specified when the file was opened matches ** all but the final 8 characters of the journal file name. ** -** c) There is currently a reserved lock on the file. +** c) There is currently a reserved lock on the file. This +** condition is waived if the noLock argument is non-zero. **/ -static jt_file *locateDatabaseHandle(const char *zJournal){ +static jt_file *locateDatabaseHandle(const char *zJournal, int noLock){ jt_file *pMain = 0; enterJtMutex(); for(pMain=g.pList; pMain; pMain=pMain->pNext){ int nName = (int)(strlen(zJournal) - strlen("-journal")); if( (pMain->flags&SQLITE_OPEN_MAIN_DB) && ((int)strlen(pMain->zName)==nName) && 0==memcmp(pMain->zName, zJournal, nName) - && (pMain->eLock>=SQLITE_LOCK_RESERVED) + && ((pMain->eLock>=SQLITE_LOCK_RESERVED) || noLock) ){ break; } } leaveJtMutex(); @@ -515,11 +517,11 @@ ){ int rc; jt_file *p = (jt_file *)pFile; if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){ if( iOfst==0 ){ - jt_file *pMain = locateDatabaseHandle(p->zName); + jt_file *pMain = locateDatabaseHandle(p->zName, 0); assert( pMain ); if( iAmt==28 ){ /* Zeroing the first journal-file header. This is the end of a ** transaction. */ @@ -560,11 +562,11 @@ } } rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){ - jt_file *pMain = locateDatabaseHandle(p->zName); + jt_file *pMain = locateDatabaseHandle(p->zName, 0); int rc2 = readJournalFile(p, pMain); if( rc==SQLITE_OK ) rc = rc2; } return rc; } @@ -574,11 +576,11 @@ */ static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){ jt_file *p = (jt_file *)pFile; if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){ /* Truncating a journal file. This is the end of a transaction. */ - jt_file *pMain = locateDatabaseHandle(p->zName); + jt_file *pMain = locateDatabaseHandle(p->zName, 0); closeTransaction(pMain); } if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ u32 pgno; u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1); @@ -602,15 +604,14 @@ /* The journal file is being synced. At this point, we inspect the ** contents of the file up to this point and set each bit in the ** jt_file.pWritable bitvec of the main database file associated with ** this journal file. */ - pMain = locateDatabaseHandle(p->zName); - assert(pMain); + pMain = locateDatabaseHandle(p->zName, 0); /* Set the bitvec values */ - if( pMain->pWritable ){ + if( pMain && pMain->pWritable ){ pMain->nSync++; rc = readJournalFile(p, pMain); if( rc!=SQLITE_OK ){ return rc; } @@ -728,11 +729,11 @@ */ static int jtDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ int nPath = (int)strlen(zPath); if( nPath>8 && 0==strcmp("-journal", &zPath[nPath-8]) ){ /* Deleting a journal file. The end of a transaction. */ - jt_file *pMain = locateDatabaseHandle(zPath); + jt_file *pMain = locateDatabaseHandle(zPath, 0); if( pMain ){ closeTransaction(pMain); } } @@ -822,10 +823,14 @@ ** Return the current time as a Julian Day number in *pTimeOut. */ static int jtCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ return g.pVfs->xCurrentTimeInt64(g.pVfs, pTimeOut); } + +static int jtGetLastError(sqlite3_vfs *pVfs, int n, char *z){ + return g.pVfs->xGetLastError(g.pVfs, n, z); +} /************************************************************************** ** Start of public API. */ Index: src/test_syscall.c ================================================================== --- src/test_syscall.c +++ src/test_syscall.c @@ -720,18 +720,24 @@ { "pagesize", test_syscall_pagesize }, { 0, 0 } }; int iCmd; int rc; + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); return TCL_ERROR; } - rc = Tcl_GetIndexFromObjStruct(interp, - objv[1], aCmd, sizeof(aCmd[0]), "sub-command", 0, &iCmd - ); + if( pVfs->iVersion<3 || pVfs->xSetSystemCall==0 ){ + Tcl_AppendResult(interp, "VFS does not support xSetSystemCall", 0); + rc = TCL_ERROR; + }else{ + rc = Tcl_GetIndexFromObjStruct(interp, + objv[1], aCmd, sizeof(aCmd[0]), "sub-command", 0, &iCmd + ); + } if( rc!=TCL_OK ) return rc; return aCmd[iCmd].xCmd(clientData, interp, objc, objv); } int SqlitetestSyscall_Init(Tcl_Interp *interp){ Index: test/dbstatus2.test ================================================================== --- test/dbstatus2.test +++ test/dbstatus2.test @@ -84,11 +84,11 @@ } {0 4 0} do_test 2.3 { db_write db 1 } {0 4 0} do_test 2.4 { db_write db 0 } {0 0 0} do_test 2.5 { db_write db 1 } {0 0 0} -ifcapable wal { +if {[wal_is_capable]} { do_test 2.6 { execsql { PRAGMA journal_mode = WAL } db_write db 1 } {0 1 0} } Index: test/e_vacuum.test ================================================================== --- test/e_vacuum.test +++ test/e_vacuum.test @@ -174,11 +174,11 @@ } {2048 0} # EVIDENCE-OF: R-48521-51450 When in write-ahead log mode, only the # auto_vacuum support property can be changed using VACUUM. # - ifcapable wal { + if {[wal_is_capable]} { do_test e_vacuum-1.3.3.1 { execsql { PRAGMA journal_mode = wal } execsql { PRAGMA page_size ; PRAGMA auto_vacuum } } {2048 0} do_test e_vacuum-1.3.3.2 { Index: test/exists.test ================================================================== --- test/exists.test +++ test/exists.test @@ -17,10 +17,11 @@ source $testdir/tester.tcl source $testdir/lock_common.tcl foreach jm {rollback wal} { + if {![wal_is_capable] && $jm=="wal"} continue set testprefix exists-$jm # This block of tests is targeted at CREATE XXX IF NOT EXISTS statements. # Index: test/hook.test ================================================================== --- test/hook.test +++ test/hook.test @@ -702,11 +702,11 @@ INSERT INTO t8 VALUES('one', 'two'); INSERT INTO t8 VALUES('three', 'four'); ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx'; } -ifcapable !session { +if 0 { # At time of writing, these two are broken. They demonstrate that the # sqlite3_preupdate_old() method does not handle the case where ALTER TABLE # has been used to add a column with a default value other than NULL. # do_preupdate_test 7.5.2.1 { Index: test/incrvacuum2.test ================================================================== --- test/incrvacuum2.test +++ test/incrvacuum2.test @@ -132,11 +132,11 @@ } } {} integrity_check incrvacuum2-3.3 -ifcapable wal { +if {[wal_is_capable]} { # At one point, when a specific page was being extracted from the b-tree # free-list (e.g. during an incremental-vacuum), all trunk pages that # occurred before the specific page in the free-list trunk were being # written to the journal or wal file. This is not necessary. Only the # extracted page and the page that contains the pointer to it need to Index: test/journal2.test ================================================================== --- test/journal2.test +++ test/journal2.test @@ -202,11 +202,11 @@ # Test that it is possible to switch from journal_mode=truncate to # journal_mode=WAL on a SAFE_DELETE file-system. SQLite should close and # delete the journal file when committing the transaction that switches # the system to WAL mode. # -ifcapable wal { +if {[wal_is_capable]} { do_test journal2-2.1 { faultsim_delete_and_reopen set ::oplog [list] execsql { PRAGMA journal_mode = persist } set ::oplog Index: test/permutations.test ================================================================== --- test/permutations.test +++ test/permutations.test @@ -726,11 +726,11 @@ # Exclude all tests that simulate IO errors. autovacuum_ioerr2.test cffault.test incrvacuum_ioerr.test ioerr.test ioerr.test ioerr2.test ioerr3.test ioerr4.test ioerr5.test vacuum3.test incrblob_err.test diskfull.test backup_ioerr.test e_fts3.test fts3cov.test fts3malloc.test fts3rnd.test - fts3snippet.test mmapfault.test + fts3snippet.test mmapfault.test sessionfault.test sessionfault2.test # Exclude test scripts that use tcl IO to access journal files or count # the number of fsync() calls. pager.test exclusive.test jrnlmode.test sync.test misc1.test journal1.test conflict.test crash8.test tkt3457.test io.test @@ -940,11 +940,13 @@ register_jt_vfs -default "" } -shutdown { unregister_jt_vfs } -files [test_set $::allquicktests -exclude { wal* incrvacuum.test ioerr.test corrupt4.test io.test crash8.test - async4.test bigfile.test backcompat.test + async4.test bigfile.test backcompat.test e_wal* fstat.test mmap2.test + pager1.test syscall.test tkt3457.test *malloc* mmap* multiplex* nolock* + pager2.test *fault* rowal* snapshot* superlock* symlink.test }] if {[info commands register_demovfs] != ""} { test_suite "demovfs" -description { Check that the demovfs (code in test_demovfs.c) more or less works. @@ -1048,19 +1050,17 @@ set ::G(perm:prefix) $options(-prefix) set ::G(perm:presql) $options(-presql) set ::G(isquick) 1 set ::G(perm:dbconfig) $options(-dbconfig) - uplevel $options(-initialize) - foreach file [lsort $options(-files)] { + uplevel $options(-initialize) if {[file tail $file] == $file} { set file [file join $::testdir $file] } slave_test_file $file + uplevel $options(-shutdown) } - uplevel $options(-shutdown) - unset ::G(perm:name) unset ::G(perm:prefix) unset ::G(perm:presql) unset ::G(perm:dbconfig) } Index: test/pragma3.test ================================================================== --- test/pragma3.test +++ test/pragma3.test @@ -219,11 +219,11 @@ # Make sure this also works in WAL mode # # This will not work with the in-memory journal permutation, as opening # [db2] switches the journal mode back to "memory" # -ifcapable wal { +if {[wal_is_capable]} { if {[permutation]!="inmemory_journal"} { sqlite3 db test.db db eval {PRAGMA journal_mode=WAL} sqlite3 db2 test.db Index: test/quota.test ================================================================== --- test/quota.test +++ test/quota.test @@ -525,6 +525,8 @@ } -body { sqlite3_quota_set * 4096 {} } catch { sqlite3_quota_shutdown } +catch { db close } +forcedelete test.db finish_test Index: test/stat.test ================================================================== --- test/stat.test +++ test/stat.test @@ -35,11 +35,11 @@ PRAGMA auto_vacuum = OFF; CREATE VIRTUAL TABLE temp.stat USING dbstat; SELECT * FROM stat; } {} -ifcapable wal { +if {[wal_is_capable]} { do_execsql_test stat-0.1 { PRAGMA journal_mode = WAL; PRAGMA journal_mode = delete; SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat; Index: test/sync.test ================================================================== --- test/sync.test +++ test/sync.test @@ -79,10 +79,11 @@ } cond_incr_sync_count 4 set sqlite_sync_count } 11 ifcapable pager_pragmas { +if {[permutation]!="journaltest"} { do_test sync-1.4 { set sqlite_sync_count 0 execsql { PRAGMA main.synchronous=off; PRAGMA db2.synchronous=off; @@ -91,9 +92,10 @@ INSERT INTO t2 VALUES(7,8); COMMIT; } set sqlite_sync_count } 0 +} } finish_test Index: test/tester.tcl ================================================================== --- test/tester.tcl +++ test/tester.tcl @@ -1941,10 +1941,16 @@ if { [wal_is_wal_mode] } { $db eval { SELECT * FROM sqlite_master } do_test $testname [list $db eval "PRAGMA main.journal_mode"] {wal} } } + +proc wal_is_capable {} { + ifcapable !wal { return 0 } + if {[permutation]=="journaltest"} { return 0 } + return 1 +} proc permutation {} { set perm "" catch {set perm $::G(perm:name)} set perm Index: test/tkt-2d1a5c67d.test ================================================================== --- test/tkt-2d1a5c67d.test +++ test/tkt-2d1a5c67d.test @@ -17,11 +17,12 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-2d1a5c67d -ifcapable {!wal || !vtab} {finish_test; return} +ifcapable {!vtab} {finish_test; return} +if {[wal_is_capable]==0} {finish_test; return} for {set ii 1} {$ii<=10} {incr ii} { do_test tkt-2d1a5c67d.1.$ii { db close forcedelete test.db test.db-wal Index: test/tkt-313723c356.test ================================================================== --- test/tkt-313723c356.test +++ test/tkt-313723c356.test @@ -16,11 +16,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl -ifcapable !wal { finish_test ; return } +if {![wal_is_capable]} { finish_test ; return } do_execsql_test tkt-313723c356.1 { PRAGMA page_size = 1024; PRAGMA journal_mode = WAL; CREATE TABLE t1(a, b); Index: test/tkt-5d863f876e.test ================================================================== --- test/tkt-5d863f876e.test +++ test/tkt-5d863f876e.test @@ -16,11 +16,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl set ::testprefix tkt-5d863f876e -ifcapable !wal {finish_test ; return } +if {![wal_is_capable]} {finish_test ; return } do_multiclient_test tn { do_test $tn.1 { sql1 { CREATE TABLE t1(a, b); Index: test/tkt-9d68c883.test ================================================================== --- test/tkt-9d68c883.test +++ test/tkt-9d68c883.test @@ -48,6 +48,8 @@ catchsql { ROLLBACK } execsql { PRAGMA integrity_check } } {ok} } +catch { db close } +unregister_devsim finish_test Index: test/zerodamage.test ================================================================== --- test/zerodamage.test +++ test/zerodamage.test @@ -87,11 +87,11 @@ UPDATE t1 SET y=randomblob(50) WHERE x=124; } concat [file_control_powersafe_overwrite db -1] [set ::max_journal_size] } {0 0 24704} -ifcapable wal { +if {[wal_is_capable]} { # Run a WAL-mode transaction with POWERSAFE_OVERWRITE on to verify that the # WAL file does not get too big. # do_test zerodamage-3.0 { db eval {