File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / test / fts3cov.test
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:16 2012 UTC (12 years, 10 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    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>