diff --git a/manifest b/manifest index 83e4629fb2..560407ffc2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sextra\spager\stests. -D 2010-06-28T19:04:02 +C Add\stests\sto\spager1.test\sand\spagerfault.test. +D 2010-06-29T10:30:24 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -209,7 +209,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6 F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726 -F src/test_vfs.c 90d51963dfe2aa28a9408b461cb06f48921be8e8 +F src/test_vfs.c 2291fd22726e499830e9958563e760effaf9e9af F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb F src/trigger.c 67e95c76d625b92d43409ace771c8e0d02a09ac2 @@ -534,9 +534,9 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec -F test/pager1.test 634c62f8c321fb5b72b4c8fa27340bd8e9db9089 +F test/pager1.test 28709653e83ce9557a983cce251ff02112d5ecca F test/pager2.test f5c757c271ce642d36a393ecbfb3aef1c240dcef -F test/pagerfault.test 210fae669249a06ef0c08da1e75b9bda7e9bf66b +F test/pagerfault.test e7fd4e54fb362ec16ce3474842ed7af390d88de0 F test/pagerfault2.test 1287f123bd5d20452113739ed7755fd254e502f1 F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806 F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb @@ -828,7 +828,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 3b68cb9c656db8c5c481199919a98f5764f7ebfa -R 3cf749e0c461e6688a0dd44d86bc37c3 +P 6b7e419ddc241f457dd69878f09f5c51c70aa379 +R d8452c9c3029633c6ea47d4358dc9dd2 U dan -Z cd8f9170613084e79dc0108e44d902f9 +Z 673ae6c021fa890a23c09b0dc8b30087 diff --git a/manifest.uuid b/manifest.uuid index 838f2c482b..d3abf045f3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6b7e419ddc241f457dd69878f09f5c51c70aa379 \ No newline at end of file +008513ee6115f8d6f4b4e1428c1c638282b971a3 \ No newline at end of file diff --git a/src/test_vfs.c b/src/test_vfs.c index 8ae55e7d46..ce0642e2c8 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -13,6 +13,21 @@ */ #if SQLITE_TEST /* This file is used for testing only */ +/* +** This file contains the implementation of the Tcl [testvfs] command, +** used to create SQLite VFS implementations with various properties and +** instrumentation to support testing SQLite. +** +** testvfs VFSNAME ?OPTIONS? +** +** Available options are: +** +** -noshm BOOLEAN (True to omit shm methods. Default false) +** -default BOOLEAN (True to make the vfs default. Default false) +** -szosfile INTEGER (Value for sqlite3_vfs.szOsFile) +** -mxpathname INTEGER (Value for sqlite3_vfs.mxPathname) +*/ + #include "sqlite3.h" #include "sqliteInt.h" @@ -20,12 +35,18 @@ typedef struct Testvfs Testvfs; typedef struct TestvfsShm TestvfsShm; typedef struct TestvfsBuffer TestvfsBuffer; typedef struct TestvfsFile TestvfsFile; +typedef struct TestvfsFd TestvfsFd; /* ** An open file handle. */ struct TestvfsFile { sqlite3_file base; /* Base class. Must be first */ + TestvfsFd *pFd; /* File data */ +}; +#define tvfsGetFd(pFile) (((TestvfsFile *)pFile)->pFd) + +struct TestvfsFd { sqlite3_vfs *pVfs; /* The VFS */ const char *zFilename; /* Filename as passed to xOpen() */ sqlite3_file *pReal; /* The real, underlying file descriptor */ @@ -34,9 +55,10 @@ struct TestvfsFile { TestvfsBuffer *pShm; /* Shared memory buffer */ u32 excllock; /* Mask of exclusive locks */ u32 sharedlock; /* Mask of shared locks */ - TestvfsFile *pNext; /* Next handle opened on the same file */ + TestvfsFd *pNext; /* Next handle opened on the same file */ }; + #define FAULT_INJECT_NONE 0 #define FAULT_INJECT_TRANSIENT 1 #define FAULT_INJECT_PERSISTENT 2 @@ -118,7 +140,7 @@ struct TestvfsBuffer { char *zFile; /* Associated file name */ int pgsz; /* Page size */ u8 *aPage[TESTVFS_MAX_PAGES]; /* Array of ckalloc'd pages */ - TestvfsFile *pFile; /* List of open handles */ + TestvfsFd *pFile; /* List of open handles */ TestvfsBuffer *pNext; /* Next in linked list of all buffers */ }; @@ -296,7 +318,9 @@ static void tvfsExecTcl( ** Close an tvfs-file. */ static int tvfsClose(sqlite3_file *pFile){ - TestvfsFile *pFd = (TestvfsFile *)pFile; + int rc; + TestvfsFile *pTestfile = (TestvfsFile *)pFile; + TestvfsFd *pFd = pTestfile->pFd; Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){ @@ -312,7 +336,10 @@ static int tvfsClose(sqlite3_file *pFile){ if( pFile->pMethods ){ ckfree((char *)pFile->pMethods); } - return sqlite3OsClose(pFd->pReal); + rc = sqlite3OsClose(pFd->pReal); + ckfree((char *)pFd); + pTestfile->pFd = 0; + return rc; } /* @@ -324,7 +351,7 @@ static int tvfsRead( int iAmt, sqlite_int64 iOfst ){ - TestvfsFile *p = (TestvfsFile *)pFile; + TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); } @@ -338,7 +365,7 @@ static int tvfsWrite( sqlite_int64 iOfst ){ int rc = SQLITE_OK; - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){ @@ -366,7 +393,7 @@ static int tvfsWrite( */ static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ int rc = SQLITE_OK; - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){ @@ -387,7 +414,7 @@ static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ */ static int tvfsSync(sqlite3_file *pFile, int flags){ int rc = SQLITE_OK; - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_SYNC_MASK ){ @@ -430,7 +457,7 @@ static int tvfsSync(sqlite3_file *pFile, int flags){ ** Return the current file-size of an tvfs-file. */ static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ - TestvfsFile *p = (TestvfsFile *)pFile; + TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsFileSize(p->pReal, pSize); } @@ -438,7 +465,7 @@ static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ ** Lock an tvfs-file. */ static int tvfsLock(sqlite3_file *pFile, int eLock){ - TestvfsFile *p = (TestvfsFile *)pFile; + TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsLock(p->pReal, eLock); } @@ -446,7 +473,7 @@ static int tvfsLock(sqlite3_file *pFile, int eLock){ ** Unlock an tvfs-file. */ static int tvfsUnlock(sqlite3_file *pFile, int eLock){ - TestvfsFile *p = (TestvfsFile *)pFile; + TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsUnlock(p->pReal, eLock); } @@ -454,7 +481,7 @@ static int tvfsUnlock(sqlite3_file *pFile, int eLock){ ** Check if another file-handle holds a RESERVED lock on an tvfs-file. */ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){ - TestvfsFile *p = (TestvfsFile *)pFile; + TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsCheckReservedLock(p->pReal, pResOut); } @@ -462,7 +489,7 @@ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){ ** File control method. For custom operations on an tvfs-file. */ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ - TestvfsFile *p = (TestvfsFile *)pFile; + TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsFileControl(p->pReal, op, pArg); } @@ -470,7 +497,7 @@ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ ** Return the sector-size in bytes for an tvfs-file. */ static int tvfsSectorSize(sqlite3_file *pFile){ - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->iSectorsize>=0 ){ return p->iSectorsize; @@ -482,7 +509,7 @@ static int tvfsSectorSize(sqlite3_file *pFile){ ** Return the device characteristic flags supported by an tvfs-file. */ static int tvfsDeviceCharacteristics(sqlite3_file *pFile){ - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->iDevchar>=0 ){ return p->iDevchar; @@ -501,15 +528,19 @@ static int tvfsOpen( int *pOutFlags ){ int rc; - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFile *pTestfile = (TestvfsFile *)pFile; + TestvfsFd *pFd; Tcl_Obj *pId = 0; Testvfs *p = (Testvfs *)pVfs->pAppData; + pFd = (TestvfsFd *)ckalloc(sizeof(TestvfsFd) + PARENTVFS(pVfs)->szOsFile); + memset(pFd, 0, sizeof(TestvfsFd) + PARENTVFS(pVfs)->szOsFile); pFd->pShm = 0; pFd->pShmId = 0; pFd->zFilename = zName; pFd->pVfs = pVfs; pFd->pReal = (sqlite3_file *)&pFd[1]; + pTestfile->pFd = pFd; /* Evaluate the Tcl script: ** @@ -541,7 +572,6 @@ static int tvfsOpen( pFd->pShmId = pId; Tcl_ResetResult(p->interp); - rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, pFd->pReal, flags, pOutFlags); if( pFd->pReal->pMethods ){ sqlite3_io_methods *pMethods; @@ -682,15 +712,13 @@ static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut); } -static int tvfsShmOpen( - sqlite3_file *pFileDes -){ +static int tvfsShmOpen(sqlite3_file *pFile){ Testvfs *p; int rc = SQLITE_OK; /* Return code */ TestvfsBuffer *pBuffer; /* Buffer to open connection to */ - TestvfsFile *pFd; /* The testvfs file structure */ + TestvfsFd *pFd; /* The testvfs file structure */ - pFd = (TestvfsFile*)pFileDes; + pFd = tvfsGetFd(pFile); p = (Testvfs *)pFd->pVfs->pAppData; assert( pFd->pShmId && pFd->pShm==0 && pFd->pNext==0 ); @@ -749,7 +777,7 @@ static int tvfsShmMap( void volatile **pp /* OUT: Mapped memory */ ){ int rc = SQLITE_OK; - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->pScript && p->mask&TESTVFS_SHMMAP_MASK ){ @@ -784,7 +812,7 @@ static int tvfsShmLock( int flags ){ int rc = SQLITE_OK; - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); int nLock; char zLock[80]; @@ -819,7 +847,7 @@ static int tvfsShmLock( int isExcl = (flags & SQLITE_SHM_EXCLUSIVE); u32 mask = (((1<pShm->pFile; p2; p2=p2->pNext){ if( p2==pFd ) continue; if( (p2->excllock&mask) || (isExcl && p2->sharedlock&mask) ){ @@ -841,7 +869,7 @@ static int tvfsShmLock( } static void tvfsShmBarrier(sqlite3_file *pFile){ - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){ @@ -856,10 +884,10 @@ static int tvfsShmClose( int deleteFlag ){ int rc = SQLITE_OK; - TestvfsFile *pFd = (TestvfsFile *)pFile; + TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); TestvfsBuffer *pBuffer = pFd->pShm; - TestvfsFile **ppFd; + TestvfsFd **ppFd; assert( pFd->pShmId && pFd->pShm ); @@ -1234,7 +1262,7 @@ static int testvfs_cmd( ){ static sqlite3_vfs tvfs_vfs = { 2, /* iVersion */ - sizeof(TestvfsFile), /* szOsFile */ + 0, /* szOsFile */ 0, /* mxPathname */ 0, /* pNext */ 0, /* zName */ @@ -1270,13 +1298,15 @@ static int testvfs_cmd( int i; int isNoshm = 0; /* True if -noshm is passed */ int isDefault = 0; /* True if -default is passed */ + int szOsFile = 0; /* Value passed to -szosfile */ + int mxPathname = -1; /* Value passed to -mxpathname */ if( objc<2 || 0!=(objc%2) ) goto bad_args; for(i=2; i2 && 0==strncmp("-noshm", zSwitch, nSwitch) ){ if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isNoshm) ){ return TCL_ERROR; @@ -1287,11 +1317,25 @@ static int testvfs_cmd( return TCL_ERROR; } } + else if( nSwitch>2 && 0==strncmp("-szosfile", zSwitch, nSwitch) ){ + if( Tcl_GetIntFromObj(interp, objv[i+1], &szOsFile) ){ + return TCL_ERROR; + } + } + else if( nSwitch>2 && 0==strncmp("-mxpathname", zSwitch, nSwitch) ){ + if( Tcl_GetIntFromObj(interp, objv[i+1], &mxPathname) ){ + return TCL_ERROR; + } + } else{ goto bad_args; } } + if( szOsFilepAppData = (void *)p; pVfs->zName = p->zName; pVfs->mxPathname = p->pParent->mxPathname; - pVfs->szOsFile += p->pParent->szOsFile; + if( mxPathname>=0 && mxPathnamemxPathname ){ + pVfs->mxPathname = mxPathname; + } + pVfs->szOsFile = szOsFile; p->pVfs = pVfs; p->isNoshm = isNoshm; p->mask = TESTVFS_ALL_MASK; @@ -1327,7 +1374,7 @@ static int testvfs_cmd( return TCL_OK; bad_args: - Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL?"); + Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT?"); return TCL_ERROR; } diff --git a/test/pager1.test b/test/pager1.test index aa9b2d5b46..f9e17d4c2a 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -49,6 +49,15 @@ do_not_use_codec # # pager1-14.*: Cases specific to "PRAGMA journal_mode=OFF" # +# pager1-15.*: Varying sqlite3_vfs.szOsFile +# +# pager1-16.*: Varying sqlite3_vfs.mxPathname +# +# pager1-17.*: Tests related to "PRAGMA omit_readlock" +# +# pager1-18.*: Test that the pager layer responds correctly if the b-tree +# requests an invalid page number (due to db corruption). +# set a_string_counter 1 proc a_string {n} { @@ -358,6 +367,10 @@ foreach {tn sql tcl} { # pager1.4.6.*: Test that when rolling back a hot-journal that contains a # master journal pointer, the master journal file is deleted # after all the hot-journals that refer to it are deleted. +# +# pager1.4.7.*: Test that if a hot-journal file exists but a client can +# open it for reading only, the database cannot be accessed and +# SQLITE_CANTOPEN is returned. # do_test pager1.4.1.1 { faultsim_delete_and_reopen @@ -635,7 +648,6 @@ testvfs tv -default 1 tv sectorsize 512 tv script copy_on_journal_delete tv filter xDelete -set ::mj_filename_length 0 proc copy_on_journal_delete {method filename args} { if {[string match *journal $filename]} faultsim_save return SQLITE_OK @@ -806,6 +818,43 @@ do_test pager1.4.6.15 { file exists $::mj_filename } {0} db close tv delete +testvfs tv -default 1 +tv sectorsize 512 +tv script copy_on_journal_delete +tv filter xDelete +proc copy_on_journal_delete {method filename args} { + if {[string match *journal $filename]} faultsim_save + return SQLITE_OK +} +faultsim_delete_and_reopen +do_execsql_test pager1.4.7.1 { + CREATE TABLE t1(x PRIMARY KEY, y); + CREATE INDEX i1 ON t1(y); + INSERT INTO t1 VALUES('I', 'one'); + INSERT INTO t1 VALUES('II', 'four'); + INSERT INTO t1 VALUES('III', 'nine'); + BEGIN; + INSERT INTO t1 VALUES('IV', 'sixteen'); + INSERT INTO t1 VALUES('V' , 'twentyfive'); + COMMIT; +} {} +tv filter {} +db close +tv delete +do_test pager1.4.7.2 { + faultsim_restore_and_reopen + catch {file attributes test.db-journal -permissions r--------} + catch {file attributes test.db-journal -readonly 1} + catchsql { SELECT * FROM t1 } +} {1 {unable to open database file}} +do_test pager1.4.7.3 { + db close + catch {file attributes test.db-journal -permissions rw-rw-rw-} + catch {file attributes test.db-journal -readonly 0} + file delete test.db-journal + file exists test.db-journal +} {0} + #------------------------------------------------------------------------- # The following tests deal with multi-file commits. # @@ -1055,6 +1104,7 @@ foreach {tn filename} { db close sqlite3 db $filename execsql { + PRAGMA auto_vacuum = 1; CREATE TABLE x1(x); INSERT INTO x1 VALUES('Charles'); INSERT INTO x1 VALUES('James'); @@ -1378,4 +1428,197 @@ do_execsql_test pager1-14.1.5 { SELECT * FROM t1; } {1 2 3 4 2 2 4 4} +#------------------------------------------------------------------------- +# Test opening and closing the pager sub-system with different values +# for the sqlite3_vfs.szOsFile variable. +# +faultsim_delete_and_reopen +do_execsql_test pager1-15.0 { + CREATE TABLE tx(y, z); + INSERT INTO tx VALUES('Ayutthaya', 'Beijing'); + INSERT INTO tx VALUES('London', 'Tokyo'); +} {} +db close +for {set i 0} {$i<513} {incr i 3} { + testvfs tv -default 1 -szosfile $i + sqlite3 db test.db + do_execsql_test pager1-15.$i.1 { + SELECT * FROM tx; + } {Ayutthaya Beijing London Tokyo} + db close + tv delete +} + +#------------------------------------------------------------------------- +# Check that it is not possible to open a database file if the full path +# to the associated journal file will be longer than sqlite3_vfs.mxPathname. +# +testvfs tv -default 1 +tv script xOpenCb +tv filter xOpen +proc xOpenCb {method filename} { + set ::file_len [string length $filename] +} +sqlite3 db test.db +db close +tv delete + +for {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} { + testvfs tv -default 1 -mxpathname $ii + + # The length of the full path to file "test.db-journal" is ($::file_len+8). + # If the configured sqlite3_vfs.mxPathname value greater than or equal to + # this, then the file can be opened. Otherwise, it cannot. + # + if {$ii >= [expr $::file_len+8]} { + set res {0 {}} + } else { + set res {1 {unable to open database file}} + } + + do_test pager1-16.1.$ii { + list [catch { sqlite3 db test.db } msg] $msg + } $res + + catch {db close} + tv delete +} + +#------------------------------------------------------------------------- +# Test "PRAGMA omit_readlock". +# +# pager1-17.$tn.1.*: Test that if a second connection has an open +# read-transaction, it is not usually possible to write +# the database. +# +# pager1-17.$tn.2.*: Test that if the second connection was opened with +# the SQLITE_OPEN_READONLY flag, and +# "PRAGMA omit_readlock = 1" is executed before attaching +# the database and opening a read-transaction on it, it is +# possible to write the db. +# +# pager1-17.$tn.3.*: Test that if the second connection was *not* opened with +# the SQLITE_OPEN_READONLY flag, executing +# "PRAGMA omit_readlock = 1" has no effect. +# +do_multiclient_test tn { + do_test pager1-17.$tn.1.1 { + sql1 { + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + } + sql2 { + BEGIN; + SELECT * FROM t1; + } + } {1 2} + do_test pager1-17.$tn.1.2 { + csql1 { INSERT INTO t1 VALUES(3, 4) } + } {1 {database is locked}} + do_test pager1-17.$tn.1.3 { + sql2 { COMMIT } + sql1 { INSERT INTO t1 VALUES(3, 4) } + } {} + + do_test pager1-17.$tn.2.1 { + code2 { + db2 close + sqlite3 db2 :memory: -readonly 1 + } + sql2 { + PRAGMA omit_readlock = 1; + ATTACH 'test.db' AS two; + BEGIN; + SELECT * FROM t1; + } + } {1 2 3 4} + do_test pager1-17.$tn.2.2 { sql1 "INSERT INTO t1 VALUES(5, 6)" } {} + do_test pager1-17.$tn.2.3 { sql2 "SELECT * FROM t1" } {1 2 3 4} + do_test pager1-17.$tn.2.4 { sql2 "COMMIT ; SELECT * FROM t1" } {1 2 3 4 5 6} + + do_test pager1-17.$tn.3.1 { + code2 { + db2 close + sqlite3 db2 :memory: + } + sql2 { + PRAGMA omit_readlock = 1; + ATTACH 'test.db' AS two; + BEGIN; + SELECT * FROM t1; + } + } {1 2 3 4 5 6} + do_test pager1-17.$tn.3.2 { + csql1 { INSERT INTO t1 VALUES(3, 4) } + } {1 {database is locked}} + do_test pager1-17.$tn.3.3 { sql2 COMMIT } {} +} + +#------------------------------------------------------------------------- +# Test the pagers response to the b-tree layer requesting illegal page +# numbers: +# +# + The locking page, +# + Page 0, +# + A page with a page number greater than (2^31-1). +# +do_test pager1-18.1 { + faultsim_delete_and_reopen + db func a_string a_string + execsql { + PRAGMA page_size = 1024; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(a_string(500), a_string(200)); + INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; + INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; + INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; + INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; + INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; + INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; + INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; + } +} {} +do_test pager1-18.2 { + set root [db one "SELECT rootpage FROM sqlite_master"] + set lockingpage [expr (0x10000/1024) + 1] + execsql { + PRAGMA writable_schema = 1; + UPDATE sqlite_master SET rootpage = $lockingpage; + } + sqlite3 db2 test.db + catchsql { SELECT count(*) FROM t1 } db2 +} {1 {database disk image is malformed}} +db2 close +do_test pager1-18.3 { + execsql { + CREATE TABLE t2(x); + INSERT INTO t2 VALUES(a_string(5000)); + } + set pgno [expr ([file size test.db] / 1024)-2] + hexio_write test.db [expr ($pgno-1)*1024] 00000000 + sqlite3 db2 test.db + catchsql { SELECT length(x) FROM t2 } db2 +} {1 {database disk image is malformed}} +db2 close +do_test pager1-18.4 { + hexio_write test.db [expr ($pgno-1)*1024] 90000000 + sqlite3 db2 test.db + catchsql { SELECT length(x) FROM t2 } db2 +} {1 {database disk image is malformed}} +db2 close +do_test pager1-18.5 { + sqlite3 db "" + execsql { + CREATE TABLE t1(a, b); + CREATE TABLE t2(a, b); + PRAGMA writable_schema = 1; + UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1'; + PRAGMA writable_schema = 0; + ALTER TABLE t1 RENAME TO x1; + } + catchsql { SELECT * FROM x1 } +} {} +db close + finish_test + diff --git a/test/pagerfault.test b/test/pagerfault.test index 356e7f80c9..9398545c88 100644 --- a/test/pagerfault.test +++ b/test/pagerfault.test @@ -473,26 +473,29 @@ do_faultsim_test pagerfault-9.1 -prep { #------------------------------------------------------------------------- # Test fault injection with a temporary database file. # -do_faultsim_test pagerfault-10 -prep { - sqlite3 db "" - db func a_string a_string; - execsql { - PRAGMA cache_size = 10; - BEGIN; - CREATE TABLE xx(a, b, UNIQUE(a, b)); - INSERT INTO xx VALUES(a_string(200), a_string(200)); - INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; - INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; - INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; - INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; - COMMIT; +foreach v {a b} { + do_faultsim_test pagerfault-10$v -prep { + sqlite3 db "" + db func a_string a_string; + execsql { + PRAGMA cache_size = 10; + BEGIN; + CREATE TABLE xx(a, b, UNIQUE(a, b)); + INSERT INTO xx VALUES(a_string(200), a_string(200)); + INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; + INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; + INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; + INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; + COMMIT; + } + } -body { + execsql { UPDATE xx SET a = a_string(300) } + } -test { + faultsim_test_result {0 {}} + if {$::v == "b"} { execsql { PRAGMA journal_mode = TRUNCATE } } + faultsim_integrity_check + faultsim_integrity_check } -} -body { - execsql { UPDATE xx SET a = a_string(300) } -} -test { - faultsim_test_result {0 {}} - faultsim_integrity_check - faultsim_integrity_check } #------------------------------------------------------------------------- @@ -542,8 +545,10 @@ do_faultsim_test pagerfault-11 -prep { faultsim_integrity_check } -} - +#------------------------------------------------------------------------- +# Test fault injection when writing to a database file that resides on +# a file-system with a sector-size larger than the database page-size. +# do_test pagerfault-12-pre1 { testvfs ss_layer -default 1 ss_layer sectorsize 4096 @@ -580,5 +585,31 @@ do_faultsim_test pagerfault-12 -prep { } +#------------------------------------------------------------------------- +# +do_test pagerfault-13-pre1 { + faultsim_delete_and_reopen + db func a_string a_string; + execsql { + PRAGMA journal_mode = PERSIST; + BEGIN; + CREATE TABLE t1(x, y UNIQUE); + INSERT INTO t1 VALUES(a_string(333), a_string(444)); + COMMIT; + } + db close + file delete -force test.db + faultsim_save +} {} +do_faultsim_test pagerfault-13 -prep { + faultsim_restore_and_reopen +} -body { + execsql { CREATE TABLE xx(a, b) } +} -test { + faultsim_test_result {0 {}} +} + +} + finish_test