| 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 |