Home | History | Annotate | Download | only in test
      1 # 2008 August 27
      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 #
     12 # This file implements regression tests for SQLite library.  The
     13 # focus of this script is transactions
     14 #
     15 # $Id: trans2.test,v 1.1 2008/08/27 18:56:36 drh Exp $
     16 #
     17 set testdir [file dirname $argv0]
     18 source $testdir/tester.tcl
     19 
     20 # A procedure to scramble the elements of list $inlist into a random order.
     21 #
     22 proc scramble {inlist} {
     23   set y {}
     24   foreach x $inlist {
     25     lappend y [list [expr {rand()}] $x]
     26   }
     27   set y [lsort $y]
     28   set outlist {}
     29   foreach x $y {
     30     lappend outlist [lindex $x 1]
     31   }
     32   return $outlist
     33 }
     34 
     35 # Generate a UUID using randomness.
     36 #
     37 expr srand(1)
     38 proc random_uuid {} {
     39   set u {}
     40   for {set i 0} {$i<5} {incr i} {
     41     append u [format %06x [expr {int(rand()*16777216)}]]
     42   }
     43   return $u
     44 }
     45 
     46 # Compute hashes on the u1 and u2 fields of the sample data.
     47 #
     48 proc hash1 {} {
     49   global data
     50   set x ""
     51   foreach rec [lsort -integer -index 0 $data] {
     52     append x [lindex $rec 1]
     53   }
     54   return [md5 $x]
     55 }
     56 proc hash2 {} {
     57   global data
     58   set x ""
     59   foreach rec [lsort -integer -index 0 $data] {
     60     append x [lindex $rec 3]
     61   }
     62   return [md5 $x]
     63 }
     64 
     65 # Create the initial data set
     66 #
     67 unset -nocomplain data i max_rowid todel n rec max1 id origres newres
     68 unset -nocomplain inssql modsql s j z
     69 set data {}
     70 for {set i 0} {$i<400} {incr i} {
     71   set rec [list $i [random_uuid] [expr {int(rand()*5000)+1000}] [random_uuid]]
     72   lappend data $rec
     73 }
     74 set max_rowid [expr {$i-1}]
     75 
     76 # Create the T1 table used to hold test data.  Populate that table with
     77 # the initial data set and check hashes to make sure everything is correct.
     78 #
     79 do_test trans2-1.1 {
     80   execsql {
     81     PRAGMA cache_size=100;
     82     CREATE TABLE t1(
     83       id INTEGER PRIMARY KEY,
     84       u1 TEXT UNIQUE,
     85       z BLOB NOT NULL,
     86       u2 TEXT UNIQUE
     87     );
     88   }
     89   foreach rec [scramble $data] {
     90     foreach {id u1 z u2} $rec break
     91     db eval {INSERT INTO t1 VALUES($id,$u1,zeroblob($z),$u2)}
     92   }
     93   db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
     94 } [list [hash1] [hash2]]
     95 
     96 # Repeat the main test loop multiple times.
     97 #
     98 for {set i 2} {$i<=30} {incr i} {
     99   # Delete one row out of every 10 in the database.  This will add
    100   # many pages to the freelist.
    101   #
    102   set todel {}
    103   set n [expr {[llength $data]/10}]
    104   set data [scramble $data]
    105   foreach rec [lrange $data 0 $n] {
    106     lappend todel [lindex $rec 0]
    107   }
    108   set data [lrange $data [expr {$n+1}] end]
    109   set max1 [lindex [lindex $data 0] 0]
    110   foreach rec $data {
    111     set id [lindex $rec 0]
    112     if {$id>$max1} {set max1 $id}
    113   }
    114   set origres [list [hash1] [hash2]]
    115   do_test trans2-$i.1 {
    116     db eval "DELETE FROM t1 WHERE id IN ([join $todel ,])"
    117     db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
    118   } $origres
    119   integrity_check trans2-$i.2
    120 
    121   # Begin a transaction and insert many new records.
    122   #
    123   set newdata {}
    124   foreach id $todel {
    125     set rec [list $id [random_uuid] \
    126                       [expr {int(rand()*5000)+1000}] [random_uuid]]
    127     lappend newdata $rec
    128     lappend data $rec
    129   }
    130   for {set j 1} {$j<50} {incr j} {
    131     set id [expr {$max_rowid+$j}]
    132     lappend todel $id
    133     set rec [list $id [random_uuid] \
    134                       [expr {int(rand()*5000)+1000}] [random_uuid]]
    135     lappend newdata $rec
    136     lappend data $rec
    137   }
    138   set max_rowid [expr {$max_rowid+$j-1}]
    139   set modsql {}
    140   set inssql {}
    141   set newres [list [hash1] [hash2]]
    142   do_test trans2-$i.3 {
    143     db eval BEGIN
    144     foreach rec [scramble $newdata] {
    145       foreach {id u1 z u2} $rec break
    146       set s "INSERT INTO t1 VALUES($id,'$u1',zeroblob($z),'$u2');"
    147       append modsql $s\n
    148       append inssql $s\n
    149       db eval $s
    150     }
    151     db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
    152   } $newres
    153   integrity_check trans2-$i.4
    154 
    155   # Do a large update that aborts do to a constraint failure near
    156   # the end.  This stresses the statement journal mechanism.
    157   #
    158   do_test trans2-$i.10 {
    159     catchsql {
    160       UPDATE t1 SET u1=u1||'x',
    161           z = CASE WHEN id<$max_rowid
    162                    THEN zeroblob((random()&65535)%5000 + 1000) END;
    163     }
    164   } {1 {t1.z may not be NULL}}
    165   do_test trans2-$i.11 {
    166     db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
    167   } $newres
    168 
    169   # Delete all of the newly inserted records.  Verify that the database
    170   # is back to its original state.
    171   #
    172   do_test trans2-$i.20 {
    173     set s "DELETE FROM t1 WHERE id IN ([join $todel ,]);"
    174     append modsql $s\n
    175     db eval $s
    176     db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
    177   } $origres
    178 
    179   # Do another large update that aborts do to a constraint failure near
    180   # the end.  This stresses the statement journal mechanism.
    181   #
    182   do_test trans2-$i.30 {
    183     catchsql {
    184       UPDATE t1 SET u1=u1||'x',
    185           z = CASE WHEN id<$max1
    186                    THEN zeroblob((random()&65535)%5000 + 1000) END;
    187     }
    188   } {1 {t1.z may not be NULL}}
    189   do_test trans2-$i.31 {
    190     db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
    191   } $origres
    192 
    193   # Redo the inserts
    194   #
    195   do_test trans2-$i.40 {
    196     db eval $inssql
    197     append modsql $inssql
    198     db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
    199   } $newres
    200 
    201   # Rollback the transaction.  Verify that the content is restored.
    202   #
    203   do_test trans2-$i.90 {
    204     db eval ROLLBACK
    205     db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
    206   } $origres
    207   integrity_check trans2-$i.91
    208 
    209   # Repeat all the changes, but this time commit.
    210   #
    211   do_test trans2-$i.92 {
    212     db eval BEGIN
    213     catchsql {
    214       UPDATE t1 SET u1=u1||'x',
    215           z = CASE WHEN id<$max1
    216                    THEN zeroblob((random()&65535)%5000 + 1000) END;
    217     }
    218     db eval $modsql
    219     catchsql {
    220       UPDATE t1 SET u1=u1||'x',
    221           z = CASE WHEN id<$max1
    222                    THEN zeroblob((random()&65535)%5000 + 1000) END;
    223     }
    224     db eval COMMIT
    225     db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
    226   } $newres
    227   integrity_check trans2-$i.93
    228 }
    229 
    230 unset -nocomplain data i max_rowid todel n rec max1 id origres newres
    231 unset -nocomplain inssql modsql s j z
    232 finish_test
    233