xref: /sqlite-3.40.0/test/trans2.test (revision 1b4b334a)
1255538e9Sdrh# 2008 August 27
2255538e9Sdrh#
3255538e9Sdrh# The author disclaims copyright to this source code.  In place of
4255538e9Sdrh# a legal notice, here is a blessing:
5255538e9Sdrh#
6255538e9Sdrh#    May you do good and not evil.
7255538e9Sdrh#    May you find forgiveness for yourself and forgive others.
8255538e9Sdrh#    May you share freely, never taking more than you give.
9255538e9Sdrh#
10255538e9Sdrh#***********************************************************************
11255538e9Sdrh#
12255538e9Sdrh# This file implements regression tests for SQLite library.  The
13255538e9Sdrh# focus of this script is transactions
14255538e9Sdrh#
15255538e9Sdrh# $Id: trans2.test,v 1.1 2008/08/27 18:56:36 drh Exp $
16255538e9Sdrh#
17255538e9Sdrhset testdir [file dirname $argv0]
18255538e9Sdrhsource $testdir/tester.tcl
19255538e9Sdrh
20255538e9Sdrh# A procedure to scramble the elements of list $inlist into a random order.
21255538e9Sdrh#
22255538e9Sdrhproc scramble {inlist} {
23255538e9Sdrh  set y {}
24255538e9Sdrh  foreach x $inlist {
25255538e9Sdrh    lappend y [list [expr {rand()}] $x]
26255538e9Sdrh  }
27255538e9Sdrh  set y [lsort $y]
28255538e9Sdrh  set outlist {}
29255538e9Sdrh  foreach x $y {
30255538e9Sdrh    lappend outlist [lindex $x 1]
31255538e9Sdrh  }
32255538e9Sdrh  return $outlist
33255538e9Sdrh}
34255538e9Sdrh
35255538e9Sdrh# Generate a UUID using randomness.
36255538e9Sdrh#
37255538e9Sdrhexpr srand(1)
38255538e9Sdrhproc random_uuid {} {
39255538e9Sdrh  set u {}
40255538e9Sdrh  for {set i 0} {$i<5} {incr i} {
41255538e9Sdrh    append u [format %06x [expr {int(rand()*16777216)}]]
42255538e9Sdrh  }
43255538e9Sdrh  return $u
44255538e9Sdrh}
45255538e9Sdrh
46255538e9Sdrh# Compute hashes on the u1 and u2 fields of the sample data.
47255538e9Sdrh#
48255538e9Sdrhproc hash1 {} {
49255538e9Sdrh  global data
50255538e9Sdrh  set x ""
51255538e9Sdrh  foreach rec [lsort -integer -index 0 $data] {
52255538e9Sdrh    append x [lindex $rec 1]
53255538e9Sdrh  }
54255538e9Sdrh  return [md5 $x]
55255538e9Sdrh}
56255538e9Sdrhproc hash2 {} {
57255538e9Sdrh  global data
58255538e9Sdrh  set x ""
59255538e9Sdrh  foreach rec [lsort -integer -index 0 $data] {
60255538e9Sdrh    append x [lindex $rec 3]
61255538e9Sdrh  }
62255538e9Sdrh  return [md5 $x]
63255538e9Sdrh}
64255538e9Sdrh
65255538e9Sdrh# Create the initial data set
66255538e9Sdrh#
67255538e9Sdrhunset -nocomplain data i max_rowid todel n rec max1 id origres newres
68255538e9Sdrhunset -nocomplain inssql modsql s j z
69255538e9Sdrhset data {}
70255538e9Sdrhfor {set i 0} {$i<400} {incr i} {
71255538e9Sdrh  set rec [list $i [random_uuid] [expr {int(rand()*5000)+1000}] [random_uuid]]
72255538e9Sdrh  lappend data $rec
73255538e9Sdrh}
74255538e9Sdrhset max_rowid [expr {$i-1}]
75255538e9Sdrh
76255538e9Sdrh# Create the T1 table used to hold test data.  Populate that table with
77255538e9Sdrh# the initial data set and check hashes to make sure everything is correct.
78255538e9Sdrh#
79255538e9Sdrhdo_test trans2-1.1 {
80255538e9Sdrh  execsql {
81255538e9Sdrh    PRAGMA cache_size=100;
82255538e9Sdrh    CREATE TABLE t1(
83255538e9Sdrh      id INTEGER PRIMARY KEY,
84255538e9Sdrh      u1 TEXT UNIQUE,
85255538e9Sdrh      z BLOB NOT NULL,
86255538e9Sdrh      u2 TEXT UNIQUE
87255538e9Sdrh    );
88255538e9Sdrh  }
89255538e9Sdrh  foreach rec [scramble $data] {
90255538e9Sdrh    foreach {id u1 z u2} $rec break
91255538e9Sdrh    db eval {INSERT INTO t1 VALUES($id,$u1,zeroblob($z),$u2)}
92255538e9Sdrh  }
93255538e9Sdrh  db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
94255538e9Sdrh} [list [hash1] [hash2]]
95255538e9Sdrh
96255538e9Sdrh# Repeat the main test loop multiple times.
97255538e9Sdrh#
98255538e9Sdrhfor {set i 2} {$i<=30} {incr i} {
99255538e9Sdrh  # Delete one row out of every 10 in the database.  This will add
100255538e9Sdrh  # many pages to the freelist.
101255538e9Sdrh  #
102255538e9Sdrh  set todel {}
103255538e9Sdrh  set n [expr {[llength $data]/10}]
104255538e9Sdrh  set data [scramble $data]
105255538e9Sdrh  foreach rec [lrange $data 0 $n] {
106255538e9Sdrh    lappend todel [lindex $rec 0]
107255538e9Sdrh  }
108255538e9Sdrh  set data [lrange $data [expr {$n+1}] end]
109255538e9Sdrh  set max1 [lindex [lindex $data 0] 0]
110255538e9Sdrh  foreach rec $data {
111255538e9Sdrh    set id [lindex $rec 0]
112255538e9Sdrh    if {$id>$max1} {set max1 $id}
113255538e9Sdrh  }
114255538e9Sdrh  set origres [list [hash1] [hash2]]
115255538e9Sdrh  do_test trans2-$i.1 {
116255538e9Sdrh    db eval "DELETE FROM t1 WHERE id IN ([join $todel ,])"
117255538e9Sdrh    db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
118255538e9Sdrh  } $origres
119255538e9Sdrh  integrity_check trans2-$i.2
120255538e9Sdrh
121255538e9Sdrh  # Begin a transaction and insert many new records.
122255538e9Sdrh  #
123255538e9Sdrh  set newdata {}
124255538e9Sdrh  foreach id $todel {
125255538e9Sdrh    set rec [list $id [random_uuid] \
126255538e9Sdrh                      [expr {int(rand()*5000)+1000}] [random_uuid]]
127255538e9Sdrh    lappend newdata $rec
128255538e9Sdrh    lappend data $rec
129255538e9Sdrh  }
130255538e9Sdrh  for {set j 1} {$j<50} {incr j} {
131255538e9Sdrh    set id [expr {$max_rowid+$j}]
132255538e9Sdrh    lappend todel $id
133255538e9Sdrh    set rec [list $id [random_uuid] \
134255538e9Sdrh                      [expr {int(rand()*5000)+1000}] [random_uuid]]
135255538e9Sdrh    lappend newdata $rec
136255538e9Sdrh    lappend data $rec
137255538e9Sdrh  }
138255538e9Sdrh  set max_rowid [expr {$max_rowid+$j-1}]
139255538e9Sdrh  set modsql {}
140255538e9Sdrh  set inssql {}
141255538e9Sdrh  set newres [list [hash1] [hash2]]
142255538e9Sdrh  do_test trans2-$i.3 {
143255538e9Sdrh    db eval BEGIN
144255538e9Sdrh    foreach rec [scramble $newdata] {
145255538e9Sdrh      foreach {id u1 z u2} $rec break
146255538e9Sdrh      set s "INSERT INTO t1 VALUES($id,'$u1',zeroblob($z),'$u2');"
147255538e9Sdrh      append modsql $s\n
148255538e9Sdrh      append inssql $s\n
149255538e9Sdrh      db eval $s
150255538e9Sdrh    }
151255538e9Sdrh    db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
152255538e9Sdrh  } $newres
153255538e9Sdrh  integrity_check trans2-$i.4
154255538e9Sdrh
155255538e9Sdrh  # Do a large update that aborts do to a constraint failure near
156255538e9Sdrh  # the end.  This stresses the statement journal mechanism.
157255538e9Sdrh  #
158255538e9Sdrh  do_test trans2-$i.10 {
159255538e9Sdrh    catchsql {
160255538e9Sdrh      UPDATE t1 SET u1=u1||'x',
161255538e9Sdrh          z = CASE WHEN id<$max_rowid
162255538e9Sdrh                   THEN zeroblob((random()&65535)%5000 + 1000) END;
163255538e9Sdrh    }
164*1b4b334aSdan  } {1 {NOT NULL constraint failed: t1.z}}
165255538e9Sdrh  do_test trans2-$i.11 {
166255538e9Sdrh    db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
167255538e9Sdrh  } $newres
168255538e9Sdrh
169255538e9Sdrh  # Delete all of the newly inserted records.  Verify that the database
170255538e9Sdrh  # is back to its original state.
171255538e9Sdrh  #
172255538e9Sdrh  do_test trans2-$i.20 {
173255538e9Sdrh    set s "DELETE FROM t1 WHERE id IN ([join $todel ,]);"
174255538e9Sdrh    append modsql $s\n
175255538e9Sdrh    db eval $s
176255538e9Sdrh    db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
177255538e9Sdrh  } $origres
178255538e9Sdrh
179255538e9Sdrh  # Do another large update that aborts do to a constraint failure near
180255538e9Sdrh  # the end.  This stresses the statement journal mechanism.
181255538e9Sdrh  #
182255538e9Sdrh  do_test trans2-$i.30 {
183255538e9Sdrh    catchsql {
184255538e9Sdrh      UPDATE t1 SET u1=u1||'x',
185255538e9Sdrh          z = CASE WHEN id<$max1
186255538e9Sdrh                   THEN zeroblob((random()&65535)%5000 + 1000) END;
187255538e9Sdrh    }
188*1b4b334aSdan  } {1 {NOT NULL constraint failed: t1.z}}
189255538e9Sdrh  do_test trans2-$i.31 {
190255538e9Sdrh    db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
191255538e9Sdrh  } $origres
192255538e9Sdrh
193255538e9Sdrh  # Redo the inserts
194255538e9Sdrh  #
195255538e9Sdrh  do_test trans2-$i.40 {
196255538e9Sdrh    db eval $inssql
197255538e9Sdrh    append modsql $inssql
198255538e9Sdrh    db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
199255538e9Sdrh  } $newres
200255538e9Sdrh
201255538e9Sdrh  # Rollback the transaction.  Verify that the content is restored.
202255538e9Sdrh  #
203255538e9Sdrh  do_test trans2-$i.90 {
204255538e9Sdrh    db eval ROLLBACK
205255538e9Sdrh    db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
206255538e9Sdrh  } $origres
207255538e9Sdrh  integrity_check trans2-$i.91
208255538e9Sdrh
209255538e9Sdrh  # Repeat all the changes, but this time commit.
210255538e9Sdrh  #
211255538e9Sdrh  do_test trans2-$i.92 {
212255538e9Sdrh    db eval BEGIN
213255538e9Sdrh    catchsql {
214255538e9Sdrh      UPDATE t1 SET u1=u1||'x',
215255538e9Sdrh          z = CASE WHEN id<$max1
216255538e9Sdrh                   THEN zeroblob((random()&65535)%5000 + 1000) END;
217255538e9Sdrh    }
218255538e9Sdrh    db eval $modsql
219255538e9Sdrh    catchsql {
220255538e9Sdrh      UPDATE t1 SET u1=u1||'x',
221255538e9Sdrh          z = CASE WHEN id<$max1
222255538e9Sdrh                   THEN zeroblob((random()&65535)%5000 + 1000) END;
223255538e9Sdrh    }
224255538e9Sdrh    db eval COMMIT
225255538e9Sdrh    db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
226255538e9Sdrh  } $newres
227255538e9Sdrh  integrity_check trans2-$i.93
228255538e9Sdrh}
229255538e9Sdrh
230255538e9Sdrhunset -nocomplain data i max_rowid todel n rec max1 id origres newres
231255538e9Sdrhunset -nocomplain inssql modsql s j z
232255538e9Sdrhfinish_test
233