persistentstorage/sqlite3api/TEST/TclScript/exclusive2.test
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 # 2007 March 24
       
     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.
       
    12 #
       
    13 # $Id: exclusive2.test,v 1.9 2008/08/22 00:25:53 aswift Exp $
       
    14 
       
    15 set testdir [file dirname $argv0]
       
    16 source $testdir/tester.tcl
       
    17 
       
    18 ifcapable {!pager_pragmas} {
       
    19   finish_test
       
    20   return
       
    21 }
       
    22 
       
    23 # This module does not work right if the cache spills at unexpected
       
    24 # moments.  So disable the soft-heap-limit.
       
    25 #
       
    26 sqlite3_soft_heap_limit 0
       
    27 
       
    28 proc pagerChangeCounter {filename new {fd ""}} {
       
    29   if {$fd==""} {
       
    30     set fd [open $filename RDWR]
       
    31     fconfigure $fd -translation binary -encoding binary
       
    32     set needClose 1
       
    33   } else {
       
    34     set needClose 0
       
    35   }
       
    36   if {$new ne ""} {
       
    37     seek $fd 24
       
    38     set a [expr {($new&0xFF000000)>>24}]
       
    39     set b [expr {($new&0x00FF0000)>>16}]
       
    40     set c [expr {($new&0x0000FF00)>>8}]
       
    41     set d [expr {($new&0x000000FF)}]
       
    42     puts -nonewline $fd [binary format cccc $a $b $c $d]
       
    43     flush $fd
       
    44   }
       
    45 
       
    46   seek $fd 24
       
    47   foreach {a b c d} [list 0 0 0 0] {}
       
    48   binary scan [read $fd 4] cccc a b c d
       
    49   set  ret [expr ($a&0x000000FF)<<24]
       
    50   incr ret [expr ($b&0x000000FF)<<16]
       
    51   incr ret [expr ($c&0x000000FF)<<8]
       
    52   incr ret [expr ($d&0x000000FF)<<0]
       
    53 
       
    54   if {$needClose} {close $fd}
       
    55   return $ret
       
    56 }
       
    57 
       
    58 proc readPagerChangeCounter {filename} {
       
    59   set fd [open $filename RDONLY]
       
    60   fconfigure $fd -translation binary -encoding binary
       
    61 
       
    62   seek $fd 24
       
    63   foreach {a b c d} [list 0 0 0 0] {}
       
    64   binary scan [read $fd 4] cccc a b c d
       
    65   set  ret [expr ($a&0x000000FF)<<24]
       
    66   incr ret [expr ($b&0x000000FF)<<16]
       
    67   incr ret [expr ($c&0x000000FF)<<8]
       
    68   incr ret [expr ($d&0x000000FF)<<0]
       
    69 
       
    70   close $fd
       
    71   return $ret
       
    72 }
       
    73 
       
    74 
       
    75 proc t1sig {{db db}} {
       
    76   execsql {SELECT count(*), md5sum(a) FROM t1} $db
       
    77 }
       
    78 do_test exclusive2-1.0 {
       
    79   readPagerChangeCounter test.db
       
    80 } {0}
       
    81 
       
    82 #-----------------------------------------------------------------------
       
    83 # The following tests - exclusive2-1.X - check that:
       
    84 #
       
    85 # 1-3:   Build a database with connection 1, calculate a signature.
       
    86 # 4-9:   Modify the database using a second connection in a way that
       
    87 #        does not modify the freelist, then reset the pager change-counter
       
    88 #        to the value it had before the modifications.
       
    89 # 8:     Check that using the first connection, the database signature
       
    90 #        is still the same. This is because it uses the in-memory cache.
       
    91 #        It can't tell the db has changed because we reset the change-counter.
       
    92 # 9:     Increment the change-counter.
       
    93 # 10:    Ensure that the first connection now sees the updated database. It
       
    94 #        sees the change-counter has been incremented and discards the 
       
    95 #        invalid in-memory cache.
       
    96 #
       
    97 # This will only work if the database cache is large enough to hold 
       
    98 # the entire database. In the case of 1024 byte pages, this means
       
    99 # the cache size must be at least 17. Otherwise, some pages will be
       
   100 # loaded from the database file in step 8.
       
   101 #
       
   102 do_test exclusive2-1.1 {
       
   103   execsql {
       
   104     BEGIN;
       
   105     CREATE TABLE t1(a, b);
       
   106     INSERT INTO t1(a) VALUES(randstr(10, 400));
       
   107     INSERT INTO t1(a) VALUES(randstr(10, 400));
       
   108     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   109     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   110     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   111     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   112     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   113     COMMIT;
       
   114     SELECT count(*) FROM t1;
       
   115   }
       
   116 } {64}
       
   117 do_test exclusive2-1.2.1 {
       
   118   # Make sure the pager cache is large enough to store the 
       
   119   # entire database.
       
   120   set nPage [expr [file size test.db]/1024]
       
   121   if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {
       
   122     execsql "PRAGMA cache_size = $nPage"
       
   123   }
       
   124   expr {[execsql {PRAGMA cache_size}] >= $nPage}
       
   125 } {1}
       
   126 do_test exclusive2-1.2 {
       
   127   set ::sig [t1sig]
       
   128   readPagerChangeCounter test.db
       
   129 } {1}
       
   130 do_test exclusive2-1.3 {
       
   131   t1sig
       
   132 } $::sig
       
   133 do_test exclusive2-1.4 {
       
   134   sqlite3 db2 test.db
       
   135   t1sig db2
       
   136 } $::sig
       
   137 do_test exclusive2-1.5 {
       
   138   execsql {
       
   139     UPDATE t1 SET b=a, a=NULL;
       
   140   } db2
       
   141   expr {[t1sig db2] eq $::sig}
       
   142 } 0
       
   143 do_test exclusive2-1.6 {
       
   144   readPagerChangeCounter test.db
       
   145 } {2}
       
   146 do_test exclusive2-1.7 {
       
   147   pagerChangeCounter test.db 1
       
   148 } {1}
       
   149 do_test exclusive2-1.9 {
       
   150   t1sig
       
   151   expr {[t1sig] eq $::sig}
       
   152 } {1}
       
   153 do_test exclusive2-1.10 {
       
   154   pagerChangeCounter test.db 2
       
   155 } {2}
       
   156 do_test exclusive2-1.11 {
       
   157   expr {[t1sig] eq $::sig}
       
   158 } {0}
       
   159 
       
   160 #--------------------------------------------------------------------
       
   161 # These tests - exclusive2-2.X - are similar to exclusive2-1.X, 
       
   162 # except that they are run with locking_mode=EXCLUSIVE.
       
   163 #
       
   164 # 1-3:   Build a database with exclusive-access connection 1, 
       
   165 #        calculate a signature.
       
   166 # 4:     Corrupt the database by writing 10000 bytes of garbage
       
   167 #        starting at the beginning of page 2. Check that connection 1
       
   168 #        still works. It should be accessing the in-memory cache.
       
   169 # 5-6:   Modify the dataase change-counter. Connection 1 still works
       
   170 #        entirely from in-memory cache, because it doesn't check the
       
   171 #        change-counter.
       
   172 # 7-8    Set the locking-mode back to normal. After the db is unlocked,
       
   173 #        SQLite detects the modified change-counter and discards the
       
   174 #        in-memory cache. Then it finds the corruption caused in step 4....
       
   175 #
       
   176 # As above, this test is only applicable if the pager cache is
       
   177 # large enough to hold the entire database. With 1024 byte pages,
       
   178 # this means 19 pages.  We also need to disable the soft-heap-limit
       
   179 # to prevent memory-induced cache spills.
       
   180 #
       
   181 do_test exclusive2-2.1 {
       
   182   execsql {PRAGMA locking_mode = exclusive;}
       
   183   execsql {
       
   184     BEGIN;
       
   185     DELETE FROM t1;
       
   186     INSERT INTO t1(a) VALUES(randstr(10, 400));
       
   187     INSERT INTO t1(a) VALUES(randstr(10, 400));
       
   188     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   189     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   190     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   191     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   192     INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
       
   193     COMMIT;
       
   194     SELECT count(*) FROM t1;
       
   195   }
       
   196 } {64}
       
   197 do_test exclusive2-2.2.1 {
       
   198   # Make sure the pager cache is large enough to store the 
       
   199   # entire database.
       
   200   set nPage [expr [file size test.db]/1024]
       
   201   if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {
       
   202     execsql "PRAGMA cache_size = $nPage"
       
   203   }
       
   204   expr {[execsql {PRAGMA cache_size}] >= $nPage}
       
   205 } {1}
       
   206 do_test exclusive2-2.2 {
       
   207   set ::sig [t1sig]
       
   208   readPagerChangeCounter test.db
       
   209 } {3}
       
   210 do_test exclusive2-2.3 {
       
   211   t1sig
       
   212 } $::sig
       
   213 
       
   214 do_test exclusive2-2.4 {
       
   215   set ::fd [open test.db RDWR]
       
   216   fconfigure $::fd -translation binary
       
   217   seek $::fd 1024
       
   218   puts -nonewline $::fd [string repeat [binary format c 0] 10000]
       
   219   flush $::fd
       
   220   t1sig
       
   221 } $::sig
       
   222 
       
   223 do_test exclusive2-2.5 {
       
   224   pagerChangeCounter test.db 5 $::fd
       
   225 } {5}
       
   226 do_test exclusive2-2.6 {
       
   227   t1sig
       
   228 } $::sig
       
   229 do_test exclusive2-2.7 {
       
   230   execsql {PRAGMA locking_mode = normal}
       
   231   t1sig
       
   232 } $::sig
       
   233 
       
   234 do_test exclusive2-2.8 {
       
   235   set rc [catch {t1sig} msg]
       
   236   list $rc $msg
       
   237 } {1 {database disk image is malformed}}
       
   238 
       
   239 #--------------------------------------------------------------------
       
   240 # These tests - exclusive2-3.X - verify that the pager change-counter
       
   241 # is only incremented by the first change when in exclusive access
       
   242 # mode. In normal mode, the change-counter is incremented once
       
   243 # per write-transaction.
       
   244 #
       
   245 
       
   246 db close
       
   247 db2 close
       
   248 catch {close $::fd}
       
   249 file delete -force test.db
       
   250 file delete -force test.db-journal
       
   251 
       
   252 do_test exclusive2-3.0 {
       
   253   sqlite3 db test.db
       
   254   execsql {
       
   255     BEGIN;
       
   256     CREATE TABLE t1(a UNIQUE);
       
   257     INSERT INTO t1 VALUES(randstr(10, 400));
       
   258     INSERT INTO t1 VALUES(randstr(10, 400));
       
   259     COMMIT;
       
   260   }
       
   261   readPagerChangeCounter test.db
       
   262 } {1}
       
   263 do_test exclusive2-3.1 {
       
   264   execsql {
       
   265     INSERT INTO t1 VALUES(randstr(10, 400));
       
   266   }
       
   267   readPagerChangeCounter test.db
       
   268 } {2}
       
   269 do_test exclusive2-3.2 {
       
   270   execsql {
       
   271     INSERT INTO t1 VALUES(randstr(10, 400));
       
   272   }
       
   273   readPagerChangeCounter test.db
       
   274 } {3}
       
   275 do_test exclusive2-3.3 {
       
   276   execsql {
       
   277     PRAGMA locking_mode = exclusive;
       
   278     INSERT INTO t1 VALUES(randstr(10, 400));
       
   279   }
       
   280   readPagerChangeCounter test.db
       
   281 } {4}
       
   282 do_test exclusive2-3.4 {
       
   283   execsql {
       
   284     INSERT INTO t1 VALUES(randstr(10, 400));
       
   285   }
       
   286   readPagerChangeCounter test.db
       
   287 } {4}
       
   288 do_test exclusive2-3.5 {
       
   289   execsql {
       
   290     PRAGMA locking_mode = normal;
       
   291     INSERT INTO t1 VALUES(randstr(10, 400));
       
   292   }
       
   293   readPagerChangeCounter test.db
       
   294 } {4}
       
   295 do_test exclusive2-3.6 {
       
   296   execsql {
       
   297     INSERT INTO t1 VALUES(randstr(10, 400));
       
   298   }
       
   299   readPagerChangeCounter test.db
       
   300 } {5}
       
   301 sqlite3_soft_heap_limit $soft_limit
       
   302 
       
   303 finish_test