| Index: third_party/sqlite/src/ext/fts3/fts3_snippet.c
|
| diff --git a/third_party/sqlite/src/ext/fts3/fts3_snippet.c b/third_party/sqlite/src/ext/fts3/fts3_snippet.c
|
| index 6b74535079209caeb91acf67d5a2669b0f36cc9a..aa8779fa61f22491ae1f357d697778e636aaac88 100644
|
| --- a/third_party/sqlite/src/ext/fts3/fts3_snippet.c
|
| +++ b/third_party/sqlite/src/ext/fts3/fts3_snippet.c
|
| @@ -11,9 +11,9 @@
|
| ******************************************************************************
|
| */
|
|
|
| +#include "fts3Int.h"
|
| #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
|
|
|
| -#include "fts3Int.h"
|
| #include <string.h>
|
| #include <assert.h>
|
|
|
| @@ -128,7 +128,7 @@ struct StrBuffer {
|
| */
|
| static void fts3GetDeltaPosition(char **pp, int *piPos){
|
| int iVal;
|
| - *pp += sqlite3Fts3GetVarint32(*pp, &iVal);
|
| + *pp += fts3GetVarint32(*pp, &iVal);
|
| *piPos += (iVal-2);
|
| }
|
|
|
| @@ -177,71 +177,19 @@ static int fts3ExprIterate(
|
| }
|
|
|
| /*
|
| -** The argument to this function is always a phrase node. Its doclist
|
| -** (Fts3Expr.aDoclist[]) and the doclists associated with all phrase nodes
|
| -** to the left of this one in the query tree have already been loaded.
|
| -**
|
| -** If this phrase node is part of a series of phrase nodes joined by
|
| -** NEAR operators (and is not the left-most of said series), then elements are
|
| -** removed from the phrases doclist consistent with the NEAR restriction. If
|
| -** required, elements may be removed from the doclists of phrases to the
|
| -** left of this one that are part of the same series of NEAR operator
|
| -** connected phrases.
|
| -**
|
| -** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
|
| -*/
|
| -static int fts3ExprNearTrim(Fts3Expr *pExpr){
|
| - int rc = SQLITE_OK;
|
| - Fts3Expr *pParent = pExpr->pParent;
|
| -
|
| - assert( pExpr->eType==FTSQUERY_PHRASE );
|
| - while( rc==SQLITE_OK
|
| - && pParent
|
| - && pParent->eType==FTSQUERY_NEAR
|
| - && pParent->pRight==pExpr
|
| - ){
|
| - /* This expression (pExpr) is the right-hand-side of a NEAR operator.
|
| - ** Find the expression to the left of the same operator.
|
| - */
|
| - int nNear = pParent->nNear;
|
| - Fts3Expr *pLeft = pParent->pLeft;
|
| -
|
| - if( pLeft->eType!=FTSQUERY_PHRASE ){
|
| - assert( pLeft->eType==FTSQUERY_NEAR );
|
| - assert( pLeft->pRight->eType==FTSQUERY_PHRASE );
|
| - pLeft = pLeft->pRight;
|
| - }
|
| -
|
| - rc = sqlite3Fts3ExprNearTrim(pLeft, pExpr, nNear);
|
| -
|
| - pExpr = pLeft;
|
| - pParent = pExpr->pParent;
|
| - }
|
| -
|
| - return rc;
|
| -}
|
| -
|
| -/*
|
| ** This is an fts3ExprIterate() 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){
|
| int rc = SQLITE_OK;
|
| + Fts3Phrase *pPhrase = pExpr->pPhrase;
|
| LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
|
|
|
| UNUSED_PARAMETER(iPhrase);
|
|
|
| p->nPhrase++;
|
| - p->nToken += pExpr->pPhrase->nToken;
|
| -
|
| - if( pExpr->isLoaded==0 ){
|
| - rc = sqlite3Fts3ExprLoadDoclist(p->pCsr, pExpr);
|
| - pExpr->isLoaded = 1;
|
| - if( rc==SQLITE_OK ){
|
| - rc = fts3ExprNearTrim(pExpr);
|
| - }
|
| - }
|
| + p->nToken += pPhrase->nToken;
|
|
|
| return rc;
|
| }
|
| @@ -412,23 +360,27 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
| SnippetIter *p = (SnippetIter *)ctx;
|
| SnippetPhrase *pPhrase = &p->aPhrase[iPhrase];
|
| char *pCsr;
|
| + int rc;
|
|
|
| pPhrase->nToken = pExpr->pPhrase->nToken;
|
| -
|
| - pCsr = sqlite3Fts3FindPositions(pExpr, p->pCsr->iPrevId, p->iCol);
|
| + rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr);
|
| + assert( rc==SQLITE_OK || pCsr==0 );
|
| if( pCsr ){
|
| int iFirst = 0;
|
| pPhrase->pList = pCsr;
|
| fts3GetDeltaPosition(&pCsr, &iFirst);
|
| + assert( iFirst>=0 );
|
| pPhrase->pHead = pCsr;
|
| pPhrase->pTail = pCsr;
|
| pPhrase->iHead = iFirst;
|
| pPhrase->iTail = iFirst;
|
| }else{
|
| - assert( pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 );
|
| + assert( rc!=SQLITE_OK || (
|
| + pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0
|
| + ));
|
| }
|
|
|
| - return SQLITE_OK;
|
| + return rc;
|
| }
|
|
|
| /*
|
| @@ -437,9 +389,9 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
| ** is the snippet with the highest score, where scores are calculated
|
| ** by adding:
|
| **
|
| -** (a) +1 point for each occurence of a matchable phrase in the snippet.
|
| +** (a) +1 point for each occurrence of a matchable phrase in the snippet.
|
| **
|
| -** (b) +1000 points for the first occurence of each matchable phrase in
|
| +** (b) +1000 points for the first occurrence of each matchable phrase in
|
| ** the snippet for which the corresponding mCovered bit is not set.
|
| **
|
| ** The selected snippet parameters are stored in structure *pFragment before
|
| @@ -552,6 +504,7 @@ static int fts3StringAppend(
|
| pStr->z = zNew;
|
| pStr->nAlloc = nAlloc;
|
| }
|
| + assert( pStr->z!=0 && (pStr->nAlloc >= pStr->n+nAppend+1) );
|
|
|
| /* Append the data to the string buffer. */
|
| memcpy(&pStr->z[pStr->n], zAppend, nAppend);
|
| @@ -583,6 +536,7 @@ static int fts3StringAppend(
|
| */
|
| static int fts3SnippetShift(
|
| Fts3Table *pTab, /* FTS3 table snippet comes from */
|
| + int iLangid, /* Language id to use in tokenizing */
|
| int nSnippet, /* Number of tokens desired for snippet */
|
| const char *zDoc, /* Document text to extract snippet from */
|
| int nDoc, /* Size of buffer zDoc in bytes */
|
| @@ -618,13 +572,12 @@ static int fts3SnippetShift(
|
| /* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired)
|
| ** or more tokens in zDoc/nDoc.
|
| */
|
| - rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
|
| + rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, iLangid, zDoc, nDoc, &pC);
|
| if( rc!=SQLITE_OK ){
|
| return rc;
|
| }
|
| - pC->pTokenizer = pTab->pTokenizer;
|
| while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){
|
| - const char *ZDUMMY; int DUMMY1, DUMMY2, DUMMY3;
|
| + const char *ZDUMMY; int DUMMY1 = 0, DUMMY2 = 0, DUMMY3 = 0;
|
| rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent);
|
| }
|
| pMod->xClose(pC);
|
| @@ -668,8 +621,6 @@ static int fts3SnippetText(
|
| int iCol = pFragment->iCol+1; /* Query column to extract text from */
|
| sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */
|
| sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */
|
| - const char *ZDUMMY; /* Dummy argument used with tokenizer */
|
| - int DUMMY1; /* Dummy argument used with tokenizer */
|
|
|
| zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol);
|
| if( zDoc==0 ){
|
| @@ -682,17 +633,29 @@ static int fts3SnippetText(
|
|
|
| /* Open a token cursor on the document. */
|
| pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
|
| - rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
|
| + rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, zDoc,nDoc,&pC);
|
| if( rc!=SQLITE_OK ){
|
| return rc;
|
| }
|
| - pC->pTokenizer = pTab->pTokenizer;
|
|
|
| while( rc==SQLITE_OK ){
|
| - int iBegin; /* Offset in zDoc of start of token */
|
| - int iFin; /* Offset in zDoc of end of token */
|
| - int isHighlight; /* True for highlighted terms */
|
| -
|
| + const char *ZDUMMY; /* Dummy argument used with tokenizer */
|
| + int DUMMY1 = -1; /* Dummy argument used with tokenizer */
|
| + int iBegin = 0; /* Offset in zDoc of start of token */
|
| + int iFin = 0; /* Offset in zDoc of end of token */
|
| + int isHighlight = 0; /* True for highlighted terms */
|
| +
|
| + /* Variable DUMMY1 is initialized to a negative value above. Elsewhere
|
| + ** in the FTS code the variable that the third argument to xNext points to
|
| + ** is initialized to zero before the first (*but not necessarily
|
| + ** subsequent*) call to xNext(). This is done for a particular application
|
| + ** that needs to know whether or not the tokenizer is being used for
|
| + ** snippet generation or for some other purpose.
|
| + **
|
| + ** Extreme care is required when writing code to depend on this
|
| + ** initialization. It is not a documented part of the tokenizer interface.
|
| + ** If a tokenizer is used directly by any code outside of FTS, this
|
| + ** convention might not be respected. */
|
| rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent);
|
| if( rc!=SQLITE_OK ){
|
| if( rc==SQLITE_DONE ){
|
| @@ -708,7 +671,9 @@ static int fts3SnippetText(
|
|
|
| if( !isShiftDone ){
|
| int n = nDoc - iBegin;
|
| - rc = fts3SnippetShift(pTab, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask);
|
| + rc = fts3SnippetShift(
|
| + pTab, pCsr->iLangid, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask
|
| + );
|
| isShiftDone = 1;
|
|
|
| /* Now that the shift has been done, check if the initial "..." are
|
| @@ -772,26 +737,6 @@ static int fts3ColumnlistCount(char **ppCollist){
|
| return nEntry;
|
| }
|
|
|
| -static void fts3LoadColumnlistCounts(char **pp, u32 *aOut, int isGlobal){
|
| - char *pCsr = *pp;
|
| - while( *pCsr ){
|
| - int nHit;
|
| - sqlite3_int64 iCol = 0;
|
| - if( *pCsr==0x01 ){
|
| - pCsr++;
|
| - pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
|
| - }
|
| - nHit = fts3ColumnlistCount(&pCsr);
|
| - assert( nHit>0 );
|
| - if( isGlobal ){
|
| - aOut[iCol*3+1]++;
|
| - }
|
| - aOut[iCol*3] += nHit;
|
| - }
|
| - pCsr++;
|
| - *pp = pCsr;
|
| -}
|
| -
|
| /*
|
| ** fts3ExprIterate() callback used to collect the "global" matchinfo stats
|
| ** for a single query.
|
| @@ -825,48 +770,9 @@ static int fts3ExprGlobalHitsCb(
|
| void *pCtx /* Pointer to MatchInfo structure */
|
| ){
|
| MatchInfo *p = (MatchInfo *)pCtx;
|
| - Fts3Cursor *pCsr = p->pCursor;
|
| - char *pIter;
|
| - char *pEnd;
|
| - char *pFree = 0;
|
| - u32 *aOut = &p->aMatchinfo[3*iPhrase*p->nCol];
|
| -
|
| - assert( pExpr->isLoaded );
|
| - assert( pExpr->eType==FTSQUERY_PHRASE );
|
| -
|
| - if( pCsr->pDeferred ){
|
| - Fts3Phrase *pPhrase = pExpr->pPhrase;
|
| - int ii;
|
| - for(ii=0; ii<pPhrase->nToken; ii++){
|
| - if( pPhrase->aToken[ii].bFulltext ) break;
|
| - }
|
| - if( ii<pPhrase->nToken ){
|
| - int nFree = 0;
|
| - int rc = sqlite3Fts3ExprLoadFtDoclist(pCsr, pExpr, &pFree, &nFree);
|
| - if( rc!=SQLITE_OK ) return rc;
|
| - pIter = pFree;
|
| - pEnd = &pFree[nFree];
|
| - }else{
|
| - int iCol; /* Column index */
|
| - for(iCol=0; iCol<p->nCol; iCol++){
|
| - aOut[iCol*3 + 1] = (u32)p->nDoc;
|
| - aOut[iCol*3 + 2] = (u32)p->nDoc;
|
| - }
|
| - return SQLITE_OK;
|
| - }
|
| - }else{
|
| - pIter = pExpr->aDoclist;
|
| - pEnd = &pExpr->aDoclist[pExpr->nDoclist];
|
| - }
|
| -
|
| - /* Fill in the global hit count matrix row for this phrase. */
|
| - while( pIter<pEnd ){
|
| - while( *pIter++ & 0x80 ); /* Skip past docid. */
|
| - fts3LoadColumnlistCounts(&pIter, &aOut[1], 1);
|
| - }
|
| -
|
| - sqlite3_free(pFree);
|
| - return SQLITE_OK;
|
| + return sqlite3Fts3EvalPhraseStats(
|
| + p->pCursor, pExpr, &p->aMatchinfo[3*iPhrase*p->nCol]
|
| + );
|
| }
|
|
|
| /*
|
| @@ -879,22 +785,22 @@ static int fts3ExprLocalHitsCb(
|
| int iPhrase, /* Phrase number */
|
| void *pCtx /* Pointer to MatchInfo structure */
|
| ){
|
| + int rc = SQLITE_OK;
|
| MatchInfo *p = (MatchInfo *)pCtx;
|
| int iStart = iPhrase * p->nCol * 3;
|
| int i;
|
|
|
| - for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
|
| -
|
| - if( pExpr->aDoclist ){
|
| + for(i=0; i<p->nCol && rc==SQLITE_OK; i++){
|
| char *pCsr;
|
| -
|
| - pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
|
| + rc = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i, &pCsr);
|
| if( pCsr ){
|
| - fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
|
| + p->aMatchinfo[iStart+i*3] = fts3ColumnlistCount(&pCsr);
|
| + }else{
|
| + p->aMatchinfo[iStart+i*3] = 0;
|
| }
|
| }
|
|
|
| - return SQLITE_OK;
|
| + return rc;
|
| }
|
|
|
| static int fts3MatchinfoCheck(
|
| @@ -904,8 +810,8 @@ static int fts3MatchinfoCheck(
|
| ){
|
| if( (cArg==FTS3_MATCHINFO_NPHRASE)
|
| || (cArg==FTS3_MATCHINFO_NCOL)
|
| - || (cArg==FTS3_MATCHINFO_NDOC && pTab->bHasStat)
|
| - || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bHasStat)
|
| + || (cArg==FTS3_MATCHINFO_NDOC && pTab->bFts4)
|
| + || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bFts4)
|
| || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize)
|
| || (cArg==FTS3_MATCHINFO_LCS)
|
| || (cArg==FTS3_MATCHINFO_HITS)
|
| @@ -960,7 +866,7 @@ static int fts3MatchinfoSelectDoctotal(
|
|
|
| a = sqlite3_column_blob(pStmt, 0);
|
| a += sqlite3Fts3GetVarint(a, &nDoc);
|
| - if( nDoc==0 ) return SQLITE_CORRUPT;
|
| + if( nDoc==0 ) return FTS_CORRUPT_VTAB;
|
| *pnDoc = (u32)nDoc;
|
|
|
| if( paLen ) *paLen = a;
|
| @@ -976,9 +882,8 @@ static int fts3MatchinfoSelectDoctotal(
|
| typedef struct LcsIterator LcsIterator;
|
| struct LcsIterator {
|
| Fts3Expr *pExpr; /* Pointer to phrase expression */
|
| - char *pRead; /* Cursor used to iterate through aDoclist */
|
| int iPosOffset; /* Tokens count up to end of this phrase */
|
| - int iCol; /* Current column number */
|
| + char *pRead; /* Cursor used to iterate through aDoclist */
|
| int iPos; /* Current position */
|
| };
|
|
|
| @@ -1009,17 +914,10 @@ static int fts3LcsIteratorAdvance(LcsIterator *pIter){
|
| int rc = 0;
|
|
|
| pRead += sqlite3Fts3GetVarint(pRead, &iRead);
|
| - if( iRead==0 ){
|
| - pIter->iCol = LCS_ITERATOR_FINISHED;
|
| + if( iRead==0 || iRead==1 ){
|
| + pRead = 0;
|
| rc = 1;
|
| }else{
|
| - if( iRead==1 ){
|
| - pRead += sqlite3Fts3GetVarint(pRead, &iRead);
|
| - pIter->iCol = (int)iRead;
|
| - pIter->iPos = pIter->iPosOffset;
|
| - pRead += sqlite3Fts3GetVarint(pRead, &iRead);
|
| - rc = 1;
|
| - }
|
| pIter->iPos += (int)(iRead-2);
|
| }
|
|
|
| @@ -1051,42 +949,36 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
| if( !aIter ) return SQLITE_NOMEM;
|
| memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
|
| (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
|
| +
|
| for(i=0; i<pInfo->nPhrase; i++){
|
| LcsIterator *pIter = &aIter[i];
|
| nToken -= pIter->pExpr->pPhrase->nToken;
|
| pIter->iPosOffset = nToken;
|
| - pIter->pRead = sqlite3Fts3FindPositions(pIter->pExpr, pCsr->iPrevId, -1);
|
| - if( pIter->pRead ){
|
| - pIter->iPos = pIter->iPosOffset;
|
| - fts3LcsIteratorAdvance(&aIter[i]);
|
| - }else{
|
| - pIter->iCol = LCS_ITERATOR_FINISHED;
|
| - }
|
| }
|
|
|
| for(iCol=0; iCol<pInfo->nCol; iCol++){
|
| int nLcs = 0; /* LCS value for this column */
|
| int nLive = 0; /* Number of iterators in aIter not at EOF */
|
|
|
| - /* Loop through the iterators in aIter[]. Set nLive to the number of
|
| - ** iterators that point to a position-list corresponding to column iCol.
|
| - */
|
| for(i=0; i<pInfo->nPhrase; i++){
|
| - assert( aIter[i].iCol>=iCol );
|
| - if( aIter[i].iCol==iCol ) nLive++;
|
| + int rc;
|
| + LcsIterator *pIt = &aIter[i];
|
| + rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead);
|
| + if( rc!=SQLITE_OK ) return rc;
|
| + if( pIt->pRead ){
|
| + pIt->iPos = pIt->iPosOffset;
|
| + fts3LcsIteratorAdvance(&aIter[i]);
|
| + nLive++;
|
| + }
|
| }
|
|
|
| - /* The following loop runs until all iterators in aIter[] have finished
|
| - ** iterating through positions in column iCol. Exactly one of the
|
| - ** iterators is advanced each time the body of the loop is run.
|
| - */
|
| while( nLive>0 ){
|
| LcsIterator *pAdv = 0; /* The iterator to advance by one position */
|
| int nThisLcs = 0; /* LCS for the current iterator positions */
|
|
|
| for(i=0; i<pInfo->nPhrase; i++){
|
| LcsIterator *pIter = &aIter[i];
|
| - if( iCol!=pIter->iCol ){
|
| + if( pIter->pRead==0 ){
|
| /* This iterator is already at EOF for this column. */
|
| nThisLcs = 0;
|
| }else{
|
| @@ -1152,7 +1044,7 @@ static int fts3MatchinfoValues(
|
|
|
| case FTS3_MATCHINFO_NDOC:
|
| if( bGlobal ){
|
| - sqlite3_int64 nDoc;
|
| + sqlite3_int64 nDoc = 0;
|
| rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
|
| pInfo->aMatchinfo[0] = (u32)nDoc;
|
| }
|
| @@ -1408,6 +1300,7 @@ struct TermOffset {
|
| };
|
|
|
| struct TermOffsetCtx {
|
| + Fts3Cursor *pCsr;
|
| int iCol; /* Column of table to populate aTerm for */
|
| int iTerm;
|
| sqlite3_int64 iDocid;
|
| @@ -1423,9 +1316,10 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
| int iTerm; /* For looping through nTerm phrase terms */
|
| char *pList; /* Pointer to position list for phrase */
|
| int iPos = 0; /* First position in position-list */
|
| + int rc;
|
|
|
| UNUSED_PARAMETER(iPhrase);
|
| - pList = sqlite3Fts3FindPositions(pExpr, p->iDocid, p->iCol);
|
| + rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pList);
|
| nTerm = pExpr->pPhrase->nToken;
|
| if( pList ){
|
| fts3GetDeltaPosition(&pList, &iPos);
|
| @@ -1439,7 +1333,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
| pT->iPos = iPos;
|
| }
|
|
|
| - return SQLITE_OK;
|
| + return rc;
|
| }
|
|
|
| /*
|
| @@ -1451,8 +1345,6 @@ void sqlite3Fts3Offsets(
|
| ){
|
| Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
|
| sqlite3_tokenizer_module const *pMod = pTab->pTokenizer->pModule;
|
| - const char *ZDUMMY; /* Dummy argument used with xNext() */
|
| - int NDUMMY; /* Dummy argument used with xNext() */
|
| int rc; /* Return Code */
|
| int nToken; /* Number of tokens in query */
|
| int iCol; /* Column currently being processed */
|
| @@ -1478,15 +1370,18 @@ void sqlite3Fts3Offsets(
|
| goto offsets_out;
|
| }
|
| sCtx.iDocid = pCsr->iPrevId;
|
| + sCtx.pCsr = pCsr;
|
|
|
| /* Loop through the table columns, appending offset information to
|
| ** string-buffer res for each column.
|
| */
|
| for(iCol=0; iCol<pTab->nColumn; iCol++){
|
| sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */
|
| - int iStart;
|
| - int iEnd;
|
| - int iCurrent;
|
| + const char *ZDUMMY; /* Dummy argument used with xNext() */
|
| + int NDUMMY = 0; /* Dummy argument used with xNext() */
|
| + int iStart = 0;
|
| + int iEnd = 0;
|
| + int iCurrent = 0;
|
| const char *zDoc;
|
| int nDoc;
|
|
|
| @@ -1515,9 +1410,10 @@ void sqlite3Fts3Offsets(
|
| }
|
|
|
| /* Initialize a tokenizer iterator to iterate through column iCol. */
|
| - rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
|
| + rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid,
|
| + zDoc, nDoc, &pC
|
| + );
|
| if( rc!=SQLITE_OK ) goto offsets_out;
|
| - pC->pTokenizer = pTab->pTokenizer;
|
|
|
| rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent);
|
| while( rc==SQLITE_OK ){
|
| @@ -1535,7 +1431,7 @@ void sqlite3Fts3Offsets(
|
|
|
| if( !pTerm ){
|
| /* All offsets for this column have been gathered. */
|
| - break;
|
| + rc = SQLITE_DONE;
|
| }else{
|
| assert( iCurrent<=iMinPos );
|
| if( 0==(0xFE&*pTerm->pList) ){
|
| @@ -1552,8 +1448,8 @@ void sqlite3Fts3Offsets(
|
| "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart
|
| );
|
| rc = fts3StringAppend(&res, aBuffer, -1);
|
| - }else if( rc==SQLITE_DONE ){
|
| - rc = SQLITE_CORRUPT;
|
| + }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){
|
| + rc = FTS_CORRUPT_VTAB;
|
| }
|
| }
|
| }
|
|
|