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