Annotation of embedaddon/sqlite3/test/wal2.test, revision 1.1

1.1     ! misho       1: # 2010 May 5
        !             2: #
        !             3: # The author disclaims copyright to this source code.  In place of
        !             4: # a legal notice, here is a blessing:
        !             5: #
        !             6: #    May you do good and not evil.
        !             7: #    May you find forgiveness for yourself and forgive others.
        !             8: #    May you share freely, never taking more than you give.
        !             9: #
        !            10: #***********************************************************************
        !            11: # This file implements regression tests for SQLite library.  The
        !            12: # focus of this file is testing the operation of the library in
        !            13: # "PRAGMA journal_mode=WAL" mode.
        !            14: #
        !            15: 
        !            16: set testdir [file dirname $argv0]
        !            17: source $testdir/tester.tcl
        !            18: source $testdir/lock_common.tcl
        !            19: source $testdir/malloc_common.tcl
        !            20: source $testdir/wal_common.tcl
        !            21: 
        !            22: set testprefix wal2
        !            23: 
        !            24: ifcapable !wal {finish_test ; return }
        !            25: 
        !            26: set sqlite_sync_count 0
        !            27: proc cond_incr_sync_count {adj} {
        !            28:   global sqlite_sync_count
        !            29:   if {$::tcl_platform(platform) == "windows"} {
        !            30:     incr sqlite_sync_count $adj
        !            31:   } {
        !            32:     ifcapable !dirsync {
        !            33:       incr sqlite_sync_count $adj
        !            34:     }
        !            35:   }
        !            36: }
        !            37: 
        !            38: proc set_tvfs_hdr {file args} {
        !            39: 
        !            40:   # Set $nHdr to the number of bytes in the wal-index header:
        !            41:   set nHdr 48
        !            42:   set nInt [expr {$nHdr/4}]
        !            43: 
        !            44:   if {[llength $args]>2} {
        !            45:     error {wrong # args: should be "set_tvfs_hdr fileName ?val1? ?val2?"}
        !            46:   }
        !            47: 
        !            48:   set blob [tvfs shm $file]
        !            49: 
        !            50:   if {[llength $args]} {
        !            51:     set ia [lindex $args 0]
        !            52:     set ib $ia
        !            53:     if {[llength $args]==2} {
        !            54:       set ib [lindex $args 1]
        !            55:     }
        !            56:     binary scan $blob a[expr $nHdr*2]a* dummy tail
        !            57:     set blob [binary format i${nInt}i${nInt}a* $ia $ib $tail]
        !            58:     tvfs shm $file $blob
        !            59:   }
        !            60: 
        !            61:   binary scan $blob i${nInt} ints
        !            62:   return $ints
        !            63: }
        !            64: 
        !            65: proc incr_tvfs_hdr {file idx incrval} {
        !            66:   set ints [set_tvfs_hdr $file]
        !            67:   set v [lindex $ints $idx]
        !            68:   incr v $incrval
        !            69:   lset ints $idx $v
        !            70:   set_tvfs_hdr $file $ints
        !            71: }
        !            72: 
        !            73: 
        !            74: #-------------------------------------------------------------------------
        !            75: # Test case wal2-1.*:
        !            76: #
        !            77: # Set up a small database containing a single table. The database is not
        !            78: # checkpointed during the test - all content resides in the log file.
        !            79: #
        !            80: # Two connections are established to the database file - a writer ([db])
        !            81: # and a reader ([db2]). For each of the 8 integer fields in the wal-index
        !            82: # header (6 fields and 2 checksum values), do the following:
        !            83: #
        !            84: #   1. Modify the database using the writer.
        !            85: #
        !            86: #   2. Attempt to read the database using the reader. Before the reader
        !            87: #      has a chance to snapshot the wal-index header, increment one
        !            88: #      of the the integer fields (so that the reader ends up with a corrupted
        !            89: #      header).
        !            90: #
        !            91: #   3. Check that the reader recovers the wal-index and reads the correct
        !            92: #      database content.
        !            93: #
        !            94: do_test wal2-1.0 {
        !            95:   proc tvfs_cb {method filename args} { 
        !            96:     set ::filename $filename
        !            97:     return SQLITE_OK 
        !            98:   }
        !            99: 
        !           100:   testvfs tvfs
        !           101:   tvfs script tvfs_cb
        !           102:   tvfs filter xShmOpen
        !           103: 
        !           104:   sqlite3 db  test.db -vfs tvfs
        !           105:   sqlite3 db2 test.db -vfs tvfs
        !           106: 
        !           107:   execsql {
        !           108:     PRAGMA journal_mode = WAL;
        !           109:     CREATE TABLE t1(a);
        !           110:   } db2
        !           111:   execsql {
        !           112:     INSERT INTO t1 VALUES(1);
        !           113:     INSERT INTO t1 VALUES(2);
        !           114:     INSERT INTO t1 VALUES(3);
        !           115:     INSERT INTO t1 VALUES(4);
        !           116:     SELECT count(a), sum(a) FROM t1;
        !           117:   }
        !           118: } {4 10}
        !           119: do_test wal2-1.1 {
        !           120:   execsql { SELECT count(a), sum(a) FROM t1 } db2
        !           121: } {4 10}
        !           122: 
        !           123: set RECOVER [list                                      \
        !           124:   {0 1 lock exclusive}   {1 7 lock exclusive}          \
        !           125:   {1 7 unlock exclusive} {0 1 unlock exclusive}        \
        !           126: ]
        !           127: set READ [list                                         \
        !           128:   {4 1 lock exclusive} {4 1 unlock exclusive}          \
        !           129:   {4 1 lock shared}    {4 1 unlock shared}             \
        !           130: ]
        !           131: 
        !           132: foreach {tn iInsert res wal_index_hdr_mod wal_locks} "
        !           133:          2    5   {5 15}    0             {$RECOVER $READ}
        !           134:          3    6   {6 21}    1             {$RECOVER $READ}
        !           135:          4    7   {7 28}    2             {$RECOVER $READ}
        !           136:          5    8   {8 36}    3             {$RECOVER $READ}
        !           137:          6    9   {9 45}    4             {$RECOVER $READ}
        !           138:          7   10   {10 55}   5             {$RECOVER $READ}
        !           139:          8   11   {11 66}   6             {$RECOVER $READ}
        !           140:          9   12   {12 78}   7             {$RECOVER $READ}
        !           141:         10   13   {13 91}   8             {$RECOVER $READ}
        !           142:         11   14   {14 105}  9             {$RECOVER $READ}
        !           143:         12   15   {15 120}  -1            {$READ}
        !           144: " {
        !           145: 
        !           146:   do_test wal2-1.$tn.1 {
        !           147:     execsql { INSERT INTO t1 VALUES($iInsert) }
        !           148:     set ::locks [list]
        !           149:     proc tvfs_cb {method args} {
        !           150:       lappend ::locks [lindex $args 2]
        !           151:       return SQLITE_OK
        !           152:     }
        !           153:     tvfs filter xShmLock
        !           154:     if {$::wal_index_hdr_mod >= 0} {
        !           155:       incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1
        !           156:     }
        !           157:     execsql { SELECT count(a), sum(a) FROM t1 } db2
        !           158:   } $res
        !           159: 
        !           160:   do_test wal2-1.$tn.2 {
        !           161:     set ::locks
        !           162:   } $wal_locks
        !           163: }
        !           164: db close
        !           165: db2 close
        !           166: tvfs delete
        !           167: forcedelete test.db test.db-wal test.db-journal
        !           168: 
        !           169: #-------------------------------------------------------------------------
        !           170: # This test case is very similar to the previous one, except, after
        !           171: # the reader reads the corrupt wal-index header, but before it has
        !           172: # a chance to re-read it under the cover of the RECOVER lock, the
        !           173: # wal-index header is replaced with a valid, but out-of-date, header.
        !           174: #
        !           175: # Because the header checksum looks Ok, the reader does not run recovery,
        !           176: # it simply drops back to a READ lock and proceeds. But because the
        !           177: # header is out-of-date, the reader reads the out-of-date snapshot.
        !           178: #
        !           179: # After this, the header is corrupted again and the reader is allowed
        !           180: # to run recovery. This time, it sees an up-to-date snapshot of the
        !           181: # database file.
        !           182: #
        !           183: set WRITER [list 0 1 lock exclusive]
        !           184: set LOCKS  [list \
        !           185:   {0 1 lock exclusive} {0 1 unlock exclusive} \
        !           186:   {4 1 lock exclusive} {4 1 unlock exclusive} \
        !           187:   {4 1 lock shared}    {4 1 unlock shared}    \
        !           188: ]
        !           189: do_test wal2-2.0 {
        !           190: 
        !           191:   testvfs tvfs
        !           192:   tvfs script tvfs_cb
        !           193:   tvfs filter xShmOpen
        !           194:   proc tvfs_cb {method args} {
        !           195:     set ::filename [lindex $args 0]
        !           196:     return SQLITE_OK
        !           197:   }
        !           198: 
        !           199:   sqlite3 db  test.db -vfs tvfs
        !           200:   sqlite3 db2 test.db -vfs tvfs
        !           201: 
        !           202:   execsql {
        !           203:     PRAGMA journal_mode = WAL;
        !           204:     CREATE TABLE t1(a);
        !           205:   } db2
        !           206:   execsql {
        !           207:     INSERT INTO t1 VALUES(1);
        !           208:     INSERT INTO t1 VALUES(2);
        !           209:     INSERT INTO t1 VALUES(3);
        !           210:     INSERT INTO t1 VALUES(4);
        !           211:     SELECT count(a), sum(a) FROM t1;
        !           212:   }
        !           213: } {4 10}
        !           214: do_test wal2-2.1 {
        !           215:   execsql { SELECT count(a), sum(a) FROM t1 } db2
        !           216: } {4 10}
        !           217: 
        !           218: foreach {tn iInsert res0 res1 wal_index_hdr_mod} {
        !           219:          2    5   {4 10}   {5 15}    0
        !           220:          3    6   {5 15}   {6 21}    1
        !           221:          4    7   {6 21}   {7 28}    2
        !           222:          5    8   {7 28}   {8 36}    3
        !           223:          6    9   {8 36}   {9 45}    4
        !           224:          7   10   {9 45}   {10 55}   5
        !           225:          8   11   {10 55}  {11 66}   6
        !           226:          9   12   {11 66}  {12 78}   7
        !           227: } {
        !           228:   tvfs filter xShmLock
        !           229: 
        !           230:   do_test wal2-2.$tn.1 {
        !           231:     set oldhdr [set_tvfs_hdr $::filename]
        !           232:     execsql { INSERT INTO t1 VALUES($iInsert) }
        !           233:     execsql { SELECT count(a), sum(a) FROM t1 }
        !           234:   } $res1
        !           235: 
        !           236:   do_test wal2-2.$tn.2 {
        !           237:     set ::locks [list]
        !           238:     proc tvfs_cb {method args} {
        !           239:       set lock [lindex $args 2]
        !           240:       lappend ::locks $lock
        !           241:       if {$lock == $::WRITER} {
        !           242:         set_tvfs_hdr $::filename $::oldhdr
        !           243:       }
        !           244:       return SQLITE_OK
        !           245:     }
        !           246: 
        !           247:     if {$::wal_index_hdr_mod >= 0} {
        !           248:       incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1
        !           249:     }
        !           250:     execsql { SELECT count(a), sum(a) FROM t1 } db2
        !           251:   } $res0
        !           252: 
        !           253:   do_test wal2-2.$tn.3 {
        !           254:     set ::locks
        !           255:   } $LOCKS
        !           256: 
        !           257:   do_test wal2-2.$tn.4 {
        !           258:     set ::locks [list]
        !           259:     proc tvfs_cb {method args} {
        !           260:       set lock [lindex $args 2]
        !           261:       lappend ::locks $lock
        !           262:       return SQLITE_OK
        !           263:     }
        !           264: 
        !           265:     if {$::wal_index_hdr_mod >= 0} {
        !           266:       incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1
        !           267:     }
        !           268:     execsql { SELECT count(a), sum(a) FROM t1 } db2
        !           269:   } $res1
        !           270: }
        !           271: db close
        !           272: db2 close
        !           273: tvfs delete
        !           274: forcedelete test.db test.db-wal test.db-journal
        !           275: 
        !           276: 
        !           277: if 0 {
        !           278: #-------------------------------------------------------------------------
        !           279: # This test case - wal2-3.* - tests the response of the library to an
        !           280: # SQLITE_BUSY when attempting to obtain a READ or RECOVER lock.
        !           281: #
        !           282: #   wal2-3.0 - 2: SQLITE_BUSY when obtaining a READ lock
        !           283: #   wal2-3.3 - 6: SQLITE_BUSY when obtaining a RECOVER lock
        !           284: #
        !           285: do_test wal2-3.0 {
        !           286:   proc tvfs_cb {method args} {
        !           287:     if {$method == "xShmLock"} {
        !           288:       if {[info exists ::locked]} { return SQLITE_BUSY }
        !           289:     }
        !           290:     return SQLITE_OK
        !           291:   }
        !           292: 
        !           293:   proc busyhandler x {
        !           294:     if {$x>3} { unset -nocomplain ::locked }
        !           295:     return 0
        !           296:   }
        !           297: 
        !           298:   testvfs tvfs
        !           299:   tvfs script tvfs_cb
        !           300:   sqlite3 db test.db -vfs tvfs
        !           301:   db busy busyhandler
        !           302: 
        !           303:   execsql {
        !           304:     PRAGMA journal_mode = WAL;
        !           305:     CREATE TABLE t1(a);
        !           306:     INSERT INTO t1 VALUES(1);
        !           307:     INSERT INTO t1 VALUES(2);
        !           308:     INSERT INTO t1 VALUES(3);
        !           309:     INSERT INTO t1 VALUES(4);
        !           310:   } 
        !           311: 
        !           312:   set ::locked 1
        !           313:   info exists ::locked
        !           314: } {1}
        !           315: do_test wal2-3.1 {
        !           316:   execsql { SELECT count(a), sum(a) FROM t1 }
        !           317: } {4 10}
        !           318: do_test wal2-3.2 {
        !           319:   info exists ::locked
        !           320: } {0}
        !           321: 
        !           322: do_test wal2-3.3 {
        !           323:   proc tvfs_cb {method args} {
        !           324:     if {$method == "xShmLock"} {
        !           325:       if {[info exists ::sabotage]} {
        !           326:         unset -nocomplain ::sabotage
        !           327:         incr_tvfs_hdr [lindex $args 0] 1 1
        !           328:       }
        !           329:       if {[info exists ::locked] && [lindex $args 2] == "RECOVER"} {
        !           330:         return SQLITE_BUSY
        !           331:       }
        !           332:     }
        !           333:     return SQLITE_OK
        !           334:   }
        !           335:   set ::sabotage 1
        !           336:   set ::locked 1
        !           337:   list [info exists ::sabotage] [info exists ::locked]
        !           338: } {1 1}
        !           339: do_test wal2-3.4 {
        !           340:   execsql { SELECT count(a), sum(a) FROM t1 }
        !           341: } {4 10}
        !           342: do_test wal2-3.5 {
        !           343:   list [info exists ::sabotage] [info exists ::locked]
        !           344: } {0 0}
        !           345: db close
        !           346: tvfs delete
        !           347: forcedelete test.db test.db-wal test.db-journal
        !           348: 
        !           349: }
        !           350: 
        !           351: #-------------------------------------------------------------------------
        !           352: # Test that a database connection using a VFS that does not support the
        !           353: # xShmXXX interfaces cannot open a WAL database.
        !           354: #
        !           355: do_test wal2-4.1 {
        !           356:   sqlite3 db test.db
        !           357:   execsql {
        !           358:     PRAGMA auto_vacuum = 0;
        !           359:     PRAGMA journal_mode = WAL;
        !           360:     CREATE TABLE data(x);
        !           361:     INSERT INTO data VALUES('need xShmOpen to see this');
        !           362:     PRAGMA wal_checkpoint;
        !           363:   }
        !           364:   # Three pages in the WAL file at this point: One copy of page 1 and two
        !           365:   # of the root page for table "data".
        !           366: } {wal 0 3 3}
        !           367: do_test wal2-4.2 {
        !           368:   db close
        !           369:   testvfs tvfs -noshm 1
        !           370:   sqlite3 db test.db -vfs tvfs
        !           371:   catchsql { SELECT * FROM data }
        !           372: } {1 {unable to open database file}}
        !           373: do_test wal2-4.3 {
        !           374:   db close
        !           375:   testvfs tvfs
        !           376:   sqlite3 db test.db -vfs tvfs
        !           377:   catchsql { SELECT * FROM data }
        !           378: } {0 {{need xShmOpen to see this}}}
        !           379: db close
        !           380: tvfs delete
        !           381: 
        !           382: #-------------------------------------------------------------------------
        !           383: # Test that if a database connection is forced to run recovery before it
        !           384: # can perform a checkpoint, it does not transition into RECOVER state.
        !           385: #
        !           386: # UPDATE: This has now changed. When running a checkpoint, if recovery is
        !           387: # required the client grabs all exclusive locks (just as it would for a
        !           388: # recovery performed as a pre-cursor to a normal database transaction).
        !           389: #
        !           390: set expected_locks [list]
        !           391: lappend expected_locks {1 1 lock exclusive}   ;# Lock checkpoint
        !           392: lappend expected_locks {0 1 lock exclusive}   ;# Lock writer
        !           393: lappend expected_locks {2 6 lock exclusive}   ;# Lock recovery & all aReadMark[]
        !           394: lappend expected_locks {2 6 unlock exclusive} ;# Unlock recovery & aReadMark[]
        !           395: lappend expected_locks {0 1 unlock exclusive} ;# Unlock writer
        !           396: lappend expected_locks {3 1 lock exclusive}   ;# Lock aReadMark[0]
        !           397: lappend expected_locks {3 1 unlock exclusive} ;# Unlock aReadMark[0]
        !           398: lappend expected_locks {1 1 unlock exclusive} ;# Unlock checkpoint
        !           399: do_test wal2-5.1 {
        !           400:   proc tvfs_cb {method args} {
        !           401:     set ::shm_file [lindex $args 0]
        !           402:     if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
        !           403:     return $::tvfs_cb_return
        !           404:   }
        !           405:   set tvfs_cb_return SQLITE_OK
        !           406: 
        !           407:   testvfs tvfs
        !           408:   tvfs script tvfs_cb
        !           409: 
        !           410:   sqlite3 db test.db -vfs tvfs
        !           411:   execsql {
        !           412:     PRAGMA journal_mode = WAL;
        !           413:     CREATE TABLE x(y);
        !           414:     INSERT INTO x VALUES(1);
        !           415:   }
        !           416: 
        !           417:   incr_tvfs_hdr $::shm_file 1 1
        !           418:   set ::locks [list]
        !           419:   execsql { PRAGMA wal_checkpoint }
        !           420:   set ::locks
        !           421: } $expected_locks
        !           422: db close
        !           423: tvfs delete
        !           424: 
        !           425: #-------------------------------------------------------------------------
        !           426: # This block, test cases wal2-6.*, tests the operation of WAL with
        !           427: # "PRAGMA locking_mode=EXCLUSIVE" set.
        !           428: #
        !           429: #   wal2-6.1.*: Changing to WAL mode before setting locking_mode=exclusive.
        !           430: #
        !           431: #   wal2-6.2.*: Changing to WAL mode after setting locking_mode=exclusive.
        !           432: #
        !           433: #   wal2-6.3.*: Changing back to rollback mode from WAL mode after setting 
        !           434: #               locking_mode=exclusive.
        !           435: #
        !           436: #   wal2-6.4.*: Check that xShmLock calls are omitted in exclusive locking
        !           437: #               mode.
        !           438: #
        !           439: #   wal2-6.5.*: 
        !           440: #
        !           441: #   wal2-6.6.*: Check that if the xShmLock() to reaquire a WAL read-lock when
        !           442: #               exiting exclusive mode fails (i.e. SQLITE_IOERR), then the
        !           443: #               connection silently remains in exclusive mode.
        !           444: #
        !           445: do_test wal2-6.1.1 {
        !           446:   forcedelete test.db test.db-wal test.db-journal
        !           447:   sqlite3 db test.db
        !           448:   execsql {
        !           449:     Pragma Journal_Mode = Wal;
        !           450:   }
        !           451: } {wal}
        !           452: do_test wal2-6.1.2 {
        !           453:   execsql { PRAGMA lock_status }
        !           454: } {main unlocked temp closed}
        !           455: do_test wal2-6.1.3 {
        !           456:   execsql {
        !           457:     SELECT * FROM sqlite_master;
        !           458:     Pragma Locking_Mode = Exclusive;
        !           459:   }
        !           460:   execsql {
        !           461:     BEGIN;
        !           462:       CREATE TABLE t1(a, b);
        !           463:       INSERT INTO t1 VALUES(1, 2);
        !           464:     COMMIT;
        !           465:     PRAGMA lock_status;
        !           466:   }
        !           467: } {main exclusive temp closed}
        !           468: do_test wal2-6.1.4 {
        !           469:   execsql { 
        !           470:     PRAGMA locking_mode = normal; 
        !           471:     PRAGMA lock_status;
        !           472:   }
        !           473: } {normal main exclusive temp closed}
        !           474: do_test wal2-6.1.5 {
        !           475:   execsql { 
        !           476:     SELECT * FROM t1;
        !           477:     PRAGMA lock_status;
        !           478:   }
        !           479: } {1 2 main shared temp closed}
        !           480: do_test wal2-6.1.6 {
        !           481:   execsql {
        !           482:     INSERT INTO t1 VALUES(3, 4);
        !           483:     PRAGMA lock_status;
        !           484:   }
        !           485: } {main shared temp closed}
        !           486: db close
        !           487: 
        !           488: do_test wal2-6.2.1 {
        !           489:   forcedelete test.db test.db-wal test.db-journal
        !           490:   sqlite3 db test.db
        !           491:   execsql {
        !           492:     Pragma Locking_Mode = Exclusive;
        !           493:     Pragma Journal_Mode = Wal;
        !           494:     Pragma Lock_Status;
        !           495:   }
        !           496: } {exclusive wal main exclusive temp closed}
        !           497: do_test wal2-6.2.2 {
        !           498:   execsql {
        !           499:     BEGIN;
        !           500:       CREATE TABLE t1(a, b);
        !           501:       INSERT INTO t1 VALUES(1, 2);
        !           502:     COMMIT;
        !           503:     Pragma loCK_STATus;
        !           504:   }
        !           505: } {main exclusive temp closed}
        !           506: do_test wal2-6.2.3 {
        !           507:   db close
        !           508:   sqlite3 db test.db
        !           509:   execsql { SELECT * FROM sqlite_master }
        !           510:   execsql { PRAGMA LOCKING_MODE = EXCLUSIVE }
        !           511: } {exclusive}
        !           512: do_test wal2-6.2.4 {
        !           513:   execsql {
        !           514:     SELECT * FROM t1;
        !           515:     pragma lock_status;
        !           516:   }
        !           517: } {1 2 main shared temp closed}
        !           518: do_test wal2-6.2.5 {
        !           519:   execsql {
        !           520:     INSERT INTO t1 VALUES(3, 4);
        !           521:     pragma lock_status;
        !           522:   }
        !           523: } {main exclusive temp closed}
        !           524: do_test wal2-6.2.6 {
        !           525:   execsql {
        !           526:     PRAGMA locking_mode = NORMAL;
        !           527:     pragma lock_status;
        !           528:   }
        !           529: } {normal main exclusive temp closed}
        !           530: do_test wal2-6.2.7 {
        !           531:   execsql {
        !           532:     BEGIN IMMEDIATE; COMMIT;
        !           533:     pragma lock_status;
        !           534:   }
        !           535: } {main shared temp closed}
        !           536: do_test wal2-6.2.8 {
        !           537:   execsql {
        !           538:     PRAGMA locking_mode = EXCLUSIVE;
        !           539:     BEGIN IMMEDIATE; COMMIT;
        !           540:     PRAGMA locking_mode = NORMAL;
        !           541:   }
        !           542:   execsql {
        !           543:     SELECT * FROM t1;
        !           544:     pragma lock_status;
        !           545:   }
        !           546: } {1 2 3 4 main shared temp closed}
        !           547: do_test wal2-6.2.9 {
        !           548:   execsql {
        !           549:     INSERT INTO t1 VALUES(5, 6);
        !           550:     SELECT * FROM t1;
        !           551:     pragma lock_status;
        !           552:   }
        !           553: } {1 2 3 4 5 6 main shared temp closed}
        !           554: db close
        !           555: 
        !           556: do_test wal2-6.3.1 {
        !           557:   forcedelete test.db test.db-wal test.db-journal
        !           558:   sqlite3 db test.db
        !           559:   execsql {
        !           560:     PRAGMA journal_mode = WAL;
        !           561:     PRAGMA locking_mode = exclusive;
        !           562:     BEGIN;
        !           563:       CREATE TABLE t1(x);
        !           564:       INSERT INTO t1 VALUES('Chico');
        !           565:       INSERT INTO t1 VALUES('Harpo');
        !           566:     COMMIT;
        !           567:   }
        !           568:   list [file exists test.db-wal] [file exists test.db-journal]
        !           569: } {1 0}
        !           570: do_test wal2-6.3.2 {
        !           571:   execsql { PRAGMA journal_mode = DELETE }
        !           572:   file exists test.db-wal
        !           573: } {0}
        !           574: do_test wal2-6.3.3 {
        !           575:   execsql { PRAGMA lock_status }
        !           576: } {main exclusive temp closed}
        !           577: do_test wal2-6.3.4 {
        !           578:   execsql { 
        !           579:     BEGIN;
        !           580:       INSERT INTO t1 VALUES('Groucho');
        !           581:   }
        !           582:   list [file exists test.db-wal] [file exists test.db-journal]
        !           583: } {0 1}
        !           584: do_test wal2-6.3.5 {
        !           585:   execsql { PRAGMA lock_status }
        !           586: } {main exclusive temp closed}
        !           587: do_test wal2-6.3.6 {
        !           588:   execsql { COMMIT }
        !           589:   list [file exists test.db-wal] [file exists test.db-journal]
        !           590: } {0 1}
        !           591: do_test wal2-6.3.7 {
        !           592:   execsql { PRAGMA lock_status }
        !           593: } {main exclusive temp closed}
        !           594: db close
        !           595: 
        !           596: 
        !           597: # This test - wal2-6.4.* - uses a single database connection and the
        !           598: # [testvfs] instrumentation to test that xShmLock() is being called
        !           599: # as expected when a WAL database is used with locking_mode=exclusive.
        !           600: #
        !           601: do_test wal2-6.4.1 {
        !           602:   forcedelete test.db test.db-wal test.db-journal
        !           603:   proc tvfs_cb {method args} {
        !           604:     set ::shm_file [lindex $args 0]
        !           605:     if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
        !           606:     return "SQLITE_OK"
        !           607:   }
        !           608:   testvfs tvfs
        !           609:   tvfs script tvfs_cb
        !           610:   sqlite3 db test.db -vfs tvfs
        !           611:   set {} {}
        !           612: } {}
        !           613: 
        !           614: set RECOVERY {
        !           615:   {0 1 lock exclusive} {1 7 lock exclusive} 
        !           616:   {1 7 unlock exclusive} {0 1 unlock exclusive}
        !           617: }
        !           618: set READMARK0_READ {
        !           619:   {3 1 lock shared} {3 1 unlock shared}
        !           620: }
        !           621: set READMARK0_WRITE {
        !           622:   {3 1 lock shared} 
        !           623:   {0 1 lock exclusive} {3 1 unlock shared} 
        !           624:   {4 1 lock exclusive} {4 1 unlock exclusive} {4 1 lock shared} 
        !           625:   {0 1 unlock exclusive} {4 1 unlock shared}
        !           626: }
        !           627: set READMARK1_SET {
        !           628:   {4 1 lock exclusive} {4 1 unlock exclusive}
        !           629: }
        !           630: set READMARK1_READ {
        !           631:   {4 1 lock shared} {4 1 unlock shared}
        !           632: }
        !           633: set READMARK1_WRITE {
        !           634:   {4 1 lock shared} 
        !           635:     {0 1 lock exclusive} {0 1 unlock exclusive} 
        !           636:   {4 1 unlock shared}
        !           637: }
        !           638: 
        !           639: foreach {tn sql res expected_locks} {
        !           640:   2 {
        !           641:     PRAGMA auto_vacuum = 0;
        !           642:     PRAGMA journal_mode = WAL;
        !           643:     BEGIN;
        !           644:       CREATE TABLE t1(x);
        !           645:       INSERT INTO t1 VALUES('Leonard');
        !           646:       INSERT INTO t1 VALUES('Arthur');
        !           647:     COMMIT;
        !           648:   } {wal} {
        !           649:     $RECOVERY 
        !           650:     $READMARK0_WRITE
        !           651:   }
        !           652: 
        !           653:   3 {
        !           654:     # This test should do the READMARK1_SET locking to populate the 
        !           655:     # aReadMark[1] slot with the current mxFrame value. Followed by
        !           656:     # READMARK1_READ to read the database.
        !           657:     #
        !           658:     SELECT * FROM t1
        !           659:   } {Leonard Arthur} {
        !           660:     $READMARK1_SET
        !           661:     $READMARK1_READ
        !           662:   }
        !           663: 
        !           664:   4 {
        !           665:     # aReadMark[1] is already set to mxFrame. So just READMARK1_READ
        !           666:     # this time, not READMARK1_SET.
        !           667:     #
        !           668:     SELECT * FROM t1 ORDER BY x
        !           669:   } {Arthur Leonard} { 
        !           670:     $READMARK1_READ 
        !           671:   }
        !           672: 
        !           673:   5 {
        !           674:     PRAGMA locking_mode = exclusive
        !           675:   } {exclusive} { } 
        !           676: 
        !           677:   6 {
        !           678:     INSERT INTO t1 VALUES('Julius Henry');
        !           679:     SELECT * FROM t1;
        !           680:   } {Leonard Arthur {Julius Henry}} {
        !           681:     $READMARK1_READ
        !           682:   }
        !           683: 
        !           684:   7 {
        !           685:     INSERT INTO t1 VALUES('Karl');
        !           686:     SELECT * FROM t1;
        !           687:   } {Leonard Arthur {Julius Henry} Karl} { }
        !           688: 
        !           689:   8 {
        !           690:     PRAGMA locking_mode = normal
        !           691:   } {normal} { }
        !           692: 
        !           693:   9 {
        !           694:     SELECT * FROM t1 ORDER BY x
        !           695:   } {Arthur {Julius Henry} Karl Leonard} $READMARK1_READ
        !           696: 
        !           697:   10 { DELETE FROM t1 } {} $READMARK1_WRITE
        !           698: 
        !           699:   11 {
        !           700:     SELECT * FROM t1
        !           701:   } {} {
        !           702:     $READMARK1_SET
        !           703:     $READMARK1_READ
        !           704:   }
        !           705: } {
        !           706: 
        !           707:   set L [list]
        !           708:   foreach el [subst $expected_locks] { lappend L $el }
        !           709: 
        !           710:   set S ""
        !           711:   foreach sq [split $sql "\n"] { 
        !           712:     set sq [string trim $sq]
        !           713:     if {[string match {#*} $sq]==0} {append S "$sq\n"}
        !           714:   }
        !           715: 
        !           716:   set ::locks [list]
        !           717:   do_test wal2-6.4.$tn.1 { execsql $S } $res
        !           718:   do_test wal2-6.4.$tn.2 { set ::locks  } $L
        !           719: }
        !           720: 
        !           721: db close
        !           722: tvfs delete
        !           723: 
        !           724: do_test wal2-6.5.1 {
        !           725:   sqlite3 db test.db
        !           726:   execsql {
        !           727:     PRAGMA auto_vacuum = 0;
        !           728:     PRAGMA journal_mode = wal;
        !           729:     PRAGMA locking_mode = exclusive;
        !           730:     CREATE TABLE t2(a, b);
        !           731:     PRAGMA wal_checkpoint;
        !           732:     INSERT INTO t2 VALUES('I', 'II');
        !           733:     PRAGMA journal_mode;
        !           734:   }
        !           735: } {wal exclusive 0 2 2 wal}
        !           736: do_test wal2-6.5.2 {
        !           737:   execsql {
        !           738:     PRAGMA locking_mode = normal;
        !           739:     INSERT INTO t2 VALUES('III', 'IV');
        !           740:     PRAGMA locking_mode = exclusive;
        !           741:     SELECT * FROM t2;
        !           742:   }
        !           743: } {normal exclusive I II III IV}
        !           744: do_test wal2-6.5.3 {
        !           745:   execsql { PRAGMA wal_checkpoint }
        !           746: } {0 2 2}
        !           747: db close
        !           748: 
        !           749: proc lock_control {method filename handle spec} {
        !           750:   foreach {start n op type} $spec break
        !           751:   if {$op == "lock"} { return SQLITE_IOERR }
        !           752:   return SQLITE_OK
        !           753: }
        !           754: do_test wal2-6.6.1 {
        !           755:   testvfs T
        !           756:   T script lock_control
        !           757:   T filter {}
        !           758:   sqlite3 db test.db -vfs T
        !           759:   execsql { SELECT * FROM sqlite_master }
        !           760:   execsql { PRAGMA locking_mode = exclusive }
        !           761:   execsql { INSERT INTO t2 VALUES('V', 'VI') }
        !           762: } {}
        !           763: do_test wal2-6.6.2 {
        !           764:   execsql { PRAGMA locking_mode = normal }
        !           765:   T filter xShmLock
        !           766:   execsql { INSERT INTO t2 VALUES('VII', 'VIII') }
        !           767: } {}
        !           768: do_test wal2-6.6.3 {
        !           769:   # At this point the connection should still be in exclusive-mode, even
        !           770:   # though it tried to exit exclusive-mode when committing the INSERT
        !           771:   # statement above. To exit exclusive mode, SQLite has to take a read-lock 
        !           772:   # on the WAL file using xShmLock(). Since that call failed, it remains
        !           773:   # in exclusive mode.
        !           774:   #
        !           775:   sqlite3 db2 test.db -vfs T
        !           776:   catchsql { SELECT * FROM t2 } db2
        !           777: } {1 {database is locked}}
        !           778: do_test wal2-6.6.2 {
        !           779:   db2 close
        !           780:   T filter {}
        !           781:   execsql { INSERT INTO t2 VALUES('IX', 'X') }
        !           782: } {}
        !           783: do_test wal2-6.6.4 {
        !           784:   # This time, we have successfully exited exclusive mode. So the second
        !           785:   # connection can read the database.
        !           786:   sqlite3 db2 test.db -vfs T
        !           787:   catchsql { SELECT * FROM t2 } db2
        !           788: } {0 {I II III IV V VI VII VIII IX X}}
        !           789: 
        !           790: db close
        !           791: db2 close
        !           792: T delete
        !           793: 
        !           794: #-------------------------------------------------------------------------
        !           795: # Test a theory about the checksum algorithm. Theory was false and this
        !           796: # test did not provoke a bug.
        !           797: #
        !           798: forcedelete test.db test.db-wal test.db-journal
        !           799: do_test wal2-7.1.1 {
        !           800:   sqlite3 db test.db
        !           801:   execsql {
        !           802:     PRAGMA page_size = 4096;
        !           803:     PRAGMA journal_mode = WAL;
        !           804:     CREATE TABLE t1(a, b);
        !           805:   }
        !           806:   file size test.db
        !           807: } {4096}
        !           808: do_test wal2-7.1.2 {
        !           809:   forcecopy test.db test2.db
        !           810:   forcecopy test.db-wal test2.db-wal
        !           811:   hexio_write test2.db-wal 48 FF
        !           812: } {1}
        !           813: do_test wal2-7.1.3 {
        !           814:   sqlite3 db2 test2.db
        !           815:   execsql { PRAGMA wal_checkpoint } db2
        !           816:   execsql { SELECT * FROM sqlite_master } db2
        !           817: } {}
        !           818: db close
        !           819: db2 close
        !           820: forcedelete test.db test.db-wal test.db-journal
        !           821: do_test wal2-8.1.2 {
        !           822:   sqlite3 db test.db
        !           823:   execsql {
        !           824:     PRAGMA auto_vacuum=OFF;
        !           825:     PRAGMA page_size = 1024;
        !           826:     PRAGMA journal_mode = WAL;
        !           827:     CREATE TABLE t1(x);
        !           828:     INSERT INTO t1 VALUES(zeroblob(8188*1020));
        !           829:     CREATE TABLE t2(y);
        !           830:     PRAGMA wal_checkpoint;
        !           831:   }
        !           832:   execsql {
        !           833:     SELECT rootpage>=8192 FROM sqlite_master WHERE tbl_name = 't2';
        !           834:   }
        !           835: } {1}
        !           836: do_test wal2-8.1.3 {
        !           837:   execsql {
        !           838:     PRAGMA cache_size = 10;
        !           839:     CREATE TABLE t3(z);
        !           840:     BEGIN;
        !           841:       INSERT INTO t3 VALUES(randomblob(900));
        !           842:       INSERT INTO t3 SELECT randomblob(900) FROM t3;
        !           843:       INSERT INTO t2 VALUES('hello');
        !           844:       INSERT INTO t3 SELECT randomblob(900) FROM t3;
        !           845:       INSERT INTO t3 SELECT randomblob(900) FROM t3;
        !           846:       INSERT INTO t3 SELECT randomblob(900) FROM t3;
        !           847:       INSERT INTO t3 SELECT randomblob(900) FROM t3;
        !           848:       INSERT INTO t3 SELECT randomblob(900) FROM t3;
        !           849:       INSERT INTO t3 SELECT randomblob(900) FROM t3;
        !           850:     ROLLBACK;
        !           851:   }
        !           852:   execsql {
        !           853:     INSERT INTO t2 VALUES('goodbye');
        !           854:     INSERT INTO t3 SELECT randomblob(900) FROM t3;
        !           855:     INSERT INTO t3 SELECT randomblob(900) FROM t3;
        !           856:   }
        !           857: } {}
        !           858: do_test wal2-8.1.4 {
        !           859:   sqlite3 db2 test.db
        !           860:   execsql { SELECT * FROM t2 }
        !           861: } {goodbye}
        !           862: db2 close
        !           863: db close
        !           864: 
        !           865: #-------------------------------------------------------------------------
        !           866: # Test that even if the checksums for both are valid, if the two copies
        !           867: # of the wal-index header in the wal-index do not match, the client
        !           868: # runs (or at least tries to run) database recovery.
        !           869: # 
        !           870: #
        !           871: proc get_name {method args} { set ::filename [lindex $args 0] ; tvfs filter {} }
        !           872: testvfs tvfs
        !           873: tvfs script get_name
        !           874: tvfs filter xShmOpen
        !           875: 
        !           876: forcedelete test.db test.db-wal test.db-journal
        !           877: do_test wal2-9.1 {
        !           878:   sqlite3 db test.db -vfs tvfs
        !           879:   execsql {
        !           880:     PRAGMA journal_mode = WAL;
        !           881:     CREATE TABLE x(y);
        !           882:     INSERT INTO x VALUES('Barton');
        !           883:     INSERT INTO x VALUES('Deakin');
        !           884:   }
        !           885: 
        !           886:   # Set $wih(1) to the contents of the wal-index header after
        !           887:   # the frames associated with the first two rows in table 'x' have
        !           888:   # been inserted. Then insert one more row and set $wih(2)
        !           889:   # to the new value of the wal-index header.
        !           890:   #
        !           891:   # If the $wih(1) is written into the wal-index before running
        !           892:   # a read operation, the client will see only the first two rows. If
        !           893:   # $wih(2) is written into the wal-index, the client will see
        !           894:   # three rows. If an invalid header is written into the wal-index, then
        !           895:   # the client will run recovery and see three rows.
        !           896:   #
        !           897:   set wih(1) [set_tvfs_hdr $::filename]
        !           898:   execsql { INSERT INTO x VALUES('Watson') }
        !           899:   set wih(2) [set_tvfs_hdr $::filename]
        !           900: 
        !           901:   sqlite3 db2 test.db -vfs tvfs
        !           902:   execsql { SELECT * FROM x } db2
        !           903: } {Barton Deakin Watson}
        !           904: 
        !           905: foreach {tn hdr1 hdr2 res} [list                                            \
        !           906:   3  $wih(1)                $wih(1)                {Barton Deakin}          \
        !           907:   4  $wih(1)                $wih(2)                {Barton Deakin Watson}   \
        !           908:   5  $wih(2)                $wih(1)                {Barton Deakin Watson}   \
        !           909:   6  $wih(2)                $wih(2)                {Barton Deakin Watson}   \
        !           910:   7  $wih(1)                $wih(1)                {Barton Deakin}          \
        !           911:   8  {0 0 0 0 0 0 0 0 0 0 0 0} {0 0 0 0 0 0 0 0 0 0 0 0} {Barton Deakin Watson}
        !           912: ] {
        !           913:   do_test wal2-9.$tn {
        !           914:     set_tvfs_hdr $::filename $hdr1 $hdr2
        !           915:     execsql { SELECT * FROM x } db2
        !           916:   } $res
        !           917: }
        !           918: 
        !           919: db2 close
        !           920: db close
        !           921: 
        !           922: #-------------------------------------------------------------------------
        !           923: # This block of tests - wal2-10.* - focus on the libraries response to
        !           924: # new versions of the wal or wal-index formats. 
        !           925: #
        !           926: #   wal2-10.1.*: Test that the library refuses to "recover" a new WAL 
        !           927: #                format.
        !           928: #
        !           929: #   wal2-10.2.*: Test that the library refuses to read or write a database
        !           930: #                if the wal-index version is newer than it understands.
        !           931: #
        !           932: # At time of writing, the only versions of the wal and wal-index formats
        !           933: # that exist are versions 3007000 (corresponding to SQLite version 3.7.0,
        !           934: # the first version of SQLite to feature wal mode).
        !           935: #
        !           936: do_test wal2-10.1.1 {
        !           937:   faultsim_delete_and_reopen
        !           938:   execsql {
        !           939:     PRAGMA journal_mode = WAL;
        !           940:     CREATE TABLE t1(a, b);
        !           941:     PRAGMA wal_checkpoint;
        !           942:     INSERT INTO t1 VALUES(1, 2);
        !           943:     INSERT INTO t1 VALUES(3, 4);
        !           944:   }
        !           945:   faultsim_save_and_close
        !           946: } {}
        !           947: do_test wal2-10.1.2 {
        !           948:   faultsim_restore_and_reopen
        !           949:   execsql { SELECT * FROM t1 }
        !           950: } {1 2 3 4}
        !           951: do_test wal2-10.1.3 {
        !           952:   faultsim_restore_and_reopen
        !           953:   set hdr [wal_set_walhdr test.db-wal]
        !           954:   lindex $hdr 1
        !           955: } {3007000}
        !           956: do_test wal2-10.1.4 {
        !           957:   lset hdr 1 3007001
        !           958:   wal_set_walhdr test.db-wal $hdr
        !           959:   catchsql { SELECT * FROM t1 }
        !           960: } {1 {unable to open database file}}
        !           961: 
        !           962: testvfs tvfs -default 1
        !           963: do_test wal2-10.2.1 {
        !           964:   faultsim_restore_and_reopen
        !           965:   execsql { SELECT * FROM t1 }
        !           966: } {1 2 3 4}
        !           967: do_test wal2-10.2.2        !           968:   set hdr [set_tvfs_hdr $::filename] 
        !           969:   lindex $hdr 0 
        !           970: } {3007000}
        !           971: do_test wal2-10.2.3        !           972:   lset hdr 0 3007001
        !           973:   wal_fix_walindex_cksum hdr 
        !           974:   set_tvfs_hdr $::filename $hdr
        !           975:   catchsql { SELECT * FROM t1 }
        !           976: } {1 {unable to open database file}}
        !           977: db close
        !           978: tvfs delete
        !           979: 
        !           980: #-------------------------------------------------------------------------
        !           981: # This block of tests - wal2-11.* - tests that it is not possible to put
        !           982: # the library into an infinite loop by presenting it with a corrupt
        !           983: # hash table (one that appears to contain a single chain of infinite 
        !           984: # length).
        !           985: #
        !           986: #   wal2-11.1.*: While reading the hash-table.
        !           987: #
        !           988: #   wal2-11.2.*: While writing the hash-table.
        !           989: #
        !           990: testvfs tvfs -default 1
        !           991: do_test wal2-11.0 {
        !           992:   faultsim_delete_and_reopen
        !           993:   execsql {
        !           994:     PRAGMA journal_mode = WAL;
        !           995:     CREATE TABLE t1(a, b, c);
        !           996:     INSERT INTO t1 VALUES(1, 2, 3);
        !           997:     INSERT INTO t1 VALUES(4, 5, 6);
        !           998:     INSERT INTO t1 VALUES(7, 8, 9);
        !           999:     SELECT * FROM t1;
        !          1000:   }
        !          1001: } {wal 1 2 3 4 5 6 7 8 9}
        !          1002: 
        !          1003: do_test wal2-11.1.1 {
        !          1004:   sqlite3 db2 test.db
        !          1005:   execsql { SELECT name FROM sqlite_master } db2
        !          1006: } {t1}
        !          1007: 
        !          1008: if {$::tcl_version>=8.5} {
        !          1009:   # Set all zeroed slots in the first hash table to invalid values.
        !          1010:   #
        !          1011:   set blob [string range [tvfs shm $::filename] 0 16383]
        !          1012:   set I [string range [tvfs shm $::filename] 16384 end]
        !          1013:   binary scan $I t* L
        !          1014:   set I [list]
        !          1015:   foreach p $L {
        !          1016:     lappend I [expr $p ? $p : 400]
        !          1017:   }
        !          1018:   append blob [binary format t* $I]
        !          1019:   tvfs shm $::filename $blob
        !          1020:   do_test wal2-11.2 {
        !          1021:     catchsql { INSERT INTO t1 VALUES(10, 11, 12) }
        !          1022:   } {1 {database disk image is malformed}}
        !          1023:   
        !          1024:   # Fill up the hash table on the first page of shared memory with 0x55 bytes.
        !          1025:   #
        !          1026:   set blob [string range [tvfs shm $::filename] 0 16383]
        !          1027:   append blob [string repeat [binary format c 55] 16384]
        !          1028:   tvfs shm $::filename $blob
        !          1029:   do_test wal2-11.3 {
        !          1030:     catchsql { SELECT * FROM t1 } db2
        !          1031:   } {1 {database disk image is malformed}}
        !          1032: }
        !          1033: 
        !          1034: db close
        !          1035: db2 close
        !          1036: tvfs delete
        !          1037: 
        !          1038: #-------------------------------------------------------------------------
        !          1039: # If a connection is required to create a WAL or SHM file, it creates 
        !          1040: # the new files with the same file-system permissions as the database 
        !          1041: # file itself. Test this.
        !          1042: #
        !          1043: if {$::tcl_platform(platform) == "unix"} {
        !          1044:   faultsim_delete_and_reopen
        !          1045:   set umask [exec /bin/sh -c umask]
        !          1046: 
        !          1047:   do_test wal2-12.1 {
        !          1048:     sqlite3 db test.db
        !          1049:     execsql { 
        !          1050:       CREATE TABLE tx(y, z);
        !          1051:       PRAGMA journal_mode = WAL;
        !          1052:     }
        !          1053:     db close
        !          1054:     list [file exists test.db-wal] [file exists test.db-shm]
        !          1055:   } {0 0}
        !          1056:   
        !          1057:   foreach {tn permissions} {
        !          1058:    1 00644
        !          1059:    2 00666
        !          1060:    3 00600
        !          1061:    4 00755
        !          1062:   } {
        !          1063:     set effective [format %.5o [expr $permissions & ~$umask]]
        !          1064:     do_test wal2-12.2.$tn.1 {
        !          1065:       file attributes test.db -permissions $permissions
        !          1066:       file attributes test.db -permissions
        !          1067:     } $permissions
        !          1068:     do_test wal2-12.2.$tn.2 {
        !          1069:       list [file exists test.db-wal] [file exists test.db-shm]
        !          1070:     } {0 0}
        !          1071:     do_test wal2-12.2.$tn.3 {
        !          1072:       sqlite3 db test.db
        !          1073:       execsql { INSERT INTO tx DEFAULT VALUES }
        !          1074:       list [file exists test.db-wal] [file exists test.db-shm]
        !          1075:     } {1 1}
        !          1076:     do_test wal2-12.2.$tn.4 {
        !          1077:       list [file attr test.db-wal -perm] [file attr test.db-shm -perm]
        !          1078:     } [list $effective $effective]
        !          1079:     do_test wal2-12.2.$tn.5 {
        !          1080:       db close
        !          1081:       list [file exists test.db-wal] [file exists test.db-shm]
        !          1082:     } {0 0}
        !          1083:   }
        !          1084: }
        !          1085: 
        !          1086: #-------------------------------------------------------------------------
        !          1087: # Test the libraries response to discovering that one or more of the
        !          1088: # database, wal or shm files cannot be opened, or can only be opened
        !          1089: # read-only.
        !          1090: #
        !          1091: if {$::tcl_platform(platform) == "unix"} {
        !          1092:   proc perm {} {
        !          1093:     set L [list]
        !          1094:     foreach f {test.db test.db-wal test.db-shm} {
        !          1095:       if {[file exists $f]} {
        !          1096:         lappend L [file attr $f -perm]
        !          1097:       } else {
        !          1098:         lappend L {}
        !          1099:       }
        !          1100:     }
        !          1101:     set L
        !          1102:   }
        !          1103: 
        !          1104:   faultsim_delete_and_reopen
        !          1105:   execsql {
        !          1106:     PRAGMA journal_mode = WAL;
        !          1107:     CREATE TABLE t1(a, b);
        !          1108:     PRAGMA wal_checkpoint;
        !          1109:     INSERT INTO t1 VALUES('3.14', '2.72');
        !          1110:   }
        !          1111:   do_test wal2-13.1.1 {
        !          1112:     list [file exists test.db-shm] [file exists test.db-wal]
        !          1113:   } {1 1}
        !          1114:   faultsim_save_and_close
        !          1115: 
        !          1116:   foreach {tn db_perm wal_perm shm_perm can_open can_read can_write} {
        !          1117:     2   00644   00644   00644   1   1   1
        !          1118:     3   00644   00400   00644   1   1   0
        !          1119:     4   00644   00644   00400   1   0   0
        !          1120:     5   00400   00644   00644   1   1   0
        !          1121: 
        !          1122:     7   00644   00000   00644   1   0   0
        !          1123:     8   00644   00644   00000   1   0   0
        !          1124:     9   00000   00644   00644   0   0   0
        !          1125:   } {
        !          1126:     faultsim_restore
        !          1127:     do_test wal2-13.$tn.1 {
        !          1128:       file attr test.db     -perm $db_perm
        !          1129:       file attr test.db-wal -perm $wal_perm
        !          1130:       file attr test.db-shm -perm $shm_perm
        !          1131: 
        !          1132:       set     L [file attr test.db -perm]
        !          1133:       lappend L [file attr test.db-wal -perm]
        !          1134:       lappend L [file attr test.db-shm -perm]
        !          1135:     } [list $db_perm $wal_perm $shm_perm]
        !          1136: 
        !          1137:     # If $can_open is true, then it should be possible to open a database
        !          1138:     # handle. Otherwise, if $can_open is 0, attempting to open the db
        !          1139:     # handle throws an "unable to open database file" exception.
        !          1140:     #
        !          1141:     set r(1) {0 ok}
        !          1142:     set r(0) {1 {unable to open database file}}
        !          1143:     do_test wal2-13.$tn.2 {
        !          1144:       list [catch {sqlite3 db test.db ; set {} ok} msg] $msg
        !          1145:     } $r($can_open)
        !          1146: 
        !          1147:     if {$can_open} {
        !          1148: 
        !          1149:       # If $can_read is true, then the client should be able to read from
        !          1150:       # the database file. If $can_read is false, attempting to read should
        !          1151:       # throw the "unable to open database file" exception. 
        !          1152:       #
        !          1153:       set a(0) {1 {unable to open database file}}
        !          1154:       set a(1) {0 {3.14 2.72}}
        !          1155:       do_test wal2-13.$tn.3 {
        !          1156:         catchsql { SELECT * FROM t1 }
        !          1157:       } $a($can_read)
        !          1158:   
        !          1159:       # Now try to write to the db file. If the client can read but not
        !          1160:       # write, then it should throw the familiar "unable to open db file"
        !          1161:       # exception. If it can read but not write, the exception should
        !          1162:       # be "attempt to write a read only database".
        !          1163:       #
        !          1164:       # If the client can read and write, the operation should succeed.
        !          1165:       #
        !          1166:       set b(0,0) {1 {unable to open database file}}
        !          1167:       set b(1,0) {1 {attempt to write a readonly database}}
        !          1168:       set b(1,1) {0 {}}
        !          1169:       do_test wal2-13.$tn.4 {
        !          1170:         catchsql { INSERT INTO t1 DEFAULT VALUES }
        !          1171:       } $b($can_read,$can_write)
        !          1172:     }
        !          1173:     catch { db close }
        !          1174:   }
        !          1175: }
        !          1176: 
        !          1177: #-------------------------------------------------------------------------
        !          1178: # Test that "PRAGMA checkpoint_fullsync" appears to be working.
        !          1179: #
        !          1180: foreach {tn sql reslist} {
        !          1181:   1 { }                                 {10 0 4 0 6 0}
        !          1182:   2 { PRAGMA checkpoint_fullfsync = 1 } {10 4 4 2 6 2}
        !          1183:   3 { PRAGMA checkpoint_fullfsync = 0 } {10 0 4 0 6 0}
        !          1184: } {
        !          1185:   faultsim_delete_and_reopen
        !          1186: 
        !          1187:   execsql {PRAGMA auto_vacuum = 0}
        !          1188:   execsql $sql
        !          1189:   do_execsql_test wal2-14.$tn.0 { PRAGMA page_size = 4096 }   {}
        !          1190:   do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal}
        !          1191: 
        !          1192:   set sqlite_sync_count 0
        !          1193:   set sqlite_fullsync_count 0
        !          1194: 
        !          1195:   do_execsql_test wal2-14.$tn.2 {
        !          1196:     PRAGMA wal_autocheckpoint = 10;
        !          1197:     CREATE TABLE t1(a, b);                -- 2 wal syncs
        !          1198:     INSERT INTO t1 VALUES(1, 2);          -- 2 wal sync
        !          1199:     PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
        !          1200:     BEGIN;
        !          1201:       INSERT INTO t1 VALUES(3, 4);
        !          1202:       INSERT INTO t1 VALUES(5, 6);
        !          1203:     COMMIT;                               -- 2 wal sync
        !          1204:     PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
        !          1205:   } {10 0 3 3 0 1 1}
        !          1206: 
        !          1207:   do_test wal2-14.$tn.3 {
        !          1208:     cond_incr_sync_count 1
        !          1209:     list $sqlite_sync_count $sqlite_fullsync_count
        !          1210:   } [lrange $reslist 0 1]
        !          1211: 
        !          1212:   set sqlite_sync_count 0
        !          1213:   set sqlite_fullsync_count 0
        !          1214: 
        !          1215:   do_test wal2-14.$tn.4 {
        !          1216:     execsql { INSERT INTO t1 VALUES(7, zeroblob(12*4096)) }
        !          1217:     list $sqlite_sync_count $sqlite_fullsync_count
        !          1218:   } [lrange $reslist 2 3]
        !          1219: 
        !          1220:   set sqlite_sync_count 0
        !          1221:   set sqlite_fullsync_count 0
        !          1222: 
        !          1223:   do_test wal2-14.$tn.5 {
        !          1224:     execsql { PRAGMA wal_autocheckpoint = 1000 }
        !          1225:     execsql { INSERT INTO t1 VALUES(9, 10) }
        !          1226:     execsql { INSERT INTO t1 VALUES(11, 12) }
        !          1227:     execsql { INSERT INTO t1 VALUES(13, 14) }
        !          1228:     db close
        !          1229:     list $sqlite_sync_count $sqlite_fullsync_count
        !          1230:   } [lrange $reslist 4 5]
        !          1231: }
        !          1232: 
        !          1233: catch { db close }
        !          1234: 
        !          1235: # PRAGMA checkpoint_fullsync
        !          1236: # PRAGMA fullfsync
        !          1237: # PRAGMA synchronous
        !          1238: #
        !          1239: foreach {tn settings restart_sync commit_sync ckpt_sync} {
        !          1240:   1  {0 0 off}     {0 0}  {0 0}  {0 0}
        !          1241:   2  {0 0 normal}  {1 0}  {0 0}  {2 0}
        !          1242:   3  {0 0 full}    {2 0}  {1 0}  {2 0}
        !          1243: 
        !          1244:   4  {0 1 off}     {0 0}  {0 0}  {0 0}
        !          1245:   5  {0 1 normal}  {0 1}  {0 0}  {0 2}
        !          1246:   6  {0 1 full}    {0 2}  {0 1}  {0 2}
        !          1247: 
        !          1248:   7  {1 0 off}     {0 0}  {0 0}  {0 0}
        !          1249:   8  {1 0 normal}  {1 0}  {0 0}  {0 2}
        !          1250:   9  {1 0 full}    {2 0}  {1 0}  {0 2}
        !          1251: 
        !          1252:   10 {1 1 off}     {0 0}  {0 0}  {0 0}
        !          1253:   11 {1 1 normal}  {0 1}  {0 0}  {0 2}
        !          1254:   12 {1 1 full}    {0 2}  {0 1}  {0 2}
        !          1255: } {
        !          1256:   forcedelete test.db
        !          1257: 
        !          1258:   testvfs tvfs -default 1
        !          1259:   tvfs filter xSync
        !          1260:   tvfs script xSyncCb
        !          1261:   proc xSyncCb {method file fileid flags} {
        !          1262:     incr ::sync($flags)
        !          1263:   }
        !          1264: 
        !          1265:   sqlite3 db test.db
        !          1266:   do_execsql_test 15.$tn.1 "
        !          1267:     PRAGMA page_size = 4096;
        !          1268:     CREATE TABLE t1(x);
        !          1269:     PRAGMA wal_autocheckpoint = OFF;
        !          1270:     PRAGMA journal_mode = WAL;
        !          1271:     PRAGMA checkpoint_fullfsync = [lindex $settings 0];
        !          1272:     PRAGMA fullfsync = [lindex $settings 1];
        !          1273:     PRAGMA synchronous = [lindex $settings 2];
        !          1274:   " {0 wal}
        !          1275: 
        !          1276: if { $tn==2} breakpoint
        !          1277:   do_test 15.$tn.2 {
        !          1278:     set sync(normal) 0
        !          1279:     set sync(full) 0
        !          1280:     execsql { INSERT INTO t1 VALUES('abc') }
        !          1281:     list $::sync(normal) $::sync(full)
        !          1282:   } $restart_sync
        !          1283: 
        !          1284:   do_test 15.$tn.3 {
        !          1285:     set sync(normal) 0
        !          1286:     set sync(full) 0
        !          1287:     execsql { INSERT INTO t1 VALUES('abc') }
        !          1288:     list $::sync(normal) $::sync(full)
        !          1289:   } $commit_sync
        !          1290: 
        !          1291:   do_test 15.$tn.4 {
        !          1292:     set sync(normal) 0
        !          1293:     set sync(full) 0
        !          1294:     execsql { INSERT INTO t1 VALUES('def') }
        !          1295:     list $::sync(normal) $::sync(full)
        !          1296:   } $commit_sync
        !          1297: 
        !          1298:   do_test 15.$tn.5 {
        !          1299:     set sync(normal) 0
        !          1300:     set sync(full) 0
        !          1301:     execsql { PRAGMA wal_checkpoint }
        !          1302:     list $::sync(normal) $::sync(full)
        !          1303:   } $ckpt_sync
        !          1304:   
        !          1305:   db close
        !          1306:   tvfs delete
        !          1307: }
        !          1308: 
        !          1309: 
        !          1310: 
        !          1311: finish_test

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>