xref: /sqlite-3.40.0/test/savepoint6.test (revision fda06bef)
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