OLD | NEW |
1 /* | 1 /* |
2 ** 2014 Jun 09 | 2 ** 2014 Jun 09 |
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 is an SQLite module implementing full-text search. | 13 ** This is an SQLite module implementing full-text search. |
14 */ | 14 */ |
15 | 15 |
16 | 16 |
17 | |
18 #include "fts5Int.h" | 17 #include "fts5Int.h" |
19 | 18 |
20 #define FTS5_DEFAULT_PAGE_SIZE 4050 | 19 #define FTS5_DEFAULT_PAGE_SIZE 4050 |
21 #define FTS5_DEFAULT_AUTOMERGE 4 | 20 #define FTS5_DEFAULT_AUTOMERGE 4 |
| 21 #define FTS5_DEFAULT_USERMERGE 4 |
22 #define FTS5_DEFAULT_CRISISMERGE 16 | 22 #define FTS5_DEFAULT_CRISISMERGE 16 |
23 #define FTS5_DEFAULT_HASHSIZE (1024*1024) | 23 #define FTS5_DEFAULT_HASHSIZE (1024*1024) |
24 | 24 |
25 /* Maximum allowed page size */ | 25 /* Maximum allowed page size */ |
26 #define FTS5_MAX_PAGE_SIZE (128*1024) | 26 #define FTS5_MAX_PAGE_SIZE (128*1024) |
27 | 27 |
28 static int fts5_iswhitespace(char x){ | 28 static int fts5_iswhitespace(char x){ |
29 return (x==' '); | 29 return (x==' '); |
30 } | 30 } |
31 | 31 |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 void sqlite3Fts5Dequote(char *z){ | 188 void sqlite3Fts5Dequote(char *z){ |
189 char quote; /* Quote character (if any ) */ | 189 char quote; /* Quote character (if any ) */ |
190 | 190 |
191 assert( 0==fts5_iswhitespace(z[0]) ); | 191 assert( 0==fts5_iswhitespace(z[0]) ); |
192 quote = z[0]; | 192 quote = z[0]; |
193 if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ | 193 if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ |
194 fts5Dequote(z); | 194 fts5Dequote(z); |
195 } | 195 } |
196 } | 196 } |
197 | 197 |
| 198 |
| 199 struct Fts5Enum { |
| 200 const char *zName; |
| 201 int eVal; |
| 202 }; |
| 203 typedef struct Fts5Enum Fts5Enum; |
| 204 |
| 205 static int fts5ConfigSetEnum( |
| 206 const Fts5Enum *aEnum, |
| 207 const char *zEnum, |
| 208 int *peVal |
| 209 ){ |
| 210 int nEnum = (int)strlen(zEnum); |
| 211 int i; |
| 212 int iVal = -1; |
| 213 |
| 214 for(i=0; aEnum[i].zName; i++){ |
| 215 if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){ |
| 216 if( iVal>=0 ) return SQLITE_ERROR; |
| 217 iVal = aEnum[i].eVal; |
| 218 } |
| 219 } |
| 220 |
| 221 *peVal = iVal; |
| 222 return iVal<0 ? SQLITE_ERROR : SQLITE_OK; |
| 223 } |
| 224 |
198 /* | 225 /* |
199 ** Parse a "special" CREATE VIRTUAL TABLE directive and update | 226 ** Parse a "special" CREATE VIRTUAL TABLE directive and update |
200 ** configuration object pConfig as appropriate. | 227 ** configuration object pConfig as appropriate. |
201 ** | 228 ** |
202 ** If successful, object pConfig is updated and SQLITE_OK returned. If | 229 ** If successful, object pConfig is updated and SQLITE_OK returned. If |
203 ** an error occurs, an SQLite error code is returned and an error message | 230 ** an error occurs, an SQLite error code is returned and an error message |
204 ** may be left in *pzErr. It is the responsibility of the caller to | 231 ** may be left in *pzErr. It is the responsibility of the caller to |
205 ** eventually free any such error message using sqlite3_free(). | 232 ** eventually free any such error message using sqlite3_free(). |
206 */ | 233 */ |
207 static int fts5ConfigParseSpecial( | 234 static int fts5ConfigParseSpecial( |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 ); | 272 ); |
246 rc = SQLITE_ERROR; | 273 rc = SQLITE_ERROR; |
247 break; | 274 break; |
248 } | 275 } |
249 | 276 |
250 while( p[0]>='0' && p[0]<='9' && nPre<1000 ){ | 277 while( p[0]>='0' && p[0]<='9' && nPre<1000 ){ |
251 nPre = nPre*10 + (p[0] - '0'); | 278 nPre = nPre*10 + (p[0] - '0'); |
252 p++; | 279 p++; |
253 } | 280 } |
254 | 281 |
255 if( rc==SQLITE_OK && (nPre<=0 || nPre>=1000) ){ | 282 if( nPre<=0 || nPre>=1000 ){ |
256 *pzErr = sqlite3_mprintf("prefix length out of range (max 999)"); | 283 *pzErr = sqlite3_mprintf("prefix length out of range (max 999)"); |
257 rc = SQLITE_ERROR; | 284 rc = SQLITE_ERROR; |
258 break; | 285 break; |
259 } | 286 } |
260 | 287 |
261 pConfig->aPrefix[pConfig->nPrefix] = nPre; | 288 pConfig->aPrefix[pConfig->nPrefix] = nPre; |
262 pConfig->nPrefix++; | 289 pConfig->nPrefix++; |
263 bFirst = 0; | 290 bFirst = 0; |
264 } | 291 } |
265 assert( pConfig->nPrefix<=FTS5_MAX_PREFIX_INDEXES ); | 292 assert( pConfig->nPrefix<=FTS5_MAX_PREFIX_INDEXES ); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 if( sqlite3_strnicmp("columnsize", zCmd, nCmd)==0 ){ | 365 if( sqlite3_strnicmp("columnsize", zCmd, nCmd)==0 ){ |
339 if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ | 366 if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ |
340 *pzErr = sqlite3_mprintf("malformed columnsize=... directive"); | 367 *pzErr = sqlite3_mprintf("malformed columnsize=... directive"); |
341 rc = SQLITE_ERROR; | 368 rc = SQLITE_ERROR; |
342 }else{ | 369 }else{ |
343 pConfig->bColumnsize = (zArg[0]=='1'); | 370 pConfig->bColumnsize = (zArg[0]=='1'); |
344 } | 371 } |
345 return rc; | 372 return rc; |
346 } | 373 } |
347 | 374 |
| 375 if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){ |
| 376 const Fts5Enum aDetail[] = { |
| 377 { "none", FTS5_DETAIL_NONE }, |
| 378 { "full", FTS5_DETAIL_FULL }, |
| 379 { "columns", FTS5_DETAIL_COLUMNS }, |
| 380 { 0, 0 } |
| 381 }; |
| 382 |
| 383 if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){ |
| 384 *pzErr = sqlite3_mprintf("malformed detail=... directive"); |
| 385 } |
| 386 return rc; |
| 387 } |
| 388 |
348 *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd); | 389 *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd); |
349 return SQLITE_ERROR; | 390 return SQLITE_ERROR; |
350 } | 391 } |
351 | 392 |
352 /* | 393 /* |
353 ** Allocate an instance of the default tokenizer ("simple") at | 394 ** Allocate an instance of the default tokenizer ("simple") at |
354 ** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error | 395 ** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error |
355 ** code if an error occurs. | 396 ** code if an error occurs. |
356 */ | 397 */ |
357 static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){ | 398 static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){ |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 if( zOut==0 ){ | 435 if( zOut==0 ){ |
395 *pRc = SQLITE_NOMEM; | 436 *pRc = SQLITE_NOMEM; |
396 }else{ | 437 }else{ |
397 memcpy(zOut, zIn, nIn+1); | 438 memcpy(zOut, zIn, nIn+1); |
398 if( fts5_isopenquote(zOut[0]) ){ | 439 if( fts5_isopenquote(zOut[0]) ){ |
399 int ii = fts5Dequote(zOut); | 440 int ii = fts5Dequote(zOut); |
400 zRet = &zIn[ii]; | 441 zRet = &zIn[ii]; |
401 *pbQuoted = 1; | 442 *pbQuoted = 1; |
402 }else{ | 443 }else{ |
403 zRet = fts5ConfigSkipBareword(zIn); | 444 zRet = fts5ConfigSkipBareword(zIn); |
404 zOut[zRet-zIn] = '\0'; | 445 if( zRet ){ |
| 446 zOut[zRet-zIn] = '\0'; |
| 447 } |
405 } | 448 } |
406 } | 449 } |
407 | 450 |
408 if( zRet==0 ){ | 451 if( zRet==0 ){ |
409 sqlite3_free(zOut); | 452 sqlite3_free(zOut); |
410 }else{ | 453 }else{ |
411 *pzOut = zOut; | 454 *pzOut = zOut; |
412 } | 455 } |
413 | 456 |
414 return zRet; | 457 return zRet; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 memset(pRet, 0, sizeof(Fts5Config)); | 536 memset(pRet, 0, sizeof(Fts5Config)); |
494 pRet->db = db; | 537 pRet->db = db; |
495 pRet->iCookie = -1; | 538 pRet->iCookie = -1; |
496 | 539 |
497 nByte = nArg * (sizeof(char*) + sizeof(u8)); | 540 nByte = nArg * (sizeof(char*) + sizeof(u8)); |
498 pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte); | 541 pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte); |
499 pRet->abUnindexed = (u8*)&pRet->azCol[nArg]; | 542 pRet->abUnindexed = (u8*)&pRet->azCol[nArg]; |
500 pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1); | 543 pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1); |
501 pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1); | 544 pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1); |
502 pRet->bColumnsize = 1; | 545 pRet->bColumnsize = 1; |
| 546 pRet->eDetail = FTS5_DETAIL_FULL; |
503 #ifdef SQLITE_DEBUG | 547 #ifdef SQLITE_DEBUG |
504 pRet->bPrefixIndex = 1; | 548 pRet->bPrefixIndex = 1; |
505 #endif | 549 #endif |
506 if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){ | 550 if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){ |
507 *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName); | 551 *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName); |
508 rc = SQLITE_ERROR; | 552 rc = SQLITE_ERROR; |
509 } | 553 } |
510 | 554 |
511 for(i=3; rc==SQLITE_OK && i<nArg; i++){ | 555 for(i=3; rc==SQLITE_OK && i<nArg; i++){ |
512 const char *zOrig = azArg[i]; | 556 const char *zOrig = azArg[i]; |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
809 nAutomerge = sqlite3_value_int(pVal); | 853 nAutomerge = sqlite3_value_int(pVal); |
810 } | 854 } |
811 if( nAutomerge<0 || nAutomerge>64 ){ | 855 if( nAutomerge<0 || nAutomerge>64 ){ |
812 *pbBadkey = 1; | 856 *pbBadkey = 1; |
813 }else{ | 857 }else{ |
814 if( nAutomerge==1 ) nAutomerge = FTS5_DEFAULT_AUTOMERGE; | 858 if( nAutomerge==1 ) nAutomerge = FTS5_DEFAULT_AUTOMERGE; |
815 pConfig->nAutomerge = nAutomerge; | 859 pConfig->nAutomerge = nAutomerge; |
816 } | 860 } |
817 } | 861 } |
818 | 862 |
| 863 else if( 0==sqlite3_stricmp(zKey, "usermerge") ){ |
| 864 int nUsermerge = -1; |
| 865 if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ |
| 866 nUsermerge = sqlite3_value_int(pVal); |
| 867 } |
| 868 if( nUsermerge<2 || nUsermerge>16 ){ |
| 869 *pbBadkey = 1; |
| 870 }else{ |
| 871 pConfig->nUsermerge = nUsermerge; |
| 872 } |
| 873 } |
| 874 |
819 else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){ | 875 else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){ |
820 int nCrisisMerge = -1; | 876 int nCrisisMerge = -1; |
821 if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ | 877 if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ |
822 nCrisisMerge = sqlite3_value_int(pVal); | 878 nCrisisMerge = sqlite3_value_int(pVal); |
823 } | 879 } |
824 if( nCrisisMerge<0 ){ | 880 if( nCrisisMerge<0 ){ |
825 *pbBadkey = 1; | 881 *pbBadkey = 1; |
826 }else{ | 882 }else{ |
827 if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; | 883 if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; |
828 pConfig->nCrisisMerge = nCrisisMerge; | 884 pConfig->nCrisisMerge = nCrisisMerge; |
(...skipping 26 matching lines...) Expand all Loading... |
855 int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ | 911 int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ |
856 const char *zSelect = "SELECT k, v FROM %Q.'%q_config'"; | 912 const char *zSelect = "SELECT k, v FROM %Q.'%q_config'"; |
857 char *zSql; | 913 char *zSql; |
858 sqlite3_stmt *p = 0; | 914 sqlite3_stmt *p = 0; |
859 int rc = SQLITE_OK; | 915 int rc = SQLITE_OK; |
860 int iVersion = 0; | 916 int iVersion = 0; |
861 | 917 |
862 /* Set default values */ | 918 /* Set default values */ |
863 pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE; | 919 pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE; |
864 pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE; | 920 pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE; |
| 921 pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE; |
865 pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; | 922 pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; |
866 pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE; | 923 pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE; |
867 | 924 |
868 zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName); | 925 zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName); |
869 if( zSql ){ | 926 if( zSql ){ |
870 rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p, 0); | 927 rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p, 0); |
871 sqlite3_free(zSql); | 928 sqlite3_free(zSql); |
872 } | 929 } |
873 | 930 |
874 assert( rc==SQLITE_OK || p==0 ); | 931 assert( rc==SQLITE_OK || p==0 ); |
(...skipping 20 matching lines...) Expand all Loading... |
895 iVersion, FTS5_CURRENT_VERSION | 952 iVersion, FTS5_CURRENT_VERSION |
896 ); | 953 ); |
897 } | 954 } |
898 } | 955 } |
899 | 956 |
900 if( rc==SQLITE_OK ){ | 957 if( rc==SQLITE_OK ){ |
901 pConfig->iCookie = iCookie; | 958 pConfig->iCookie = iCookie; |
902 } | 959 } |
903 return rc; | 960 return rc; |
904 } | 961 } |
905 | |
OLD | NEW |