fts4merge.test 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. # 2012 March 06
  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 testing the incremental merge function.
  13. #
  14. set testdir [file dirname $argv0]
  15. source $testdir/tester.tcl
  16. source $testdir/fts3_common.tcl
  17. # If SQLITE_ENABLE_FTS3 is defined, omit this file.
  18. ifcapable !fts3 {
  19. finish_test
  20. return
  21. }
  22. proc fts3_integrity_check {tbl} {
  23. db eval "INSERT INTO $tbl ($tbl) VALUES('integrity-check')"
  24. return "ok"
  25. }
  26. foreach mod {fts3 fts4} {
  27. set ::testprefix fts4merge-$mod
  28. reset_db
  29. #-------------------------------------------------------------------------
  30. # Test cases 1.*
  31. #
  32. do_test 1.0 { fts3_build_db_1 -module $mod 1004 } {}
  33. do_test 1.1 { fts3_integrity_check t1 } {ok}
  34. do_execsql_test 1.1 {
  35. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level
  36. } {
  37. 0 {0 1 2 3 4 5 6 7 8 9 10 11}
  38. 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13}
  39. 2 {0 1 2}
  40. }
  41. for {set i 0} {$i<20} {incr i} {
  42. do_execsql_test 1.2.$i.1 { INSERT INTO t1(t1) VALUES('merge=1') }
  43. do_test 1.2.$i.2 { fts3_integrity_check t1 } ok
  44. do_execsql_test 1.2.$i.3 {
  45. SELECT docid FROM t1 WHERE t1 MATCH 'zero one two three'
  46. } {123 132 213 231 312 321}
  47. }
  48. do_execsql_test 1.3 {
  49. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level
  50. } {
  51. 0 {0 1 2 3}
  52. 1 {0 1 2 3 4 5 6}
  53. 2 {0 1 2 3}
  54. }
  55. for {set i 0} {$i<100} {incr i} {
  56. do_execsql_test 1.4.$i { INSERT INTO t1(t1) VALUES('merge=1,4') }
  57. do_test 1.4.$i.2 { fts3_integrity_check t1 } ok
  58. do_execsql_test 1.4.$i.3 {
  59. SELECT docid FROM t1 WHERE t1 MATCH 'zero one two three'
  60. } {123 132 213 231 312 321}
  61. }
  62. do_execsql_test 1.5 {
  63. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level
  64. } {
  65. 2 {0 1}
  66. 3 0
  67. }
  68. #-------------------------------------------------------------------------
  69. # Test cases 2.* test that errors in the xxx part of the 'merge=xxx' are
  70. # handled correctly.
  71. #
  72. do_execsql_test 2.0 "CREATE VIRTUAL TABLE t2 USING $mod"
  73. foreach {tn arg} {
  74. 1 {merge=abc}
  75. 2 {merge=%%%}
  76. 3 {merge=,}
  77. 4 {merge=5,}
  78. 5 {merge=6,%}
  79. 6 {merge=6,six}
  80. 7 {merge=6,1}
  81. 8 {merge=6,0}
  82. } {
  83. do_catchsql_test 2.$tn {
  84. INSERT INTO t2(t2) VALUES($arg);
  85. } {1 {SQL logic error or missing database}}
  86. }
  87. #-------------------------------------------------------------------------
  88. # Test cases 3.*
  89. #
  90. do_test 3.0 {
  91. reset_db
  92. execsql { PRAGMA page_size = 512 }
  93. fts3_build_db_2 -module $mod 30040
  94. } {}
  95. do_test 3.1 { fts3_integrity_check t2 } {ok}
  96. do_execsql_test 3.2 {
  97. SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level
  98. } {
  99. 0 {0 1 2 3 4 5 6}
  100. 1 {0 1 2 3 4}
  101. 2 {0 1 2 3 4}
  102. 3 {0 1 2 3 4 5 6}
  103. }
  104. do_execsql_test 3.3 {
  105. INSERT INTO t2(t2) VALUES('merge=1000000,2');
  106. SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level
  107. } {
  108. 0 0
  109. 2 0
  110. 3 0
  111. 4 0
  112. 6 0
  113. }
  114. #-------------------------------------------------------------------------
  115. # Test cases 4.*
  116. #
  117. reset_db
  118. do_execsql_test 4.1 "
  119. PRAGMA page_size = 512;
  120. CREATE VIRTUAL TABLE t4 USING $mod;
  121. PRAGMA main.page_size;
  122. " {512}
  123. do_test 4.2 {
  124. foreach x {a c b d e f g h i j k l m n o p} {
  125. execsql "INSERT INTO t4 VALUES('[string repeat $x 600]')"
  126. }
  127. execsql {SELECT level, group_concat(idx, ' ') FROM t4_segdir GROUP BY level}
  128. } {0 {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15}}
  129. foreach {tn expect} {
  130. 1 "0 {0 1 2 3 4 5 6 7 8 9 10 11 12 13} 1 0"
  131. 2 "0 {0 1 2 3 4 5 6 7 8 9 10 11 12} 1 0"
  132. 3 "0 {0 1 2 3 4 5 6 7 8 9 10 11} 1 0"
  133. 4 "0 {0 1 2 3 4 5 6 7 8 9 10} 1 0"
  134. 5 "0 {0 1 2 3 4 5 6 7 8 9} 1 0"
  135. 6 "0 {0 1 2 3 4 5 6 7 8} 1 0"
  136. 7 "0 {0 1 2 3 4 5 6 7} 1 0"
  137. 8 "0 {0 1 2 3 4 5 6} 1 0"
  138. 9 "0 {0 1 2 3 4 5} 1 0"
  139. } {
  140. do_execsql_test 4.3.$tn {
  141. INSERT INTO t4(t4) VALUES('merge=1,16');
  142. SELECT level, group_concat(idx, ' ') FROM t4_segdir GROUP BY level;
  143. } $expect
  144. }
  145. do_execsql_test 4.4.1 {
  146. SELECT quote(value) FROM t4_stat WHERE rowid=1
  147. } {X'0006'}
  148. do_execsql_test 4.4.2 {
  149. DELETE FROM t4_stat WHERE rowid=1;
  150. INSERT INTO t4(t4) VALUES('merge=1,12');
  151. SELECT level, group_concat(idx, ' ') FROM t4_segdir GROUP BY level;
  152. } "0 {0 1 2 3 4 5} 1 0"
  153. #-------------------------------------------------------------------------
  154. # Test cases 5.*
  155. #
  156. # Test that if a crisis-merge occurs that disrupts an ongoing incremental
  157. # merge, the next call to "merge=A,B" identifies this and starts a new
  158. # incremental merge. There are two scenarios:
  159. #
  160. # * There are less segments on the input level that the disrupted
  161. # incremental merge operated on, or
  162. #
  163. # * Sufficient segments exist on the input level but the segments
  164. # contain keys smaller than the largest key in the potential output
  165. # segment.
  166. #
  167. do_test 5.1 {
  168. reset_db
  169. fts3_build_db_1 -module $mod 1000
  170. } {}
  171. do_execsql_test 5.2 {
  172. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level;
  173. } {
  174. 0 {0 1 2 3 4 5 6 7}
  175. 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13}
  176. 2 {0 1 2}
  177. }
  178. do_execsql_test 5.3 {
  179. INSERT INTO t1(t1) VALUES('merge=1,5');
  180. INSERT INTO t1(t1) VALUES('merge=1,5');
  181. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level;
  182. } {
  183. 0 {0 1 2}
  184. 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14}
  185. 2 {0 1 2 3}
  186. }
  187. do_execsql_test 5.4 {SELECT quote(value) from t1_stat WHERE rowid=1} {X'0105'}
  188. do_test 5.5 {
  189. foreach docid [execsql {SELECT docid FROM t1}] {
  190. execsql {INSERT INTO t1 SELECT * FROM t1 WHERE docid=$docid}
  191. }
  192. } {}
  193. do_execsql_test 5.6 {SELECT quote(value) from t1_stat WHERE rowid=1} {X'0105'}
  194. do_execsql_test 5.7 {
  195. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level;
  196. SELECT quote(value) from t1_stat WHERE rowid=1;
  197. } {
  198. 0 {0 1 2 3 4 5 6 7 8 9 10}
  199. 1 {0 1 2 3 4 5 6 7 8 9 10 11 12}
  200. 2 {0 1 2 3 4 5 6 7}
  201. X'0105'
  202. }
  203. do_execsql_test 5.8 {
  204. INSERT INTO t1(t1) VALUES('merge=1,6');
  205. INSERT INTO t1(t1) VALUES('merge=1,6');
  206. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level;
  207. SELECT quote(value) from t1_stat WHERE rowid=1;
  208. } {
  209. 0 {0 1 2 3 4}
  210. 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13}
  211. 2 {0 1 2 3 4 5 6 7 8} X'0106'
  212. }
  213. do_test 5.8.1 { fts3_integrity_check t1 } ok
  214. do_test 5.9 {
  215. set L [expr 16*16*7 + 16*3 + 12]
  216. foreach docid [execsql {
  217. SELECT docid FROM t1 UNION ALL SELECT docid FROM t1 LIMIT $L
  218. }] {
  219. execsql {INSERT INTO t1 SELECT * FROM t1 WHERE docid=$docid}
  220. }
  221. } {}
  222. do_execsql_test 5.10 {
  223. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level;
  224. SELECT quote(value) from t1_stat WHERE rowid=1;
  225. } {
  226. 0 0 1 {0 1} 2 0 3 0 X'0106'
  227. }
  228. do_execsql_test 5.11 {
  229. INSERT INTO t1(t1) VALUES('merge=1,6');
  230. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level;
  231. SELECT quote(value) from t1_stat WHERE rowid=1;
  232. } {
  233. 0 0 1 {0 1} 2 0 3 0 X''
  234. }
  235. #-------------------------------------------------------------------------
  236. # Test cases 6.*
  237. #
  238. # At one point the following test caused an assert() to fail (because the
  239. # second 'merge=1,2' operation below actually "merges" a single input
  240. # segment, which was unexpected).
  241. #
  242. do_test 6.1 {
  243. reset_db
  244. set a [string repeat a 900]
  245. set b [string repeat b 900]
  246. set c [string repeat c 900]
  247. set d [string repeat d 900]
  248. execsql "CREATE VIRTUAL TABLE t1 USING $mod"
  249. execsql {
  250. BEGIN;
  251. INSERT INTO t1 VALUES($a);
  252. INSERT INTO t1 VALUES($b);
  253. COMMIT;
  254. BEGIN;
  255. INSERT INTO t1 VALUES($c);
  256. INSERT INTO t1 VALUES($d);
  257. COMMIT;
  258. }
  259. execsql {
  260. INSERT INTO t1(t1) VALUES('merge=1,2');
  261. INSERT INTO t1(t1) VALUES('merge=1,2');
  262. }
  263. } {}
  264. #-------------------------------------------------------------------------
  265. # Test cases 7.*
  266. #
  267. # Test that the value returned by sqlite3_total_changes() increases by
  268. # 1 following a no-op "merge=A,B", or by more than 1 if actual work is
  269. # performed.
  270. #
  271. do_test 7.0 {
  272. reset_db
  273. fts3_build_db_1 -module $mod 1000
  274. } {}
  275. do_execsql_test 7.1 {
  276. SELECT level, group_concat(idx, ' ') FROM t1_segdir GROUP BY level
  277. } {
  278. 0 {0 1 2 3 4 5 6 7}
  279. 1 {0 1 2 3 4 5 6 7 8 9 10 11 12 13}
  280. 2 {0 1 2}
  281. }
  282. do_test 7.2 {
  283. set x [db total_changes]
  284. execsql { INSERT INTO t1(t1) VALUES('merge=2,10') }
  285. expr { ([db total_changes] - $x)>1 }
  286. } {1}
  287. do_test 7.3 {
  288. set x [db total_changes]
  289. execsql { INSERT INTO t1(t1) VALUES('merge=200,10') }
  290. expr { ([db total_changes] - $x)>1 }
  291. } {1}
  292. do_test 7.4 {
  293. set x [db total_changes]
  294. execsql { INSERT INTO t1(t1) VALUES('merge=200,10') }
  295. expr { ([db total_changes] - $x)>1 }
  296. } {0}
  297. do_test 7.5 {
  298. set x [db total_changes]
  299. execsql { INSERT INTO t1(t1) VALUES('merge=200,10') }
  300. expr { ([db total_changes] - $x)>1 }
  301. } {0}
  302. }
  303. finish_test