-C If\san\serror\s(OOM\sor\sSQLITE_FULL\serror)\soccurs\swhile\sexecuting\san\sSQL\sstatement\sand\sa\sstatement-transaction\sis\sautomatically\srolled\sback\sas\sa\sresult,\sif\sa\ssecond\serror\soccurs\sduring\sthe\sstatement\srollback\sdo\sa\sfull\stransaction\srollback\sinstead.\sOtherwise\sthe\sclient\scan\sbe\sleft\swith\san\sinconsistent\scache.
-D 2010-06-03T09:17:38
+C Enhancements\sto\stest_vfs.c\sand\swalfault.test.
+D 2010-06-03T09:25:10
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
-F src/test_vfs.c fe1eda8d3910823d9edc26113f91bb292369850a
+F src/test_vfs.c bae03f62556a11cf5c7c3ea1211a604a3834263a
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
-F test/malloc_common.tcl 7d2478b7f084afd8cb14b1121097ea3d989216b3
+F test/malloc_common.tcl 9b58ffd50d073dccf0493e3ca4aa39bc64ce3047
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
F test/wal.test bfec61450b47cdf09f7d2269f9e9967683b8b0fc
-F test/wal2.test a2146846c4dd940252f18ec1e00431346286bcb3
+F test/wal2.test 1dcbbe59ab662bebb859bb1ede83143f8a39814e
F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432
F test/walcksum.test 4efa8fb88c32bed8288ea4385a9cc113a5c8f0bf
F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
-F test/walfault.test 9015004b56bc2cb8cf5c96183853f1157e61ff70
+F test/walfault.test 058c9e2829fc5e3e01ae4984980a6da9af15368a
F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 91cb08ffb6332a142542c012b58aa49206ee5704
-R efb6b25ebd6ed72f29b742d935423851
+P eb80ddc665132c607c258b59131025a296269dad
+R b8571e46e77ae4334ee4b99c40b16506
U dan
-Z 0bec386ab07ce5c674d40d75eae0944a
+Z a97b394e32c2defcb9f264e6738c31ca
-eb80ddc665132c607c258b59131025a296269dad
\ No newline at end of file
+ac0de2f39e948f3b00e96eebf56ebee70472020d
\ No newline at end of file
sqlite3_vfs *pParent; /* The VFS to use for file IO */
sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */
Tcl_Interp *interp; /* Interpreter to run script in */
+ Tcl_Obj *pScript; /* Script to execute */
int nScript; /* Number of elements in array apScript */
- Tcl_Obj **apScript; /* Script to execute */
+ Tcl_Obj **apScript; /* Array version of pScript */
TestvfsBuffer *pBuffer; /* List of shared buffers */
int isNoshm;
int mask;
int iIoerrCnt;
int ioerr;
+ int nIoerrFail;
};
/*
-** A shared-memory buffer.
+** The Testvfs.mask variable is set to a combination of the following.
+** If a bit is clear in Testvfs.mask, then calls made by SQLite to the
+** corresponding VFS method is ignored for purposes of:
+**
+** + Simulating IO errors, and
+** + Invoking the Tcl callback script.
*/
-struct TestvfsBuffer {
- char *zFile; /* Associated file name */
- int n; /* Size of allocated buffer in bytes */
- u8 *a; /* Buffer allocated using ckalloc() */
- int nRef; /* Number of references to this object */
- TestvfsBuffer *pNext; /* Next in linked list of all buffers */
-};
-
#define TESTVFS_SHMOPEN_MASK 0x00000001
#define TESTVFS_SHMSIZE_MASK 0x00000002
#define TESTVFS_SHMGET_MASK 0x00000004
#define TESTVFS_ALL_MASK 0x0000007F
+/*
+** A shared-memory buffer.
+*/
+struct TestvfsBuffer {
+ char *zFile; /* Associated file name */
+ int n; /* Size of allocated buffer in bytes */
+ u8 *a; /* Buffer allocated using ckalloc() */
+ int nRef; /* Number of references to this object */
+ TestvfsBuffer *pNext; /* Next in linked list of all buffers */
+};
+
#define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent)
+#define TESTVFS_MAX_ARGS 12
+
/*
** Method declarations for TestvfsFile.
){
int rc; /* Return code from Tcl_EvalObj() */
int nArg; /* Elements in eval'd list */
+ int nScript;
+ Tcl_Obj ** ap;
+
+ assert( p->pScript );
+
+ if( !p->apScript ){
+ int nByte;
+ int i;
+ if( TCL_OK!=Tcl_ListObjGetElements(p->interp, p->pScript, &nScript, &ap) ){
+ Tcl_BackgroundError(p->interp);
+ Tcl_ResetResult(p->interp);
+ return;
+ }
+ p->nScript = nScript;
+ nByte = (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *);
+ p->apScript = (Tcl_Obj **)ckalloc(nByte);
+ memset(p->apScript, 0, nByte);
+ for(i=0; i<nScript; i++){
+ p->apScript[i] = ap[i];
+ }
+ }
p->apScript[p->nScript] = Tcl_NewStringObj(zMethod, -1);
p->apScript[p->nScript+1] = arg1;
return 0;
}
+static int tvfsInjectIoerr(Testvfs *p){
+ int ret = 0;
+ if( p->ioerr ){
+ p->iIoerrCnt--;
+ if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){
+ ret = 1;
+ p->nIoerrFail++;
+ }
+ }
+ return ret;
+}
+
static int tvfsShmOpen(
sqlite3_file *pFileDes
){
** script is used as the connection name.
*/
Tcl_ResetResult(p->interp);
- if( p->mask&TESTVFS_SHMOPEN_MASK ){
+ if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){
tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0);
+ if( tvfsResultCode(p, &rc) ){
+ if( rc!=SQLITE_OK ) return rc;
+ }else{
+ pId = Tcl_GetObjResult(p->interp);
+ }
}
- if( tvfsResultCode(p, &rc) ){
- if( rc!=SQLITE_OK ) return rc;
+ if( !pId ){
pId = Tcl_NewStringObj("anon", -1);
- }else{
- pId = Tcl_GetObjResult(p->interp);
}
Tcl_IncrRefCount(pId);
+
+ assert( rc==SQLITE_OK );
+ if( p->mask&TESTVFS_SHMOPEN_MASK && tvfsInjectIoerr(p) ){
+ Tcl_DecrRefCount(pId);
+ return SQLITE_IOERR;
+ }
+
pFd->pShmId = pId;
/* Search for a TestvfsBuffer. Create a new one if required. */
TestvfsFile *pFd = (TestvfsFile *)pFile;
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
- if( p->mask&TESTVFS_SHMSIZE_MASK ){
+ if( p->pScript && p->mask&TESTVFS_SHMSIZE_MASK ){
tvfsExecTcl(p, "xShmSize",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
}
+ if( rc==SQLITE_OK && p->mask&TESTVFS_SHMSIZE_MASK && tvfsInjectIoerr(p) ){
+ rc = SQLITE_IOERR;
+ }
if( rc==SQLITE_OK ){
tvfsGrowBuffer(pFd, reqSize, pNewSize);
}
TestvfsFile *pFd = (TestvfsFile *)pFile;
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
- if( p->mask&TESTVFS_SHMGET_MASK ){
+ if( p->pScript && p->mask&TESTVFS_SHMGET_MASK ){
tvfsExecTcl(p, "xShmGet",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
}
+ if( rc==SQLITE_OK && p->mask&TESTVFS_SHMGET_MASK && tvfsInjectIoerr(p) ){
+ rc = SQLITE_IOERR;
+ }
if( rc==SQLITE_OK ){
tvfsGrowBuffer(pFd, reqMapSize, pMapSize);
*pp = pFd->pShm->a;
TestvfsFile *pFd = (TestvfsFile *)pFile;
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
- if( p->mask&TESTVFS_SHMRELEASE_MASK ){
+ if( p->pScript && p->mask&TESTVFS_SHMRELEASE_MASK ){
tvfsExecTcl(p, "xShmRelease",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
int nLock;
char zLock[80];
- if( p->mask&TESTVFS_SHMLOCK_MASK ){
+ if( p->pScript && p->mask&TESTVFS_SHMLOCK_MASK ){
sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n);
nLock = strlen(zLock);
if( flags & SQLITE_SHM_LOCK ){
TestvfsFile *pFd = (TestvfsFile *)pFile;
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
- if( p->mask&TESTVFS_SHMBARRIER_MASK ){
+ if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){
tvfsExecTcl(p, "xShmBarrier",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
assert( (deleteFlag!=0)==(pBuffer->nRef==1) );
#endif
- if( p->mask&TESTVFS_SHMCLOSE_MASK ){
+ if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){
tvfsExecTcl(p, "xShmClose",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
){
Testvfs *p = (Testvfs *)cd;
- static const char *CMD_strs[] = { "shm", "delete", "filter", "ioerr", 0 };
- enum DB_enum { CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR };
+ static const char *CMD_strs[] = {
+ "shm", "delete", "filter", "ioerr", "script", 0
+ };
+ enum DB_enum {
+ CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT
+ };
+
int i;
if( objc<2 ){
break;
}
+ case CMD_SCRIPT: {
+ if( objc==3 ){
+ int nByte;
+ if( p->pScript ){
+ Tcl_DecrRefCount(p->pScript);
+ ckfree((char *)p->apScript);
+ p->apScript = 0;
+ p->nScript = 0;
+ }
+ Tcl_GetStringFromObj(objv[2], &nByte);
+ if( nByte>0 ){
+ p->pScript = Tcl_DuplicateObj(objv[2]);
+ Tcl_IncrRefCount(p->pScript);
+ }
+ }else if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
+ return TCL_ERROR;
+ }
+
+ Tcl_ResetResult(interp);
+ if( p->pScript ) Tcl_SetObjResult(interp, p->pScript);
+
+ break;
+ }
+
+ /*
+ ** TESTVFS ioerr ?IFAIL PERSIST?
+ **
+ ** Where IFAIL is an integer and PERSIST is boolean.
+ */
case CMD_IOERR: {
- int iRet = ((p->iIoerrCnt<0) ? (1+(p->iIoerrCnt*-1)) : 0);
- if( objc==2 ){
- p->ioerr = 0;
- p->iIoerrCnt = 0;
- }else if( objc==4 ){
+ int iRet = p->nIoerrFail;
+
+ p->nIoerrFail = 0;
+ p->ioerr = 0;
+ p->iIoerrCnt = 0;
+
+ if( objc==4 ){
int iCnt, iPersist;
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt)
|| TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &iPersist)
){
return TCL_ERROR;
}
- p->ioerr = (iPersist!=0) + 1;
+ p->ioerr = (iCnt>0) + iPersist;
p->iIoerrCnt = iCnt;
- }else{
+ }else if( objc!=2 ){
Tcl_AppendResult(interp, "Bad args", 0);
+ return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet));
break;
}
static void testvfs_obj_del(ClientData cd){
- int i;
Testvfs *p = (Testvfs *)cd;
- for(i=0; i<p->nScript; i++){
- Tcl_DecrRefCount(p->apScript[i]);
- }
+ if( p->pScript ) Tcl_DecrRefCount(p->pScript);
sqlite3_vfs_unregister(p->pVfs);
+ ckfree((char *)p->apScript);
ckfree((char *)p->pVfs);
ckfree((char *)p);
}
-#define TESTVFS_MAX_ARGS 12
-
/*
-** Usage: testvfs ?-noshm? VFSNAME SCRIPT
+** Usage: testvfs VFSNAME ?SWITCHES?
+**
+** Switches are:
+**
+** -noshm BOOLEAN (True to omit shm methods. Default false)
+** -default BOOLEAN (True to make the vfs default. Default false)
**
** This command creates two things when it is invoked: an SQLite VFS, and
** a Tcl command. Both are named VFSNAME. The VFS is installed. It is not
Testvfs *p; /* New object */
sqlite3_vfs *pVfs; /* New VFS */
char *zVfs;
- Tcl_Obj *pScript;
- int nScript; /* Number of elements in list pScript */
- Tcl_Obj **apScript; /* Array of pScript elements */
int nByte; /* Bytes of space to allocate at p */
- int i; /* Counter variable */
+
+ int i;
int isNoshm = 0; /* True if -noshm is passed */
+ int isDefault = 0; /* True if -default is passed */
- if( objc<3 ) goto bad_args;
- if( strcmp(Tcl_GetString(objv[1]), "-noshm")==0 ){
- isNoshm = 1;
- }
- if( objc!=3+isNoshm ) goto bad_args;
- zVfs = Tcl_GetString(objv[isNoshm+1]);
- pScript = objv[isNoshm+2];
+ if( objc<2 || 0!=(objc%2) ) goto bad_args;
+ for(i=2; i<objc; i += 2){
+ int nSwitch;
+ char *zSwitch;
- if( TCL_OK!=Tcl_ListObjGetElements(interp, pScript, &nScript, &apScript) ){
- return TCL_ERROR;
+ zSwitch = Tcl_GetStringFromObj(objv[i], &nSwitch);
+ if( nSwitch>2 && 0==strncmp("-noshm", zSwitch, nSwitch) ){
+ if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isNoshm) ){
+ return TCL_ERROR;
+ }
+ }
+ else if( nSwitch>2 && 0==strncmp("-default", zSwitch, nSwitch) ){
+ if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isDefault) ){
+ return TCL_ERROR;
+ }
+ }
+ else{
+ goto bad_args;
+ }
}
- nByte = sizeof(Testvfs)
- + (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *)
- + strlen(zVfs)+1;
+ zVfs = Tcl_GetString(objv[1]);
+ nByte = sizeof(Testvfs) + strlen(zVfs)+1;
p = (Testvfs *)ckalloc(nByte);
memset(p, 0, nByte);
p->pParent = sqlite3_vfs_find(0);
p->interp = interp;
- p->nScript = nScript;
- p->apScript = (Tcl_Obj **)&p[1];
- for(i=0; i<nScript; i++){
- p->apScript[i] = apScript[i];
- Tcl_IncrRefCount(p->apScript[i]);
- }
- p->zName = (char *)&p->apScript[nScript+TESTVFS_MAX_ARGS];
- strcpy(p->zName, zVfs);
+
+ p->zName = (char *)&p[1];
+ memcpy(p->zName, zVfs, strlen(zVfs)+1);
pVfs = (sqlite3_vfs *)ckalloc(sizeof(sqlite3_vfs));
memcpy(pVfs, &tvfs_vfs, sizeof(sqlite3_vfs));
p->mask = TESTVFS_ALL_MASK;
Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
- sqlite3_vfs_register(pVfs, 0);
+ sqlite3_vfs_register(pVfs, isDefault);
return TCL_OK;
bad_args:
- Tcl_WrongNumArgs(interp, 1, objv, "?-noshm? VFSNAME SCRIPT");
+ Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL?");
return TCL_ERROR;
}
return 0
}
+# Transient and persistent OOM errors:
+#
+set FAULTSIM(oom-transient) [list \
+ -injectstart {oom_injectstart 0} \
+ -injectstop oom_injectstop \
+ -injecterrlist {{1 {out of memory}}} \
+]
+set FAULTSIM(oom-persistent) [list \
+ -injectstart {oom_injectstart 1000000} \
+ -injectstop oom_injectstop \
+ -injecterrlist {{1 {out of memory}}} \
+]
+
+# Transient and persistent IO errors:
+#
+set FAULTSIM(ioerr-transient) [list \
+ -injectstart {ioerr_injectstart 0} \
+ -injectstop ioerr_injectstop \
+ -injecterrlist {{1 {disk I/O error}}} \
+]
+set FAULTSIM(ioerr-persistent) [list \
+ -injectstart {ioerr_injectstart 1} \
+ -injectstop ioerr_injectstop \
+ -injecterrlist {{1 {disk I/O error}}} \
+]
+
+# Transient and persistent SHM errors:
+#
+set FAULTSIM(shmerr-transient) [list \
+ -injectinstall shmerr_injectinstall \
+ -injectstart {shmerr_injectstart 0} \
+ -injectstop shmerr_injectstop \
+ -injecterrlist {{1 {disk I/O error}}} \
+ -injectuninstall shmerr_injectuninstall \
+]
+set FAULTSIM(shmerr-persistent) [list \
+ -injectinstall shmerr_injectinstall \
+ -injectstart {shmerr_injectstart 1} \
+ -injectstop shmerr_injectstop \
+ -injecterrlist {{1 {disk I/O error}}} \
+ -injectuninstall shmerr_injectuninstall \
+]
+
+
#--------------------------------------------------------------------------
# Usage do_faultsim_test NAME ?OPTIONS...?
# -test Script to execute after -body.
#
proc do_faultsim_test {name args} {
- set DEFAULT(-faults) [list \
- oom-transient oom-persistent \
- ioerr-transient ioerr-persistent \
- ]
+ global FAULTSIM
+
+ set DEFAULT(-faults) [array names FAULTSIM]
set DEFAULT(-prep) ""
set DEFAULT(-body) ""
set DEFAULT(-test) ""
if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" }
}
- set A(oom-transient) [list \
- -injectstart {oom_injectstart 0} \
- -injectstop oom_injectstop \
- -injecterrlist {{1 {out of memory}}} \
- ]
- set A(oom-persistent) [list \
- -injectstart {oom_injectstart 1000000} \
- -injectstop oom_injectstop \
- -injecterrlist {{1 {out of memory}}} \
- ]
-
- set A(ioerr-transient) [list \
- -injectstart {ioerr_injectstart 0} \
- -injectstop ioerr_injectstop \
- -injecterrlist {{1 {disk I/O error}}} \
- ]
-
- set A(ioerr-persistent) [list \
- -injectstart {ioerr_injectstart 1} \
- -injectstop ioerr_injectstop \
- -injecterrlist {{1 {disk I/O error}}} \
- ]
-
+ set faultlist [list]
foreach f $O(-faults) {
- if {[info exists A($f)]==0} { error "unknown fault: $f" }
+ set flist [array names FAULTSIM $f]
+ if {[llength $flist]==0} { error "unknown fault: $f" }
+ set faultlist [concat $faultlist $flist]
}
+
set testspec [list -prep $O(-prep) -body $O(-body) -test $O(-test)]
- foreach f $O(-faults) {
- eval do_one_faultsim_test "$name-$f" $A($f) $testspec
+ foreach f [lsort -unique $faultlist] {
+ eval do_one_faultsim_test "$name-$f" $FAULTSIM($f) $testspec
}
}
sqlite3_db_config_lookaside db 0 0 0
}
+proc faultsim_integrity_check {{db db}} {
+ set ic [$db eval { PRAGMA integrity_check }]
+ if {$ic != "ok"} { error "Integrity check: $ic" }
+}
+
+proc faultsim_delete_and_reopen {{file test.db}} {
+ catch { db close }
+ file delete -force test.db test.db-wal test.db-journal
+ sqlite3 db test.db
+}
+
-# The following procs are used as [do_faultsim_test] when injecting OOM
-# faults into test cases.
+# The following procs are used as [do_one_faultsim_test] callbacks when
+# injecting OOM faults into test cases.
#
proc oom_injectstart {nRepeat iFail} {
sqlite3_memdebug_fail $iFail -repeat $nRepeat
sqlite3_memdebug_fail -1
}
+# The following procs are used as [do_one_faultsim_test] callbacks when
+# injecting IO error faults into test cases.
+#
proc ioerr_injectstart {persist iFail} {
set ::sqlite_io_error_persist $persist
set ::sqlite_io_error_pending $iFail
return $sv
}
+# The following procs are used as [do_one_faultsim_test] callbacks when
+# injecting shared-memory related error faults into test cases.
+#
+proc shmerr_injectinstall {} {
+ testvfs shmfault -default true
+}
+proc shmerr_injectuninstall {} {
+ catch {db close}
+ catch {db2 close}
+ shmfault delete
+}
+proc shmerr_injectstart {persist iFail} {
+ shmfault ioerr $iFail $persist
+}
+proc shmerr_injectstop {} {
+ shmfault ioerr 0 0
+}
+
# This command is not called directly. It is used by the
# [faultsim_test_result] command created by [do_faultsim_test] and used
# by -test scripts.
# -injecterrlist List of generally acceptable test results (i.e. error
# messages). Example: [list {1 {out of memory}}]
#
+# -injectinstall
+#
+# -injectuninstall
+#
# -prep Script to execute before -body.
#
# -body Script to execute (with fault injection).
#
proc do_one_faultsim_test {testname args} {
- set DEFAULT(-injectstart) {oom_injectstart 0}
- set DEFAULT(-injectstop) {oom_injectstop}
- set DEFAULT(-injecterrlist) [list {1 {out of memory}}]
- set DEFAULT(-prep) ""
- set DEFAULT(-body) ""
- set DEFAULT(-test) ""
+ set DEFAULT(-injectstart) "expr"
+ set DEFAULT(-injectstop) "expr 0"
+ set DEFAULT(-injecterrlist) [list]
+ set DEFAULT(-injectinstall) ""
+ set DEFAULT(-injectuninstall) ""
+ set DEFAULT(-prep) ""
+ set DEFAULT(-body) ""
+ set DEFAULT(-test) ""
array set O [array get DEFAULT]
array set O $args
uplevel faultsim_test_result_int \$args [list $O(-injecterrlist)]
"
+ eval $O(-injectinstall)
+
set stop 0
for {set iFail 1} {!$stop} {incr iFail} {
#
if {$nfail==0} { set stop 1 }
}
+
+ eval $O(-injectuninstall)
}
# Usage: do_malloc_test <test number> <options...>
#
do_test wal2-1.0 {
proc tvfs_cb {method args} { return SQLITE_OK }
- testvfs tvfs tvfs_cb
+ testvfs tvfs
+ tvfs script tvfs_cb
sqlite3 db test.db -vfs tvfs
sqlite3 db2 test.db -vfs tvfs
]
do_test wal2-2.0 {
- testvfs tvfs tvfs_cb
+ testvfs tvfs
+ tvfs script tvfs_cb
proc tvfs_cb {method args} {
if {$method == "xShmOpen"} { set ::shm_file [lindex $args 0] }
return SQLITE_OK
return 0
}
- testvfs tvfs tvfs_cb
+ testvfs tvfs
+ tvfs script tvfs_cb
sqlite3 db test.db -vfs tvfs
db busy busyhandler
} {wal}
do_test wal2-4.2 {
db close
- proc ok {args} {return SQLITE_OK}
- testvfs -noshm tvfs ok
+ testvfs tvfs -noshm 1
sqlite3 db test.db -vfs tvfs
catchsql { SELECT * FROM data }
} {1 {unable to open database file}}
do_test wal2-4.3 {
db close
- proc ok {args} {return SQLITE_OK}
- testvfs tvfs ok
+ testvfs tvfs
sqlite3 db test.db -vfs tvfs
catchsql { SELECT * FROM data }
} {0 {{need xShmOpen to see this}}}
}
set tvfs_cb_return SQLITE_OK
- testvfs tvfs tvfs_cb
+ testvfs tvfs
+ tvfs script tvfs_cb
sqlite3 db test.db -vfs tvfs
execsql {
if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
return "SQLITE_OK"
}
- testvfs tvfs tvfs_cb
+ testvfs tvfs
+ tvfs script tvfs_cb
sqlite3 db test.db -vfs tvfs
} {}
} -body {
execsql { SELECT count(*) FROM x }
} -test {
-
faultsim_test_result {0 8}
-
- # Run the integrity_check to make sure nothing strange has occurred.
- #
- set ic [db eval { PRAGMA integrity_check }]
- if {$ic != "ok"} { error "Integrity check: $ic" }
+ faultsim_integrity_check
}
#--------------------------------------------------------------------------
faultsim_test_result {0 {}}
}
-# A [testvfs] callback for the VFS created by [do_shmfault_test]. This
-# callback injects SQLITE_IOERR faults into methods for which an entry
-# in array ::shmfault_ioerr_methods is defined. For example, to enable
-# errors in xShmOpen:
-#
-# set ::shmfault_ioerr_methods(xShmOpen) 1
-#
-# Faults are not injected into xShmRelease, xShmClose or xShmLock method
-# calls. The global tcl variables used are:
-#
-# $::shmfault_ioerr_countdown
-# $::shmfault_ioerr_persist
-#
-proc shmfault_vfs_cb {method args} {
-
- # If ::shmfault_ioerr_countdown is not set, always return SQLITE_OK.
- #
- if {[info exists ::shmfault_ioerr_countdown]==0} { return SQLITE_OK }
-
- incr ::shmfault_ioerr_countdown -1
- if { ($::shmfault_ioerr_countdown==0)
- || ($::shmfault_ioerr_countdown<=0 && $::shmfault_ioerr_persist)
- } {
- return SQLITE_IOERR
+file delete -force test.db test.db-wal test.db-journal
+faultsim_save_and_close
+do_faultsim_test walfault-4 -prep {
+ faultsim_restore_and_reopen
+} -body {
+ execsql {
+ PRAGMA journal_mode = WAL;
+ CREATE TABLE t1(a PRIMARY KEY, b);
+ INSERT INTO t1 VALUES('a', 'b');
+ PRAGMA wal_checkpoint;
+ SELECT * FROM t1;
}
- return SQLITE_OK
-}
-
-# Options are:
-#
-# -tclprep TCL
-# -sqlprep SQL
-# -sqlbody SQL
-#
-proc do_shmfault_test {name args} {
-
- set A(-tclprep) "sqlite3 db test.db -vfs shmfault"
- set A(-sqlprep) ""
- set A(-sqlbody) ""
- set A(-methods) [list xShmGet xShmOpen xShmSize]
- set A(-coverageonly) 0
- array set A $args
-
- # Create a VFS to use:
- testvfs shmfault shmfault_vfs_cb
- shmfault filter $A(-methods)
-
- foreach mode {transient persistent} {
- set ::shmfault_ioerr_persist [expr {$mode == "persistent"}]
-
- for {set nDelay 1} {$nDelay < 10000} {incr nDelay} {
-
- file delete -force test.db test.db-wal test.db-journal
-
- eval $A(-tclprep)
- db eval $A(-sqlprep)
-
- set ::shmfault_ioerr_countdown $nDelay
- set rc [catch { db eval $A(-sqlbody) } msg]
- set hit_error [expr {$::shmfault_ioerr_countdown<=0}]
- unset ::shmfault_ioerr_countdown
+} -test {
+ faultsim_test_result {0 {wal a b}}
+ faultsim_integrity_check
+}
- catch { db close }
-
- if {$A(-coverageonly)} { set rc $hit_error }
- do_test $name-$mode.$nDelay.1 [list set {} $hit_error] $rc
-
- if {$hit_error==0} break
- }
+do_test walfault-5-pre-1 {
+ catch { db close }
+ file delete -force test.db test.db-wal test.db-journal
+ sqlite3 db test.db
+ execsql {
+ PRAGMA page_size = 512;
+ PRAGMA journal_mode = WAL;
}
-
- shmfault delete
-}
-
-do_shmfault_test walfault-shm-1 -sqlbody {
- PRAGMA journal_mode = WAL;
- CREATE TABLE t1(a PRIMARY KEY, b);
- INSERT INTO t1 VALUES('a', 'b');
- PRAGMA wal_checkpoint;
+ faultsim_save_and_close
+} {}
+do_faultsim_test walfault-5 -faults shmerr* -prep {
+ faultsim_restore_and_reopen
+ execsql { PRAGMA wal_autocheckpoint = 0 }
+ shmfault filter xShmSize
+} -body {
+ execsql {
+ CREATE TABLE t1(x);
+ BEGIN;
+ INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */
+ INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
+ COMMIT;
+ SELECT count(*) FROM t1;
+ }
+} -test {
+ faultsim_test_result {0 16384}
+ faultsim_integrity_check
}
-do_shmfault_test walfault-shm-2 -methods xShmSize -sqlprep {
- PRAGMA page_size = 512;
- PRAGMA journal_mode = WAL;
- PRAGMA wal_autocheckpoint = 0;
-} -sqlbody {
- CREATE TABLE t1(x);
- BEGIN;
- INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */
- INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
- COMMIT;
-}
-do_shmfault_test walfault-shm-3 -methods xShmSize -tclprep {
- sqlite3 db test.db -vfs shmfault
- shmfault filter {}
- db eval {
+do_test walfault-6-pre-1 {
+ catch { db close }
+ file delete -force test.db test.db-wal test.db-journal
+ sqlite3 db test.db
+ execsql {
PRAGMA page_size = 512;
PRAGMA journal_mode = WAL;
PRAGMA wal_autocheckpoint = 0;
INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
COMMIT;
}
-
- set ::shmfault_ioerr_countdown 1
- shmfault filter xShmGet
- db close
- shmfault filter {}
- if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}
-
- sqlite3 db test.db -vfs shmfault
-} -sqlbody {
- SELECT count(*) FROM t1;
+ faultsim_save_and_close
+} {}
+do_faultsim_test walfault-6 -faults shmerr* -prep {
+ faultsim_restore_and_reopen
+ shmfault filter xShmSize
+} -body {
+ execsql { SELECT count(*) FROM t1 }
+} -test {
+ faultsim_test_result {0 16384}
+ faultsim_integrity_check
+ set n [db one {SELECT count(*) FROM t1}]
+ if {$n != 16384 && $n != 0} { error "Incorrect number of rows: $n" }
}
-do_shmfault_test walfault-shm-4 -tclprep {
- sqlite3 db test.db -vfs shmfault
- unset -nocomplain ::shmfault_ioerr_countdown
- db eval {
+do_test walfault-7-pre-1 {
+ faultsim_delete_and_reopen
+ execsql {
PRAGMA page_size = 512;
PRAGMA journal_mode = WAL;
PRAGMA wal_autocheckpoint = 0;
INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
COMMIT;
}
-
- set ::shmfault_ioerr_countdown 1
- shmfault filter xShmGet
- db close
- shmfault filter {}
- if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}
- sqlite3 db test.db -vfs shmfault
-} -sqlbody {
- SELECT count(*) FROM t1;
+ faultsim_save_and_close
+} {}
+do_faultsim_test walfault-7 -prep {
+ faultsim_restore_and_reopen
+} -body {
+ execsql { SELECT count(*) FROM t1 }
+} -test {
+ faultsim_test_result {0 4}
+ set n [db one {SELECT count(*) FROM t1}]
+ if {$n != 4 && $n != 0} { error "Incorrect number of rows: $n" }
}
-do_shmfault_test walfault-shm-5.1 -coverageonly 1 -sqlprep {
- PRAGMA cache_size = 10;
- PRAGMA journal_mode = WAL;
- CREATE TABLE abc(a PRIMARY KEY);
- INSERT INTO abc VALUES(randomblob(900));
-} -sqlbody {
- BEGIN;
- INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
- INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */
- INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
- INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
- ROLLBACK;
+do_test walfault-8-pre-1 {
+ faultsim_delete_and_reopen
+ execsql {
+ PRAGMA journal_mode = WAL;
+ CREATE TABLE abc(a PRIMARY KEY);
+ INSERT INTO abc VALUES(randomblob(900));
+ }
+ faultsim_save_and_close
+} {}
+do_faultsim_test walfault-8 -prep {
+ faultsim_restore_and_reopen
+ execsql { PRAGMA cache_size = 10 }
+} -body {
+ execsql {
+ BEGIN;
+ INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
+ --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */
+ --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
+ --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
+ ROLLBACK;
+ SELECT count(*) FROM abc;
+ }
+} -test {
+ faultsim_test_result {0 1}
+
+ faultsim_integrity_check
+ catch { db eval ROLLBACK }
+ faultsim_integrity_check
+
+ set n [db one {SELECT count(*) FROM abc}]
+ if {$n != 1} { error "Incorrect number of rows: $n" }
}
-do_shmfault_test walfault-shm-5.2 -coverageonly 1 -sqlprep {
- PRAGMA cache_size = 10;
- PRAGMA journal_mode = WAL;
- CREATE TABLE abc(a PRIMARY KEY);
- INSERT INTO abc VALUES(randomblob(900));
-} -sqlbody {
- BEGIN;
- INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
- SAVEPOINT spoint;
- INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */
- INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
- INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
- ROLLBACK TO spoint;
- COMMIT;
+do_test walfault-9-pre-1 {
+ faultsim_delete_and_reopen
+ execsql {
+ PRAGMA journal_mode = WAL;
+ CREATE TABLE abc(a PRIMARY KEY);
+ INSERT INTO abc VALUES(randomblob(900));
+ }
+ faultsim_save_and_close
+} {}
+do_faultsim_test walfault-9 -prep {
+ #if {$iFail<73} { set iFail 73 }
+ #if {$iFail>73} { exit }
+
+ faultsim_restore_and_reopen
+ execsql { PRAGMA cache_size = 10 }
+} -body {
+ execsql {
+ BEGIN;
+ INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
+ SAVEPOINT spoint;
+ INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */
+ INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
+ INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
+ ROLLBACK TO spoint;
+ COMMIT;
+ SELECT count(*) FROM abc;
+ }
+} -test {
+ faultsim_test_result {0 2}
+ faultsim_integrity_check
+
+ catch { db eval { ROLLBACK TO spoint } }
+ catch { db eval { COMMIT } }
+ set n [db one {SELECT count(*) FROM abc}]
+ if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" }
}
#-------------------------------------------------------------------------
}
do_test walfault-shm-6.1 {
set ::shm_state 0
- testvfs tvfs shmfault_vfs_cb_6
+ testvfs tvfs
+ tvfs script shmfault_vfs_cb_6
sqlite3 db test.db -vfs tvfs
sqlite3 db2 test.db -vfs tvfs