progress.test 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. # 2001 September 15
  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 file is testing the 'progress callback'.
  13. #
  14. # $Id: progress.test,v 1.8 2007/06/15 14:53:53 danielk1977 Exp $
  15. set testdir [file dirname $argv0]
  16. source $testdir/tester.tcl
  17. # If the progress callback is not available in this build, skip this
  18. # whole file.
  19. ifcapable !progress {
  20. finish_test
  21. return
  22. }
  23. # Build some test data
  24. #
  25. execsql {
  26. BEGIN;
  27. CREATE TABLE t1(a);
  28. INSERT INTO t1 VALUES(1);
  29. INSERT INTO t1 VALUES(2);
  30. INSERT INTO t1 VALUES(3);
  31. INSERT INTO t1 VALUES(4);
  32. INSERT INTO t1 VALUES(5);
  33. INSERT INTO t1 VALUES(6);
  34. INSERT INTO t1 VALUES(7);
  35. INSERT INTO t1 VALUES(8);
  36. INSERT INTO t1 VALUES(9);
  37. INSERT INTO t1 VALUES(10);
  38. COMMIT;
  39. }
  40. # Test that the progress callback is invoked.
  41. do_test progress-1.0 {
  42. set counter 0
  43. db progress 1 "[namespace code {incr counter}] ; expr 0"
  44. execsql {
  45. SELECT * FROM t1
  46. }
  47. expr $counter > 1
  48. } 1
  49. do_test progress-1.0.1 {
  50. db progress
  51. } {::namespace inscope :: {incr counter} ; expr 0}
  52. do_test progress-1.0.2 {
  53. set v [catch {db progress xyz bogus} msg]
  54. lappend v $msg
  55. } {1 {expected integer but got "xyz"}}
  56. # Test that the query is abandoned when the progress callback returns non-zero
  57. do_test progress-1.1 {
  58. set counter 0
  59. db progress 1 "[namespace code {incr counter}] ; expr 1"
  60. set rc [catch {execsql {
  61. SELECT * FROM t1
  62. }}]
  63. list $counter $rc
  64. } {1 1}
  65. # Test that the query is rolled back when the progress callback returns
  66. # non-zero.
  67. do_test progress-1.2 {
  68. # This figures out how many opcodes it takes to copy 5 extra rows into t1.
  69. db progress 1 "[namespace code {incr five_rows}] ; expr 0"
  70. set five_rows 0
  71. execsql {
  72. INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 6
  73. }
  74. db progress 0 ""
  75. execsql {
  76. DELETE FROM t1 WHERE a > 10
  77. }
  78. # Now set up the progress callback to abandon the query after the number of
  79. # opcodes to copy 5 rows. That way, when we try to copy 6 rows, we know
  80. # some data will have been inserted into the table by the time the progress
  81. # callback abandons the query.
  82. db progress $five_rows "expr 1"
  83. catchsql {
  84. INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 9
  85. }
  86. execsql {
  87. SELECT count(*) FROM t1
  88. }
  89. } 10
  90. # Test that an active transaction remains active and not rolled back
  91. # after the progress query abandons a query.
  92. #
  93. # UPDATE: It is now recognised that this is a sure route to database
  94. # corruption. So the transaction is rolled back.
  95. do_test progress-1.3 {
  96. db progress 0 ""
  97. execsql BEGIN
  98. execsql {
  99. INSERT INTO t1 VALUES(11)
  100. }
  101. db progress 1 "expr 1"
  102. catchsql {
  103. INSERT INTO t1 VALUES(12)
  104. }
  105. db progress 0 ""
  106. catchsql COMMIT
  107. } {1 {cannot commit - no transaction is active}}
  108. do_test progress-1.3.1 {
  109. execsql {
  110. SELECT count(*) FROM t1
  111. }
  112. } 10
  113. # Check that a value of 0 for N means no progress callback
  114. do_test progress-1.4 {
  115. set counter 0
  116. db progress 0 "[namespace code {incr counter}] ; expr 0"
  117. execsql {
  118. SELECT * FROM t1;
  119. }
  120. set counter
  121. } 0
  122. db progress 0 ""
  123. # Make sure other queries can be run from within the progress
  124. # handler. Ticket #1827
  125. #
  126. do_test progress-1.5 {
  127. set rx 0
  128. proc set_rx {args} {
  129. db progress 0 {}
  130. set ::rx [db eval {SELECT count(*) FROM t1}]
  131. return [expr 0]
  132. }
  133. db progress 10 set_rx
  134. db eval {
  135. SELECT sum(a) FROM t1
  136. }
  137. } {55}
  138. do_test progress-1.6 {
  139. set ::rx
  140. } {10}
  141. # Check that abandoning a query using the progress handler does
  142. # not cause other queries to abort. Ticket #2415.
  143. do_test progress-1.7 {
  144. execsql {
  145. CREATE TABLE abc(a, b, c);
  146. INSERT INTO abc VALUES(1, 2, 3);
  147. INSERT INTO abc VALUES(4, 5, 6);
  148. INSERT INTO abc VALUES(7, 8, 9);
  149. }
  150. set ::res [list]
  151. explain {SELECT a, b, c FROM abc}
  152. db eval {SELECT a, b, c FROM abc} {
  153. lappend ::res $a $b $c
  154. db progress 5 "expr 1"
  155. catch {db eval {SELECT a, b, c FROM abc} { }} msg
  156. db progress 5 "expr 0"
  157. lappend ::res $msg
  158. }
  159. set ::res
  160. } {1 2 3 interrupted 4 5 6 interrupted 7 8 9 interrupted}
  161. finish_test