diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index ee3981cfb9..818e130db3 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -646,7 +646,7 @@ int fts3InitVtab( int nName; #ifdef SQLITE_TEST - char *zTestParam = 0; + const char *zTestParam = 0; if( strncmp(argv[argc-1], "test:", 5)==0 ){ zTestParam = argv[argc-1]; argc--; @@ -1470,8 +1470,7 @@ static int fts3DoclistMerge( break; } - case MERGE_POS_NEAR: - case MERGE_NEAR: { + default: assert( mergetype==MERGE_POS_NEAR || mergetype==MERGE_NEAR ); { char *aTmp = 0; char **ppPos = 0; if( mergetype==MERGE_POS_NEAR ){ @@ -1506,9 +1505,6 @@ static int fts3DoclistMerge( sqlite3_free(aTmp); break; } - - default: - assert(!"Invalid mergetype value passed to fts3DoclistMerge()"); } *pnBuffer = (int)(p-aBuffer); @@ -2085,7 +2081,7 @@ static int fts3FunctionArg( ){ Fts3Cursor *pRet; if( sqlite3_value_type(pVal)!=SQLITE_BLOB - && sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *) + || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *) ){ char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc); sqlite3_result_error(pContext, zErr, -1); @@ -2101,22 +2097,31 @@ static int fts3FunctionArg( ** Implementation of the snippet() function for FTS3 */ static void fts3SnippetFunc( - sqlite3_context *pContext, - int argc, - sqlite3_value **argv + sqlite3_context *pContext, /* SQLite function call context */ + int nVal, /* Size of apVal[] array */ + sqlite3_value **apVal /* Array of arguments */ ){ Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ const char *zStart = ""; const char *zEnd = ""; const char *zEllipsis = "..."; - if( argc<1 || argc>4 ) return; - if( fts3FunctionArg(pContext, "snippet", argv[0], &pCsr) ) return; + /* There must be at least one argument passed to this function (otherwise + ** the non-overloaded version would have been called instead of this one). + */ + assert( nVal>=1 ); - switch( argc ){ - case 4: zEllipsis = (const char*)sqlite3_value_text(argv[3]); - case 3: zEnd = (const char*)sqlite3_value_text(argv[2]); - case 2: zStart = (const char*)sqlite3_value_text(argv[1]); + if( nVal>4 ){ + sqlite3_result_error(pContext, + "wrong number of arguments to function snippet()", -1); + return; + } + if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return; + + switch( nVal ){ + case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]); + case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]); + case 2: zStart = (const char*)sqlite3_value_text(apVal[1]); } sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis); diff --git a/manifest b/manifest index ab1ae10f57..af701c58d6 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,5 @@ ------BEGIN PGP SIGNED MESSAGE----- -Hash: SHA1 - -C Enhanced\sdetection\sof\sdatabase\scorruption\sin\sbtree.c:allocateSpace(). -D 2009-12-06T03:35:51 +C Add\ssome\stests\sfor\sOR,\sAND\sand\sNOT\soperations\sto\sfts3rnd.test.\sAdd\stests\sto\scheck\sthat\serrors\sare\sreturned\swhen\sbad\sarguments\sare\spassed\sto\sfts3\sfunctions\ssnippet,\soffsets\sand\soptimize.\sMinor\sfix\sfor\sthe\ssame +D 2009-12-07T12:34:52 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -59,7 +56,7 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c f4152f277722781048c9bba19aa605dbb831ad9a +F ext/fts3/fts3.c 43d8cfd021d06d594ec74eb01d35c0a5731055ae F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3Int.h cc716c74afa7da8e0f8ef39404f33ea62a823eb3 F ext/fts3/fts3_expr.c c18794a62c257d3456d3314c5a18e348ae0d84bd @@ -329,7 +326,7 @@ F test/descidx3.test 3394ad4d089335cac743c36a14129d6d931c316f F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 F test/e_fkey.test fd1fcf89badd5f2773d7ac04775b5ff3488eda17 -F test/e_fts3.test ad278add0deca99d2d8ec3d8b06ffed965d5abc2 +F test/e_fts3.test 8907e25b2c7d6bda9f7077356f64bc5e26c251a7 F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398 F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041 @@ -405,7 +402,7 @@ F test/fts3expr.test 05dab77387801e4900009917bb18f556037d82da F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a F test/fts3malloc.test d02ee86b21edd2b43044e0d6dfdcd26cb6efddcb F test/fts3near.test dc196dd17b4606f440c580d45b3d23aa975fd077 -F test/fts3rnd.test 351197c4459c9d0a20e6413e5bc541a0dbfc4765 +F test/fts3rnd.test ec82795eb358b7a4d6ce79e764d8d55556197584 F test/func.test af106ed834001738246d276659406823e35cde7b F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/fuzz.test a4174c3009a3e2c2e14b31b364ebf7ddb49de2c9 @@ -779,14 +776,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 7a9a35327c55452e858335933ce11669fc888aeb -R 0f3ea22a321de0315884a4805815ec31 -U drh -Z 107d016b4cea97422dcf94676d1dec5c ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1.4.6 (GNU/Linux) - -iD8DBQFLGyaaoxKgR168RlERAqRoAJ9BqTXTTVZfQIaYlvy+t0KsL1+C7ACfZ/dm -hnb7PcWLb+b0XHgfDg673P4= -=+6jS ------END PGP SIGNATURE----- +P 5a511f98877f0f7f12d336b7831f3da901856b02 +R 2006ff195b109f8cae8438329e516c90 +U dan +Z 55cd6fd2906fc3343a73a0ae677b4c81 diff --git a/manifest.uuid b/manifest.uuid index 89f0f2bfcb..ed71393961 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5a511f98877f0f7f12d336b7831f3da901856b02 \ No newline at end of file +5811df3f0412598d189d46b58de4deff24573651 \ No newline at end of file diff --git a/test/e_fts3.test b/test/e_fts3.test index 319f7f67c2..1c7afc2625 100644 --- a/test/e_fts3.test +++ b/test/e_fts3.test @@ -32,6 +32,9 @@ proc write_test {tn tbl sql} { proc read_test {tn sql result} { uplevel [list do_select_test e_fts3-$tn $sql $result] } +proc error_test {tn sql result} { + uplevel [list do_error_test e_fts3-$tn $sql $result] +} #------------------------------------------------------------------------- @@ -43,7 +46,7 @@ proc read_test {tn sql result} { # DO_MALLOC_TEST=1: Run tests with transient OOM errors. # DO_MALLOC_TEST=2: Run tests with persistent OOM errors. # -foreach DO_MALLOC_TEST {0 1 2} { +foreach DO_MALLOC_TEST [lrange {0 1 2} 0 end] { # Reset the database and database connection. If this iteration of the # [foreach] loop is testing with OOM errors, disable the lookaside buffer. @@ -435,5 +438,32 @@ read_test 1.8.2.4 { # End of tests of example code in fts3.html #------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Test that errors in the arguments passed to the snippet and offsets +# functions are handled correctly. +# +set DO_MALLOC_TEST 0 +ddl_test 2.1.1 { CREATE VIRTUAL TABLE t1 USING fts3(a, b) } +write_test 2.1.2 t1_content { + INSERT INTO t1 VALUES('one two three', x'A1B2C3D4E5F6'); +} +error_test 2.1.3 { + SELECT offsets(a) FROM t1 WHERE a MATCH 'one' +} {illegal first argument to offsets} +error_test 2.1.4 { + SELECT offsets(b) FROM t1 WHERE a MATCH 'one' +} {illegal first argument to offsets} +error_test 2.1.5 { + SELECT optimize(a) FROM t1 LIMIT 1 +} {illegal first argument to optimize} +error_test 2.1.6 { + SELECT snippet(a) FROM t1 WHERE a MATCH 'one' +} {illegal first argument to snippet} +error_test 2.1.7 { + SELECT snippet() FROM t1 WHERE a MATCH 'one' +} {unable to use function snippet in the requested context} +error_test 2.1.8 { + SELECT snippet(a, b, 'A', 'B', 'C') FROM t1 WHERE a MATCH 'one' +} {wrong number of arguments to function snippet()} finish_test diff --git a/test/fts3rnd.test b/test/fts3rnd.test index 5acac485ff..0fb1512289 100644 --- a/test/fts3rnd.test +++ b/test/fts3rnd.test @@ -69,27 +69,14 @@ proc update_row {rowid} { execsql "UPDATE t1 SET [lindex $cols $iCol] = \$doc WHERE rowid = \$rowid" } -# Primitives to query the in-memory table. -# -proc simple_term {zTerm} { +proc simple_phrase {zPrefix} { set ret [list] - foreach {key value} [array get ::t1] { - if {[string first $zTerm $value]>=0} { lappend ret $key } - } - lsort -integer $ret -} - -proc simple_prefix {zPrefix} { - set ret [list] - set pattern [format "*%s%s*" $zPrefix [ - string repeat {[a-z]} [expr {3-[string length $zPrefix]}] - ]] + set pattern "*[string map {* \[a-z\]} $zPrefix]*" foreach {key value} [array get ::t1] { if {[string match $pattern $value]} { lappend ret $key } } lsort -integer $ret } - proc simple_near {termlist nNear} { set ret [list] @@ -121,6 +108,35 @@ proc simple_near {termlist nNear} { lsort -unique -integer $ret } +# The following three procs: +# +# setup_not A B +# setup_or A B +# setup_and A B +# +# each take two arguments. Both arguments must be lists of integer values +# sorted by value. The return value is the list produced by evaluating +# the equivalent of "A op B", where op is the FTS3 operator NOT, OR or +# AND. +# +proc setop_not {A B} { + foreach b $B { set n($b) {} } + set ret [list] + foreach a $A { if {![info exists n($a)]} {lappend ret $a} } + return $ret +} +proc setop_or {A B} { + lsort -integer -uniq [concat $A $B] +} +proc setop_and {A B} { + foreach b $B { set n($b) {} } + set ret [list] + foreach a $A { if {[info exists n($a)]} {lappend ret $a} } + return $ret +} + +set sqlite_fts3_enable_parentheses 1 + foreach nodesize {50 500 1000 2000} { catch { array unset ::t1 } @@ -162,7 +178,7 @@ foreach nodesize {50 500 1000 2000} { set term [random_term] do_test fts3rnd-1.$nodesize.$iTest.1.$i { execsql { SELECT docid FROM t1 WHERE t1 MATCH $term } - } [simple_term $term] + } [simple_phrase $term] } # This time, use the first two characters of each term as a term prefix @@ -174,7 +190,7 @@ foreach nodesize {50 500 1000 2000} { set match "${prefix}*" do_test fts3rnd-1.$nodesize.$iTest.2.$i { execsql { SELECT docid FROM t1 WHERE t1 MATCH $match } - } [simple_prefix $prefix] + } [simple_phrase $match] } # Similar to the above, except for phrase queries. @@ -184,9 +200,9 @@ foreach nodesize {50 500 1000 2000} { set match "\"$term\"" do_test fts3rnd-1.$nodesize.$iTest.3.$i { execsql { SELECT docid FROM t1 WHERE t1 MATCH $match } - } [simple_term $term] + } [simple_phrase $term] } - + # Three word phrases. # for {set i 0} {$i < 10} {incr i} { @@ -194,7 +210,20 @@ foreach nodesize {50 500 1000 2000} { set match "\"$term\"" do_test fts3rnd-1.$nodesize.$iTest.4.$i { execsql { SELECT docid FROM t1 WHERE t1 MATCH $match } - } [simple_term $term] + } [simple_phrase $term] + } + + # Three word phrases made up of term-prefixes. + # + for {set i 0} {$i < 10} {incr i} { + set query "[string range [random_term] 0 1]* " + append query "[string range [random_term] 0 1]* " + append query "[string range [random_term] 0 1]*" + + set match "\"$query\"" + do_test fts3rnd-1.$nodesize.$iTest.5.$i { + execsql { SELECT docid FROM t1 WHERE t1 MATCH $match } + } [simple_phrase $query] } # A NEAR query with terms as the arguments. @@ -202,11 +231,11 @@ foreach nodesize {50 500 1000 2000} { for {set i 0} {$i < 10} {incr i} { set terms [list [random_term] [random_term]] set match [join $terms " NEAR "] - do_test fts3rnd-1.$nodesize.$iTest.5.$i.$match { + do_test fts3rnd-1.$nodesize.$iTest.6.$i { execsql { SELECT docid FROM t1 WHERE t1 MATCH $match } } [simple_near $terms 10] } - + # A 3-way NEAR query with terms as the arguments. # for {set i 0} {$i < 10} {incr i} { @@ -214,11 +243,49 @@ foreach nodesize {50 500 1000 2000} { set nNear 11 set match [join $terms " NEAR/$nNear "] set fts3 [execsql { SELECT docid FROM t1 WHERE t1 MATCH $match }] - set tcl [simple_near $terms $nNear] - do_test fts3rnd-1.$nodesize.$iTest.5.$i.$match { + do_test fts3rnd-1.$nodesize.$iTest.7.$i { execsql { SELECT docid FROM t1 WHERE t1 MATCH $match } } [simple_near $terms $nNear] } + + # Set operations on simple term queries. + # + foreach {tn op proc} { + 8 OR setop_or + 9 NOT setop_not + 10 AND setop_and + } { + for {set i 0} {$i < 10} {incr i} { + set term1 [random_term] + set term2 [random_term] + set match "$term1 $op $term2" + do_test fts3rnd-1.$nodesize.$iTest.$tn.$i { + execsql { SELECT docid FROM t1 WHERE t1 MATCH $match } + } [$proc [simple_phrase $term1] [simple_phrase $term2]] + } + } + + # Set operations on NEAR queries. + # + foreach {tn op proc} { + 8 OR setop_or + 9 NOT setop_not + 10 AND setop_and + } { + for {set i 0} {$i < 10} {incr i} { + set term1 [random_term] + set term2 [random_term] + set term3 [random_term] + set term4 [random_term] + set match "$term1 NEAR $term2 $op $term3 NEAR $term4" + do_test fts3rnd-1.$nodesize.$iTest.$tn.$i { + execsql { SELECT docid FROM t1 WHERE t1 MATCH $match } + } [$proc \ + [simple_near [list $term1 $term2] 10] \ + [simple_near [list $term3 $term4] 10] + ] + } + } } }