Annotation of embedaddon/sqlite3/test/fts3cov.test, revision 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>