]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add tests to pager1.test and pagerfault.test.
authordan <dan@noemail.net>
Tue, 29 Jun 2010 10:30:23 +0000 (10:30 +0000)
committerdan <dan@noemail.net>
Tue, 29 Jun 2010 10:30:23 +0000 (10:30 +0000)
FossilOrigin-Name: 008513ee6115f8d6f4b4e1428c1c638282b971a3

manifest
manifest.uuid
src/test_vfs.c
test/pager1.test
test/pagerfault.test

index 83e4629fb20198f2060742bb16550d5de733a6e6..560407ffc21d1cfd98bc27d2a8441ba30ac623e9 100644 (file)
--- 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
index 838f2c482b12ebd9061649711436454f3519a5cd..d3abf045f323660f80db20743073b0c5c47cc953 100644 (file)
@@ -1 +1 @@
-6b7e419ddc241f457dd69878f09f5c51c70aa379
\ No newline at end of file
+008513ee6115f8d6f4b4e1428c1c638282b971a3
\ No newline at end of file
index 8ae55e7d46d1f0ffb5d42221c045f4b0fd5b3824..ce0642e2c8f24be0c83d3541bf6505a6fd646ace 100644 (file)
 */
 #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<<n)-1) << ofst);
     if( isLock ){
-      TestvfsFile *p2;
+      TestvfsFd *p2;
       for(p2=pFd->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; i<objc; i += 2){
     int nSwitch;
     char *zSwitch;
-
     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;
@@ -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( szOsFile<sizeof(TestvfsFile) ){
+    szOsFile = sizeof(TestvfsFile);
+  }
+
   zVfs = Tcl_GetString(objv[1]);
   nByte = sizeof(Testvfs) + strlen(zVfs)+1;
   p = (Testvfs *)ckalloc(nByte);
@@ -1317,7 +1361,10 @@ static int testvfs_cmd(
   pVfs->pAppData = (void *)p;
   pVfs->zName = p->zName;
   pVfs->mxPathname = p->pParent->mxPathname;
-  pVfs->szOsFile += p->pParent->szOsFile;
+  if( mxPathname>=0 && mxPathname<pVfs->mxPathname ){
+    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;
 }
 
index aa9b2d5b46f1b9257ec10c24542d372022e5ee41..f9e17d4c2afc163e82d6ece94ba88fe435b6dee5 100644 (file)
@@ -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
+
index 356e7f80c9dcb02b1a675290644e440c0812dcae..9398545c88265f9c7640a2d02cb17f1540d73de5 100644 (file)
@@ -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