blob: b1d0d46f5c9f3beef77133eb0e620059828e6871 [file] [log] [blame]
danielk1977e7e6f122009-01-03 10:41:29 +00001# 2009 January 3
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#
drhdda70fe2009-06-05 17:09:11 +000012# $Id: savepoint6.test,v 1.4 2009/06/05 17:09:12 drh Exp $
danielk1977e7e6f122009-01-03 10:41:29 +000013
14set testdir [file dirname $argv0]
15source $testdir/tester.tcl
16
danielk1977f2c31ad2009-01-06 13:40:08 +000017proc sql {zSql} {
18 uplevel db eval [list $zSql]
19 #puts stderr "$zSql ;"
20}
21
22set DATABASE_SCHEMA {
danielk1977e7e6f122009-01-03 10:41:29 +000023 PRAGMA auto_vacuum = incremental;
24 CREATE TABLE t1(x, y);
25 CREATE UNIQUE INDEX i1 ON t1(x);
26 CREATE INDEX i2 ON t1(y);
danielk1977f2c31ad2009-01-06 13:40:08 +000027}
danielk1977e7e6f122009-01-03 10:41:29 +000028
dan430e74c2010-06-07 17:47:26 +000029if {0==[info exists ::G(savepoint6_iterations)]} {
30 set ::G(savepoint6_iterations) 1000
dan31f98fc2010-04-27 05:42:32 +000031}
dane180c292010-04-26 17:42:56 +000032
danielk1977e7e6f122009-01-03 10:41:29 +000033#--------------------------------------------------------------------------
34# In memory database state.
35#
36# ::lSavepoint is a list containing one entry for each active savepoint. The
37# first entry in the list corresponds to the most recently opened savepoint.
38# Each entry consists of two elements:
39#
40# 1. The savepoint name.
41#
42# 2. A serialized Tcl array representing the contents of table t1 at the
43# start of the savepoint. The keys of the array are the x values. The
44# values are the y values.
45#
46# Array ::aEntry contains the contents of database table t1. Array keys are
47# x values, the array data values are y values.
48#
49set lSavepoint [list]
50array set aEntry [list]
51
52proc x_to_y {x} {
53 set nChar [expr int(rand()*250) + 250]
54 set str " $nChar [string repeat $x. $nChar]"
55 string range $str 1 $nChar
56}
57#--------------------------------------------------------------------------
58
59#-------------------------------------------------------------------------
60# Procs to operate on database:
61#
62# savepoint NAME
63# rollback NAME
64# release NAME
65#
66# insert_rows XVALUES
67# delete_rows XVALUES
68#
69proc savepoint {zName} {
danielk1977f2c31ad2009-01-06 13:40:08 +000070 catch { sql "SAVEPOINT $zName" }
danielk1977e7e6f122009-01-03 10:41:29 +000071 lappend ::lSavepoint [list $zName [array get ::aEntry]]
72}
73
74proc rollback {zName} {
danielk1977f2c31ad2009-01-06 13:40:08 +000075 catch { sql "ROLLBACK TO $zName" }
danielk1977e7e6f122009-01-03 10:41:29 +000076 for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
77 set zSavepoint [lindex $::lSavepoint $i 0]
78 if {$zSavepoint eq $zName} {
79 unset -nocomplain ::aEntry
80 array set ::aEntry [lindex $::lSavepoint $i 1]
81
82
83 if {$i+1 < [llength $::lSavepoint]} {
84 set ::lSavepoint [lreplace $::lSavepoint [expr $i+1] end]
85 }
86 break
87 }
88 }
89}
90
91proc release {zName} {
danielk1977f2c31ad2009-01-06 13:40:08 +000092 catch { sql "RELEASE $zName" }
danielk1977e7e6f122009-01-03 10:41:29 +000093 for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
94 set zSavepoint [lindex $::lSavepoint $i 0]
95 if {$zSavepoint eq $zName} {
96 set ::lSavepoint [lreplace $::lSavepoint $i end]
97 break
98 }
99 }
danielk1977f2c31ad2009-01-06 13:40:08 +0000100
101 if {[llength $::lSavepoint] == 0} {
102 #puts stderr "-- End of transaction!!!!!!!!!!!!!"
103 }
danielk1977e7e6f122009-01-03 10:41:29 +0000104}
105
106proc insert_rows {lX} {
107 foreach x $lX {
108 set y [x_to_y $x]
109
110 # Update database [db]
danielk1977f2c31ad2009-01-06 13:40:08 +0000111 sql "INSERT OR REPLACE INTO t1 VALUES($x, '$y')"
danielk1977e7e6f122009-01-03 10:41:29 +0000112
113 # Update the Tcl database.
114 set ::aEntry($x) $y
115 }
116}
117
118proc delete_rows {lX} {
119 foreach x $lX {
120 # Update database [db]
danielk1977f2c31ad2009-01-06 13:40:08 +0000121 sql "DELETE FROM t1 WHERE x = $x"
danielk1977e7e6f122009-01-03 10:41:29 +0000122
123 # Update the Tcl database.
124 unset -nocomplain ::aEntry($x)
125 }
126}
127#-------------------------------------------------------------------------
128
129#-------------------------------------------------------------------------
130# Proc to compare database content with the in-memory representation.
131#
132# checkdb
133#
134proc checkdb {} {
135 set nEntry [db one {SELECT count(*) FROM t1}]
136 set nEntry2 [array size ::aEntry]
137 if {$nEntry != $nEntry2} {
138 error "$nEntry entries in database, $nEntry2 entries in array"
139 }
140 db eval {SELECT x, y FROM t1} {
141 if {![info exists ::aEntry($x)]} {
142 error "Entry $x exists in database, but not in array"
143 }
144 if {$::aEntry($x) ne $y} {
145 error "Entry $x is set to {$y} in database, {$::aEntry($x)} in array"
146 }
147 }
148
149 db eval { PRAGMA integrity_check }
150}
151#-------------------------------------------------------------------------
152
153#-------------------------------------------------------------------------
154# Proc to return random set of x values.
155#
156# random_integers
157#
158proc random_integers {nRes nRange} {
159 set ret [list]
160 for {set i 0} {$i<$nRes} {incr i} {
161 lappend ret [expr int(rand()*$nRange)]
162 }
163 return $ret
164}
165#-------------------------------------------------------------------------
166
danielk1977e7e6f122009-01-03 10:41:29 +0000167proc database_op {} {
168 set i [expr int(rand()*2)]
169 if {$i==0} {
170 insert_rows [random_integers 100 1000]
171 }
172 if {$i==1} {
173 delete_rows [random_integers 100 1000]
174 set i [expr int(rand()*3)]
175 if {$i==0} {
danielk1977f2c31ad2009-01-06 13:40:08 +0000176 sql {PRAGMA incremental_vacuum}
danielk1977e7e6f122009-01-03 10:41:29 +0000177 }
178 }
179}
180
181proc savepoint_op {} {
182 set names {one two three four five}
183 set cmds {savepoint savepoint savepoint savepoint release rollback}
184
185 set C [lindex $cmds [expr int(rand()*6)]]
186 set N [lindex $names [expr int(rand()*5)]]
187
danielk1977f2c31ad2009-01-06 13:40:08 +0000188 #puts stderr " $C $N ; "
189 #flush stderr
190
danielk1977e7e6f122009-01-03 10:41:29 +0000191 $C $N
192 return ok
193}
194
danielk1977f2c31ad2009-01-06 13:40:08 +0000195expr srand(0)
196
197############################################################################
198############################################################################
199# Start of test cases.
200
201do_test savepoint6-1.1 {
202 sql $DATABASE_SCHEMA
203} {}
204do_test savepoint6-1.2 {
205 insert_rows {
206 497 166 230 355 779 588 394 317 290 475 362 193 805 851 564
207 763 44 930 389 819 765 760 966 280 538 414 500 18 25 287 320
208 30 382 751 87 283 981 429 630 974 421 270 810 405
209 }
210
danielk1977e7e6f122009-01-03 10:41:29 +0000211 savepoint one
danielk1977f2c31ad2009-01-06 13:40:08 +0000212 insert_rows 858
213 delete_rows 930
214 savepoint two
215 execsql {PRAGMA incremental_vacuum}
216 savepoint three
217 insert_rows 144
218 rollback three
219 rollback two
danielk1977e7e6f122009-01-03 10:41:29 +0000220 release one
danielk1977e7e6f122009-01-03 10:41:29 +0000221
danielk1977f2c31ad2009-01-06 13:40:08 +0000222 execsql {SELECT count(*) FROM t1}
223} {44}
danielk1977e7e6f122009-01-03 10:41:29 +0000224
danielk1977f2c31ad2009-01-06 13:40:08 +0000225foreach zSetup [list {
226 set testname normal
227 sqlite3 db test.db
228} {
dan4cd78b42010-04-26 16:57:10 +0000229 if {[wal_is_wal_mode]} continue
danielk1977f2c31ad2009-01-06 13:40:08 +0000230 set testname tempdb
231 sqlite3 db ""
232} {
dan430e74c2010-06-07 17:47:26 +0000233 if {[permutation] eq "journaltest"} {
danielk1977be871042009-01-07 17:06:52 +0000234 continue
235 }
236 set testname nosync
237 sqlite3 db test.db
238 sql { PRAGMA synchronous = off }
239} {
danielk1977f2c31ad2009-01-06 13:40:08 +0000240 set testname smallcache
241 sqlite3 db test.db
242 sql { PRAGMA cache_size = 10 }
243}] {
244
245 unset -nocomplain ::lSavepoint
246 unset -nocomplain ::aEntry
247
danielk1977be871042009-01-07 17:06:52 +0000248 catch { db close }
mistachkinfda06be2011-08-02 00:57:34 +0000249 forcedelete test.db test.db-wal test.db-journal
danielk1977f2c31ad2009-01-06 13:40:08 +0000250 eval $zSetup
251 sql $DATABASE_SCHEMA
252
dan4cd78b42010-04-26 16:57:10 +0000253 wal_set_journal_mode
254
danielk1977f2c31ad2009-01-06 13:40:08 +0000255 do_test savepoint6-$testname.setup {
256 savepoint one
257 insert_rows [random_integers 100 1000]
258 release one
danielk1977e7e6f122009-01-03 10:41:29 +0000259 checkdb
260 } {ok}
danielk1977f2c31ad2009-01-06 13:40:08 +0000261
dan430e74c2010-06-07 17:47:26 +0000262 for {set i 0} {$i < $::G(savepoint6_iterations)} {incr i} {
danielk1977f2c31ad2009-01-06 13:40:08 +0000263 do_test savepoint6-$testname.$i.1 {
264 savepoint_op
265 checkdb
266 } {ok}
267
268 do_test savepoint6-$testname.$i.2 {
269 database_op
270 database_op
271 checkdb
272 } {ok}
273 }
dan4cd78b42010-04-26 16:57:10 +0000274
275 wal_check_journal_mode savepoint6-$testname.walok
danielk1977e7e6f122009-01-03 10:41:29 +0000276}
277
278unset -nocomplain ::lSavepoint
279unset -nocomplain ::aEntry
280
281finish_test