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.1.1 2012/02/21 17:04:16 misho 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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>