persistentstorage/sqlite3api/TEST/TclScript/trans2.test
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     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