trans2.test 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. # 2008 August 27
  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. #
  12. # This file implements regression tests for SQLite library. The
  13. # focus of this script is transactions
  14. #
  15. # $Id: trans2.test,v 1.1 2008/08/27 18:56:36 drh Exp $
  16. #
  17. set testdir [file dirname $argv0]
  18. source $testdir/tester.tcl
  19. # A procedure to scramble the elements of list $inlist into a random order.
  20. #
  21. proc scramble {inlist} {
  22. set y {}
  23. foreach x $inlist {
  24. lappend y [list [expr {rand()}] $x]
  25. }
  26. set y [lsort $y]
  27. set outlist {}
  28. foreach x $y {
  29. lappend outlist [lindex $x 1]
  30. }
  31. return $outlist
  32. }
  33. # Generate a UUID using randomness.
  34. #
  35. expr srand(1)
  36. proc random_uuid {} {
  37. set u {}
  38. for {set i 0} {$i<5} {incr i} {
  39. append u [format %06x [expr {int(rand()*16777216)}]]
  40. }
  41. return $u
  42. }
  43. # Compute hashes on the u1 and u2 fields of the sample data.
  44. #
  45. proc hash1 {} {
  46. global data
  47. set x ""
  48. foreach rec [lsort -integer -index 0 $data] {
  49. append x [lindex $rec 1]
  50. }
  51. return [md5 $x]
  52. }
  53. proc hash2 {} {
  54. global data
  55. set x ""
  56. foreach rec [lsort -integer -index 0 $data] {
  57. append x [lindex $rec 3]
  58. }
  59. return [md5 $x]
  60. }
  61. # Create the initial data set
  62. #
  63. unset -nocomplain data i max_rowid todel n rec max1 id origres newres
  64. unset -nocomplain inssql modsql s j z
  65. set data {}
  66. for {set i 0} {$i<400} {incr i} {
  67. set rec [list $i [random_uuid] [expr {int(rand()*5000)+1000}] [random_uuid]]
  68. lappend data $rec
  69. }
  70. set max_rowid [expr {$i-1}]
  71. # Create the T1 table used to hold test data. Populate that table with
  72. # the initial data set and check hashes to make sure everything is correct.
  73. #
  74. do_test trans2-1.1 {
  75. execsql {
  76. PRAGMA cache_size=100;
  77. CREATE TABLE t1(
  78. id INTEGER PRIMARY KEY,
  79. u1 TEXT UNIQUE,
  80. z BLOB NOT NULL,
  81. u2 TEXT UNIQUE
  82. );
  83. }
  84. foreach rec [scramble $data] {
  85. foreach {id u1 z u2} $rec break
  86. db eval {INSERT INTO t1 VALUES($id,$u1,zeroblob($z),$u2)}
  87. }
  88. db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
  89. } [list [hash1] [hash2]]
  90. # Repeat the main test loop multiple times.
  91. #
  92. for {set i 2} {$i<=30} {incr i} {
  93. # Delete one row out of every 10 in the database. This will add
  94. # many pages to the freelist.
  95. #
  96. set todel {}
  97. set n [expr {[llength $data]/10}]
  98. set data [scramble $data]
  99. foreach rec [lrange $data 0 $n] {
  100. lappend todel [lindex $rec 0]
  101. }
  102. set data [lrange $data [expr {$n+1}] end]
  103. set max1 [lindex [lindex $data 0] 0]
  104. foreach rec $data {
  105. set id [lindex $rec 0]
  106. if {$id>$max1} {set max1 $id}
  107. }
  108. set origres [list [hash1] [hash2]]
  109. do_test trans2-$i.1 {
  110. db eval "DELETE FROM t1 WHERE id IN ([join $todel ,])"
  111. db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
  112. } $origres
  113. integrity_check trans2-$i.2
  114. # Begin a transaction and insert many new records.
  115. #
  116. set newdata {}
  117. foreach id $todel {
  118. set rec [list $id [random_uuid] \
  119. [expr {int(rand()*5000)+1000}] [random_uuid]]
  120. lappend newdata $rec
  121. lappend data $rec
  122. }
  123. for {set j 1} {$j<50} {incr j} {
  124. set id [expr {$max_rowid+$j}]
  125. lappend todel $id
  126. set rec [list $id [random_uuid] \
  127. [expr {int(rand()*5000)+1000}] [random_uuid]]
  128. lappend newdata $rec
  129. lappend data $rec
  130. }
  131. set max_rowid [expr {$max_rowid+$j-1}]
  132. set modsql {}
  133. set inssql {}
  134. set newres [list [hash1] [hash2]]
  135. do_test trans2-$i.3 {
  136. db eval BEGIN
  137. foreach rec [scramble $newdata] {
  138. foreach {id u1 z u2} $rec break
  139. set s "INSERT INTO t1 VALUES($id,'$u1',zeroblob($z),'$u2');"
  140. append modsql $s\n
  141. append inssql $s\n
  142. db eval $s
  143. }
  144. db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
  145. } $newres
  146. integrity_check trans2-$i.4
  147. # Do a large update that aborts do to a constraint failure near
  148. # the end. This stresses the statement journal mechanism.
  149. #
  150. do_test trans2-$i.10 {
  151. catchsql {
  152. UPDATE t1 SET u1=u1||'x',
  153. z = CASE WHEN id<$max_rowid
  154. THEN zeroblob((random()&65535)%5000 + 1000) END;
  155. }
  156. } {1 {t1.z may not be NULL}}
  157. do_test trans2-$i.11 {
  158. db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
  159. } $newres
  160. # Delete all of the newly inserted records. Verify that the database
  161. # is back to its original state.
  162. #
  163. do_test trans2-$i.20 {
  164. set s "DELETE FROM t1 WHERE id IN ([join $todel ,]);"
  165. append modsql $s\n
  166. db eval $s
  167. db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
  168. } $origres
  169. # Do another large update that aborts do to a constraint failure near
  170. # the end. This stresses the statement journal mechanism.
  171. #
  172. do_test trans2-$i.30 {
  173. catchsql {
  174. UPDATE t1 SET u1=u1||'x',
  175. z = CASE WHEN id<$max1
  176. THEN zeroblob((random()&65535)%5000 + 1000) END;
  177. }
  178. } {1 {t1.z may not be NULL}}
  179. do_test trans2-$i.31 {
  180. db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
  181. } $origres
  182. # Redo the inserts
  183. #
  184. do_test trans2-$i.40 {
  185. db eval $inssql
  186. append modsql $inssql
  187. db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
  188. } $newres
  189. # Rollback the transaction. Verify that the content is restored.
  190. #
  191. do_test trans2-$i.90 {
  192. db eval ROLLBACK
  193. db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
  194. } $origres
  195. integrity_check trans2-$i.91
  196. # Repeat all the changes, but this time commit.
  197. #
  198. do_test trans2-$i.92 {
  199. db eval BEGIN
  200. catchsql {
  201. UPDATE t1 SET u1=u1||'x',
  202. z = CASE WHEN id<$max1
  203. THEN zeroblob((random()&65535)%5000 + 1000) END;
  204. }
  205. db eval $modsql
  206. catchsql {
  207. UPDATE t1 SET u1=u1||'x',
  208. z = CASE WHEN id<$max1
  209. THEN zeroblob((random()&65535)%5000 + 1000) END;
  210. }
  211. db eval COMMIT
  212. db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
  213. } $newres
  214. integrity_check trans2-$i.93
  215. }
  216. unset -nocomplain data i max_rowid todel n rec max1 id origres newres
  217. unset -nocomplain inssql modsql s j z
  218. finish_test