file:data.db?mode=readonly |
** An error. "readonly" is not a valid option for the "mode" parameter.
**
diff --git a/src/test_vfs.c b/src/test_vfs.c
index 613b0fce77..7ee2a93453 100644
--- a/src/test_vfs.c
+++ b/src/test_vfs.c
@@ -127,8 +127,10 @@ struct Testvfs {
#define TESTVFS_FULLPATHNAME_MASK 0x00008000
#define TESTVFS_READ_MASK 0x00010000
#define TESTVFS_UNLOCK_MASK 0x00020000
+#define TESTVFS_LOCK_MASK 0x00040000
+#define TESTVFS_CKLOCK_MASK 0x00080000
-#define TESTVFS_ALL_MASK 0x0003FFFF
+#define TESTVFS_ALL_MASK 0x000FFFFF
#define TESTVFS_MAX_PAGES 1024
@@ -466,8 +468,15 @@ static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
** Lock an tvfs-file.
*/
static int tvfsLock(sqlite3_file *pFile, int eLock){
- TestvfsFd *p = tvfsGetFd(pFile);
- return sqlite3OsLock(p->pReal, eLock);
+ TestvfsFd *pFd = tvfsGetFd(pFile);
+ Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
+ if( p->pScript && p->mask&TESTVFS_LOCK_MASK ){
+ char zLock[30];
+ sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock);
+ tvfsExecTcl(p, "xLock", Tcl_NewStringObj(pFd->zFilename, -1),
+ Tcl_NewStringObj(zLock, -1), 0, 0);
+ }
+ return sqlite3OsLock(pFd->pReal, eLock);
}
/*
@@ -476,6 +485,12 @@ static int tvfsLock(sqlite3_file *pFile, int eLock){
static int tvfsUnlock(sqlite3_file *pFile, int eLock){
TestvfsFd *pFd = tvfsGetFd(pFile);
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
+ if( p->pScript && p->mask&TESTVFS_UNLOCK_MASK ){
+ char zLock[30];
+ sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock);
+ tvfsExecTcl(p, "xUnlock", Tcl_NewStringObj(pFd->zFilename, -1),
+ Tcl_NewStringObj(zLock, -1), 0, 0);
+ }
if( p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){
return SQLITE_IOERR_UNLOCK;
}
@@ -486,8 +501,13 @@ 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){
- TestvfsFd *p = tvfsGetFd(pFile);
- return sqlite3OsCheckReservedLock(p->pReal, pResOut);
+ TestvfsFd *pFd = tvfsGetFd(pFile);
+ Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
+ if( p->pScript && p->mask&TESTVFS_CKLOCK_MASK ){
+ tvfsExecTcl(p, "xCheckReservedLock", Tcl_NewStringObj(pFd->zFilename, -1),
+ 0, 0, 0);
+ }
+ return sqlite3OsCheckReservedLock(pFd->pReal, pResOut);
}
/*
@@ -1111,26 +1131,32 @@ static int testvfs_obj_cmd(
break;
}
+ /* TESTVFS filter METHOD-LIST
+ **
+ ** Activate special processing for those methods contained in the list
+ */
case CMD_FILTER: {
static struct VfsMethod {
char *zName;
int mask;
} vfsmethod [] = {
- { "xShmOpen", TESTVFS_SHMOPEN_MASK },
- { "xShmLock", TESTVFS_SHMLOCK_MASK },
- { "xShmBarrier", TESTVFS_SHMBARRIER_MASK },
- { "xShmUnmap", TESTVFS_SHMCLOSE_MASK },
- { "xShmMap", TESTVFS_SHMMAP_MASK },
- { "xSync", TESTVFS_SYNC_MASK },
- { "xDelete", TESTVFS_DELETE_MASK },
- { "xWrite", TESTVFS_WRITE_MASK },
- { "xRead", TESTVFS_READ_MASK },
- { "xTruncate", TESTVFS_TRUNCATE_MASK },
- { "xOpen", TESTVFS_OPEN_MASK },
- { "xClose", TESTVFS_CLOSE_MASK },
- { "xAccess", TESTVFS_ACCESS_MASK },
- { "xFullPathname", TESTVFS_FULLPATHNAME_MASK },
- { "xUnlock", TESTVFS_UNLOCK_MASK },
+ { "xShmOpen", TESTVFS_SHMOPEN_MASK },
+ { "xShmLock", TESTVFS_SHMLOCK_MASK },
+ { "xShmBarrier", TESTVFS_SHMBARRIER_MASK },
+ { "xShmUnmap", TESTVFS_SHMCLOSE_MASK },
+ { "xShmMap", TESTVFS_SHMMAP_MASK },
+ { "xSync", TESTVFS_SYNC_MASK },
+ { "xDelete", TESTVFS_DELETE_MASK },
+ { "xWrite", TESTVFS_WRITE_MASK },
+ { "xRead", TESTVFS_READ_MASK },
+ { "xTruncate", TESTVFS_TRUNCATE_MASK },
+ { "xOpen", TESTVFS_OPEN_MASK },
+ { "xClose", TESTVFS_CLOSE_MASK },
+ { "xAccess", TESTVFS_ACCESS_MASK },
+ { "xFullPathname", TESTVFS_FULLPATHNAME_MASK },
+ { "xUnlock", TESTVFS_UNLOCK_MASK },
+ { "xLock", TESTVFS_LOCK_MASK },
+ { "xCheckReservedLock", TESTVFS_CKLOCK_MASK },
};
Tcl_Obj **apElem = 0;
int nElem = 0;
@@ -1162,6 +1188,12 @@ static int testvfs_obj_cmd(
break;
}
+ /*
+ ** TESTVFS script ?SCRIPT?
+ **
+ ** Query or set the script to be run when filtered VFS events
+ ** occur.
+ */
case CMD_SCRIPT: {
if( objc==3 ){
int nByte;
@@ -1248,6 +1280,7 @@ static int testvfs_obj_cmd(
{ "safe_append", SQLITE_IOCAP_SAFE_APPEND },
{ "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN },
{ "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE },
+ { "immutable", SQLITE_IOCAP_IMMUTABLE },
{ 0, 0 }
};
Tcl_Obj *pRet;
diff --git a/test/nolock.test b/test/nolock.test
new file mode 100644
index 0000000000..98ed762cac
--- /dev/null
+++ b/test/nolock.test
@@ -0,0 +1,143 @@
+# 2014-05-07
+#
+# 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.
+#
+#***********************************************************************
+#
+# This file implements regression tests for SQLite library. The
+# focus of this file is testing the nolock=1 and immutable=1 query
+# parameters and the SQLITE_IOCAP_IMMUTABLE device characteristic.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+unset -nocomplain tvfs_calls
+proc tvfs_reset {} {
+ global tvfs_calls
+ array set tvfs_calls {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0}
+}
+proc tvfs_callback {op args} {
+ global tvfs_calls
+ incr tvfs_calls($op)
+ return SQLITE_OK
+}
+tvfs_reset
+
+testvfs tvfs
+tvfs script tvfs_callback
+tvfs filter {xLock xUnlock xCheckReservedLock xAccess}
+
+############################################################################
+# Verify that the nolock=1 query parameter for URI filenames disables all
+# calls to xLock and xUnlock for rollback databases.
+#
+do_test nolock-1.0 {
+ db close
+ forcedelete test.db
+ tvfs_reset
+ sqlite db test.db -vfs tvfs
+ db eval {CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3);}
+ list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
+ xCheckReservedLock $::tvfs_calls(xCheckReservedLock)
+} {xLock 7 xUnlock 5 xCheckReservedLock 0}
+
+do_test nolock-1.1 {
+ db close
+ forcedelete test.db
+ tvfs_reset
+ sqlite db file:test.db?nolock=0 -vfs tvfs -uri 1
+ db eval {CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3);}
+ list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
+ xCheckReservedLock $::tvfs_calls(xCheckReservedLock)
+} {xLock 7 xUnlock 5 xCheckReservedLock 0}
+
+do_test nolock-1.2 {
+ db close
+ forcedelete test.db
+ tvfs_reset
+ sqlite db file:test.db?nolock=1 -vfs tvfs -uri 1
+ db eval {CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3);}
+ list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
+ xCheckReservedLock $::tvfs_calls(xCheckReservedLock)
+} {xLock 0 xUnlock 0 xCheckReservedLock 0}
+
+#############################################################################
+# Verify that immutable=1 disables both locking and xAccess calls to the
+# journal files.
+#
+do_test nolock-2.0 {
+ db close
+ forcedelete test.db
+ # begin by creating a test database
+ sqlite3 db test.db
+ db eval {
+ CREATE TABLE t1(a,b);
+ INSERT INTO t1 VALUES('hello','world');
+ CREATE TABLE t2(x,y);
+ INSERT INTO t2 VALUES(12345,67890);
+ SELECT * FROM t1, t2;
+ }
+} {hello world 12345 67890}
+do_test nolock-2.1 {
+ tvfs_reset
+ sqlite3 db2 test.db -vfs tvfs
+ db2 eval {SELECT * FROM t1, t2}
+} {hello world 12345 67890}
+do_test nolock-2.2 {
+ list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
+ xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
+ xAccess $::tvfs_calls(xAccess)
+} {xLock 2 xUnlock 2 xCheckReservedLock 0 xAccess 4}
+
+
+do_test nolock-2.11 {
+ db2 close
+ tvfs_reset
+ sqlite3 db2 file:test.db?immutable=0 -vfs tvfs -uri 1
+ db2 eval {SELECT * FROM t1, t2}
+} {hello world 12345 67890}
+do_test nolock-2.12 {
+ list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
+ xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
+ xAccess $::tvfs_calls(xAccess)
+} {xLock 2 xUnlock 2 xCheckReservedLock 0 xAccess 4}
+
+
+do_test nolock-2.21 {
+ db2 close
+ tvfs_reset
+ sqlite3 db2 file:test.db?immutable=1 -vfs tvfs -uri 1
+ db2 eval {SELECT * FROM t1, t2}
+} {hello world 12345 67890}
+do_test nolock-2.22 {
+ list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
+ xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
+ xAccess $::tvfs_calls(xAccess)
+} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0}
+
+############################################################################
+# Verify that the SQLITE_IOCAP_IMMUTABLE flag works
+#
+do_test nolock-3.1 {
+ db2 close
+ tvfs devchar immutable
+ tvfs_reset
+ sqlite3 db2 test.db -vfs tvfs
+ db2 eval {SELECT * FROM t1, t2}
+} {hello world 12345 67890}
+do_test nolock-3.2 {
+ list xLock $::tvfs_calls(xLock) xUnlock $::tvfs_calls(xUnlock) \
+ xCheckReservedLock $::tvfs_calls(xCheckReservedLock) \
+ xAccess $::tvfs_calls(xAccess)
+} {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0}
+
+db2 close
+db close
+tvfs delete
+finish_test
|