mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
If a token within an FTS query is prefixed with a '^' character, it must be the first token in a column of data to match.
FossilOrigin-Name: 63ac33c860eb32ce96699f06bf83121cec2ffaca
This commit is contained in:
@ -2347,6 +2347,67 @@ static void fts3DoclistPhraseMerge(
|
||||
*pnRight = p - aOut;
|
||||
}
|
||||
|
||||
/*
|
||||
** When this function is called, pList points to a doclist containing position
|
||||
** data, length *pnList bytes. This removes all entries from the doclist that
|
||||
** do not correspond to the first token in a column and overwrites pList
|
||||
** with the result. *pnList is set to the length of the new doclist before
|
||||
** returning.
|
||||
**
|
||||
** If bDescDoclist is true, then both the input and output are in descending
|
||||
** order. Otherwise, ascending.
|
||||
*/
|
||||
static void fts3DoclistFirstFilter(
|
||||
int bDescDoclist, /* True if pList is a descending doclist */
|
||||
char *pList, /* Buffer containing doclist */
|
||||
int *pnList /* IN/OUT: Size of doclist */
|
||||
){
|
||||
char *p = pList;
|
||||
char *pOut = pList;
|
||||
char *pEnd = &pList[*pnList];
|
||||
|
||||
sqlite3_int64 iDoc;
|
||||
sqlite3_int64 iPrev;
|
||||
int bFirstOut = 0;
|
||||
|
||||
fts3GetDeltaVarint3(&p, pEnd, 0, &iDoc);
|
||||
while( p ){
|
||||
int bWritten = 0;
|
||||
if( *p!=0x01 ){
|
||||
if( *p==0x02 ){
|
||||
fts3PutDeltaVarint3(&pOut, bDescDoclist, &iPrev, &bFirstOut, iDoc);
|
||||
*pOut++ = 0x02;
|
||||
bWritten = 1;
|
||||
}
|
||||
fts3ColumnlistCopy(0, &p);
|
||||
}
|
||||
|
||||
while( *p==0x01 ){
|
||||
sqlite3_int64 iCol;
|
||||
p++;
|
||||
p += sqlite3Fts3GetVarint(p, &iCol);
|
||||
if( *p==0x02 ){
|
||||
if( bWritten==0 ){
|
||||
fts3PutDeltaVarint3(&pOut, bDescDoclist, &iPrev, &bFirstOut, iDoc);
|
||||
bWritten = 1;
|
||||
}
|
||||
pOut += sqlite3Fts3PutVarint(pOut, iCol);
|
||||
*pOut++ = 0x02;
|
||||
}
|
||||
fts3ColumnlistCopy(0, &p);
|
||||
}
|
||||
if( bWritten ){
|
||||
*pOut++ = 0x00;
|
||||
}
|
||||
|
||||
assert( *p==0x00 );
|
||||
p++;
|
||||
fts3GetDeltaVarint3(&p, pEnd, bDescDoclist, &iDoc);
|
||||
}
|
||||
|
||||
*pnList = (pOut - pList);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Merge all doclists in the TermSelect.aaOutput[] array into a single
|
||||
@ -3518,6 +3579,10 @@ static void fts3EvalPhraseMergeToken(
|
||||
){
|
||||
assert( iToken!=p->iDoclistToken );
|
||||
|
||||
if( p->aToken[iToken].bFirst ){
|
||||
fts3DoclistFirstFilter(pTab->bDescIdx, pList, &nList);
|
||||
}
|
||||
|
||||
if( pList==0 ){
|
||||
sqlite3_free(p->doclist.aAll);
|
||||
p->doclist.aAll = 0;
|
||||
@ -3721,6 +3786,7 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
|
||||
&& p->nToken==1
|
||||
&& pFirst->pSegcsr
|
||||
&& pFirst->pSegcsr->bLookup
|
||||
&& pFirst->bFirst==0
|
||||
){
|
||||
/* Use the incremental approach. */
|
||||
int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
|
||||
|
@ -310,6 +310,7 @@ struct Fts3PhraseToken {
|
||||
char *z; /* Text of the token */
|
||||
int n; /* Number of bytes in buffer z */
|
||||
int isPrefix; /* True if token ends with a "*" character */
|
||||
int bFirst; /* True if token must appear at position 0 */
|
||||
|
||||
/* Variables above this point are populated when the expression is
|
||||
** parsed (by code in fts3_expr.c). Below this point the variables are
|
||||
|
@ -180,9 +180,21 @@ static int getNextToken(
|
||||
pRet->pPhrase->aToken[0].isPrefix = 1;
|
||||
iEnd++;
|
||||
}
|
||||
if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){
|
||||
pParse->isNot = 1;
|
||||
|
||||
while( 1 ){
|
||||
if( !sqlite3_fts3_enable_parentheses
|
||||
&& iStart>0 && z[iStart-1]=='-'
|
||||
){
|
||||
pParse->isNot = 1;
|
||||
iStart--;
|
||||
}else if( iStart>0 && z[iStart-1]=='^' ){
|
||||
pRet->pPhrase->aToken[0].bFirst = 1;
|
||||
iStart--;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
nConsumed = iEnd;
|
||||
}
|
||||
@ -281,6 +293,7 @@ static int getNextString(
|
||||
|
||||
pToken->n = nByte;
|
||||
pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
|
||||
pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^');
|
||||
nToken = ii+1;
|
||||
}
|
||||
}
|
||||
|
@ -3117,6 +3117,7 @@ int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
|
||||
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
|
||||
Fts3PhraseToken *pPT = pDef->pToken;
|
||||
if( (pDef->iCol>=p->nColumn || pDef->iCol==i)
|
||||
&& (pPT->bFirst==0 || iPos==0)
|
||||
&& (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken))
|
||||
&& (0==memcmp(zToken, pPT->z, pPT->n))
|
||||
){
|
||||
|
Reference in New Issue
Block a user