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