Annotation of embedaddon/sqlite3/test/fts3cov.test, revision 1.1.1.1

1.1       misho       1: # 2009 December 03
                      2: #
                      3: #    May you do good and not evil.
                      4: #    May you find forgiveness for yourself and forgive others.
                      5: #    May you share freely, never taking more than you give.
                      6: #
                      7: #***********************************************************************
                      8: #
                      9: # The tests in this file are structural coverage tests for FTS3.
                     10: #
                     11: 
                     12: set testdir [file dirname $argv0]
                     13: source $testdir/tester.tcl
                     14: 
                     15: # If this build does not include FTS3, skip the tests in this file.
                     16: #
                     17: ifcapable !fts3 { finish_test ; return }
                     18: source $testdir/fts3_common.tcl
                     19: source $testdir/malloc_common.tcl
                     20: 
                     21: set DO_MALLOC_TEST 0
                     22: set testprefix fts3cov
                     23: 
                     24: #--------------------------------------------------------------------------
                     25: # When it first needs to read a block from the %_segments table, the FTS3 
                     26: # module compiles an SQL statement for that purpose. The statement is 
                     27: # stored and reused each subsequent time a block is read. This test case 
                     28: # tests the effects of an OOM error occuring while compiling the statement.
                     29: #
                     30: # Similarly, when FTS3 first needs to scan through a set of segment leaves
                     31: # to find a set of documents that matches a term, it allocates a string
                     32: # containing the text of the required SQL, and compiles one or more 
                     33: # statements to traverse the leaves. This test case tests that OOM errors
                     34: # that occur while allocating this string and statement are handled correctly
                     35: # also.
                     36: #
                     37: do_test fts3cov-1.1 {
                     38:   execsql { 
                     39:     CREATE VIRTUAL TABLE t1 USING fts3(x);
                     40:     INSERT INTO t1(t1) VALUES('nodesize=24');
                     41:     BEGIN;
                     42:       INSERT INTO t1 VALUES('Is the night chilly and dark?');
                     43:       INSERT INTO t1 VALUES('The night is chilly, but not dark.');
                     44:       INSERT INTO t1 VALUES('The thin gray cloud is spread on high,');
                     45:       INSERT INTO t1 VALUES('It covers but not hides the sky.');
                     46:     COMMIT;
                     47:     SELECT count(*)>0 FROM t1_segments;
                     48:   }
                     49: } {1}
                     50: 
                     51: set DO_MALLOC_TEST 1
                     52: do_restart_select_test fts3cov-1.2 {
                     53:   SELECT docid FROM t1 WHERE t1 MATCH 'chilly';
                     54: } {1 2}
                     55: set DO_MALLOC_TEST 0
                     56: 
                     57: #--------------------------------------------------------------------------
                     58: # When querying the full-text index, if an expected internal node block is 
                     59: # missing from the %_segments table, or if a NULL value is stored in the 
                     60: # %_segments table instead of a binary blob, database corruption should be 
                     61: # reported.
                     62: #
                     63: # Even with tiny 24 byte nodes, it takes a fair bit of data to produce a
                     64: # segment b-tree that uses the %_segments table to store internal nodes. 
                     65: #
                     66: do_test fts3cov-2.1 {
                     67:   execsql {
                     68:     INSERT INTO t1(t1) VALUES('nodesize=24');
                     69:     BEGIN;
                     70:       INSERT INTO t1 VALUES('The moon is behind, and at the full;');
                     71:       INSERT INTO t1 VALUES('And yet she looks both small and dull.');
                     72:       INSERT INTO t1 VALUES('The night is chill, the cloud is gray:');
                     73:       INSERT INTO t1 VALUES('''T is a month before the month of May,');
                     74:       INSERT INTO t1 VALUES('And the Spring comes slowly up this way.');
                     75:       INSERT INTO t1 VALUES('The lovely lady, Christabel,');
                     76:       INSERT INTO t1 VALUES('Whom her father loves so well,');
                     77:       INSERT INTO t1 VALUES('What makes her in the wood so late,');
                     78:       INSERT INTO t1 VALUES('A furlong from the castle gate?');
                     79:       INSERT INTO t1 VALUES('She had dreams all yesternight');
                     80:       INSERT INTO t1 VALUES('Of her own betrothed knight;');
                     81:       INSERT INTO t1 VALUES('And she in the midnight wood will pray');
                     82:       INSERT INTO t1 VALUES('For the weal of her lover that''s far away.');
                     83:     COMMIT;
                     84:   }
                     85:   execsql {
                     86:     INSERT INTO t1(t1) VALUES('optimize');
                     87:     SELECT substr(hex(root), 1, 2) FROM t1_segdir;
                     88:   }
                     89: } {03}
                     90: 
                     91: # Test the "missing entry" case:
                     92: do_test fts3cov-2.2 {
                     93:   set root [db one {SELECT root FROM t1_segdir}]
                     94:   read_fts3varint [string range $root 1 end] left_child
                     95:   execsql { DELETE FROM t1_segments WHERE blockid = $left_child }
                     96: } {}
                     97: do_error_test fts3cov-2.3 {
                     98:   SELECT * FROM t1 WHERE t1 MATCH 'c*'
                     99: } {SQL logic error or missing database}
                    100: 
                    101: # Test the "replaced with NULL" case:
                    102: do_test fts3cov-2.4 {
                    103:   execsql { INSERT INTO t1_segments VALUES($left_child, NULL) }
                    104: } {}
                    105: do_error_test fts3cov-2.5 {
                    106:   SELECT * FROM t1 WHERE t1 MATCH 'cloud'
                    107: } {SQL logic error or missing database}
                    108: 
                    109: #--------------------------------------------------------------------------
                    110: # The following tests are to test the effects of OOM errors while storing
                    111: # terms in the pending-hash table. Specifically, while creating doclist
                    112: # blobs to store in the table. More specifically, to test OOM errors while
                    113: # appending column numbers to doclists. For example, if a doclist consists
                    114: # of:
                    115: #
                    116: #   <docid> <column 0 offset-list> 0x01 <column N> <column N offset-list>
                    117: #
                    118: # The following tests check that malloc errors encountered while appending
                    119: # the "0x01 <column N>" data to the dynamically growable blob used to 
                    120: # accumulate the doclist in memory are handled correctly.
                    121: #
                    122: do_test fts3cov-3.1 {
                    123:   set cols [list]
                    124:   set vals [list]
                    125:   for {set i 0} {$i < 120} {incr i} {
                    126:     lappend cols "col$i"
                    127:     lappend vals "'word'"
                    128:   }
                    129:   execsql "CREATE VIRTUAL TABLE t2 USING fts3([join $cols ,])"
                    130: } {}
                    131: set DO_MALLOC_TEST 1 
                    132: do_write_test fts3cov-3.2 t2_content "
                    133:   INSERT INTO t2(docid, [join $cols ,]) VALUES(1, [join $vals ,])
                    134: "
                    135: do_write_test fts3cov-3.3 t2_content "
                    136:   INSERT INTO t2(docid, [join $cols ,]) VALUES(200, [join $vals ,])
                    137: "
                    138: do_write_test fts3cov-3.4 t2_content "
                    139:   INSERT INTO t2(docid, [join $cols ,]) VALUES(60000, [join $vals ,])
                    140: "
                    141: 
                    142: #-------------------------------------------------------------------------
                    143: # If too much data accumulates in the pending-terms hash table, it is
                    144: # flushed to the database automatically, even if the transaction has not
                    145: # finished. The following tests check the effects of encountering an OOM 
                    146: # while doing this.
                    147: #
                    148: do_test fts3cov-4.1 {
                    149:   execsql {
                    150:     CREATE VIRTUAL TABLE t3 USING fts3(x);
                    151:     INSERT INTO t3(t3) VALUES('nodesize=24');
                    152:     INSERT INTO t3(t3) VALUES('maxpending=100');
                    153:   }
                    154: } {}
                    155: set DO_MALLOC_TEST 1 
                    156: do_write_test fts3cov-4.2 t3_content {
                    157:   INSERT INTO t3(docid, x)
                    158:     SELECT 1, 'Then Christabel stretched forth her hand,' UNION ALL
                    159:     SELECT 3, 'And comforted fair Geraldine:'             UNION ALL
                    160:     SELECT 4, '''O well, bright dame, may you command'    UNION ALL
                    161:     SELECT 5, 'The service of Sir Leoline;'               UNION ALL
                    162:     SELECT 2, 'And gladly our stout chivalry'             UNION ALL
                    163:     SELECT 7, 'Will he send forth, and friends withal,'   UNION ALL
                    164:     SELECT 8, 'To guide and guard you safe and free'      UNION ALL
                    165:     SELECT 6, 'Home to your noble father''s hall.'''
                    166: }
                    167: 
                    168: #-------------------------------------------------------------------------
                    169: # When building the internal tree structure for each segment b-tree, FTS3
                    170: # assumes that the content of each internal node will be less than
                    171: # $nodesize bytes, where $nodesize is the advisory node size. If this turns
                    172: # out to be untrue, then an extra buffer must be malloc'd for each term.
                    173: # This test case tests these paths and the effects of said mallocs failing
                    174: # by inserting insert a document with some fairly large terms into a
                    175: # full-text table with a very small node-size. 
                    176: #
                    177: # Test this handling of large terms in three contexts:
                    178: #
                    179: #   1. When flushing the pending-terms table.
                    180: #   2. When optimizing the data structures using the INSERT syntax. 
                    181: #   2. When optimizing the data structures using the deprecated SELECT syntax. 
                    182: #
                    183: do_test fts3cov-5.1 {
                    184:   execsql {
                    185:     CREATE VIRTUAL TABLE t4 USING fts3(x);
                    186:     INSERT INTO t4(t4) VALUES('nodesize=24');
                    187:   }
                    188: } {}
                    189: set DO_MALLOC_TEST 1
                    190: 
                    191: # Test when flushing pending-terms table.
                    192: do_write_test fts3cov-5.2 t4_content {
                    193:   INSERT INTO t4
                    194:     SELECT 'ItisanancientMarinerAndhestoppethoneofthreeAA' UNION ALL
                    195:     SELECT 'ItisanancientMarinerAndhestoppethoneofthreeBB' UNION ALL
                    196:     SELECT 'ItisanancientMarinerAndhestoppethoneofthreeCC' UNION ALL
                    197:     SELECT 'BythylonggreybeardandglitteringeyeNowwhereforestoppstAA' UNION ALL
                    198:     SELECT 'BythylonggreybeardandglitteringeyeNowwhereforestoppstBB' UNION ALL
                    199:     SELECT 'BythylonggreybeardandglitteringeyeNowwhereforestoppstCC'
                    200: }
                    201: 
                    202: # Test when optimizing via INSERT.
                    203: do_test fts3cov-5.3 { execsql { INSERT INTO t4 VALUES('extra!') } } {}
                    204: do_write_test fts3cov-5.2 t4_segments { INSERT INTO t4(t4) VALUES('optimize') }
                    205: 
                    206: # Test when optimizing via SELECT.
                    207: do_test fts3cov-5.5 { execsql { INSERT INTO t4 VALUES('more extra!') } } {}
                    208: do_write_test fts3cov-5.6 t4_segments {
                    209:   SELECT * FROM (SELECT optimize(t4) FROM t4 LIMIT 1)
                    210:   EXCEPT SELECT 'Index optimized'
                    211: }
                    212: 
                    213: #-------------------------------------------------------------------------
                    214: # When merging all segments at a given level to create a single segment
                    215: # at level+1, FTS3 runs a query of the form:
                    216: #
                    217: #   SELECT count(*) FROM %_segdir WHERE level = ?
                    218: #
                    219: # The query is compiled the first time this operation is required and
                    220: # reused thereafter. This test aims to test the effects of an OOM while
                    221: # preparing and executing this query for the first time.
                    222: #
                    223: # Then, keep inserting rows into the table so that the effects of an OOM
                    224: # while re-executing the same query can also be tested.
                    225: #
                    226: do_test fts3cov-6.1 {
                    227:   execsql { CREATE VIRTUAL TABLE t5 USING fts3(x) }
                    228:   for {set i 0} {$i<16} {incr i} { execsql "INSERT INTO t5 VALUES('term$i')" }
                    229:   execsql { SELECT count(*) FROM t5_segdir }
                    230: } {16}
                    231: 
                    232: # First time.
                    233: db close
                    234: sqlite3 db test.db
                    235: do_write_test fts3cov-6.2 t5_content {
                    236:   INSERT INTO t5 VALUES('segment number 16!');
                    237: }
                    238: 
                    239: # Second time.
                    240: do_test fts3cov-6.3 {
                    241:   for {set i 1} {$i<16} {incr i} { execsql "INSERT INTO t5 VALUES('term$i')" }
                    242:   execsql { SELECT count(*) FROM t5_segdir }
                    243: } {17}
                    244: do_write_test fts3cov-6.4 t5_content {
                    245:   INSERT INTO t5 VALUES('segment number 16!');
                    246: }
                    247: 
                    248: #-------------------------------------------------------------------------
                    249: # Update the docid of a row. Test this in two scenarios:
                    250: #
                    251: #   1. When the row being updated is the only row in the table.
                    252: #   2. When it is not.
                    253: #
                    254: # The two cases above take different paths because in case 1 all data 
                    255: # structures can simply be emptied before inserting the new row record.
                    256: # In case 2, the data structures actually have to be updated.
                    257: #
                    258: do_test fts3cov-7.1 {
                    259:   execsql {
                    260:     CREATE VIRTUAL TABLE t7 USING fts3(a, b, c);
                    261:     INSERT INTO t7 VALUES('A', 'B', 'C');
                    262:     UPDATE t7 SET docid = 5;
                    263:     SELECT docid, * FROM t7;
                    264:   }
                    265: } {5 A B C}
                    266: do_test fts3cov-7.2 {
                    267:   execsql {
                    268:     INSERT INTO t7 VALUES('D', 'E', 'F');
                    269:     UPDATE t7 SET docid = 1 WHERE docid = 6;
                    270:     SELECT docid, * FROM t7;
                    271:   }
                    272: } {1 D E F 5 A B C}
                    273: 
                    274: #-------------------------------------------------------------------------
                    275: # If a set of documents are modified within a transaction, the 
                    276: # pending-terms table must be flushed each time a document with a docid
                    277: # less than or equal to the previous docid is modified. 
                    278: #
                    279: # This test checks the effects of an OOM error occuring when the 
                    280: # pending-terms table is flushed for this reason as part of a DELETE 
                    281: # statement.
                    282: #
                    283: do_malloc_test fts3cov-8 -sqlprep {
                    284:   BEGIN;
                    285:     CREATE VIRTUAL TABLE t8 USING fts3;
                    286:     INSERT INTO t8 VALUES('the output of each batch run');
                    287:     INSERT INTO t8 VALUES('(possibly a day''s work)');
                    288:     INSERT INTO t8 VALUES('was written to two separate disks');
                    289:   COMMIT;
                    290: } -sqlbody {
                    291:   BEGIN;
                    292:     DELETE FROM t8 WHERE rowid = 3;
                    293:     DELETE FROM t8 WHERE rowid = 2;
                    294:     DELETE FROM t8 WHERE rowid = 1;
                    295:   COMMIT;
                    296: }
                    297: 
                    298: #-------------------------------------------------------------------------
                    299: # Test some branches in the code that handles "special" inserts like:
                    300: #
                    301: #   INSERT INTO t1(t1) VALUES('optimize');
                    302: #
                    303: # Also test that an optimize (INSERT method) works on an empty table.
                    304: #
                    305: set DO_MALLOC_TEST 0
                    306: do_test fts3cov-9.1 {
                    307:   execsql { CREATE VIRTUAL TABLE xx USING fts3 }
                    308: } {}
                    309: do_error_test fts3cov-9.2 {
                    310:   INSERT INTO xx(xx) VALUES('optimise');   -- British spelling
                    311: } {SQL logic error or missing database}
                    312: do_error_test fts3cov-9.3 {
                    313:   INSERT INTO xx(xx) VALUES('short');
                    314: } {SQL logic error or missing database}
                    315: do_error_test fts3cov-9.4 {
                    316:   INSERT INTO xx(xx) VALUES('waytoolongtobecorrect');
                    317: } {SQL logic error or missing database}
                    318: do_test fts3cov-9.5 {
                    319:   execsql { INSERT INTO xx(xx) VALUES('optimize') }
                    320: } {}
                    321: 
                    322: #-------------------------------------------------------------------------
                    323: # Test that a table can be optimized in the middle of a transaction when
                    324: # the pending-terms table is non-empty. This case involves some extra
                    325: # branches because data must be read not only from the database, but
                    326: # also from the pending-terms table.
                    327: #
                    328: do_malloc_test fts3cov-10 -sqlprep {
                    329:   CREATE VIRTUAL TABLE t10 USING fts3;
                    330:   INSERT INTO t10 VALUES('Optimising images for the web is a tricky business');
                    331:   BEGIN;
                    332:     INSERT INTO t10 VALUES('You have to get the right balance between');
                    333: } -sqlbody {
                    334:   INSERT INTO t10(t10) VALUES('optimize');
                    335: }
                    336: 
                    337: #-------------------------------------------------------------------------
                    338: # Test a full-text query for a term that was once in the index, but is
                    339: # no longer.
                    340: #
                    341: do_test fts3cov-11.1 {
                    342:   execsql { 
                    343:     CREATE VIRTUAL TABLE xx USING fts3;
                    344:     INSERT INTO xx VALUES('one two three');
                    345:     INSERT INTO xx VALUES('four five six');
                    346:     DELETE FROM xx WHERE docid = 1;
                    347:   }
                    348:   execsql { SELECT * FROM xx WHERE xx MATCH 'two' }
                    349: } {}
                    350: 
                    351: 
                    352: do_malloc_test fts3cov-12 -sqlprep {
                    353:   CREATE VIRTUAL TABLE t12 USING fts3;
                    354:   INSERT INTO t12 VALUES('is one of the two togther');
                    355:   BEGIN;
                    356:     INSERT INTO t12 VALUES('one which was appropriate at the time');
                    357: } -sqlbody {
                    358:   SELECT * FROM t12 WHERE t12 MATCH 'one'
                    359: }
                    360: 
                    361: do_malloc_test fts3cov-13 -sqlprep {
                    362:   PRAGMA encoding = 'UTF-16';
                    363:   CREATE VIRTUAL TABLE t13 USING fts3;
                    364:   INSERT INTO t13 VALUES('two scalar functions');
                    365:   INSERT INTO t13 VALUES('scalar two functions');
                    366:   INSERT INTO t13 VALUES('functions scalar two');
                    367: } -sqlbody {
                    368:   SELECT snippet(t13, '%%', '%%', '#') FROM t13 WHERE t13 MATCH 'two';
                    369:   SELECT snippet(t13, '%%', '%%') FROM t13 WHERE t13 MATCH 'two';
                    370:   SELECT snippet(t13, '%%') FROM t13 WHERE t13 MATCH 'two';
                    371: }
                    372: 
                    373: do_execsql_test 14.0 {
                    374:   CREATE VIRTUAL TABLE t14 USING fts4(a, b);
                    375:   INSERT INTO t14 VALUES('one two three', 'one three four');
                    376:   INSERT INTO t14 VALUES('a b c', 'd e a');
                    377: }
                    378: do_execsql_test 14.1 {
                    379:   SELECT rowid FROM t14 WHERE t14 MATCH '"one two three"'
                    380: } {1}
                    381: do_execsql_test 14.2 {
                    382:   SELECT rowid FROM t14 WHERE t14 MATCH '"one four"'
                    383: } {}
                    384: do_execsql_test 14.3 {
                    385:   SELECT rowid FROM t14 WHERE t14 MATCH '"e a"'
                    386: } {2}
                    387: do_execsql_test 14.5 {
                    388:   SELECT rowid FROM t14 WHERE t14 MATCH '"e b"'
                    389: } {}
                    390: do_catchsql_test 14.6 {
                    391:   SELECT rowid FROM t14 WHERE rowid MATCH 'one'
                    392: } {1 {unable to use function MATCH in the requested context}}
                    393: do_catchsql_test 14.7 {
                    394:   SELECT rowid FROM t14 WHERE docid MATCH 'one'
                    395: } {1 {unable to use function MATCH in the requested context}}
                    396: 
                    397: do_execsql_test 15.0 {
                    398:   CREATE VIRTUAL TABLE t15 USING fts4(a, b, c);
                    399:   INSERT INTO t15 VALUES('abc def ghi', 'abc2 def2 ghi2', 'abc3 def3 ghi3');
                    400:   INSERT INTO t15 VALUES('abc2 def2 ghi2', 'abc2 def2 ghi2', 'abc def3 ghi3');
                    401: }
                    402: do_execsql_test 15.1 {
                    403:   SELECT rowid FROM t15 WHERE t15 MATCH '"abc* def2"'
                    404: } {1 2}
                    405: 
                    406: # Test a corruption case.
                    407: #
                    408: do_execsql_test 16.1 {
                    409:   CREATE VIRTUAL TABLE t16 USING fts4;
                    410:   INSERT INTO t16 VALUES('theoretical work to examine the relationship');
                    411:   INSERT INTO t16 VALUES('solution of our problems on the invisible');
                    412:   DELETE FROM t16_content WHERE rowid = 2;
                    413: }
                    414: do_catchsql_test 16.2 {
                    415:   SELECT * FROM t16 WHERE t16 MATCH 'invisible'
                    416: } {1 {database disk image is malformed}}
                    417: 
                    418: # And another corruption test case.
                    419: #
                    420: do_execsql_test 17.1 {
                    421:   CREATE VIRTUAL TABLE t17 USING fts4;
                    422:   INSERT INTO t17(content) VALUES('one one one');
                    423:   UPDATE t17_segdir SET root = X'00036F6E65FFFFFFFFFFFFFFFFFFFFFF02030300'
                    424: } {}
                    425: do_catchsql_test 17.2 {
                    426:   SELECT * FROM t17 WHERE t17 MATCH 'one'
                    427: } {1 {database disk image is malformed}}
                    428: 
                    429: 
                    430: 
                    431: 
                    432: finish_test

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>