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