return sParse.rc;
}
-static char *fts5ExprStrdup(int *pRc, const char *zIn){
- char *zRet = 0;
- if( *pRc==SQLITE_OK ){
- int nByte = strlen(zIn) + 1;
- zRet = sqlite3_malloc(nByte);
- if( zRet ){
- memcpy(zRet, zIn, nByte);
- }else{
- *pRc = SQLITE_NOMEM;
- }
- }
- return zRet;
-}
-
-static void *fts5ExprMalloc(int *pRc, int nByte){
- void *pRet = 0;
- if( *pRc==SQLITE_OK ){
- pRet = sqlite3_malloc(nByte);
- if( pRet ){
- memset(pRet, 0, nByte);
- }else{
- *pRc = SQLITE_NOMEM;
- }
- }
- return pRet;
-}
-
/*
** Create a new FTS5 expression by cloning phrase iPhrase of the
** expression passed as the second argument.
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
pOrig = pExpr->apExprPhrase[iPhrase];
- pCopy = (Fts5ExprPhrase*)fts5ExprMalloc(&rc,
+ pCopy = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * pOrig->nTerm
);
if( pCopy ){
Fts5ExprNode *pNode;
Fts5ExprNearset *pNear;
- pNew = (Fts5Expr*)fts5ExprMalloc(&rc, sizeof(Fts5Expr));
- apPhrase = (Fts5ExprPhrase**)fts5ExprMalloc(&rc, sizeof(Fts5ExprPhrase*));
- pNode = (Fts5ExprNode*)fts5ExprMalloc(&rc, sizeof(Fts5ExprNode));
- pNear = (Fts5ExprNearset*)fts5ExprMalloc(&rc,
+ pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+ apPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
+ sizeof(Fts5ExprPhrase*)
+ );
+ pNode = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNode));
+ pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)
);
for(i=0; i<pOrig->nTerm; i++){
- pCopy->aTerm[i].zTerm = fts5ExprStrdup(&rc, pOrig->aTerm[i].zTerm);
+ pCopy->aTerm[i].zTerm = sqlite3Fts5Strndup(&rc, pOrig->aTerm[i].zTerm,-1);
pCopy->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
}
}
/*
-** Advance each term iterator in each phrase in pNear. If any reach EOF,
-** set output variable *pbEof to true before returning.
+** Advance the first term iterator in the first phrase of pNear. Set output
+** variable *pbEof to true if it reaches EOF or if an error occurs.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** occurs.
*/
-static int fts5ExprNearAdvanceAll(
+static int fts5ExprNearAdvanceFirst(
Fts5Expr *pExpr, /* Expression pPhrase belongs to */
- Fts5ExprNearset *pNear, /* Near object to advance iterators of */
- int *pbEof /* OUT: Set to true if phrase at EOF */
+ Fts5ExprNode *pNode, /* FTS5_STRING node */
+ int bFromValid,
+ i64 iFrom
){
- int i, j; /* Phrase and token index, respectively */
+ Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter;
+ int rc;
- for(i=0; i<pNear->nPhrase; i++){
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- for(j=0; j<pPhrase->nTerm; j++){
- Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
- int rc = sqlite3Fts5IterNext(pIter);
- if( rc || sqlite3Fts5IterEof(pIter) ){
- *pbEof = 1;
- return rc;
- }
- }
+ if( bFromValid ){
+ rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
+ }else{
+ rc = sqlite3Fts5IterNext(pIter);
}
- return SQLITE_OK;
+ pNode->bEof = (rc || sqlite3Fts5IterEof(pIter));
+ return rc;
}
/*
*/
static int fts5ExprNearNextRowidMatch(
Fts5Expr *pExpr, /* Expression pPhrase belongs to */
- Fts5ExprNode *pNode,
- int bFromValid,
- i64 iFrom
+ Fts5ExprNode *pNode
){
Fts5ExprNearset *pNear = pNode->pNear;
int rc = SQLITE_OK;
** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it
** means the minimum rowid. */
iLast = sqlite3Fts5IterRowid(pNear->apPhrase[0]->aTerm[0].pIter);
- if( bFromValid && (iFrom>iLast)==(pExpr->bDesc==0) ){
- assert( pExpr->bDesc || iFrom>=iLast );
- iLast = iFrom;
- }
do {
bMatch = 1;
*/
static int fts5ExprNearNextMatch(
Fts5Expr *pExpr, /* Expression that pNear is a part of */
- Fts5ExprNode *pNode, /* The "NEAR" node (FTS5_STRING) */
- int bFromValid,
- i64 iFrom
+ Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */
){
int rc = SQLITE_OK;
Fts5ExprNearset *pNear = pNode->pNear;
int i;
/* Advance the iterators until they all point to the same rowid */
- rc = fts5ExprNearNextRowidMatch(pExpr, pNode, bFromValid, iFrom);
+ rc = fts5ExprNearNextRowidMatch(pExpr, pNode);
if( rc!=SQLITE_OK || pNode->bEof ) break;
/* Check that each phrase in the nearset matches the current row.
/* If control flows to here, then the current rowid is not a match.
** Advance all term iterators in all phrases to the next rowid. */
if( rc==SQLITE_OK ){
- rc = fts5ExprNearAdvanceAll(pExpr, pNear, &pNode->bEof);
+ rc = fts5ExprNearAdvanceFirst(pExpr, pNode, 0, 0);
}
if( pNode->bEof || rc!=SQLITE_OK ) break;
}
}
/* fts5ExprNodeNext() calls fts5ExprNodeNextMatch(). And vice-versa. */
-static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*, int, i64);
+static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*);
+
+
+static int fts5RowidCmp(
+ Fts5Expr *pExpr,
+ i64 iLhs,
+ i64 iRhs
+){
+ assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
+ if( pExpr->bDesc==0 ){
+ if( iLhs<iRhs ) return -1;
+ return (iLhs > iRhs);
+ }else{
+ if( iLhs>iRhs ) return -1;
+ return (iLhs < iRhs);
+ }
+}
/*
** Compare the values currently indicated by the two nodes as follows:
){
if( p2->bEof ) return -1;
if( p1->bEof ) return +1;
- if( pExpr->bDesc==0 ){
- if( p1->iRowid<p2->iRowid ) return -1;
- return (p1->iRowid > p2->iRowid);
- }else{
- if( p1->iRowid>p2->iRowid ) return -1;
- return (p1->iRowid < p2->iRowid);
- }
+ return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid);
}
/*
if( pNode->bEof==0 ){
switch( pNode->eType ){
case FTS5_STRING: {
- rc = fts5ExprNearAdvanceAll(pExpr, pNode->pNear, &pNode->bEof);
+ rc = fts5ExprNearAdvanceFirst(pExpr, pNode, bFromValid, iFrom);
break;
};
Fts5ExprNode *p2 = pNode->pRight;
int cmp = fts5NodeCompare(pExpr, p1, p2);
- if( cmp==0 ){
+ if( cmp<=0 || (bFromValid && fts5RowidCmp(pExpr,p1->iRowid,iFrom)<0) ){
rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
+ }
+
+ if( cmp>=0 || (bFromValid && fts5RowidCmp(pExpr,p2->iRowid,iFrom)<0) ){
if( rc==SQLITE_OK ){
rc = fts5ExprNodeNext(pExpr, p2, bFromValid, iFrom);
}
- }else{
- rc = fts5ExprNodeNext(pExpr, (cmp < 0) ? p1 : p2, bFromValid, iFrom);
}
break;
}
if( rc==SQLITE_OK ){
- rc = fts5ExprNodeNextMatch(pExpr, pNode, bFromValid, iFrom);
+ rc = fts5ExprNodeNextMatch(pExpr, pNode);
}
}
+ /* Assert that if bFromValid was true, either:
+ **
+ ** a) an error occurred, or
+ ** b) the node is now at EOF, or
+ ** c) the node is now at or past rowid iFrom.
+ */
+ assert( bFromValid==0
+ || rc!=SQLITE_OK /* a */
+ || pNode->bEof /* b */
+ || pNode->iRowid==iFrom || pExpr->bDesc==(pNode->iRowid<iFrom) /* c */
+ );
+
return rc;
}
}
/*
-**
+** If pNode currently points to a match, this function returns SQLITE_OK
+** without modifying it. Otherwise, pNode is advanced until it does point
+** to a match or EOF is reached.
*/
static int fts5ExprNodeNextMatch(
- Fts5Expr *pExpr,
- Fts5ExprNode *pNode,
- int bFromValid,
- i64 iFrom
+ Fts5Expr *pExpr, /* Expression of which pNode is a part */
+ Fts5ExprNode *pNode /* Expression node to test */
){
int rc = SQLITE_OK;
if( pNode->bEof==0 ){
switch( pNode->eType ){
case FTS5_STRING: {
- rc = fts5ExprNearNextMatch(pExpr, pNode, bFromValid, iFrom);
+ rc = fts5ExprNearNextMatch(pExpr, pNode);
break;
}
while( p1->bEof==0 && p2->bEof==0 && p2->iRowid!=p1->iRowid ){
Fts5ExprNode *pAdv;
+ i64 iFrom;
assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
if( pExpr->bDesc==(p1->iRowid > p2->iRowid) ){
pAdv = p1;
- if( bFromValid==0 || pExpr->bDesc==(p2->iRowid < iFrom) ){
- iFrom = p2->iRowid;
- }
+ iFrom = p2->iRowid;
}else{
pAdv = p2;
- if( bFromValid==0 || pExpr->bDesc==(p1->iRowid < iFrom) ){
- iFrom = p1->iRowid;
- }
+ iFrom = p1->iRowid;
}
rc = fts5ExprNodeNext(pExpr, pAdv, 1, iFrom);
if( rc!=SQLITE_OK ) break;
default: assert( pNode->eType==FTS5_NOT ); {
Fts5ExprNode *p1 = pNode->pLeft;
Fts5ExprNode *p2 = pNode->pRight;
- while( rc==SQLITE_OK ){
- int cmp;
- while( rc==SQLITE_OK && (cmp = fts5NodeCompare(pExpr, p1, p2))>0 ){
- rc = fts5ExprNodeNext(pExpr, p2, bFromValid, iFrom);
+
+ while( rc==SQLITE_OK && p1->bEof==0 ){
+ int cmp = fts5NodeCompare(pExpr, p1, p2);
+ if( cmp>0 ){
+ rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid);
+ cmp = fts5NodeCompare(pExpr, p1, p2);
}
- if( rc || cmp ) break;
- rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
+ assert( rc!=SQLITE_OK || cmp<=0 );
+ if( rc || cmp<0 ) break;
+ rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
}
pNode->bEof = p1->bEof;
pNode->iRowid = p1->iRowid;
/* Attempt to advance to the first match */
if( rc==SQLITE_OK && pNode->bEof==0 ){
- rc = fts5ExprNearNextMatch(pExpr, pNode, 0, 0);
+ rc = fts5ExprNearNextMatch(pExpr, pNode);
}
}else{
rc = fts5ExprNodeFirst(pExpr, pNode->pRight);
}
if( rc==SQLITE_OK ){
- rc = fts5ExprNodeNextMatch(pExpr, pNode, 0, 0);
+ rc = fts5ExprNodeNextMatch(pExpr, pNode);
}
}
return rc;
return p->pRoot->iRowid;
}
-/*
-** Argument pIn points to a buffer of nIn bytes. This function allocates
-** and returns a new buffer populated with a copy of (pIn/nIn) with a
-** nul-terminator byte appended to it.
-**
-** It is the responsibility of the caller to eventually free the returned
-** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned.
-*/
-static char *fts5Strndup(int *pRc, const char *pIn, int nIn){
- char *zRet = 0;
- if( *pRc==SQLITE_OK ){
- zRet = (char*)sqlite3_malloc(nIn+1);
- if( zRet ){
- memcpy(zRet, pIn, nIn);
- zRet[nIn] = '\0';
- }else{
- *pRc = SQLITE_NOMEM;
- }
- }
- return zRet;
-}
-
static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){
int rc = SQLITE_OK;
- *pz = fts5Strndup(&rc, pToken->p, pToken->n);
+ *pz = sqlite3Fts5Strndup(&rc, pToken->p, pToken->n);
return rc;
}
pRet->iCol = -1;
}
}else if( (pNear->nPhrase % SZALLOC)==0 ){
- int nNew = pRet->nPhrase + SZALLOC;
+ int nNew = pNear->nPhrase + SZALLOC;
int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte);
pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
memset(pTerm, 0, sizeof(Fts5ExprTerm));
- pTerm->zTerm = fts5Strndup(&rc, pToken, nToken);
+ pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
return rc;
}
** in the pParse object.
*/
void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){
- if( pParse->rc==SQLITE_OK ){
- if( pTok->n!=4 || memcmp("NEAR", pTok->p, 4) ){
- sqlite3Fts5ParseError(
- pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p
- );
- }
+ if( pTok->n!=4 || memcmp("NEAR", pTok->p, 4) ){
+ sqlite3Fts5ParseError(
+ pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p
+ );
}
}
Fts5ExprNearset *pNear,
Fts5Token *p
){
- char *z = 0;
- int rc = fts5ParseStringFromToken(p, &z);
- if( rc==SQLITE_OK ){
- Fts5Config *pConfig = pParse->pConfig;
- int i;
- for(i=0; i<pConfig->nCol; i++){
- if( 0==sqlite3_stricmp(pConfig->azCol[i], z) ){
- pNear->iCol = i;
- break;
+ if( pParse->rc==SQLITE_OK ){
+ char *z = 0;
+ int rc = fts5ParseStringFromToken(p, &z);
+ if( rc==SQLITE_OK ){
+ Fts5Config *pConfig = pParse->pConfig;
+ int i;
+ for(i=0; i<pConfig->nCol; i++){
+ if( 0==sqlite3_stricmp(pConfig->azCol[i], z) ){
+ pNear->iCol = i;
+ break;
+ }
}
+ if( i==pConfig->nCol ){
+ sqlite3Fts5ParseError(pParse, "no such column: %s", z);
+ }
+ sqlite3_free(z);
+ }else{
+ pParse->rc = rc;
}
- if( i==pConfig->nCol ){
- sqlite3Fts5ParseError(pParse, "no such column: %s", z);
- }
- sqlite3_free(z);
- }else{
- pParse->rc = rc;
}
}
-C Further\simprovements\sto\stest\scoverage\sof\sfts5\scode.
-D 2015-05-01T20:38:57.153
+C Reorganize\ssome\sof\sthe\sfts5\sexpression\sparsing\scode.\sImprove\stest\scoverage\sof\sthe\ssame.
+D 2015-05-02T20:35:24.467
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 31b38b9da2e4b36f54a013bd71a5c3f6e45ca78f
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F ext/fts5/extract_api_docs.tcl 55a6d648d516f35d9a1e580ac00de27154e1904a
F ext/fts5/fts5.c 3a0a73bcfbcb7e65ccda099cfb8fd268d2480c7e
F ext/fts5/fts5.h 24a2cc35b5e76eec57b37ba48c12d9d2cb522b3a
-F ext/fts5/fts5Int.h 2e0a1a6b77e1e014b7e9b1479ca686ff79930457
+F ext/fts5/fts5Int.h 05e97ffb2911e8c8cfcb8bdb009e17347c24eb2d
F ext/fts5/fts5_aux.c d53f00f31ad615ca4f139dd8751f9041afa00971
-F ext/fts5/fts5_buffer.c 8c8cfe7f09ca2767ab53ea883f9a0af0edb6bbae
-F ext/fts5/fts5_config.c ecbbd5163758a958106867051892e0dfecf68b5c
-F ext/fts5/fts5_expr.c e2005ba7823f4ac51d46a8e5aaa1ff66c701b32e
+F ext/fts5/fts5_buffer.c 70b971e13503566f1e257941c60817ba0920a16b
+F ext/fts5/fts5_config.c 4e0de8bea4746a7560740b9dcf8be4dced68ef4f
+F ext/fts5/fts5_expr.c f49d68411dc72cb66f2b55cc109dbf3dce368eef
F ext/fts5/fts5_hash.c 29d8b0668727863cc1f1efa65efe4dd78635b016
F ext/fts5/fts5_index.c de588982b0237b1605d6c37afd115b34c95c3da1
F ext/fts5/fts5_storage.c ef60fc9dcc4e274f9589165e26833173c273ae18
F ext/fts5/test/fts5corrupt2.test 494111fd4f2dab36499cf97718eaba1f7c11e9d0
F ext/fts5/test/fts5dlidx.test 748a84ceb74a4154725096a26dfa854260b0182f
F ext/fts5/test/fts5doclist.test 635b80ac785627841a59c583bac702b55d49fdc5
-F ext/fts5/test/fts5ea.test 7cc498993c16849bb866dbdfb008d91a29f9870b
+F ext/fts5/test/fts5ea.test f4d35cd2776dab9358206f7d88a67ea187fdec22
F ext/fts5/test/fts5eb.test 728a1f23f263548f5c29b29dfb851b5f2dbe723e
F ext/fts5/test/fts5fault1.test ed71717a479bef32d05f02d9c48691011d160d4d
F ext/fts5/test/fts5fault2.test 26c3d70648f691e2cc9391e14bbc11a973656383
F ext/fts5/test/fts5fault3.test d6e9577d4312e331a913c72931bf131704efc8f3
-F ext/fts5/test/fts5fault4.test 4090af395d8d3342c0a0b27349dd71eb7cc6262d
+F ext/fts5/test/fts5fault4.test 09728cadb4897c97cea092edb9c431d9ec25b88b
F ext/fts5/test/fts5full.test 0924bdca5416a242103239ace79c6f5aa34bab8d
F ext/fts5/test/fts5hash.test adb7b0442cc1c77c507f07e16d11490486e75dfa
F ext/fts5/test/fts5merge.test 453a0717881aa7784885217b2040f3f275caff03
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P add4f4681c648dcbecaa68d08f7b2f4e6d63003c
-R 58de859125935eeaf7ecede3ffbb5a07
+P d4331943dff259380c4025bb740d8aba6972d351
+R 5651f6663bbd8efe3d630621e3f4b900
U dan
-Z fc00d731e9356a3f17b66c35cad599ad
+Z 822e7611ba479003f18b45bbb7ca820a