mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
Fix another problem with fts3/4 auxiliary functions and NEAR expressions that consist entirely of deferred tokens.
FossilOrigin-Name: a8c91c132f6157b7e3649f57a799984b1d7f8a18fd434515c875617d4195db29
This commit is contained in:
@ -5765,6 +5765,21 @@ static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This is an sqlite3Fts3ExprIterate() callback. If the Fts3Expr.aMI[] array
|
||||
** has not yet been allocated, allocate and zero it. Otherwise, just zero
|
||||
** it.
|
||||
*/
|
||||
static int fts3AllocateMSI(Fts3Expr *pExpr, int iPhrase, void *pCtx){
|
||||
Fts3Table *pTab = (Fts3Table*)pCtx;
|
||||
if( pExpr->aMI==0 ){
|
||||
pExpr->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
|
||||
if( pExpr->aMI==0 ) return SQLITE_NOMEM;
|
||||
}
|
||||
memset(pExpr->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Expression pExpr must be of type FTSQUERY_PHRASE.
|
||||
**
|
||||
@ -5786,7 +5801,6 @@ static int fts3EvalGatherStats(
|
||||
if( pExpr->aMI==0 ){
|
||||
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
|
||||
Fts3Expr *pRoot; /* Root of NEAR expression */
|
||||
Fts3Expr *p; /* Iterator used for several purposes */
|
||||
|
||||
sqlite3_int64 iPrevId = pCsr->iPrevId;
|
||||
sqlite3_int64 iDocid;
|
||||
@ -5794,7 +5808,9 @@ static int fts3EvalGatherStats(
|
||||
|
||||
/* Find the root of the NEAR expression */
|
||||
pRoot = pExpr;
|
||||
while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){
|
||||
while( pRoot->pParent
|
||||
&& (pRoot->pParent->eType==FTSQUERY_NEAR || pRoot->bDeferred)
|
||||
){
|
||||
pRoot = pRoot->pParent;
|
||||
}
|
||||
iDocid = pRoot->iDocid;
|
||||
@ -5802,14 +5818,8 @@ static int fts3EvalGatherStats(
|
||||
assert( pRoot->bStart );
|
||||
|
||||
/* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */
|
||||
for(p=pRoot; p; p=p->pLeft){
|
||||
Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight);
|
||||
assert( pE->aMI==0 );
|
||||
pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
|
||||
if( !pE->aMI ) return SQLITE_NOMEM;
|
||||
memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
|
||||
}
|
||||
|
||||
rc = sqlite3Fts3ExprIterate(pRoot, fts3AllocateMSI, (void*)pTab);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
fts3EvalRestart(pCsr, pRoot, &rc);
|
||||
|
||||
while( pCsr->isEof==0 && rc==SQLITE_OK ){
|
||||
@ -5965,6 +5975,7 @@ int sqlite3Fts3EvalPhrasePoslist(
|
||||
u8 bTreeEof = 0;
|
||||
Fts3Expr *p; /* Used to iterate from pExpr to root */
|
||||
Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
|
||||
Fts3Expr *pRun; /* Closest non-deferred ancestor of pNear */
|
||||
int bMatch;
|
||||
|
||||
/* Check if this phrase descends from an OR expression node. If not,
|
||||
@ -5979,25 +5990,30 @@ int sqlite3Fts3EvalPhrasePoslist(
|
||||
if( p->bEof ) bTreeEof = 1;
|
||||
}
|
||||
if( bOr==0 ) return SQLITE_OK;
|
||||
pRun = pNear;
|
||||
while( pRun->bDeferred ){
|
||||
assert( pRun->pParent );
|
||||
pRun = pRun->pParent;
|
||||
}
|
||||
|
||||
/* This is the descendent of an OR node. In this case we cannot use
|
||||
** an incremental phrase. Load the entire doclist for the phrase
|
||||
** into memory in this case. */
|
||||
if( pPhrase->bIncr ){
|
||||
int bEofSave = pNear->bEof;
|
||||
fts3EvalRestart(pCsr, pNear, &rc);
|
||||
while( rc==SQLITE_OK && !pNear->bEof ){
|
||||
fts3EvalNextRow(pCsr, pNear, &rc);
|
||||
if( bEofSave==0 && pNear->iDocid==iDocid ) break;
|
||||
int bEofSave = pRun->bEof;
|
||||
fts3EvalRestart(pCsr, pRun, &rc);
|
||||
while( rc==SQLITE_OK && !pRun->bEof ){
|
||||
fts3EvalNextRow(pCsr, pRun, &rc);
|
||||
if( bEofSave==0 && pRun->iDocid==iDocid ) break;
|
||||
}
|
||||
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
|
||||
if( rc==SQLITE_OK && pNear->bEof!=bEofSave ){
|
||||
if( rc==SQLITE_OK && pRun->bEof!=bEofSave ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
}
|
||||
}
|
||||
if( bTreeEof ){
|
||||
while( rc==SQLITE_OK && !pNear->bEof && !pNear->bDeferred ){
|
||||
fts3EvalNextRow(pCsr, pNear, &rc);
|
||||
while( rc==SQLITE_OK && !pRun->bEof ){
|
||||
fts3EvalNextRow(pCsr, pRun, &rc);
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
@ -650,5 +650,7 @@ int sqlite3FtsUnicodeIsalnum(int);
|
||||
int sqlite3FtsUnicodeIsdiacritic(int);
|
||||
#endif
|
||||
|
||||
int sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*);
|
||||
|
||||
#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
|
||||
#endif /* _FTSINT_H */
|
||||
|
@ -41,7 +41,7 @@ typedef sqlite3_int64 i64;
|
||||
|
||||
|
||||
/*
|
||||
** Used as an fts3ExprIterate() context when loading phrase doclists to
|
||||
** Used as an sqlite3Fts3ExprIterate() context when loading phrase doclists to
|
||||
** Fts3Expr.aDoclist[]/nDoclist.
|
||||
*/
|
||||
typedef struct LoadDoclistCtx LoadDoclistCtx;
|
||||
@ -85,7 +85,7 @@ struct SnippetFragment {
|
||||
};
|
||||
|
||||
/*
|
||||
** This type is used as an fts3ExprIterate() context object while
|
||||
** This type is used as an sqlite3Fts3ExprIterate() context object while
|
||||
** accumulating the data returned by the matchinfo() function.
|
||||
*/
|
||||
typedef struct MatchInfo MatchInfo;
|
||||
@ -244,7 +244,7 @@ static void fts3GetDeltaPosition(char **pp, i64 *piPos){
|
||||
}
|
||||
|
||||
/*
|
||||
** Helper function for fts3ExprIterate() (see below).
|
||||
** Helper function for sqlite3Fts3ExprIterate() (see below).
|
||||
*/
|
||||
static int fts3ExprIterate2(
|
||||
Fts3Expr *pExpr, /* Expression to iterate phrases of */
|
||||
@ -278,7 +278,7 @@ static int fts3ExprIterate2(
|
||||
** Otherwise, SQLITE_OK is returned after a callback has been made for
|
||||
** all eligible phrase nodes.
|
||||
*/
|
||||
static int fts3ExprIterate(
|
||||
int sqlite3Fts3ExprIterate(
|
||||
Fts3Expr *pExpr, /* Expression to iterate phrases of */
|
||||
int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */
|
||||
void *pCtx /* Second argument to pass to callback */
|
||||
@ -287,10 +287,9 @@ 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
|
||||
** This is an sqlite3Fts3ExprIterate() callback used while loading the
|
||||
** doclists for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
|
||||
** fts3ExprLoadDoclists().
|
||||
*/
|
||||
static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
@ -322,9 +321,9 @@ static int fts3ExprLoadDoclists(
|
||||
int *pnToken /* OUT: Number of tokens in query */
|
||||
){
|
||||
int rc; /* Return Code */
|
||||
LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
|
||||
LoadDoclistCtx sCtx = {0,0,0}; /* Context for sqlite3Fts3ExprIterate() */
|
||||
sCtx.pCsr = pCsr;
|
||||
rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx);
|
||||
rc = sqlite3Fts3ExprIterate(pCsr->pExpr,fts3ExprLoadDoclistsCb,(void*)&sCtx);
|
||||
if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
|
||||
if( pnToken ) *pnToken = sCtx.nToken;
|
||||
return rc;
|
||||
@ -337,7 +336,7 @@ static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
}
|
||||
static int fts3ExprPhraseCount(Fts3Expr *pExpr){
|
||||
int nPhrase = 0;
|
||||
(void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
|
||||
(void)sqlite3Fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
|
||||
return nPhrase;
|
||||
}
|
||||
|
||||
@ -465,8 +464,9 @@ static void fts3SnippetDetails(
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is an fts3ExprIterate() callback used by fts3BestSnippet().
|
||||
** Each invocation populates an element of the SnippetIter.aPhrase[] array.
|
||||
** This function is an sqlite3Fts3ExprIterate() callback used by
|
||||
** fts3BestSnippet(). Each invocation populates an element of the
|
||||
** SnippetIter.aPhrase[] array.
|
||||
*/
|
||||
static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
SnippetIter *p = (SnippetIter *)ctx;
|
||||
@ -556,7 +556,9 @@ static int fts3BestSnippet(
|
||||
sIter.nSnippet = nSnippet;
|
||||
sIter.nPhrase = nList;
|
||||
sIter.iCurrent = -1;
|
||||
rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter);
|
||||
rc = sqlite3Fts3ExprIterate(
|
||||
pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
/* Set the *pmSeen output variable. */
|
||||
@ -917,10 +919,10 @@ static int fts3ExprLHitGather(
|
||||
}
|
||||
|
||||
/*
|
||||
** fts3ExprIterate() callback used to collect the "global" matchinfo stats
|
||||
** for a single query.
|
||||
** sqlite3Fts3ExprIterate() callback used to collect the "global" matchinfo
|
||||
** stats for a single query.
|
||||
**
|
||||
** fts3ExprIterate() callback to load the 'global' elements of a
|
||||
** sqlite3Fts3ExprIterate() callback to load the 'global' elements of a
|
||||
** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements
|
||||
** of the matchinfo array that are constant for all rows returned by the
|
||||
** current query.
|
||||
@ -955,7 +957,7 @@ static int fts3ExprGlobalHitsCb(
|
||||
}
|
||||
|
||||
/*
|
||||
** fts3ExprIterate() callback used to collect the "local" part of the
|
||||
** sqlite3Fts3ExprIterate() callback used to collect the "local" part of the
|
||||
** FTS3_MATCHINFO_HITS array. The local stats are those elements of the
|
||||
** array that are different for each row returned by the query.
|
||||
*/
|
||||
@ -1151,7 +1153,7 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
||||
**/
|
||||
aIter = sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase);
|
||||
if( !aIter ) return SQLITE_NOMEM;
|
||||
(void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
|
||||
(void)sqlite3Fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
|
||||
|
||||
for(i=0; i<pInfo->nPhrase; i++){
|
||||
LcsIterator *pIter = &aIter[i];
|
||||
@ -1328,11 +1330,11 @@ static int fts3MatchinfoValues(
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
|
||||
rc = sqlite3Fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
|
||||
sqlite3Fts3EvalTestDeferred(pCsr, &rc);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
(void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
|
||||
(void)sqlite3Fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1555,7 +1557,7 @@ struct TermOffsetCtx {
|
||||
};
|
||||
|
||||
/*
|
||||
** This function is an fts3ExprIterate() callback used by sqlite3Fts3Offsets().
|
||||
** This function is an sqlite3Fts3ExprIterate() callback used by sqlite3Fts3Offsets().
|
||||
*/
|
||||
static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
TermOffsetCtx *p = (TermOffsetCtx *)ctx;
|
||||
@ -1637,7 +1639,9 @@ void sqlite3Fts3Offsets(
|
||||
*/
|
||||
sCtx.iCol = iCol;
|
||||
sCtx.iTerm = 0;
|
||||
rc = fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx);
|
||||
rc = sqlite3Fts3ExprIterate(
|
||||
pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto offsets_out;
|
||||
|
||||
/* Retreive the text stored in column iCol. If an SQL NULL is stored
|
||||
|
Reference in New Issue
Block a user