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