crash.test 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  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.
  12. #
  13. # The focus of this file is testing the ability of the database to
  14. # uses its rollback journal to recover intact (no database corruption)
  15. # from a power failure during the middle of a COMMIT. The OS interface
  16. # modules are overloaded using the modified I/O routines found in test6.c.
  17. # These routines allow us to simulate the kind of file damage that
  18. # occurs after a power failure.
  19. #
  20. # $Id: crash.test,v 1.27 2008/01/08 15:18:52 drh Exp $
  21. set testdir [file dirname $argv0]
  22. source $testdir/tester.tcl
  23. ifcapable !crashtest {
  24. finish_test
  25. return
  26. }
  27. set repeats 100
  28. #set repeats 10
  29. # The following procedure computes a "signature" for table "abc". If
  30. # abc changes in any way, the signature should change.
  31. proc signature {} {
  32. return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc}]
  33. }
  34. proc signature2 {} {
  35. return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc2}]
  36. }
  37. #--------------------------------------------------------------------------
  38. # Simple crash test:
  39. #
  40. # crash-1.1: Create a database with a table with two rows.
  41. # crash-1.2: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
  42. # the first journal-sync.
  43. # crash-1.3: Ensure the database is in the same state as after crash-1.1.
  44. # crash-1.4: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
  45. # the first database-sync.
  46. # crash-1.5: Ensure the database is in the same state as after crash-1.1.
  47. # crash-1.6: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
  48. # the second journal-sync.
  49. # crash-1.7: Ensure the database is in the same state as after crash-1.1.
  50. #
  51. # Tests 1.8 through 1.11 test for crashes on the third journal sync and
  52. # second database sync. Neither of these is required in such a small test
  53. # case, so these tests are just to verify that the test infrastructure
  54. # operates as expected.
  55. #
  56. do_test crash-1.1 {
  57. execsql {
  58. CREATE TABLE abc(a, b, c);
  59. INSERT INTO abc VALUES(1, 2, 3);
  60. INSERT INTO abc VALUES(4, 5, 6);
  61. }
  62. set ::sig [signature]
  63. expr 0
  64. } {0}
  65. for {set i 0} {$i<10} {incr i} {
  66. set seed [expr {int(abs(rand()*10000))}]
  67. do_test crash-1.2.$i {
  68. crashsql -delay 1 -file test.db-journal -seed $seed {
  69. DELETE FROM abc WHERE a = 1;
  70. }
  71. } {1 {child process exited abnormally}}
  72. do_test crash-1.3.$i {
  73. signature
  74. } $::sig
  75. }
  76. do_test crash-1.4 {
  77. crashsql -delay 1 -file test.db {
  78. DELETE FROM abc WHERE a = 1;
  79. }
  80. } {1 {child process exited abnormally}}
  81. do_test crash-1.5 {
  82. signature
  83. } $::sig
  84. do_test crash-1.6 {
  85. crashsql -delay 2 -file test.db-journal {
  86. DELETE FROM abc WHERE a = 1;
  87. }
  88. } {1 {child process exited abnormally}}
  89. do_test crash-1.7 {
  90. catchsql {
  91. SELECT * FROM abc;
  92. }
  93. } {0 {1 2 3 4 5 6}}
  94. do_test crash-1.8 {
  95. crashsql -delay 3 -file test.db-journal {
  96. DELETE FROM abc WHERE a = 1;
  97. }
  98. } {0 {}}
  99. do_test crash-1.9 {
  100. catchsql {
  101. SELECT * FROM abc;
  102. }
  103. } {0 {4 5 6}}
  104. do_test crash-1.10 {
  105. crashsql -delay 2 -file test.db {
  106. DELETE FROM abc WHERE a = 4;
  107. }
  108. } {0 {}}
  109. do_test crash-1.11 {
  110. catchsql {
  111. SELECT * FROM abc;
  112. }
  113. } {0 {}}
  114. #--------------------------------------------------------------------------
  115. # The following tests test recovery when both the database file and the
  116. # journal file contain corrupt data. This can happen after pages are
  117. # written to the database file before a transaction is committed due to
  118. # cache-pressure.
  119. #
  120. # crash-2.1: Insert 18 pages of data into the database.
  121. # crash-2.2: Check the database file size looks ok.
  122. # crash-2.3: Delete 15 or so pages (with a 10 page page-cache), then crash.
  123. # crash-2.4: Ensure the database is in the same state as after crash-2.1.
  124. #
  125. # Test cases crash-2.5 and crash-2.6 check that the database is OK if the
  126. # crash occurs during the main database file sync. But this isn't really
  127. # different from the crash-1.* cases.
  128. #
  129. do_test crash-2.1 {
  130. execsql { BEGIN }
  131. for {set n 0} {$n < 1000} {incr n} {
  132. execsql "INSERT INTO abc VALUES($n, [expr 2*$n], [expr 3*$n])"
  133. }
  134. execsql { COMMIT }
  135. set ::sig [signature]
  136. execsql { SELECT sum(a), sum(b), sum(c) from abc }
  137. } {499500 999000 1498500}
  138. do_test crash-2.2 {
  139. expr ([file size test.db] / 1024)>16
  140. } {1}
  141. do_test crash-2.3 {
  142. crashsql -delay 2 -file test.db-journal {
  143. DELETE FROM abc WHERE a < 800;
  144. }
  145. } {1 {child process exited abnormally}}
  146. do_test crash-2.4 {
  147. signature
  148. } $sig
  149. do_test crash-2.5 {
  150. crashsql -delay 1 -file test.db {
  151. DELETE FROM abc WHERE a<800;
  152. }
  153. } {1 {child process exited abnormally}}
  154. do_test crash-2.6 {
  155. signature
  156. } $sig
  157. #--------------------------------------------------------------------------
  158. # The crash-3.* test cases are essentially the same test as test case
  159. # crash-2.*, but with a more complicated data set.
  160. #
  161. # The test is repeated a few times with different seeds for the random
  162. # number generator in the crashing executable. Because there is no way to
  163. # seed the random number generator directly, some SQL is added to the test
  164. # case to 'use up' a different quantity random numbers before the test SQL
  165. # is executed.
  166. #
  167. # Make sure the file is much bigger than the pager-cache (10 pages). This
  168. # ensures that cache-spills happen regularly.
  169. do_test crash-3.0 {
  170. execsql {
  171. INSERT INTO abc SELECT * FROM abc;
  172. INSERT INTO abc SELECT * FROM abc;
  173. INSERT INTO abc SELECT * FROM abc;
  174. INSERT INTO abc SELECT * FROM abc;
  175. INSERT INTO abc SELECT * FROM abc;
  176. }
  177. expr ([file size test.db] / 1024) > 450
  178. } {1}
  179. for {set i 1} {$i < $repeats} {incr i} {
  180. set sig [signature]
  181. do_test crash-3.$i.1 {
  182. set seed [expr {int(abs(rand()*10000))}]
  183. crashsql -delay [expr $i%5 + 1] -file test.db-journal -seed $seed "
  184. BEGIN;
  185. SELECT random() FROM abc LIMIT $i;
  186. INSERT INTO abc VALUES(randstr(10,10), 0, 0);
  187. DELETE FROM abc WHERE random()%10!=0;
  188. COMMIT;
  189. "
  190. } {1 {child process exited abnormally}}
  191. do_test crash-3.$i.2 {
  192. signature
  193. } $sig
  194. }
  195. #--------------------------------------------------------------------------
  196. # The following test cases - crash-4.* - test the correct recovery of the
  197. # database when a crash occurs during a multi-file transaction.
  198. #
  199. # crash-4.1.*: Test recovery when crash occurs during sync() of the
  200. # main database journal file.
  201. # crash-4.2.*: Test recovery when crash occurs during sync() of an
  202. # attached database journal file.
  203. # crash-4.3.*: Test recovery when crash occurs during sync() of the master
  204. # journal file.
  205. #
  206. ifcapable attach {
  207. do_test crash-4.0 {
  208. forcedelete test2.db
  209. forcedelete test2.db-journal
  210. execsql {
  211. ATTACH 'test2.db' AS aux;
  212. PRAGMA aux.default_cache_size = 10;
  213. CREATE TABLE aux.abc2 AS SELECT 2*a as a, 2*b as b, 2*c as c FROM abc;
  214. }
  215. expr ([file size test2.db] / 1024) > 450
  216. } {1}
  217. set fin 0
  218. for {set i 1} {$i<$repeats} {incr i} {
  219. set seed [expr {int(abs(rand()*10000))}]
  220. set sig [signature]
  221. set sig2 [signature2]
  222. do_test crash-4.1.$i.1 {
  223. set c [crashsql -delay $i -file test.db-journal -seed $::seed "
  224. ATTACH 'test2.db' AS aux;
  225. BEGIN;
  226. SELECT randstr($i,$i) FROM abc LIMIT $i;
  227. INSERT INTO abc VALUES(randstr(10,10), 0, 0);
  228. DELETE FROM abc WHERE random()%10!=0;
  229. INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
  230. DELETE FROM abc2 WHERE random()%10!=0;
  231. COMMIT;
  232. "]
  233. if { $c == {0 {}} } {
  234. set ::fin 1
  235. set c {1 {child process exited abnormally}}
  236. }
  237. set c
  238. } {1 {child process exited abnormally}}
  239. if {$::fin} break
  240. do_test crash-4.1.$i.2 {
  241. signature
  242. } $sig
  243. do_test crash-4.1.$i.3 {
  244. signature2
  245. } $sig2
  246. }
  247. set i 0
  248. set fin 0
  249. while {[incr i]} {
  250. set seed [expr {int(abs(rand()*10000))}]
  251. set sig [signature]
  252. set sig2 [signature2]
  253. set ::fin 0
  254. do_test crash-4.2.$i.1 {
  255. set c [crashsql -delay $i -file test2.db-journal -seed $::seed "
  256. ATTACH 'test2.db' AS aux;
  257. BEGIN;
  258. SELECT randstr($i,$i) FROM abc LIMIT $i;
  259. INSERT INTO abc VALUES(randstr(10,10), 0, 0);
  260. DELETE FROM abc WHERE random()%10!=0;
  261. INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
  262. DELETE FROM abc2 WHERE random()%10!=0;
  263. COMMIT;
  264. "]
  265. if { $c == {0 {}} } {
  266. set ::fin 1
  267. set c {1 {child process exited abnormally}}
  268. }
  269. set c
  270. } {1 {child process exited abnormally}}
  271. if { $::fin } break
  272. do_test crash-4.2.$i.2 {
  273. signature
  274. } $sig
  275. do_test crash-4.2.$i.3 {
  276. signature2
  277. } $sig2
  278. }
  279. for {set i 1} {$i < 5} {incr i} {
  280. set sig [signature]
  281. set sig2 [signature2]
  282. do_test crash-4.3.$i.1 {
  283. crashsql -delay 1 -file test.db-mj* "
  284. ATTACH 'test2.db' AS aux;
  285. BEGIN;
  286. SELECT random() FROM abc LIMIT $i;
  287. INSERT INTO abc VALUES(randstr(10,10), 0, 0);
  288. DELETE FROM abc WHERE random()%10!=0;
  289. INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
  290. DELETE FROM abc2 WHERE random()%10!=0;
  291. COMMIT;
  292. "
  293. } {1 {child process exited abnormally}}
  294. do_test crash-4.3.$i.2 {
  295. signature
  296. } $sig
  297. do_test crash-4.3.$i.3 {
  298. signature2
  299. } $sig2
  300. }
  301. }
  302. #--------------------------------------------------------------------------
  303. # The following test cases - crash-5.* - exposes a bug that existed in the
  304. # sqlite3pager_movepage() API used by auto-vacuum databases.
  305. # database when a crash occurs during a multi-file transaction. See comments
  306. # in test crash-5.3 for details.
  307. #
  308. db close
  309. forcedelete test.db
  310. sqlite3 db test.db
  311. do_test crash-5.1 {
  312. execsql {
  313. CREATE TABLE abc(a, b, c); -- Root page 3
  314. INSERT INTO abc VALUES(randstr(1500,1500), 0, 0); -- Overflow page 4
  315. INSERT INTO abc SELECT * FROM abc;
  316. INSERT INTO abc SELECT * FROM abc;
  317. INSERT INTO abc SELECT * FROM abc;
  318. }
  319. } {}
  320. do_test crash-5.2 {
  321. expr [file size test.db] / 1024
  322. } [expr [string match [execsql {pragma auto_vacuum}] 1] ? 11 : 10]
  323. set sig [signature]
  324. do_test crash-5.3 {
  325. # The SQL below is used to expose a bug that existed in
  326. # sqlite3pager_movepage() during development of the auto-vacuum feature. It
  327. # functions as follows:
  328. #
  329. # 1: Begin a transaction.
  330. # 2: Put page 4 on the free-list (was the overflow page for the row deleted).
  331. # 3: Write data to page 4 (it becomes the overflow page for the row inserted).
  332. # The old page 4 data has been written to the journal file, but the
  333. # journal file has not been sync()hronized.
  334. # 4: Create a table, which calls sqlite3pager_movepage() to move page 4
  335. # to the end of the database (page 12) to make room for the new root-page.
  336. # 5: Put pressure on the pager-cache. This results in page 4 being written
  337. # to the database file to make space in the cache to load a new page. The
  338. # bug was that page 4 was written to the database file before the journal
  339. # is sync()hronized.
  340. # 6: Commit. A crash occurs during the sync of the journal file.
  341. #
  342. # End result: Before the bug was fixed, data has been written to page 4 of the
  343. # database file and the journal file does not contain trustworthy rollback
  344. # data for this page.
  345. #
  346. crashsql -delay 1 -file test.db-journal {
  347. BEGIN; -- 1
  348. DELETE FROM abc WHERE oid = 1; -- 2
  349. INSERT INTO abc VALUES(randstr(1500,1500), 0, 0); -- 3
  350. CREATE TABLE abc2(a, b, c); -- 4
  351. SELECT * FROM abc; -- 5
  352. COMMIT; -- 6
  353. }
  354. } {1 {child process exited abnormally}}
  355. integrity_check crash-5.4
  356. do_test crash-5.5 {
  357. signature
  358. } $sig
  359. #--------------------------------------------------------------------------
  360. # The following test cases - crash-6.* - test that a DROP TABLE operation
  361. # is correctly rolled back in the event of a crash while the database file
  362. # is being written. This is mainly to test that all pages are written to the
  363. # journal file before truncation in an auto-vacuum database.
  364. #
  365. do_test crash-6.1 {
  366. crashsql -delay 1 -file test.db {
  367. DROP TABLE abc;
  368. }
  369. } {1 {child process exited abnormally}}
  370. do_test crash-6.2 {
  371. signature
  372. } $sig
  373. #--------------------------------------------------------------------------
  374. # These test cases test the case where the master journal file name is
  375. # corrupted slightly so that the corruption has to be detected by the
  376. # checksum.
  377. do_test crash-7.1 {
  378. crashsql -delay 1 -file test.db {
  379. ATTACH 'test2.db' AS aux;
  380. BEGIN;
  381. INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);
  382. INSERT INTO abc2 VALUES(randstr(1500,1500), 0, 0);
  383. COMMIT;
  384. }
  385. # Change the checksum value for the master journal name.
  386. set f [open test.db-journal a]
  387. fconfigure $f -encoding binary
  388. seek $f [expr [file size test.db-journal] - 12]
  389. puts -nonewline $f "\00\00\00\00"
  390. close $f
  391. } {}
  392. do_test crash-7.2 {
  393. signature
  394. } $sig
  395. finish_test