xref: /sqlite-3.40.0/test/fts4opt.test (revision 6ab91a7a)
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  sqlite3_db_config $db DEFENSIVE 0
41  $db eval [string map [list % $tbl] {
42    BEGIN;
43      CREATE TEMP TABLE tmp_segdir(
44        level, idx, start_block, leaves_end_block, end_block, root
45      );
46
47      INSERT INTO temp.tmp_segdir
48        SELECT
49        1024*(o.level / 1024) + 32,                                -- level
50        sum(o.level<i.level OR (o.level=i.level AND o.idx>i.idx)), -- idx
51        o.start_block, o.leaves_end_block, o.end_block, o.root     -- other
52        FROM %_segdir o, %_segdir i
53        WHERE (o.level / 1024) = (i.level / 1024)
54        GROUP BY o.level, o.idx;
55
56      DELETE FROM %_segdir;
57      INSERT INTO %_segdir SELECT * FROM temp.tmp_segdir;
58      DROP TABLE temp.tmp_segdir;
59
60    COMMIT;
61  }]
62}
63
64do_test 1.1 {
65  execsql { CREATE VIRTUAL TABLE t2 USING fts4(words, prefix="1,2,3") }
66  foreach {docid words} [db eval { SELECT * FROM t1 }] {
67    execsql { INSERT INTO t2(docid, words) VALUES($docid, $words) }
68  }
69} {}
70
71do_execsql_test 1.2 {
72  SELECT level, count(*) FROM t2_segdir GROUP BY level
73} {
74  0    13    1 15    2 5
75  1024 13 1025 15 1026 5
76  2048 13 2049 15 2050 5
77  3072 13 3073 15 3074 5
78}
79
80do_execsql_test 1.3 { INSERT INTO t2(t2) VALUES('integrity-check') }
81prepare_for_optimize db t2
82do_execsql_test 1.4 { INSERT INTO t2(t2) VALUES('integrity-check') }
83
84do_execsql_test 1.5 {
85  SELECT level, count(*) FROM t2_segdir GROUP BY level
86} {
87  32   33
88  1056 33
89  2080 33
90  3104 33
91}
92
93do_test 1.6 {
94  while 1 {
95    set tc1 [db total_changes]
96    execsql { INSERT INTO t2(t2) VALUES('merge=5,2') }
97    set tc2 [db total_changes]
98    if {($tc2 - $tc1) < 2} break
99  }
100  execsql { SELECT level, count(*) FROM t2_segdir GROUP BY level }
101} {33 1 1057 1 2081 1 3105 1}
102do_execsql_test 1.7 { INSERT INTO t2(t2) VALUES('integrity-check') }
103
104do_execsql_test 1.8 {
105  INSERT INTO t2(words) SELECT words FROM t1;
106  SELECT level, count(*) FROM t2_segdir GROUP BY level;
107} {0 2 1024 2 2048 2 3072 2}
108
109#-------------------------------------------------------------------------
110
111do_execsql_test 2.0 {
112  DELETE FROM t2;
113}
114do_test 2.1 {
115  foreach {docid words} [db eval { SELECT * FROM t1 }] {
116    execsql { INSERT INTO t2(docid, words) VALUES($docid, $words) }
117  }
118
119  set i 0
120  foreach {docid words} [db eval { SELECT * FROM t1 }] {
121    if {[incr i] % 2} { execsql { DELETE FROM t2 WHERE docid = $docid } }
122  }
123
124  set i 0
125  foreach {docid words} [db eval { SELECT * FROM t1 }] {
126    if {[incr i] % 3} {
127      execsql { INSERT OR REPLACE INTO t2(docid, words) VALUES($docid, $words) }
128    }
129  }
130} {}
131
132do_execsql_test 2.2 {
133  SELECT level, count(*) FROM t2_segdir GROUP BY level
134} {
135  0    10    1 15    2 12
136  1024 10 1025 15 1026 12
137  2048 10 2049 15 2050 12
138  3072 10 3073 15 3074 12
139}
140
141do_execsql_test 2.3 { INSERT INTO t2(t2) VALUES('integrity-check') }
142prepare_for_optimize db t2
143do_execsql_test 2.4 { INSERT INTO t2(t2) VALUES('integrity-check') }
144
145do_execsql_test 2.5 {
146  SELECT level, count(*) FROM t2_segdir GROUP BY level
147} {
148    32 37
149  1056 37
150  2080 37
151  3104 37
152}
153
154do_test 2.6 {
155  while 1 {
156    set tc1 [db total_changes]
157    execsql { INSERT INTO t2(t2) VALUES('merge=5,2') }
158    set tc2 [db total_changes]
159    if {($tc2 - $tc1) < 2} break
160  }
161  execsql { SELECT level, count(*) FROM t2_segdir GROUP BY level }
162} {33 1 1057 1 2081 1 3105 1}
163do_execsql_test 2.7 { INSERT INTO t2(t2) VALUES('integrity-check') }
164
165do_execsql_test 2.8 {
166  INSERT INTO t2(words) SELECT words FROM t1;
167  SELECT level, count(*) FROM t2_segdir GROUP BY level;
168} {0 2 1024 2 2048 2 3072 2}
169
170#-------------------------------------------------------------------------
171# Check that 'optimize' works when there is data in the in-memory hash
172# table, but no segments at all on disk.
173#
174do_execsql_test 3.1 {
175  CREATE VIRTUAL TABLE fts USING fts4 (t);
176  INSERT INTO fts (fts) VALUES ('optimize');
177}
178do_execsql_test 3.2 {
179  INSERT INTO fts(fts) VALUES('integrity-check');
180  SELECT count(*) FROM fts_segdir;
181} {0}
182do_execsql_test 3.3 {
183  BEGIN;
184  INSERT INTO fts (rowid, t) VALUES (2, 'test');
185  INSERT INTO fts (fts) VALUES ('optimize');
186  COMMIT;
187  SELECT level, idx FROM fts_segdir;
188} {0 0}
189do_execsql_test 3.4 {
190  INSERT INTO fts(fts) VALUES('integrity-check');
191  SELECT rowid FROM fts WHERE fts MATCH 'test';
192} {2}
193do_execsql_test 3.5 {
194  INSERT INTO fts (fts) VALUES ('optimize');
195  INSERT INTO fts(fts) VALUES('integrity-check');
196}
197do_test 3.6 {
198  set c1 [db total_changes]
199  execsql { INSERT INTO fts (fts) VALUES ('optimize') }
200  expr {[db total_changes] - $c1}
201} {1}
202do_test 3.7 {
203  execsql { INSERT INTO fts (rowid, t) VALUES (3, 'xyz') }
204  set c1 [db total_changes]
205  execsql { INSERT INTO fts (fts) VALUES ('optimize') }
206  expr {([db total_changes] - $c1) > 1}
207} {1}
208do_test 3.8 {
209  set c1 [db total_changes]
210  execsql { INSERT INTO fts (fts) VALUES ('optimize') }
211  expr {[db total_changes] - $c1}
212} {1}
213
214finish_test
215