3 # The author disclaims copyright to this source code. In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
12 # $Id: savepoint6.test,v 1.4 2009/06/05 17:09:12 drh Exp $
14 set testdir [file dirname $argv0]
15 source $testdir/tester.tcl
18 uplevel db eval [list $zSql]
19 #puts stderr "$zSql ;"
23 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);
29 if {0==[info exists ::G(savepoint6_iterations)]} {
30 set ::G(savepoint6_iterations) 1000
33 #--------------------------------------------------------------------------
34 # In memory database state.
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:
40 # 1. The savepoint name.
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.
46 # Array ::aEntry contains the contents of database table t1. Array keys are
47 # x values, the array data values are y values.
50 array set aEntry [list]
53 set nChar [expr int(rand()*250) + 250]
54 set str " $nChar [string repeat $x. $nChar]"
55 string range $str 1 $nChar
57 #--------------------------------------------------------------------------
59 #-------------------------------------------------------------------------
60 # Procs to operate on database:
69 proc savepoint {zName} {
70 catch { sql "SAVEPOINT $zName" }
71 lappend ::lSavepoint [list $zName [array get ::aEntry]]
74 proc rollback {zName} {
75 catch { sql "ROLLBACK TO $zName" }
76 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]
83 if {$i+1 < [llength $::lSavepoint]} {
84 set ::lSavepoint [lreplace $::lSavepoint [expr $i+1] end]
91 proc release {zName} {
92 catch { sql "RELEASE $zName" }
93 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]
101 if {[llength $::lSavepoint] == 0} {
102 #puts stderr "-- End of transaction!!!!!!!!!!!!!"
106 proc insert_rows {lX} {
110 # Update database [db]
111 sql "INSERT OR REPLACE INTO t1 VALUES($x, '$y')"
113 # Update the Tcl database.
118 proc delete_rows {lX} {
120 # Update database [db]
121 sql "DELETE FROM t1 WHERE x = $x"
123 # Update the Tcl database.
124 unset -nocomplain ::aEntry($x)
127 #-------------------------------------------------------------------------
129 #-------------------------------------------------------------------------
130 # Proc to compare database content with the in-memory representation.
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"
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"
144 if {$::aEntry($x) ne $y} {
145 error "Entry $x is set to {$y} in database, {$::aEntry($x)} in array"
149 db eval { PRAGMA integrity_check }
151 #-------------------------------------------------------------------------
153 #-------------------------------------------------------------------------
154 # Proc to return random set of x values.
158 proc random_integers {nRes nRange} {
160 for {set i 0} {$i<$nRes} {incr i} {
161 lappend ret [expr int(rand()*$nRange)]
165 #-------------------------------------------------------------------------
167 proc database_op {} {
168 set i [expr int(rand()*2)]
170 insert_rows [random_integers 100 1000]
173 delete_rows [random_integers 100 1000]
174 set i [expr int(rand()*3)]
176 sql {PRAGMA incremental_vacuum}
181 proc savepoint_op {} {
182 set names {one two three four five}
183 set cmds {savepoint savepoint savepoint savepoint release rollback}
185 set C [lindex $cmds [expr int(rand()*6)]]
186 set N [lindex $names [expr int(rand()*5)]]
188 #puts stderr " $C $N ; "
197 ############################################################################
198 ############################################################################
199 # Start of test cases.
201 do_test savepoint6-1.1 {
204 do_test savepoint6-1.2 {
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
215 execsql {PRAGMA incremental_vacuum}
222 execsql {SELECT count(*) FROM t1}
225 foreach zSetup [list {
229 if {[wal_is_wal_mode]} continue
233 if {[permutation] eq "journaltest"} {
238 sql { PRAGMA synchronous = off }
240 set testname smallcache
242 sql { PRAGMA cache_size = 10 }
245 unset -nocomplain ::lSavepoint
246 unset -nocomplain ::aEntry
249 forcedelete test.db test.db-wal test.db-journal
255 do_test savepoint6-$testname.setup {
257 insert_rows [random_integers 100 1000]
262 for {set i 0} {$i < $::G(savepoint6_iterations)} {incr i} {
263 do_test savepoint6-$testname.$i.1 {
268 do_test savepoint6-$testname.$i.2 {
275 wal_check_journal_mode savepoint6-$testname.walok
278 unset -nocomplain ::lSavepoint
279 unset -nocomplain ::aEntry