Annotation of embedaddon/sqlite3/test/wal2.test, revision 1.1.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>