Home | History | Annotate | Download | only in test
      1 # 2008 June 26
      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 focus
     12 # of this script is testing the FTS3 module's optimize() function.
     13 #
     14 
     15 set testdir [file dirname $argv0]
     16 source $testdir/tester.tcl
     17 source $testdir/fts3_common.tcl
     18 
     19 # If SQLITE_ENABLE_FTS3 is not defined, omit this file.
     20 ifcapable !fts3 {
     21   finish_test
     22   return
     23 }
     24 
     25 #*************************************************************************
     26 # Utility function to check for the expected terms in the segment
     27 # level/index.  _all version does same but for entire index.
     28 proc check_terms {test level index terms} {
     29   set where "level = $level AND idx = $index"
     30   do_test $test.terms [list fts3_terms t1 $where] $terms
     31 }
     32 proc check_terms_all {test terms} {
     33   do_test $test.terms [list fts3_terms t1 1] $terms
     34 }
     35 
     36 # Utility function to check for the expected doclist for the term in
     37 # segment level/index.  _all version does same for entire index.
     38 proc check_doclist {test level index term doclist} {
     39   set where "level = $level AND idx = $index"
     40   do_test $test.doclist [list fts3_doclist t1 $term $where] $doclist
     41 }
     42 proc check_doclist_all {test term doclist} {
     43   do_test $test.doclist [list fts3_doclist t1 $term 1] $doclist
     44 }
     45 
     46 #*************************************************************************
     47 # Test results when all rows are deleted and one is added back.
     48 # Previously older segments would continue to exist, but now the index
     49 # should be dropped when the table is empty.  The results should look
     50 # exactly like we never added the earlier rows in the first place.
     51 db eval {
     52   DROP TABLE IF EXISTS t1;
     53   CREATE VIRTUAL TABLE t1 USING fts3(c);
     54   INSERT INTO t1 (docid, c) VALUES (1, 'This is a test');
     55   INSERT INTO t1 (docid, c) VALUES (2, 'That was a test');
     56   INSERT INTO t1 (docid, c) VALUES (3, 'This is a test');
     57   DELETE FROM t1 WHERE 1=1; -- Delete each row rather than dropping table.
     58   INSERT INTO t1 (docid, c) VALUES (1, 'This is a test');
     59 }
     60 
     61 # Should be a single initial segment.
     62 do_test fts3d-1.segments {
     63   execsql {
     64     SELECT level, idx FROM t1_segdir ORDER BY level, idx;
     65   }
     66 } {0 0}
     67 do_test fts3d-1.matches {
     68   execsql {
     69     SELECT OFFSETS(t1) FROM t1
     70      WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid;
     71   }
     72 } {{0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}}
     73 
     74 check_terms_all fts3d-1.1 {a is test this}
     75 check_doclist_all fts3d-1.1.1 a {[1 0[2]]}
     76 check_doclist_all fts3d-1.1.2 is {[1 0[1]]}
     77 check_doclist_all fts3d-1.1.3 test {[1 0[3]]}
     78 check_doclist_all fts3d-1.1.4 this {[1 0[0]]}
     79 
     80 check_terms   fts3d-1.2   0 0 {a is test this}
     81 check_doclist fts3d-1.2.1 0 0 a {[1 0[2]]}
     82 check_doclist fts3d-1.2.2 0 0 is {[1 0[1]]}
     83 check_doclist fts3d-1.2.3 0 0 test {[1 0[3]]}
     84 check_doclist fts3d-1.2.4 0 0 this {[1 0[0]]}
     85 
     86 #*************************************************************************
     87 # Test results when everything is optimized manually.
     88 # NOTE(shess): This is a copy of fts3c-1.3.  I've pulled a copy here
     89 # because fts3d-2 and fts3d-3 should have identical results.
     90 db eval {
     91   DROP TABLE IF EXISTS t1;
     92   CREATE VIRTUAL TABLE t1 USING fts3(c);
     93   INSERT INTO t1 (docid, c) VALUES (1, 'This is a test');
     94   INSERT INTO t1 (docid, c) VALUES (2, 'That was a test');
     95   INSERT INTO t1 (docid, c) VALUES (3, 'This is a test');
     96   DELETE FROM t1 WHERE docid IN (1,3);
     97   DROP TABLE IF EXISTS t1old;
     98   ALTER TABLE t1 RENAME TO t1old;
     99   CREATE VIRTUAL TABLE t1 USING fts3(c);
    100   INSERT INTO t1 (docid, c) SELECT docid, c FROM t1old;
    101   DROP TABLE t1old;
    102 }
    103 
    104 # Should be a single optimal segment with the same logical results.
    105 do_test fts3d-2.segments {
    106   execsql {
    107     SELECT level, idx FROM t1_segdir ORDER BY level, idx;
    108   }
    109 } {0 0}
    110 do_test fts3d-2.matches {
    111   execsql {
    112     SELECT OFFSETS(t1) FROM t1
    113      WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid;
    114   }
    115 } {{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4}}
    116 
    117 check_terms_all fts3d-2.1 {a test that was}
    118 check_doclist_all fts3d-2.1.1 a {[2 0[2]]}
    119 check_doclist_all fts3d-2.1.2 test {[2 0[3]]}
    120 check_doclist_all fts3d-2.1.3 that {[2 0[0]]}
    121 check_doclist_all fts3d-2.1.4 was {[2 0[1]]}
    122 
    123 check_terms fts3d-2.2 0 0 {a test that was}
    124 check_doclist fts3d-2.2.1 0 0 a {[2 0[2]]}
    125 check_doclist fts3d-2.2.2 0 0 test {[2 0[3]]}
    126 check_doclist fts3d-2.2.3 0 0 that {[2 0[0]]}
    127 check_doclist fts3d-2.2.4 0 0 was {[2 0[1]]}
    128 
    129 #*************************************************************************
    130 # Test results when everything is optimized via optimize().
    131 db eval {
    132   DROP TABLE IF EXISTS t1;
    133   CREATE VIRTUAL TABLE t1 USING fts3(c);
    134   INSERT INTO t1 (docid, c) VALUES (1, 'This is a test');
    135   INSERT INTO t1 (docid, c) VALUES (2, 'That was a test');
    136   INSERT INTO t1 (docid, c) VALUES (3, 'This is a test');
    137   DELETE FROM t1 WHERE docid IN (1,3);
    138   SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
    139 }
    140 
    141 # Should be a single optimal segment with the same logical results.
    142 do_test fts3d-3.segments {
    143   execsql {
    144     SELECT level, idx FROM t1_segdir ORDER BY level, idx;
    145   }
    146 } {0 0}
    147 do_test fts3d-3.matches {
    148   execsql {
    149     SELECT OFFSETS(t1) FROM t1
    150      WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid;
    151   }
    152 } {{0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4}}
    153 
    154 check_terms_all fts3d-3.1 {a test that was}
    155 check_doclist_all fts3d-3.1.1 a {[2 0[2]]}
    156 check_doclist_all fts3d-3.1.2 test {[2 0[3]]}
    157 check_doclist_all fts3d-3.1.3 that {[2 0[0]]}
    158 check_doclist_all fts3d-3.1.4 was {[2 0[1]]}
    159 
    160 check_terms fts3d-3.2 0 0 {a test that was}
    161 check_doclist fts3d-3.2.1 0 0 a {[2 0[2]]}
    162 check_doclist fts3d-3.2.2 0 0 test {[2 0[3]]}
    163 check_doclist fts3d-3.2.3 0 0 that {[2 0[0]]}
    164 check_doclist fts3d-3.2.4 0 0 was {[2 0[1]]}
    165 
    166 #*************************************************************************
    167 # Test optimize() against a table involving segment merges.
    168 # NOTE(shess): Since there's no transaction, each of the INSERT/UPDATE
    169 # statements generates a segment.
    170 db eval {
    171   DROP TABLE IF EXISTS t1;
    172   CREATE VIRTUAL TABLE t1 USING fts3(c);
    173 
    174   INSERT INTO t1 (rowid, c) VALUES (1, 'This is a test');
    175   INSERT INTO t1 (rowid, c) VALUES (2, 'That was a test');
    176   INSERT INTO t1 (rowid, c) VALUES (3, 'This is a test');
    177 
    178   UPDATE t1 SET c = 'This is a test one' WHERE rowid = 1;
    179   UPDATE t1 SET c = 'That was a test one' WHERE rowid = 2;
    180   UPDATE t1 SET c = 'This is a test one' WHERE rowid = 3;
    181 
    182   UPDATE t1 SET c = 'This is a test two' WHERE rowid = 1;
    183   UPDATE t1 SET c = 'That was a test two' WHERE rowid = 2;
    184   UPDATE t1 SET c = 'This is a test two' WHERE rowid = 3;
    185 
    186   UPDATE t1 SET c = 'This is a test three' WHERE rowid = 1;
    187   UPDATE t1 SET c = 'That was a test three' WHERE rowid = 2;
    188   UPDATE t1 SET c = 'This is a test three' WHERE rowid = 3;
    189 
    190   UPDATE t1 SET c = 'This is a test four' WHERE rowid = 1;
    191   UPDATE t1 SET c = 'That was a test four' WHERE rowid = 2;
    192   UPDATE t1 SET c = 'This is a test four' WHERE rowid = 3;
    193 
    194   UPDATE t1 SET c = 'This is a test' WHERE rowid = 1;
    195   UPDATE t1 SET c = 'That was a test' WHERE rowid = 2;
    196   UPDATE t1 SET c = 'This is a test' WHERE rowid = 3;
    197 }
    198 
    199 # 2 segments in level 0, 1 in level 1 (18 segments created, 16
    200 # merged).
    201 do_test fts3d-4.segments {
    202   execsql {
    203     SELECT level, idx FROM t1_segdir ORDER BY level, idx;
    204   }
    205 } {0 0 0 1 1 0}
    206 
    207 do_test fts3d-4.matches {
    208   execsql {
    209     SELECT OFFSETS(t1) FROM t1
    210      WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid;
    211   }
    212 } [list {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4} \
    213         {0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \
    214         {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}]
    215 
    216 check_terms_all fts3d-4.1      {a four is one test that this three two was}
    217 check_doclist_all fts3d-4.1.1  a {[1 0[2]] [2 0[2]] [3 0[2]]}
    218 check_doclist_all fts3d-4.1.2  four {}
    219 check_doclist_all fts3d-4.1.3  is {[1 0[1]] [3 0[1]]}
    220 check_doclist_all fts3d-4.1.4  one {}
    221 check_doclist_all fts3d-4.1.5  test {[1 0[3]] [2 0[3]] [3 0[3]]}
    222 check_doclist_all fts3d-4.1.6  that {[2 0[0]]}
    223 check_doclist_all fts3d-4.1.7  this {[1 0[0]] [3 0[0]]}
    224 check_doclist_all fts3d-4.1.8  three {}
    225 check_doclist_all fts3d-4.1.9  two {}
    226 check_doclist_all fts3d-4.1.10 was {[2 0[1]]}
    227 
    228 check_terms fts3d-4.2     0 0 {a four test that was}
    229 check_doclist fts3d-4.2.1 0 0 a {[2 0[2]]}
    230 check_doclist fts3d-4.2.2 0 0 four {[2]}
    231 check_doclist fts3d-4.2.3 0 0 test {[2 0[3]]}
    232 check_doclist fts3d-4.2.4 0 0 that {[2 0[0]]}
    233 check_doclist fts3d-4.2.5 0 0 was {[2 0[1]]}
    234 
    235 check_terms fts3d-4.3     0 1 {a four is test this}
    236 check_doclist fts3d-4.3.1 0 1 a {[3 0[2]]}
    237 check_doclist fts3d-4.3.2 0 1 four {[3]}
    238 check_doclist fts3d-4.3.3 0 1 is {[3 0[1]]}
    239 check_doclist fts3d-4.3.4 0 1 test {[3 0[3]]}
    240 check_doclist fts3d-4.3.5 0 1 this {[3 0[0]]}
    241 
    242 check_terms fts3d-4.4      1 0 {a four is one test that this three two was}
    243 check_doclist fts3d-4.4.1  1 0 a {[1 0[2]] [2 0[2]] [3 0[2]]}
    244 check_doclist fts3d-4.4.2  1 0 four {[1] [2 0[4]] [3 0[4]]}
    245 check_doclist fts3d-4.4.3  1 0 is {[1 0[1]] [3 0[1]]}
    246 check_doclist fts3d-4.4.4  1 0 one {[1] [2] [3]}
    247 check_doclist fts3d-4.4.5  1 0 test {[1 0[3]] [2 0[3]] [3 0[3]]}
    248 check_doclist fts3d-4.4.6  1 0 that {[2 0[0]]}
    249 check_doclist fts3d-4.4.7  1 0 this {[1 0[0]] [3 0[0]]}
    250 check_doclist fts3d-4.4.8  1 0 three {[1] [2] [3]}
    251 check_doclist fts3d-4.4.9  1 0 two {[1] [2] [3]}
    252 check_doclist fts3d-4.4.10 1 0 was {[2 0[1]]}
    253 
    254 # Optimize should leave the result in the level of the highest-level
    255 # prior segment.
    256 breakpoint
    257 do_test fts3d-4.5 {
    258   execsql {
    259     SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
    260     SELECT level, idx FROM t1_segdir ORDER BY level, idx;
    261   }
    262 } {{Index optimized} 1 0}
    263 
    264 # Identical to fts3d-4.matches.
    265 do_test fts3d-4.5.matches {
    266   execsql {
    267     SELECT OFFSETS(t1) FROM t1
    268      WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid;
    269   }
    270 } [list {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4} \
    271         {0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \
    272         {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}]
    273 
    274 check_terms_all fts3d-4.5.1     {a is test that this was}
    275 check_doclist_all fts3d-4.5.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]}
    276 check_doclist_all fts3d-4.5.1.2 is {[1 0[1]] [3 0[1]]}
    277 check_doclist_all fts3d-4.5.1.3 test {[1 0[3]] [2 0[3]] [3 0[3]]}
    278 check_doclist_all fts3d-4.5.1.4 that {[2 0[0]]}
    279 check_doclist_all fts3d-4.5.1.5 this {[1 0[0]] [3 0[0]]}
    280 check_doclist_all fts3d-4.5.1.6 was {[2 0[1]]}
    281 
    282 check_terms fts3d-4.5.2     1 0 {a is test that this was}
    283 check_doclist fts3d-4.5.2.1 1 0 a {[1 0[2]] [2 0[2]] [3 0[2]]}
    284 check_doclist fts3d-4.5.2.2 1 0 is {[1 0[1]] [3 0[1]]}
    285 check_doclist fts3d-4.5.2.3 1 0 test {[1 0[3]] [2 0[3]] [3 0[3]]}
    286 check_doclist fts3d-4.5.2.4 1 0 that {[2 0[0]]}
    287 check_doclist fts3d-4.5.2.5 1 0 this {[1 0[0]] [3 0[0]]}
    288 check_doclist fts3d-4.5.2.6 1 0 was {[2 0[1]]}
    289 
    290 # Re-optimizing does nothing.
    291 do_test fts3d-5.0 {
    292   execsql {
    293     SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
    294     SELECT level, idx FROM t1_segdir ORDER BY level, idx;
    295   }
    296 } {{Index already optimal} 1 0}
    297 
    298 # Even if we move things around, still does nothing.
    299 do_test fts3d-5.1 {
    300   execsql {
    301     UPDATE t1_segdir SET level = 2 WHERE level = 1 AND idx = 0;
    302     SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
    303     SELECT level, idx FROM t1_segdir ORDER BY level, idx;
    304   }
    305 } {{Index already optimal} 2 0}
    306 
    307 finish_test
    308