mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Minor changes made while planning a larger change.
FossilOrigin-Name: 84097a4c759b1d65890af885f137d3cb16eef584
This commit is contained in:
@ -2767,11 +2767,13 @@ static int fts3NearMerge(
|
|||||||
** each doclist that are not within nNear tokens of a corresponding entry
|
** each doclist that are not within nNear tokens of a corresponding entry
|
||||||
** in the other doclist.
|
** in the other doclist.
|
||||||
*/
|
*/
|
||||||
int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
|
int sqlite3Fts3ExprNearTrim(Fts3Expr *pELeft, Fts3Expr *pERight, int nNear){
|
||||||
int rc; /* Return code */
|
int rc; /* Return code */
|
||||||
|
Fts3Phrase *pLeft = pELeft->pPhrase;
|
||||||
|
Fts3Phrase *pRight = pERight->pPhrase;
|
||||||
|
|
||||||
assert( pLeft->eType==FTSQUERY_PHRASE );
|
assert( pELeft->eType==FTSQUERY_PHRASE && pLeft );
|
||||||
assert( pRight->eType==FTSQUERY_PHRASE );
|
assert( pERight->eType==FTSQUERY_PHRASE && pRight );
|
||||||
assert( pLeft->isLoaded && pRight->isLoaded );
|
assert( pLeft->isLoaded && pRight->isLoaded );
|
||||||
|
|
||||||
if( pLeft->aDoclist==0 || pRight->aDoclist==0 ){
|
if( pLeft->aDoclist==0 || pRight->aDoclist==0 ){
|
||||||
@ -2785,8 +2787,8 @@ int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
|
|||||||
int nOut; /* Size of buffer aOut in bytes */
|
int nOut; /* Size of buffer aOut in bytes */
|
||||||
|
|
||||||
rc = fts3NearMerge(MERGE_POS_NEAR, nNear,
|
rc = fts3NearMerge(MERGE_POS_NEAR, nNear,
|
||||||
pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
|
pLeft->nToken, pLeft->aDoclist, pLeft->nDoclist,
|
||||||
pRight->pPhrase->nToken, pRight->aDoclist, pRight->nDoclist,
|
pRight->nToken, pRight->aDoclist, pRight->nDoclist,
|
||||||
&aOut, &nOut
|
&aOut, &nOut
|
||||||
);
|
);
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
@ -2795,8 +2797,8 @@ int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
|
|||||||
pRight->nDoclist = nOut;
|
pRight->nDoclist = nOut;
|
||||||
|
|
||||||
rc = fts3NearMerge(MERGE_POS_NEAR, nNear,
|
rc = fts3NearMerge(MERGE_POS_NEAR, nNear,
|
||||||
pRight->pPhrase->nToken, pRight->aDoclist, pRight->nDoclist,
|
pRight->nToken, pRight->aDoclist, pRight->nDoclist,
|
||||||
pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
|
pLeft->nToken, pLeft->aDoclist, pLeft->nDoclist,
|
||||||
&aOut, &nOut
|
&aOut, &nOut
|
||||||
);
|
);
|
||||||
sqlite3_free(pLeft->aDoclist);
|
sqlite3_free(pLeft->aDoclist);
|
||||||
@ -3459,12 +3461,19 @@ static int fts3RollbackMethod(sqlite3_vtab *pVtab){
|
|||||||
*/
|
*/
|
||||||
int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *pCsr, Fts3Expr *pExpr){
|
int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *pCsr, Fts3Expr *pExpr){
|
||||||
int rc;
|
int rc;
|
||||||
assert( pExpr->eType==FTSQUERY_PHRASE && pExpr->pPhrase );
|
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||||
|
assert( pExpr->eType==FTSQUERY_PHRASE && pPhrase );
|
||||||
assert( pCsr->eEvalmode==FTS3_EVAL_NEXT );
|
assert( pCsr->eEvalmode==FTS3_EVAL_NEXT );
|
||||||
rc = fts3EvalExpr(pCsr, pExpr, &pExpr->aDoclist, &pExpr->nDoclist, 1);
|
rc = fts3EvalExpr(pCsr, pExpr, &pPhrase->aDoclist, &pPhrase->nDoclist, 1);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** TODO: This is something to do with matchinfo(). Similar to
|
||||||
|
** sqlite3ExprLoadDoclists() but slightly different.
|
||||||
|
**
|
||||||
|
** UPDATE: Only used when there are deferred tokens.
|
||||||
|
*/
|
||||||
int sqlite3Fts3ExprLoadFtDoclist(
|
int sqlite3Fts3ExprLoadFtDoclist(
|
||||||
Fts3Cursor *pCsr,
|
Fts3Cursor *pCsr,
|
||||||
Fts3Expr *pExpr,
|
Fts3Expr *pExpr,
|
||||||
@ -3510,44 +3519,46 @@ char *sqlite3Fts3FindPositions(
|
|||||||
sqlite3_int64 iDocid, /* Docid associated with requested pos-list */
|
sqlite3_int64 iDocid, /* Docid associated with requested pos-list */
|
||||||
int iCol /* Column of requested pos-list */
|
int iCol /* Column of requested pos-list */
|
||||||
){
|
){
|
||||||
assert( pExpr->isLoaded );
|
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||||
if( pExpr->aDoclist ){
|
assert( pPhrase->isLoaded );
|
||||||
char *pEnd = &pExpr->aDoclist[pExpr->nDoclist];
|
|
||||||
|
if( pPhrase->aDoclist ){
|
||||||
|
char *pEnd = &pPhrase->aDoclist[pPhrase->nDoclist];
|
||||||
char *pCsr;
|
char *pCsr;
|
||||||
|
|
||||||
if( pExpr->pCurrent==0 ){
|
if( pPhrase->pCurrent==0 ){
|
||||||
if( pCursor->desc==0 ){
|
if( pCursor->desc==0 ){
|
||||||
pExpr->pCurrent = pExpr->aDoclist;
|
pPhrase->pCurrent = pPhrase->aDoclist;
|
||||||
pExpr->iCurrent = 0;
|
pPhrase->iCurrent = 0;
|
||||||
fts3GetDeltaVarint(&pExpr->pCurrent, &pExpr->iCurrent);
|
fts3GetDeltaVarint(&pPhrase->pCurrent, &pPhrase->iCurrent);
|
||||||
}else{
|
}else{
|
||||||
pCsr = pExpr->aDoclist;
|
pCsr = pPhrase->aDoclist;
|
||||||
while( pCsr<pEnd ){
|
while( pCsr<pEnd ){
|
||||||
fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent);
|
fts3GetDeltaVarint(&pCsr, &pPhrase->iCurrent);
|
||||||
fts3PoslistCopy(0, &pCsr);
|
fts3PoslistCopy(0, &pCsr);
|
||||||
}
|
}
|
||||||
fts3ReversePoslist(pExpr->aDoclist, &pCsr);
|
fts3ReversePoslist(pPhrase->aDoclist, &pCsr);
|
||||||
pExpr->pCurrent = pCsr;
|
pPhrase->pCurrent = pCsr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pCsr = pExpr->pCurrent;
|
pCsr = pPhrase->pCurrent;
|
||||||
assert( pCsr );
|
assert( pCsr );
|
||||||
|
|
||||||
while( (pCursor->desc==0 && pCsr<pEnd)
|
while( (pCursor->desc==0 && pCsr<pEnd)
|
||||||
|| (pCursor->desc && pCsr>pExpr->aDoclist)
|
|| (pCursor->desc && pCsr>pPhrase->aDoclist)
|
||||||
){
|
){
|
||||||
if( pCursor->desc==0 && pExpr->iCurrent<iDocid ){
|
if( pCursor->desc==0 && pPhrase->iCurrent<iDocid ){
|
||||||
fts3PoslistCopy(0, &pCsr);
|
fts3PoslistCopy(0, &pCsr);
|
||||||
if( pCsr<pEnd ){
|
if( pCsr<pEnd ){
|
||||||
fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent);
|
fts3GetDeltaVarint(&pCsr, &pPhrase->iCurrent);
|
||||||
}
|
}
|
||||||
pExpr->pCurrent = pCsr;
|
pPhrase->pCurrent = pCsr;
|
||||||
}else if( pCursor->desc && pExpr->iCurrent>iDocid ){
|
}else if( pCursor->desc && pPhrase->iCurrent>iDocid ){
|
||||||
fts3GetReverseDeltaVarint(&pCsr, pExpr->aDoclist, &pExpr->iCurrent);
|
fts3GetReverseDeltaVarint(&pCsr, pPhrase->aDoclist, &pPhrase->iCurrent);
|
||||||
fts3ReversePoslist(pExpr->aDoclist, &pCsr);
|
fts3ReversePoslist(pPhrase->aDoclist, &pCsr);
|
||||||
pExpr->pCurrent = pCsr;
|
pPhrase->pCurrent = pCsr;
|
||||||
}else{
|
}else{
|
||||||
if( pExpr->iCurrent==iDocid ){
|
if( pPhrase->iCurrent==iDocid ){
|
||||||
int iThis = 0;
|
int iThis = 0;
|
||||||
if( iCol<0 ){
|
if( iCol<0 ){
|
||||||
/* If iCol is negative, return a pointer to the start of the
|
/* If iCol is negative, return a pointer to the start of the
|
||||||
|
@ -268,17 +268,16 @@ struct Fts3Cursor {
|
|||||||
** sequence. A single token is the base case and the most common case.
|
** sequence. A single token is the base case and the most common case.
|
||||||
** For a sequence of tokens contained in double-quotes (i.e. "one two three")
|
** For a sequence of tokens contained in double-quotes (i.e. "one two three")
|
||||||
** nToken will be the number of tokens in the string.
|
** nToken will be the number of tokens in the string.
|
||||||
**
|
|
||||||
** The nDocMatch and nMatch variables contain data that may be used by the
|
|
||||||
** matchinfo() function. They are populated when the full-text index is
|
|
||||||
** queried for hits on the phrase. If one or more tokens in the phrase
|
|
||||||
** are deferred, the nDocMatch and nMatch variables are populated based
|
|
||||||
** on the assumption that the
|
|
||||||
*/
|
*/
|
||||||
struct Fts3PhraseToken {
|
struct Fts3PhraseToken {
|
||||||
char *z; /* Text of the token */
|
char *z; /* Text of the token */
|
||||||
int n; /* Number of bytes in buffer z */
|
int n; /* Number of bytes in buffer z */
|
||||||
int isPrefix; /* True if token ends with a "*" character */
|
int isPrefix; /* True if token ends with a "*" character */
|
||||||
|
|
||||||
|
/* Variables above this point are populated when the expression is
|
||||||
|
** parsed (by code in fts3_expr.c). Below this point the variables are
|
||||||
|
** used when evaluating the expression. */
|
||||||
|
|
||||||
int bFulltext; /* True if full-text index was used */
|
int bFulltext; /* True if full-text index was used */
|
||||||
Fts3SegReaderCursor *pSegcsr; /* Segment-reader for this token */
|
Fts3SegReaderCursor *pSegcsr; /* Segment-reader for this token */
|
||||||
Fts3DeferredToken *pDeferred; /* Deferred token object for this token */
|
Fts3DeferredToken *pDeferred; /* Deferred token object for this token */
|
||||||
@ -288,18 +287,24 @@ struct Fts3Phrase {
|
|||||||
/* Variables populated by fts3_expr.c when parsing a MATCH expression */
|
/* Variables populated by fts3_expr.c when parsing a MATCH expression */
|
||||||
int nToken; /* Number of tokens in the phrase */
|
int nToken; /* Number of tokens in the phrase */
|
||||||
int iColumn; /* Index of column this phrase must match */
|
int iColumn; /* Index of column this phrase must match */
|
||||||
int isNot; /* Phrase prefixed by unary not (-) operator */
|
|
||||||
|
int isLoaded; /* True if aDoclist/nDoclist are initialized. */
|
||||||
|
char *aDoclist; /* Buffer containing doclist */
|
||||||
|
int nDoclist; /* Size of aDoclist in bytes */
|
||||||
|
sqlite3_int64 iCurrent;
|
||||||
|
char *pCurrent;
|
||||||
|
|
||||||
Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */
|
Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A tree of these objects forms the RHS of a MATCH operator.
|
** A tree of these objects forms the RHS of a MATCH operator.
|
||||||
**
|
**
|
||||||
** If Fts3Expr.eType is either FTSQUERY_NEAR or FTSQUERY_PHRASE and isLoaded
|
** If Fts3Expr.eType is FTSQUERY_PHRASE and isLoaded is true, then aDoclist
|
||||||
** is true, then aDoclist points to a malloced buffer, size nDoclist bytes,
|
** points to a malloced buffer, size nDoclist bytes, containing the results
|
||||||
** containing the results of the NEAR or phrase query in FTS3 doclist
|
** of this phrase query in FTS3 doclist format. As usual, the initial
|
||||||
** format. As usual, the initial "Length" field found in doclists stored
|
** "Length" field found in doclists stored on disk is omitted from this
|
||||||
** on disk is omitted from this buffer.
|
** buffer.
|
||||||
**
|
**
|
||||||
** Variable pCurrent always points to the start of a docid field within
|
** Variable pCurrent always points to the start of a docid field within
|
||||||
** aDoclist. Since the doclist is usually scanned in docid order, this can
|
** aDoclist. Since the doclist is usually scanned in docid order, this can
|
||||||
@ -312,13 +317,6 @@ struct Fts3Expr {
|
|||||||
Fts3Expr *pLeft; /* Left operand */
|
Fts3Expr *pLeft; /* Left operand */
|
||||||
Fts3Expr *pRight; /* Right operand */
|
Fts3Expr *pRight; /* Right operand */
|
||||||
Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */
|
Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */
|
||||||
|
|
||||||
int isLoaded; /* True if aDoclist/nDoclist are initialized. */
|
|
||||||
char *aDoclist; /* Buffer containing doclist */
|
|
||||||
int nDoclist; /* Size of aDoclist in bytes */
|
|
||||||
|
|
||||||
sqlite3_int64 iCurrent;
|
|
||||||
char *pCurrent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -81,12 +81,21 @@ int sqlite3_fts3_enable_parentheses = 0;
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
** isNot:
|
||||||
|
** This variable is used by function getNextNode(). When getNextNode() is
|
||||||
|
** called, it sets ParseContext.isNot to true if the 'next node' is a
|
||||||
|
** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the
|
||||||
|
** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to
|
||||||
|
** zero.
|
||||||
|
*/
|
||||||
typedef struct ParseContext ParseContext;
|
typedef struct ParseContext ParseContext;
|
||||||
struct ParseContext {
|
struct ParseContext {
|
||||||
sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
|
sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
|
||||||
const char **azCol; /* Array of column names for fts3 table */
|
const char **azCol; /* Array of column names for fts3 table */
|
||||||
int nCol; /* Number of entries in azCol[] */
|
int nCol; /* Number of entries in azCol[] */
|
||||||
int iDefaultCol; /* Default column to query */
|
int iDefaultCol; /* Default column to query */
|
||||||
|
int isNot; /* True if getNextNode() sees a unary - */
|
||||||
sqlite3_context *pCtx; /* Write error message here */
|
sqlite3_context *pCtx; /* Write error message here */
|
||||||
int nNest; /* Number of nested brackets */
|
int nNest; /* Number of nested brackets */
|
||||||
};
|
};
|
||||||
@ -172,7 +181,7 @@ static int getNextToken(
|
|||||||
iEnd++;
|
iEnd++;
|
||||||
}
|
}
|
||||||
if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){
|
if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){
|
||||||
pRet->pPhrase->isNot = 1;
|
pParse->isNot = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nConsumed = iEnd;
|
nConsumed = iEnd;
|
||||||
@ -224,36 +233,55 @@ static int getNextString(
|
|||||||
char *zTemp = 0;
|
char *zTemp = 0;
|
||||||
int nTemp = 0;
|
int nTemp = 0;
|
||||||
|
|
||||||
|
const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
|
||||||
|
int nToken = 0;
|
||||||
|
|
||||||
|
/* The final Fts3Expr data structure, including the Fts3Phrase,
|
||||||
|
** Fts3PhraseToken structures token buffers are all stored as a single
|
||||||
|
** allocation so that the expression can be freed with a single call to
|
||||||
|
** sqlite3_free(). Setting this up requires a two pass approach.
|
||||||
|
**
|
||||||
|
** The first pass, in the block below, uses a tokenizer cursor to iterate
|
||||||
|
** through the tokens in the expression. This pass uses fts3ReallocOrFree()
|
||||||
|
** to assemble data in two dynamic buffers:
|
||||||
|
**
|
||||||
|
** Buffer p: Points to the Fts3Expr structure, followed by the Fts3Phrase
|
||||||
|
** structure, followed by the array of Fts3PhraseToken
|
||||||
|
** structures. This pass only populates the Fts3PhraseToken array.
|
||||||
|
**
|
||||||
|
** Buffer zTemp: Contains copies of all tokens.
|
||||||
|
**
|
||||||
|
** The second pass, in the block that begins "if( rc==SQLITE_DONE )" below,
|
||||||
|
** appends buffer zTemp to buffer p, and fills in the Fts3Expr and Fts3Phrase
|
||||||
|
** structures.
|
||||||
|
*/
|
||||||
rc = pModule->xOpen(pTokenizer, zInput, nInput, &pCursor);
|
rc = pModule->xOpen(pTokenizer, zInput, nInput, &pCursor);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
int ii;
|
int ii;
|
||||||
pCursor->pTokenizer = pTokenizer;
|
pCursor->pTokenizer = pTokenizer;
|
||||||
for(ii=0; rc==SQLITE_OK; ii++){
|
for(ii=0; rc==SQLITE_OK; ii++){
|
||||||
const char *zToken;
|
const char *zByte;
|
||||||
int nToken, iBegin, iEnd, iPos;
|
int nByte, iBegin, iEnd, iPos;
|
||||||
rc = pModule->xNext(pCursor, &zToken, &nToken, &iBegin, &iEnd, &iPos);
|
rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
|
Fts3PhraseToken *pToken;
|
||||||
p = fts3ReallocOrFree(p, nByte+ii*sizeof(Fts3PhraseToken));
|
|
||||||
zTemp = fts3ReallocOrFree(zTemp, nTemp + nToken);
|
p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken));
|
||||||
if( !p || !zTemp ){
|
if( !p ) goto no_mem;
|
||||||
goto no_mem;
|
|
||||||
}
|
zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte);
|
||||||
if( ii==0 ){
|
if( !zTemp ) goto no_mem;
|
||||||
memset(p, 0, nByte);
|
|
||||||
p->pPhrase = (Fts3Phrase *)&p[1];
|
assert( nToken==ii );
|
||||||
}
|
pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii];
|
||||||
p->pPhrase = (Fts3Phrase *)&p[1];
|
memset(pToken, 0, sizeof(Fts3PhraseToken));
|
||||||
memset(&p->pPhrase->aToken[ii], 0, sizeof(Fts3PhraseToken));
|
|
||||||
p->pPhrase->nToken = ii+1;
|
memcpy(&zTemp[nTemp], zByte, nByte);
|
||||||
p->pPhrase->aToken[ii].n = nToken;
|
nTemp += nByte;
|
||||||
memcpy(&zTemp[nTemp], zToken, nToken);
|
|
||||||
nTemp += nToken;
|
pToken->n = nByte;
|
||||||
if( iEnd<nInput && zInput[iEnd]=='*' ){
|
pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
|
||||||
p->pPhrase->aToken[ii].isPrefix = 1;
|
nToken = ii+1;
|
||||||
}else{
|
|
||||||
p->pPhrase->aToken[ii].isPrefix = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,28 +291,24 @@ static int getNextString(
|
|||||||
|
|
||||||
if( rc==SQLITE_DONE ){
|
if( rc==SQLITE_DONE ){
|
||||||
int jj;
|
int jj;
|
||||||
char *zNew = NULL;
|
char *zBuf = 0;
|
||||||
int nNew = 0;
|
|
||||||
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
|
p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp);
|
||||||
nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(Fts3PhraseToken);
|
if( !p ) goto no_mem;
|
||||||
p = fts3ReallocOrFree(p, nByte + nTemp);
|
memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p);
|
||||||
if( !p ){
|
|
||||||
goto no_mem;
|
|
||||||
}
|
|
||||||
if( zTemp ){
|
|
||||||
zNew = &(((char *)p)[nByte]);
|
|
||||||
memcpy(zNew, zTemp, nTemp);
|
|
||||||
}else{
|
|
||||||
memset(p, 0, nByte+nTemp);
|
|
||||||
}
|
|
||||||
p->pPhrase = (Fts3Phrase *)&p[1];
|
|
||||||
for(jj=0; jj<p->pPhrase->nToken; jj++){
|
|
||||||
p->pPhrase->aToken[jj].z = &zNew[nNew];
|
|
||||||
nNew += p->pPhrase->aToken[jj].n;
|
|
||||||
}
|
|
||||||
sqlite3_free(zTemp);
|
|
||||||
p->eType = FTSQUERY_PHRASE;
|
p->eType = FTSQUERY_PHRASE;
|
||||||
|
p->pPhrase = (Fts3Phrase *)&p[1];
|
||||||
p->pPhrase->iColumn = pParse->iDefaultCol;
|
p->pPhrase->iColumn = pParse->iDefaultCol;
|
||||||
|
p->pPhrase->nToken = nToken;
|
||||||
|
|
||||||
|
zBuf = (char *)&p->pPhrase->aToken[nToken];
|
||||||
|
memcpy(zBuf, zTemp, nTemp);
|
||||||
|
sqlite3_free(zTemp);
|
||||||
|
|
||||||
|
for(jj=0; jj<p->pPhrase->nToken; jj++){
|
||||||
|
p->pPhrase->aToken[jj].z = zBuf;
|
||||||
|
zBuf += p->pPhrase->aToken[jj].n;
|
||||||
|
}
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,6 +365,8 @@ static int getNextNode(
|
|||||||
const char *zInput = z;
|
const char *zInput = z;
|
||||||
int nInput = n;
|
int nInput = n;
|
||||||
|
|
||||||
|
pParse->isNot = 0;
|
||||||
|
|
||||||
/* Skip over any whitespace before checking for a keyword, an open or
|
/* Skip over any whitespace before checking for a keyword, an open or
|
||||||
** close bracket, or a quoted string.
|
** close bracket, or a quoted string.
|
||||||
*/
|
*/
|
||||||
@ -559,7 +585,7 @@ static int fts3ExprParse(
|
|||||||
int isPhrase;
|
int isPhrase;
|
||||||
|
|
||||||
if( !sqlite3_fts3_enable_parentheses
|
if( !sqlite3_fts3_enable_parentheses
|
||||||
&& p->eType==FTSQUERY_PHRASE && p->pPhrase->isNot
|
&& p->eType==FTSQUERY_PHRASE && pParse->isNot
|
||||||
){
|
){
|
||||||
/* Create an implicit NOT operator. */
|
/* Create an implicit NOT operator. */
|
||||||
Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr));
|
Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr));
|
||||||
@ -577,7 +603,6 @@ static int fts3ExprParse(
|
|||||||
p = pPrev;
|
p = pPrev;
|
||||||
}else{
|
}else{
|
||||||
int eType = p->eType;
|
int eType = p->eType;
|
||||||
assert( eType!=FTSQUERY_PHRASE || !p->pPhrase->isNot );
|
|
||||||
isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft);
|
isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft);
|
||||||
|
|
||||||
/* The isRequirePhrase variable is set to true if a phrase or
|
/* The isRequirePhrase variable is set to true if a phrase or
|
||||||
@ -740,9 +765,10 @@ int sqlite3Fts3ExprParse(
|
|||||||
*/
|
*/
|
||||||
void sqlite3Fts3ExprFree(Fts3Expr *p){
|
void sqlite3Fts3ExprFree(Fts3Expr *p){
|
||||||
if( p ){
|
if( p ){
|
||||||
|
assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 );
|
||||||
sqlite3Fts3ExprFree(p->pLeft);
|
sqlite3Fts3ExprFree(p->pLeft);
|
||||||
sqlite3Fts3ExprFree(p->pRight);
|
sqlite3Fts3ExprFree(p->pRight);
|
||||||
sqlite3_free(p->aDoclist);
|
if( p->pPhrase ) sqlite3_free(p->pPhrase->aDoclist);
|
||||||
sqlite3_free(p);
|
sqlite3_free(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -800,7 +826,7 @@ static char *exprToString(Fts3Expr *pExpr, char *zBuf){
|
|||||||
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||||
int i;
|
int i;
|
||||||
zBuf = sqlite3_mprintf(
|
zBuf = sqlite3_mprintf(
|
||||||
"%zPHRASE %d %d", zBuf, pPhrase->iColumn, pPhrase->isNot);
|
"%zPHRASE %d 0", zBuf, pPhrase->iColumn);
|
||||||
for(i=0; zBuf && i<pPhrase->nToken; i++){
|
for(i=0; zBuf && i<pPhrase->nToken; i++){
|
||||||
zBuf = sqlite3_mprintf("%z %.*s%s", zBuf,
|
zBuf = sqlite3_mprintf("%z %.*s%s", zBuf,
|
||||||
pPhrase->aToken[i].n, pPhrase->aToken[i].z,
|
pPhrase->aToken[i].n, pPhrase->aToken[i].z,
|
||||||
|
@ -228,16 +228,17 @@ static int fts3ExprNearTrim(Fts3Expr *pExpr){
|
|||||||
*/
|
*/
|
||||||
static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
|
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||||
LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
|
LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
|
||||||
|
|
||||||
UNUSED_PARAMETER(iPhrase);
|
UNUSED_PARAMETER(iPhrase);
|
||||||
|
|
||||||
p->nPhrase++;
|
p->nPhrase++;
|
||||||
p->nToken += pExpr->pPhrase->nToken;
|
p->nToken += pPhrase->nToken;
|
||||||
|
|
||||||
if( pExpr->isLoaded==0 ){
|
if( pPhrase->isLoaded==0 ){
|
||||||
rc = sqlite3Fts3ExprLoadDoclist(p->pCsr, pExpr);
|
rc = sqlite3Fts3ExprLoadDoclist(p->pCsr, pExpr);
|
||||||
pExpr->isLoaded = 1;
|
pPhrase->isLoaded = 1;
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = fts3ExprNearTrim(pExpr);
|
rc = fts3ExprNearTrim(pExpr);
|
||||||
}
|
}
|
||||||
@ -826,16 +827,15 @@ static int fts3ExprGlobalHitsCb(
|
|||||||
){
|
){
|
||||||
MatchInfo *p = (MatchInfo *)pCtx;
|
MatchInfo *p = (MatchInfo *)pCtx;
|
||||||
Fts3Cursor *pCsr = p->pCursor;
|
Fts3Cursor *pCsr = p->pCursor;
|
||||||
|
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||||
char *pIter;
|
char *pIter;
|
||||||
char *pEnd;
|
char *pEnd;
|
||||||
char *pFree = 0;
|
char *pFree = 0;
|
||||||
u32 *aOut = &p->aMatchinfo[3*iPhrase*p->nCol];
|
u32 *aOut = &p->aMatchinfo[3*iPhrase*p->nCol];
|
||||||
|
|
||||||
assert( pExpr->isLoaded );
|
assert( pPhrase->isLoaded );
|
||||||
assert( pExpr->eType==FTSQUERY_PHRASE );
|
|
||||||
|
|
||||||
if( pCsr->pDeferred ){
|
if( pCsr->pDeferred ){
|
||||||
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
|
||||||
int ii;
|
int ii;
|
||||||
for(ii=0; ii<pPhrase->nToken; ii++){
|
for(ii=0; ii<pPhrase->nToken; ii++){
|
||||||
if( pPhrase->aToken[ii].bFulltext ) break;
|
if( pPhrase->aToken[ii].bFulltext ) break;
|
||||||
@ -855,8 +855,8 @@ static int fts3ExprGlobalHitsCb(
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
pIter = pExpr->aDoclist;
|
pIter = pPhrase->aDoclist;
|
||||||
pEnd = &pExpr->aDoclist[pExpr->nDoclist];
|
pEnd = &pPhrase->aDoclist[pPhrase->nDoclist];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the global hit count matrix row for this phrase. */
|
/* Fill in the global hit count matrix row for this phrase. */
|
||||||
@ -885,7 +885,7 @@ static int fts3ExprLocalHitsCb(
|
|||||||
|
|
||||||
for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
|
for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
|
||||||
|
|
||||||
if( pExpr->aDoclist ){
|
if( pExpr->pPhrase->aDoclist ){
|
||||||
char *pCsr;
|
char *pCsr;
|
||||||
|
|
||||||
pCsr = sqlite3Fts3FindPositions(p->pCursor, pExpr, p->pCursor->iPrevId, -1);
|
pCsr = sqlite3Fts3FindPositions(p->pCursor, pExpr, p->pCursor->iPrevId, -1);
|
||||||
|
@ -2642,15 +2642,17 @@ char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *pDeferred, int *pnByte){
|
|||||||
*/
|
*/
|
||||||
static void fts3DeferredDoclistClear(Fts3Expr *pExpr){
|
static void fts3DeferredDoclistClear(Fts3Expr *pExpr){
|
||||||
if( pExpr ){
|
if( pExpr ){
|
||||||
|
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||||
fts3DeferredDoclistClear(pExpr->pLeft);
|
fts3DeferredDoclistClear(pExpr->pLeft);
|
||||||
fts3DeferredDoclistClear(pExpr->pRight);
|
fts3DeferredDoclistClear(pExpr->pRight);
|
||||||
if( pExpr->isLoaded ){
|
if( pPhrase ){
|
||||||
sqlite3_free(pExpr->aDoclist);
|
assert( pExpr->eType==FTSQUERY_PHRASE );
|
||||||
pExpr->isLoaded = 0;
|
sqlite3_free(pPhrase->aDoclist);
|
||||||
pExpr->aDoclist = 0;
|
pPhrase->isLoaded = 0;
|
||||||
pExpr->nDoclist = 0;
|
pPhrase->aDoclist = 0;
|
||||||
pExpr->pCurrent = 0;
|
pPhrase->nDoclist = 0;
|
||||||
pExpr->iCurrent = 0;
|
pPhrase->pCurrent = 0;
|
||||||
|
pPhrase->iCurrent = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
22
manifest
22
manifest
@ -1,5 +1,5 @@
|
|||||||
C If\sa\sprefix\sindex\sof\ssize\sN\sis\snot\spresent,\suse\sa\sprefix\sindex\sof\ssize\sN+1\salong\swith\sthe\sterms\sindex\sfor\squeries\sfor\sprefixes\sof\slength\sN.
|
C Minor\schanges\smade\swhile\splanning\sa\slarger\schange.
|
||||||
D 2011-05-25T19:17:32.713
|
D 2011-05-28T15:57:40.694
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d
|
F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@ -61,21 +61,21 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
|
|||||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||||
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
|
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
|
||||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||||
F ext/fts3/fts3.c b44e0abc7aaef8d5489533b3f0556b28097378f9
|
F ext/fts3/fts3.c eb59cdd89e9309ab9b2dca196a7c52f9e8927319
|
||||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||||
F ext/fts3/fts3Int.h deeeac21d17da06683a79b40ae119b93cf86f90a
|
F ext/fts3/fts3Int.h 832f4d421f03a9d364186e779ee51994df500c62
|
||||||
F ext/fts3/fts3_aux.c 2817a1ec9ffbad673cb1a1527ad807811bc7645b
|
F ext/fts3/fts3_aux.c 2817a1ec9ffbad673cb1a1527ad807811bc7645b
|
||||||
F ext/fts3/fts3_expr.c 5f49e0deaf723724b08100bb3ff40aab02ad0c93
|
F ext/fts3/fts3_expr.c 25e30cf24198333f2ed545af905b168e88f56903
|
||||||
F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c
|
F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c
|
||||||
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
|
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
|
||||||
F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
|
F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
|
||||||
F ext/fts3/fts3_porter.c d61cfd81fb0fd8fbcb25adcaee0ba671aefaa5c2
|
F ext/fts3/fts3_porter.c d61cfd81fb0fd8fbcb25adcaee0ba671aefaa5c2
|
||||||
F ext/fts3/fts3_snippet.c 92b40397b28422c35c4127492d7ac6da34d1966a
|
F ext/fts3/fts3_snippet.c 6ee626017ddcf7d72ca4f587724e3506434fc0d7
|
||||||
F ext/fts3/fts3_term.c 0ade1812c0e97f394b58299810dfd5d2fb7ba501
|
F ext/fts3/fts3_term.c 0ade1812c0e97f394b58299810dfd5d2fb7ba501
|
||||||
F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d
|
F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d
|
||||||
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
||||||
F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d
|
F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d
|
||||||
F ext/fts3/fts3_write.c beaa93bcbe1664fcada75b70893f9b221acf2777
|
F ext/fts3/fts3_write.c ed58c53fbcbc2ea79258e734159a5951ffeb1bd4
|
||||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||||
F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||||
@ -489,7 +489,7 @@ F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
|
|||||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||||
F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c
|
F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c
|
||||||
F test/fuzzer1.test 3105b5a89a6cb0d475f0877debec942fe4143462
|
F test/fuzzer1.test 3105b5a89a6cb0d475f0877debec942fe4143462
|
||||||
F test/hook.test f04c3412463f8ec117c1c704c74ca0f627ce733a
|
F test/hook.test f2277c309e4ee8067d95d6b9b315568e9d5329b2
|
||||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||||
F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d
|
F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d
|
||||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||||
@ -939,7 +939,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
|||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
||||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||||
P f0f0a03db214b68a37069f64c27ae8520220c900
|
P cc83991caae7c7d647432d5711b6cd80228c3002
|
||||||
R 95d28d5ab6425c93022acec043aee69b
|
R eef52aec1faead4921ebaf39c1605d2b
|
||||||
U dan
|
U dan
|
||||||
Z 2f1dd28b688335ffa6210dbb33afadf5
|
Z 01d8f7aea2ce8ebb35c05ccc519b614f
|
||||||
|
@ -1 +1 @@
|
|||||||
cc83991caae7c7d647432d5711b6cd80228c3002
|
84097a4c759b1d65890af885f137d3cb16eef584
|
@ -274,6 +274,34 @@ ifcapable compound&&attach {
|
|||||||
set ::update_hook
|
set ::update_hook
|
||||||
} [list]
|
} [list]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_test hook-4.4 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t4(a UNIQUE, b);
|
||||||
|
INSERT INTO t4 VALUES(1, 'a');
|
||||||
|
INSERT INTO t4 VALUES(2, 'b');
|
||||||
|
}
|
||||||
|
set ::update_hook [list]
|
||||||
|
execsql {
|
||||||
|
REPLACE INTO t4 VALUES(1, 'c');
|
||||||
|
}
|
||||||
|
set ::update_hook
|
||||||
|
} [list INSERT main t4 3 ]
|
||||||
|
do_execsql_test hook-4.4.1 {
|
||||||
|
SELECT * FROM t4 ORDER BY a;
|
||||||
|
} {1 c 2 b}
|
||||||
|
do_test hook-4.4.2 {
|
||||||
|
set ::update_hook [list]
|
||||||
|
execsql {
|
||||||
|
PRAGMA recursive_triggers = on;
|
||||||
|
REPLACE INTO t4 VALUES(1, 'd');
|
||||||
|
}
|
||||||
|
set ::update_hook
|
||||||
|
} [list INSERT main t4 4 ]
|
||||||
|
do_execsql_test hook-4.4.3 {
|
||||||
|
SELECT * FROM t4 ORDER BY a;
|
||||||
|
} {1 d 2 b}
|
||||||
|
|
||||||
db update_hook {}
|
db update_hook {}
|
||||||
#
|
#
|
||||||
#----------------------------------------------------------------------------
|
#----------------------------------------------------------------------------
|
||||||
|
Reference in New Issue
Block a user