interrupt.test 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. # 2004 Feb 8
  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. # This file implements regression tests for SQLite library. The
  12. # focus of this script is the sqlite_interrupt() API.
  13. #
  14. # $Id: interrupt.test,v 1.16 2008/01/16 17:46:38 drh Exp $
  15. set testdir [file dirname $argv0]
  16. source $testdir/tester.tcl
  17. set DB [sqlite3_connection_pointer db]
  18. # This routine attempts to execute the sql in $sql. It triggers an
  19. # interrupt at progressively later and later points during the processing
  20. # and checks to make sure SQLITE_INTERRUPT is returned. Eventually,
  21. # the routine completes successfully.
  22. #
  23. proc interrupt_test {testid sql result {initcnt 0}} {
  24. set orig_sum [cksum]
  25. set i $initcnt
  26. while 1 {
  27. incr i
  28. set ::sqlite_interrupt_count $i
  29. do_test $testid.$i.1 [format {
  30. set ::r [catchsql %s]
  31. set ::code [db errorcode]
  32. expr {$::code==0 || $::code==9}
  33. } [list $sql]] 1
  34. if {$::code==9} {
  35. do_test $testid.$i.2 {
  36. cksum
  37. } $orig_sum
  38. } else {
  39. do_test $testid.$i.99 {
  40. set ::r
  41. } [list 0 $result]
  42. break
  43. }
  44. }
  45. set ::sqlite_interrupt_count 0
  46. }
  47. do_test interrupt-1.1 {
  48. execsql {
  49. CREATE TABLE t1(a,b);
  50. SELECT name FROM sqlite_master;
  51. }
  52. } {t1}
  53. interrupt_test interrupt-1.2 {DROP TABLE t1} {}
  54. do_test interrupt-1.3 {
  55. execsql {
  56. SELECT name FROM sqlite_master;
  57. }
  58. } {}
  59. integrity_check interrupt-1.4
  60. do_test interrrupt-2.1 {
  61. execsql {
  62. BEGIN;
  63. CREATE TABLE t1(a,b);
  64. INSERT INTO t1 VALUES(1,randstr(300,400));
  65. INSERT INTO t1 SELECT a+1, randstr(300,400) FROM t1;
  66. INSERT INTO t1 SELECT a+2, a || '-' || b FROM t1;
  67. INSERT INTO t1 SELECT a+4, a || '-' || b FROM t1;
  68. INSERT INTO t1 SELECT a+8, a || '-' || b FROM t1;
  69. INSERT INTO t1 SELECT a+16, a || '-' || b FROM t1;
  70. INSERT INTO t1 SELECT a+32, a || '-' || b FROM t1;
  71. COMMIT;
  72. UPDATE t1 SET b=substr(b,-5,5);
  73. SELECT count(*) from t1;
  74. }
  75. } 64
  76. set origsize [file size test.db]
  77. set cksum [db eval {SELECT md5sum(a || b) FROM t1}]
  78. ifcapable {vacuum} {
  79. interrupt_test interrupt-2.2 {VACUUM} {} 100
  80. }
  81. do_test interrupt-2.3 {
  82. execsql {
  83. SELECT md5sum(a || b) FROM t1;
  84. }
  85. } $cksum
  86. ifcapable {vacuum && !default_autovacuum} {
  87. do_test interrupt-2.4 {
  88. expr {$::origsize>[file size test.db]}
  89. } 1
  90. }
  91. ifcapable {explain} {
  92. do_test interrupt-2.5 {
  93. set sql {EXPLAIN SELECT max(a,b), a, b FROM t1}
  94. execsql $sql
  95. set rc [catch {db eval $sql {sqlite3_interrupt $DB}} msg]
  96. lappend rc $msg
  97. } {1 interrupted}
  98. }
  99. integrity_check interrupt-2.6
  100. # Ticket #594. If an interrupt occurs in the middle of a transaction
  101. # and that transaction is later rolled back, the internal schema tables do
  102. # not reset.
  103. #
  104. # UPDATE: Interrupting a DML statement in the middle of a transaction now
  105. # causes the transaction to roll back. Leaving the transaction open after
  106. # an SQL statement was interrupted halfway through risks database corruption.
  107. #
  108. ifcapable tempdb {
  109. for {set i 1} {$i<50} {incr i 5} {
  110. do_test interrupt-3.$i.1 {
  111. execsql {
  112. BEGIN;
  113. CREATE TEMP TABLE t2(x,y);
  114. SELECT name FROM sqlite_temp_master;
  115. }
  116. } {t2}
  117. do_test interrupt-3.$i.2 {
  118. set ::sqlite_interrupt_count $::i
  119. catchsql {
  120. INSERT INTO t2 SELECT * FROM t1;
  121. }
  122. } {1 interrupted}
  123. do_test interrupt-3.$i.3 {
  124. execsql {
  125. SELECT name FROM sqlite_temp_master;
  126. }
  127. } {}
  128. do_test interrupt-3.$i.4 {
  129. catchsql {
  130. ROLLBACK
  131. }
  132. } {1 {cannot rollback - no transaction is active}}
  133. do_test interrupt-3.$i.5 {
  134. catchsql {SELECT name FROM sqlite_temp_master};
  135. execsql {
  136. SELECT name FROM sqlite_temp_master;
  137. }
  138. } {}
  139. }
  140. }
  141. # There are reports of a memory leak if an interrupt occurs during
  142. # the beginning of a complex query - before the first callback. We
  143. # will try to reproduce it here:
  144. #
  145. execsql {
  146. CREATE TABLE t2(a,b,c);
  147. INSERT INTO t2 SELECT round(a/10), randstr(50,80), randstr(50,60) FROM t1;
  148. }
  149. set sql {
  150. SELECT max(min(b,c)), min(max(b,c)), a FROM t2 GROUP BY a ORDER BY a;
  151. }
  152. set sqlite_interrupt_count 1000000
  153. execsql $sql
  154. set max_count [expr {1000000-$sqlite_interrupt_count}]
  155. for {set i 1} {$i<$max_count-5} {incr i 1} {
  156. do_test interrupt-4.$i.1 {
  157. set ::sqlite_interrupt_count $::i
  158. catchsql $sql
  159. } {1 interrupted}
  160. }
  161. if {0} { # This doesn't work anymore since the collation factor is
  162. # no longer called during schema parsing.
  163. # Interrupt during parsing
  164. #
  165. do_test interrupt-5.1 {
  166. proc fake_interrupt {args} {
  167. db collate fake_collation no-op
  168. sqlite3_interrupt db
  169. return SQLITE_OK
  170. }
  171. db collation_needed fake_interrupt
  172. catchsql {
  173. CREATE INDEX fake ON fake1(a COLLATE fake_collation, b, c DESC);
  174. }
  175. } {1 interrupt}
  176. }
  177. finish_test