Add tests for the matchinfo-like test function. Fix problems found in test and fts5 code by doing so.

FossilOrigin-Name: 9e3aafe44a0813aa2a0c6172fdba1440b8a973ec
This commit is contained in:
dan 2015-08-05 19:35:59 +00:00
parent b20a42e316
commit 50b5491771
9 changed files with 594 additions and 61 deletions

View File

@ -2012,7 +2012,7 @@ int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
** Return the number of phrases in expression pExpr. ** Return the number of phrases in expression pExpr.
*/ */
int sqlite3Fts5ExprPhraseCount(Fts5Expr *pExpr){ int sqlite3Fts5ExprPhraseCount(Fts5Expr *pExpr){
return pExpr->nPhrase; return (pExpr ? pExpr->nPhrase : 0);
} }
/* /*

View File

@ -3944,7 +3944,7 @@ static void fts5FlushOneHash(Fts5Index *p){
/* Decide if the term will fit on the current leaf. If it will not, /* Decide if the term will fit on the current leaf. If it will not,
** flush the leaf to disk here. */ ** flush the leaf to disk here. */
if( (pBuf->n + nTerm + 2) > pgsz ){ if( pBuf->n>4 && (pBuf->n + nTerm + 2) > pgsz ){
fts5WriteFlushLeaf(p, &writer); fts5WriteFlushLeaf(p, &writer);
pBuf = &writer.writer.buf; pBuf = &writer.writer.buf;
if( (nTerm + 32) > pBuf->nSpace ){ if( (nTerm + 32) > pBuf->nSpace ){

View File

@ -169,6 +169,11 @@ struct Fts5Sorter {
*/ */
struct Fts5Cursor { struct Fts5Cursor {
sqlite3_vtab_cursor base; /* Base class used by SQLite core */ sqlite3_vtab_cursor base; /* Base class used by SQLite core */
Fts5Cursor *pNext; /* Next cursor in Fts5Cursor.pCsr list */
int *aColumnSize; /* Values for xColumnSize() */
i64 iCsrId; /* Cursor id */
/* Zero from this point onwards on cursor reset */
int ePlan; /* FTS5_PLAN_XXX value */ int ePlan; /* FTS5_PLAN_XXX value */
int bDesc; /* True for "ORDER BY rowid DESC" queries */ int bDesc; /* True for "ORDER BY rowid DESC" queries */
i64 iFirstRowid; /* Return no rowids earlier than this */ i64 iFirstRowid; /* Return no rowids earlier than this */
@ -177,7 +182,6 @@ struct Fts5Cursor {
Fts5Expr *pExpr; /* Expression for MATCH queries */ Fts5Expr *pExpr; /* Expression for MATCH queries */
Fts5Sorter *pSorter; /* Sorter for "ORDER BY rank" queries */ Fts5Sorter *pSorter; /* Sorter for "ORDER BY rank" queries */
int csrflags; /* Mask of cursor flags (see below) */ int csrflags; /* Mask of cursor flags (see below) */
Fts5Cursor *pNext; /* Next cursor in Fts5Cursor.pCsr list */
i64 iSpecial; /* Result of special query */ i64 iSpecial; /* Result of special query */
/* "rank" function. Populated on demand from vtab.xColumn(). */ /* "rank" function. Populated on demand from vtab.xColumn(). */
@ -188,11 +192,9 @@ struct Fts5Cursor {
sqlite3_value **apRankArg; /* Array of trailing arguments */ sqlite3_value **apRankArg; /* Array of trailing arguments */
sqlite3_stmt *pRankArgStmt; /* Origin of objects in apRankArg[] */ sqlite3_stmt *pRankArgStmt; /* Origin of objects in apRankArg[] */
/* Variables used by auxiliary functions */ /* Auxiliary data storage */
i64 iCsrId; /* Cursor id */
Fts5Auxiliary *pAux; /* Currently executing extension function */ Fts5Auxiliary *pAux; /* Currently executing extension function */
Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */ Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
int *aColumnSize; /* Values for xColumnSize() */
/* Cache used by auxiliary functions xInst() and xInstCount() */ /* Cache used by auxiliary functions xInst() and xInstCount() */
int nInstCount; /* Number of phrase instances */ int nInstCount; /* Number of phrase instances */
@ -429,12 +431,12 @@ static int fts5CreateMethod(
/* /*
** The different query plans. ** The different query plans.
*/ */
#define FTS5_PLAN_MATCH 0 /* (<tbl> MATCH ?) */ #define FTS5_PLAN_MATCH 1 /* (<tbl> MATCH ?) */
#define FTS5_PLAN_SOURCE 1 /* A source cursor for SORTED_MATCH */ #define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */
#define FTS5_PLAN_SPECIAL 2 /* An internal query */ #define FTS5_PLAN_SPECIAL 3 /* An internal query */
#define FTS5_PLAN_SORTED_MATCH 3 /* (<tbl> MATCH ? ORDER BY rank) */ #define FTS5_PLAN_SORTED_MATCH 4 /* (<tbl> MATCH ? ORDER BY rank) */
#define FTS5_PLAN_SCAN 4 /* No usable constraint */ #define FTS5_PLAN_SCAN 5 /* No usable constraint */
#define FTS5_PLAN_ROWID 5 /* (rowid = ?) */ #define FTS5_PLAN_ROWID 6 /* (rowid = ?) */
/* /*
** Implementation of the xBestIndex method for FTS5 tables. Within the ** Implementation of the xBestIndex method for FTS5 tables. Within the
@ -610,6 +612,44 @@ static void fts5CsrNewrow(Fts5Cursor *pCsr){
); );
} }
static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
Fts5Auxdata *pData;
Fts5Auxdata *pNext;
sqlite3_free(pCsr->aInst);
if( pCsr->pStmt ){
int eStmt = fts5StmtType(pCsr);
sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
}
if( pCsr->pSorter ){
Fts5Sorter *pSorter = pCsr->pSorter;
sqlite3_finalize(pSorter->pStmt);
sqlite3_free(pSorter);
}
if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){
sqlite3Fts5ExprFree(pCsr->pExpr);
}
for(pData=pCsr->pAuxdata; pData; pData=pNext){
pNext = pData->pNext;
if( pData->xDelete ) pData->xDelete(pData->pPtr);
sqlite3_free(pData);
}
sqlite3_finalize(pCsr->pRankArgStmt);
sqlite3_free(pCsr->apRankArg);
if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){
sqlite3_free(pCsr->zRank);
sqlite3_free(pCsr->zRankArgs);
}
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr));
}
/* /*
** Close the cursor. For additional information see the documentation ** Close the cursor. For additional information see the documentation
** on the xClose method of the virtual table interface. ** on the xClose method of the virtual table interface.
@ -619,41 +659,12 @@ static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
Fts5Cursor **pp; Fts5Cursor **pp;
Fts5Auxdata *pData;
Fts5Auxdata *pNext;
sqlite3_free(pCsr->aInst);
if( pCsr->pStmt ){
int eStmt = fts5StmtType(pCsr);
sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
}
if( pCsr->pSorter ){
Fts5Sorter *pSorter = pCsr->pSorter;
sqlite3_finalize(pSorter->pStmt);
sqlite3_free(pSorter);
}
if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){
sqlite3Fts5ExprFree(pCsr->pExpr);
}
for(pData=pCsr->pAuxdata; pData; pData=pNext){
pNext = pData->pNext;
if( pData->xDelete ) pData->xDelete(pData->pPtr);
sqlite3_free(pData);
}
fts5FreeCursorComponents(pCsr);
/* Remove the cursor from the Fts5Global.pCsr list */ /* Remove the cursor from the Fts5Global.pCsr list */
for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext); for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext);
*pp = pCsr->pNext; *pp = pCsr->pNext;
sqlite3_finalize(pCsr->pRankArgStmt);
sqlite3_free(pCsr->apRankArg);
if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){
sqlite3_free(pCsr->zRank);
sqlite3_free(pCsr->zRankArgs);
}
sqlite3_free(pCsr); sqlite3_free(pCsr);
} }
return SQLITE_OK; return SQLITE_OK;
@ -757,11 +768,11 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
int rc = SQLITE_OK; int rc = SQLITE_OK;
assert( (pCsr->ePlan<2)== assert( (pCsr->ePlan<3)==
(pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
); );
if( pCsr->ePlan<2 ){ if( pCsr->ePlan<3 ){
int bSkip = 0; int bSkip = 0;
if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc; if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid); rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
@ -1042,6 +1053,11 @@ static int fts5FilterMethod(
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */ sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
char **pzErrmsg = pConfig->pzErrmsg; char **pzErrmsg = pConfig->pzErrmsg;
if( pCsr->ePlan ){
fts5FreeCursorComponents(pCsr);
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
}
assert( pCsr->pStmt==0 ); assert( pCsr->pStmt==0 );
assert( pCsr->pExpr==0 ); assert( pCsr->pExpr==0 );
assert( pCsr->csrflags==0 ); assert( pCsr->csrflags==0 );

View File

@ -30,7 +30,9 @@
** they are not (as the "b AND c" sub-tree does not match the current ** they are not (as the "b AND c" sub-tree does not match the current
** row. ** row.
** **
** 2) ... ** 2) For the values returned by 'x' that apply to all rows of the table,
** NEAR constraints are not considered. But for the number of hits in
** the current row, they are.
** **
** This file exports a single function that may be called to register the ** This file exports a single function that may be called to register the
** matchinfo() implementation with a database handle: ** matchinfo() implementation with a database handle:
@ -82,13 +84,13 @@ static fts5_api *fts5_api_from_db(sqlite3 *db){
/* /*
** Argument f should be a flag accepted by matchinfo() (a valid character ** Argument f should be a flag accepted by matchinfo() (a valid character
** in the string passed as the second argument). If it is not, 0 is ** in the string passed as the second argument). If it is not, -1 is
** returned. Otherwise, if f is a valid matchinfo flag, the value returned ** returned. Otherwise, if f is a valid matchinfo flag, the value returned
** is the number of 32-bit integers added to the output array if the ** is the number of 32-bit integers added to the output array if the
** table has nCol columns and the query nPhrase phrases. ** table has nCol columns and the query nPhrase phrases.
*/ */
static int fts5MatchinfoFlagsize(int nCol, int nPhrase, char f){ static int fts5MatchinfoFlagsize(int nCol, int nPhrase, char f){
int ret = 0; int ret = -1;
switch( f ){ switch( f ){
case 'p': ret = 1; break; case 'p': ret = 1; break;
case 'c': ret = 1; break; case 'c': ret = 1; break;
@ -247,9 +249,38 @@ static int fts5MatchinfoLocalCb(
break; break;
} }
case 's': case 's': {
int nInst;
memset(aOut, 0, sizeof(u32) * p->nCol); memset(aOut, 0, sizeof(u32) * p->nCol);
rc = pApi->xInstCount(pFts, &nInst);
for(i=0; rc==SQLITE_OK && i<nInst; i++){
int iPhrase, iOff, iCol = 0;
int iNextPhrase;
int iNextOff;
int nSeq = 1;
int j;
rc = pApi->xInst(pFts, i, &iPhrase, &iCol, &iOff);
iNextPhrase = iPhrase+1;
iNextOff = iOff+pApi->xPhraseSize(pFts, 0);
for(j=i+1; rc==SQLITE_OK && j<nInst; j++){
int ip, ic, io;
rc = pApi->xInst(pFts, j, &ip, &ic, &io);
if( ic!=iCol || io>iNextOff ) break;
if( ip==iNextPhrase && io==iNextOff ){
nSeq++;
iNextPhrase = ip+1;
iNextOff = io + pApi->xPhraseSize(pFts, ip);
}
}
if( nSeq>aOut[iCol] ) aOut[iCol] = nSeq;
}
break; break;
}
} }
return rc; return rc;
} }
@ -274,7 +305,7 @@ static Fts5MatchinfoCtx *fts5MatchinfoNew(
nInt = 0; nInt = 0;
for(i=0; zArg[i]; i++){ for(i=0; zArg[i]; i++){
int n = fts5MatchinfoFlagsize(nCol, nPhrase, zArg[i]); int n = fts5MatchinfoFlagsize(nCol, nPhrase, zArg[i]);
if( n==0 ){ if( n<0 ){
char *zErr = sqlite3_mprintf("unrecognized matchinfo flag: %c", zArg[i]); char *zErr = sqlite3_mprintf("unrecognized matchinfo flag: %c", zArg[i]);
sqlite3_result_error(pCtx, zErr, -1); sqlite3_result_error(pCtx, zErr, -1);
sqlite3_free(zErr); sqlite3_free(zErr);

View File

@ -93,6 +93,10 @@ proc fts5_test_queryphrase {cmd} {
set res set res
} }
proc fts5_test_phrasecount {cmd} {
$cmd xPhraseCount
}
proc fts5_test_all {cmd} { proc fts5_test_all {cmd} {
set res [list] set res [list]
lappend res columnsize [fts5_test_columnsize $cmd] lappend res columnsize [fts5_test_columnsize $cmd]
@ -115,6 +119,7 @@ proc fts5_aux_test_functions {db} {
fts5_test_all fts5_test_all
fts5_test_queryphrase fts5_test_queryphrase
fts5_test_phrasecount
} { } {
sqlite3_fts5_create_function $db $f $f sqlite3_fts5_create_function $db $f $f
} }

View File

@ -277,5 +277,28 @@ foreach {tn q res} {
} $res } $res
} }
#-------------------------------------------------------------------------
# Test xPhraseCount() for some different queries.
#
do_test 9.1 {
execsql { CREATE VIRTUAL TABLE t9 USING fts5(x) }
foreach x {
"a b c" "d e f"
} {
execsql { INSERT INTO t9 VALUES($x) }
}
} {}
foreach {tn q cnt} {
1 {a AND b} 2
2 {a OR b} 2
3 {a OR b OR c} 3
4 {NEAR(a b)} 2
} {
do_execsql_test 9.2.$tn {
SELECT fts5_test_phrasecount(t9) FROM t9 WHERE t9 MATCH $q LIMIT 1
} $cnt
}
finish_test finish_test

View File

@ -0,0 +1,457 @@
# 2015 August 05
#
# 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.
#
#***********************************************************************
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5matchinfo
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { finish_test ; return }
proc mit {blob} {
set scan(littleEndian) i*
set scan(bigEndian) I*
binary scan $blob $scan($::tcl_platform(byteOrder)) r
return $r
}
db func mit mit
sqlite3_fts5_register_matchinfo db
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(content);
}
do_execsql_test 1.1 {
INSERT INTO t1(content) VALUES('I wandered lonely as a cloud');
INSERT INTO t1(content) VALUES('That floats on high o''er vales and hills,');
INSERT INTO t1(content) VALUES('When all at once I saw a crowd,');
INSERT INTO t1(content) VALUES('A host, of golden daffodils,');
SELECT mit(matchinfo(t1)) FROM t1 WHERE t1 MATCH 'I';
} {{1 1 1 2 2} {1 1 1 2 2}}
# Now create an FTS4 table that does not specify matchinfo=fts3.
#
do_execsql_test 1.2 {
CREATE VIRTUAL TABLE t2 USING fts5(content);
INSERT INTO t2 SELECT * FROM t1;
SELECT mit(matchinfo(t2)) FROM t2 WHERE t2 MATCH 'I';
} {{1 1 1 2 2} {1 1 1 2 2}}
#--------------------------------------------------------------------------
# Proc [do_matchinfo_test] is used to test the FTSX matchinfo() function.
#
# The first argument - $tn - is a test identifier. This may be either a
# full identifier (i.e. "fts3matchinfo-1.1") or, if global var $testprefix
# is set, just the numeric component (i.e. "1.1").
#
# The second argument is the name of an FTSX table. The third is the
# full text of a WHERE/MATCH expression to query the table for
# (i.e. "t1 MATCH 'abc'"). The final argument - $results - should be a
# key-value list (serialized array) with matchinfo() format specifiers
# as keys, and the results of executing the statement:
#
# SELECT matchinfo($tbl, '$key') FROM $tbl WHERE $expr
#
# For example:
#
# CREATE VIRTUAL TABLE t1 USING fts4;
# INSERT INTO t1 VALUES('abc');
# INSERT INTO t1 VALUES('def');
# INSERT INTO t1 VALUES('abc abc');
#
# do_matchinfo_test 1.1 t1 "t1 MATCH 'abc'" {
# n {3 3}
# p {1 1}
# c {1 1}
# x {{1 3 2} {2 3 2}}
# }
#
# If the $results list contains keys mapped to "-" instead of a matchinfo()
# result, then this command computes the expected results based on other
# mappings to test the matchinfo() function. For example, the command above
# could be changed to:
#
# do_matchinfo_test 1.1 t1 "t1 MATCH 'abc'" {
# n {3 3} p {1 1} c {1 1} x {{1 3 2} {2 3 2}}
# pcx -
# }
#
# And this command would compute the expected results for matchinfo(t1, 'pcx')
# based on the results of matchinfo(t1, 'p'), matchinfo(t1, 'c') and
# matchinfo(t1, 'x') in order to test 'pcx'.
#
proc do_matchinfo_test {tn tbl expr results} {
foreach {fmt res} $results {
if {$res == "-"} continue
set resarray($fmt) $res
}
set nRow 0
foreach {fmt res} [array get resarray] {
if {[llength $res]>$nRow} { set nRow [llength $res] }
}
# Construct expected results for any formats for which the caller
# supplied result is "-".
#
foreach {fmt res} $results {
if {$res == "-"} {
set res [list]
for {set iRow 0} {$iRow<$nRow} {incr iRow} {
set rowres [list]
foreach c [split $fmt ""] {
set rowres [concat $rowres [lindex $resarray($c) $iRow]]
}
lappend res $rowres
}
set resarray($fmt) $res
}
}
# Test each matchinfo() request individually.
#
foreach {fmt res} [array get resarray] {
set sql "SELECT mit(matchinfo($tbl, '$fmt')) FROM $tbl WHERE $expr"
do_execsql_test $tn.$fmt $sql [normalize2 $res]
}
# Test them all executed together (multiple invocations of matchinfo()).
#
set exprlist [list]
foreach {format res} [array get resarray] {
lappend exprlist "mit(matchinfo($tbl, '$format'))"
}
set allres [list]
for {set iRow 0} {$iRow<$nRow} {incr iRow} {
foreach {format res} [array get resarray] {
lappend allres [lindex $res $iRow]
}
}
set sql "SELECT [join $exprlist ,] FROM $tbl WHERE $expr"
do_execsql_test $tn.multi $sql [normalize2 $allres]
}
proc normalize2 {list_of_lists} {
set res [list]
foreach elem $list_of_lists {
lappend res [list {*}$elem]
}
return $res
}
do_execsql_test 4.1.0 {
CREATE VIRTUAL TABLE t4 USING fts5(x, y);
INSERT INTO t4 VALUES('a b c d e', 'f g h i j');
INSERT INTO t4 VALUES('f g h i j', 'a b c d e');
}
do_matchinfo_test 4.1.1 t4 {t4 MATCH 'a b c'} {
s {{3 0} {0 3}}
}
do_matchinfo_test 4.1.1 t4 {t4 MATCH 'a b c'} {
p {3 3}
x {
{1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1}
{0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1}
}
}
do_matchinfo_test 4.1.1 t4 {t4 MATCH 'a b c'} {
p {3 3}
c {2 2}
x {
{1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1}
{0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1}
}
n {2 2}
l {{5 5} {5 5}}
a {{5 5} {5 5}}
s {{3 0} {0 3}}
xxxxxxxxxxxxxxxxxx - pcx - xpc - ccc - pppxpcpcx - laxnpc -
xpxsscplax -
}
do_matchinfo_test 4.1.2 t4 {t4 MATCH '"g h i"'} {
p {1 1}
c {2 2}
x {
{0 1 1 1 1 1}
{1 1 1 0 1 1}
}
n {2 2}
l {{5 5} {5 5}}
a {{5 5} {5 5}}
s {{0 1} {1 0}}
xxxxxxxxxxxxxxxxxx - pcx - xpc - ccc - pppxpcpcx - laxnpc -
sxsxs -
}
do_matchinfo_test 4.1.3 t4 {t4 MATCH 'a b'} { s {{2 0} {0 2}} }
do_matchinfo_test 4.1.4 t4 {t4 MATCH '"a b" c'} { s {{2 0} {0 2}} }
do_matchinfo_test 4.1.5 t4 {t4 MATCH 'a "b c"'} { s {{2 0} {0 2}} }
do_matchinfo_test 4.1.6 t4 {t4 MATCH 'd d'} { s {{1 0} {0 1}} }
do_matchinfo_test 4.1.7 t4 {t4 MATCH 'f OR abcd'} {
x {
{0 1 1 1 1 1 0 0 0 0 0 0}
{1 1 1 0 1 1 0 0 0 0 0 0}
}
}
do_matchinfo_test 4.1.8 t4 {t4 MATCH 'f NOT abcd'} {
x {
{0 1 1 1 1 1 0 0 0 0 0 0}
{1 1 1 0 1 1 0 0 0 0 0 0}
}
}
do_execsql_test 4.2.0 {
CREATE VIRTUAL TABLE t5 USING fts5(content);
INSERT INTO t5 VALUES('a a a a a');
INSERT INTO t5 VALUES('a b a b a');
INSERT INTO t5 VALUES('c b c b c');
INSERT INTO t5 VALUES('x x x x x');
}
do_matchinfo_test 4.2.1 t5 {t5 MATCH 'a a'} {
x {{5 8 2 5 8 2} {3 8 2 3 8 2}}
s {2 1}
}
do_matchinfo_test 4.2.2 t5 {t5 MATCH 'a b'} { s {2} }
do_matchinfo_test 4.2.3 t5 {t5 MATCH 'a b a'} { s {3} }
do_matchinfo_test 4.2.4 t5 {t5 MATCH 'a a a'} { s {3 1} }
do_matchinfo_test 4.2.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
do_matchinfo_test 4.2.6 t5 {t5 MATCH 'a OR b'} { s {1 2 1} }
do_execsql_test 4.3.0 "INSERT INTO t5 VALUES('x y [string repeat {b } 50000]')";
# It used to be that the second 'a' token would be deferred. That doesn't
# work any longer.
if 0 {
do_matchinfo_test 4.3.1 t5 {t5 MATCH 'a a'} {
x {{5 8 2 5 5 5} {3 8 2 3 5 5}}
s {2 1}
}
}
do_matchinfo_test 4.3.2 t5 {t5 MATCH 'a b'} { s {2} }
do_matchinfo_test 4.3.3 t5 {t5 MATCH 'a b a'} { s {3} }
do_matchinfo_test 4.3.4 t5 {t5 MATCH 'a a a'} { s {3 1} }
do_matchinfo_test 4.3.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
do_matchinfo_test 4.3.6 t5 {t5 MATCH 'a OR b'} { s {1 2 1 1} }
do_execsql_test 4.4.0.1 { INSERT INTO t5(t5) VALUES('optimize') }
do_matchinfo_test 4.4.2 t5 {t5 MATCH 'a b'} { s {2} }
do_matchinfo_test 4.4.1 t5 {t5 MATCH 'a a'} { s {2 1} }
do_matchinfo_test 4.4.2 t5 {t5 MATCH 'a b'} { s {2} }
do_matchinfo_test 4.4.3 t5 {t5 MATCH 'a b a'} { s {3} }
do_matchinfo_test 4.4.4 t5 {t5 MATCH 'a a a'} { s {3 1} }
do_matchinfo_test 4.4.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
do_execsql_test 4.5.0 {
CREATE VIRTUAL TABLE t6 USING fts5(a, b, c);
INSERT INTO t6 VALUES('a', 'b', 'c');
}
do_matchinfo_test 4.5.1 t6 {t6 MATCH 'a b c'} { s {{1 1 1}} }
#-------------------------------------------------------------------------
# Test the outcome of matchinfo() when used within a query that does not
# use the full-text index (i.e. lookup by rowid or full-table scan).
#
do_execsql_test 7.1 {
CREATE VIRTUAL TABLE t10 USING fts5(content);
INSERT INTO t10 VALUES('first record');
INSERT INTO t10 VALUES('second record');
}
do_execsql_test 7.2 {
SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) FROM t10;
} {blob 8 blob 8}
do_execsql_test 7.3 {
SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) FROM t10 WHERE rowid=1;
} {blob 8}
do_execsql_test 7.4 {
SELECT typeof(matchinfo(t10)), length(matchinfo(t10))
FROM t10 WHERE t10 MATCH 'record'
} {blob 20 blob 20}
#-------------------------------------------------------------------------
# Test a special case - matchinfo('nxa') with many zero length documents.
# Special because "x" internally uses a statement used by both "n" and "a".
# This was causing a problem at one point in the obscure case where the
# total number of bytes of data stored in an fts3 table was greater than
# the number of rows. i.e. when the following query returns true:
#
# SELECT sum(length(content)) < count(*) FROM fts4table;
#
do_execsql_test 8.1 {
CREATE VIRTUAL TABLE t11 USING fts5(content);
INSERT INTO t11(t11, rank) VALUES('pgsz', 32);
INSERT INTO t11 VALUES('quitealongstringoftext');
INSERT INTO t11 VALUES('anotherquitealongstringoftext');
INSERT INTO t11 VALUES('athirdlongstringoftext');
INSERT INTO t11 VALUES('andonemoreforgoodluck');
}
do_test 8.2 {
for {set i 0} {$i < 200} {incr i} {
execsql { INSERT INTO t11 VALUES('') }
}
execsql { INSERT INTO t11(t11) VALUES('optimize') }
} {}
do_execsql_test 8.3 {
SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*'
} {{204 1 3 3 0} {204 1 3 3 0} {204 1 3 3 0}}
#-------------------------------------------------------------------------
breakpoint
do_execsql_test 8.1 {
CREATE VIRTUAL TABLE t12 USING fts5(content);
INSERT INTO t12 VALUES('a b c d');
SELECT mit(matchinfo(t12, 'x')) FROM t12 WHERE t12 MATCH 'NEAR(a d, 1) OR a';
} {{0 1 1 0 1 1 1 1 1}}
do_execsql_test 8.2 {
INSERT INTO t12 VALUES('a d c d');
SELECT mit(matchinfo(t12, 'x')) FROM t12 WHERE t12 MATCH 'NEAR(a d, 1) OR a';
} {
{0 2 2 0 3 2 1 2 2} {1 2 2 1 3 2 1 2 2}
}
do_execsql_test 8.3 {
INSERT INTO t12 VALUES('a d d a');
SELECT mit(matchinfo(t12, 'x')) FROM t12 WHERE t12 MATCH 'NEAR(a d, 1) OR a';
} {
{0 4 3 0 5 3 1 4 3} {1 4 3 1 5 3 1 4 3} {2 4 3 2 5 3 2 4 3}
}
#---------------------------------------------------------------------------
# Test for a memory leak
#
do_execsql_test 10.1 {
DROP TABLE t10;
CREATE VIRTUAL TABLE t10 USING fts5(idx, value);
INSERT INTO t10 values (1, 'one'),(2, 'two'),(3, 'three');
SELECT t10.rowid, t10.*
FROM t10
JOIN (SELECT 1 AS idx UNION SELECT 2 UNION SELECT 3) AS x
WHERE t10 MATCH x.idx
AND matchinfo(t10) not null
GROUP BY t10.rowid
ORDER BY 1;
} {1 1 one 2 2 two 3 3 three}
#---------------------------------------------------------------------------
# Test the 'y' matchinfo flag
#
set sqlite_fts3_enable_parentheses 1
reset_db
do_execsql_test 11.0 {
CREATE VIRTUAL TABLE tt USING fts3(x, y);
INSERT INTO tt VALUES('c d a c d d', 'e a g b d a'); -- 1
INSERT INTO tt VALUES('c c g a e b', 'c g d g e c'); -- 2
INSERT INTO tt VALUES('b e f d e g', 'b a c b c g'); -- 3
INSERT INTO tt VALUES('a c f f g d', 'd b f d e g'); -- 4
INSERT INTO tt VALUES('g a c f c f', 'd g g b c c'); -- 5
INSERT INTO tt VALUES('g a c e b b', 'd b f b g g'); -- 6
INSERT INTO tt VALUES('f d a a f c', 'e e a d c f'); -- 7
INSERT INTO tt VALUES('a c b b g f', 'a b a e d f'); -- 8
INSERT INTO tt VALUES('b a f e c c', 'f d b b a b'); -- 9
INSERT INTO tt VALUES('f d c e a c', 'f a f a a f'); -- 10
}
db func mit mit
foreach {tn expr res} {
1 "a" {
1 {1 2} 2 {1 0} 3 {0 1} 4 {1 0} 5 {1 0}
6 {1 0} 7 {2 1} 8 {1 2} 9 {1 1} 10 {1 3}
}
2 "b" {
1 {0 1} 2 {1 0} 3 {1 2} 4 {0 1} 5 {0 1}
6 {2 2} 8 {2 1} 9 {1 3}
}
3 "y:a" {
1 {0 2} 3 {0 1}
7 {0 1} 8 {0 2} 9 {0 1} 10 {0 3}
}
4 "x:a" {
1 {1 0} 2 {1 0} 4 {1 0} 5 {1 0}
6 {1 0} 7 {2 0} 8 {1 0} 9 {1 0} 10 {1 0}
}
5 "a OR b" {
1 {1 2 0 1} 2 {1 0 1 0} 3 {0 1 1 2} 4 {1 0 0 1} 5 {1 0 0 1}
6 {1 0 2 2} 7 {2 1 0 0} 8 {1 2 2 1} 9 {1 1 1 3} 10 {1 3 0 0}
}
6 "a AND b" {
1 {1 2 0 1} 2 {1 0 1 0} 3 {0 1 1 2} 4 {1 0 0 1} 5 {1 0 0 1}
6 {1 0 2 2} 8 {1 2 2 1} 9 {1 1 1 3}
}
7 "a OR (a AND b)" {
1 {1 2 1 2 0 1} 2 {1 0 1 0 1 0} 3 {0 1 0 1 1 2} 4 {1 0 1 0 0 1}
5 {1 0 1 0 0 1} 6 {1 0 1 0 2 2} 7 {2 1 0 0 0 0} 8 {1 2 1 2 2 1}
9 {1 1 1 1 1 3} 10 {1 3 0 0 0 0}
}
} {
do_execsql_test 11.1.$tn.1 {
SELECT rowid, mit(matchinfo(tt, 'y')) FROM tt WHERE tt MATCH $expr
} $res
set r2 [list]
foreach {rowid L} $res {
lappend r2 $rowid
set M [list]
foreach {a b} $L {
lappend M [expr ($a ? 1 : 0) + ($b ? 2 : 0)]
}
lappend r2 $M
}
do_execsql_test 11.1.$tn.2 {
SELECT rowid, mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH $expr
} $r2
do_execsql_test 11.1.$tn.2 {
SELECT rowid, mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH $expr
} $r2
}
set sqlite_fts3_enable_parentheses 0
#---------------------------------------------------------------------------
# Test the 'b' matchinfo flag
#
set sqlite_fts3_enable_parentheses 1
reset_db
db func mit mit
do_test 12.0 {
set cols [list]
for {set i 0} {$i < 50} {incr i} { lappend cols "c$i" }
execsql "CREATE VIRTUAL TABLE tt USING fts3([join $cols ,])"
} {}
do_execsql_test 12.1 {
INSERT INTO tt (rowid, c4, c45) VALUES(1, 'abc', 'abc');
SELECT mit(matchinfo(tt, 'b')) FROM tt WHERE tt MATCH 'abc';
} [list [list [expr 1<<4] [expr 1<<(45-32)]]]
set sqlite_fts3_enable_parentheses 0
finish_test

View File

@ -1,5 +1,5 @@
C Update\sthe\sspellfix\svirtual\stable\sextension\sso\sthat\san\sexplicit\s"top\s=\s?"\sconstraint\sworks\seven\sif\sthere\sis\salso\sa\s"distance\s<\s?"\sor\s"distance\s<=\s?"\sconstraint. C Add\stests\sfor\sthe\smatchinfo-like\stest\sfunction.\sFix\sproblems\sfound\sin\stest\sand\sfts5\scode\sby\sdoing\sso.
D 2015-08-05T15:29:32.743 D 2015-08-05T19:35:59.318
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2fc9ca6bf5949d415801c007ed3004a4bdb7c380 F Makefile.in 2fc9ca6bf5949d415801c007ed3004a4bdb7c380
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -110,25 +110,25 @@ F ext/fts5/fts5Int.h 45f2ceb3c030f70e2cc4c199e9f700c2f2367f77
F ext/fts5/fts5_aux.c 044cb176a815f4388308738437f6e130aa384fb0 F ext/fts5/fts5_aux.c 044cb176a815f4388308738437f6e130aa384fb0
F ext/fts5/fts5_buffer.c 80f9ba4431848cb857e3d2158f5280093dcd8015 F ext/fts5/fts5_buffer.c 80f9ba4431848cb857e3d2158f5280093dcd8015
F ext/fts5/fts5_config.c fdfa63ae8e527ecfaa50f94063c610429cc887cf F ext/fts5/fts5_config.c fdfa63ae8e527ecfaa50f94063c610429cc887cf
F ext/fts5/fts5_expr.c 31c175602c3f7ef8eb79e9af7059a6d88b6bb570 F ext/fts5/fts5_expr.c 495b24f47f4d71b63339572a5beaf9f6e1b486fe
F ext/fts5/fts5_hash.c 4bf4b99708848357b8a2b5819e509eb6d3df9246 F ext/fts5/fts5_hash.c 4bf4b99708848357b8a2b5819e509eb6d3df9246
F ext/fts5/fts5_index.c 67def0a6953c37aa5e5ce41040f4f4543654a681 F ext/fts5/fts5_index.c 28718af591ec59df0c3804cefdccd619b44a0e38
F ext/fts5/fts5_main.c dbf7a80c01a06e582107886e93de0a67bfc35d71 F ext/fts5/fts5_main.c 4c8af0015aaf1db2c81df4f617840a921360ef50
F ext/fts5/fts5_storage.c 22ec9b5d35a39e2b5b65daf4ba7cd47fbb2d0df5 F ext/fts5/fts5_storage.c 22ec9b5d35a39e2b5b65daf4ba7cd47fbb2d0df5
F ext/fts5/fts5_tcl.c fac2c0a30e708696bd5130324968eef9021c0235 F ext/fts5/fts5_tcl.c fac2c0a30e708696bd5130324968eef9021c0235
F ext/fts5/fts5_test_mi.c a11a5f262fb3e36f943ce008933528c88f1520ca F ext/fts5/fts5_test_mi.c f27e865f492b96a115bc37b3e2d149ab9a1c05be
F ext/fts5/fts5_tokenize.c 2836f6728bd74c7efac7487f5d9c27ca3e1b509c F ext/fts5/fts5_tokenize.c 2836f6728bd74c7efac7487f5d9c27ca3e1b509c
F ext/fts5/fts5_unicode2.c 78273fbd588d1d9bd0a7e4e0ccc9207348bae33c F ext/fts5/fts5_unicode2.c 78273fbd588d1d9bd0a7e4e0ccc9207348bae33c
F ext/fts5/fts5_varint.c 3f86ce09cab152e3d45490d7586b7ed2e40c13f1 F ext/fts5/fts5_varint.c 3f86ce09cab152e3d45490d7586b7ed2e40c13f1
F ext/fts5/fts5_vocab.c 4622e0b7d84a488a1585aaa56eb214ee67a988bc F ext/fts5/fts5_vocab.c 4622e0b7d84a488a1585aaa56eb214ee67a988bc
F ext/fts5/fts5parse.y 833db1101b78c0c47686ab1b84918e38c36e9452 F ext/fts5/fts5parse.y 833db1101b78c0c47686ab1b84918e38c36e9452
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
F ext/fts5/test/fts5_common.tcl e0b4a846a7670f6232a644ece69ef25a5c19c0e8 F ext/fts5/test/fts5_common.tcl 3338968de1880ca12b0451ae8f9b8b12d14e0ba7
F ext/fts5/test/fts5aa.test c6e680a0d1b6c2616a382f1006d5d91eca697bd0 F ext/fts5/test/fts5aa.test c6e680a0d1b6c2616a382f1006d5d91eca697bd0
F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad
F ext/fts5/test/fts5ac.test 9737992d08c56bfd4803e933744d2d764e23795c F ext/fts5/test/fts5ac.test 9737992d08c56bfd4803e933744d2d764e23795c
F ext/fts5/test/fts5ad.test b2edee8b7de0c21d2c88f8a18c195034aad6952d F ext/fts5/test/fts5ad.test b2edee8b7de0c21d2c88f8a18c195034aad6952d
F ext/fts5/test/fts5ae.test ddc558e3e3b52db0101f7541b2e3849b77052c92 F ext/fts5/test/fts5ae.test 0a9984fc3479f89f8c63d9848d6ed0c465dfcebe
F ext/fts5/test/fts5af.test c2501ec2b61d6b179c305f5d2b8782ab3d4f832a F ext/fts5/test/fts5af.test c2501ec2b61d6b179c305f5d2b8782ab3d4f832a
F ext/fts5/test/fts5ag.test ec3e119b728196620a31507ef503c455a7a73505 F ext/fts5/test/fts5ag.test ec3e119b728196620a31507ef503c455a7a73505
F ext/fts5/test/fts5ah.test b9e78fa986a7bd564ebadfb244de02c84d7ac3ae F ext/fts5/test/fts5ah.test b9e78fa986a7bd564ebadfb244de02c84d7ac3ae
@ -160,6 +160,7 @@ F ext/fts5/test/fts5fault6.test 234dc6355f8d3f8b5be2763f30699d770247c215
F ext/fts5/test/fts5full.test 6f6143af0c6700501d9fd597189dfab1555bb741 F ext/fts5/test/fts5full.test 6f6143af0c6700501d9fd597189dfab1555bb741
F ext/fts5/test/fts5hash.test 42eb066f667e9a389a63437cb7038c51974d4fc6 F ext/fts5/test/fts5hash.test 42eb066f667e9a389a63437cb7038c51974d4fc6
F ext/fts5/test/fts5integrity.test 29f41d2c7126c6122fbb5d54e556506456876145 F ext/fts5/test/fts5integrity.test 29f41d2c7126c6122fbb5d54e556506456876145
F ext/fts5/test/fts5matchinfo.test a2527a254a6e776bd3f6de9cea272553cd75c463
F ext/fts5/test/fts5merge.test 8f3cdba2ec9c5e7e568246e81b700ad37f764367 F ext/fts5/test/fts5merge.test 8f3cdba2ec9c5e7e568246e81b700ad37f764367
F ext/fts5/test/fts5near.test b214cddb1c1f1bddf45c75af768f20145f7e71cc F ext/fts5/test/fts5near.test b214cddb1c1f1bddf45c75af768f20145f7e71cc
F ext/fts5/test/fts5optimize.test 42741e7c085ee0a1276140a752d4407d97c2c9f5 F ext/fts5/test/fts5optimize.test 42741e7c085ee0a1276140a752d4407d97c2c9f5
@ -1369,7 +1370,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P c9ff4ca4a0b44bbb8d6676144ddf77b04426e619 P 0888838371608558f31d5bcb5fed1c8861aa52c1
R 180a25ce6d192ff71ad9fad98491dc51 R b837a8fea4ed8bb39bab13a658342231
U dan U dan
Z 9568c0ed64c13f8590f8982853b1718d Z 2863536f4e3d0af66e750ac913251784

View File

@ -1 +1 @@
0888838371608558f31d5bcb5fed1c8861aa52c1 9e3aafe44a0813aa2a0c6172fdba1440b8a973ec