xref: /sqlite-3.40.0/test/fts4opt.test (revision 3b328522)
1# 2016 March 8
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
13set testdir [file dirname $argv0]
14source $testdir/tester.tcl
15source $testdir/fts3_common.tcl
16set ::testprefix fts4opt
17
18# If SQLITE_ENABLE_FTS3 is defined, omit this file.
19ifcapable !fts3 {
20  finish_test
21  return
22}
23
24# Create the fts_kjv_genesis procedure which fills and FTS3/4 table
25# with the complete text of the Book of Genesis.
26#
27source $testdir/genesis.tcl
28
29do_execsql_test 1.0 { CREATE TABLE t1(docid, words) }
30fts_kjv_genesis
31
32#-------------------------------------------------------------------------
33# Argument $db is an open database handle. $tbl is the name of an FTS3/4
34# table with the database. This command rearranges the contents of the
35# %_segdir table so that all segments within each index are on the same
36# level. This means that the 'merge' command can then be used for an
37# incremental optimize routine.
38#
39proc prepare_for_optimize {db tbl} {
40  $db eval [string map [list % $tbl] {
41    BEGIN;
42      CREATE TEMP TABLE tmp_segdir(
43        level, idx, start_block, leaves_end_block, end_block, root
44      );
45
46      INSERT INTO temp.tmp_segdir
47        SELECT
48        1024*(o.level / 1024) + 32,                                -- level
49        sum(o.level<i.level OR (o.level=i.level AND o.idx>i.idx)), -- idx
50        o.start_block, o.leaves_end_block, o.end_block, o.root     -- other
51        FROM %_segdir o, %_segdir i
52        WHERE (o.level / 1024) = (i.level / 1024)
53        GROUP BY o.level, o.idx;
54
55      DELETE FROM %_segdir;
56      INSERT INTO %_segdir SELECT * FROM temp.tmp_segdir;
57      DROP TABLE temp.tmp_segdir;
58
59    COMMIT;
60  }]
61}
62
63do_test 1.1 {
64  execsql { CREATE VIRTUAL TABLE t2 USING fts4(words, prefix="1,2,3") }
65  foreach {docid words} [db eval { SELECT * FROM t1 }] {
66    execsql { INSERT INTO t2(docid, words) VALUES($docid, $words) }
67  }
68} {}
69
70do_execsql_test 1.2 {
71  SELECT level, count(*) FROM t2_segdir GROUP BY level
72} {
73  0    13    1 15    2 5
74  1024 13 1025 15 1026 5
75  2048 13 2049 15 2050 5
76  3072 13 3073 15 3074 5
77}
78
79do_execsql_test 1.3 { INSERT INTO t2(t2) VALUES('integrity-check') }
80prepare_for_optimize db t2
81do_execsql_test 1.4 { INSERT INTO t2(t2) VALUES('integrity-check') }
82
83do_execsql_test 1.5 {
84  SELECT level, count(*) FROM t2_segdir GROUP BY level
85} {
86  32   33
87  1056 33
88  2080 33
89  3104 33
90}
91
92do_test 1.6 {
93  while 1 {
94    set tc1 [db total_changes]
95    execsql { INSERT INTO t2(t2) VALUES('merge=5,2') }
96    set tc2 [db total_changes]
97    if {($tc2 - $tc1) < 2} break
98  }
99  execsql { SELECT level, count(*) FROM t2_segdir GROUP BY level }
100} {33 1 1057 1 2081 1 3105 1}
101do_execsql_test 1.7 { INSERT INTO t2(t2) VALUES('integrity-check') }
102
103do_execsql_test 1.8 {
104  INSERT INTO t2(words) SELECT words FROM t1;
105  SELECT level, count(*) FROM t2_segdir GROUP BY level;
106} {0 2 1024 2 2048 2 3072 2}
107
108#-------------------------------------------------------------------------
109
110do_execsql_test 2.0 {
111  DELETE FROM t2;
112}
113do_test 2.1 {
114  foreach {docid words} [db eval { SELECT * FROM t1 }] {
115    execsql { INSERT INTO t2(docid, words) VALUES($docid, $words) }
116  }
117
118  set i 0
119  foreach {docid words} [db eval { SELECT * FROM t1 }] {
120    if {[incr i] % 2} { execsql { DELETE FROM t2 WHERE docid = $docid } }
121  }
122
123  set i 0
124  foreach {docid words} [db eval { SELECT * FROM t1 }] {
125    if {[incr i] % 3} {
126      execsql { INSERT OR REPLACE INTO t2(docid, words) VALUES($docid, $words) }
127    }
128  }
129} {}
130
131do_execsql_test 2.2 {
132  SELECT level, count(*) FROM t2_segdir GROUP BY level
133} {
134  0    10    1 15    2 12
135  1024 10 1025 15 1026 12
136  2048 10 2049 15 2050 12
137  3072 10 3073 15 3074 12
138}
139
140do_execsql_test 2.3 { INSERT INTO t2(t2) VALUES('integrity-check') }
141prepare_for_optimize db t2
142do_execsql_test 2.4 { INSERT INTO t2(t2) VALUES('integrity-check') }
143
144do_execsql_test 2.5 {
145  SELECT level, count(*) FROM t2_segdir GROUP BY level
146} {
147    32 37
148  1056 37
149  2080 37
150  3104 37
151}
152
153do_test 2.6 {
154  while 1 {
155    set tc1 [db total_changes]
156    execsql { INSERT INTO t2(t2) VALUES('merge=5,2') }
157    set tc2 [db total_changes]
158    if {($tc2 - $tc1) < 2} break
159  }
160  execsql { SELECT level, count(*) FROM t2_segdir GROUP BY level }
161} {33 1 1057 1 2081 1 3105 1}
162do_execsql_test 2.7 { INSERT INTO t2(t2) VALUES('integrity-check') }
163
164do_execsql_test 2.8 {
165  INSERT INTO t2(words) SELECT words FROM t1;
166  SELECT level, count(*) FROM t2_segdir GROUP BY level;
167} {0 2 1024 2 2048 2 3072 2}
168
169#-------------------------------------------------------------------------
170# Check that 'optimize' works when there is data in the in-memory hash
171# table, but no segments at all on disk.
172#
173do_execsql_test 3.1 {
174  CREATE VIRTUAL TABLE fts USING fts4 (t);
175  INSERT INTO fts (fts) VALUES ('optimize');
176}
177do_execsql_test 3.2 {
178  INSERT INTO fts(fts) VALUES('integrity-check');
179  SELECT count(*) FROM fts_segdir;
180} {0}
181do_execsql_test 3.3 {
182  BEGIN;
183  INSERT INTO fts (rowid, t) VALUES (2, 'test');
184  INSERT INTO fts (fts) VALUES ('optimize');
185  COMMIT;
186  SELECT level, idx FROM fts_segdir;
187} {0 0}
188do_execsql_test 3.4 {
189  INSERT INTO fts(fts) VALUES('integrity-check');
190  SELECT rowid FROM fts WHERE fts MATCH 'test';
191} {2}
192do_execsql_test 3.5 {
193  INSERT INTO fts (fts) VALUES ('optimize');
194  INSERT INTO fts(fts) VALUES('integrity-check');
195}
196do_test 3.6 {
197  set c1 [db total_changes]
198  execsql { INSERT INTO fts (fts) VALUES ('optimize') }
199  expr {[db total_changes] - $c1}
200} {1}
201do_test 3.7 {
202  execsql { INSERT INTO fts (rowid, t) VALUES (3, 'xyz') }
203  set c1 [db total_changes]
204  execsql { INSERT INTO fts (fts) VALUES ('optimize') }
205  expr {([db total_changes] - $c1) > 1}
206} {1}
207do_test 3.8 {
208  set c1 [db total_changes]
209  execsql { INSERT INTO fts (fts) VALUES ('optimize') }
210  expr {[db total_changes] - $c1}
211} {1}
212
213finish_test
214