OLD | NEW |
1 /* | 1 /* |
2 ** 2008 Nov 28 | 2 ** 2008 Nov 28 |
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 ** |
11 ****************************************************************************** | 11 ****************************************************************************** |
12 ** | 12 ** |
13 ** This module contains code that implements a parser for fts3 query strings | 13 ** This module contains code that implements a parser for fts3 query strings |
14 ** (the right-hand argument to the MATCH operator). Because the supported | 14 ** (the right-hand argument to the MATCH operator). Because the supported |
15 ** syntax is relatively simple, the whole tokenizer/parser system is | 15 ** syntax is relatively simple, the whole tokenizer/parser system is |
16 ** hand-coded. The public interface to this module is declared in source | 16 ** hand-coded. |
17 ** code file "fts3_expr.h". | |
18 */ | 17 */ |
19 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) | 18 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) |
20 | 19 |
21 /* | 20 /* |
22 ** By default, this module parses the legacy syntax that has been | 21 ** By default, this module parses the legacy syntax that has been |
23 ** traditionally used by fts3. Or, if SQLITE_ENABLE_FTS3_PARENTHESIS | 22 ** traditionally used by fts3. Or, if SQLITE_ENABLE_FTS3_PARENTHESIS |
24 ** is defined, then it uses the new syntax. The differences between | 23 ** is defined, then it uses the new syntax. The differences between |
25 ** the new and the old syntaxes are: | 24 ** the new and the old syntaxes are: |
26 ** | 25 ** |
27 ** a) The new syntax supports parenthesis. The old does not. | 26 ** a) The new syntax supports parenthesis. The old does not. |
28 ** | 27 ** |
29 ** b) The new syntax supports the AND and NOT operators. The old does not. | 28 ** b) The new syntax supports the AND and NOT operators. The old does not. |
30 ** | 29 ** |
31 ** c) The old syntax supports the "-" token qualifier. This is not | 30 ** c) The old syntax supports the "-" token qualifier. This is not |
32 ** supported by the new syntax (it is replaced by the NOT operator). | 31 ** supported by the new syntax (it is replaced by the NOT operator). |
33 ** | 32 ** |
34 ** d) When using the old syntax, the OR operator has a greater precedence | 33 ** d) When using the old syntax, the OR operator has a greater precedence |
35 ** than an implicit AND. When using the new, both implicity and explicit | 34 ** than an implicit AND. When using the new, both implicity and explicit |
36 ** AND operators have a higher precedence than OR. | 35 ** AND operators have a higher precedence than OR. |
37 ** | 36 ** |
38 ** If compiled with SQLITE_TEST defined, then this module exports the | 37 ** If compiled with SQLITE_TEST defined, then this module exports the |
39 ** symbol "int sqlite3_fts3_enable_parentheses". Setting this variable | 38 ** symbol "int sqlite3_fts3_enable_parentheses". Setting this variable |
40 ** to zero causes the module to use the old syntax. If it is set to | 39 ** to zero causes the module to use the old syntax. If it is set to |
41 ** non-zero the new syntax is activated. This is so both syntaxes can | 40 ** non-zero the new syntax is activated. This is so both syntaxes can |
42 ** be tested using a single build of testfixture. | 41 ** be tested using a single build of testfixture. |
| 42 ** |
| 43 ** The following describes the syntax supported by the fts3 MATCH |
| 44 ** operator in a similar format to that used by the lemon parser |
| 45 ** generator. This module does not use actually lemon, it uses a |
| 46 ** custom parser. |
| 47 ** |
| 48 ** query ::= andexpr (OR andexpr)*. |
| 49 ** |
| 50 ** andexpr ::= notexpr (AND? notexpr)*. |
| 51 ** |
| 52 ** notexpr ::= nearexpr (NOT nearexpr|-TOKEN)*. |
| 53 ** notexpr ::= LP query RP. |
| 54 ** |
| 55 ** nearexpr ::= phrase (NEAR distance_opt nearexpr)*. |
| 56 ** |
| 57 ** distance_opt ::= . |
| 58 ** distance_opt ::= / INTEGER. |
| 59 ** |
| 60 ** phrase ::= TOKEN. |
| 61 ** phrase ::= COLUMN:TOKEN. |
| 62 ** phrase ::= "TOKEN TOKEN TOKEN...". |
43 */ | 63 */ |
| 64 |
44 #ifdef SQLITE_TEST | 65 #ifdef SQLITE_TEST |
45 int sqlite3_fts3_enable_parentheses = 0; | 66 int sqlite3_fts3_enable_parentheses = 0; |
46 #else | 67 #else |
47 # ifdef SQLITE_ENABLE_FTS3_PARENTHESIS | 68 # ifdef SQLITE_ENABLE_FTS3_PARENTHESIS |
48 # define sqlite3_fts3_enable_parentheses 1 | 69 # define sqlite3_fts3_enable_parentheses 1 |
49 # else | 70 # else |
50 # define sqlite3_fts3_enable_parentheses 0 | 71 # define sqlite3_fts3_enable_parentheses 0 |
51 # endif | 72 # endif |
52 #endif | 73 #endif |
53 | 74 |
54 /* | 75 /* |
55 ** Default span for NEAR operators. | 76 ** Default span for NEAR operators. |
56 */ | 77 */ |
57 #define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10 | 78 #define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10 |
58 | 79 |
59 #include "fts3_expr.h" | 80 #include "fts3Int.h" |
60 #include "sqlite3.h" | |
61 #include <string.h> | 81 #include <string.h> |
62 #include <assert.h> | 82 #include <assert.h> |
63 | 83 |
64 typedef struct ParseContext ParseContext; | 84 typedef struct ParseContext ParseContext; |
65 struct ParseContext { | 85 struct ParseContext { |
66 sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ | 86 sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ |
67 const char **azCol; /* Array of column names for fts3 table */ | 87 const char **azCol; /* Array of column names for fts3 table */ |
68 int nCol; /* Number of entries in azCol[] */ | 88 int nCol; /* Number of entries in azCol[] */ |
69 int iDefaultCol; /* Default column to query */ | 89 int iDefaultCol; /* Default column to query */ |
70 sqlite3_context *pCtx; /* Write error message here */ | 90 sqlite3_context *pCtx; /* Write error message here */ |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 *pnConsumed = nConsumed; | 173 *pnConsumed = nConsumed; |
154 *ppExpr = pRet; | 174 *ppExpr = pRet; |
155 return rc; | 175 return rc; |
156 } | 176 } |
157 | 177 |
158 | 178 |
159 /* | 179 /* |
160 ** Enlarge a memory allocation. If an out-of-memory allocation occurs, | 180 ** Enlarge a memory allocation. If an out-of-memory allocation occurs, |
161 ** then free the old allocation. | 181 ** then free the old allocation. |
162 */ | 182 */ |
163 void *fts3ReallocOrFree(void *pOrig, int nNew){ | 183 static void *fts3ReallocOrFree(void *pOrig, int nNew){ |
164 void *pRet = sqlite3_realloc(pOrig, nNew); | 184 void *pRet = sqlite3_realloc(pOrig, nNew); |
165 if( !pRet ){ | 185 if( !pRet ){ |
166 sqlite3_free(pOrig); | 186 sqlite3_free(pOrig); |
167 } | 187 } |
168 return pRet; | 188 return pRet; |
169 } | 189 } |
170 | 190 |
171 /* | 191 /* |
172 ** Buffer zInput, length nInput, contains the contents of a quoted string | 192 ** Buffer zInput, length nInput, contains the contents of a quoted string |
173 ** that appeared as part of an fts3 query expression. Neither quote character | 193 ** that appeared as part of an fts3 query expression. Neither quote character |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 } | 244 } |
225 } | 245 } |
226 } | 246 } |
227 | 247 |
228 pModule->xClose(pCursor); | 248 pModule->xClose(pCursor); |
229 pCursor = 0; | 249 pCursor = 0; |
230 } | 250 } |
231 | 251 |
232 if( rc==SQLITE_DONE ){ | 252 if( rc==SQLITE_DONE ){ |
233 int jj; | 253 int jj; |
234 char *zNew; | 254 char *zNew = NULL; |
235 int nNew = 0; | 255 int nNew = 0; |
236 int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase); | 256 int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase); |
237 nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(struct PhraseToken); | 257 nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(struct PhraseToken); |
238 p = fts3ReallocOrFree(p, nByte + nTemp); | 258 p = fts3ReallocOrFree(p, nByte + nTemp); |
239 if( !p ){ | 259 if( !p ){ |
240 goto no_mem; | 260 goto no_mem; |
241 } | 261 } |
242 if( zTemp ){ | 262 if( zTemp ){ |
243 zNew = &(((char *)p)[nByte]); | 263 zNew = &(((char *)p)[nByte]); |
244 memcpy(zNew, zTemp, nTemp); | 264 memcpy(zNew, zTemp, nTemp); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 ** if a malloc failure occurs, or SQLITE_ERROR if a parse error is encountered. | 303 ** if a malloc failure occurs, or SQLITE_ERROR if a parse error is encountered. |
284 ** If SQLITE_ERROR is returned, pContext is populated with an error message. | 304 ** If SQLITE_ERROR is returned, pContext is populated with an error message. |
285 */ | 305 */ |
286 static int getNextNode( | 306 static int getNextNode( |
287 ParseContext *pParse, /* fts3 query parse context */ | 307 ParseContext *pParse, /* fts3 query parse context */ |
288 const char *z, int n, /* Input string */ | 308 const char *z, int n, /* Input string */ |
289 Fts3Expr **ppExpr, /* OUT: expression */ | 309 Fts3Expr **ppExpr, /* OUT: expression */ |
290 int *pnConsumed /* OUT: Number of bytes consumed */ | 310 int *pnConsumed /* OUT: Number of bytes consumed */ |
291 ){ | 311 ){ |
292 static const struct Fts3Keyword { | 312 static const struct Fts3Keyword { |
293 char z[4]; /* Keyword text */ | 313 char *z; /* Keyword text */ |
294 unsigned char n; /* Length of the keyword */ | 314 unsigned char n; /* Length of the keyword */ |
295 unsigned char parenOnly; /* Only valid in paren mode */ | 315 unsigned char parenOnly; /* Only valid in paren mode */ |
296 unsigned char eType; /* Keyword code */ | 316 unsigned char eType; /* Keyword code */ |
297 } aKeyword[] = { | 317 } aKeyword[] = { |
298 { "OR" , 2, 0, FTSQUERY_OR }, | 318 { "OR" , 2, 0, FTSQUERY_OR }, |
299 { "AND", 3, 1, FTSQUERY_AND }, | 319 { "AND", 3, 1, FTSQUERY_AND }, |
300 { "NOT", 3, 1, FTSQUERY_NOT }, | 320 { "NOT", 3, 1, FTSQUERY_NOT }, |
301 { "NEAR", 4, 0, FTSQUERY_NEAR } | 321 { "NEAR", 4, 0, FTSQUERY_NEAR } |
302 }; | 322 }; |
303 int ii; | 323 int ii; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 | 366 |
347 /* At this point this is probably a keyword. But for that to be true, | 367 /* At this point this is probably a keyword. But for that to be true, |
348 ** the next byte must contain either whitespace, an open or close | 368 ** the next byte must contain either whitespace, an open or close |
349 ** parenthesis, a quote character, or EOF. | 369 ** parenthesis, a quote character, or EOF. |
350 */ | 370 */ |
351 cNext = zInput[nKey]; | 371 cNext = zInput[nKey]; |
352 if( fts3isspace(cNext) | 372 if( fts3isspace(cNext) |
353 || cNext=='"' || cNext=='(' || cNext==')' || cNext==0 | 373 || cNext=='"' || cNext=='(' || cNext==')' || cNext==0 |
354 ){ | 374 ){ |
355 pRet = (Fts3Expr *)sqlite3_malloc(sizeof(Fts3Expr)); | 375 pRet = (Fts3Expr *)sqlite3_malloc(sizeof(Fts3Expr)); |
| 376 if( !pRet ){ |
| 377 return SQLITE_NOMEM; |
| 378 } |
356 memset(pRet, 0, sizeof(Fts3Expr)); | 379 memset(pRet, 0, sizeof(Fts3Expr)); |
357 pRet->eType = pKey->eType; | 380 pRet->eType = pKey->eType; |
358 pRet->nNear = nNear; | 381 pRet->nNear = nNear; |
359 *ppExpr = pRet; | 382 *ppExpr = pRet; |
360 *pnConsumed = (zInput - z) + nKey; | 383 *pnConsumed = (int)((zInput - z) + nKey); |
361 return SQLITE_OK; | 384 return SQLITE_OK; |
362 } | 385 } |
363 | 386 |
364 /* Turns out that wasn't a keyword after all. This happens if the | 387 /* Turns out that wasn't a keyword after all. This happens if the |
365 ** user has supplied a token such as "ORacle". Continue. | 388 ** user has supplied a token such as "ORacle". Continue. |
366 */ | 389 */ |
367 } | 390 } |
368 } | 391 } |
369 | 392 |
370 /* Check for an open bracket. */ | 393 /* Check for an open bracket. */ |
371 if( sqlite3_fts3_enable_parentheses ){ | 394 if( sqlite3_fts3_enable_parentheses ){ |
372 if( *zInput=='(' ){ | 395 if( *zInput=='(' ){ |
373 int nConsumed; | 396 int nConsumed; |
374 int rc; | 397 int rc; |
375 pParse->nNest++; | 398 pParse->nNest++; |
376 rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed); | 399 rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed); |
377 if( rc==SQLITE_OK && !*ppExpr ){ | 400 if( rc==SQLITE_OK && !*ppExpr ){ |
378 rc = SQLITE_DONE; | 401 rc = SQLITE_DONE; |
379 } | 402 } |
380 *pnConsumed = (zInput - z) + 1 + nConsumed; | 403 *pnConsumed = (int)((zInput - z) + 1 + nConsumed); |
381 return rc; | 404 return rc; |
382 } | 405 } |
383 | 406 |
384 /* Check for a close bracket. */ | 407 /* Check for a close bracket. */ |
385 if( *zInput==')' ){ | 408 if( *zInput==')' ){ |
386 pParse->nNest--; | 409 pParse->nNest--; |
387 *pnConsumed = (zInput - z) + 1; | 410 *pnConsumed = (int)((zInput - z) + 1); |
388 return SQLITE_DONE; | 411 return SQLITE_DONE; |
389 } | 412 } |
390 } | 413 } |
391 | 414 |
392 /* See if we are dealing with a quoted phrase. If this is the case, then | 415 /* See if we are dealing with a quoted phrase. If this is the case, then |
393 ** search for the closing quote and pass the whole string to getNextString() | 416 ** search for the closing quote and pass the whole string to getNextString() |
394 ** for processing. This is easy to do, as fts3 has no syntax for escaping | 417 ** for processing. This is easy to do, as fts3 has no syntax for escaping |
395 ** a quote character embedded in a string. | 418 ** a quote character embedded in a string. |
396 */ | 419 */ |
397 if( *zInput=='"' ){ | 420 if( *zInput=='"' ){ |
398 for(ii=1; ii<nInput && zInput[ii]!='"'; ii++); | 421 for(ii=1; ii<nInput && zInput[ii]!='"'; ii++); |
399 *pnConsumed = (zInput - z) + ii + 1; | 422 *pnConsumed = (int)((zInput - z) + ii + 1); |
400 if( ii==nInput ){ | 423 if( ii==nInput ){ |
401 return SQLITE_ERROR; | 424 return SQLITE_ERROR; |
402 } | 425 } |
403 return getNextString(pParse, &zInput[1], ii-1, ppExpr); | 426 return getNextString(pParse, &zInput[1], ii-1, ppExpr); |
404 } | 427 } |
405 | 428 |
406 | 429 |
407 /* If control flows to this point, this must be a regular token, or | 430 /* If control flows to this point, this must be a regular token, or |
408 ** the end of the input. Read a regular token using the sqlite3_tokenizer | 431 ** the end of the input. Read a regular token using the sqlite3_tokenizer |
409 ** interface. Before doing so, figure out if there is an explicit | 432 ** interface. Before doing so, figure out if there is an explicit |
410 ** column specifier for the token. | 433 ** column specifier for the token. |
411 ** | 434 ** |
412 ** TODO: Strangely, it is not possible to associate a column specifier | 435 ** TODO: Strangely, it is not possible to associate a column specifier |
413 ** with a quoted phrase, only with a single token. Not sure if this was | 436 ** with a quoted phrase, only with a single token. Not sure if this was |
414 ** an implementation artifact or an intentional decision when fts3 was | 437 ** an implementation artifact or an intentional decision when fts3 was |
415 ** first implemented. Whichever it was, this module duplicates the | 438 ** first implemented. Whichever it was, this module duplicates the |
416 ** limitation. | 439 ** limitation. |
417 */ | 440 */ |
418 iCol = pParse->iDefaultCol; | 441 iCol = pParse->iDefaultCol; |
419 iColLen = 0; | 442 iColLen = 0; |
420 for(ii=0; ii<pParse->nCol; ii++){ | 443 for(ii=0; ii<pParse->nCol; ii++){ |
421 const char *zStr = pParse->azCol[ii]; | 444 const char *zStr = pParse->azCol[ii]; |
422 int nStr = strlen(zStr); | 445 int nStr = (int)strlen(zStr); |
423 if( nInput>nStr && zInput[nStr]==':' | 446 if( nInput>nStr && zInput[nStr]==':' |
424 && sqlite3_strnicmp(zStr, zInput, nStr)==0 | 447 && sqlite3_strnicmp(zStr, zInput, nStr)==0 |
425 ){ | 448 ){ |
426 iCol = ii; | 449 iCol = ii; |
427 iColLen = ((zInput - z) + nStr + 1); | 450 iColLen = (int)((zInput - z) + nStr + 1); |
428 break; | 451 break; |
429 } | 452 } |
430 } | 453 } |
431 rc = getNextToken(pParse, iCol, &z[iColLen], n-iColLen, ppExpr, pnConsumed); | 454 rc = getNextToken(pParse, iCol, &z[iColLen], n-iColLen, ppExpr, pnConsumed); |
432 *pnConsumed += iColLen; | 455 *pnConsumed += iColLen; |
433 return rc; | 456 return rc; |
434 } | 457 } |
435 | 458 |
436 /* | 459 /* |
437 ** The argument is an Fts3Expr structure for a binary operator (any type | 460 ** The argument is an Fts3Expr structure for a binary operator (any type |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
683 sParse.pTokenizer = pTokenizer; | 706 sParse.pTokenizer = pTokenizer; |
684 sParse.azCol = (const char **)azCol; | 707 sParse.azCol = (const char **)azCol; |
685 sParse.nCol = nCol; | 708 sParse.nCol = nCol; |
686 sParse.iDefaultCol = iDefaultCol; | 709 sParse.iDefaultCol = iDefaultCol; |
687 sParse.nNest = 0; | 710 sParse.nNest = 0; |
688 if( z==0 ){ | 711 if( z==0 ){ |
689 *ppExpr = 0; | 712 *ppExpr = 0; |
690 return SQLITE_OK; | 713 return SQLITE_OK; |
691 } | 714 } |
692 if( n<0 ){ | 715 if( n<0 ){ |
693 n = strlen(z); | 716 n = (int)strlen(z); |
694 } | 717 } |
695 rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed); | 718 rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed); |
696 | 719 |
697 /* Check for mismatched parenthesis */ | 720 /* Check for mismatched parenthesis */ |
698 if( rc==SQLITE_OK && sParse.nNest ){ | 721 if( rc==SQLITE_OK && sParse.nNest ){ |
699 rc = SQLITE_ERROR; | 722 rc = SQLITE_ERROR; |
700 sqlite3Fts3ExprFree(*ppExpr); | 723 sqlite3Fts3ExprFree(*ppExpr); |
701 *ppExpr = 0; | 724 *ppExpr = 0; |
702 } | 725 } |
703 | 726 |
704 return rc; | 727 return rc; |
705 } | 728 } |
706 | 729 |
707 /* | 730 /* |
708 ** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse(). | 731 ** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse(). |
709 */ | 732 */ |
710 void sqlite3Fts3ExprFree(Fts3Expr *p){ | 733 void sqlite3Fts3ExprFree(Fts3Expr *p){ |
711 if( p ){ | 734 if( p ){ |
712 sqlite3Fts3ExprFree(p->pLeft); | 735 sqlite3Fts3ExprFree(p->pLeft); |
713 sqlite3Fts3ExprFree(p->pRight); | 736 sqlite3Fts3ExprFree(p->pRight); |
| 737 sqlite3_free(p->aDoclist); |
714 sqlite3_free(p); | 738 sqlite3_free(p); |
715 } | 739 } |
716 } | 740 } |
717 | 741 |
718 /**************************************************************************** | 742 /**************************************************************************** |
719 ***************************************************************************** | 743 ***************************************************************************** |
720 ** Everything after this point is just test code. | 744 ** Everything after this point is just test code. |
721 */ | 745 */ |
722 | 746 |
723 #ifdef SQLITE_TEST | 747 #ifdef SQLITE_TEST |
(...skipping 14 matching lines...) Expand all Loading... |
738 | 762 |
739 *pp = 0; | 763 *pp = 0; |
740 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); | 764 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); |
741 if( rc!=SQLITE_OK ){ | 765 if( rc!=SQLITE_OK ){ |
742 return rc; | 766 return rc; |
743 } | 767 } |
744 | 768 |
745 sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); | 769 sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); |
746 if( SQLITE_ROW==sqlite3_step(pStmt) ){ | 770 if( SQLITE_ROW==sqlite3_step(pStmt) ){ |
747 if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){ | 771 if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){ |
748 memcpy(pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); | 772 memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); |
749 } | 773 } |
750 } | 774 } |
751 | 775 |
752 return sqlite3_finalize(pStmt); | 776 return sqlite3_finalize(pStmt); |
753 } | 777 } |
754 | 778 |
755 /* | 779 /* |
756 ** This function is part of the test interface for the query parser. It | 780 ** This function is part of the test interface for the query parser. It |
757 ** writes a text representation of the query expression pExpr into the | 781 ** writes a text representation of the query expression pExpr into the |
758 ** buffer pointed to by argument zBuf. It is assumed that zBuf is large | 782 ** buffer pointed to by argument zBuf. It is assumed that zBuf is large |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
882 if( pModule && pTokenizer ){ | 906 if( pModule && pTokenizer ){ |
883 rc = pModule->xDestroy(pTokenizer); | 907 rc = pModule->xDestroy(pTokenizer); |
884 } | 908 } |
885 sqlite3_free(azCol); | 909 sqlite3_free(azCol); |
886 } | 910 } |
887 | 911 |
888 /* | 912 /* |
889 ** Register the query expression parser test function fts3_exprtest() | 913 ** Register the query expression parser test function fts3_exprtest() |
890 ** with database connection db. | 914 ** with database connection db. |
891 */ | 915 */ |
892 void sqlite3Fts3ExprInitTestInterface(sqlite3* db){ | 916 int sqlite3Fts3ExprInitTestInterface(sqlite3* db){ |
893 sqlite3_create_function( | 917 return sqlite3_create_function( |
894 db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0 | 918 db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0 |
895 ); | 919 ); |
896 } | 920 } |
897 | 921 |
898 #endif | 922 #endif |
899 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ | 923 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ |
OLD | NEW |