OLD | NEW |
1 /* | 1 /* |
2 ** 2014 May 31 | 2 ** 2014 May 31 |
3 ** | 3 ** |
4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
6 ** | 6 ** |
7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
10 ** | 10 ** |
(...skipping 22 matching lines...) Expand all Loading... |
33 void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*)); | 33 void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*)); |
34 void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*); | 34 void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*); |
35 #ifndef NDEBUG | 35 #ifndef NDEBUG |
36 #include <stdio.h> | 36 #include <stdio.h> |
37 void sqlite3Fts5ParserTrace(FILE*, char*); | 37 void sqlite3Fts5ParserTrace(FILE*, char*); |
38 #endif | 38 #endif |
39 | 39 |
40 | 40 |
41 struct Fts5Expr { | 41 struct Fts5Expr { |
42 Fts5Index *pIndex; | 42 Fts5Index *pIndex; |
| 43 Fts5Config *pConfig; |
43 Fts5ExprNode *pRoot; | 44 Fts5ExprNode *pRoot; |
44 int bDesc; /* Iterate in descending rowid order */ | 45 int bDesc; /* Iterate in descending rowid order */ |
45 int nPhrase; /* Number of phrases in expression */ | 46 int nPhrase; /* Number of phrases in expression */ |
46 Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */ | 47 Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */ |
47 }; | 48 }; |
48 | 49 |
49 /* | 50 /* |
50 ** eType: | 51 ** eType: |
51 ** Expression node type. Always one of: | 52 ** Expression node type. Always one of: |
52 ** | 53 ** |
53 ** FTS5_AND (nChild, apChild valid) | 54 ** FTS5_AND (nChild, apChild valid) |
54 ** FTS5_OR (nChild, apChild valid) | 55 ** FTS5_OR (nChild, apChild valid) |
55 ** FTS5_NOT (nChild, apChild valid) | 56 ** FTS5_NOT (nChild, apChild valid) |
56 ** FTS5_STRING (pNear valid) | 57 ** FTS5_STRING (pNear valid) |
57 ** FTS5_TERM (pNear valid) | 58 ** FTS5_TERM (pNear valid) |
58 */ | 59 */ |
59 struct Fts5ExprNode { | 60 struct Fts5ExprNode { |
60 int eType; /* Node type */ | 61 int eType; /* Node type */ |
61 int bEof; /* True at EOF */ | 62 int bEof; /* True at EOF */ |
62 int bNomatch; /* True if entry is not a match */ | 63 int bNomatch; /* True if entry is not a match */ |
63 | 64 |
| 65 /* Next method for this node. */ |
| 66 int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64); |
| 67 |
64 i64 iRowid; /* Current rowid */ | 68 i64 iRowid; /* Current rowid */ |
65 Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */ | 69 Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */ |
66 | 70 |
67 /* Child nodes. For a NOT node, this array always contains 2 entries. For | 71 /* Child nodes. For a NOT node, this array always contains 2 entries. For |
68 ** AND or OR nodes, it contains 2 or more entries. */ | 72 ** AND or OR nodes, it contains 2 or more entries. */ |
69 int nChild; /* Number of child nodes */ | 73 int nChild; /* Number of child nodes */ |
70 Fts5ExprNode *apChild[1]; /* Array of child nodes */ | 74 Fts5ExprNode *apChild[1]; /* Array of child nodes */ |
71 }; | 75 }; |
72 | 76 |
73 #define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING) | 77 #define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING) |
74 | 78 |
75 /* | 79 /* |
| 80 ** Invoke the xNext method of an Fts5ExprNode object. This macro should be |
| 81 ** used as if it has the same signature as the xNext() methods themselves. |
| 82 */ |
| 83 #define fts5ExprNodeNext(a,b,c,d) (b)->xNext((a), (b), (c), (d)) |
| 84 |
| 85 /* |
76 ** An instance of the following structure represents a single search term | 86 ** An instance of the following structure represents a single search term |
77 ** or term prefix. | 87 ** or term prefix. |
78 */ | 88 */ |
79 struct Fts5ExprTerm { | 89 struct Fts5ExprTerm { |
80 int bPrefix; /* True for a prefix term */ | 90 int bPrefix; /* True for a prefix term */ |
81 char *zTerm; /* nul-terminated term */ | 91 char *zTerm; /* nul-terminated term */ |
82 Fts5IndexIter *pIter; /* Iterator for this term */ | 92 Fts5IndexIter *pIter; /* Iterator for this term */ |
83 Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */ | 93 Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */ |
84 }; | 94 }; |
85 | 95 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 pToken->n = 1; | 160 pToken->n = 1; |
151 switch( *z ){ | 161 switch( *z ){ |
152 case '(': tok = FTS5_LP; break; | 162 case '(': tok = FTS5_LP; break; |
153 case ')': tok = FTS5_RP; break; | 163 case ')': tok = FTS5_RP; break; |
154 case '{': tok = FTS5_LCP; break; | 164 case '{': tok = FTS5_LCP; break; |
155 case '}': tok = FTS5_RCP; break; | 165 case '}': tok = FTS5_RCP; break; |
156 case ':': tok = FTS5_COLON; break; | 166 case ':': tok = FTS5_COLON; break; |
157 case ',': tok = FTS5_COMMA; break; | 167 case ',': tok = FTS5_COMMA; break; |
158 case '+': tok = FTS5_PLUS; break; | 168 case '+': tok = FTS5_PLUS; break; |
159 case '*': tok = FTS5_STAR; break; | 169 case '*': tok = FTS5_STAR; break; |
| 170 case '-': tok = FTS5_MINUS; break; |
160 case '\0': tok = FTS5_EOF; break; | 171 case '\0': tok = FTS5_EOF; break; |
161 | 172 |
162 case '"': { | 173 case '"': { |
163 const char *z2; | 174 const char *z2; |
164 tok = FTS5_STRING; | 175 tok = FTS5_STRING; |
165 | 176 |
166 for(z2=&z[1]; 1; z2++){ | 177 for(z2=&z[1]; 1; z2++){ |
167 if( z2[0]=='"' ){ | 178 if( z2[0]=='"' ){ |
168 z2++; | 179 z2++; |
169 if( z2[0]!='"' ) break; | 180 if( z2[0]!='"' ) break; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); | 237 }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); |
227 sqlite3Fts5ParserFree(pEngine, fts5ParseFree); | 238 sqlite3Fts5ParserFree(pEngine, fts5ParseFree); |
228 | 239 |
229 assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 ); | 240 assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 ); |
230 if( sParse.rc==SQLITE_OK ){ | 241 if( sParse.rc==SQLITE_OK ){ |
231 *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); | 242 *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); |
232 if( pNew==0 ){ | 243 if( pNew==0 ){ |
233 sParse.rc = SQLITE_NOMEM; | 244 sParse.rc = SQLITE_NOMEM; |
234 sqlite3Fts5ParseNodeFree(sParse.pExpr); | 245 sqlite3Fts5ParseNodeFree(sParse.pExpr); |
235 }else{ | 246 }else{ |
236 pNew->pRoot = sParse.pExpr; | 247 if( !sParse.pExpr ){ |
| 248 const int nByte = sizeof(Fts5ExprNode); |
| 249 pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte); |
| 250 if( pNew->pRoot ){ |
| 251 pNew->pRoot->bEof = 1; |
| 252 } |
| 253 }else{ |
| 254 pNew->pRoot = sParse.pExpr; |
| 255 } |
237 pNew->pIndex = 0; | 256 pNew->pIndex = 0; |
| 257 pNew->pConfig = pConfig; |
238 pNew->apExprPhrase = sParse.apPhrase; | 258 pNew->apExprPhrase = sParse.apPhrase; |
239 pNew->nPhrase = sParse.nPhrase; | 259 pNew->nPhrase = sParse.nPhrase; |
240 sParse.apPhrase = 0; | 260 sParse.apPhrase = 0; |
241 } | 261 } |
| 262 }else{ |
| 263 sqlite3Fts5ParseNodeFree(sParse.pExpr); |
242 } | 264 } |
243 | 265 |
244 sqlite3_free(sParse.apPhrase); | 266 sqlite3_free(sParse.apPhrase); |
245 *pzErr = sParse.zErr; | 267 *pzErr = sParse.zErr; |
246 return sParse.rc; | 268 return sParse.rc; |
247 } | 269 } |
248 | 270 |
249 /* | 271 /* |
250 ** Free the expression node object passed as the only argument. | 272 ** Free the expression node object passed as the only argument. |
251 */ | 273 */ |
(...skipping 25 matching lines...) Expand all Loading... |
277 */ | 299 */ |
278 static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ | 300 static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ |
279 i64 iRet = 0; | 301 i64 iRet = 0; |
280 int bRetValid = 0; | 302 int bRetValid = 0; |
281 Fts5ExprTerm *p; | 303 Fts5ExprTerm *p; |
282 | 304 |
283 assert( pTerm->pSynonym ); | 305 assert( pTerm->pSynonym ); |
284 assert( bDesc==0 || bDesc==1 ); | 306 assert( bDesc==0 || bDesc==1 ); |
285 for(p=pTerm; p; p=p->pSynonym){ | 307 for(p=pTerm; p; p=p->pSynonym){ |
286 if( 0==sqlite3Fts5IterEof(p->pIter) ){ | 308 if( 0==sqlite3Fts5IterEof(p->pIter) ){ |
287 i64 iRowid = sqlite3Fts5IterRowid(p->pIter); | 309 i64 iRowid = p->pIter->iRowid; |
288 if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){ | 310 if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){ |
289 iRet = iRowid; | 311 iRet = iRowid; |
290 bRetValid = 1; | 312 bRetValid = 1; |
291 } | 313 } |
292 } | 314 } |
293 } | 315 } |
294 | 316 |
295 if( pbEof && bRetValid==0 ) *pbEof = 1; | 317 if( pbEof && bRetValid==0 ) *pbEof = 1; |
296 return iRet; | 318 return iRet; |
297 } | 319 } |
298 | 320 |
299 /* | 321 /* |
300 ** Argument pTerm must be a synonym iterator. | 322 ** Argument pTerm must be a synonym iterator. |
301 */ | 323 */ |
302 static int fts5ExprSynonymPoslist( | 324 static int fts5ExprSynonymList( |
303 Fts5ExprTerm *pTerm, | 325 Fts5ExprTerm *pTerm, |
304 Fts5Colset *pColset, | |
305 i64 iRowid, | 326 i64 iRowid, |
306 int *pbDel, /* OUT: Caller should sqlite3_free(*pa) */ | 327 Fts5Buffer *pBuf, /* Use this buffer for space if required */ |
307 u8 **pa, int *pn | 328 u8 **pa, int *pn |
308 ){ | 329 ){ |
309 Fts5PoslistReader aStatic[4]; | 330 Fts5PoslistReader aStatic[4]; |
310 Fts5PoslistReader *aIter = aStatic; | 331 Fts5PoslistReader *aIter = aStatic; |
311 int nIter = 0; | 332 int nIter = 0; |
312 int nAlloc = 4; | 333 int nAlloc = 4; |
313 int rc = SQLITE_OK; | 334 int rc = SQLITE_OK; |
314 Fts5ExprTerm *p; | 335 Fts5ExprTerm *p; |
315 | 336 |
316 assert( pTerm->pSynonym ); | 337 assert( pTerm->pSynonym ); |
317 for(p=pTerm; p; p=p->pSynonym){ | 338 for(p=pTerm; p; p=p->pSynonym){ |
318 Fts5IndexIter *pIter = p->pIter; | 339 Fts5IndexIter *pIter = p->pIter; |
319 if( sqlite3Fts5IterEof(pIter)==0 && sqlite3Fts5IterRowid(pIter)==iRowid ){ | 340 if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){ |
320 const u8 *a; | 341 if( pIter->nData==0 ) continue; |
321 int n; | |
322 i64 dummy; | |
323 rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy); | |
324 if( rc!=SQLITE_OK ) goto synonym_poslist_out; | |
325 if( nIter==nAlloc ){ | 342 if( nIter==nAlloc ){ |
326 int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; | 343 int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; |
327 Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte); | 344 Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte); |
328 if( aNew==0 ){ | 345 if( aNew==0 ){ |
329 rc = SQLITE_NOMEM; | 346 rc = SQLITE_NOMEM; |
330 goto synonym_poslist_out; | 347 goto synonym_poslist_out; |
331 } | 348 } |
332 memcpy(aNew, aIter, sizeof(Fts5PoslistReader) * nIter); | 349 memcpy(aNew, aIter, sizeof(Fts5PoslistReader) * nIter); |
333 nAlloc = nAlloc*2; | 350 nAlloc = nAlloc*2; |
334 if( aIter!=aStatic ) sqlite3_free(aIter); | 351 if( aIter!=aStatic ) sqlite3_free(aIter); |
335 aIter = aNew; | 352 aIter = aNew; |
336 } | 353 } |
337 sqlite3Fts5PoslistReaderInit(a, n, &aIter[nIter]); | 354 sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &aIter[nIter]); |
338 assert( aIter[nIter].bEof==0 ); | 355 assert( aIter[nIter].bEof==0 ); |
339 nIter++; | 356 nIter++; |
340 } | 357 } |
341 } | 358 } |
342 | 359 |
343 assert( *pbDel==0 ); | |
344 if( nIter==1 ){ | 360 if( nIter==1 ){ |
345 *pa = (u8*)aIter[0].a; | 361 *pa = (u8*)aIter[0].a; |
346 *pn = aIter[0].n; | 362 *pn = aIter[0].n; |
347 }else{ | 363 }else{ |
348 Fts5PoslistWriter writer = {0}; | 364 Fts5PoslistWriter writer = {0}; |
349 Fts5Buffer buf = {0,0,0}; | |
350 i64 iPrev = -1; | 365 i64 iPrev = -1; |
| 366 fts5BufferZero(pBuf); |
351 while( 1 ){ | 367 while( 1 ){ |
352 int i; | 368 int i; |
353 i64 iMin = FTS5_LARGEST_INT64; | 369 i64 iMin = FTS5_LARGEST_INT64; |
354 for(i=0; i<nIter; i++){ | 370 for(i=0; i<nIter; i++){ |
355 if( aIter[i].bEof==0 ){ | 371 if( aIter[i].bEof==0 ){ |
356 if( aIter[i].iPos==iPrev ){ | 372 if( aIter[i].iPos==iPrev ){ |
357 if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) continue; | 373 if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) continue; |
358 } | 374 } |
359 if( aIter[i].iPos<iMin ){ | 375 if( aIter[i].iPos<iMin ){ |
360 iMin = aIter[i].iPos; | 376 iMin = aIter[i].iPos; |
361 } | 377 } |
362 } | 378 } |
363 } | 379 } |
364 if( iMin==FTS5_LARGEST_INT64 || rc!=SQLITE_OK ) break; | 380 if( iMin==FTS5_LARGEST_INT64 || rc!=SQLITE_OK ) break; |
365 rc = sqlite3Fts5PoslistWriterAppend(&buf, &writer, iMin); | 381 rc = sqlite3Fts5PoslistWriterAppend(pBuf, &writer, iMin); |
366 iPrev = iMin; | 382 iPrev = iMin; |
367 } | 383 } |
368 if( rc ){ | 384 if( rc==SQLITE_OK ){ |
369 sqlite3_free(buf.p); | 385 *pa = pBuf->p; |
370 }else{ | 386 *pn = pBuf->n; |
371 *pa = buf.p; | |
372 *pn = buf.n; | |
373 *pbDel = 1; | |
374 } | 387 } |
375 } | 388 } |
376 | 389 |
377 synonym_poslist_out: | 390 synonym_poslist_out: |
378 if( aIter!=aStatic ) sqlite3_free(aIter); | 391 if( aIter!=aStatic ) sqlite3_free(aIter); |
379 return rc; | 392 return rc; |
380 } | 393 } |
381 | 394 |
382 | 395 |
383 /* | 396 /* |
384 ** All individual term iterators in pPhrase are guaranteed to be valid and | 397 ** All individual term iterators in pPhrase are guaranteed to be valid and |
385 ** pointing to the same rowid when this function is called. This function | 398 ** pointing to the same rowid when this function is called. This function |
386 ** checks if the current rowid really is a match, and if so populates | 399 ** checks if the current rowid really is a match, and if so populates |
387 ** the pPhrase->poslist buffer accordingly. Output parameter *pbMatch | 400 ** the pPhrase->poslist buffer accordingly. Output parameter *pbMatch |
388 ** is set to true if this is really a match, or false otherwise. | 401 ** is set to true if this is really a match, or false otherwise. |
389 ** | 402 ** |
390 ** SQLITE_OK is returned if an error occurs, or an SQLite error code | 403 ** SQLITE_OK is returned if an error occurs, or an SQLite error code |
391 ** otherwise. It is not considered an error code if the current rowid is | 404 ** otherwise. It is not considered an error code if the current rowid is |
392 ** not a match. | 405 ** not a match. |
393 */ | 406 */ |
394 static int fts5ExprPhraseIsMatch( | 407 static int fts5ExprPhraseIsMatch( |
395 Fts5ExprNode *pNode, /* Node pPhrase belongs to */ | 408 Fts5ExprNode *pNode, /* Node pPhrase belongs to */ |
396 Fts5Colset *pColset, /* Restrict matches to these columns */ | |
397 Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */ | 409 Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */ |
398 int *pbMatch /* OUT: Set to true if really a match */ | 410 int *pbMatch /* OUT: Set to true if really a match */ |
399 ){ | 411 ){ |
400 Fts5PoslistWriter writer = {0}; | 412 Fts5PoslistWriter writer = {0}; |
401 Fts5PoslistReader aStatic[4]; | 413 Fts5PoslistReader aStatic[4]; |
402 Fts5PoslistReader *aIter = aStatic; | 414 Fts5PoslistReader *aIter = aStatic; |
403 int i; | 415 int i; |
404 int rc = SQLITE_OK; | 416 int rc = SQLITE_OK; |
405 | 417 |
406 fts5BufferZero(&pPhrase->poslist); | 418 fts5BufferZero(&pPhrase->poslist); |
407 | 419 |
408 /* If the aStatic[] array is not large enough, allocate a large array | 420 /* If the aStatic[] array is not large enough, allocate a large array |
409 ** using sqlite3_malloc(). This approach could be improved upon. */ | 421 ** using sqlite3_malloc(). This approach could be improved upon. */ |
410 if( pPhrase->nTerm>(int)ArraySize(aStatic) ){ | 422 if( pPhrase->nTerm>ArraySize(aStatic) ){ |
411 int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; | 423 int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; |
412 aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte); | 424 aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte); |
413 if( !aIter ) return SQLITE_NOMEM; | 425 if( !aIter ) return SQLITE_NOMEM; |
414 } | 426 } |
415 memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm); | 427 memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm); |
416 | 428 |
417 /* Initialize a term iterator for each term in the phrase */ | 429 /* Initialize a term iterator for each term in the phrase */ |
418 for(i=0; i<pPhrase->nTerm; i++){ | 430 for(i=0; i<pPhrase->nTerm; i++){ |
419 Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; | 431 Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; |
420 i64 dummy; | |
421 int n = 0; | 432 int n = 0; |
422 int bFlag = 0; | 433 int bFlag = 0; |
423 const u8 *a = 0; | 434 u8 *a = 0; |
424 if( pTerm->pSynonym ){ | 435 if( pTerm->pSynonym ){ |
425 rc = fts5ExprSynonymPoslist( | 436 Fts5Buffer buf = {0, 0, 0}; |
426 pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n | 437 rc = fts5ExprSynonymList(pTerm, pNode->iRowid, &buf, &a, &n); |
427 ); | 438 if( rc ){ |
| 439 sqlite3_free(a); |
| 440 goto ismatch_out; |
| 441 } |
| 442 if( a==buf.p ) bFlag = 1; |
428 }else{ | 443 }else{ |
429 rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy); | 444 a = (u8*)pTerm->pIter->pData; |
| 445 n = pTerm->pIter->nData; |
430 } | 446 } |
431 if( rc!=SQLITE_OK ) goto ismatch_out; | |
432 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]); | 447 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]); |
433 aIter[i].bFlag = (u8)bFlag; | 448 aIter[i].bFlag = (u8)bFlag; |
434 if( aIter[i].bEof ) goto ismatch_out; | 449 if( aIter[i].bEof ) goto ismatch_out; |
435 } | 450 } |
436 | 451 |
437 while( 1 ){ | 452 while( 1 ){ |
438 int bMatch; | 453 int bMatch; |
439 i64 iPos = aIter[0].iPos; | 454 i64 iPos = aIter[0].iPos; |
440 do { | 455 do { |
441 bMatch = 1; | 456 bMatch = 1; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 const u8 *a, int n, /* Buffer to read position list from */ | 508 const u8 *a, int n, /* Buffer to read position list from */ |
494 Fts5LookaheadReader *p /* Iterator object to initialize */ | 509 Fts5LookaheadReader *p /* Iterator object to initialize */ |
495 ){ | 510 ){ |
496 memset(p, 0, sizeof(Fts5LookaheadReader)); | 511 memset(p, 0, sizeof(Fts5LookaheadReader)); |
497 p->a = a; | 512 p->a = a; |
498 p->n = n; | 513 p->n = n; |
499 fts5LookaheadReaderNext(p); | 514 fts5LookaheadReaderNext(p); |
500 return fts5LookaheadReaderNext(p); | 515 return fts5LookaheadReaderNext(p); |
501 } | 516 } |
502 | 517 |
503 #if 0 | |
504 static int fts5LookaheadReaderEof(Fts5LookaheadReader *p){ | |
505 return (p->iPos==FTS5_LOOKAHEAD_EOF); | |
506 } | |
507 #endif | |
508 | |
509 typedef struct Fts5NearTrimmer Fts5NearTrimmer; | 518 typedef struct Fts5NearTrimmer Fts5NearTrimmer; |
510 struct Fts5NearTrimmer { | 519 struct Fts5NearTrimmer { |
511 Fts5LookaheadReader reader; /* Input iterator */ | 520 Fts5LookaheadReader reader; /* Input iterator */ |
512 Fts5PoslistWriter writer; /* Writer context */ | 521 Fts5PoslistWriter writer; /* Writer context */ |
513 Fts5Buffer *pOut; /* Output poslist */ | 522 Fts5Buffer *pOut; /* Output poslist */ |
514 }; | 523 }; |
515 | 524 |
516 /* | 525 /* |
517 ** The near-set object passed as the first argument contains more than | 526 ** The near-set object passed as the first argument contains more than |
518 ** one phrase. All phrases currently point to the same row. The | 527 ** one phrase. All phrases currently point to the same row. The |
(...skipping 17 matching lines...) Expand all Loading... |
536 Fts5ExprPhrase **apPhrase = pNear->apPhrase; | 545 Fts5ExprPhrase **apPhrase = pNear->apPhrase; |
537 | 546 |
538 int i; | 547 int i; |
539 int rc = *pRc; | 548 int rc = *pRc; |
540 int bMatch; | 549 int bMatch; |
541 | 550 |
542 assert( pNear->nPhrase>1 ); | 551 assert( pNear->nPhrase>1 ); |
543 | 552 |
544 /* If the aStatic[] array is not large enough, allocate a large array | 553 /* If the aStatic[] array is not large enough, allocate a large array |
545 ** using sqlite3_malloc(). This approach could be improved upon. */ | 554 ** using sqlite3_malloc(). This approach could be improved upon. */ |
546 if( pNear->nPhrase>(int)ArraySize(aStatic) ){ | 555 if( pNear->nPhrase>ArraySize(aStatic) ){ |
547 int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; | 556 int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; |
548 a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte); | 557 a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte); |
549 }else{ | 558 }else{ |
550 memset(aStatic, 0, sizeof(aStatic)); | 559 memset(aStatic, 0, sizeof(aStatic)); |
551 } | 560 } |
552 if( rc!=SQLITE_OK ){ | 561 if( rc!=SQLITE_OK ){ |
553 *pRc = rc; | 562 *pRc = rc; |
554 return 0; | 563 return 0; |
555 } | 564 } |
556 | 565 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
614 | 623 |
615 ismatch_out: { | 624 ismatch_out: { |
616 int bRet = a[0].pOut->n>0; | 625 int bRet = a[0].pOut->n>0; |
617 *pRc = rc; | 626 *pRc = rc; |
618 if( a!=aStatic ) sqlite3_free(a); | 627 if( a!=aStatic ) sqlite3_free(a); |
619 return bRet; | 628 return bRet; |
620 } | 629 } |
621 } | 630 } |
622 | 631 |
623 /* | 632 /* |
624 ** Advance the first term iterator in the first phrase of pNear. Set output | |
625 ** variable *pbEof to true if it reaches EOF or if an error occurs. | |
626 ** | |
627 ** Return SQLITE_OK if successful, or an SQLite error code if an error | |
628 ** occurs. | |
629 */ | |
630 static int fts5ExprNearAdvanceFirst( | |
631 Fts5Expr *pExpr, /* Expression pPhrase belongs to */ | |
632 Fts5ExprNode *pNode, /* FTS5_STRING or FTS5_TERM node */ | |
633 int bFromValid, | |
634 i64 iFrom | |
635 ){ | |
636 Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0]; | |
637 int rc = SQLITE_OK; | |
638 | |
639 if( pTerm->pSynonym ){ | |
640 int bEof = 1; | |
641 Fts5ExprTerm *p; | |
642 | |
643 /* Find the firstest rowid any synonym points to. */ | |
644 i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0); | |
645 | |
646 /* Advance each iterator that currently points to iRowid. Or, if iFrom | |
647 ** is valid - each iterator that points to a rowid before iFrom. */ | |
648 for(p=pTerm; p; p=p->pSynonym){ | |
649 if( sqlite3Fts5IterEof(p->pIter)==0 ){ | |
650 i64 ii = sqlite3Fts5IterRowid(p->pIter); | |
651 if( ii==iRowid | |
652 || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) | |
653 ){ | |
654 if( bFromValid ){ | |
655 rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom); | |
656 }else{ | |
657 rc = sqlite3Fts5IterNext(p->pIter); | |
658 } | |
659 if( rc!=SQLITE_OK ) break; | |
660 if( sqlite3Fts5IterEof(p->pIter)==0 ){ | |
661 bEof = 0; | |
662 } | |
663 }else{ | |
664 bEof = 0; | |
665 } | |
666 } | |
667 } | |
668 | |
669 /* Set the EOF flag if either all synonym iterators are at EOF or an | |
670 ** error has occurred. */ | |
671 pNode->bEof = (rc || bEof); | |
672 }else{ | |
673 Fts5IndexIter *pIter = pTerm->pIter; | |
674 | |
675 assert( Fts5NodeIsString(pNode) ); | |
676 if( bFromValid ){ | |
677 rc = sqlite3Fts5IterNextFrom(pIter, iFrom); | |
678 }else{ | |
679 rc = sqlite3Fts5IterNext(pIter); | |
680 } | |
681 | |
682 pNode->bEof = (rc || sqlite3Fts5IterEof(pIter)); | |
683 } | |
684 | |
685 return rc; | |
686 } | |
687 | |
688 /* | |
689 ** Advance iterator pIter until it points to a value equal to or laster | 633 ** Advance iterator pIter until it points to a value equal to or laster |
690 ** than the initial value of *piLast. If this means the iterator points | 634 ** than the initial value of *piLast. If this means the iterator points |
691 ** to a value laster than *piLast, update *piLast to the new lastest value. | 635 ** to a value laster than *piLast, update *piLast to the new lastest value. |
692 ** | 636 ** |
693 ** If the iterator reaches EOF, set *pbEof to true before returning. If | 637 ** If the iterator reaches EOF, set *pbEof to true before returning. If |
694 ** an error occurs, set *pRc to an error code. If either *pbEof or *pRc | 638 ** an error occurs, set *pRc to an error code. If either *pbEof or *pRc |
695 ** are set, return a non-zero value. Otherwise, return zero. | 639 ** are set, return a non-zero value. Otherwise, return zero. |
696 */ | 640 */ |
697 static int fts5ExprAdvanceto( | 641 static int fts5ExprAdvanceto( |
698 Fts5IndexIter *pIter, /* Iterator to advance */ | 642 Fts5IndexIter *pIter, /* Iterator to advance */ |
699 int bDesc, /* True if iterator is "rowid DESC" */ | 643 int bDesc, /* True if iterator is "rowid DESC" */ |
700 i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ | 644 i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ |
701 int *pRc, /* OUT: Error code */ | 645 int *pRc, /* OUT: Error code */ |
702 int *pbEof /* OUT: Set to true if EOF */ | 646 int *pbEof /* OUT: Set to true if EOF */ |
703 ){ | 647 ){ |
704 i64 iLast = *piLast; | 648 i64 iLast = *piLast; |
705 i64 iRowid; | 649 i64 iRowid; |
706 | 650 |
707 iRowid = sqlite3Fts5IterRowid(pIter); | 651 iRowid = pIter->iRowid; |
708 if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){ | 652 if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){ |
709 int rc = sqlite3Fts5IterNextFrom(pIter, iLast); | 653 int rc = sqlite3Fts5IterNextFrom(pIter, iLast); |
710 if( rc || sqlite3Fts5IterEof(pIter) ){ | 654 if( rc || sqlite3Fts5IterEof(pIter) ){ |
711 *pRc = rc; | 655 *pRc = rc; |
712 *pbEof = 1; | 656 *pbEof = 1; |
713 return 1; | 657 return 1; |
714 } | 658 } |
715 iRowid = sqlite3Fts5IterRowid(pIter); | 659 iRowid = pIter->iRowid; |
716 assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) ); | 660 assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) ); |
717 } | 661 } |
718 *piLast = iRowid; | 662 *piLast = iRowid; |
719 | 663 |
720 return 0; | 664 return 0; |
721 } | 665 } |
722 | 666 |
723 static int fts5ExprSynonymAdvanceto( | 667 static int fts5ExprSynonymAdvanceto( |
724 Fts5ExprTerm *pTerm, /* Term iterator to advance */ | 668 Fts5ExprTerm *pTerm, /* Term iterator to advance */ |
725 int bDesc, /* True if iterator is "rowid DESC" */ | 669 int bDesc, /* True if iterator is "rowid DESC" */ |
726 i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ | 670 i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ |
727 int *pRc /* OUT: Error code */ | 671 int *pRc /* OUT: Error code */ |
728 ){ | 672 ){ |
729 int rc = SQLITE_OK; | 673 int rc = SQLITE_OK; |
730 i64 iLast = *piLast; | 674 i64 iLast = *piLast; |
731 Fts5ExprTerm *p; | 675 Fts5ExprTerm *p; |
732 int bEof = 0; | 676 int bEof = 0; |
733 | 677 |
734 for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){ | 678 for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){ |
735 if( sqlite3Fts5IterEof(p->pIter)==0 ){ | 679 if( sqlite3Fts5IterEof(p->pIter)==0 ){ |
736 i64 iRowid = sqlite3Fts5IterRowid(p->pIter); | 680 i64 iRowid = p->pIter->iRowid; |
737 if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){ | 681 if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){ |
738 rc = sqlite3Fts5IterNextFrom(p->pIter, iLast); | 682 rc = sqlite3Fts5IterNextFrom(p->pIter, iLast); |
739 } | 683 } |
740 } | 684 } |
741 } | 685 } |
742 | 686 |
743 if( rc!=SQLITE_OK ){ | 687 if( rc!=SQLITE_OK ){ |
744 *pRc = rc; | 688 *pRc = rc; |
745 bEof = 1; | 689 bEof = 1; |
746 }else{ | 690 }else{ |
747 *piLast = fts5ExprSynonymRowid(pTerm, bDesc, &bEof); | 691 *piLast = fts5ExprSynonymRowid(pTerm, bDesc, &bEof); |
748 } | 692 } |
749 return bEof; | 693 return bEof; |
750 } | 694 } |
751 | 695 |
752 | 696 |
753 static int fts5ExprNearTest( | 697 static int fts5ExprNearTest( |
754 int *pRc, | 698 int *pRc, |
755 Fts5Expr *pExpr, /* Expression that pNear is a part of */ | 699 Fts5Expr *pExpr, /* Expression that pNear is a part of */ |
756 Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */ | 700 Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */ |
757 ){ | 701 ){ |
758 Fts5ExprNearset *pNear = pNode->pNear; | 702 Fts5ExprNearset *pNear = pNode->pNear; |
759 int rc = *pRc; | 703 int rc = *pRc; |
| 704 |
| 705 if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){ |
| 706 Fts5ExprTerm *pTerm; |
| 707 Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; |
| 708 pPhrase->poslist.n = 0; |
| 709 for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ |
| 710 Fts5IndexIter *pIter = pTerm->pIter; |
| 711 if( sqlite3Fts5IterEof(pIter)==0 ){ |
| 712 if( pIter->iRowid==pNode->iRowid && pIter->nData>0 ){ |
| 713 pPhrase->poslist.n = 1; |
| 714 } |
| 715 } |
| 716 } |
| 717 return pPhrase->poslist.n; |
| 718 }else{ |
| 719 int i; |
| 720 |
| 721 /* Check that each phrase in the nearset matches the current row. |
| 722 ** Populate the pPhrase->poslist buffers at the same time. If any |
| 723 ** phrase is not a match, break out of the loop early. */ |
| 724 for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){ |
| 725 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; |
| 726 if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){ |
| 727 int bMatch = 0; |
| 728 rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch); |
| 729 if( bMatch==0 ) break; |
| 730 }else{ |
| 731 Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; |
| 732 fts5BufferSet(&rc, &pPhrase->poslist, pIter->nData, pIter->pData); |
| 733 } |
| 734 } |
| 735 |
| 736 *pRc = rc; |
| 737 if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){ |
| 738 return 1; |
| 739 } |
| 740 return 0; |
| 741 } |
| 742 } |
| 743 |
| 744 |
| 745 /* |
| 746 ** Initialize all term iterators in the pNear object. If any term is found |
| 747 ** to match no documents at all, return immediately without initializing any |
| 748 ** further iterators. |
| 749 ** |
| 750 ** If an error occurs, return an SQLite error code. Otherwise, return |
| 751 ** SQLITE_OK. It is not considered an error if some term matches zero |
| 752 ** documents. |
| 753 */ |
| 754 static int fts5ExprNearInitAll( |
| 755 Fts5Expr *pExpr, |
| 756 Fts5ExprNode *pNode |
| 757 ){ |
| 758 Fts5ExprNearset *pNear = pNode->pNear; |
760 int i; | 759 int i; |
761 | 760 |
762 /* Check that each phrase in the nearset matches the current row. | 761 assert( pNode->bNomatch==0 ); |
763 ** Populate the pPhrase->poslist buffers at the same time. If any | 762 for(i=0; i<pNear->nPhrase; i++){ |
764 ** phrase is not a match, break out of the loop early. */ | |
765 for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){ | |
766 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; | 763 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; |
767 if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){ | 764 if( pPhrase->nTerm==0 ){ |
768 int bMatch = 0; | 765 pNode->bEof = 1; |
769 rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch); | 766 return SQLITE_OK; |
770 if( bMatch==0 ) break; | |
771 }else{ | 767 }else{ |
772 rc = sqlite3Fts5IterPoslistBuffer( | 768 int j; |
773 pPhrase->aTerm[0].pIter, &pPhrase->poslist | 769 for(j=0; j<pPhrase->nTerm; j++){ |
774 ); | 770 Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; |
| 771 Fts5ExprTerm *p; |
| 772 int bHit = 0; |
| 773 |
| 774 for(p=pTerm; p; p=p->pSynonym){ |
| 775 int rc; |
| 776 if( p->pIter ){ |
| 777 sqlite3Fts5IterClose(p->pIter); |
| 778 p->pIter = 0; |
| 779 } |
| 780 rc = sqlite3Fts5IndexQuery( |
| 781 pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm), |
| 782 (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | |
| 783 (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), |
| 784 pNear->pColset, |
| 785 &p->pIter |
| 786 ); |
| 787 assert( (rc==SQLITE_OK)==(p->pIter!=0) ); |
| 788 if( rc!=SQLITE_OK ) return rc; |
| 789 if( 0==sqlite3Fts5IterEof(p->pIter) ){ |
| 790 bHit = 1; |
| 791 } |
| 792 } |
| 793 |
| 794 if( bHit==0 ){ |
| 795 pNode->bEof = 1; |
| 796 return SQLITE_OK; |
| 797 } |
| 798 } |
775 } | 799 } |
776 } | 800 } |
777 | 801 |
778 *pRc = rc; | 802 pNode->bEof = 0; |
779 if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){ | 803 return SQLITE_OK; |
780 return 1; | |
781 } | |
782 | |
783 return 0; | |
784 } | |
785 | |
786 static int fts5ExprTokenTest( | |
787 Fts5Expr *pExpr, /* Expression that pNear is a part of */ | |
788 Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */ | |
789 ){ | |
790 /* As this "NEAR" object is actually a single phrase that consists | |
791 ** of a single term only, grab pointers into the poslist managed by the | |
792 ** fts5_index.c iterator object. This is much faster than synthesizing | |
793 ** a new poslist the way we have to for more complicated phrase or NEAR | |
794 ** expressions. */ | |
795 Fts5ExprNearset *pNear = pNode->pNear; | |
796 Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; | |
797 Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; | |
798 Fts5Colset *pColset = pNear->pColset; | |
799 int rc; | |
800 | |
801 assert( pNode->eType==FTS5_TERM ); | |
802 assert( pNear->nPhrase==1 && pPhrase->nTerm==1 ); | |
803 assert( pPhrase->aTerm[0].pSynonym==0 ); | |
804 | |
805 rc = sqlite3Fts5IterPoslist(pIter, pColset, | |
806 (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid | |
807 ); | |
808 pNode->bNomatch = (pPhrase->poslist.n==0); | |
809 return rc; | |
810 } | 804 } |
811 | 805 |
812 /* | 806 /* |
| 807 ** If pExpr is an ASC iterator, this function returns a value with the |
| 808 ** same sign as: |
| 809 ** |
| 810 ** (iLhs - iRhs) |
| 811 ** |
| 812 ** Otherwise, if this is a DESC iterator, the opposite is returned: |
| 813 ** |
| 814 ** (iRhs - iLhs) |
| 815 */ |
| 816 static int fts5RowidCmp( |
| 817 Fts5Expr *pExpr, |
| 818 i64 iLhs, |
| 819 i64 iRhs |
| 820 ){ |
| 821 assert( pExpr->bDesc==0 || pExpr->bDesc==1 ); |
| 822 if( pExpr->bDesc==0 ){ |
| 823 if( iLhs<iRhs ) return -1; |
| 824 return (iLhs > iRhs); |
| 825 }else{ |
| 826 if( iLhs>iRhs ) return -1; |
| 827 return (iLhs < iRhs); |
| 828 } |
| 829 } |
| 830 |
| 831 static void fts5ExprSetEof(Fts5ExprNode *pNode){ |
| 832 int i; |
| 833 pNode->bEof = 1; |
| 834 pNode->bNomatch = 0; |
| 835 for(i=0; i<pNode->nChild; i++){ |
| 836 fts5ExprSetEof(pNode->apChild[i]); |
| 837 } |
| 838 } |
| 839 |
| 840 static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){ |
| 841 if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){ |
| 842 Fts5ExprNearset *pNear = pNode->pNear; |
| 843 int i; |
| 844 for(i=0; i<pNear->nPhrase; i++){ |
| 845 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; |
| 846 pPhrase->poslist.n = 0; |
| 847 } |
| 848 }else{ |
| 849 int i; |
| 850 for(i=0; i<pNode->nChild; i++){ |
| 851 fts5ExprNodeZeroPoslist(pNode->apChild[i]); |
| 852 } |
| 853 } |
| 854 } |
| 855 |
| 856 |
| 857 |
| 858 /* |
| 859 ** Compare the values currently indicated by the two nodes as follows: |
| 860 ** |
| 861 ** res = (*p1) - (*p2) |
| 862 ** |
| 863 ** Nodes that point to values that come later in the iteration order are |
| 864 ** considered to be larger. Nodes at EOF are the largest of all. |
| 865 ** |
| 866 ** This means that if the iteration order is ASC, then numerically larger |
| 867 ** rowids are considered larger. Or if it is the default DESC, numerically |
| 868 ** smaller rowids are larger. |
| 869 */ |
| 870 static int fts5NodeCompare( |
| 871 Fts5Expr *pExpr, |
| 872 Fts5ExprNode *p1, |
| 873 Fts5ExprNode *p2 |
| 874 ){ |
| 875 if( p2->bEof ) return -1; |
| 876 if( p1->bEof ) return +1; |
| 877 return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid); |
| 878 } |
| 879 |
| 880 /* |
813 ** All individual term iterators in pNear are guaranteed to be valid when | 881 ** All individual term iterators in pNear are guaranteed to be valid when |
814 ** this function is called. This function checks if all term iterators | 882 ** this function is called. This function checks if all term iterators |
815 ** point to the same rowid, and if not, advances them until they do. | 883 ** point to the same rowid, and if not, advances them until they do. |
816 ** If an EOF is reached before this happens, *pbEof is set to true before | 884 ** If an EOF is reached before this happens, *pbEof is set to true before |
817 ** returning. | 885 ** returning. |
818 ** | 886 ** |
819 ** SQLITE_OK is returned if an error occurs, or an SQLite error code | 887 ** SQLITE_OK is returned if an error occurs, or an SQLite error code |
820 ** otherwise. It is not considered an error code if an iterator reaches | 888 ** otherwise. It is not considered an error code if an iterator reaches |
821 ** EOF. | 889 ** EOF. |
822 */ | 890 */ |
823 static int fts5ExprNearNextMatch( | 891 static int fts5ExprNodeTest_STRING( |
824 Fts5Expr *pExpr, /* Expression pPhrase belongs to */ | 892 Fts5Expr *pExpr, /* Expression pPhrase belongs to */ |
825 Fts5ExprNode *pNode | 893 Fts5ExprNode *pNode |
826 ){ | 894 ){ |
827 Fts5ExprNearset *pNear = pNode->pNear; | 895 Fts5ExprNearset *pNear = pNode->pNear; |
828 Fts5ExprPhrase *pLeft = pNear->apPhrase[0]; | 896 Fts5ExprPhrase *pLeft = pNear->apPhrase[0]; |
829 int rc = SQLITE_OK; | 897 int rc = SQLITE_OK; |
830 i64 iLast; /* Lastest rowid any iterator points to */ | 898 i64 iLast; /* Lastest rowid any iterator points to */ |
831 int i, j; /* Phrase and token index, respectively */ | 899 int i, j; /* Phrase and token index, respectively */ |
832 int bMatch; /* True if all terms are at the same rowid */ | 900 int bMatch; /* True if all terms are at the same rowid */ |
833 const int bDesc = pExpr->bDesc; | 901 const int bDesc = pExpr->bDesc; |
834 | 902 |
835 /* Check that this node should not be FTS5_TERM */ | 903 /* Check that this node should not be FTS5_TERM */ |
836 assert( pNear->nPhrase>1 | 904 assert( pNear->nPhrase>1 |
837 || pNear->apPhrase[0]->nTerm>1 | 905 || pNear->apPhrase[0]->nTerm>1 |
838 || pNear->apPhrase[0]->aTerm[0].pSynonym | 906 || pNear->apPhrase[0]->aTerm[0].pSynonym |
839 ); | 907 ); |
840 | 908 |
841 /* Initialize iLast, the "lastest" rowid any iterator points to. If the | 909 /* Initialize iLast, the "lastest" rowid any iterator points to. If the |
842 ** iterator skips through rowids in the default ascending order, this means | 910 ** iterator skips through rowids in the default ascending order, this means |
843 ** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it | 911 ** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it |
844 ** means the minimum rowid. */ | 912 ** means the minimum rowid. */ |
845 if( pLeft->aTerm[0].pSynonym ){ | 913 if( pLeft->aTerm[0].pSynonym ){ |
846 iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0); | 914 iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0); |
847 }else{ | 915 }else{ |
848 iLast = sqlite3Fts5IterRowid(pLeft->aTerm[0].pIter); | 916 iLast = pLeft->aTerm[0].pIter->iRowid; |
849 } | 917 } |
850 | 918 |
851 do { | 919 do { |
852 bMatch = 1; | 920 bMatch = 1; |
853 for(i=0; i<pNear->nPhrase; i++){ | 921 for(i=0; i<pNear->nPhrase; i++){ |
854 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; | 922 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; |
855 for(j=0; j<pPhrase->nTerm; j++){ | 923 for(j=0; j<pPhrase->nTerm; j++){ |
856 Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; | 924 Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; |
857 if( pTerm->pSynonym ){ | 925 if( pTerm->pSynonym ){ |
858 i64 iRowid = fts5ExprSynonymRowid(pTerm, bDesc, 0); | 926 i64 iRowid = fts5ExprSynonymRowid(pTerm, bDesc, 0); |
859 if( iRowid==iLast ) continue; | 927 if( iRowid==iLast ) continue; |
860 bMatch = 0; | 928 bMatch = 0; |
861 if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){ | 929 if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){ |
| 930 pNode->bNomatch = 0; |
862 pNode->bEof = 1; | 931 pNode->bEof = 1; |
863 return rc; | 932 return rc; |
864 } | 933 } |
865 }else{ | 934 }else{ |
866 Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; | 935 Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; |
867 i64 iRowid = sqlite3Fts5IterRowid(pIter); | 936 if( pIter->iRowid==iLast || pIter->bEof ) continue; |
868 if( iRowid==iLast ) continue; | |
869 bMatch = 0; | 937 bMatch = 0; |
870 if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){ | 938 if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){ |
871 return rc; | 939 return rc; |
872 } | 940 } |
873 } | 941 } |
874 } | 942 } |
875 } | 943 } |
876 }while( bMatch==0 ); | 944 }while( bMatch==0 ); |
877 | 945 |
878 pNode->iRowid = iLast; | 946 pNode->iRowid = iLast; |
879 pNode->bNomatch = (0==fts5ExprNearTest(&rc, pExpr, pNode)); | 947 pNode->bNomatch = ((0==fts5ExprNearTest(&rc, pExpr, pNode)) && rc==SQLITE_OK); |
| 948 assert( pNode->bEof==0 || pNode->bNomatch==0 ); |
880 | 949 |
881 return rc; | 950 return rc; |
882 } | 951 } |
883 | 952 |
884 /* | 953 /* |
885 ** Initialize all term iterators in the pNear object. If any term is found | 954 ** Advance the first term iterator in the first phrase of pNear. Set output |
886 ** to match no documents at all, return immediately without initializing any | 955 ** variable *pbEof to true if it reaches EOF or if an error occurs. |
887 ** further iterators. | 956 ** |
| 957 ** Return SQLITE_OK if successful, or an SQLite error code if an error |
| 958 ** occurs. |
888 */ | 959 */ |
889 static int fts5ExprNearInitAll( | 960 static int fts5ExprNodeNext_STRING( |
890 Fts5Expr *pExpr, | 961 Fts5Expr *pExpr, /* Expression pPhrase belongs to */ |
891 Fts5ExprNode *pNode | 962 Fts5ExprNode *pNode, /* FTS5_STRING or FTS5_TERM node */ |
| 963 int bFromValid, |
| 964 i64 iFrom |
892 ){ | 965 ){ |
893 Fts5ExprNearset *pNear = pNode->pNear; | 966 Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0]; |
894 int i, j; | |
895 int rc = SQLITE_OK; | 967 int rc = SQLITE_OK; |
896 | 968 |
897 for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){ | 969 pNode->bNomatch = 0; |
898 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; | 970 if( pTerm->pSynonym ){ |
899 for(j=0; j<pPhrase->nTerm; j++){ | 971 int bEof = 1; |
900 Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; | 972 Fts5ExprTerm *p; |
901 Fts5ExprTerm *p; | |
902 int bEof = 1; | |
903 | 973 |
904 for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){ | 974 /* Find the firstest rowid any synonym points to. */ |
905 if( p->pIter ){ | 975 i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0); |
906 sqlite3Fts5IterClose(p->pIter); | 976 |
907 p->pIter = 0; | 977 /* Advance each iterator that currently points to iRowid. Or, if iFrom |
908 } | 978 ** is valid - each iterator that points to a rowid before iFrom. */ |
909 rc = sqlite3Fts5IndexQuery( | 979 for(p=pTerm; p; p=p->pSynonym){ |
910 pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm), | 980 if( sqlite3Fts5IterEof(p->pIter)==0 ){ |
911 (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | | 981 i64 ii = p->pIter->iRowid; |
912 (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), | 982 if( ii==iRowid |
913 pNear->pColset, | 983 || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) |
914 &p->pIter | 984 ){ |
915 ); | 985 if( bFromValid ){ |
916 assert( rc==SQLITE_OK || p->pIter==0 ); | 986 rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom); |
917 if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){ | 987 }else{ |
| 988 rc = sqlite3Fts5IterNext(p->pIter); |
| 989 } |
| 990 if( rc!=SQLITE_OK ) break; |
| 991 if( sqlite3Fts5IterEof(p->pIter)==0 ){ |
| 992 bEof = 0; |
| 993 } |
| 994 }else{ |
918 bEof = 0; | 995 bEof = 0; |
919 } | 996 } |
920 } | 997 } |
| 998 } |
921 | 999 |
922 if( bEof ){ | 1000 /* Set the EOF flag if either all synonym iterators are at EOF or an |
923 pNode->bEof = 1; | 1001 ** error has occurred. */ |
924 return rc; | 1002 pNode->bEof = (rc || bEof); |
925 } | 1003 }else{ |
| 1004 Fts5IndexIter *pIter = pTerm->pIter; |
| 1005 |
| 1006 assert( Fts5NodeIsString(pNode) ); |
| 1007 if( bFromValid ){ |
| 1008 rc = sqlite3Fts5IterNextFrom(pIter, iFrom); |
| 1009 }else{ |
| 1010 rc = sqlite3Fts5IterNext(pIter); |
926 } | 1011 } |
| 1012 |
| 1013 pNode->bEof = (rc || sqlite3Fts5IterEof(pIter)); |
| 1014 } |
| 1015 |
| 1016 if( pNode->bEof==0 ){ |
| 1017 assert( rc==SQLITE_OK ); |
| 1018 rc = fts5ExprNodeTest_STRING(pExpr, pNode); |
927 } | 1019 } |
928 | 1020 |
929 return rc; | 1021 return rc; |
930 } | 1022 } |
931 | 1023 |
932 /* fts5ExprNodeNext() calls fts5ExprNodeNextMatch(). And vice-versa. */ | |
933 static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*); | |
934 | 1024 |
| 1025 static int fts5ExprNodeTest_TERM( |
| 1026 Fts5Expr *pExpr, /* Expression that pNear is a part of */ |
| 1027 Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */ |
| 1028 ){ |
| 1029 /* As this "NEAR" object is actually a single phrase that consists |
| 1030 ** of a single term only, grab pointers into the poslist managed by the |
| 1031 ** fts5_index.c iterator object. This is much faster than synthesizing |
| 1032 ** a new poslist the way we have to for more complicated phrase or NEAR |
| 1033 ** expressions. */ |
| 1034 Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0]; |
| 1035 Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; |
| 1036 |
| 1037 assert( pNode->eType==FTS5_TERM ); |
| 1038 assert( pNode->pNear->nPhrase==1 && pPhrase->nTerm==1 ); |
| 1039 assert( pPhrase->aTerm[0].pSynonym==0 ); |
| 1040 |
| 1041 pPhrase->poslist.n = pIter->nData; |
| 1042 if( pExpr->pConfig->eDetail==FTS5_DETAIL_FULL ){ |
| 1043 pPhrase->poslist.p = (u8*)pIter->pData; |
| 1044 } |
| 1045 pNode->iRowid = pIter->iRowid; |
| 1046 pNode->bNomatch = (pPhrase->poslist.n==0); |
| 1047 return SQLITE_OK; |
| 1048 } |
935 | 1049 |
936 /* | 1050 /* |
937 ** If pExpr is an ASC iterator, this function returns a value with the | 1051 ** xNext() method for a node of type FTS5_TERM. |
938 ** same sign as: | |
939 ** | |
940 ** (iLhs - iRhs) | |
941 ** | |
942 ** Otherwise, if this is a DESC iterator, the opposite is returned: | |
943 ** | |
944 ** (iRhs - iLhs) | |
945 */ | 1052 */ |
946 static int fts5RowidCmp( | 1053 static int fts5ExprNodeNext_TERM( |
947 Fts5Expr *pExpr, | 1054 Fts5Expr *pExpr, |
948 i64 iLhs, | 1055 Fts5ExprNode *pNode, |
949 i64 iRhs | 1056 int bFromValid, |
| 1057 i64 iFrom |
950 ){ | 1058 ){ |
951 assert( pExpr->bDesc==0 || pExpr->bDesc==1 ); | 1059 int rc; |
952 if( pExpr->bDesc==0 ){ | 1060 Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter; |
953 if( iLhs<iRhs ) return -1; | 1061 |
954 return (iLhs > iRhs); | 1062 assert( pNode->bEof==0 ); |
| 1063 if( bFromValid ){ |
| 1064 rc = sqlite3Fts5IterNextFrom(pIter, iFrom); |
955 }else{ | 1065 }else{ |
956 if( iLhs>iRhs ) return -1; | 1066 rc = sqlite3Fts5IterNext(pIter); |
957 return (iLhs < iRhs); | |
958 } | 1067 } |
| 1068 if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){ |
| 1069 rc = fts5ExprNodeTest_TERM(pExpr, pNode); |
| 1070 }else{ |
| 1071 pNode->bEof = 1; |
| 1072 pNode->bNomatch = 0; |
| 1073 } |
| 1074 return rc; |
959 } | 1075 } |
960 | 1076 |
961 static void fts5ExprSetEof(Fts5ExprNode *pNode){ | 1077 static void fts5ExprNodeTest_OR( |
| 1078 Fts5Expr *pExpr, /* Expression of which pNode is a part */ |
| 1079 Fts5ExprNode *pNode /* Expression node to test */ |
| 1080 ){ |
| 1081 Fts5ExprNode *pNext = pNode->apChild[0]; |
962 int i; | 1082 int i; |
963 pNode->bEof = 1; | 1083 |
964 for(i=0; i<pNode->nChild; i++){ | 1084 for(i=1; i<pNode->nChild; i++){ |
965 fts5ExprSetEof(pNode->apChild[i]); | 1085 Fts5ExprNode *pChild = pNode->apChild[i]; |
| 1086 int cmp = fts5NodeCompare(pExpr, pNext, pChild); |
| 1087 if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){ |
| 1088 pNext = pChild; |
| 1089 } |
966 } | 1090 } |
| 1091 pNode->iRowid = pNext->iRowid; |
| 1092 pNode->bEof = pNext->bEof; |
| 1093 pNode->bNomatch = pNext->bNomatch; |
967 } | 1094 } |
968 | 1095 |
969 static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){ | 1096 static int fts5ExprNodeNext_OR( |
970 if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){ | 1097 Fts5Expr *pExpr, |
971 Fts5ExprNearset *pNear = pNode->pNear; | 1098 Fts5ExprNode *pNode, |
972 int i; | 1099 int bFromValid, |
973 for(i=0; i<pNear->nPhrase; i++){ | 1100 i64 iFrom |
974 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; | 1101 ){ |
975 pPhrase->poslist.n = 0; | 1102 int i; |
976 } | 1103 i64 iLast = pNode->iRowid; |
977 }else{ | 1104 |
978 int i; | 1105 for(i=0; i<pNode->nChild; i++){ |
979 for(i=0; i<pNode->nChild; i++){ | 1106 Fts5ExprNode *p1 = pNode->apChild[i]; |
980 fts5ExprNodeZeroPoslist(pNode->apChild[i]); | 1107 assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 ); |
| 1108 if( p1->bEof==0 ){ |
| 1109 if( (p1->iRowid==iLast) |
| 1110 || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0) |
| 1111 ){ |
| 1112 int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom); |
| 1113 if( rc!=SQLITE_OK ) return rc; |
| 1114 } |
981 } | 1115 } |
982 } | 1116 } |
| 1117 |
| 1118 fts5ExprNodeTest_OR(pExpr, pNode); |
| 1119 return SQLITE_OK; |
983 } | 1120 } |
984 | 1121 |
985 | |
986 static int fts5ExprNodeNext(Fts5Expr*, Fts5ExprNode*, int, i64); | |
987 | |
988 /* | 1122 /* |
989 ** Argument pNode is an FTS5_AND node. | 1123 ** Argument pNode is an FTS5_AND node. |
990 */ | 1124 */ |
991 static int fts5ExprAndNextRowid( | 1125 static int fts5ExprNodeTest_AND( |
992 Fts5Expr *pExpr, /* Expression pPhrase belongs to */ | 1126 Fts5Expr *pExpr, /* Expression pPhrase belongs to */ |
993 Fts5ExprNode *pAnd /* FTS5_AND node to advance */ | 1127 Fts5ExprNode *pAnd /* FTS5_AND node to advance */ |
994 ){ | 1128 ){ |
995 int iChild; | 1129 int iChild; |
996 i64 iLast = pAnd->iRowid; | 1130 i64 iLast = pAnd->iRowid; |
997 int rc = SQLITE_OK; | 1131 int rc = SQLITE_OK; |
998 int bMatch; | 1132 int bMatch; |
999 | 1133 |
1000 assert( pAnd->bEof==0 ); | 1134 assert( pAnd->bEof==0 ); |
1001 do { | 1135 do { |
1002 pAnd->bNomatch = 0; | 1136 pAnd->bNomatch = 0; |
1003 bMatch = 1; | 1137 bMatch = 1; |
1004 for(iChild=0; iChild<pAnd->nChild; iChild++){ | 1138 for(iChild=0; iChild<pAnd->nChild; iChild++){ |
1005 Fts5ExprNode *pChild = pAnd->apChild[iChild]; | 1139 Fts5ExprNode *pChild = pAnd->apChild[iChild]; |
1006 if( 0 && pChild->eType==FTS5_STRING ){ | 1140 int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid); |
1007 /* TODO */ | 1141 if( cmp>0 ){ |
1008 }else{ | 1142 /* Advance pChild until it points to iLast or laster */ |
1009 int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid); | 1143 rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast); |
1010 if( cmp>0 ){ | 1144 if( rc!=SQLITE_OK ) return rc; |
1011 /* Advance pChild until it points to iLast or laster */ | |
1012 rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast); | |
1013 if( rc!=SQLITE_OK ) return rc; | |
1014 } | |
1015 } | 1145 } |
1016 | 1146 |
1017 /* If the child node is now at EOF, so is the parent AND node. Otherwise, | 1147 /* If the child node is now at EOF, so is the parent AND node. Otherwise, |
1018 ** the child node is guaranteed to have advanced at least as far as | 1148 ** the child node is guaranteed to have advanced at least as far as |
1019 ** rowid iLast. So if it is not at exactly iLast, pChild->iRowid is the | 1149 ** rowid iLast. So if it is not at exactly iLast, pChild->iRowid is the |
1020 ** new lastest rowid seen so far. */ | 1150 ** new lastest rowid seen so far. */ |
1021 assert( pChild->bEof || fts5RowidCmp(pExpr, iLast, pChild->iRowid)<=0 ); | 1151 assert( pChild->bEof || fts5RowidCmp(pExpr, iLast, pChild->iRowid)<=0 ); |
1022 if( pChild->bEof ){ | 1152 if( pChild->bEof ){ |
1023 fts5ExprSetEof(pAnd); | 1153 fts5ExprSetEof(pAnd); |
1024 bMatch = 1; | 1154 bMatch = 1; |
1025 break; | 1155 break; |
1026 }else if( iLast!=pChild->iRowid ){ | 1156 }else if( iLast!=pChild->iRowid ){ |
1027 bMatch = 0; | 1157 bMatch = 0; |
1028 iLast = pChild->iRowid; | 1158 iLast = pChild->iRowid; |
1029 } | 1159 } |
1030 | 1160 |
1031 if( pChild->bNomatch ){ | 1161 if( pChild->bNomatch ){ |
1032 pAnd->bNomatch = 1; | 1162 pAnd->bNomatch = 1; |
1033 } | 1163 } |
1034 } | 1164 } |
1035 }while( bMatch==0 ); | 1165 }while( bMatch==0 ); |
1036 | 1166 |
1037 if( pAnd->bNomatch && pAnd!=pExpr->pRoot ){ | 1167 if( pAnd->bNomatch && pAnd!=pExpr->pRoot ){ |
1038 fts5ExprNodeZeroPoslist(pAnd); | 1168 fts5ExprNodeZeroPoslist(pAnd); |
1039 } | 1169 } |
1040 pAnd->iRowid = iLast; | 1170 pAnd->iRowid = iLast; |
1041 return SQLITE_OK; | 1171 return SQLITE_OK; |
1042 } | 1172 } |
1043 | 1173 |
1044 | 1174 static int fts5ExprNodeNext_AND( |
1045 /* | |
1046 ** Compare the values currently indicated by the two nodes as follows: | |
1047 ** | |
1048 ** res = (*p1) - (*p2) | |
1049 ** | |
1050 ** Nodes that point to values that come later in the iteration order are | |
1051 ** considered to be larger. Nodes at EOF are the largest of all. | |
1052 ** | |
1053 ** This means that if the iteration order is ASC, then numerically larger | |
1054 ** rowids are considered larger. Or if it is the default DESC, numerically | |
1055 ** smaller rowids are larger. | |
1056 */ | |
1057 static int fts5NodeCompare( | |
1058 Fts5Expr *pExpr, | |
1059 Fts5ExprNode *p1, | |
1060 Fts5ExprNode *p2 | |
1061 ){ | |
1062 if( p2->bEof ) return -1; | |
1063 if( p1->bEof ) return +1; | |
1064 return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid); | |
1065 } | |
1066 | |
1067 /* | |
1068 ** Advance node iterator pNode, part of expression pExpr. If argument | |
1069 ** bFromValid is zero, then pNode is advanced exactly once. Or, if argument | |
1070 ** bFromValid is non-zero, then pNode is advanced until it is at or past | |
1071 ** rowid value iFrom. Whether "past" means "less than" or "greater than" | |
1072 ** depends on whether this is an ASC or DESC iterator. | |
1073 */ | |
1074 static int fts5ExprNodeNext( | |
1075 Fts5Expr *pExpr, | 1175 Fts5Expr *pExpr, |
1076 Fts5ExprNode *pNode, | 1176 Fts5ExprNode *pNode, |
1077 int bFromValid, | 1177 int bFromValid, |
1078 i64 iFrom | 1178 i64 iFrom |
1079 ){ | 1179 ){ |
1080 int rc = SQLITE_OK; | 1180 int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); |
1081 | 1181 if( rc==SQLITE_OK ){ |
1082 if( pNode->bEof==0 ){ | 1182 rc = fts5ExprNodeTest_AND(pExpr, pNode); |
1083 switch( pNode->eType ){ | |
1084 case FTS5_STRING: { | |
1085 rc = fts5ExprNearAdvanceFirst(pExpr, pNode, bFromValid, iFrom); | |
1086 break; | |
1087 }; | |
1088 | |
1089 case FTS5_TERM: { | |
1090 Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter; | |
1091 if( bFromValid ){ | |
1092 rc = sqlite3Fts5IterNextFrom(pIter, iFrom); | |
1093 }else{ | |
1094 rc = sqlite3Fts5IterNext(pIter); | |
1095 } | |
1096 if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){ | |
1097 assert( rc==SQLITE_OK ); | |
1098 rc = fts5ExprTokenTest(pExpr, pNode); | |
1099 }else{ | |
1100 pNode->bEof = 1; | |
1101 } | |
1102 return rc; | |
1103 }; | |
1104 | |
1105 case FTS5_AND: { | |
1106 Fts5ExprNode *pLeft = pNode->apChild[0]; | |
1107 rc = fts5ExprNodeNext(pExpr, pLeft, bFromValid, iFrom); | |
1108 break; | |
1109 } | |
1110 | |
1111 case FTS5_OR: { | |
1112 int i; | |
1113 i64 iLast = pNode->iRowid; | |
1114 | |
1115 for(i=0; rc==SQLITE_OK && i<pNode->nChild; i++){ | |
1116 Fts5ExprNode *p1 = pNode->apChild[i]; | |
1117 assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 ); | |
1118 if( p1->bEof==0 ){ | |
1119 if( (p1->iRowid==iLast) | |
1120 || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0) | |
1121 ){ | |
1122 rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom); | |
1123 } | |
1124 } | |
1125 } | |
1126 | |
1127 break; | |
1128 } | |
1129 | |
1130 default: assert( pNode->eType==FTS5_NOT ); { | |
1131 assert( pNode->nChild==2 ); | |
1132 rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); | |
1133 break; | |
1134 } | |
1135 } | |
1136 | |
1137 if( rc==SQLITE_OK ){ | |
1138 rc = fts5ExprNodeNextMatch(pExpr, pNode); | |
1139 } | |
1140 } | 1183 } |
1141 | |
1142 /* Assert that if bFromValid was true, either: | |
1143 ** | |
1144 ** a) an error occurred, or | |
1145 ** b) the node is now at EOF, or | |
1146 ** c) the node is now at or past rowid iFrom. | |
1147 */ | |
1148 assert( bFromValid==0 | |
1149 || rc!=SQLITE_OK /* a */ | |
1150 || pNode->bEof /* b */ | |
1151 || pNode->iRowid==iFrom || pExpr->bDesc==(pNode->iRowid<iFrom) /* c */ | |
1152 ); | |
1153 | |
1154 return rc; | 1184 return rc; |
1155 } | 1185 } |
1156 | 1186 |
| 1187 static int fts5ExprNodeTest_NOT( |
| 1188 Fts5Expr *pExpr, /* Expression pPhrase belongs to */ |
| 1189 Fts5ExprNode *pNode /* FTS5_NOT node to advance */ |
| 1190 ){ |
| 1191 int rc = SQLITE_OK; |
| 1192 Fts5ExprNode *p1 = pNode->apChild[0]; |
| 1193 Fts5ExprNode *p2 = pNode->apChild[1]; |
| 1194 assert( pNode->nChild==2 ); |
| 1195 |
| 1196 while( rc==SQLITE_OK && p1->bEof==0 ){ |
| 1197 int cmp = fts5NodeCompare(pExpr, p1, p2); |
| 1198 if( cmp>0 ){ |
| 1199 rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid); |
| 1200 cmp = fts5NodeCompare(pExpr, p1, p2); |
| 1201 } |
| 1202 assert( rc!=SQLITE_OK || cmp<=0 ); |
| 1203 if( cmp || p2->bNomatch ) break; |
| 1204 rc = fts5ExprNodeNext(pExpr, p1, 0, 0); |
| 1205 } |
| 1206 pNode->bEof = p1->bEof; |
| 1207 pNode->bNomatch = p1->bNomatch; |
| 1208 pNode->iRowid = p1->iRowid; |
| 1209 if( p1->bEof ){ |
| 1210 fts5ExprNodeZeroPoslist(p2); |
| 1211 } |
| 1212 return rc; |
| 1213 } |
| 1214 |
| 1215 static int fts5ExprNodeNext_NOT( |
| 1216 Fts5Expr *pExpr, |
| 1217 Fts5ExprNode *pNode, |
| 1218 int bFromValid, |
| 1219 i64 iFrom |
| 1220 ){ |
| 1221 int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); |
| 1222 if( rc==SQLITE_OK ){ |
| 1223 rc = fts5ExprNodeTest_NOT(pExpr, pNode); |
| 1224 } |
| 1225 return rc; |
| 1226 } |
1157 | 1227 |
1158 /* | 1228 /* |
1159 ** If pNode currently points to a match, this function returns SQLITE_OK | 1229 ** If pNode currently points to a match, this function returns SQLITE_OK |
1160 ** without modifying it. Otherwise, pNode is advanced until it does point | 1230 ** without modifying it. Otherwise, pNode is advanced until it does point |
1161 ** to a match or EOF is reached. | 1231 ** to a match or EOF is reached. |
1162 */ | 1232 */ |
1163 static int fts5ExprNodeNextMatch( | 1233 static int fts5ExprNodeTest( |
1164 Fts5Expr *pExpr, /* Expression of which pNode is a part */ | 1234 Fts5Expr *pExpr, /* Expression of which pNode is a part */ |
1165 Fts5ExprNode *pNode /* Expression node to test */ | 1235 Fts5ExprNode *pNode /* Expression node to test */ |
1166 ){ | 1236 ){ |
1167 int rc = SQLITE_OK; | 1237 int rc = SQLITE_OK; |
1168 if( pNode->bEof==0 ){ | 1238 if( pNode->bEof==0 ){ |
1169 switch( pNode->eType ){ | 1239 switch( pNode->eType ){ |
1170 | 1240 |
1171 case FTS5_STRING: { | 1241 case FTS5_STRING: { |
1172 /* Advance the iterators until they all point to the same rowid */ | 1242 rc = fts5ExprNodeTest_STRING(pExpr, pNode); |
1173 rc = fts5ExprNearNextMatch(pExpr, pNode); | |
1174 break; | 1243 break; |
1175 } | 1244 } |
1176 | 1245 |
1177 case FTS5_TERM: { | 1246 case FTS5_TERM: { |
1178 rc = fts5ExprTokenTest(pExpr, pNode); | 1247 rc = fts5ExprNodeTest_TERM(pExpr, pNode); |
1179 break; | 1248 break; |
1180 } | 1249 } |
1181 | 1250 |
1182 case FTS5_AND: { | 1251 case FTS5_AND: { |
1183 rc = fts5ExprAndNextRowid(pExpr, pNode); | 1252 rc = fts5ExprNodeTest_AND(pExpr, pNode); |
1184 break; | 1253 break; |
1185 } | 1254 } |
1186 | 1255 |
1187 case FTS5_OR: { | 1256 case FTS5_OR: { |
1188 Fts5ExprNode *pNext = pNode->apChild[0]; | 1257 fts5ExprNodeTest_OR(pExpr, pNode); |
1189 int i; | |
1190 | |
1191 for(i=1; i<pNode->nChild; i++){ | |
1192 Fts5ExprNode *pChild = pNode->apChild[i]; | |
1193 int cmp = fts5NodeCompare(pExpr, pNext, pChild); | |
1194 if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){ | |
1195 pNext = pChild; | |
1196 } | |
1197 } | |
1198 pNode->iRowid = pNext->iRowid; | |
1199 pNode->bEof = pNext->bEof; | |
1200 pNode->bNomatch = pNext->bNomatch; | |
1201 break; | 1258 break; |
1202 } | 1259 } |
1203 | 1260 |
1204 default: assert( pNode->eType==FTS5_NOT ); { | 1261 default: assert( pNode->eType==FTS5_NOT ); { |
1205 Fts5ExprNode *p1 = pNode->apChild[0]; | 1262 rc = fts5ExprNodeTest_NOT(pExpr, pNode); |
1206 Fts5ExprNode *p2 = pNode->apChild[1]; | |
1207 assert( pNode->nChild==2 ); | |
1208 | |
1209 while( rc==SQLITE_OK && p1->bEof==0 ){ | |
1210 int cmp = fts5NodeCompare(pExpr, p1, p2); | |
1211 if( cmp>0 ){ | |
1212 rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid); | |
1213 cmp = fts5NodeCompare(pExpr, p1, p2); | |
1214 } | |
1215 assert( rc!=SQLITE_OK || cmp<=0 ); | |
1216 if( cmp || p2->bNomatch ) break; | |
1217 rc = fts5ExprNodeNext(pExpr, p1, 0, 0); | |
1218 } | |
1219 pNode->bEof = p1->bEof; | |
1220 pNode->iRowid = p1->iRowid; | |
1221 break; | 1263 break; |
1222 } | 1264 } |
1223 } | 1265 } |
1224 } | 1266 } |
1225 return rc; | 1267 return rc; |
1226 } | 1268 } |
1227 | 1269 |
1228 | 1270 |
1229 /* | 1271 /* |
1230 ** Set node pNode, which is part of expression pExpr, to point to the first | 1272 ** Set node pNode, which is part of expression pExpr, to point to the first |
1231 ** match. If there are no matches, set the Node.bEof flag to indicate EOF. | 1273 ** match. If there are no matches, set the Node.bEof flag to indicate EOF. |
1232 ** | 1274 ** |
1233 ** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise. | 1275 ** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise. |
1234 ** It is not an error if there are no matches. | 1276 ** It is not an error if there are no matches. |
1235 */ | 1277 */ |
1236 static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ | 1278 static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ |
1237 int rc = SQLITE_OK; | 1279 int rc = SQLITE_OK; |
1238 pNode->bEof = 0; | 1280 pNode->bEof = 0; |
| 1281 pNode->bNomatch = 0; |
1239 | 1282 |
1240 if( Fts5NodeIsString(pNode) ){ | 1283 if( Fts5NodeIsString(pNode) ){ |
1241 /* Initialize all term iterators in the NEAR object. */ | 1284 /* Initialize all term iterators in the NEAR object. */ |
1242 rc = fts5ExprNearInitAll(pExpr, pNode); | 1285 rc = fts5ExprNearInitAll(pExpr, pNode); |
| 1286 }else if( pNode->xNext==0 ){ |
| 1287 pNode->bEof = 1; |
1243 }else{ | 1288 }else{ |
1244 int i; | 1289 int i; |
| 1290 int nEof = 0; |
1245 for(i=0; i<pNode->nChild && rc==SQLITE_OK; i++){ | 1291 for(i=0; i<pNode->nChild && rc==SQLITE_OK; i++){ |
| 1292 Fts5ExprNode *pChild = pNode->apChild[i]; |
1246 rc = fts5ExprNodeFirst(pExpr, pNode->apChild[i]); | 1293 rc = fts5ExprNodeFirst(pExpr, pNode->apChild[i]); |
| 1294 assert( pChild->bEof==0 || pChild->bEof==1 ); |
| 1295 nEof += pChild->bEof; |
1247 } | 1296 } |
1248 pNode->iRowid = pNode->apChild[0]->iRowid; | 1297 pNode->iRowid = pNode->apChild[0]->iRowid; |
| 1298 |
| 1299 switch( pNode->eType ){ |
| 1300 case FTS5_AND: |
| 1301 if( nEof>0 ) fts5ExprSetEof(pNode); |
| 1302 break; |
| 1303 |
| 1304 case FTS5_OR: |
| 1305 if( pNode->nChild==nEof ) fts5ExprSetEof(pNode); |
| 1306 break; |
| 1307 |
| 1308 default: |
| 1309 assert( pNode->eType==FTS5_NOT ); |
| 1310 pNode->bEof = pNode->apChild[0]->bEof; |
| 1311 break; |
| 1312 } |
1249 } | 1313 } |
1250 | 1314 |
1251 if( rc==SQLITE_OK ){ | 1315 if( rc==SQLITE_OK ){ |
1252 rc = fts5ExprNodeNextMatch(pExpr, pNode); | 1316 rc = fts5ExprNodeTest(pExpr, pNode); |
1253 } | 1317 } |
1254 return rc; | 1318 return rc; |
1255 } | 1319 } |
1256 | 1320 |
1257 | 1321 |
1258 /* | 1322 /* |
1259 ** Begin iterating through the set of documents in index pIdx matched by | 1323 ** Begin iterating through the set of documents in index pIdx matched by |
1260 ** the MATCH expression passed as the first argument. If the "bDesc" | 1324 ** the MATCH expression passed as the first argument. If the "bDesc" |
1261 ** parameter is passed a non-zero value, iteration is in descending rowid | 1325 ** parameter is passed a non-zero value, iteration is in descending rowid |
1262 ** order. Or, if it is zero, in ascending order. | 1326 ** order. Or, if it is zero, in ascending order. |
1263 ** | 1327 ** |
1264 ** If iterating in ascending rowid order (bDesc==0), the first document | 1328 ** If iterating in ascending rowid order (bDesc==0), the first document |
1265 ** visited is that with the smallest rowid that is larger than or equal | 1329 ** visited is that with the smallest rowid that is larger than or equal |
1266 ** to parameter iFirst. Or, if iterating in ascending order (bDesc==1), | 1330 ** to parameter iFirst. Or, if iterating in ascending order (bDesc==1), |
1267 ** then the first document visited must have a rowid smaller than or | 1331 ** then the first document visited must have a rowid smaller than or |
1268 ** equal to iFirst. | 1332 ** equal to iFirst. |
1269 ** | 1333 ** |
1270 ** Return SQLITE_OK if successful, or an SQLite error code otherwise. It | 1334 ** Return SQLITE_OK if successful, or an SQLite error code otherwise. It |
1271 ** is not considered an error if the query does not match any documents. | 1335 ** is not considered an error if the query does not match any documents. |
1272 */ | 1336 */ |
1273 int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){ | 1337 int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){ |
1274 Fts5ExprNode *pRoot = p->pRoot; | 1338 Fts5ExprNode *pRoot = p->pRoot; |
1275 int rc = SQLITE_OK; | 1339 int rc; /* Return code */ |
1276 if( pRoot ){ | |
1277 p->pIndex = pIdx; | |
1278 p->bDesc = bDesc; | |
1279 rc = fts5ExprNodeFirst(p, pRoot); | |
1280 | 1340 |
1281 /* If not at EOF but the current rowid occurs earlier than iFirst in | 1341 p->pIndex = pIdx; |
1282 ** the iteration order, move to document iFirst or later. */ | 1342 p->bDesc = bDesc; |
1283 if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){ | 1343 rc = fts5ExprNodeFirst(p, pRoot); |
1284 rc = fts5ExprNodeNext(p, pRoot, 1, iFirst); | |
1285 } | |
1286 | 1344 |
1287 /* If the iterator is not at a real match, skip forward until it is. */ | 1345 /* If not at EOF but the current rowid occurs earlier than iFirst in |
1288 while( pRoot->bNomatch && rc==SQLITE_OK && pRoot->bEof==0 ){ | 1346 ** the iteration order, move to document iFirst or later. */ |
1289 rc = fts5ExprNodeNext(p, pRoot, 0, 0); | 1347 if( rc==SQLITE_OK |
1290 } | 1348 && 0==pRoot->bEof |
| 1349 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 |
| 1350 ){ |
| 1351 rc = fts5ExprNodeNext(p, pRoot, 1, iFirst); |
| 1352 } |
| 1353 |
| 1354 /* If the iterator is not at a real match, skip forward until it is. */ |
| 1355 while( pRoot->bNomatch ){ |
| 1356 assert( pRoot->bEof==0 && rc==SQLITE_OK ); |
| 1357 rc = fts5ExprNodeNext(p, pRoot, 0, 0); |
1291 } | 1358 } |
1292 return rc; | 1359 return rc; |
1293 } | 1360 } |
1294 | 1361 |
1295 /* | 1362 /* |
1296 ** Move to the next document | 1363 ** Move to the next document |
1297 ** | 1364 ** |
1298 ** Return SQLITE_OK if successful, or an SQLite error code otherwise. It | 1365 ** Return SQLITE_OK if successful, or an SQLite error code otherwise. It |
1299 ** is not considered an error if the query does not match any documents. | 1366 ** is not considered an error if the query does not match any documents. |
1300 */ | 1367 */ |
1301 int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){ | 1368 int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){ |
1302 int rc; | 1369 int rc; |
1303 Fts5ExprNode *pRoot = p->pRoot; | 1370 Fts5ExprNode *pRoot = p->pRoot; |
| 1371 assert( pRoot->bEof==0 && pRoot->bNomatch==0 ); |
1304 do { | 1372 do { |
1305 rc = fts5ExprNodeNext(p, pRoot, 0, 0); | 1373 rc = fts5ExprNodeNext(p, pRoot, 0, 0); |
1306 }while( pRoot->bNomatch && pRoot->bEof==0 && rc==SQLITE_OK ); | 1374 assert( pRoot->bNomatch==0 || (rc==SQLITE_OK && pRoot->bEof==0) ); |
| 1375 }while( pRoot->bNomatch ); |
1307 if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){ | 1376 if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){ |
1308 pRoot->bEof = 1; | 1377 pRoot->bEof = 1; |
1309 } | 1378 } |
1310 return rc; | 1379 return rc; |
1311 } | 1380 } |
1312 | 1381 |
1313 int sqlite3Fts5ExprEof(Fts5Expr *p){ | 1382 int sqlite3Fts5ExprEof(Fts5Expr *p){ |
1314 return (p->pRoot==0 || p->pRoot->bEof); | 1383 return p->pRoot->bEof; |
1315 } | 1384 } |
1316 | 1385 |
1317 i64 sqlite3Fts5ExprRowid(Fts5Expr *p){ | 1386 i64 sqlite3Fts5ExprRowid(Fts5Expr *p){ |
1318 return p->pRoot->iRowid; | 1387 return p->pRoot->iRowid; |
1319 } | 1388 } |
1320 | 1389 |
1321 static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){ | 1390 static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){ |
1322 int rc = SQLITE_OK; | 1391 int rc = SQLITE_OK; |
1323 *pz = sqlite3Fts5Strndup(&rc, pToken->p, pToken->n); | 1392 *pz = sqlite3Fts5Strndup(&rc, pToken->p, pToken->n); |
1324 return rc; | 1393 return rc; |
1325 } | 1394 } |
1326 | 1395 |
1327 /* | 1396 /* |
1328 ** Free the phrase object passed as the only argument. | 1397 ** Free the phrase object passed as the only argument. |
1329 */ | 1398 */ |
1330 static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){ | 1399 static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){ |
1331 if( pPhrase ){ | 1400 if( pPhrase ){ |
1332 int i; | 1401 int i; |
1333 for(i=0; i<pPhrase->nTerm; i++){ | 1402 for(i=0; i<pPhrase->nTerm; i++){ |
1334 Fts5ExprTerm *pSyn; | 1403 Fts5ExprTerm *pSyn; |
1335 Fts5ExprTerm *pNext; | 1404 Fts5ExprTerm *pNext; |
1336 Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; | 1405 Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; |
1337 sqlite3_free(pTerm->zTerm); | 1406 sqlite3_free(pTerm->zTerm); |
1338 sqlite3Fts5IterClose(pTerm->pIter); | 1407 sqlite3Fts5IterClose(pTerm->pIter); |
1339 | |
1340 for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){ | 1408 for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){ |
1341 pNext = pSyn->pSynonym; | 1409 pNext = pSyn->pSynonym; |
1342 sqlite3Fts5IterClose(pSyn->pIter); | 1410 sqlite3Fts5IterClose(pSyn->pIter); |
| 1411 fts5BufferFree((Fts5Buffer*)&pSyn[1]); |
1343 sqlite3_free(pSyn); | 1412 sqlite3_free(pSyn); |
1344 } | 1413 } |
1345 } | 1414 } |
1346 if( pPhrase->poslist.nSpace>0 ) fts5BufferFree(&pPhrase->poslist); | 1415 if( pPhrase->poslist.nSpace>0 ) fts5BufferFree(&pPhrase->poslist); |
1347 sqlite3_free(pPhrase); | 1416 sqlite3_free(pPhrase); |
1348 } | 1417 } |
1349 } | 1418 } |
1350 | 1419 |
1351 /* | 1420 /* |
1352 ** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated | 1421 ** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1387 }else{ | 1456 }else{ |
1388 pRet = pNear; | 1457 pRet = pNear; |
1389 } | 1458 } |
1390 } | 1459 } |
1391 | 1460 |
1392 if( pRet==0 ){ | 1461 if( pRet==0 ){ |
1393 assert( pParse->rc!=SQLITE_OK ); | 1462 assert( pParse->rc!=SQLITE_OK ); |
1394 sqlite3Fts5ParseNearsetFree(pNear); | 1463 sqlite3Fts5ParseNearsetFree(pNear); |
1395 sqlite3Fts5ParsePhraseFree(pPhrase); | 1464 sqlite3Fts5ParsePhraseFree(pPhrase); |
1396 }else{ | 1465 }else{ |
| 1466 if( pRet->nPhrase>0 ){ |
| 1467 Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1]; |
| 1468 assert( pLast==pParse->apPhrase[pParse->nPhrase-2] ); |
| 1469 if( pPhrase->nTerm==0 ){ |
| 1470 fts5ExprPhraseFree(pPhrase); |
| 1471 pRet->nPhrase--; |
| 1472 pParse->nPhrase--; |
| 1473 pPhrase = pLast; |
| 1474 }else if( pLast->nTerm==0 ){ |
| 1475 fts5ExprPhraseFree(pLast); |
| 1476 pParse->apPhrase[pParse->nPhrase-2] = pPhrase; |
| 1477 pParse->nPhrase--; |
| 1478 pRet->nPhrase--; |
| 1479 } |
| 1480 } |
1397 pRet->apPhrase[pRet->nPhrase++] = pPhrase; | 1481 pRet->apPhrase[pRet->nPhrase++] = pPhrase; |
1398 } | 1482 } |
1399 return pRet; | 1483 return pRet; |
1400 } | 1484 } |
1401 | 1485 |
1402 typedef struct TokenCtx TokenCtx; | 1486 typedef struct TokenCtx TokenCtx; |
1403 struct TokenCtx { | 1487 struct TokenCtx { |
1404 Fts5ExprPhrase *pPhrase; | 1488 Fts5ExprPhrase *pPhrase; |
1405 int rc; | 1489 int rc; |
1406 }; | 1490 }; |
1407 | 1491 |
1408 /* | 1492 /* |
1409 ** Callback for tokenizing terms used by ParseTerm(). | 1493 ** Callback for tokenizing terms used by ParseTerm(). |
1410 */ | 1494 */ |
1411 static int fts5ParseTokenize( | 1495 static int fts5ParseTokenize( |
1412 void *pContext, /* Pointer to Fts5InsertCtx object */ | 1496 void *pContext, /* Pointer to Fts5InsertCtx object */ |
1413 int tflags, /* Mask of FTS5_TOKEN_* flags */ | 1497 int tflags, /* Mask of FTS5_TOKEN_* flags */ |
1414 const char *pToken, /* Buffer containing token */ | 1498 const char *pToken, /* Buffer containing token */ |
1415 int nToken, /* Size of token in bytes */ | 1499 int nToken, /* Size of token in bytes */ |
1416 int iUnused1, /* Start offset of token */ | 1500 int iUnused1, /* Start offset of token */ |
1417 int iUnused2 /* End offset of token */ | 1501 int iUnused2 /* End offset of token */ |
1418 ){ | 1502 ){ |
1419 int rc = SQLITE_OK; | 1503 int rc = SQLITE_OK; |
1420 const int SZALLOC = 8; | 1504 const int SZALLOC = 8; |
1421 TokenCtx *pCtx = (TokenCtx*)pContext; | 1505 TokenCtx *pCtx = (TokenCtx*)pContext; |
1422 Fts5ExprPhrase *pPhrase = pCtx->pPhrase; | 1506 Fts5ExprPhrase *pPhrase = pCtx->pPhrase; |
1423 | 1507 |
| 1508 UNUSED_PARAM2(iUnused1, iUnused2); |
| 1509 |
1424 /* If an error has already occurred, this is a no-op */ | 1510 /* If an error has already occurred, this is a no-op */ |
1425 if( pCtx->rc!=SQLITE_OK ) return pCtx->rc; | 1511 if( pCtx->rc!=SQLITE_OK ) return pCtx->rc; |
| 1512 if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; |
1426 | 1513 |
1427 assert( pPhrase==0 || pPhrase->nTerm>0 ); | 1514 if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){ |
1428 if( pPhrase && (tflags & FTS5_TOKEN_COLOCATED) ){ | |
1429 Fts5ExprTerm *pSyn; | 1515 Fts5ExprTerm *pSyn; |
1430 int nByte = sizeof(Fts5ExprTerm) + nToken+1; | 1516 int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; |
1431 pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte); | 1517 pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte); |
1432 if( pSyn==0 ){ | 1518 if( pSyn==0 ){ |
1433 rc = SQLITE_NOMEM; | 1519 rc = SQLITE_NOMEM; |
1434 }else{ | 1520 }else{ |
1435 memset(pSyn, 0, nByte); | 1521 memset(pSyn, 0, nByte); |
1436 pSyn->zTerm = (char*)&pSyn[1]; | 1522 pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); |
1437 memcpy(pSyn->zTerm, pToken, nToken); | 1523 memcpy(pSyn->zTerm, pToken, nToken); |
1438 pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; | 1524 pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; |
1439 pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; | 1525 pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; |
1440 } | 1526 } |
1441 }else{ | 1527 }else{ |
1442 Fts5ExprTerm *pTerm; | 1528 Fts5ExprTerm *pTerm; |
1443 if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){ | 1529 if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){ |
1444 Fts5ExprPhrase *pNew; | 1530 Fts5ExprPhrase *pNew; |
1445 int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); | 1531 int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); |
1446 | 1532 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1508 Fts5Config *pConfig = pParse->pConfig; | 1594 Fts5Config *pConfig = pParse->pConfig; |
1509 TokenCtx sCtx; /* Context object passed to callback */ | 1595 TokenCtx sCtx; /* Context object passed to callback */ |
1510 int rc; /* Tokenize return code */ | 1596 int rc; /* Tokenize return code */ |
1511 char *z = 0; | 1597 char *z = 0; |
1512 | 1598 |
1513 memset(&sCtx, 0, sizeof(TokenCtx)); | 1599 memset(&sCtx, 0, sizeof(TokenCtx)); |
1514 sCtx.pPhrase = pAppend; | 1600 sCtx.pPhrase = pAppend; |
1515 | 1601 |
1516 rc = fts5ParseStringFromToken(pToken, &z); | 1602 rc = fts5ParseStringFromToken(pToken, &z); |
1517 if( rc==SQLITE_OK ){ | 1603 if( rc==SQLITE_OK ){ |
1518 int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0); | 1604 int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_PREFIX : 0); |
1519 int n; | 1605 int n; |
1520 sqlite3Fts5Dequote(z); | 1606 sqlite3Fts5Dequote(z); |
1521 n = (int)strlen(z); | 1607 n = (int)strlen(z); |
1522 rc = sqlite3Fts5Tokenize(pConfig, flags, z, n, &sCtx, fts5ParseTokenize); | 1608 rc = sqlite3Fts5Tokenize(pConfig, flags, z, n, &sCtx, fts5ParseTokenize); |
1523 } | 1609 } |
1524 sqlite3_free(z); | 1610 sqlite3_free(z); |
1525 if( rc || (rc = sCtx.rc) ){ | 1611 if( rc || (rc = sCtx.rc) ){ |
1526 pParse->rc = rc; | 1612 pParse->rc = rc; |
1527 fts5ExprPhraseFree(sCtx.pPhrase); | 1613 fts5ExprPhraseFree(sCtx.pPhrase); |
1528 sCtx.pPhrase = 0; | 1614 sCtx.pPhrase = 0; |
1529 }else if( sCtx.pPhrase ){ | 1615 }else{ |
1530 | 1616 |
1531 if( pAppend==0 ){ | 1617 if( pAppend==0 ){ |
1532 if( (pParse->nPhrase % 8)==0 ){ | 1618 if( (pParse->nPhrase % 8)==0 ){ |
1533 int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); | 1619 int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); |
1534 Fts5ExprPhrase **apNew; | 1620 Fts5ExprPhrase **apNew; |
1535 apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte); | 1621 apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte); |
1536 if( apNew==0 ){ | 1622 if( apNew==0 ){ |
1537 pParse->rc = SQLITE_NOMEM; | 1623 pParse->rc = SQLITE_NOMEM; |
1538 fts5ExprPhraseFree(sCtx.pPhrase); | 1624 fts5ExprPhraseFree(sCtx.pPhrase); |
1539 return 0; | 1625 return 0; |
1540 } | 1626 } |
1541 pParse->apPhrase = apNew; | 1627 pParse->apPhrase = apNew; |
1542 } | 1628 } |
1543 pParse->nPhrase++; | 1629 pParse->nPhrase++; |
1544 } | 1630 } |
1545 | 1631 |
| 1632 if( sCtx.pPhrase==0 ){ |
| 1633 /* This happens when parsing a token or quoted phrase that contains |
| 1634 ** no token characters at all. (e.g ... MATCH '""'). */ |
| 1635 sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase)); |
| 1636 }else if( sCtx.pPhrase->nTerm ){ |
| 1637 sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix; |
| 1638 } |
1546 pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; | 1639 pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; |
1547 assert( sCtx.pPhrase->nTerm>0 ); | |
1548 sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix; | |
1549 } | 1640 } |
1550 | 1641 |
1551 return sCtx.pPhrase; | 1642 return sCtx.pPhrase; |
1552 } | 1643 } |
1553 | 1644 |
1554 /* | 1645 /* |
1555 ** Create a new FTS5 expression by cloning phrase iPhrase of the | 1646 ** Create a new FTS5 expression by cloning phrase iPhrase of the |
1556 ** expression passed as the second argument. | 1647 ** expression passed as the second argument. |
1557 */ | 1648 */ |
1558 int sqlite3Fts5ExprClonePhrase( | 1649 int sqlite3Fts5ExprClonePhrase( |
1559 Fts5Config *pConfig, | |
1560 Fts5Expr *pExpr, | 1650 Fts5Expr *pExpr, |
1561 int iPhrase, | 1651 int iPhrase, |
1562 Fts5Expr **ppNew | 1652 Fts5Expr **ppNew |
1563 ){ | 1653 ){ |
1564 int rc = SQLITE_OK; /* Return code */ | 1654 int rc = SQLITE_OK; /* Return code */ |
1565 Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */ | 1655 Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */ |
1566 int i; /* Used to iterate through phrase terms */ | |
1567 | |
1568 Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ | 1656 Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ |
1569 | |
1570 TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */ | 1657 TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */ |
1571 | 1658 |
1572 | |
1573 pOrig = pExpr->apExprPhrase[iPhrase]; | 1659 pOrig = pExpr->apExprPhrase[iPhrase]; |
1574 | |
1575 pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); | 1660 pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); |
1576 if( rc==SQLITE_OK ){ | 1661 if( rc==SQLITE_OK ){ |
1577 pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, | 1662 pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, |
1578 sizeof(Fts5ExprPhrase*)); | 1663 sizeof(Fts5ExprPhrase*)); |
1579 } | 1664 } |
1580 if( rc==SQLITE_OK ){ | 1665 if( rc==SQLITE_OK ){ |
1581 pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, | 1666 pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, |
1582 sizeof(Fts5ExprNode)); | 1667 sizeof(Fts5ExprNode)); |
1583 } | 1668 } |
1584 if( rc==SQLITE_OK ){ | 1669 if( rc==SQLITE_OK ){ |
1585 pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, | 1670 pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, |
1586 sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); | 1671 sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); |
1587 } | 1672 } |
| 1673 if( rc==SQLITE_OK ){ |
| 1674 Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; |
| 1675 if( pColsetOrig ){ |
| 1676 int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); |
| 1677 Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); |
| 1678 if( pColset ){ |
| 1679 memcpy(pColset, pColsetOrig, nByte); |
| 1680 } |
| 1681 pNew->pRoot->pNear->pColset = pColset; |
| 1682 } |
| 1683 } |
1588 | 1684 |
1589 for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){ | 1685 if( pOrig->nTerm ){ |
1590 int tflags = 0; | 1686 int i; /* Used to iterate through phrase terms */ |
1591 Fts5ExprTerm *p; | 1687 for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){ |
1592 for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ | 1688 int tflags = 0; |
1593 const char *zTerm = p->zTerm; | 1689 Fts5ExprTerm *p; |
1594 rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), | 1690 for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ |
1595 0, 0); | 1691 const char *zTerm = p->zTerm; |
1596 tflags = FTS5_TOKEN_COLOCATED; | 1692 rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), |
| 1693 0, 0); |
| 1694 tflags = FTS5_TOKEN_COLOCATED; |
| 1695 } |
| 1696 if( rc==SQLITE_OK ){ |
| 1697 sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; |
| 1698 } |
1597 } | 1699 } |
1598 if( rc==SQLITE_OK ){ | 1700 }else{ |
1599 sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; | 1701 /* This happens when parsing a token or quoted phrase that contains |
1600 } | 1702 ** no token characters at all. (e.g ... MATCH '""'). */ |
| 1703 sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); |
1601 } | 1704 } |
1602 | 1705 |
1603 if( rc==SQLITE_OK ){ | 1706 if( rc==SQLITE_OK ){ |
1604 /* All the allocations succeeded. Put the expression object together. */ | 1707 /* All the allocations succeeded. Put the expression object together. */ |
1605 pNew->pIndex = pExpr->pIndex; | 1708 pNew->pIndex = pExpr->pIndex; |
| 1709 pNew->pConfig = pExpr->pConfig; |
1606 pNew->nPhrase = 1; | 1710 pNew->nPhrase = 1; |
1607 pNew->apExprPhrase[0] = sCtx.pPhrase; | 1711 pNew->apExprPhrase[0] = sCtx.pPhrase; |
1608 pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase; | 1712 pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase; |
1609 pNew->pRoot->pNear->nPhrase = 1; | 1713 pNew->pRoot->pNear->nPhrase = 1; |
1610 sCtx.pPhrase->pNode = pNew->pRoot; | 1714 sCtx.pPhrase->pNode = pNew->pRoot; |
1611 | 1715 |
1612 if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){ | 1716 if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){ |
1613 pNew->pRoot->eType = FTS5_TERM; | 1717 pNew->pRoot->eType = FTS5_TERM; |
| 1718 pNew->pRoot->xNext = fts5ExprNodeNext_TERM; |
1614 }else{ | 1719 }else{ |
1615 pNew->pRoot->eType = FTS5_STRING; | 1720 pNew->pRoot->eType = FTS5_STRING; |
| 1721 pNew->pRoot->xNext = fts5ExprNodeNext_STRING; |
1616 } | 1722 } |
1617 }else{ | 1723 }else{ |
1618 sqlite3Fts5ExprFree(pNew); | 1724 sqlite3Fts5ExprFree(pNew); |
1619 fts5ExprPhraseFree(sCtx.pPhrase); | 1725 fts5ExprPhraseFree(sCtx.pPhrase); |
1620 pNew = 0; | 1726 pNew = 0; |
1621 } | 1727 } |
1622 | 1728 |
1623 *ppNew = pNew; | 1729 *ppNew = pNew; |
1624 return rc; | 1730 return rc; |
1625 } | 1731 } |
(...skipping 10 matching lines...) Expand all Loading... |
1636 pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p | 1742 pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p |
1637 ); | 1743 ); |
1638 } | 1744 } |
1639 } | 1745 } |
1640 | 1746 |
1641 void sqlite3Fts5ParseSetDistance( | 1747 void sqlite3Fts5ParseSetDistance( |
1642 Fts5Parse *pParse, | 1748 Fts5Parse *pParse, |
1643 Fts5ExprNearset *pNear, | 1749 Fts5ExprNearset *pNear, |
1644 Fts5Token *p | 1750 Fts5Token *p |
1645 ){ | 1751 ){ |
1646 int nNear = 0; | 1752 if( pNear ){ |
1647 int i; | 1753 int nNear = 0; |
1648 if( p->n ){ | 1754 int i; |
1649 for(i=0; i<p->n; i++){ | 1755 if( p->n ){ |
1650 char c = (char)p->p[i]; | 1756 for(i=0; i<p->n; i++){ |
1651 if( c<'0' || c>'9' ){ | 1757 char c = (char)p->p[i]; |
1652 sqlite3Fts5ParseError( | 1758 if( c<'0' || c>'9' ){ |
1653 pParse, "expected integer, got \"%.*s\"", p->n, p->p | 1759 sqlite3Fts5ParseError( |
1654 ); | 1760 pParse, "expected integer, got \"%.*s\"", p->n, p->p |
1655 return; | 1761 ); |
| 1762 return; |
| 1763 } |
| 1764 nNear = nNear * 10 + (p->p[i] - '0'); |
1656 } | 1765 } |
1657 nNear = nNear * 10 + (p->p[i] - '0'); | 1766 }else{ |
| 1767 nNear = FTS5_DEFAULT_NEARDIST; |
1658 } | 1768 } |
1659 }else{ | 1769 pNear->nNear = nNear; |
1660 nNear = FTS5_DEFAULT_NEARDIST; | |
1661 } | 1770 } |
1662 pNear->nNear = nNear; | |
1663 } | 1771 } |
1664 | 1772 |
1665 /* | 1773 /* |
1666 ** The second argument passed to this function may be NULL, or it may be | 1774 ** The second argument passed to this function may be NULL, or it may be |
1667 ** an existing Fts5Colset object. This function returns a pointer to | 1775 ** an existing Fts5Colset object. This function returns a pointer to |
1668 ** a new colset object containing the contents of (p) with new value column | 1776 ** a new colset object containing the contents of (p) with new value column |
1669 ** number iCol appended. | 1777 ** number iCol appended. |
1670 ** | 1778 ** |
1671 ** If an OOM error occurs, store an error code in pParse and return NULL. | 1779 ** If an OOM error occurs, store an error code in pParse and return NULL. |
1672 ** The old colset object (if any) is not freed in this case. | 1780 ** The old colset object (if any) is not freed in this case. |
(...skipping 27 matching lines...) Expand all Loading... |
1700 | 1808 |
1701 #ifndef NDEBUG | 1809 #ifndef NDEBUG |
1702 /* Check that the array is in order and contains no duplicate entries. */ | 1810 /* Check that the array is in order and contains no duplicate entries. */ |
1703 for(i=1; i<pNew->nCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] ); | 1811 for(i=1; i<pNew->nCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] ); |
1704 #endif | 1812 #endif |
1705 } | 1813 } |
1706 | 1814 |
1707 return pNew; | 1815 return pNew; |
1708 } | 1816 } |
1709 | 1817 |
| 1818 /* |
| 1819 ** Allocate and return an Fts5Colset object specifying the inverse of |
| 1820 ** the colset passed as the second argument. Free the colset passed |
| 1821 ** as the second argument before returning. |
| 1822 */ |
| 1823 Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){ |
| 1824 Fts5Colset *pRet; |
| 1825 int nCol = pParse->pConfig->nCol; |
| 1826 |
| 1827 pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, |
| 1828 sizeof(Fts5Colset) + sizeof(int)*nCol |
| 1829 ); |
| 1830 if( pRet ){ |
| 1831 int i; |
| 1832 int iOld = 0; |
| 1833 for(i=0; i<nCol; i++){ |
| 1834 if( iOld>=p->nCol || p->aiCol[iOld]!=i ){ |
| 1835 pRet->aiCol[pRet->nCol++] = i; |
| 1836 }else{ |
| 1837 iOld++; |
| 1838 } |
| 1839 } |
| 1840 } |
| 1841 |
| 1842 sqlite3_free(p); |
| 1843 return pRet; |
| 1844 } |
| 1845 |
1710 Fts5Colset *sqlite3Fts5ParseColset( | 1846 Fts5Colset *sqlite3Fts5ParseColset( |
1711 Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ | 1847 Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ |
1712 Fts5Colset *pColset, /* Existing colset object */ | 1848 Fts5Colset *pColset, /* Existing colset object */ |
1713 Fts5Token *p | 1849 Fts5Token *p |
1714 ){ | 1850 ){ |
1715 Fts5Colset *pRet = 0; | 1851 Fts5Colset *pRet = 0; |
1716 int iCol; | 1852 int iCol; |
1717 char *z; /* Dequoted copy of token p */ | 1853 char *z; /* Dequoted copy of token p */ |
1718 | 1854 |
1719 z = sqlite3Fts5Strndup(&pParse->rc, p->p, p->n); | 1855 z = sqlite3Fts5Strndup(&pParse->rc, p->p, p->n); |
(...skipping 17 matching lines...) Expand all Loading... |
1737 } | 1873 } |
1738 | 1874 |
1739 return pRet; | 1875 return pRet; |
1740 } | 1876 } |
1741 | 1877 |
1742 void sqlite3Fts5ParseSetColset( | 1878 void sqlite3Fts5ParseSetColset( |
1743 Fts5Parse *pParse, | 1879 Fts5Parse *pParse, |
1744 Fts5ExprNearset *pNear, | 1880 Fts5ExprNearset *pNear, |
1745 Fts5Colset *pColset | 1881 Fts5Colset *pColset |
1746 ){ | 1882 ){ |
| 1883 if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ |
| 1884 pParse->rc = SQLITE_ERROR; |
| 1885 pParse->zErr = sqlite3_mprintf( |
| 1886 "fts5: column queries are not supported (detail=none)" |
| 1887 ); |
| 1888 sqlite3_free(pColset); |
| 1889 return; |
| 1890 } |
| 1891 |
1747 if( pNear ){ | 1892 if( pNear ){ |
1748 pNear->pColset = pColset; | 1893 pNear->pColset = pColset; |
1749 }else{ | 1894 }else{ |
1750 sqlite3_free(pColset); | 1895 sqlite3_free(pColset); |
1751 } | 1896 } |
1752 } | 1897 } |
1753 | 1898 |
| 1899 static void fts5ExprAssignXNext(Fts5ExprNode *pNode){ |
| 1900 switch( pNode->eType ){ |
| 1901 case FTS5_STRING: { |
| 1902 Fts5ExprNearset *pNear = pNode->pNear; |
| 1903 if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 |
| 1904 && pNear->apPhrase[0]->aTerm[0].pSynonym==0 |
| 1905 ){ |
| 1906 pNode->eType = FTS5_TERM; |
| 1907 pNode->xNext = fts5ExprNodeNext_TERM; |
| 1908 }else{ |
| 1909 pNode->xNext = fts5ExprNodeNext_STRING; |
| 1910 } |
| 1911 break; |
| 1912 }; |
| 1913 |
| 1914 case FTS5_OR: { |
| 1915 pNode->xNext = fts5ExprNodeNext_OR; |
| 1916 break; |
| 1917 }; |
| 1918 |
| 1919 case FTS5_AND: { |
| 1920 pNode->xNext = fts5ExprNodeNext_AND; |
| 1921 break; |
| 1922 }; |
| 1923 |
| 1924 default: assert( pNode->eType==FTS5_NOT ); { |
| 1925 pNode->xNext = fts5ExprNodeNext_NOT; |
| 1926 break; |
| 1927 }; |
| 1928 } |
| 1929 } |
| 1930 |
1754 static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){ | 1931 static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){ |
1755 if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){ | 1932 if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){ |
1756 int nByte = sizeof(Fts5ExprNode*) * pSub->nChild; | 1933 int nByte = sizeof(Fts5ExprNode*) * pSub->nChild; |
1757 memcpy(&p->apChild[p->nChild], pSub->apChild, nByte); | 1934 memcpy(&p->apChild[p->nChild], pSub->apChild, nByte); |
1758 p->nChild += pSub->nChild; | 1935 p->nChild += pSub->nChild; |
1759 sqlite3_free(pSub); | 1936 sqlite3_free(pSub); |
1760 }else{ | 1937 }else{ |
1761 p->apChild[p->nChild++] = pSub; | 1938 p->apChild[p->nChild++] = pSub; |
1762 } | 1939 } |
1763 } | 1940 } |
(...skipping 29 matching lines...) Expand all Loading... |
1793 if( pLeft->eType==eType ) nChild += pLeft->nChild-1; | 1970 if( pLeft->eType==eType ) nChild += pLeft->nChild-1; |
1794 if( pRight->eType==eType ) nChild += pRight->nChild-1; | 1971 if( pRight->eType==eType ) nChild += pRight->nChild-1; |
1795 } | 1972 } |
1796 | 1973 |
1797 nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); | 1974 nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); |
1798 pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); | 1975 pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); |
1799 | 1976 |
1800 if( pRet ){ | 1977 if( pRet ){ |
1801 pRet->eType = eType; | 1978 pRet->eType = eType; |
1802 pRet->pNear = pNear; | 1979 pRet->pNear = pNear; |
| 1980 fts5ExprAssignXNext(pRet); |
1803 if( eType==FTS5_STRING ){ | 1981 if( eType==FTS5_STRING ){ |
1804 int iPhrase; | 1982 int iPhrase; |
1805 for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){ | 1983 for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){ |
1806 pNear->apPhrase[iPhrase]->pNode = pRet; | 1984 pNear->apPhrase[iPhrase]->pNode = pRet; |
| 1985 if( pNear->apPhrase[iPhrase]->nTerm==0 ){ |
| 1986 pRet->xNext = 0; |
| 1987 pRet->eType = FTS5_EOF; |
| 1988 } |
1807 } | 1989 } |
1808 if( pNear->nPhrase==1 | 1990 |
1809 && pNear->apPhrase[0]->nTerm==1 | 1991 if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL |
1810 && pNear->apPhrase[0]->aTerm[0].pSynonym==0 | 1992 && (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1) |
1811 ){ | 1993 ){ |
1812 pRet->eType = FTS5_TERM; | 1994 assert( pParse->rc==SQLITE_OK ); |
| 1995 pParse->rc = SQLITE_ERROR; |
| 1996 assert( pParse->zErr==0 ); |
| 1997 pParse->zErr = sqlite3_mprintf( |
| 1998 "fts5: %s queries are not supported (detail!=full)", |
| 1999 pNear->nPhrase==1 ? "phrase": "NEAR" |
| 2000 ); |
| 2001 sqlite3_free(pRet); |
| 2002 pRet = 0; |
1813 } | 2003 } |
| 2004 |
1814 }else{ | 2005 }else{ |
1815 fts5ExprAddChildren(pRet, pLeft); | 2006 fts5ExprAddChildren(pRet, pLeft); |
1816 fts5ExprAddChildren(pRet, pRight); | 2007 fts5ExprAddChildren(pRet, pRight); |
1817 } | 2008 } |
1818 } | 2009 } |
1819 } | 2010 } |
1820 | 2011 |
1821 if( pRet==0 ){ | 2012 if( pRet==0 ){ |
1822 assert( pParse->rc!=SQLITE_OK ); | 2013 assert( pParse->rc!=SQLITE_OK ); |
1823 sqlite3Fts5ParseNodeFree(pLeft); | 2014 sqlite3Fts5ParseNodeFree(pLeft); |
1824 sqlite3Fts5ParseNodeFree(pRight); | 2015 sqlite3Fts5ParseNodeFree(pRight); |
1825 sqlite3Fts5ParseNearsetFree(pNear); | 2016 sqlite3Fts5ParseNearsetFree(pNear); |
1826 } | 2017 } |
1827 return pRet; | 2018 return pRet; |
1828 } | 2019 } |
1829 | 2020 |
| 2021 Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( |
| 2022 Fts5Parse *pParse, /* Parse context */ |
| 2023 Fts5ExprNode *pLeft, /* Left hand child expression */ |
| 2024 Fts5ExprNode *pRight /* Right hand child expression */ |
| 2025 ){ |
| 2026 Fts5ExprNode *pRet = 0; |
| 2027 Fts5ExprNode *pPrev; |
| 2028 |
| 2029 if( pParse->rc ){ |
| 2030 sqlite3Fts5ParseNodeFree(pLeft); |
| 2031 sqlite3Fts5ParseNodeFree(pRight); |
| 2032 }else{ |
| 2033 |
| 2034 assert( pLeft->eType==FTS5_STRING |
| 2035 || pLeft->eType==FTS5_TERM |
| 2036 || pLeft->eType==FTS5_EOF |
| 2037 || pLeft->eType==FTS5_AND |
| 2038 ); |
| 2039 assert( pRight->eType==FTS5_STRING |
| 2040 || pRight->eType==FTS5_TERM |
| 2041 || pRight->eType==FTS5_EOF |
| 2042 ); |
| 2043 |
| 2044 if( pLeft->eType==FTS5_AND ){ |
| 2045 pPrev = pLeft->apChild[pLeft->nChild-1]; |
| 2046 }else{ |
| 2047 pPrev = pLeft; |
| 2048 } |
| 2049 assert( pPrev->eType==FTS5_STRING |
| 2050 || pPrev->eType==FTS5_TERM |
| 2051 || pPrev->eType==FTS5_EOF |
| 2052 ); |
| 2053 |
| 2054 if( pRight->eType==FTS5_EOF ){ |
| 2055 assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] ); |
| 2056 sqlite3Fts5ParseNodeFree(pRight); |
| 2057 pRet = pLeft; |
| 2058 pParse->nPhrase--; |
| 2059 } |
| 2060 else if( pPrev->eType==FTS5_EOF ){ |
| 2061 Fts5ExprPhrase **ap; |
| 2062 |
| 2063 if( pPrev==pLeft ){ |
| 2064 pRet = pRight; |
| 2065 }else{ |
| 2066 pLeft->apChild[pLeft->nChild-1] = pRight; |
| 2067 pRet = pLeft; |
| 2068 } |
| 2069 |
| 2070 ap = &pParse->apPhrase[pParse->nPhrase-1-pRight->pNear->nPhrase]; |
| 2071 assert( ap[0]==pPrev->pNear->apPhrase[0] ); |
| 2072 memmove(ap, &ap[1], sizeof(Fts5ExprPhrase*)*pRight->pNear->nPhrase); |
| 2073 pParse->nPhrase--; |
| 2074 |
| 2075 sqlite3Fts5ParseNodeFree(pPrev); |
| 2076 } |
| 2077 else{ |
| 2078 pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0); |
| 2079 } |
| 2080 } |
| 2081 |
| 2082 return pRet; |
| 2083 } |
| 2084 |
1830 static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ | 2085 static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ |
1831 int nByte = 0; | 2086 int nByte = 0; |
1832 Fts5ExprTerm *p; | 2087 Fts5ExprTerm *p; |
1833 char *zQuoted; | 2088 char *zQuoted; |
1834 | 2089 |
1835 /* Determine the maximum amount of space required. */ | 2090 /* Determine the maximum amount of space required. */ |
1836 for(p=pTerm; p; p=p->pSynonym){ | 2091 for(p=pTerm; p; p=p->pSynonym){ |
1837 nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; | 2092 nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; |
1838 } | 2093 } |
1839 zQuoted = sqlite3_malloc(nByte); | 2094 zQuoted = sqlite3_malloc(nByte); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1916 zRet = fts5PrintfAppend(zRet, "--"); | 2171 zRet = fts5PrintfAppend(zRet, "--"); |
1917 if( zRet==0 ) return 0; | 2172 if( zRet==0 ) return 0; |
1918 | 2173 |
1919 for(i=0; i<pNear->nPhrase; i++){ | 2174 for(i=0; i<pNear->nPhrase; i++){ |
1920 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; | 2175 Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; |
1921 | 2176 |
1922 zRet = fts5PrintfAppend(zRet, " {"); | 2177 zRet = fts5PrintfAppend(zRet, " {"); |
1923 for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){ | 2178 for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){ |
1924 char *zTerm = pPhrase->aTerm[iTerm].zTerm; | 2179 char *zTerm = pPhrase->aTerm[iTerm].zTerm; |
1925 zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm); | 2180 zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm); |
| 2181 if( pPhrase->aTerm[iTerm].bPrefix ){ |
| 2182 zRet = fts5PrintfAppend(zRet, "*"); |
| 2183 } |
1926 } | 2184 } |
1927 | 2185 |
1928 if( zRet ) zRet = fts5PrintfAppend(zRet, "}"); | 2186 if( zRet ) zRet = fts5PrintfAppend(zRet, "}"); |
1929 if( zRet==0 ) return 0; | 2187 if( zRet==0 ) return 0; |
1930 } | 2188 } |
1931 | 2189 |
1932 }else{ | 2190 }else{ |
1933 char const *zOp = 0; | 2191 char const *zOp = 0; |
1934 int i; | 2192 int i; |
1935 switch( pExpr->eType ){ | 2193 switch( pExpr->eType ){ |
(...skipping 15 matching lines...) Expand all Loading... |
1951 zRet = fts5PrintfAppend(zRet, " [%z]", z); | 2209 zRet = fts5PrintfAppend(zRet, " [%z]", z); |
1952 } | 2210 } |
1953 } | 2211 } |
1954 } | 2212 } |
1955 | 2213 |
1956 return zRet; | 2214 return zRet; |
1957 } | 2215 } |
1958 | 2216 |
1959 static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ | 2217 static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ |
1960 char *zRet = 0; | 2218 char *zRet = 0; |
| 2219 if( pExpr->eType==0 ){ |
| 2220 return sqlite3_mprintf("\"\""); |
| 2221 }else |
1961 if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ | 2222 if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ |
1962 Fts5ExprNearset *pNear = pExpr->pNear; | 2223 Fts5ExprNearset *pNear = pExpr->pNear; |
1963 int i; | 2224 int i; |
1964 int iTerm; | 2225 int iTerm; |
1965 | 2226 |
1966 if( pNear->pColset ){ | 2227 if( pNear->pColset ){ |
1967 int iCol = pNear->pColset->aiCol[0]; | 2228 int iCol = pNear->pColset->aiCol[0]; |
1968 zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]); | 2229 zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]); |
1969 if( zRet==0 ) return 0; | 2230 if( zRet==0 ) return 0; |
1970 } | 2231 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2011 break; | 2272 break; |
2012 } | 2273 } |
2013 | 2274 |
2014 for(i=0; i<pExpr->nChild; i++){ | 2275 for(i=0; i<pExpr->nChild; i++){ |
2015 char *z = fts5ExprPrint(pConfig, pExpr->apChild[i]); | 2276 char *z = fts5ExprPrint(pConfig, pExpr->apChild[i]); |
2016 if( z==0 ){ | 2277 if( z==0 ){ |
2017 sqlite3_free(zRet); | 2278 sqlite3_free(zRet); |
2018 zRet = 0; | 2279 zRet = 0; |
2019 }else{ | 2280 }else{ |
2020 int e = pExpr->apChild[i]->eType; | 2281 int e = pExpr->apChild[i]->eType; |
2021 int b = (e!=FTS5_STRING && e!=FTS5_TERM); | 2282 int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF); |
2022 zRet = fts5PrintfAppend(zRet, "%s%s%z%s", | 2283 zRet = fts5PrintfAppend(zRet, "%s%s%z%s", |
2023 (i==0 ? "" : zOp), | 2284 (i==0 ? "" : zOp), |
2024 (b?"(":""), z, (b?")":"") | 2285 (b?"(":""), z, (b?")":"") |
2025 ); | 2286 ); |
2026 } | 2287 } |
2027 if( zRet==0 ) break; | 2288 if( zRet==0 ) break; |
2028 } | 2289 } |
2029 } | 2290 } |
2030 | 2291 |
2031 return zRet; | 2292 return zRet; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2083 } | 2344 } |
2084 | 2345 |
2085 zExpr = (const char*)sqlite3_value_text(apVal[0]); | 2346 zExpr = (const char*)sqlite3_value_text(apVal[0]); |
2086 | 2347 |
2087 rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr); | 2348 rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr); |
2088 if( rc==SQLITE_OK ){ | 2349 if( rc==SQLITE_OK ){ |
2089 rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr); | 2350 rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr); |
2090 } | 2351 } |
2091 if( rc==SQLITE_OK ){ | 2352 if( rc==SQLITE_OK ){ |
2092 char *zText; | 2353 char *zText; |
2093 if( pExpr->pRoot==0 ){ | 2354 if( pExpr->pRoot->xNext==0 ){ |
2094 zText = sqlite3_mprintf(""); | 2355 zText = sqlite3_mprintf(""); |
2095 }else if( bTcl ){ | 2356 }else if( bTcl ){ |
2096 zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot); | 2357 zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot); |
2097 }else{ | 2358 }else{ |
2098 zText = fts5ExprPrint(pConfig, pExpr->pRoot); | 2359 zText = fts5ExprPrint(pConfig, pExpr->pRoot); |
2099 } | 2360 } |
2100 if( zText==0 ){ | 2361 if( zText==0 ){ |
2101 rc = SQLITE_NOMEM; | 2362 rc = SQLITE_NOMEM; |
2102 }else{ | 2363 }else{ |
2103 sqlite3_result_text(pCtx, zText, -1, SQLITE_TRANSIENT); | 2364 sqlite3_result_text(pCtx, zText, -1, SQLITE_TRANSIENT); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2183 } aFunc[] = { | 2444 } aFunc[] = { |
2184 { "fts5_expr", fts5ExprFunctionHr }, | 2445 { "fts5_expr", fts5ExprFunctionHr }, |
2185 { "fts5_expr_tcl", fts5ExprFunctionTcl }, | 2446 { "fts5_expr_tcl", fts5ExprFunctionTcl }, |
2186 { "fts5_isalnum", fts5ExprIsAlnum }, | 2447 { "fts5_isalnum", fts5ExprIsAlnum }, |
2187 { "fts5_fold", fts5ExprFold }, | 2448 { "fts5_fold", fts5ExprFold }, |
2188 }; | 2449 }; |
2189 int i; | 2450 int i; |
2190 int rc = SQLITE_OK; | 2451 int rc = SQLITE_OK; |
2191 void *pCtx = (void*)pGlobal; | 2452 void *pCtx = (void*)pGlobal; |
2192 | 2453 |
2193 for(i=0; rc==SQLITE_OK && i<(int)ArraySize(aFunc); i++){ | 2454 for(i=0; rc==SQLITE_OK && i<ArraySize(aFunc); i++){ |
2194 struct Fts5ExprFunc *p = &aFunc[i]; | 2455 struct Fts5ExprFunc *p = &aFunc[i]; |
2195 rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); | 2456 rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); |
2196 } | 2457 } |
2197 | 2458 |
2198 /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */ | 2459 /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */ |
2199 #ifndef NDEBUG | 2460 #ifndef NDEBUG |
2200 (void)sqlite3Fts5ParserTrace; | 2461 (void)sqlite3Fts5ParserTrace; |
2201 #endif | 2462 #endif |
2202 | 2463 |
2203 return rc; | 2464 return rc; |
(...skipping 24 matching lines...) Expand all Loading... |
2228 Fts5ExprNode *pNode = pPhrase->pNode; | 2489 Fts5ExprNode *pNode = pPhrase->pNode; |
2229 if( pNode->bEof==0 && pNode->iRowid==pExpr->pRoot->iRowid ){ | 2490 if( pNode->bEof==0 && pNode->iRowid==pExpr->pRoot->iRowid ){ |
2230 *pa = pPhrase->poslist.p; | 2491 *pa = pPhrase->poslist.p; |
2231 nRet = pPhrase->poslist.n; | 2492 nRet = pPhrase->poslist.n; |
2232 }else{ | 2493 }else{ |
2233 *pa = 0; | 2494 *pa = 0; |
2234 nRet = 0; | 2495 nRet = 0; |
2235 } | 2496 } |
2236 return nRet; | 2497 return nRet; |
2237 } | 2498 } |
| 2499 |
| 2500 struct Fts5PoslistPopulator { |
| 2501 Fts5PoslistWriter writer; |
| 2502 int bOk; /* True if ok to populate */ |
| 2503 int bMiss; |
| 2504 }; |
| 2505 |
| 2506 Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ |
| 2507 Fts5PoslistPopulator *pRet; |
| 2508 pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); |
| 2509 if( pRet ){ |
| 2510 int i; |
| 2511 memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); |
| 2512 for(i=0; i<pExpr->nPhrase; i++){ |
| 2513 Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist; |
| 2514 Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; |
| 2515 assert( pExpr->apExprPhrase[i]->nTerm==1 ); |
| 2516 if( bLive && |
| 2517 (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof) |
| 2518 ){ |
| 2519 pRet[i].bMiss = 1; |
| 2520 }else{ |
| 2521 pBuf->n = 0; |
| 2522 } |
| 2523 } |
| 2524 } |
| 2525 return pRet; |
| 2526 } |
| 2527 |
| 2528 struct Fts5ExprCtx { |
| 2529 Fts5Expr *pExpr; |
| 2530 Fts5PoslistPopulator *aPopulator; |
| 2531 i64 iOff; |
| 2532 }; |
| 2533 typedef struct Fts5ExprCtx Fts5ExprCtx; |
| 2534 |
| 2535 /* |
| 2536 ** TODO: Make this more efficient! |
| 2537 */ |
| 2538 static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){ |
| 2539 int i; |
| 2540 for(i=0; i<pColset->nCol; i++){ |
| 2541 if( pColset->aiCol[i]==iCol ) return 1; |
| 2542 } |
| 2543 return 0; |
| 2544 } |
| 2545 |
| 2546 static int fts5ExprPopulatePoslistsCb( |
| 2547 void *pCtx, /* Copy of 2nd argument to xTokenize() */ |
| 2548 int tflags, /* Mask of FTS5_TOKEN_* flags */ |
| 2549 const char *pToken, /* Pointer to buffer containing token */ |
| 2550 int nToken, /* Size of token in bytes */ |
| 2551 int iUnused1, /* Byte offset of token within input text */ |
| 2552 int iUnused2 /* Byte offset of end of token within input text */ |
| 2553 ){ |
| 2554 Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx; |
| 2555 Fts5Expr *pExpr = p->pExpr; |
| 2556 int i; |
| 2557 |
| 2558 UNUSED_PARAM2(iUnused1, iUnused2); |
| 2559 |
| 2560 if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; |
| 2561 if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++; |
| 2562 for(i=0; i<pExpr->nPhrase; i++){ |
| 2563 Fts5ExprTerm *pTerm; |
| 2564 if( p->aPopulator[i].bOk==0 ) continue; |
| 2565 for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ |
| 2566 int nTerm = (int)strlen(pTerm->zTerm); |
| 2567 if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix)) |
| 2568 && memcmp(pTerm->zTerm, pToken, nTerm)==0 |
| 2569 ){ |
| 2570 int rc = sqlite3Fts5PoslistWriterAppend( |
| 2571 &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff |
| 2572 ); |
| 2573 if( rc ) return rc; |
| 2574 break; |
| 2575 } |
| 2576 } |
| 2577 } |
| 2578 return SQLITE_OK; |
| 2579 } |
| 2580 |
| 2581 int sqlite3Fts5ExprPopulatePoslists( |
| 2582 Fts5Config *pConfig, |
| 2583 Fts5Expr *pExpr, |
| 2584 Fts5PoslistPopulator *aPopulator, |
| 2585 int iCol, |
| 2586 const char *z, int n |
| 2587 ){ |
| 2588 int i; |
| 2589 Fts5ExprCtx sCtx; |
| 2590 sCtx.pExpr = pExpr; |
| 2591 sCtx.aPopulator = aPopulator; |
| 2592 sCtx.iOff = (((i64)iCol) << 32) - 1; |
| 2593 |
| 2594 for(i=0; i<pExpr->nPhrase; i++){ |
| 2595 Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; |
| 2596 Fts5Colset *pColset = pNode->pNear->pColset; |
| 2597 if( (pColset && 0==fts5ExprColsetTest(pColset, iCol)) |
| 2598 || aPopulator[i].bMiss |
| 2599 ){ |
| 2600 aPopulator[i].bOk = 0; |
| 2601 }else{ |
| 2602 aPopulator[i].bOk = 1; |
| 2603 } |
| 2604 } |
| 2605 |
| 2606 return sqlite3Fts5Tokenize(pConfig, |
| 2607 FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb |
| 2608 ); |
| 2609 } |
| 2610 |
| 2611 static void fts5ExprClearPoslists(Fts5ExprNode *pNode){ |
| 2612 if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){ |
| 2613 pNode->pNear->apPhrase[0]->poslist.n = 0; |
| 2614 }else{ |
| 2615 int i; |
| 2616 for(i=0; i<pNode->nChild; i++){ |
| 2617 fts5ExprClearPoslists(pNode->apChild[i]); |
| 2618 } |
| 2619 } |
| 2620 } |
| 2621 |
| 2622 static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){ |
| 2623 pNode->iRowid = iRowid; |
| 2624 pNode->bEof = 0; |
| 2625 switch( pNode->eType ){ |
| 2626 case FTS5_TERM: |
| 2627 case FTS5_STRING: |
| 2628 return (pNode->pNear->apPhrase[0]->poslist.n>0); |
| 2629 |
| 2630 case FTS5_AND: { |
| 2631 int i; |
| 2632 for(i=0; i<pNode->nChild; i++){ |
| 2633 if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){ |
| 2634 fts5ExprClearPoslists(pNode); |
| 2635 return 0; |
| 2636 } |
| 2637 } |
| 2638 break; |
| 2639 } |
| 2640 |
| 2641 case FTS5_OR: { |
| 2642 int i; |
| 2643 int bRet = 0; |
| 2644 for(i=0; i<pNode->nChild; i++){ |
| 2645 if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){ |
| 2646 bRet = 1; |
| 2647 } |
| 2648 } |
| 2649 return bRet; |
| 2650 } |
| 2651 |
| 2652 default: { |
| 2653 assert( pNode->eType==FTS5_NOT ); |
| 2654 if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid) |
| 2655 || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid) |
| 2656 ){ |
| 2657 fts5ExprClearPoslists(pNode); |
| 2658 return 0; |
| 2659 } |
| 2660 break; |
| 2661 } |
| 2662 } |
| 2663 return 1; |
| 2664 } |
| 2665 |
| 2666 void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ |
| 2667 fts5ExprCheckPoslists(pExpr->pRoot, iRowid); |
| 2668 } |
| 2669 |
| 2670 /* |
| 2671 ** This function is only called for detail=columns tables. |
| 2672 */ |
| 2673 int sqlite3Fts5ExprPhraseCollist( |
| 2674 Fts5Expr *pExpr, |
| 2675 int iPhrase, |
| 2676 const u8 **ppCollist, |
| 2677 int *pnCollist |
| 2678 ){ |
| 2679 Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase]; |
| 2680 Fts5ExprNode *pNode = pPhrase->pNode; |
| 2681 int rc = SQLITE_OK; |
| 2682 |
| 2683 assert( iPhrase>=0 && iPhrase<pExpr->nPhrase ); |
| 2684 assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); |
| 2685 |
| 2686 if( pNode->bEof==0 |
| 2687 && pNode->iRowid==pExpr->pRoot->iRowid |
| 2688 && pPhrase->poslist.n>0 |
| 2689 ){ |
| 2690 Fts5ExprTerm *pTerm = &pPhrase->aTerm[0]; |
| 2691 if( pTerm->pSynonym ){ |
| 2692 Fts5Buffer *pBuf = (Fts5Buffer*)&pTerm->pSynonym[1]; |
| 2693 rc = fts5ExprSynonymList( |
| 2694 pTerm, pNode->iRowid, pBuf, (u8**)ppCollist, pnCollist |
| 2695 ); |
| 2696 }else{ |
| 2697 *ppCollist = pPhrase->aTerm[0].pIter->pData; |
| 2698 *pnCollist = pPhrase->aTerm[0].pIter->nData; |
| 2699 } |
| 2700 }else{ |
| 2701 *ppCollist = 0; |
| 2702 *pnCollist = 0; |
| 2703 } |
| 2704 |
| 2705 return rc; |
| 2706 } |
| 2707 |
OLD | NEW |