Index: src/fts5.c ================================================================== --- src/fts5.c +++ src/fts5.c @@ -2264,10 +2264,11 @@ sqlite4DbFree(db, pCsr->aMem[i].zMalloc); } sqlite4DbFree(db, pCsr->aMem); } + sqlite4KVCursorClose(pCsr->pCsr); fts5ExpressionFree(db, pCsr->pExpr); sqlite4DbFree(db, pCsr->pIter); sqlite4DbFree(db, pCsr->aKey); sqlite4DbFree(db, pCsr->anRow); sqlite4DbFree(db, pCsr); @@ -2685,10 +2686,25 @@ }else{ rc = SQLITE4_MISUSE; } return rc; } + +int sqlite4_mi_phrase_token_count(sqlite4_context *pCtx, int iP, int *pn){ + int rc = SQLITE4_OK; + if( pCtx->pFts ){ + Fts5Expr *pExpr = pCtx->pFts->pExpr; + if( iP>pExpr->nPhrase || iP<0 ){ + *pn = 0; + }else{ + *pn = pExpr->apPhrase[iP]->nToken; + } + }else{ + rc = SQLITE4_MISUSE; + } + return rc; +} int sqlite4_mi_stream_count(sqlite4_context *pCtx, int *pn){ int rc = SQLITE4_OK; Fts5Cursor *pCsr = pCtx->pFts; if( pCsr ){ @@ -3062,10 +3078,47 @@ pIter->iCurrent = -1; }else{ pIter->iCurrent = pBest - pIter->aList; } } + +static void fts5InitExprIterator( + const u8 *aPk, + int nPk, + Fts5ExprNode *p, + Fts5MatchIter *pIter +){ + if( p ){ + if( p->eType==TOKEN_PRIMITIVE ){ + if( p->nPk==nPk && 0==memcmp(aPk, p->aPk, nPk) ){ + int i; + for(i=0; ipPhrase->nStr; i++){ + Fts5Str *pStr = &p->pPhrase->aStr[i]; + InstanceList *pList = &pIter->aList[pIter->iCurrent++]; + fts5InstanceListInit(pStr->aList, pStr->nList, pList); + fts5InstanceListNext(pList); + } + }else{ + memset(&pIter->aList[pIter->iCurrent], 0, sizeof(InstanceList)); + pIter->iCurrent += p->pPhrase->nStr; + } + } + fts5InitExprIterator(aPk, nPk, p->pLeft, pIter); + fts5InitExprIterator(aPk, nPk, p->pRight, pIter); + } +} + +static void fts5InitIterator(Fts5Cursor *pCsr){ + Fts5MatchIter *pIter = pCsr->pIter; + Fts5ExprNode *pRoot = pCsr->pExpr->pRoot; + + pIter->iCurrent = 0; + fts5InitExprIterator(pRoot->aPk, pRoot->nPk, pRoot, pIter); + pIter->iMatch = 0; + pIter->bValid = 1; + fts5IterSetCurrent(pIter, pCsr->pExpr->nPhrase); +} int sqlite4_mi_match_detail( sqlite4_context *pCtx, /* Context object passed to mi function */ int iMatch, /* Index of match */ int *piOff, /* OUT: Token offset of match */ @@ -3090,19 +3143,21 @@ rc = SQLITE4_NOMEM; } } if( rc==SQLITE4_OK && (pIter->bValid==0 || iMatchiMatch) ){ + fts5InitIterator(pCsr); +#if 0 int i; for(i=0; ipExpr->nPhrase; i++){ Fts5Str *pStr = pCsr->pExpr->apPhrase[i]; fts5InstanceListInit(pStr->aList, pStr->nList, &pIter->aList[i]); fts5InstanceListNext(&pIter->aList[i]); } - pIter->iMatch = 0; fts5IterSetCurrent(pIter, pCsr->pExpr->nPhrase); +#endif } if( rc==SQLITE4_OK ){ assert( pIter->iMatch<=iMatch ); while( pIter->iCurrent>=0 && pIter->iMatch=0 && iColumn!=iCol ) continue; allmask |= (1 << iPhrase); @@ -338,11 +341,14 @@ aMask[iMask] = aMask[iMask] >> nShift; }else{ aMask[iMask] = 0; } } - aMask[iPhrase] = aMask[iPhrase] | (1<<(nToken-1)); + sqlite4_mi_phrase_token_count(pCtx, iPhrase, &nPTok); + for(iPTok=0; iPTok