| OLD | NEW | 
 | (Empty) | 
|    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 |  | 
| OLD | NEW |