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 {NOT NULL constraint failed: t1.z}} | |
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 {NOT NULL constraint failed: t1.z}} | |
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 |