From: dan Date: Fri, 29 May 2015 19:00:22 +0000 (+0000) Subject: Add extra tests and fixes for multi-column matches. X-Git-Tag: version-3.8.11~114^2~24 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a8c024905cb690b548c0536bf67656bba8e90753;p=thirdparty%2Fsqlite.git Add extra tests and fixes for multi-column matches. FossilOrigin-Name: ae6794ffa23ef6191bd8834422abf322d978c11b --- diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c index 23827293fe..18bcd0d374 100644 --- a/ext/fts5/fts5_expr.c +++ b/ext/fts5/fts5_expr.c @@ -333,6 +333,14 @@ void sqlite3Fts5ExprFree(Fts5Expr *p){ } } +static int fts5ExprColsetTest(Fts5ExprColset *pColset, int iCol){ + int i; + for(i=0; inCol; i++){ + if( pColset->aiCol[i]==iCol ) return 1; + } + return 0; +} + /* ** All individual term iterators in pPhrase are guaranteed to be valid and ** pointing to the same rowid when this function is called. This function @@ -355,7 +363,12 @@ static int fts5ExprPhraseIsMatch( Fts5PoslistReader *aIter = aStatic; int i; int rc = SQLITE_OK; - int iCol = pColset ? pColset->aiCol[0] : -1; + int iCol = -1; + + if( pColset && pColset->nCol==1 ){ + iCol = pColset->aiCol[0]; + pColset = 0; + } fts5BufferZero(&pPhrase->poslist); @@ -396,9 +409,11 @@ static int fts5ExprPhraseIsMatch( } }while( bMatch==0 ); - /* Append position iPos to the output */ - rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos); - if( rc!=SQLITE_OK ) goto ismatch_out; + if( pColset==0 || fts5ExprColsetTest(pColset, FTS5_POS2COLUMN(iPos)) ){ + /* Append position iPos to the output */ + rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos); + if( rc!=SQLITE_OK ) goto ismatch_out; + } for(i=0; inTerm; i++){ if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out; @@ -459,25 +474,25 @@ struct Fts5NearTrimmer { ** one phrase. All phrases currently point to the same row. The ** Fts5ExprPhrase.poslist buffers are populated accordingly. This function ** tests if the current row contains instances of each phrase sufficiently -** close together to meet the NEAR constraint. Output variable *pbMatch -** is set to true if it does, or false otherwise. -** -** If no error occurs, SQLITE_OK is returned. Or, if an error does occur, -** an SQLite error code. If a value other than SQLITE_OK is returned, the -** final value of *pbMatch is undefined. +** close together to meet the NEAR constraint. Non-zero is returned if it +** does, or zero otherwise. ** -** TODO: This function should also edit the position lists associated -** with each phrase to remove any phrase instances that are not part of -** a set of intances that collectively matches the NEAR constraint. +** If in/out parameter (*pRc) is set to other than SQLITE_OK when this +** function is called, it is a no-op. Or, if an error (e.g. SQLITE_NOMEM) +** occurs within this function (*pRc) is set accordingly before returning. +** The return value is undefined in both these cases. +** +** If no error occurs and non-zero (a match) is returned, the position-list +** of each phrase object is edited to contain only those entries that +** meet the constraint before returning. */ -static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){ +static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ Fts5NearTrimmer aStatic[4]; Fts5NearTrimmer *a = aStatic; - Fts5ExprPhrase **apPhrase = pNear->apPhrase; int i; - int rc = SQLITE_OK; + int rc = *pRc; int bMatch; assert( pNear->nPhrase>1 ); @@ -486,12 +501,14 @@ static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){ ** using sqlite3_malloc(). This approach could be improved upon. */ if( pNear->nPhrase>(sizeof(aStatic) / sizeof(aStatic[0])) ){ int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; - a = (Fts5NearTrimmer*)sqlite3_malloc(nByte); - if( !a ) return SQLITE_NOMEM; - memset(a, 0, nByte); + a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte); }else{ memset(aStatic, 0, sizeof(aStatic)); } + if( rc!=SQLITE_OK ){ + *pRc = rc; + return 0; + } /* Initialize a lookahead iterator for each phrase. After passing the ** buffer and buffer size to the lookaside-reader init function, zero @@ -551,10 +568,12 @@ static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){ if( fts5LookaheadReaderNext(&a[iAdv].reader) ) goto ismatch_out; } - ismatch_out: - *pbMatch = (a[0].pOut->n>0); - if( a!=aStatic ) sqlite3_free(a); - return rc; + ismatch_out: { + int bRet = a[0].pOut->n>0; + *pRc = rc; + if( a!=aStatic ) sqlite3_free(a); + return bRet; + } } /* @@ -700,6 +719,24 @@ static int fts5ExprExtractCol( return p - (*pa); } +static int fts5ExprExtractColset ( + Fts5ExprColset *pColset, /* Colset to filter on */ + const u8 *pPos, int nPos, /* Position list */ + Fts5Buffer *pBuf /* Output buffer */ +){ + int rc = SQLITE_OK; + int i; + + fts5BufferZero(pBuf); + for(i=0; inCol; i++){ + const u8 *pSub = pPos; + int nSub = fts5ExprExtractCol(&pSub, nPos, pColset->aiCol[i]); + if( nSub ){ + fts5BufferAppendBlob(&rc, pBuf, nSub, pSub); + } + } + return rc; +} /* @@ -756,24 +793,14 @@ static int fts5ExprNearNextMatch( assert( pPhrase->poslist.nSpace==0 ); pPhrase->poslist.n = fts5ExprExtractCol(&pPos, nPos, pColset->aiCol[0]); pPhrase->poslist.p = (u8*)pPos; - }else{ - int i; - fts5BufferZero(&pPhrase->poslist); - for(i=0; inCol; i++){ - const u8 *pSub = pPos; - int nSub = fts5ExprExtractCol(&pSub, nPos, pColset->aiCol[i]); - if( nSub ){ - fts5BufferAppendBlob(&rc, &pPhrase->poslist, nSub, pSub); - } - } + }else if( rc==SQLITE_OK ){ + rc = fts5ExprExtractColset(pColset, pPos, nPos, &pPhrase->poslist); } if( pPhrase->poslist.n ) return rc; }else{ int i; - assert( pNear->pColset==0 || pNear->pColset->nCol==1 ); - /* Advance the iterators until they all point to the same rowid */ rc = fts5ExprNearNextRowidMatch(pExpr, pNode); if( rc!=SQLITE_OK || pNode->bEof ) break; @@ -794,12 +821,9 @@ static int fts5ExprNearNextMatch( } } - if( rc==SQLITE_OK && i==pNear->nPhrase ){ - int bMatch = 1; - if( pNear->nPhrase>1 ){ - rc = fts5ExprNearIsMatch(pNear, &bMatch); - } - if( rc!=SQLITE_OK || bMatch ) break; + if( i==pNear->nPhrase ){ + if( i==1 ) break; + if( fts5ExprNearIsMatch(&rc, pNear) ) break; } } @@ -1558,7 +1582,7 @@ static char *fts5ExprPrintTcl( int i; int iTerm; - zRet = fts5PrintfAppend(zRet, "[%s ", zNearsetCmd); + zRet = fts5PrintfAppend(zRet, "%s ", zNearsetCmd); if( zRet==0 ) return 0; if( pNear->pColset ){ int *aiCol = pNear->pColset->aiCol; @@ -1596,7 +1620,6 @@ static char *fts5ExprPrintTcl( if( zRet==0 ) return 0; } - zRet = fts5PrintfAppend(zRet, "]"); if( zRet==0 ) return 0; }else{ @@ -1604,24 +1627,18 @@ static char *fts5ExprPrintTcl( char *z1 = 0; char *z2 = 0; switch( pExpr->eType ){ - case FTS5_AND: zOp = "&&"; break; - case FTS5_NOT: zOp = "&& !"; break; + case FTS5_AND: zOp = "AND"; break; + case FTS5_NOT: zOp = "NOT"; break; default: assert( pExpr->eType==FTS5_OR ); - zOp = "||"; + zOp = "OR"; break; } z1 = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pLeft); z2 = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRight); if( z1 && z2 ){ - int b1 = pExpr->pLeft->eType!=FTS5_STRING; - int b2 = pExpr->pRight->eType!=FTS5_STRING; - zRet = sqlite3_mprintf("%s%s%s %s %s%s%s", - b1 ? "(" : "", z1, b1 ? ")" : "", - zOp, - b2 ? "(" : "", z2, b2 ? ")" : "" - ); + zRet = sqlite3_mprintf("%s [%s] [%s]", zOp, z1, z2); } sqlite3_free(z1); sqlite3_free(z2); diff --git a/ext/fts5/test/fts5_common.tcl b/ext/fts5/test/fts5_common.tcl index 70f5063b79..e4a689bb72 100644 --- a/ext/fts5/test/fts5_common.tcl +++ b/ext/fts5/test/fts5_common.tcl @@ -147,3 +147,139 @@ proc fts5_rnddoc {n} { set doc } +#------------------------------------------------------------------------- +# Usage: +# +# nearset aCol ?-pc VARNAME? ?-near N? ?-col C? -- phrase1 phrase2... +# +# This command is used to test if a document (set of column values) matches +# the logical equivalent of a single FTS5 NEAR() clump and, if so, return +# the equivalent of an FTS5 position list. +# +# Parameter $aCol is passed a list of the column values for the document +# to test. Parameters $phrase1 and so on are the phrases. +# +# The result is a list of phrase hits. Each phrase hit is formatted as +# three integers separated by "." characters, in the following format: +# +# . . +# +# Options: +# +# -near N (NEAR distance. Default 10) +# -col C (List of column indexes to match against) +# -pc VARNAME (variable in caller frame to use for phrase numbering) +# +proc nearset {aCol args} { + set O(-near) 10 + set O(-col) {} + set O(-pc) "" + + set nOpt [lsearch -exact $args --] + if {$nOpt<0} { error "no -- option" } + + foreach {k v} [lrange $args 0 [expr $nOpt-1]] { + if {[info exists O($k)]==0} { error "unrecognized option $k" } + set O($k) $v + } + + if {$O(-pc) == ""} { + set counter 0 + } else { + upvar $O(-pc) counter + } + + # Set $phraselist to be a list of phrases. $nPhrase its length. + set phraselist [lrange $args [expr $nOpt+1] end] + set nPhrase [llength $phraselist] + + for {set j 0} {$j < [llength $aCol]} {incr j} { + for {set i 0} {$i < $nPhrase} {incr i} { + set A($j,$i) [list] + } + } + + set iCol -1 + foreach col $aCol { + incr iCol + if {$O(-col)!="" && [lsearch $O(-col) $iCol]<0} continue + set nToken [llength $col] + + set iFL [expr $O(-near) >= $nToken ? $nToken - 1 : $O(-near)] + for { } {$iFL < $nToken} {incr iFL} { + for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { + set B($iPhrase) [list] + } + + for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { + set p [lindex $phraselist $iPhrase] + set nPm1 [expr {[llength $p] - 1}] + set iFirst [expr $iFL - $O(-near) - [llength $p]] + + for {set i $iFirst} {$i <= $iFL} {incr i} { + if {[lrange $col $i [expr $i+$nPm1]] == $p} { lappend B($iPhrase) $i } + } + if {[llength $B($iPhrase)] == 0} break + } + + if {$iPhrase==$nPhrase} { + for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { + set A($iCol,$iPhrase) [concat $A($iCol,$iPhrase) $B($iPhrase)] + set A($iCol,$iPhrase) [lsort -integer -uniq $A($iCol,$iPhrase)] + } + } + } + } + + set res [list] + #puts [array names A] + + for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { + for {set iCol 0} {$iCol < [llength $aCol]} {incr iCol} { + foreach a $A($iCol,$iPhrase) { + lappend res "$counter.$iCol.$a" + } + } + incr counter + } + + #puts $res + sort_poslist $res +} + +#------------------------------------------------------------------------- +# Usage: +# +# sort_poslist LIST +# +# Sort a position list of the type returned by command [nearset] +# +proc sort_poslist {L} { + lsort -command instcompare $L +} +proc instcompare {lhs rhs} { + foreach {p1 c1 o1} [split $lhs .] {} + foreach {p2 c2 o2} [split $rhs .] {} + + set res [expr $c1 - $c2] + if {$res==0} { set res [expr $o1 - $o2] } + if {$res==0} { set res [expr $p1 - $p2] } + + return $res +} + +#------------------------------------------------------------------------- +# Logical operators used by the commands returned by fts5_tcl_expr(). +# +proc AND {a b} { + if {[llength $a]==0 || [llength $b]==0} { return [list] } + sort_poslist [concat $a $b] +} +proc OR {a b} { + sort_poslist [concat $a $b] +} +proc NOT {a b} { + if {[llength $b]} { return [list] } + return $a +} + diff --git a/ext/fts5/test/fts5ac.test b/ext/fts5/test/fts5ac.test index eb58ca9791..96c2e9f290 100644 --- a/ext/fts5/test/fts5ac.test +++ b/ext/fts5/test/fts5ac.test @@ -125,126 +125,6 @@ set data { 99 {r c v w i v h a t a c v c r e} {h h u m g o f b a e o} } -#------------------------------------------------------------------------- -# Usage: -# -# poslist aCol ?-pc VARNAME? ?-near N? ?-col C? -- phrase1 phrase2... -# -# This command is used to test if a document (set of column values) matches -# the logical equivalent of a single FTS5 NEAR() clump and, if so, return -# the equivalent of an FTS5 position list. -# -# Parameter $aCol is passed a list of the column values for the document -# to test. Parameters $phrase1 and so on are the phrases. -# -# The result is a list of phrase hits. Each phrase hit is formatted as -# three integers separated by "." characters, in the following format: -# -# . . -# -# Options: -# -# -near N (NEAR distance. Default 10) -# -col C (List of column indexes to match against) -# -pc VARNAME (variable in caller frame to use for phrase numbering) -# -proc poslist {aCol args} { - set O(-near) 10 - set O(-col) {} - set O(-pc) "" - - set nOpt [lsearch -exact $args --] - if {$nOpt<0} { error "no -- option" } - - foreach {k v} [lrange $args 0 [expr $nOpt-1]] { - if {[info exists O($k)]==0} { error "unrecognized option $k" } - set O($k) $v - } - - if {$O(-pc) == ""} { - set counter 0 - } else { - upvar $O(-pc) counter - } - - # Set $phraselist to be a list of phrases. $nPhrase its length. - set phraselist [lrange $args [expr $nOpt+1] end] - set nPhrase [llength $phraselist] - - for {set j 0} {$j < [llength $aCol]} {incr j} { - for {set i 0} {$i < $nPhrase} {incr i} { - set A($j,$i) [list] - } - } - - set iCol -1 - foreach col $aCol { - incr iCol - if {$O(-col)!="" && [lsearch $O(-col) $iCol]<0} continue - set nToken [llength $col] - - set iFL [expr $O(-near) >= $nToken ? $nToken - 1 : $O(-near)] - for { } {$iFL < $nToken} {incr iFL} { - for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { - set B($iPhrase) [list] - } - - for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { - set p [lindex $phraselist $iPhrase] - set nPm1 [expr {[llength $p] - 1}] - set iFirst [expr $iFL - $O(-near) - [llength $p]] - - for {set i $iFirst} {$i <= $iFL} {incr i} { - if {[lrange $col $i [expr $i+$nPm1]] == $p} { lappend B($iPhrase) $i } - } - if {[llength $B($iPhrase)] == 0} break - } - - if {$iPhrase==$nPhrase} { - for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { - set A($iCol,$iPhrase) [concat $A($iCol,$iPhrase) $B($iPhrase)] - set A($iCol,$iPhrase) [lsort -integer -uniq $A($iCol,$iPhrase)] - } - } - } - } - - set res [list] -#puts [array names A] - - for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} { - for {set iCol 0} {$iCol < [llength $aCol]} {incr iCol} { - foreach a $A($iCol,$iPhrase) { - lappend res "$counter.$iCol.$a" - } - } - incr counter - } - - #puts $res - return $res -} - -# Usage: -# -# nearset aCol ?-near N? ?-col C? -- phrase1 phrase2... -# -proc nearset {args} { - set plist [poslist {*}$args] - return [expr [llength [lindex $plist 0]]>0] -} - -proc instcompare {lhs rhs} { - foreach {p1 c1 o1} [split $lhs .] {} - foreach {p2 c2 o2} [split $rhs .] {} - - set res [expr $c1 - $c2] - if {$res==0} { set res [expr $o1 - $o2] } - if {$res==0} { set res [expr $p1 - $p2] } - - return $res -} - # Argument $expr is an FTS5 match expression designed to be executed against # an FTS5 table with the following schema: # @@ -262,25 +142,20 @@ proc instcompare {lhs rhs} { # proc matchdata {bPos expr {bAsc 1}} { - set tclexpr [db one {SELECT fts5_expr_tcl($expr, 'nearset $cols', 'x', 'y')}] + set tclexpr [db one { + SELECT fts5_expr_tcl($expr, 'nearset $cols -pc ::pc', 'x', 'y') + }] set res [list] #puts $tclexpr foreach {id x y} $::data { set cols [list $x $y] - if $tclexpr { + set ::pc 0 + #set hits [lsort -command instcompare [eval $tclexpr]] + set hits [eval $tclexpr] + if {[llength $hits]>0} { if {$bPos} { - set N [regexp -all -inline {\[nearset [^\]]*\]} $tclexpr] - set rowres [list] - set cnt 0 - foreach phrase $N { - set arglist [string range $phrase 9 end-1] - set cmd "poslist [lindex $arglist 0] -pc cnt [lrange $arglist 1 end]" - set pos [eval $cmd] - set rowres [concat $rowres $pos] - } - set rowres [lsort -command instcompare $rowres] - lappend res [list $id $rowres] + lappend res [list $id $hits] } else { lappend res $id } @@ -425,11 +300,11 @@ foreach {tn2 sql} { } $res } - do_test $tn2.4.1 { poslist {{a b c}} -- a } {0.0.0} - do_test $tn2.4.2 { poslist {{a b c}} -- c } {0.0.2} + do_test $tn2.4.1 { nearset {{a b c}} -- a } {0.0.0} + do_test $tn2.4.2 { nearset {{a b c}} -- c } {0.0.2} foreach {tn expr tclexpr} { - 1 {a b} {[N $x -- {a}] && [N $x -- {b}]} + 1 {a b} {AND [N $x -- {a}] [N $x -- {b}]} } { do_execsql_test $tn2.5.$tn { SELECT fts5_expr_tcl($expr, 'N $x') @@ -477,7 +352,7 @@ foreach {tn2 sql} { do_execsql_test 3.1 { SELECT fts5_expr_tcl('a AND b'); -} {{[nearset -- {a}] && [nearset -- {b}]}} +} {{AND [nearset -- {a}] [nearset -- {b}]}} finish_test diff --git a/ext/fts5/test/fts5auto.test b/ext/fts5/test/fts5auto.test new file mode 100644 index 0000000000..48d9148882 --- /dev/null +++ b/ext/fts5/test/fts5auto.test @@ -0,0 +1,307 @@ +# 2015 May 30 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# +# This file contains automatically generated tests for various types +# of MATCH expressions. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5auto + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + + +set data { + -4026076 + {n x w k b p x b n t t d s} {f j j s p j o} + {w v i y r} {i p y s} + {a o q v e n q r} {q v g u c y a z y} + 3995120 + {c} {e e w d t} + {x c p f w r s m l r b f d} {g g u e} + {s n u t d v p d} {b k v p m f} + -2913881 + {k m} {a} + {w r j z n s l} {m j i w d t w e l} + {z n c} {v f b m} + 174082 + {j} {q l w u k e q v r i} + {j l} {u v w r s p e l} + {p i k j k q c t g u s} {g u y s m h q k g t e s o r} + 3207399 + {e t} {} + {p} {y v r b e k h d e v} + {t m w z b g q t s d d h} {o n v u i t o y k j} + 182399 + {} {m o s o x d y f a x j z} + {x n z r c d} {n r x i r} + {s v s} {a u} + 768994 + {e u t q v z q k j p u f j p} {y c b} + {p s d} {k n w p m p p} + {u o x s d} {f s g r d b d r m m m z y} + 3931037 + {c j p x e} {c n k t h z o i} + {} {r r p j k x w q} + {o r d z d} {x} + 3105748 + {p x r u} {x i s w o t o g x m z i w} + {q x m z} {h c j w b l y w x c o} + {m b k v} {t v q i s a d x} + -2501642 + {o u d n w o m o o s n t r h} {k p e u y p e z d j r y g} + {v b b h d d q y j q j} {a m w d t} + {y e f n} {a k x i x} + -1745680 + {z u w j f d b f} {j w i c g u d w e} + {m f p v m a s p v c o s} {s c r z o t w l b e a q} + {m k q} {k b a v o} + -932328 + {r v i u m q d r} {f z u v h c m r f g} + {r x r} {k p i d h h w h z u a x} + {k m j p} {h l j a e u c i q x x f x g} + -3923818 + {t t p b n u i h e c k} {m z} + {v u d c} {v y y j s g} + {o a f k k q p h g x e n z x} {h d w c o l} + -2145922 + {z z l f a l g e d c d h} {j b j p k o o u b q} + {d i g q t f d r h k} {n w g j c x r p t y f l c t} + {d o c u k f o} {r y s x z s p p h g t p y c} + 4552917 + {j w j y h l k u} {n a} + {y h w c n k} {b} + {w} {z l r t s i m v c y} + 2292008 + {q v q j w y y x u t} {r q z n h a b o} + {d q y} {y v o e j} + {} {a b h c d l p d x} + 1407892 + {n j j u q d o a u c f} {r d b w o q n g} + {d e v w s} {v d v o u o x s l s j z y} + {j y w h i f g i h m} {v n z b n y} + -4412544 + {g h h r s} {h e r e} + {n q s} {o p z r m l l t} + {p} {f s u o b j} + 1209110 + {o a a z t t u h j} {z z i r k r} + {i c x q w g v o x z i z p} {q o g k i n z x e d v w v} + {p f v b g f e d n p u c y k} {q z z a i p a a s r e z} + 3448977 + {i v} {l u x t b o k} + {f h u v p} {k a o y j} + {d m k c j} {v c e r u e f i t} + -4703774 + {d h v w u z r e h x o l t} {p s f y w y r q d a m w} + {c h g c g j j f t b i c q} {s e} + {c t q j g f} {v n r w y r a g e j d} + 2414151 + {s o o s d s k q b f q v p e} {j r o b t o p d l o o x} + {d d k t v e} {} + {t v o d w} {w e q w h y c y y i j b a m} + -3342407 + {m c h n e p d o c r w n t} {j d k s p q l} + {t g s r w x j l r z r} {h} + {r q v x i r a n h s} {m y p b v w r a u o g q r} + -993951 + {l n p u o j d x t u u c o j} {k r n a r e k v i t o e} + {q f t t a a c z v f} {o n m p v f o e n} + {h z h i p s b j z h} {i t w m k c u g n i} + 1575251 + {} {z s i j d o x j a r t} + {h g j u j n v e n z} {p z j n n f} + {s q q f d w r l y i z d o m} {b a n d h t b y g h d} + 4263668 + {q g t h f s} {s g x p f q z i s o f l i} + {q k} {w v h a x n a r b} + {m j a h o b i x k r w z q u} {m t r g j o e q t m p u l} + 2487819 + {m w g x r n e u t s r} {b x a t u u j c r n} + {j} {w f j r e e y l p} + {o u h b} {o c a c a b v} + 167966 + {o d b s d o a u m o x y} {c} + {r w d o b v} {z e b} + {i n z a f g z o} {m u b a g} + 1948599 + {n r g q d j s} {n k} + {l b p d v t k h y y} {u m k e c} + {t b n y o t b} {j w c i r x x} + 2941631 + {l d p l b g f} {e k e} + {p j} {m c s w t b k n l d x} + {f o v y v l} {c w p s w j w c u t y} + 3561104 + {d r j j r j i g p} {u} + {g r j q} {z l p d s n f c h t d c v z} + {w r c f s x z y} {g f o k g g} + -2223281 + {y e t j j z f p o m m z} {h k o g o} + {m x a t} {l q x l} + {r w k d l s y b} {q g k b} + -4502874 + {k k b x k l f} {r} + {} {q m z b k h k u n e z} + {z q g y m y u} {} + 1757599 + {d p z j y u r} {z p l q w j t j} + {n i r x r y j} {} + {h} {w t d q c x z z x e e} + -4809589 + {} {z p x u h i i n g} + {w q s u d b f x n} {l y k b b r x t i} + {n d v j q o t o d p z e} {u r y u v u c} + 1068408 + {y e} {e g s k e w t p v o b k} + {z c m s} {r u r u h n h b p q g b} + {j k b l} {m c d t s r s q a d b o f} + -1972554 + {m s w} {d k v s a r k p a r i v} + {g j z k p} {y k c v r e u o q f i b a} + {i p i} {c z w c y b n z i v} + -2052385 + {} {x e u f f g n c i x n e i e} + {} {p s w d x p g} + {} {s j a h n} + 2805981 + {m x g c w o e} {k g u y r y i u e g g} + {f k j v t x p h x k u} {w i} + {b l f z f v t n} {i u d o d p h s m u} + 2507621 + {} {u b n l x f n j t} + {u r x l h} {h r l m r} + {d y e n b s q v t k n q q} {x l t v w h a s k} + -3138375 + {e o f j y x u w v e w z} {r d q g k n n v r c z n e w} + {l y i q z k j p u f q s k} {c i l l i m a a g a z r x f} + {a v k h m q z b y n z} {q g w c y r r o a} + -457971 + {j x a w e c s h f l f} {q} + {j f v j u m d q r v v} {x n v a w} + {i e h d h f u w t t z} {v s u l s v o v i k n e} + 2265221 + {z t c y w n y r t} {n b a x s} + {q w a v} {a b s d x i g w t e z h} + {t l} {j k r w f f y j o k u} + -3941280 + {r x t o z} {f j n z k} + {t x e b t d b k w i s} {j t y h i h} + {y q g n g s u v c z j z n g} {n n g t l p h} + 2084745 + {z d z d} {j} + {o e k t b k a z l w} {o p i h k c x} + {c r b t i j f} {z e n m} + 1265843 + {} {j s g j j x u y} + {u q t f} {g o g} + {w o j e d} {w q n a c t q x j} + -2941116 + {i n c u o} {f b} + {o m s q d o z a q} {f s v o b b} + {o a z c h r} {j e w h b f z} + -1265441 + {p g z q v a o a x a} {s t h} + {w i p o c} {s n d g f z w q o d v v l j} + {y f b i a s v} {u m o z k k s t s d p b l p} + -1989158 + {r i c n} {r e w w i n z} + {q u s y b w u g y g f o} {y} + {d} {j x i b x u y d c p v a h} + 2391989 + {b n w x w f q h p i} {e u b b i n a i o c d g} + {v a z o i e n l x l r} {r u f o r k w m d w} + {k s} {r f e j q p w} +} + +do_test 1.0 { + execsql { + BEGIN; + CREATE VIRTUAL TABLE tt USING fts5(a, b, c, d, e, f); + } + foreach {rowid a b c d e f} $data { + execsql { + INSERT INTO tt(rowid, a, b, c, d, e, f) + VALUES($rowid, $a, $b, $c, $d, $e, $f) + } + } + execsql { + COMMIT; + } +} {} + +proc fts5_test_poslist {cmd} { + set res [list] + for {set i 0} {$i < [$cmd xInstCount]} {incr i} { + lappend res [string map {{ } .} [$cmd xInst $i]] + } + set res +} +sqlite3_fts5_create_function db fts5_test_poslist fts5_test_poslist + +proc matchdata {expr} { + set tclexpr [db one { + SELECT fts5_expr_tcl( + $expr, 'nearset $cols -pc ::pc', 'a','b','c','d','e','f' + ) + }] + set res [list] + + db eval {SELECT rowid, * FROM tt} { + set cols [list $a $b $c $d $e $f] + set ::pc 0 + set rowdata [eval $tclexpr] + + if {$rowdata != ""} { + lappend res $rowid $rowdata + } + } + + set res +} + +#------------------------------------------------------------------------- +# + +do_execsql_test 2.0 { + SELECT rowid, fts5_test_poslist(tt) FROM tt WHERE tt MATCH 'a AND b'; +} [matchdata "a AND b"] + +do_test 2.1 { + llength [matchdata "a AND b"] +} 62 + +foreach {tn expr} { + 1 { [a] : x } + 2 { [a b] : x } + 3 { [a b f] : x } + 4 { [f a b] : x } + 5 { [f a b] : x y } + 6 { [f a b] : x + y } + 7 { [c a b] : x + c } + 8 { [c d] : "l m" } + 9 { [c e] : "l m" } +} { + set res [matchdata $expr] + do_test 3.$tn.[llength $res] { + execsql { + SELECT rowid, fts5_test_poslist(tt) FROM tt WHERE tt MATCH $expr + } + } $res +} + + +finish_test + diff --git a/ext/fts5/test/fts5fault4.test b/ext/fts5/test/fts5fault4.test index fe3fb0796a..417d470ed3 100644 --- a/ext/fts5/test/fts5fault4.test +++ b/ext/fts5/test/fts5fault4.test @@ -312,7 +312,7 @@ do_faultsim_test 10.1 -faults oom-t* -body { do_faultsim_test 10.2 -faults oom-t* -body { db one { SELECT fts5_expr_tcl('x:"a b c" AND b NEAR(a b)', 'ns', 'x') } } -test { - set res {[ns -col 0 -- {a b c}] && ([ns -- {b}] && [ns -near 10 -- {a} {b}])} + set res {AND [ns -col 0 -- {a b c}] [AND [ns -- {b}] [ns -near 10 -- {a} {b}]]} faultsim_test_result [list 0 $res] } diff --git a/manifest b/manifest index 47d2f6be5c..ecafa77346 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssyntax\sto\sfts5\sused\sto\sspecify\sthat\sa\sphrase\sor\sNEAR\sgroup\sshould\smatch\sa\ssubset\sof\scolumns.\sFor\sexample\s"[col1\scol2\s...]\s:\s". -D 2015-05-29T15:55:30.046 +C Add\sextra\stests\sand\sfixes\sfor\smulti-column\smatches. +D 2015-05-29T19:00:22.571 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2c28e557780395095c307a6e5cb539419027eb5e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -111,7 +111,7 @@ F ext/fts5/fts5Int.h 3bcecc469fe570ab188d123e1d33d6e5e11a5129 F ext/fts5/fts5_aux.c d53f00f31ad615ca4f139dd8751f9041afa00971 F ext/fts5/fts5_buffer.c 861599a0abe2383f0cd0352c57001140a26b0930 F ext/fts5/fts5_config.c 11f969ed711a0a8b611d47431d74c372ad78c713 -F ext/fts5/fts5_expr.c c607282529c7b5747fc2bcf80770d6abc22638bb +F ext/fts5/fts5_expr.c 1685b331ecb880cb8807e2dc7fc4184d2933bb96 F ext/fts5/fts5_hash.c 54dd25348a46ea62ea96322c572e08cd1fb37304 F ext/fts5/fts5_index.c 59b8a3dfde24ddb80c31088148a3dfc779db22ab F ext/fts5/fts5_storage.c 5d2b51adb304643d8f825ba89283d628418b20c2 @@ -121,10 +121,10 @@ F ext/fts5/fts5_unicode2.c da3cf712f05cd8347c8c5bc00964cc0361c88da9 F ext/fts5/fts5_vocab.c 1f8543b2c1ae4427f127a911bc8e60873fcd7bf9 F ext/fts5/fts5parse.y 4ee667932d561a150d96483cf563281b95a9e523 F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba -F ext/fts5/test/fts5_common.tcl 6d663e8c3d8409857363f66560df96b8ca813e79 +F ext/fts5/test/fts5_common.tcl 632ff0fd8bf3dd55c2ddaac2c16428548d5af7be F ext/fts5/test/fts5aa.test 5f73afe6a1394fdba9bc18302876ded81021bee6 F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad -F ext/fts5/test/fts5ac.test d35bbe22dd23b3dbac3e1d3f07eed0206213a480 +F ext/fts5/test/fts5ac.test 999fd5f44579f1eb565ed7cf3861c427537ff097 F ext/fts5/test/fts5ad.test 312f3c8ed9592533499c5b94d2059ae6382913a0 F ext/fts5/test/fts5ae.test 9175201baf8c885fc1cbb2da11a0c61fd11224db F ext/fts5/test/fts5af.test c2501ec2b61d6b179c305f5d2b8782ab3d4f832a @@ -134,6 +134,7 @@ F ext/fts5/test/fts5ai.test f20e53bbf0c55bc596f1fd47f2740dae028b8f37 F ext/fts5/test/fts5aj.test 05b569f5c16ea3098fb1984eec5cf50dbdaae5d8 F ext/fts5/test/fts5ak.test 7b8c5df96df599293f920b7e5521ebc79f647592 F ext/fts5/test/fts5al.test fc60ebeac9d8e366e71309d4c31fa72199d711d7 +F ext/fts5/test/fts5auto.test 62e62fa7d60c50d334c5f6cf6b1ed1d49fa3d8d8 F ext/fts5/test/fts5aux.test e5631607bbc05ac1c38cf7d691000509aca71ef3 F ext/fts5/test/fts5auxdata.test c69b86092bf1a157172de5f9169731af3403179b F ext/fts5/test/fts5bigpl.test b1cfd00561350ab04994ba7dd9d48468e5e0ec3b @@ -149,7 +150,7 @@ F ext/fts5/test/fts5eb.test 728a1f23f263548f5c29b29dfb851b5f2dbe723e F ext/fts5/test/fts5fault1.test b42d3296be8a75f557cf2cbce0d8b483fc9db45b F ext/fts5/test/fts5fault2.test 28c36c843bb39ae855ba79827417ecc37f114341 F ext/fts5/test/fts5fault3.test d6e9577d4312e331a913c72931bf131704efc8f3 -F ext/fts5/test/fts5fault4.test e7170486d71de72fe88018b5b920c0a9f6c19801 +F ext/fts5/test/fts5fault4.test b854f9895cb07cec58204d5a7ca82d03ce824e73 F ext/fts5/test/fts5fault5.test 54da9fd4c3434a1d4f6abdcb6469299d91cf5875 F ext/fts5/test/fts5fault6.test 234dc6355f8d3f8b5be2763f30699d770247c215 F ext/fts5/test/fts5full.test 0924bdca5416a242103239ace79c6f5aa34bab8d @@ -1331,7 +1332,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P b29ac50af0491a780a5a4c0985d88d0e5e014ba3 -R 34ff180b006ad5f21871399f838e5dbb +P 0fc0ea20920615f3e48ea2dbe2b7dcd979b0993e +R 358d1aaaac138ca9e6a38de66a871d33 U dan -Z f15f3e2fe41d81aa9045dd94b23ec6a4 +Z c843d103a5028eb0d546bbe1e7e6abdc diff --git a/manifest.uuid b/manifest.uuid index d1b95a249f..6a7e8e7df1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0fc0ea20920615f3e48ea2dbe2b7dcd979b0993e \ No newline at end of file +ae6794ffa23ef6191bd8834422abf322d978c11b \ No newline at end of file