1e7e6f12aSdanielk1977# 2009 January 3 2e7e6f12aSdanielk1977# 3e7e6f12aSdanielk1977# The author disclaims copyright to this source code. In place of 4e7e6f12aSdanielk1977# a legal notice, here is a blessing: 5e7e6f12aSdanielk1977# 6e7e6f12aSdanielk1977# May you do good and not evil. 7e7e6f12aSdanielk1977# May you find forgiveness for yourself and forgive others. 8e7e6f12aSdanielk1977# May you share freely, never taking more than you give. 9e7e6f12aSdanielk1977# 10e7e6f12aSdanielk1977#*********************************************************************** 11e7e6f12aSdanielk1977# 12dda70fe3Sdrh# $Id: savepoint6.test,v 1.4 2009/06/05 17:09:12 drh Exp $ 13e7e6f12aSdanielk1977 14e7e6f12aSdanielk1977set testdir [file dirname $argv0] 15e7e6f12aSdanielk1977source $testdir/tester.tcl 16e7e6f12aSdanielk1977 17f2c31ad8Sdanielk1977proc sql {zSql} { 18f2c31ad8Sdanielk1977 uplevel db eval [list $zSql] 19f2c31ad8Sdanielk1977 #puts stderr "$zSql ;" 20f2c31ad8Sdanielk1977} 21f2c31ad8Sdanielk1977 22f2c31ad8Sdanielk1977set DATABASE_SCHEMA { 23e7e6f12aSdanielk1977 PRAGMA auto_vacuum = incremental; 24e7e6f12aSdanielk1977 CREATE TABLE t1(x, y); 25e7e6f12aSdanielk1977 CREATE UNIQUE INDEX i1 ON t1(x); 26e7e6f12aSdanielk1977 CREATE INDEX i2 ON t1(y); 27e7e6f12aSdanielk1977} 28e7e6f12aSdanielk1977 29430e74cdSdanif {0==[info exists ::G(savepoint6_iterations)]} { 30430e74cdSdan set ::G(savepoint6_iterations) 1000 3131f98fc8Sdan} 32e180c296Sdan 33e7e6f12aSdanielk1977#-------------------------------------------------------------------------- 34e7e6f12aSdanielk1977# In memory database state. 35e7e6f12aSdanielk1977# 36e7e6f12aSdanielk1977# ::lSavepoint is a list containing one entry for each active savepoint. The 37e7e6f12aSdanielk1977# first entry in the list corresponds to the most recently opened savepoint. 38e7e6f12aSdanielk1977# Each entry consists of two elements: 39e7e6f12aSdanielk1977# 40e7e6f12aSdanielk1977# 1. The savepoint name. 41e7e6f12aSdanielk1977# 42e7e6f12aSdanielk1977# 2. A serialized Tcl array representing the contents of table t1 at the 43e7e6f12aSdanielk1977# start of the savepoint. The keys of the array are the x values. The 44e7e6f12aSdanielk1977# values are the y values. 45e7e6f12aSdanielk1977# 46e7e6f12aSdanielk1977# Array ::aEntry contains the contents of database table t1. Array keys are 47e7e6f12aSdanielk1977# x values, the array data values are y values. 48e7e6f12aSdanielk1977# 49e7e6f12aSdanielk1977set lSavepoint [list] 50e7e6f12aSdanielk1977array set aEntry [list] 51e7e6f12aSdanielk1977 52e7e6f12aSdanielk1977proc x_to_y {x} { 53e7e6f12aSdanielk1977 set nChar [expr int(rand()*250) + 250] 54e7e6f12aSdanielk1977 set str " $nChar [string repeat $x. $nChar]" 55e7e6f12aSdanielk1977 string range $str 1 $nChar 56e7e6f12aSdanielk1977} 57e7e6f12aSdanielk1977#-------------------------------------------------------------------------- 58e7e6f12aSdanielk1977 59e7e6f12aSdanielk1977#------------------------------------------------------------------------- 60e7e6f12aSdanielk1977# Procs to operate on database: 61e7e6f12aSdanielk1977# 62e7e6f12aSdanielk1977# savepoint NAME 63e7e6f12aSdanielk1977# rollback NAME 64e7e6f12aSdanielk1977# release NAME 65e7e6f12aSdanielk1977# 66e7e6f12aSdanielk1977# insert_rows XVALUES 67e7e6f12aSdanielk1977# delete_rows XVALUES 68e7e6f12aSdanielk1977# 69e7e6f12aSdanielk1977proc savepoint {zName} { 70f2c31ad8Sdanielk1977 catch { sql "SAVEPOINT $zName" } 71e7e6f12aSdanielk1977 lappend ::lSavepoint [list $zName [array get ::aEntry]] 72e7e6f12aSdanielk1977} 73e7e6f12aSdanielk1977 74e7e6f12aSdanielk1977proc rollback {zName} { 75f2c31ad8Sdanielk1977 catch { sql "ROLLBACK TO $zName" } 76e7e6f12aSdanielk1977 for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} { 77e7e6f12aSdanielk1977 set zSavepoint [lindex $::lSavepoint $i 0] 78e7e6f12aSdanielk1977 if {$zSavepoint eq $zName} { 79e7e6f12aSdanielk1977 unset -nocomplain ::aEntry 80e7e6f12aSdanielk1977 array set ::aEntry [lindex $::lSavepoint $i 1] 81e7e6f12aSdanielk1977 82e7e6f12aSdanielk1977 83e7e6f12aSdanielk1977 if {$i+1 < [llength $::lSavepoint]} { 84e7e6f12aSdanielk1977 set ::lSavepoint [lreplace $::lSavepoint [expr $i+1] end] 85e7e6f12aSdanielk1977 } 86e7e6f12aSdanielk1977 break 87e7e6f12aSdanielk1977 } 88e7e6f12aSdanielk1977 } 89e7e6f12aSdanielk1977} 90e7e6f12aSdanielk1977 91e7e6f12aSdanielk1977proc release {zName} { 92f2c31ad8Sdanielk1977 catch { sql "RELEASE $zName" } 93e7e6f12aSdanielk1977 for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} { 94e7e6f12aSdanielk1977 set zSavepoint [lindex $::lSavepoint $i 0] 95e7e6f12aSdanielk1977 if {$zSavepoint eq $zName} { 96e7e6f12aSdanielk1977 set ::lSavepoint [lreplace $::lSavepoint $i end] 97e7e6f12aSdanielk1977 break 98e7e6f12aSdanielk1977 } 99e7e6f12aSdanielk1977 } 100f2c31ad8Sdanielk1977 101f2c31ad8Sdanielk1977 if {[llength $::lSavepoint] == 0} { 102f2c31ad8Sdanielk1977 #puts stderr "-- End of transaction!!!!!!!!!!!!!" 103f2c31ad8Sdanielk1977 } 104e7e6f12aSdanielk1977} 105e7e6f12aSdanielk1977 106e7e6f12aSdanielk1977proc insert_rows {lX} { 107e7e6f12aSdanielk1977 foreach x $lX { 108e7e6f12aSdanielk1977 set y [x_to_y $x] 109e7e6f12aSdanielk1977 110e7e6f12aSdanielk1977 # Update database [db] 111f2c31ad8Sdanielk1977 sql "INSERT OR REPLACE INTO t1 VALUES($x, '$y')" 112e7e6f12aSdanielk1977 113e7e6f12aSdanielk1977 # Update the Tcl database. 114e7e6f12aSdanielk1977 set ::aEntry($x) $y 115e7e6f12aSdanielk1977 } 116e7e6f12aSdanielk1977} 117e7e6f12aSdanielk1977 118e7e6f12aSdanielk1977proc delete_rows {lX} { 119e7e6f12aSdanielk1977 foreach x $lX { 120e7e6f12aSdanielk1977 # Update database [db] 121f2c31ad8Sdanielk1977 sql "DELETE FROM t1 WHERE x = $x" 122e7e6f12aSdanielk1977 123e7e6f12aSdanielk1977 # Update the Tcl database. 124e7e6f12aSdanielk1977 unset -nocomplain ::aEntry($x) 125e7e6f12aSdanielk1977 } 126e7e6f12aSdanielk1977} 127e7e6f12aSdanielk1977#------------------------------------------------------------------------- 128e7e6f12aSdanielk1977 129e7e6f12aSdanielk1977#------------------------------------------------------------------------- 130e7e6f12aSdanielk1977# Proc to compare database content with the in-memory representation. 131e7e6f12aSdanielk1977# 132e7e6f12aSdanielk1977# checkdb 133e7e6f12aSdanielk1977# 134e7e6f12aSdanielk1977proc checkdb {} { 135e7e6f12aSdanielk1977 set nEntry [db one {SELECT count(*) FROM t1}] 136e7e6f12aSdanielk1977 set nEntry2 [array size ::aEntry] 137e7e6f12aSdanielk1977 if {$nEntry != $nEntry2} { 138e7e6f12aSdanielk1977 error "$nEntry entries in database, $nEntry2 entries in array" 139e7e6f12aSdanielk1977 } 140e7e6f12aSdanielk1977 db eval {SELECT x, y FROM t1} { 141e7e6f12aSdanielk1977 if {![info exists ::aEntry($x)]} { 142e7e6f12aSdanielk1977 error "Entry $x exists in database, but not in array" 143e7e6f12aSdanielk1977 } 144e7e6f12aSdanielk1977 if {$::aEntry($x) ne $y} { 145e7e6f12aSdanielk1977 error "Entry $x is set to {$y} in database, {$::aEntry($x)} in array" 146e7e6f12aSdanielk1977 } 147e7e6f12aSdanielk1977 } 148e7e6f12aSdanielk1977 149e7e6f12aSdanielk1977 db eval { PRAGMA integrity_check } 150e7e6f12aSdanielk1977} 151e7e6f12aSdanielk1977#------------------------------------------------------------------------- 152e7e6f12aSdanielk1977 153e7e6f12aSdanielk1977#------------------------------------------------------------------------- 154e7e6f12aSdanielk1977# Proc to return random set of x values. 155e7e6f12aSdanielk1977# 156e7e6f12aSdanielk1977# random_integers 157e7e6f12aSdanielk1977# 158e7e6f12aSdanielk1977proc random_integers {nRes nRange} { 159e7e6f12aSdanielk1977 set ret [list] 160e7e6f12aSdanielk1977 for {set i 0} {$i<$nRes} {incr i} { 161e7e6f12aSdanielk1977 lappend ret [expr int(rand()*$nRange)] 162e7e6f12aSdanielk1977 } 163e7e6f12aSdanielk1977 return $ret 164e7e6f12aSdanielk1977} 165e7e6f12aSdanielk1977#------------------------------------------------------------------------- 166e7e6f12aSdanielk1977 167e7e6f12aSdanielk1977proc database_op {} { 168e7e6f12aSdanielk1977 set i [expr int(rand()*2)] 169e7e6f12aSdanielk1977 if {$i==0} { 170e7e6f12aSdanielk1977 insert_rows [random_integers 100 1000] 171e7e6f12aSdanielk1977 } 172e7e6f12aSdanielk1977 if {$i==1} { 173e7e6f12aSdanielk1977 delete_rows [random_integers 100 1000] 174e7e6f12aSdanielk1977 set i [expr int(rand()*3)] 175e7e6f12aSdanielk1977 if {$i==0} { 176f2c31ad8Sdanielk1977 sql {PRAGMA incremental_vacuum} 177e7e6f12aSdanielk1977 } 178e7e6f12aSdanielk1977 } 179e7e6f12aSdanielk1977} 180e7e6f12aSdanielk1977 181e7e6f12aSdanielk1977proc savepoint_op {} { 182e7e6f12aSdanielk1977 set names {one two three four five} 183e7e6f12aSdanielk1977 set cmds {savepoint savepoint savepoint savepoint release rollback} 184e7e6f12aSdanielk1977 185e7e6f12aSdanielk1977 set C [lindex $cmds [expr int(rand()*6)]] 186e7e6f12aSdanielk1977 set N [lindex $names [expr int(rand()*5)]] 187e7e6f12aSdanielk1977 188f2c31ad8Sdanielk1977 #puts stderr " $C $N ; " 189f2c31ad8Sdanielk1977 #flush stderr 190f2c31ad8Sdanielk1977 191e7e6f12aSdanielk1977 $C $N 192e7e6f12aSdanielk1977 return ok 193e7e6f12aSdanielk1977} 194e7e6f12aSdanielk1977 195f2c31ad8Sdanielk1977expr srand(0) 196f2c31ad8Sdanielk1977 197f2c31ad8Sdanielk1977############################################################################ 198f2c31ad8Sdanielk1977############################################################################ 199f2c31ad8Sdanielk1977# Start of test cases. 200f2c31ad8Sdanielk1977 201f2c31ad8Sdanielk1977do_test savepoint6-1.1 { 202f2c31ad8Sdanielk1977 sql $DATABASE_SCHEMA 203f2c31ad8Sdanielk1977} {} 204f2c31ad8Sdanielk1977do_test savepoint6-1.2 { 205f2c31ad8Sdanielk1977 insert_rows { 206f2c31ad8Sdanielk1977 497 166 230 355 779 588 394 317 290 475 362 193 805 851 564 207f2c31ad8Sdanielk1977 763 44 930 389 819 765 760 966 280 538 414 500 18 25 287 320 208f2c31ad8Sdanielk1977 30 382 751 87 283 981 429 630 974 421 270 810 405 209f2c31ad8Sdanielk1977 } 210f2c31ad8Sdanielk1977 211f2c31ad8Sdanielk1977 savepoint one 212f2c31ad8Sdanielk1977 insert_rows 858 213f2c31ad8Sdanielk1977 delete_rows 930 214f2c31ad8Sdanielk1977 savepoint two 215f2c31ad8Sdanielk1977 execsql {PRAGMA incremental_vacuum} 216f2c31ad8Sdanielk1977 savepoint three 217f2c31ad8Sdanielk1977 insert_rows 144 218f2c31ad8Sdanielk1977 rollback three 219f2c31ad8Sdanielk1977 rollback two 220f2c31ad8Sdanielk1977 release one 221f2c31ad8Sdanielk1977 222f2c31ad8Sdanielk1977 execsql {SELECT count(*) FROM t1} 223f2c31ad8Sdanielk1977} {44} 224f2c31ad8Sdanielk1977 225f2c31ad8Sdanielk1977foreach zSetup [list { 226f2c31ad8Sdanielk1977 set testname normal 227f2c31ad8Sdanielk1977 sqlite3 db test.db 228f2c31ad8Sdanielk1977} { 2294cd78b4dSdan if {[wal_is_wal_mode]} continue 230f2c31ad8Sdanielk1977 set testname tempdb 231f2c31ad8Sdanielk1977 sqlite3 db "" 232f2c31ad8Sdanielk1977} { 233430e74cdSdan if {[permutation] eq "journaltest"} { 234be871047Sdanielk1977 continue 235be871047Sdanielk1977 } 236be871047Sdanielk1977 set testname nosync 237be871047Sdanielk1977 sqlite3 db test.db 238be871047Sdanielk1977 sql { PRAGMA synchronous = off } 239be871047Sdanielk1977} { 240f2c31ad8Sdanielk1977 set testname smallcache 241f2c31ad8Sdanielk1977 sqlite3 db test.db 242f2c31ad8Sdanielk1977 sql { PRAGMA cache_size = 10 } 243f2c31ad8Sdanielk1977}] { 244f2c31ad8Sdanielk1977 245f2c31ad8Sdanielk1977 unset -nocomplain ::lSavepoint 246f2c31ad8Sdanielk1977 unset -nocomplain ::aEntry 247f2c31ad8Sdanielk1977 248be871047Sdanielk1977 catch { db close } 249*fda06befSmistachkin forcedelete test.db test.db-wal test.db-journal 250f2c31ad8Sdanielk1977 eval $zSetup 251f2c31ad8Sdanielk1977 sql $DATABASE_SCHEMA 252f2c31ad8Sdanielk1977 2534cd78b4dSdan wal_set_journal_mode 2544cd78b4dSdan 255f2c31ad8Sdanielk1977 do_test savepoint6-$testname.setup { 256e7e6f12aSdanielk1977 savepoint one 257e7e6f12aSdanielk1977 insert_rows [random_integers 100 1000] 258e7e6f12aSdanielk1977 release one 259e7e6f12aSdanielk1977 checkdb 260e7e6f12aSdanielk1977 } {ok} 261e7e6f12aSdanielk1977 262430e74cdSdan for {set i 0} {$i < $::G(savepoint6_iterations)} {incr i} { 263f2c31ad8Sdanielk1977 do_test savepoint6-$testname.$i.1 { 264e7e6f12aSdanielk1977 savepoint_op 265f2c31ad8Sdanielk1977 checkdb 266e7e6f12aSdanielk1977 } {ok} 267e7e6f12aSdanielk1977 268f2c31ad8Sdanielk1977 do_test savepoint6-$testname.$i.2 { 269e7e6f12aSdanielk1977 database_op 270e7e6f12aSdanielk1977 database_op 271e7e6f12aSdanielk1977 checkdb 272e7e6f12aSdanielk1977 } {ok} 273e7e6f12aSdanielk1977 } 2744cd78b4dSdan 2754cd78b4dSdan wal_check_journal_mode savepoint6-$testname.walok 276f2c31ad8Sdanielk1977} 277e7e6f12aSdanielk1977 278e7e6f12aSdanielk1977unset -nocomplain ::lSavepoint 279e7e6f12aSdanielk1977unset -nocomplain ::aEntry 280e7e6f12aSdanielk1977 281e7e6f12aSdanielk1977finish_test 282