mirror of https://github.com/sqlite/sqlite
Add new fts3 matchinfo option 'b'. Also optimize existing option 'y'.
FossilOrigin-Name: 2e7679a1df4020dc0166f5de8ffd664df18a3002
This commit is contained in:
commit
6ebf1eb2c4
|
@ -1675,7 +1675,7 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
|
|||
sqlite3Fts3ExprFree(pCsr->pExpr);
|
||||
sqlite3Fts3FreeDeferredTokens(pCsr);
|
||||
sqlite3_free(pCsr->aDoclist);
|
||||
sqlite3_free(pCsr->aMatchinfo);
|
||||
sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
|
||||
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
|
||||
sqlite3_free(pCsr);
|
||||
return SQLITE_OK;
|
||||
|
@ -3176,7 +3176,7 @@ static int fts3FilterMethod(
|
|||
/* In case the cursor has been used before, clear it now. */
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
sqlite3_free(pCsr->aDoclist);
|
||||
sqlite3_free(pCsr->aMatchinfo);
|
||||
sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
|
||||
sqlite3Fts3ExprFree(pCsr->pExpr);
|
||||
memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
|
||||
|
||||
|
|
|
@ -197,6 +197,8 @@ typedef struct Fts3DeferredToken Fts3DeferredToken;
|
|||
typedef struct Fts3SegReader Fts3SegReader;
|
||||
typedef struct Fts3MultiSegReader Fts3MultiSegReader;
|
||||
|
||||
typedef struct MatchinfoBuffer MatchinfoBuffer;
|
||||
|
||||
/*
|
||||
** A connection to a fulltext index is an instance of the following
|
||||
** structure. The xCreate and xConnect methods create an instance
|
||||
|
@ -306,9 +308,7 @@ struct Fts3Cursor {
|
|||
i64 iMinDocid; /* Minimum docid to return */
|
||||
i64 iMaxDocid; /* Maximum docid to return */
|
||||
int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
|
||||
u32 *aMatchinfo; /* Information about most recent match */
|
||||
int nMatchinfo; /* Number of elements in aMatchinfo[] */
|
||||
char *zMatchinfo; /* Matchinfo specification */
|
||||
MatchinfoBuffer *pMIBuffer; /* Buffer for matchinfo data */
|
||||
};
|
||||
|
||||
#define FTS3_EVAL_FILTER 0
|
||||
|
@ -428,7 +428,9 @@ struct Fts3Expr {
|
|||
u8 bStart; /* True if iDocid is valid */
|
||||
u8 bDeferred; /* True if this expression is entirely deferred */
|
||||
|
||||
u32 *aMI;
|
||||
/* The following are used by the fts3_snippet.c module. */
|
||||
int iPhrase; /* Index of this phrase in matchinfo() results */
|
||||
u32 *aMI; /* See above */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -564,6 +566,7 @@ void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
|
|||
const char *, const char *, int, int
|
||||
);
|
||||
void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
|
||||
void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p);
|
||||
|
||||
/* fts3_expr.c */
|
||||
int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int,
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define FTS3_MATCHINFO_LCS 's' /* nCol values */
|
||||
#define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */
|
||||
#define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */
|
||||
#define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */
|
||||
|
||||
/*
|
||||
** The default value for the second argument to matchinfo().
|
||||
|
@ -89,9 +90,22 @@ struct MatchInfo {
|
|||
int nCol; /* Number of columns in table */
|
||||
int nPhrase; /* Number of matchable phrases in query */
|
||||
sqlite3_int64 nDoc; /* Number of docs in database */
|
||||
char flag;
|
||||
u32 *aMatchinfo; /* Pre-allocated buffer */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of this structure is used to manage a pair of buffers, each
|
||||
** (nElem * sizeof(u32)) bytes in size. See the MatchinfoBuffer code below
|
||||
** for details.
|
||||
*/
|
||||
struct MatchinfoBuffer {
|
||||
u8 aRef[3];
|
||||
int nElem;
|
||||
int bGlobal; /* Set if global data is loaded */
|
||||
char *zMatchinfo;
|
||||
u32 aMatchinfo[0];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
|
@ -107,6 +121,97 @@ struct StrBuffer {
|
|||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
** Start of MatchinfoBuffer code.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Allocate a two-slot MatchinfoBuffer object.
|
||||
*/
|
||||
static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){
|
||||
MatchinfoBuffer *pRet;
|
||||
int nByte = sizeof(u32) * (2*nElem + 2) + sizeof(MatchinfoBuffer);
|
||||
int nStr = strlen(zMatchinfo);
|
||||
|
||||
pRet = sqlite3_malloc(nByte + nStr+1);
|
||||
if( pRet ){
|
||||
memset(pRet, 0, nByte);
|
||||
pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet;
|
||||
pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*(nElem+1);
|
||||
pRet->nElem = nElem;
|
||||
pRet->zMatchinfo = ((char*)pRet) + nByte;
|
||||
memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1);
|
||||
pRet->aRef[0] = 1;
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
|
||||
static void fts3MIBufferFree(void *p){
|
||||
MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]);
|
||||
|
||||
assert( (u32*)p==&pBuf->aMatchinfo[1]
|
||||
|| (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2]
|
||||
);
|
||||
if( (u32*)p==&pBuf->aMatchinfo[1] ){
|
||||
pBuf->aRef[1] = 0;
|
||||
}else{
|
||||
pBuf->aRef[2] = 0;
|
||||
}
|
||||
|
||||
if( pBuf->aRef[0]==0 && pBuf->aRef[1]==0 && pBuf->aRef[2]==0 ){
|
||||
sqlite3_free(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
|
||||
void (*xRet)(void*) = 0;
|
||||
u32 *aOut = 0;
|
||||
|
||||
if( p->aRef[1]==0 ){
|
||||
p->aRef[1] = 1;
|
||||
aOut = &p->aMatchinfo[1];
|
||||
xRet = fts3MIBufferFree;
|
||||
}
|
||||
else if( p->aRef[2]==0 ){
|
||||
p->aRef[2] = 1;
|
||||
aOut = &p->aMatchinfo[p->nElem+2];
|
||||
xRet = fts3MIBufferFree;
|
||||
}else{
|
||||
aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32));
|
||||
if( aOut ){
|
||||
xRet = sqlite3_free;
|
||||
if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32));
|
||||
}
|
||||
}
|
||||
|
||||
*paOut = aOut;
|
||||
return xRet;
|
||||
}
|
||||
|
||||
static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){
|
||||
p->bGlobal = 1;
|
||||
memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32));
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a MatchinfoBuffer object allocated using fts3MIBufferNew()
|
||||
*/
|
||||
void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){
|
||||
if( p ){
|
||||
assert( p->aRef[0]==1 );
|
||||
p->aRef[0] = 0;
|
||||
if( p->aRef[0]==0 && p->aRef[1]==0 && p->aRef[2]==0 ){
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** End of MatchinfoBuffer code.
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
** This function is used to help iterate through a position-list. A position
|
||||
** list is a list of unique integers, sorted from smallest to largest. Each
|
||||
|
@ -143,7 +248,7 @@ static int fts3ExprIterate2(
|
|||
void *pCtx /* Second argument to pass to callback */
|
||||
){
|
||||
int rc; /* Return code */
|
||||
int eType = pExpr->eType; /* Type of expression node pExpr */
|
||||
int eType = pExpr->eType; /* Type of expression node pExpr */
|
||||
|
||||
if( eType!=FTSQUERY_PHRASE ){
|
||||
assert( pExpr->pLeft && pExpr->pRight );
|
||||
|
@ -177,6 +282,7 @@ static int fts3ExprIterate(
|
|||
return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This is an fts3ExprIterate() callback used while loading the doclists
|
||||
** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
|
||||
|
@ -221,8 +327,7 @@ static int fts3ExprLoadDoclists(
|
|||
|
||||
static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
(*(int *)ctx)++;
|
||||
UNUSED_PARAMETER(pExpr);
|
||||
UNUSED_PARAMETER(iPhrase);
|
||||
pExpr->iPhrase = iPhrase;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
static int fts3ExprPhraseCount(Fts3Expr *pExpr){
|
||||
|
@ -443,7 +548,7 @@ static int fts3BestSnippet(
|
|||
sIter.nSnippet = nSnippet;
|
||||
sIter.nPhrase = nList;
|
||||
sIter.iCurrent = -1;
|
||||
rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
|
||||
rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
/* Set the *pmSeen output variable. */
|
||||
|
@ -744,6 +849,60 @@ static int fts3ColumnlistCount(char **ppCollist){
|
|||
return nEntry;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function gathers 'y' or 'b' data for a single phrase.
|
||||
*/
|
||||
static void fts3ExprLHits(
|
||||
Fts3Expr *pExpr, /* Phrase expression node */
|
||||
MatchInfo *p /* Matchinfo context */
|
||||
){
|
||||
Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab;
|
||||
int iStart;
|
||||
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||
char *pIter = pPhrase->doclist.pList;
|
||||
int iCol = 0;
|
||||
|
||||
assert( p->flag==FTS3_MATCHINFO_LHITS_BM || p->flag==FTS3_MATCHINFO_LHITS );
|
||||
if( p->flag==FTS3_MATCHINFO_LHITS ){
|
||||
iStart = pExpr->iPhrase * p->nCol;
|
||||
}else{
|
||||
iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
|
||||
}
|
||||
|
||||
while( 1 ){
|
||||
int nHit = fts3ColumnlistCount(&pIter);
|
||||
if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
|
||||
if( p->flag==FTS3_MATCHINFO_LHITS ){
|
||||
p->aMatchinfo[iStart + iCol] = (u32)nHit;
|
||||
}else if( nHit ){
|
||||
p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F));
|
||||
}
|
||||
}
|
||||
assert( *pIter==0x00 || *pIter==0x01 );
|
||||
if( *pIter!=0x01 ) break;
|
||||
pIter++;
|
||||
pIter += fts3GetVarint32(pIter, &iCol);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Gather the results for matchinfo directives 'y' and 'b'.
|
||||
*/
|
||||
static void fts3ExprLHitGather(
|
||||
Fts3Expr *pExpr,
|
||||
MatchInfo *p
|
||||
){
|
||||
assert( (pExpr->pLeft==0)==(pExpr->pRight==0) );
|
||||
if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){
|
||||
if( pExpr->pLeft ){
|
||||
fts3ExprLHitGather(pExpr->pLeft, p);
|
||||
fts3ExprLHitGather(pExpr->pRight, p);
|
||||
}else{
|
||||
fts3ExprLHits(pExpr, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** fts3ExprIterate() callback used to collect the "global" matchinfo stats
|
||||
** for a single query.
|
||||
|
@ -810,51 +969,6 @@ static int fts3ExprLocalHitsCb(
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** fts3ExprIterate() callback used to gather information for the matchinfo
|
||||
** directive 'y'.
|
||||
*/
|
||||
static int fts3ExprLHitsCb(
|
||||
Fts3Expr *pExpr, /* Phrase expression node */
|
||||
int iPhrase, /* Phrase number */
|
||||
void *pCtx /* Pointer to MatchInfo structure */
|
||||
){
|
||||
MatchInfo *p = (MatchInfo *)pCtx;
|
||||
Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
int iStart = iPhrase * p->nCol;
|
||||
Fts3Expr *pEof; /* Ancestor node already at EOF */
|
||||
|
||||
/* This must be a phrase */
|
||||
assert( pExpr->pPhrase );
|
||||
|
||||
/* Initialize all output integers to zero. */
|
||||
memset(&p->aMatchinfo[iStart], 0, sizeof(u32) * p->nCol);
|
||||
|
||||
/* Check if this or any parent node is at EOF. If so, then all output
|
||||
** values are zero. */
|
||||
for(pEof=pExpr; pEof && pEof->bEof==0; pEof=pEof->pParent);
|
||||
|
||||
if( pEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){
|
||||
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||
char *pIter = pPhrase->doclist.pList;
|
||||
int iCol = 0;
|
||||
|
||||
while( 1 ){
|
||||
int nHit = fts3ColumnlistCount(&pIter);
|
||||
if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
|
||||
p->aMatchinfo[iStart + iCol] = (u32)nHit;
|
||||
}
|
||||
assert( *pIter==0x00 || *pIter==0x01 );
|
||||
if( *pIter!=0x01 ) break;
|
||||
pIter++;
|
||||
pIter += fts3GetVarint32(pIter, &iCol);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fts3MatchinfoCheck(
|
||||
Fts3Table *pTab,
|
||||
char cArg,
|
||||
|
@ -868,6 +982,7 @@ static int fts3MatchinfoCheck(
|
|||
|| (cArg==FTS3_MATCHINFO_LCS)
|
||||
|| (cArg==FTS3_MATCHINFO_HITS)
|
||||
|| (cArg==FTS3_MATCHINFO_LHITS)
|
||||
|| (cArg==FTS3_MATCHINFO_LHITS_BM)
|
||||
){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -895,6 +1010,10 @@ static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
|
|||
nVal = pInfo->nCol * pInfo->nPhrase;
|
||||
break;
|
||||
|
||||
case FTS3_MATCHINFO_LHITS_BM:
|
||||
nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( cArg==FTS3_MATCHINFO_HITS );
|
||||
nVal = pInfo->nCol * pInfo->nPhrase * 3;
|
||||
|
@ -1089,7 +1208,7 @@ static int fts3MatchinfoValues(
|
|||
sqlite3_stmt *pSelect = 0;
|
||||
|
||||
for(i=0; rc==SQLITE_OK && zArg[i]; i++){
|
||||
|
||||
pInfo->flag = zArg[i];
|
||||
switch( zArg[i] ){
|
||||
case FTS3_MATCHINFO_NPHRASE:
|
||||
if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase;
|
||||
|
@ -1149,9 +1268,13 @@ static int fts3MatchinfoValues(
|
|||
}
|
||||
break;
|
||||
|
||||
case FTS3_MATCHINFO_LHITS:
|
||||
(void)fts3ExprIterate(pCsr->pExpr, fts3ExprLHitsCb, (void*)pInfo);
|
||||
case FTS3_MATCHINFO_LHITS_BM:
|
||||
case FTS3_MATCHINFO_LHITS: {
|
||||
int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32);
|
||||
memset(pInfo->aMatchinfo, 0, nZero);
|
||||
fts3ExprLHitGather(pCsr->pExpr, pInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
Fts3Expr *pExpr;
|
||||
|
@ -1184,7 +1307,8 @@ static int fts3MatchinfoValues(
|
|||
** Populate pCsr->aMatchinfo[] with data for the current row. The
|
||||
** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
|
||||
*/
|
||||
static int fts3GetMatchinfo(
|
||||
static void fts3GetMatchinfo(
|
||||
sqlite3_context *pCtx, /* Return results here */
|
||||
Fts3Cursor *pCsr, /* FTS3 Cursor object */
|
||||
const char *zArg /* Second argument to matchinfo() function */
|
||||
){
|
||||
|
@ -1193,6 +1317,9 @@ static int fts3GetMatchinfo(
|
|||
int rc = SQLITE_OK;
|
||||
int bGlobal = 0; /* Collect 'global' stats as well as local */
|
||||
|
||||
u32 *aOut = 0;
|
||||
void (*xDestroyOut)(void*) = 0;
|
||||
|
||||
memset(&sInfo, 0, sizeof(MatchInfo));
|
||||
sInfo.pCursor = pCsr;
|
||||
sInfo.nCol = pTab->nColumn;
|
||||
|
@ -1200,21 +1327,18 @@ static int fts3GetMatchinfo(
|
|||
/* If there is cached matchinfo() data, but the format string for the
|
||||
** cache does not match the format string for this request, discard
|
||||
** the cached data. */
|
||||
if( pCsr->zMatchinfo && strcmp(pCsr->zMatchinfo, zArg) ){
|
||||
assert( pCsr->aMatchinfo );
|
||||
sqlite3_free(pCsr->aMatchinfo);
|
||||
pCsr->zMatchinfo = 0;
|
||||
pCsr->aMatchinfo = 0;
|
||||
if( pCsr->pMIBuffer && strcmp(pCsr->pMIBuffer->zMatchinfo, zArg) ){
|
||||
sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
|
||||
pCsr->pMIBuffer = 0;
|
||||
}
|
||||
|
||||
/* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
|
||||
/* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the
|
||||
** matchinfo function has been called for this query. In this case
|
||||
** allocate the array used to accumulate the matchinfo data and
|
||||
** initialize those elements that are constant for every row.
|
||||
*/
|
||||
if( pCsr->aMatchinfo==0 ){
|
||||
if( pCsr->pMIBuffer==0 ){
|
||||
int nMatchinfo = 0; /* Number of u32 elements in match-info */
|
||||
int nArg; /* Bytes in zArg */
|
||||
int i; /* Used to iterate through zArg */
|
||||
|
||||
/* Determine the number of phrases in the query */
|
||||
|
@ -1223,30 +1347,46 @@ static int fts3GetMatchinfo(
|
|||
|
||||
/* Determine the number of integers in the buffer returned by this call. */
|
||||
for(i=0; zArg[i]; i++){
|
||||
char *zErr = 0;
|
||||
if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){
|
||||
sqlite3_result_error(pCtx, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
return;
|
||||
}
|
||||
nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]);
|
||||
}
|
||||
|
||||
/* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */
|
||||
nArg = (int)strlen(zArg);
|
||||
pCsr->aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo + nArg + 1);
|
||||
if( !pCsr->aMatchinfo ) return SQLITE_NOMEM;
|
||||
pCsr->pMIBuffer = fts3MIBufferNew(nMatchinfo, zArg);
|
||||
if( !pCsr->pMIBuffer ) rc = SQLITE_NOMEM;
|
||||
|
||||
pCsr->zMatchinfo = (char *)&pCsr->aMatchinfo[nMatchinfo];
|
||||
pCsr->nMatchinfo = nMatchinfo;
|
||||
memcpy(pCsr->zMatchinfo, zArg, nArg+1);
|
||||
memset(pCsr->aMatchinfo, 0, sizeof(u32)*nMatchinfo);
|
||||
pCsr->isMatchinfoNeeded = 1;
|
||||
bGlobal = 1;
|
||||
}
|
||||
|
||||
sInfo.aMatchinfo = pCsr->aMatchinfo;
|
||||
sInfo.nPhrase = pCsr->nPhrase;
|
||||
if( pCsr->isMatchinfoNeeded ){
|
||||
rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg);
|
||||
pCsr->isMatchinfoNeeded = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
xDestroyOut = fts3MIBufferAlloc(pCsr->pMIBuffer, &aOut);
|
||||
if( xDestroyOut==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
if( rc==SQLITE_OK ){
|
||||
sInfo.aMatchinfo = aOut;
|
||||
sInfo.nPhrase = pCsr->nPhrase;
|
||||
rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg);
|
||||
if( bGlobal ){
|
||||
fts3MIBufferSetGlobal(pCsr->pMIBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_result_error_code(pCtx, rc);
|
||||
if( xDestroyOut ) xDestroyOut(aOut);
|
||||
}else{
|
||||
int n = pCsr->pMIBuffer->nElem * sizeof(u32);
|
||||
sqlite3_result_blob(pCtx, aOut, n, xDestroyOut);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1452,7 +1592,7 @@ void sqlite3Fts3Offsets(
|
|||
*/
|
||||
sCtx.iCol = iCol;
|
||||
sCtx.iTerm = 0;
|
||||
(void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void *)&sCtx);
|
||||
(void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx);
|
||||
|
||||
/* Retreive the text stored in column iCol. If an SQL NULL is stored
|
||||
** in column iCol, jump immediately to the next iteration of the loop.
|
||||
|
@ -1544,19 +1684,9 @@ void sqlite3Fts3Matchinfo(
|
|||
const char *zArg /* Second arg to matchinfo() function */
|
||||
){
|
||||
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
|
||||
int rc;
|
||||
int i;
|
||||
const char *zFormat;
|
||||
|
||||
if( zArg ){
|
||||
for(i=0; zArg[i]; i++){
|
||||
char *zErr = 0;
|
||||
if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){
|
||||
sqlite3_result_error(pContext, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
zFormat = zArg;
|
||||
}else{
|
||||
zFormat = FTS3_MATCHINFO_DEFAULT;
|
||||
|
@ -1565,17 +1695,10 @@ void sqlite3Fts3Matchinfo(
|
|||
if( !pCsr->pExpr ){
|
||||
sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Retrieve matchinfo() data. */
|
||||
rc = fts3GetMatchinfo(pCsr, zFormat);
|
||||
sqlite3Fts3SegmentsClose(pTab);
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_result_error_code(pContext, rc);
|
||||
}else{
|
||||
int n = pCsr->nMatchinfo * sizeof(u32);
|
||||
sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
|
||||
/* Retrieve matchinfo() data. */
|
||||
fts3GetMatchinfo(pContext, pCsr, zFormat);
|
||||
sqlite3Fts3SegmentsClose(pTab);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
22
manifest
22
manifest
|
@ -1,5 +1,5 @@
|
|||
C Add\smissing\s"finish_test"\scommands\sto\sthe\send\sof\sthe\stwo\snew\stest\sscripts\nfor\ssqlite3_analyzer\sand\ssqldiff.
|
||||
D 2015-05-11T18:48:52.709
|
||||
C Add\snew\sfts3\smatchinfo\soption\s'b'.\sAlso\soptimize\sexisting\soption\s'y'.
|
||||
D 2015-05-11T19:01:18.521
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in edfc69769e613a6359c42c06ea1d42c3bece1736
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
|
@ -78,16 +78,16 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
|||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 2fb98467f4b670c8934cdd97d1ba3ffa7382764c
|
||||
F ext/fts3/fts3.c 341e9d9a3c7615bac8e815a8937d576265b22f78
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h 59ecaa2d7af0da44c70b6aeaebdcfc070d14abab
|
||||
F ext/fts3/fts3Int.h 142837a7544dff49121b67091a71c4f7a4546b0f
|
||||
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
|
||||
F ext/fts3/fts3_expr.c 71c063da9c2a4167fb54aec089dd5ef33a58c9cb
|
||||
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5
|
||||
F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009
|
||||
F ext/fts3/fts3_snippet.c 40a96ba78e90aba7d7d6d014a18049bb218060fd
|
||||
F ext/fts3/fts3_snippet.c b7aaa8698096b26e1c6eb563e317409323398142
|
||||
F ext/fts3/fts3_term.c 88c55a6fa1a51ab494e33dced0401a6c28791fd7
|
||||
F ext/fts3/fts3_test.c 8a3a78c4458b2d7c631fcf4b152a5cd656fa7038
|
||||
F ext/fts3/fts3_tokenize_vtab.c a27593ab19657166f6fa5ec073b678cc29a75860
|
||||
|
@ -594,11 +594,11 @@ F test/fts3fault2.test f953bb3cf903988172270a9a0aafd5a890b0f98f
|
|||
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
|
||||
F test/fts3join.test 53e66a0c21eb568580674a43b21c059acb26f499
|
||||
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
|
||||
F test/fts3matchinfo.test 3e5f5ac2e0a8ba42eafd4c685f803ca48b4c3a83
|
||||
F test/fts3matchinfo.test 07009313ad6c082f94d8c9c3228eb8940c93ac71
|
||||
F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905
|
||||
F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2
|
||||
F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce
|
||||
F test/fts3query.test c838b18f2b859e15fd31c64be3d79ef1556803ca
|
||||
F test/fts3query.test f33eb71a1fe1084ea585eeb7ee76b390729f5170
|
||||
F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
|
||||
F test/fts3shared.test 57e26a801f21027b7530da77db54286a6fe4997e
|
||||
F test/fts3snippet.test 63dbd687d5bf5191f1b8e6a0977aa9c1e28a7004
|
||||
|
@ -1258,7 +1258,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 85a4a46c3bb9fd8124969c9e975086c795113b7e
|
||||
R dbcd907b1272e0530a99c0695a45d6f7
|
||||
U drh
|
||||
Z 28eaa7fe5ab9618b47710962d47606de
|
||||
P 1d5e72b1c4e0350c492e12f102acc41e1777ef98 82e5a6e088c58815140ad36715ac11c96527cb25
|
||||
R 795248e8534b4aa5326a7558d85be223
|
||||
U dan
|
||||
Z ae2284b291e4689841953453008382e8
|
||||
|
|
|
@ -1 +1 @@
|
|||
1d5e72b1c4e0350c492e12f102acc41e1777ef98
|
||||
2e7679a1df4020dc0166f5de8ffd664df18a3002
|
|
@ -507,10 +507,49 @@ foreach {tn expr res} {
|
|||
}
|
||||
|
||||
} {
|
||||
do_execsql_test 11.1.$tn {
|
||||
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
|
||||
breakpoint
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -173,8 +173,8 @@ do_select_tests 5.4 -errorformat {
|
|||
4 "SELECT optimize(content) FROM t2 WHERE t2 MATCH 'history'" optimize
|
||||
}
|
||||
do_catchsql_test 5.5.1 {
|
||||
SELECT matchinfo(t2, 'abc') FROM t2 WHERE t2 MATCH 'history'
|
||||
} {1 {unrecognized matchinfo request: b}}
|
||||
SELECT matchinfo(t2, 'abcd') FROM t2 WHERE t2 MATCH 'history'
|
||||
} {1 {unrecognized matchinfo request: d}}
|
||||
|
||||
do_execsql_test 5.5 { DROP TABLE t2 }
|
||||
|
||||
|
|
Loading…
Reference in New Issue