rbuvacuum.test 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. # 2016 April 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. #
  12. # This file contains tests for the RBU module. More specifically, it
  13. # contains tests to ensure that the sqlite3rbu_vacuum() API works as
  14. # expected.
  15. #
  16. source [file join [file dirname [info script]] rbu_common.tcl]
  17. if_no_rbu_support { finish_test ; return }
  18. set ::testprefix rbuvacuum
  19. foreach step {0 1} {
  20. set ::testprefix rbuvacuum-step=$step
  21. reset_db
  22. # Simplest possible vacuum.
  23. do_execsql_test 1.0 {
  24. PRAGMA page_size = 1024;
  25. CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
  26. INSERT INTO t1 VALUES(1, 2, 3);
  27. INSERT INTO t1 VALUES(4, 5, 6);
  28. INSERT INTO t1 VALUES(7, 8, 9);
  29. PRAGMA integrity_check;
  30. } {ok}
  31. do_rbu_vacuum_test 1.1 $step
  32. # A vacuum that actually reclaims space.
  33. do_execsql_test 1.2.1 {
  34. INSERT INTO t1 VALUES(8, randomblob(900), randomblob(900));
  35. INSERT INTO t1 VALUES(9, randomblob(900), randomblob(900));
  36. INSERT INTO t1 VALUES(10, randomblob(900), randomblob(900));
  37. INSERT INTO t1 VALUES(11, randomblob(900), randomblob(900));
  38. INSERT INTO t1 VALUES(12, randomblob(900), randomblob(900));
  39. PRAGMA page_count;
  40. } {12}
  41. do_execsql_test 1.2.2 {
  42. DELETE FROM t1 WHERE rowid BETWEEN 8 AND 11;
  43. PRAGMA page_count;
  44. } {12}
  45. do_rbu_vacuum_test 1.2.3 $step
  46. do_execsql_test 1.2.4 {
  47. PRAGMA page_count;
  48. } {3}
  49. # Add an index to the table.
  50. do_execsql_test 1.3.1 {
  51. CREATE INDEX t1b ON t1(b);
  52. INSERT INTO t1 VALUES(13, randomblob(900), randomblob(900));
  53. INSERT INTO t1 VALUES(14, randomblob(900), randomblob(900));
  54. INSERT INTO t1 VALUES(15, randomblob(900), randomblob(900));
  55. INSERT INTO t1 VALUES(16, randomblob(900), randomblob(900));
  56. PRAGMA page_count;
  57. } {18}
  58. do_execsql_test 1.3.2 {
  59. DELETE FROM t1 WHERE rowid BETWEEN 12 AND 15;
  60. PRAGMA page_count;
  61. } {18}
  62. do_rbu_vacuum_test 1.3.3 $step
  63. do_execsql_test 1.3.4 {
  64. PRAGMA page_count;
  65. } {5}
  66. # WITHOUT ROWID table.
  67. do_execsql_test 1.4.1 {
  68. CREATE TABLE t2(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID;
  69. INSERT INTO t2 VALUES(randomblob(900), 1, randomblob(900));
  70. INSERT INTO t2 VALUES(randomblob(900), 2, randomblob(900));
  71. INSERT INTO t2 VALUES(randomblob(900), 3, randomblob(900));
  72. INSERT INTO t2 VALUES(randomblob(900), 4, randomblob(900));
  73. INSERT INTO t2 VALUES(randomblob(900), 6, randomblob(900));
  74. INSERT INTO t2 VALUES(randomblob(900), 7, randomblob(900));
  75. INSERT INTO t2 VALUES(randomblob(900), 8, randomblob(900));
  76. DELETE FROM t2 WHERE b BETWEEN 2 AND 7;
  77. PRAGMA page_count;
  78. } {20}
  79. do_rbu_vacuum_test 1.4.2 $step
  80. do_execsql_test 1.4.3 {
  81. PRAGMA page_count;
  82. } {10}
  83. # WITHOUT ROWID table with an index.
  84. do_execsql_test 1.4.1 {
  85. CREATE INDEX t2c ON t2(c);
  86. INSERT INTO t2 VALUES(randomblob(900), 9, randomblob(900));
  87. INSERT INTO t2 VALUES(randomblob(900), 10, randomblob(900));
  88. INSERT INTO t2 VALUES(randomblob(900), 11, randomblob(900));
  89. INSERT INTO t2 VALUES(randomblob(900), 12, randomblob(900));
  90. INSERT INTO t2 VALUES(randomblob(900), 13, randomblob(900));
  91. DELETE FROM t2 WHERE b BETWEEN 8 AND 12;
  92. PRAGMA page_count;
  93. } {35}
  94. do_rbu_vacuum_test 1.4.2 $step
  95. do_execsql_test 1.4.3 {
  96. PRAGMA page_count;
  97. } {15}
  98. do_execsql_test 1.4.4 {
  99. VACUUM;
  100. PRAGMA page_count;
  101. } {15}
  102. do_execsql_test 1.5.1 {
  103. CREATE TABLE t3(a, b, c);
  104. INSERT INTO t3 VALUES('a', 'b', 'c');
  105. INSERT INTO t3 VALUES('d', 'e', 'f');
  106. INSERT INTO t3 VALUES('g', 'h', 'i');
  107. }
  108. do_rbu_vacuum_test 1.5.2 $step
  109. do_execsql_test 1.5.3 {
  110. SELECT * FROM t3
  111. } {a b c d e f g h i}
  112. do_execsql_test 1.5.4 {
  113. CREATE INDEX t3a ON t3(a);
  114. CREATE INDEX t3b ON t3(b);
  115. CREATE INDEX t3c ON t3(c);
  116. INSERT INTO t3 VALUES('j', 'k', 'l');
  117. DELETE FROM t3 WHERE a = 'g';
  118. }
  119. do_rbu_vacuum_test 1.5.5 $step
  120. do_execsql_test 1.5.6 {
  121. SELECT rowid, * FROM t3 ORDER BY b
  122. } {1 a b c 2 d e f 4 j k l}
  123. do_execsql_test 1.6.1 {
  124. CREATE TABLE t4(a PRIMARY KEY, b, c);
  125. INSERT INTO t4 VALUES('a', 'b', 'c');
  126. INSERT INTO t4 VALUES('d', 'e', 'f');
  127. INSERT INTO t4 VALUES('g', 'h', 'i');
  128. }
  129. do_rbu_vacuum_test 1.6.2 $step
  130. do_execsql_test 1.6.3 {
  131. SELECT * FROM t4
  132. } {a b c d e f g h i}
  133. do_execsql_test 1.6.4 {
  134. CREATE INDEX t4a ON t4(a);
  135. CREATE INDEX t4b ON t4(b);
  136. CREATE INDEX t4c ON t4(c);
  137. INSERT INTO t4 VALUES('j', 'k', 'l');
  138. DELETE FROM t4 WHERE a='g';
  139. }
  140. do_rbu_vacuum_test 1.6.5 $step
  141. do_execsql_test 1.6.6 {
  142. SELECT * FROM t4 ORDER BY b
  143. } {a b c d e f j k l}
  144. reset_db
  145. do_execsql_test 1.7.0 {
  146. CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
  147. INSERT INTO t1 VALUES(NULL, 'one');
  148. INSERT INTO t1 VALUES(NULL, 'two');
  149. DELETE FROM t1 WHERE a=2;
  150. INSERT INTO t1 VALUES(NULL, 'three');
  151. INSERT INTO t1 VALUES(NULL, 'four');
  152. DELETE FROM t1 WHERE a=4;
  153. INSERT INTO t1 VALUES(NULL, 'five');
  154. INSERT INTO t1 VALUES(NULL, 'six');
  155. DELETE FROM t1 WHERE a=6;
  156. SELECT * FROM t1;
  157. } {1 one 3 three 5 five}
  158. do_rbu_vacuum_test 1.7.1 $step
  159. do_execsql_test 1.7.2 {
  160. INSERT INTO t1 VALUES(NULL, 'seven');
  161. SELECT * FROM t1;
  162. } {1 one 3 three 5 five 7 seven}
  163. reset_db
  164. do_execsql_test 1.8.0 {
  165. CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
  166. CREATE INDEX i1 ON t1(b);
  167. INSERT INTO t1 VALUES(NULL, 'one');
  168. INSERT INTO t1 VALUES(NULL, 'two');
  169. INSERT INTO t1 VALUES(NULL, 'three');
  170. INSERT INTO t1 VALUES(NULL, 'four');
  171. INSERT INTO t1 VALUES(NULL, 'five');
  172. INSERT INTO t1 VALUES(NULL, 'six');
  173. ANALYZE;
  174. SELECT * FROM sqlite_stat1;
  175. } {t1 i1 {6 1}}
  176. do_rbu_vacuum_test 1.8.1 $step
  177. do_execsql_test 1.7.2 {
  178. SELECT * FROM sqlite_stat1;
  179. } {t1 i1 {6 1}}
  180. reset_db
  181. do_execsql_test 1.9.0 {
  182. PRAGMA page_size = 8192;
  183. PRAGMA auto_vacuum = 2;
  184. PRAGMA user_version = 412;
  185. PRAGMA application_id = 413;
  186. CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
  187. CREATE INDEX i1 ON t1(b);
  188. INSERT INTO t1 VALUES(NULL, 'one');
  189. INSERT INTO t1 VALUES(NULL, 'two');
  190. INSERT INTO t1 VALUES(NULL, 'three');
  191. INSERT INTO t1 VALUES(NULL, 'four');
  192. INSERT INTO t1 VALUES(NULL, 'five');
  193. INSERT INTO t1 VALUES(NULL, 'six');
  194. PRAGMA main.page_size;
  195. PRAGMA main.auto_vacuum;
  196. PRAGMA main.user_version;
  197. PRAGMA main.application_id;
  198. } {8192 2 412 413}
  199. do_rbu_vacuum_test 1.9.1 $step
  200. do_execsql_test 1.9.2 {
  201. PRAGMA main.page_size;
  202. PRAGMA main.auto_vacuum;
  203. PRAGMA main.user_version;
  204. PRAGMA main.application_id;
  205. } {8192 2 412 413}
  206. # Vacuum a database with a large sqlite_master table.
  207. #
  208. reset_db
  209. do_test 1.10.1 {
  210. for {set i 1} {$i < 50} {incr i} {
  211. execsql "PRAGMA page_size = 1024"
  212. execsql "CREATE TABLE t$i (a, b, c, PRIMARY KEY(a, b));"
  213. execsql "
  214. INSERT INTO t$i VALUES(1, 2, 3);
  215. INSERT INTO t$i VALUES(4, 5, 6);
  216. "
  217. }
  218. } {}
  219. do_rbu_vacuum_test 1.10.2 $step
  220. # Database with empty tables.
  221. #
  222. reset_db
  223. do_execsql_test 1.11.1 {
  224. CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
  225. CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
  226. CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
  227. CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
  228. INSERT INTO t4 VALUES(1, 2);
  229. }
  230. do_rbu_vacuum_test 1.11.2 $step
  231. do_execsql_test 1.11.3 {
  232. SELECT * FROM t1;
  233. SELECT * FROM t2;
  234. SELECT * FROM t3;
  235. SELECT * FROM t4;
  236. } {1 2}
  237. reset_db
  238. do_execsql_test 1.12.1 {
  239. CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
  240. CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
  241. CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
  242. CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
  243. INSERT INTO t1 VALUES(1, 2);
  244. }
  245. do_rbu_vacuum_test 1.12.2 $step
  246. do_execsql_test 1.12.3 {
  247. SELECT * FROM t1;
  248. SELECT * FROM t2;
  249. SELECT * FROM t3;
  250. SELECT * FROM t4;
  251. } {1 2}
  252. }
  253. set ::testprefix rbuvacuum
  254. #-------------------------------------------------------------------------
  255. # Test some error cases:
  256. #
  257. # 2.1.* the db being vacuumed being in wal mode already.
  258. # 2.2.* database modified mid vacuum.
  259. #
  260. reset_db
  261. do_execsql_test 2.1.0 {
  262. CREATE TABLE t1(a, b);
  263. INSERT INTO t1 VALUES(1, 2);
  264. INSERT INTO t1 VALUES(3, 4);
  265. INSERT INTO t1 VALUES(5, 6);
  266. INSERT INTO t1 VALUES(7, 8);
  267. PRAGMA journal_mode = wal;
  268. INSERT INTO t1 VALUES(9, 10);
  269. } wal
  270. do_test 2.1.1 {
  271. sqlite3rbu_vacuum rbu test.db state.db
  272. rbu step
  273. } {SQLITE_ERROR}
  274. do_test 2.1.2 {
  275. list [catch { rbu close } msg] $msg
  276. } {1 {SQLITE_ERROR - cannot vacuum wal mode database}}
  277. do_test 2.1.3 {
  278. sqlite3rbu_vacuum rbu test.db state.db
  279. rbu step
  280. } {SQLITE_ERROR}
  281. do_test 2.1.4 {
  282. list [catch { rbu close_no_error } msg] $msg
  283. } {1 SQLITE_ERROR}
  284. reset_db
  285. do_execsql_test 2.2.0 {
  286. CREATE TABLE tx(a PRIMARY KEY, b BLOB);
  287. INSERT INTO tx VALUES(1, randomblob(900));
  288. INSERT INTO tx SELECT a+1, randomblob(900) FROM tx;
  289. INSERT INTO tx SELECT a+2, randomblob(900) FROM tx;
  290. INSERT INTO tx SELECT a+4, randomblob(900) FROM tx;
  291. INSERT INTO tx SELECT a+8, randomblob(900) FROM tx;
  292. }
  293. db_save_and_close
  294. for {set i 1} 1 {incr i} {
  295. db_restore_and_reopen
  296. sqlite3rbu_vacuum rbu test.db state.db
  297. for {set step 0} {$step<$i} {incr step} { rbu step }
  298. rbu close
  299. if {[file exists test.db-wal]} break
  300. execsql { INSERT INTO tx VALUES(20, 20) }
  301. do_test 2.2.$i.1 {
  302. sqlite3rbu_vacuum rbu test.db state.db
  303. rbu step
  304. } {SQLITE_BUSY}
  305. do_test 2.2.$i.2 {
  306. list [catch { rbu close } msg] $msg
  307. } {1 {SQLITE_BUSY - database modified during rbu vacuum}}
  308. }
  309. #-------------------------------------------------------------------------
  310. # Test that a database that uses custom collation sequences can be RBU
  311. # vacuumed.
  312. #
  313. reset_db
  314. forcedelete state.db
  315. proc noop {args} {}
  316. proc length_cmp {x y} {
  317. set n1 [string length $x]
  318. set n2 [string length $y]
  319. return [expr $n1 - $n2]
  320. }
  321. sqlite3_create_collation_v2 db length length_cmp noop
  322. do_execsql_test 3.0 {
  323. CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
  324. INSERT INTO t1 VALUES(1, 'i');
  325. INSERT INTO t1 VALUES(2, 'iiii');
  326. INSERT INTO t1 VALUES(3, 'ii');
  327. INSERT INTO t1 VALUES(4, 'iii');
  328. SELECT a FROM t1 ORDER BY b COLLATE length;
  329. } {1 3 4 2}
  330. do_execsql_test 3.1 {
  331. CREATE INDEX i1 ON t1(b COLLATE length);
  332. }
  333. do_test 3.2 {
  334. sqlite3rbu_vacuum rbu test.db state.db
  335. while {[rbu step]=="SQLITE_OK"} {}
  336. list [catch { rbu close } msg] $msg
  337. } {1 {SQLITE_ERROR - no such collation sequence: length}}
  338. do_test 3.3 {
  339. sqlite3rbu_vacuum rbu test.db state.db
  340. set db1 [rbu db 0]
  341. sqlite3_create_collation_v2 $db1 length length_cmp noop
  342. while {[rbu step]=="SQLITE_OK"} {}
  343. list [catch { rbu close } msg] $msg
  344. } {1 {SQLITE_ERROR - no such collation sequence: length}}
  345. do_test 3.4 {
  346. sqlite3rbu_vacuum rbu test.db state.db
  347. set db1 [rbu db 1]
  348. sqlite3_create_collation_v2 $db1 length length_cmp noop
  349. while {[rbu step]=="SQLITE_OK"} {}
  350. list [catch { rbu close } msg] $msg
  351. } {1 {SQLITE_ERROR - no such collation sequence: length}}
  352. do_test 3.5 {
  353. sqlite3rbu_vacuum rbu test.db state.db
  354. set db1 [rbu db 0]
  355. set db2 [rbu db 1]
  356. sqlite3_create_collation_v2 $db1 length length_cmp noop
  357. sqlite3_create_collation_v2 $db2 length length_cmp noop
  358. while {[rbu step]=="SQLITE_OK"} {}
  359. list [catch { rbu close } msg] $msg
  360. } {0 SQLITE_DONE}
  361. catch { db close }
  362. finish_test