diff --git a/ext/fts5/fts5Int.h b/ext/fts5/fts5Int.h index c7392b06e6..d9249b93b1 100644 --- a/ext/fts5/fts5Int.h +++ b/ext/fts5/fts5Int.h @@ -118,8 +118,7 @@ int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader*); typedef struct Fts5PoslistWriter Fts5PoslistWriter; struct Fts5PoslistWriter { - int iCol; - int iOff; + i64 iPrev; }; int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64); @@ -130,6 +129,12 @@ int sqlite3Fts5PoslistNext( int *piOff /* IN/OUT: Current token offset */ ); +int sqlite3Fts5PoslistNext64( + const u8 *a, int n, /* Buffer containing poslist */ + int *pi, /* IN/OUT: Offset within a[] */ + i64 *piOff /* IN/OUT: Current offset */ +); + /* ** End of interface to code in fts5_buffer.c. **************************************************************************/ diff --git a/ext/fts5/fts5_buffer.c b/ext/fts5/fts5_buffer.c index 2afce95020..b69af615b9 100644 --- a/ext/fts5/fts5_buffer.c +++ b/ext/fts5/fts5_buffer.c @@ -138,27 +138,40 @@ void sqlite3Fts5BufferSet( sqlite3Fts5BufferAppendBlob(pRc, pBuf, nData, pData); } +int sqlite3Fts5PoslistNext64( + const u8 *a, int n, /* Buffer containing poslist */ + int *pi, /* IN/OUT: Offset within a[] */ + i64 *piOff /* IN/OUT: Current offset */ +){ + int i = *pi; + if( i>=n ){ + /* EOF */ + return 1; + }else{ + i64 iOff = *piOff; + int iVal; + i += getVarint32(&a[i], iVal); + if( iVal==1 ){ + i += getVarint32(&a[i], iVal); + iOff = ((i64)iVal) << 32; + i += getVarint32(&a[i], iVal); + } + *piOff = iOff + (iVal-2); + *pi = i; + return 0; + } +} + /* ** Advance the iterator object passed as the only argument. Return true ** if the iterator reaches EOF, or false otherwise. */ int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader *pIter){ - if( pIter->i>=pIter->n ){ + if( sqlite3Fts5PoslistNext64(pIter->a, pIter->n, &pIter->i, &pIter->iPos) + || (pIter->iCol>=0 && (pIter->iPos >> 32) > pIter->iCol) + ){ pIter->bEof = 1; - }else{ - int iVal; - pIter->i += getVarint32(&pIter->a[pIter->i], iVal); - if( iVal==1 ){ - pIter->i += getVarint32(&pIter->a[pIter->i], iVal); - if( pIter->iCol>=0 && iVal>pIter->iCol ){ - pIter->bEof = 1; - }else{ - pIter->iPos = ((u64)iVal << 32); - pIter->i += getVarint32(&pIter->a[pIter->i], iVal); - } - } - pIter->iPos += (iVal-2); } return pIter->bEof; } @@ -183,18 +196,15 @@ int sqlite3Fts5PoslistWriterAppend( Fts5PoslistWriter *pWriter, i64 iPos ){ + static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; int rc = SQLITE_OK; - int iCol = (int)(iPos >> 32); - int iOff = (iPos & 0x7FFFFFFF); - - if( iCol!=pWriter->iCol ){ + if( (iPos & colmask) != (pWriter->iPrev & colmask) ){ fts5BufferAppendVarint(&rc, pBuf, 1); - fts5BufferAppendVarint(&rc, pBuf, iCol); - pWriter->iCol = iCol; - pWriter->iOff = 0; + fts5BufferAppendVarint(&rc, pBuf, (iPos >> 32)); + pWriter->iPrev = (iPos & colmask); } - fts5BufferAppendVarint(&rc, pBuf, (iOff - pWriter->iOff) + 2); - + fts5BufferAppendVarint(&rc, pBuf, (iPos - pWriter->iPrev) + 2); + pWriter->iPrev = iPos; return rc; } diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c index 3ea885e75c..06faf7ebff 100644 --- a/ext/fts5/fts5_expr.c +++ b/ext/fts5/fts5_expr.c @@ -52,7 +52,7 @@ struct Fts5ExprNode { Fts5ExprNode *pRight; /* Right hand child node */ Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */ int bEof; /* True at EOF */ - i64 iRowid; + i64 iRowid; /* Current rowid */ }; /* @@ -70,6 +70,7 @@ struct Fts5ExprTerm { ** within a document for it to match. */ struct Fts5ExprPhrase { + Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */ Fts5Buffer poslist; /* Current position list */ int nTerm; /* Number of entries in aTerm[] */ Fts5ExprTerm aTerm[0]; /* Terms that make up this phrase */ @@ -266,7 +267,7 @@ static int fts5ExprPhraseIsMatch( Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */ int *pbMatch /* OUT: Set to true if really a match */ ){ - Fts5PoslistWriter writer = {0, 0}; + Fts5PoslistWriter writer = {0}; Fts5PoslistReader aStatic[4]; Fts5PoslistReader *aIter = aStatic; int i; @@ -322,6 +323,46 @@ static int fts5ExprPhraseIsMatch( return rc; } +typedef struct Fts5LookaheadReader Fts5LookaheadReader; +struct Fts5LookaheadReader { + const u8 *a; /* Buffer containing position list */ + int n; /* Size of buffer a[] in bytes */ + int i; /* Current offset in position list */ + i64 iPos; /* Current position */ + i64 iLookahead; /* Next position */ +}; + +#define FTS5_LOOKAHEAD_EOF (((i64)1) << 62) + +static int fts5LookaheadReaderNext(Fts5LookaheadReader *p){ + p->iPos = p->iLookahead; + if( sqlite3Fts5PoslistNext64(p->a, p->n, &p->i, &p->iLookahead) ){ + p->iLookahead = FTS5_LOOKAHEAD_EOF; + } + return (p->iPos==FTS5_LOOKAHEAD_EOF); +} + +static int fts5LookaheadReaderInit( + const u8 *a, int n, /* Buffer to read position list from */ + Fts5LookaheadReader *p /* Iterator object to initialize */ +){ + memset(p, 0, sizeof(Fts5LookaheadReader)); + p->a = a; + p->n = n; + fts5LookaheadReaderNext(p); + return fts5LookaheadReaderNext(p); +} + +static int fts5LookaheadReaderEof(Fts5LookaheadReader *p){ + return (p->iPos==FTS5_LOOKAHEAD_EOF); +} + +typedef struct Fts5NearTrimmer Fts5NearTrimmer; +struct Fts5NearTrimmer { + Fts5LookaheadReader reader; /* Input iterator */ + Fts5PoslistWriter writer; /* Writer context */ + Fts5Buffer *pOut; /* Output poslist */ +}; /* ** The near-set object passed as the first argument contains more than @@ -340,8 +381,11 @@ static int fts5ExprPhraseIsMatch( ** a set of intances that collectively matches the NEAR constraint. */ static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){ - Fts5PoslistReader aStatic[4]; - Fts5PoslistReader *aIter = aStatic; + Fts5NearTrimmer aStatic[4]; + Fts5NearTrimmer *a = aStatic; + + Fts5ExprPhrase **apPhrase = pNear->apPhrase; + int i; int rc = SQLITE_OK; int bMatch; @@ -352,36 +396,75 @@ static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){ /* If the aStatic[] array is not large enough, allocate a large array ** using sqlite3_malloc(). This approach could be improved upon. */ if( pNear->nPhrase>(sizeof(aStatic) / sizeof(aStatic[0])) ){ - int nByte = sizeof(Fts5PoslistReader) * pNear->nPhrase; - aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte); - if( !aIter ) return SQLITE_NOMEM; + int nByte = sizeof(Fts5LookaheadReader) * pNear->nPhrase; + a = (Fts5NearTrimmer*)sqlite3_malloc(nByte); + if( !a ) return SQLITE_NOMEM; + memset(a, 0, nByte); + }else{ + memset(aStatic, 0, sizeof(aStatic)); } - /* Initialize a term iterator for each phrase */ + /* Initialize a lookahead iterator for each phrase. After passing the + ** buffer and buffer size to the lookaside-reader init function, zero + ** the phrase poslist buffer. The new poslist for the phrase (containing + ** the same entries as the original with some entries removed on account + ** of the NEAR constraint) is written over the original even as it is + ** being read. This is safe as the entries for the new poslist are a + ** subset of the old, so it is not possible for data yet to be read to + ** be overwritten. */ for(i=0; inPhrase; i++){ - Fts5Buffer *pPoslist = &pNear->apPhrase[i]->poslist; - sqlite3Fts5PoslistReaderInit(-1, pPoslist->p, pPoslist->n, &aIter[i]); + Fts5Buffer *pPoslist = &apPhrase[i]->poslist; + fts5LookaheadReaderInit(pPoslist->p, pPoslist->n, &a[i].reader); + pPoslist->n = 0; + a[i].pOut = pPoslist; } - iMax = aIter[0].iPos; - do { - bMatch = 1; - for(i=0; inPhrase; i++){ - Fts5PoslistReader *pPos = &aIter[i]; - i64 iMin = iMax - pNear->apPhrase[i]->nTerm - pNear->nNear; - if( pPos->iPosiPos>iMax ){ - bMatch = 0; - while( pPos->iPosnPhrase; i++){ + Fts5LookaheadReader *pPos = &a[i].reader; + iMin = iMax - pNear->apPhrase[i]->nTerm - pNear->nNear; + if( pPos->iPosiPos>iMax ){ + bMatch = 0; + while( pPos->iPosiPos>iMax ) iMax = pPos->iPos; } - if( pPos->iPos>iMax ) iMax = pPos->iPos; + } + }while( bMatch==0 ); + + /* Add an entry to each output position list */ + for(i=0; inPhrase; i++){ + i64 iPos = a[i].reader.iPos; + Fts5PoslistWriter *pWriter = &a[i].writer; + if( a[i].pOut->n==0 || iPos!=pWriter->iPrev ){ + sqlite3Fts5PoslistWriterAppend(a[i].pOut, pWriter, iPos); } } - }while( bMatch==0 ); + + iAdv = 0; + iMin = a[0].reader.iLookahead; + for(i=0; inPhrase; i++){ + if( a[i].reader.iLookahead < iMin ){ + iMin = a[i].reader.iLookahead; + iAdv = i; + } + } + if( fts5LookaheadReaderNext(&a[iAdv].reader) ) goto ismatch_out; + } ismatch_out: - *pbMatch = bMatch; - if( aIter!=aStatic ) sqlite3_free(aIter); + *pbMatch = (a[0].pOut->n>0); + if( a!=aStatic ) sqlite3_free(a); return rc; } @@ -519,7 +602,7 @@ static int fts5ExprNearNextMatch( while( 1 ){ int i; - /* Advance the iterators until they are a match */ + /* Advance the iterators until they all point to the same rowid */ rc = fts5ExprNearNextRowidMatch(pExpr, pNode); if( pNode->bEof || rc!=SQLITE_OK ) break; @@ -545,6 +628,8 @@ static int fts5ExprNearNextMatch( if( rc!=SQLITE_OK || bMatch ) break; } + /* If control flows to here, then the current rowid is not a match. + ** Advance all term iterators in all phrases to the next rowid. */ rc = fts5ExprNearAdvanceAll(pExpr, pNear, &pNode->bEof); if( pNode->bEof || rc!=SQLITE_OK ) break; } @@ -661,6 +746,14 @@ static int fts5ExprNodeNext(Fts5Expr *pExpr, Fts5ExprNode *pNode){ return rc; } +static void fts5ExprSetEof(Fts5ExprNode *pNode){ + if( pNode ){ + pNode->bEof = 1; + fts5ExprSetEof(pNode->pLeft); + fts5ExprSetEof(pNode->pRight); + } +} + /* ** */ @@ -688,7 +781,9 @@ static int fts5ExprNodeNextMatch(Fts5Expr *pExpr, Fts5ExprNode *pNode){ rc = fts5ExprNodeNext(pExpr, pAdv); if( rc!=SQLITE_OK ) break; } - pNode->bEof = p1->bEof || p2->bEof; + if( p1->bEof || p2->bEof ){ + fts5ExprSetEof(pNode); + } pNode->iRowid = p1->iRowid; break; } @@ -1090,6 +1185,12 @@ Fts5ExprNode *sqlite3Fts5ParseNode( pRet->pLeft = pLeft; pRet->pRight = pRight; pRet->pNear = pNear; + if( eType==FTS5_STRING ){ + int iPhrase; + for(iPhrase=0; iPhrasenPhrase; iPhrase++){ + pNear->apPhrase[iPhrase]->pNode = pRet; + } + } } } @@ -1398,7 +1499,8 @@ int sqlite3Fts5ExprPhraseSize(Fts5Expr *pExpr, int iPhrase){ int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){ if( iPhrase>=0 && iPhrasenPhrase ){ Fts5ExprPhrase *pPhrase = pExpr->apPhrase[iPhrase]; - if( sqlite3Fts5IterRowid(pPhrase->aTerm[0].pIter)==pExpr->pRoot->iRowid ){ + Fts5ExprNode *pNode = pPhrase->pNode; + if( pNode->bEof==0 && pNode->iRowid==pExpr->pRoot->iRowid ){ *pa = pPhrase->poslist.p; return pPhrase->poslist.n; } diff --git a/manifest b/manifest index 7d4537622b..c84bbf7a32 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swith\sposition\slist\sprocessing\sfor\sOR\squeries. -D 2014-07-17T15:14:07.541 +C Fix\sissues\swith\sposition\slists\sand\sNEAR\sconstraints. +D 2014-07-18T19:59:00.547 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -105,11 +105,11 @@ F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7 F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368 F ext/fts5/fts5.c 20bcb1e10756c72b550947236960edf96929ca2f F ext/fts5/fts5.h cda3b9d73e6ffa6d0cd35b7da6b808bf3a1ada32 -F ext/fts5/fts5Int.h 2d4c1e1ebdf18278776fcd8a64233ff3c04ea51f +F ext/fts5/fts5Int.h 6cf315d3999c14572012d676fa1baf4f4323587b F ext/fts5/fts5_aux.c 27b082732fd76277fd7e9277f52903723d97f99b -F ext/fts5/fts5_buffer.c b7aa6cdf4a63642fcc12359cedc4be748ca400cc +F ext/fts5/fts5_buffer.c 71cf2016b2881e7aea39f952995eafa510d96cbd F ext/fts5/fts5_config.c 94f1b4cb4de6a7cd5780c14adb0198e289df8cef -F ext/fts5/fts5_expr.c 52a1b47cfd30feb09c522392b1ba246eda7023f4 +F ext/fts5/fts5_expr.c 288b3e016253eab69ea8cefbff346a4697b44291 F ext/fts5/fts5_index.c 9ff3008e903aa9077b0a7a7aa76ab6080eb07a36 F ext/fts5/fts5_storage.c 7848d8f8528d798bba159900ea310a6d4a279da8 F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9 @@ -597,8 +597,9 @@ F test/fts4noti.test 524807f0c36d49deea7920cdd4cd687408b58849 F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36 F test/fts5aa.test c8d3b9694f6b2864161c7437408464a535d19343 F test/fts5ab.test dc04ed48cf93ca957d174406e6c192f2ff4f3397 -F test/fts5ac.test 84599f8253abc7e10b929b8ee0b47c5edd4eafbd +F test/fts5ac.test 9be418d037763f4cc5d86f4239db41fc86bb4f85 F test/fts5ad.test 2ed38bbc865678cb2905247120d02ebba7f20e07 +F test/fts5ae.test 5d5ffba68e850d9ade99cdd3f5c6431c82dad81d F test/fts5ea.test ff43b40f8879ba50b82def70f2ab67c195d1a1d4 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef @@ -1194,7 +1195,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 c1f9a4b76c0bbc1ef9f6cdb5d62aa5d536fdf38e -R c3e4d3fb829636894b73dbf001062a3f +P 5808f30fae0d844c52a785bf18872be371d4af68 +R c645036fa73431553c03d7990bbe09ec U dan -Z 4c19ad3988f765a5de2b9174d276eba9 +Z 973aba4d2c5c8ae6a3e94f9739fdfe1b diff --git a/manifest.uuid b/manifest.uuid index 0f87023763..e082d6160a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5808f30fae0d844c52a785bf18872be371d4af68 \ No newline at end of file +16352d3654d5672cd0251db51dbe19f779373feb \ No newline at end of file diff --git a/test/fts5ac.test b/test/fts5ac.test index 3257480134..ae6e56e7e7 100644 --- a/test/fts5ac.test +++ b/test/fts5ac.test @@ -309,21 +309,57 @@ foreach {tn expr} { 2.3 "d+c OR u" 2.4 "d+c OR u+d" + 3.1 { a AND b AND c } } { set res [matchdata 1 $expr] - do_execsql_test 2.1.$tn.[llength $res] { + do_execsql_test 2.$tn.[llength $res] { SELECT rowid, fts5_test(xx, 'poslist') FROM xx WHERE xx match $expr } $res } +#------------------------------------------------------------------------- +# Queries on a specific column. +# +foreach {tn expr} { + 1 "x:a" + 2 "y:a" + 3 "x:b" + 4 "y:b" +} { + set res [matchdata 1 $expr] + do_execsql_test 3.$tn.[llength $res] { + SELECT rowid, fts5_test(xx, 'poslist') FROM xx WHERE xx match $expr + } $res +} -do_test 2.1 { poslist {{a b c}} -- a } {0.0} -do_test 2.2 { poslist {{a b c}} -- c } {0.2} +#------------------------------------------------------------------------- +# Some NEAR queries. +# +foreach {tn expr} { + 1 "NEAR(a b)" + 2 "NEAR(r c)" + 2 { NEAR(r c, 5) } + 3 { NEAR(r c, 3) } + 4 { NEAR(r c, 2) } + 5 { NEAR(r c, 0) } + 6 { NEAR(a b c) } + 7 { NEAR(a b c, 8) } + 8 { x : NEAR(r c) } + 9 { y : NEAR(r c) } +} { + set res [matchdata 1 $expr] + do_execsql_test 4.1.$tn.[llength $res] { + SELECT rowid, fts5_test(xx, 'poslist') FROM xx WHERE xx match $expr + } $res +} + +do_test 4.1 { poslist {{a b c}} -- a } {0.0} +do_test 4.2 { poslist {{a b c}} -- c } {0.2} foreach {tn expr tclexpr} { 1 {a b} {[N $x -- {a}] && [N $x -- {b}]} } { - do_execsql_test 3.$tn {SELECT fts5_expr_tcl($expr, 'N $x')} [list $tclexpr] + do_execsql_test 5.$tn {SELECT fts5_expr_tcl($expr, 'N $x')} [list $tclexpr] } #------------------------------------------------------------------------- @@ -356,7 +392,7 @@ foreach {bAsc sql} { 19 { c NOT b OR a AND d } } { set res [matchdata 0 $expr $bAsc] - do_execsql_test 4.$bAsc.$tn.[llength $res] $sql $res + do_execsql_test 6.$bAsc.$tn.[llength $res] $sql $res } } diff --git a/test/fts5ae.test b/test/fts5ae.test new file mode 100644 index 0000000000..c433d43208 --- /dev/null +++ b/test/fts5ae.test @@ -0,0 +1,136 @@ +# 2014 June 17 +# +# 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 implements regression tests for SQLite library. The +# focus of this script is testing the FTS5 module. +# +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fts5ae + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a, b); + INSERT INTO t1(t1) VALUES('pgsz=32'); +} + +do_execsql_test 1.1 { + INSERT INTO t1 VALUES('hello', 'world'); + SELECT rowid FROM t1 WHERE t1 MATCH 'hello' ORDER BY rowid ASC; +} {1} + +do_execsql_test 1.2 { + INSERT INTO t1 VALUES('world', 'hello'); + SELECT rowid FROM t1 WHERE t1 MATCH 'hello' ORDER BY rowid ASC; +} {1 2} + +do_execsql_test 1.3 { + INSERT INTO t1 VALUES('world', 'world'); + SELECT rowid FROM t1 WHERE t1 MATCH 'hello' ORDER BY rowid ASC; +} {1 2} + +do_execsql_test 1.4.1 { + INSERT INTO t1 VALUES('hello', 'hello'); +} + +do_execsql_test 1.4.2 { + SELECT rowid FROM t1 WHERE t1 MATCH 'hello' ORDER BY rowid ASC; +} {1 2 4} + + +#------------------------------------------------------------------------- +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE t2 USING fts5(x, y); + INSERT INTO t2 VALUES('u t l w w m s', 'm f m o l t k o p e'); + INSERT INTO t2 VALUES('f g q e l n d m z x q', 'z s i i i m f w w f n g p'); +} + +do_execsql_test 2.1 { + SELECT rowid, fts5_test(t2, 'poslist') FROM t2 + WHERE t2 MATCH 'm' ORDER BY rowid; +} { + 1 {{0.5 1.0 1.2}} + 2 {{0.7 1.5}} +} + +do_execsql_test 2.2 { + SELECT rowid, fts5_test(t2, 'poslist') FROM t2 + WHERE t2 MATCH 'u OR q' ORDER BY rowid; +} { + 1 {0.0 {}} + 2 {{} {0.2 0.10}} +} + +do_execsql_test 2.3 { + SELECT rowid, fts5_test(t2, 'poslist') FROM t2 + WHERE t2 MATCH 'y:o' ORDER BY rowid; +} { + 1 {{1.3 1.7}} +} + +#------------------------------------------------------------------------- +# +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE t3 USING fts5(x, y); + INSERT INTO t3 VALUES( 'j f h o x x a z g b a f a m i b', 'j z c z y x w t'); + INSERT INTO t3 VALUES( 'r c', ''); +} + +do_execsql_test 3.1 { + SELECT rowid, fts5_test(t3, 'poslist') FROM t3 WHERE t3 MATCH 'NEAR(a b)'; +} { + 1 {{0.6 0.10 0.12} {0.9 0.15}} +} + +do_execsql_test 3.2 { + SELECT rowid, fts5_test(t3, 'poslist') FROM t3 WHERE t3 MATCH 'NEAR(r c)'; +} { + 2 {0.0 0.1} +} + +do_execsql_test 3.3 { + INSERT INTO t3 + VALUES('k x j r m a d o i z j', 'r t t t f e b r x i v j v g o'); + SELECT rowid, fts5_test(t3, 'poslist') + FROM t3 WHERE t3 MATCH 'a OR b AND c'; +} { + 3 {0.5 {} {}} + 1 {{0.6 0.10 0.12} {0.9 0.15} 1.2} +} + +#------------------------------------------------------------------------- +# +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE t4 USING fts5(x, y); + INSERT INTO t4 + VALUES('k x j r m a d o i z j', 'r t t t f e b r x i v j v g o'); +} + +breakpoint +do_execsql_test 4.1 { + SELECT rowid, fts5_test(t4, 'poslist') FROM t4 WHERE t4 MATCH 'a OR b AND c'; +} { + 1 {0.5 {} {}} +} + +#93 {0.5 1.6 {}} + + +finish_test + +