Fix a problem causing the recovery extension to use excessive memory and CPU time...
[sqlite.git] / test / fts4opt.test
blob4b3d003239971c511fc7bb40dc4ec25c9a644aa5
1 # 2016 March 8
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
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.
10 #*************************************************************************
13 set testdir [file dirname $argv0]
14 source $testdir/tester.tcl
15 source $testdir/fts3_common.tcl
16 set ::testprefix fts4opt
18 # If SQLITE_ENABLE_FTS3 is defined, omit this file.
19 ifcapable !fts3 {
20   finish_test
21   return
24 # Create the fts_kjv_genesis procedure which fills and FTS3/4 table 
25 # with the complete text of the Book of Genesis.
27 source $testdir/genesis.tcl
29 do_execsql_test 1.0 { CREATE TABLE t1(docid, words) }
30 fts_kjv_genesis
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.
39 proc 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       );
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   }]
64 do_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 } {}
71 do_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
80 do_execsql_test 1.3 { INSERT INTO t2(t2) VALUES('integrity-check') }
81 prepare_for_optimize db t2
82 do_execsql_test 1.4 { INSERT INTO t2(t2) VALUES('integrity-check') }
84 do_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
93 do_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}
102 do_execsql_test 1.7 { INSERT INTO t2(t2) VALUES('integrity-check') }
104 do_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}
109 #-------------------------------------------------------------------------
111 do_execsql_test 2.0 {
112   DELETE FROM t2;
114 do_test 2.1 {
115   foreach {docid words} [db eval { SELECT * FROM t1 }] {
116     execsql { INSERT INTO t2(docid, words) VALUES($docid, $words) }
117   }
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   }
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 } {}
132 do_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
141 do_execsql_test 2.3 { INSERT INTO t2(t2) VALUES('integrity-check') }
142 prepare_for_optimize db t2
143 do_execsql_test 2.4 { INSERT INTO t2(t2) VALUES('integrity-check') }
145 do_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
154 do_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}
163 do_execsql_test 2.7 { INSERT INTO t2(t2) VALUES('integrity-check') }
165 do_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}
170 #-------------------------------------------------------------------------
171 # Check that 'optimize' works when there is data in the in-memory hash
172 # table, but no segments at all on disk.
174 do_execsql_test 3.1 {
175   CREATE VIRTUAL TABLE fts USING fts4 (t);
176   INSERT INTO fts (fts) VALUES ('optimize');
178 do_execsql_test 3.2 {
179   INSERT INTO fts(fts) VALUES('integrity-check');
180   SELECT count(*) FROM fts_segdir;
181 } {0}
182 do_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}
189 do_execsql_test 3.4 {
190   INSERT INTO fts(fts) VALUES('integrity-check');
191   SELECT rowid FROM fts WHERE fts MATCH 'test';
192 } {2}
193 do_execsql_test 3.5 {
194   INSERT INTO fts (fts) VALUES ('optimize');
195   INSERT INTO fts(fts) VALUES('integrity-check');
197 do_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}
202 do_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}
208 do_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}
214 finish_test