CoolFace
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
fts5.c27998 linesDownload Raw Back to root
1 2/*3** This, the "fts5.c" source file, is a composite file that is itself4** assembled from the following files:5**6**    fts5.h7**    fts5Int.h8**    fts5parse.h          <--- Generated from fts5parse.y by Lemon9**    fts5parse.c          <--- Generated from fts5parse.y by Lemon10**    fts5_aux.c11**    fts5_buffer.c12**    fts5_config.c13**    fts5_expr.c14**    fts5_hash.c15**    fts5_index.c16**    fts5_main.c17**    fts5_storage.c18**    fts5_tokenize.c19**    fts5_unicode2.c20**    fts5_varint.c21**    fts5_vocab.c22*/23#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) 24 25#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 26# define NDEBUG 127#endif28#if defined(NDEBUG) && defined(SQLITE_DEBUG)29# undef NDEBUG30#endif31 32#ifdef HAVE_STDINT_H33#include <stdint.h>34#endif35#ifdef HAVE_INTTYPES_H36#include <inttypes.h>37#endif38#line 1 "fts5.h"39/*40** 2014 May 3141**42** The author disclaims copyright to this source code.  In place of43** a legal notice, here is a blessing:44**45**    May you do good and not evil.46**    May you find forgiveness for yourself and forgive others.47**    May you share freely, never taking more than you give.48**49******************************************************************************50**51** Interfaces to extend FTS5. Using the interfaces defined in this file, 52** FTS5 may be extended with:53**54**     * custom tokenizers, and55**     * custom auxiliary functions.56*/57 58 59#ifndef _FTS5_H60#define _FTS5_H61 62#include "sqlite3.h"63 64#ifdef __cplusplus65extern "C" {66#endif67 68/*************************************************************************69** CUSTOM AUXILIARY FUNCTIONS70**71** Virtual table implementations may overload SQL functions by implementing72** the sqlite3_module.xFindFunction() method.73*/74 75typedef struct Fts5ExtensionApi Fts5ExtensionApi;76typedef struct Fts5Context Fts5Context;77typedef struct Fts5PhraseIter Fts5PhraseIter;78 79typedef void (*fts5_extension_function)(80  const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */81  Fts5Context *pFts,              /* First arg to pass to pApi functions */82  sqlite3_context *pCtx,          /* Context for returning result/error */83  int nVal,                       /* Number of values in apVal[] array */84  sqlite3_value **apVal           /* Array of trailing arguments */85);86 87struct Fts5PhraseIter {88  const unsigned char *a;89  const unsigned char *b;90};91 92/*93** EXTENSION API FUNCTIONS94**95** xUserData(pFts):96**   Return a copy of the pUserData pointer passed to the xCreateFunction()97**   API when the extension function was registered.98**99** xColumnTotalSize(pFts, iCol, pnToken):100**   If parameter iCol is less than zero, set output variable *pnToken101**   to the total number of tokens in the FTS5 table. Or, if iCol is102**   non-negative but less than the number of columns in the table, return103**   the total number of tokens in column iCol, considering all rows in 104**   the FTS5 table.105**106**   If parameter iCol is greater than or equal to the number of columns107**   in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.108**   an OOM condition or IO error), an appropriate SQLite error code is 109**   returned.110**111** xColumnCount(pFts):112**   Return the number of columns in the table.113**114** xColumnSize(pFts, iCol, pnToken):115**   If parameter iCol is less than zero, set output variable *pnToken116**   to the total number of tokens in the current row. Or, if iCol is117**   non-negative but less than the number of columns in the table, set118**   *pnToken to the number of tokens in column iCol of the current row.119**120**   If parameter iCol is greater than or equal to the number of columns121**   in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.122**   an OOM condition or IO error), an appropriate SQLite error code is 123**   returned.124**125**   This function may be quite inefficient if used with an FTS5 table126**   created with the "columnsize=0" option.127**128** xColumnText:129**   If parameter iCol is less than zero, or greater than or equal to the130**   number of columns in the table, SQLITE_RANGE is returned. 131**132**   Otherwise, this function attempts to retrieve the text of column iCol of133**   the current document. If successful, (*pz) is set to point to a buffer134**   containing the text in utf-8 encoding, (*pn) is set to the size in bytes135**   (not characters) of the buffer and SQLITE_OK is returned. Otherwise,136**   if an error occurs, an SQLite error code is returned and the final values137**   of (*pz) and (*pn) are undefined.138**139** xPhraseCount:140**   Returns the number of phrases in the current query expression.141**142** xPhraseSize:143**   If parameter iCol is less than zero, or greater than or equal to the144**   number of phrases in the current query, as returned by xPhraseCount, 145**   0 is returned. Otherwise, this function returns the number of tokens in146**   phrase iPhrase of the query. Phrases are numbered starting from zero.147**148** xInstCount:149**   Set *pnInst to the total number of occurrences of all phrases within150**   the query within the current row. Return SQLITE_OK if successful, or151**   an error code (i.e. SQLITE_NOMEM) if an error occurs.152**153**   This API can be quite slow if used with an FTS5 table created with the154**   "detail=none" or "detail=column" option. If the FTS5 table is created 155**   with either "detail=none" or "detail=column" and "content=" option 156**   (i.e. if it is a contentless table), then this API always returns 0.157**158** xInst:159**   Query for the details of phrase match iIdx within the current row.160**   Phrase matches are numbered starting from zero, so the iIdx argument161**   should be greater than or equal to zero and smaller than the value162**   output by xInstCount(). If iIdx is less than zero or greater than163**   or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.164**165**   Otherwise, output parameter *piPhrase is set to the phrase number, *piCol166**   to the column in which it occurs and *piOff the token offset of the167**   first token of the phrase. SQLITE_OK is returned if successful, or an168**   error code (i.e. SQLITE_NOMEM) if an error occurs.169**170**   This API can be quite slow if used with an FTS5 table created with the171**   "detail=none" or "detail=column" option. 172**173** xRowid:174**   Returns the rowid of the current row.175**176** xTokenize:177**   Tokenize text using the tokenizer belonging to the FTS5 table.178**179** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback):180**   This API function is used to query the FTS table for phrase iPhrase181**   of the current query. Specifically, a query equivalent to:182**183**       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid184**185**   with $p set to a phrase equivalent to the phrase iPhrase of the186**   current query is executed. Any column filter that applies to187**   phrase iPhrase of the current query is included in $p. For each 188**   row visited, the callback function passed as the fourth argument 189**   is invoked. The context and API objects passed to the callback 190**   function may be used to access the properties of each matched row.191**   Invoking Api.xUserData() returns a copy of the pointer passed as 192**   the third argument to pUserData.193**194**   If parameter iPhrase is less than zero, or greater than or equal to195**   the number of phrases in the query, as returned by xPhraseCount(),196**   this function returns SQLITE_RANGE.197**198**   If the callback function returns any value other than SQLITE_OK, the199**   query is abandoned and the xQueryPhrase function returns immediately.200**   If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.201**   Otherwise, the error code is propagated upwards.202**203**   If the query runs to completion without incident, SQLITE_OK is returned.204**   Or, if some error occurs before the query completes or is aborted by205**   the callback, an SQLite error code is returned.206**207**208** xSetAuxdata(pFts5, pAux, xDelete)209**210**   Save the pointer passed as the second argument as the extension function's 211**   "auxiliary data". The pointer may then be retrieved by the current or any212**   future invocation of the same fts5 extension function made as part of213**   the same MATCH query using the xGetAuxdata() API.214**215**   Each extension function is allocated a single auxiliary data slot for216**   each FTS query (MATCH expression). If the extension function is invoked 217**   more than once for a single FTS query, then all invocations share a 218**   single auxiliary data context.219**220**   If there is already an auxiliary data pointer when this function is221**   invoked, then it is replaced by the new pointer. If an xDelete callback222**   was specified along with the original pointer, it is invoked at this223**   point.224**225**   The xDelete callback, if one is specified, is also invoked on the226**   auxiliary data pointer after the FTS5 query has finished.227**228**   If an error (e.g. an OOM condition) occurs within this function,229**   the auxiliary data is set to NULL and an error code returned. If the230**   xDelete parameter was not NULL, it is invoked on the auxiliary data231**   pointer before returning.232**233**234** xGetAuxdata(pFts5, bClear)235**236**   Returns the current auxiliary data pointer for the fts5 extension 237**   function. See the xSetAuxdata() method for details.238**239**   If the bClear argument is non-zero, then the auxiliary data is cleared240**   (set to NULL) before this function returns. In this case the xDelete,241**   if any, is not invoked.242**243**244** xRowCount(pFts5, pnRow)245**246**   This function is used to retrieve the total number of rows in the table.247**   In other words, the same value that would be returned by:248**249**        SELECT count(*) FROM ftstable;250**251** xPhraseFirst()252**   This function is used, along with type Fts5PhraseIter and the xPhraseNext253**   method, to iterate through all instances of a single query phrase within254**   the current row. This is the same information as is accessible via the255**   xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient256**   to use, this API may be faster under some circumstances. To iterate 257**   through instances of phrase iPhrase, use the following code:258**259**       Fts5PhraseIter iter;260**       int iCol, iOff;261**       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);262**           iCol>=0;263**           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)264**       ){265**         // An instance of phrase iPhrase at offset iOff of column iCol266**       }267**268**   The Fts5PhraseIter structure is defined above. Applications should not269**   modify this structure directly - it should only be used as shown above270**   with the xPhraseFirst() and xPhraseNext() API methods (and by271**   xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).272**273**   This API can be quite slow if used with an FTS5 table created with the274**   "detail=none" or "detail=column" option. If the FTS5 table is created 275**   with either "detail=none" or "detail=column" and "content=" option 276**   (i.e. if it is a contentless table), then this API always iterates277**   through an empty set (all calls to xPhraseFirst() set iCol to -1).278**279**   In all cases, matches are visited in (column ASC, offset ASC) order.280**   i.e. all those in column 0, sorted by offset, followed by those in 281**   column 1, etc.282**283** xPhraseNext()284**   See xPhraseFirst above.285**286** xPhraseFirstColumn()287**   This function and xPhraseNextColumn() are similar to the xPhraseFirst()288**   and xPhraseNext() APIs described above. The difference is that instead289**   of iterating through all instances of a phrase in the current row, these290**   APIs are used to iterate through the set of columns in the current row291**   that contain one or more instances of a specified phrase. For example:292**293**       Fts5PhraseIter iter;294**       int iCol;295**       for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);296**           iCol>=0;297**           pApi->xPhraseNextColumn(pFts, &iter, &iCol)298**       ){299**         // Column iCol contains at least one instance of phrase iPhrase300**       }301**302**   This API can be quite slow if used with an FTS5 table created with the303**   "detail=none" option. If the FTS5 table is created with either 304**   "detail=none" "content=" option (i.e. if it is a contentless table), 305**   then this API always iterates through an empty set (all calls to 306**   xPhraseFirstColumn() set iCol to -1).307**308**   The information accessed using this API and its companion309**   xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext310**   (or xInst/xInstCount). The chief advantage of this API is that it is311**   significantly more efficient than those alternatives when used with312**   "detail=column" tables.  313**314** xPhraseNextColumn()315**   See xPhraseFirstColumn above.316**317** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)318**   This is used to access token iToken of phrase iPhrase of the current319**   query. Before returning, output parameter *ppToken is set to point320**   to a buffer containing the requested token, and *pnToken to the321**   size of this buffer in bytes.322**323**   If iPhrase or iToken are less than zero, or if iPhrase is greater than324**   or equal to the number of phrases in the query as reported by 325**   xPhraseCount(), or if iToken is equal to or greater than the number of326**   tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken327     are both zeroed.328**329**   The output text is not a copy of the query text that specified the330**   token. It is the output of the tokenizer module. For tokendata=1331**   tables, this includes any embedded 0x00 and trailing data.332**333** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)334**   This is used to access token iToken of phrase hit iIdx within the335**   current row. If iIdx is less than zero or greater than or equal to the336**   value returned by xInstCount(), SQLITE_RANGE is returned.  Otherwise,337**   output variable (*ppToken) is set to point to a buffer containing the338**   matching document token, and (*pnToken) to the size of that buffer in 339**   bytes. 340**341**   The output text is not a copy of the document text that was tokenized.342**   It is the output of the tokenizer module. For tokendata=1 tables, this 343**   includes any embedded 0x00 and trailing data.344**345**   This API may be slow in some cases if the token identified by parameters 346**   iIdx and iToken matched a prefix token in the query. In most cases, the347**   first call to this API for each prefix token in the query is forced348**   to scan the portion of the full-text index that matches the prefix349**   token to collect the extra data required by this API. If the prefix350**   token matches a large number of token instances in the document set,351**   this may be a performance problem. 352**353**   If the user knows in advance that a query may use this API for a354**   prefix token, FTS5 may be configured to collect all required data as part355**   of the initial querying of the full-text index, avoiding the second scan356**   entirely. This also causes prefix queries that do not use this API to 357**   run more slowly and use more memory. FTS5 may be configured in this way358**   either on a per-table basis using the [FTS5 insttoken | 'insttoken'] 359**   option, or on a per-query basis using the 360**   [fts5_insttoken | fts5_insttoken()] user function.361**362**   This API can be quite slow if used with an FTS5 table created with the363**   "detail=none" or "detail=column" option. 364**365** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)366**   If parameter iCol is less than zero, or greater than or equal to the367**   number of columns in the table, SQLITE_RANGE is returned.368**369**   Otherwise, this function attempts to retrieve the locale associated370**   with column iCol of the current row. Usually, there is no associated371**   locale, and output parameters (*pzLocale) and (*pnLocale) are set372**   to NULL and 0, respectively. However, if the fts5_locale() function373**   was used to associate a locale with the value when it was inserted374**   into the fts5 table, then (*pzLocale) is set to point to a nul-terminated375**   buffer containing the name of the locale in utf-8 encoding. (*pnLocale) 376**   is set to the size in bytes of the buffer, not including the 377**   nul-terminator.378**379**   If successful, SQLITE_OK is returned. Or, if an error occurs, an380**   SQLite error code is returned. The final value of the output parameters381**   is undefined in this case.382**383** xTokenize_v2:384**   Tokenize text using the tokenizer belonging to the FTS5 table. This385**   API is the same as the xTokenize() API, except that it allows a tokenizer386**   locale to be specified.387*/388struct Fts5ExtensionApi {389  int iVersion;                   /* Currently always set to 4 */390 391  void *(*xUserData)(Fts5Context*);392 393  int (*xColumnCount)(Fts5Context*);394  int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);395  int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);396 397  int (*xTokenize)(Fts5Context*, 398    const char *pText, int nText, /* Text to tokenize */399    void *pCtx,                   /* Context passed to xToken() */400    int (*xToken)(void*, int, const char*, int, int, int)       /* Callback */401  );402 403  int (*xPhraseCount)(Fts5Context*);404  int (*xPhraseSize)(Fts5Context*, int iPhrase);405 406  int (*xInstCount)(Fts5Context*, int *pnInst);407  int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);408 409  sqlite3_int64 (*xRowid)(Fts5Context*);410  int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);411  int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);412 413  int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,414    int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)415  );416  int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));417  void *(*xGetAuxdata)(Fts5Context*, int bClear);418 419  int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);420  void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);421 422  int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);423  void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);424 425  /* Below this point are iVersion>=3 only */426  int (*xQueryToken)(Fts5Context*, 427      int iPhrase, int iToken, 428      const char **ppToken, int *pnToken429  );430  int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);431 432  /* Below this point are iVersion>=4 only */433  int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);434  int (*xTokenize_v2)(Fts5Context*,435    const char *pText, int nText,      /* Text to tokenize */436    const char *pLocale, int nLocale,  /* Locale to pass to tokenizer */437    void *pCtx,                        /* Context passed to xToken() */438    int (*xToken)(void*, int, const char*, int, int, int)       /* Callback */439  );440};441 442/* 443** CUSTOM AUXILIARY FUNCTIONS444*************************************************************************/445 446/*************************************************************************447** CUSTOM TOKENIZERS448**449** Applications may also register custom tokenizer types. A tokenizer 450** is registered by providing fts5 with a populated instance of the 451** following structure. All structure methods must be defined, setting452** any member of the fts5_tokenizer struct to NULL leads to undefined453** behaviour. The structure methods are expected to function as follows:454**455** xCreate:456**   This function is used to allocate and initialize a tokenizer instance.457**   A tokenizer instance is required to actually tokenize text.458**459**   The first argument passed to this function is a copy of the (void*)460**   pointer provided by the application when the fts5_tokenizer_v2 object461**   was registered with FTS5 (the third argument to xCreateTokenizer()). 462**   The second and third arguments are an array of nul-terminated strings463**   containing the tokenizer arguments, if any, specified following the464**   tokenizer name as part of the CREATE VIRTUAL TABLE statement used465**   to create the FTS5 table.466**467**   The final argument is an output variable. If successful, (*ppOut) 468**   should be set to point to the new tokenizer handle and SQLITE_OK469**   returned. If an error occurs, some value other than SQLITE_OK should470**   be returned. In this case, fts5 assumes that the final value of *ppOut 471**   is undefined.472**473** xDelete:474**   This function is invoked to delete a tokenizer handle previously475**   allocated using xCreate(). Fts5 guarantees that this function will476**   be invoked exactly once for each successful call to xCreate().477**478** xTokenize:479**   This function is expected to tokenize the nText byte string indicated 480**   by argument pText. pText may or may not be nul-terminated. The first481**   argument passed to this function is a pointer to an Fts5Tokenizer object482**   returned by an earlier call to xCreate().483**484**   The third argument indicates the reason that FTS5 is requesting485**   tokenization of the supplied text. This is always one of the following486**   four values:487**488**   <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into489**            or removed from the FTS table. The tokenizer is being invoked to490**            determine the set of tokens to add to (or delete from) the491**            FTS index.492**493**       <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed 494**            against the FTS index. The tokenizer is being called to tokenize 495**            a bareword or quoted string specified as part of the query.496**497**       <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as498**            FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is499**            followed by a "*" character, indicating that the last token500**            returned by the tokenizer will be treated as a token prefix.501**502**       <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to 503**            satisfy an fts5_api.xTokenize() request made by an auxiliary504**            function. Or an fts5_api.xColumnSize() request made by the same505**            on a columnsize=0 database.  506**   </ul>507**508**   The sixth and seventh arguments passed to xTokenize() - pLocale and509**   nLocale - are a pointer to a buffer containing the locale to use for510**   tokenization (e.g. "en_US") and its size in bytes, respectively. The511**   pLocale buffer is not nul-terminated. pLocale may be passed NULL (in512**   which case nLocale is always 0) to indicate that the tokenizer should513**   use its default locale.514**515**   For each token in the input string, the supplied callback xToken() must516**   be invoked. The first argument to it should be a copy of the pointer517**   passed as the second argument to xTokenize(). The third and fourth518**   arguments are a pointer to a buffer containing the token text, and the519**   size of the token in bytes. The 4th and 5th arguments are the byte offsets520**   of the first byte of and first byte immediately following the text from521**   which the token is derived within the input.522**523**   The second argument passed to the xToken() callback ("tflags") should524**   normally be set to 0. The exception is if the tokenizer supports 525**   synonyms. In this case see the discussion below for details.526**527**   FTS5 assumes the xToken() callback is invoked for each token in the 528**   order that they occur within the input text.529**530**   If an xToken() callback returns any value other than SQLITE_OK, then531**   the tokenization should be abandoned and the xTokenize() method should532**   immediately return a copy of the xToken() return value. Or, if the533**   input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,534**   if an error occurs with the xTokenize() implementation itself, it535**   may abandon the tokenization and return any error code other than536**   SQLITE_OK or SQLITE_DONE.537**538**   If the tokenizer is registered using an fts5_tokenizer_v2 object,539**   then the xTokenize() method has two additional arguments - pLocale540**   and nLocale. These specify the locale that the tokenizer should use541**   for the current request. If pLocale and nLocale are both 0, then the542**   tokenizer should use its default locale. Otherwise, pLocale points to543**   an nLocale byte buffer containing the name of the locale to use as utf-8 544**   text. pLocale is not nul-terminated.545**546** FTS5_TOKENIZER547**548** There is also an fts5_tokenizer object. This is an older, deprecated,549** version of fts5_tokenizer_v2. It is similar except that:550**551**  <ul>552**    <li> There is no "iVersion" field, and553**    <li> The xTokenize() method does not take a locale argument.554**  </ul>555**556** Legacy fts5_tokenizer tokenizers must be registered using the557** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().558**559** Tokenizer implementations registered using either API may be retrieved560** using both xFindTokenizer() and xFindTokenizer_v2().561**562** SYNONYM SUPPORT563**564**   Custom tokenizers may also support synonyms. Consider a case in which a565**   user wishes to query for a phrase such as "first place". Using the 566**   built-in tokenizers, the FTS5 query 'first + place' will match instances567**   of "first place" within the document set, but not alternative forms568**   such as "1st place". In some applications, it would be better to match569**   all instances of "first place" or "1st place" regardless of which form570**   the user specified in the MATCH query text.571**572**   There are several ways to approach this in FTS5:573**574**   <ol><li> By mapping all synonyms to a single token. In this case, using575**            the above example, this means that the tokenizer returns the576**            same token for inputs "first" and "1st". Say that token is in577**            fact "first", so that when the user inserts the document "I won578**            1st place" entries are added to the index for tokens "i", "won",579**            "first" and "place". If the user then queries for '1st + place',580**            the tokenizer substitutes "first" for "1st" and the query works581**            as expected.582**583**       <li> By querying the index for all synonyms of each query term584**            separately. In this case, when tokenizing query text, the585**            tokenizer may provide multiple synonyms for a single term 586**            within the document. FTS5 then queries the index for each 587**            synonym individually. For example, faced with the query:588**589**   <codeblock>590**     ... MATCH 'first place'</codeblock>591**592**            the tokenizer offers both "1st" and "first" as synonyms for the593**            first token in the MATCH query and FTS5 effectively runs a query 594**            similar to:595**596**   <codeblock>597**     ... MATCH '(first OR 1st) place'</codeblock>598**599**            except that, for the purposes of auxiliary functions, the query600**            still appears to contain just two phrases - "(first OR 1st)" 601**            being treated as a single phrase.602**603**       <li> By adding multiple synonyms for a single term to the FTS index.604**            Using this method, when tokenizing document text, the tokenizer605**            provides multiple synonyms for each token. So that when a 606**            document such as "I won first place" is tokenized, entries are607**            added to the FTS index for "i", "won", "first", "1st" and608**            "place".609**610**            This way, even if the tokenizer does not provide synonyms611**            when tokenizing query text (it should not - to do so would be612**            inefficient), it doesn't matter if the user queries for 613**            'first + place' or '1st + place', as there are entries in the614**            FTS index corresponding to both forms of the first token.615**   </ol>616**617**   Whether it is parsing document or query text, any call to xToken that618**   specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit619**   is considered to supply a synonym for the previous token. For example,620**   when parsing the document "I won first place", a tokenizer that supports621**   synonyms would call xToken() 5 times, as follows:622**623**   <codeblock>624**       xToken(pCtx, 0, "i",                      1,  0,  1);625**       xToken(pCtx, 0, "won",                    3,  2,  5);626**       xToken(pCtx, 0, "first",                  5,  6, 11);627**       xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3,  6, 11);628**       xToken(pCtx, 0, "place",                  5, 12, 17);629**</codeblock>630**631**   It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time632**   xToken() is called. Multiple synonyms may be specified for a single token633**   by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. 634**   There is no limit to the number of synonyms that may be provided for a635**   single token.636**637**   In many cases, method (1) above is the best approach. It does not add 638**   extra data to the FTS index or require FTS5 to query for multiple terms,639**   so it is efficient in terms of disk space and query speed. However, it640**   does not support prefix queries very well. If, as suggested above, the641**   token "first" is substituted for "1st" by the tokenizer, then the query:642**643**   <codeblock>644**     ... MATCH '1s*'</codeblock>645**646**   will not match documents that contain the token "1st" (as the tokenizer647**   will probably not map "1s" to any prefix of "first").648**649**   For full prefix support, method (3) may be preferred. In this case, 650**   because the index contains entries for both "first" and "1st", prefix651**   queries such as 'fi*' or '1s*' will match correctly. However, because652**   extra entries are added to the FTS index, this method uses more space653**   within the database.654**655**   Method (2) offers a midpoint between (1) and (3). Using this method,656**   a query such as '1s*' will match documents that contain the literal 657**   token "1st", but not "first" (assuming the tokenizer is not able to658**   provide synonyms for prefixes). However, a non-prefix query like '1st'659**   will match against "1st" and "first". This method does not require660**   extra disk space, as no extra entries are added to the FTS index. 661**   On the other hand, it may require more CPU cycles to run MATCH queries,662**   as separate queries of the FTS index are required for each synonym.663**664**   When using methods (2) or (3), it is important that the tokenizer only665**   provide synonyms when tokenizing document text (method (3)) or query666**   text (method (2)), not both. Doing so will not cause any errors, but is667**   inefficient.668*/669typedef struct Fts5Tokenizer Fts5Tokenizer;670typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;671struct fts5_tokenizer_v2 {672  int iVersion;             /* Currently always 2 */673 674  int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);675  void (*xDelete)(Fts5Tokenizer*);676  int (*xTokenize)(Fts5Tokenizer*, 677      void *pCtx,678      int flags,            /* Mask of FTS5_TOKENIZE_* flags */679      const char *pText, int nText, 680      const char *pLocale, int nLocale,681      int (*xToken)(682        void *pCtx,         /* Copy of 2nd argument to xTokenize() */683        int tflags,         /* Mask of FTS5_TOKEN_* flags */684        const char *pToken, /* Pointer to buffer containing token */685        int nToken,         /* Size of token in bytes */686        int iStart,         /* Byte offset of token within input text */687        int iEnd            /* Byte offset of end of token within input text */688      )689  );690};691 692/*693** New code should use the fts5_tokenizer_v2 type to define tokenizer694** implementations. The following type is included for legacy applications695** that still use it.696*/697typedef struct fts5_tokenizer fts5_tokenizer;698struct fts5_tokenizer {699  int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);700  void (*xDelete)(Fts5Tokenizer*);701  int (*xTokenize)(Fts5Tokenizer*, 702      void *pCtx,703      int flags,            /* Mask of FTS5_TOKENIZE_* flags */704      const char *pText, int nText, 705      int (*xToken)(706        void *pCtx,         /* Copy of 2nd argument to xTokenize() */707        int tflags,         /* Mask of FTS5_TOKEN_* flags */708        const char *pToken, /* Pointer to buffer containing token */709        int nToken,         /* Size of token in bytes */710        int iStart,         /* Byte offset of token within input text */711        int iEnd            /* Byte offset of end of token within input text */712      )713  );714};715 716 717/* Flags that may be passed as the third argument to xTokenize() */718#define FTS5_TOKENIZE_QUERY     0x0001719#define FTS5_TOKENIZE_PREFIX    0x0002720#define FTS5_TOKENIZE_DOCUMENT  0x0004721#define FTS5_TOKENIZE_AUX       0x0008722 723/* Flags that may be passed by the tokenizer implementation back to FTS5724** as the third argument to the supplied xToken callback. */725#define FTS5_TOKEN_COLOCATED    0x0001      /* Same position as prev. token */726 727/*728** END OF CUSTOM TOKENIZERS729*************************************************************************/730 731/*************************************************************************732** FTS5 EXTENSION REGISTRATION API733*/734typedef struct fts5_api fts5_api;735struct fts5_api {736  int iVersion;                   /* Currently always set to 3 */737 738  /* Create a new tokenizer */739  int (*xCreateTokenizer)(740    fts5_api *pApi,741    const char *zName,742    void *pUserData,743    fts5_tokenizer *pTokenizer,744    void (*xDestroy)(void*)745  );746 747  /* Find an existing tokenizer */748  int (*xFindTokenizer)(749    fts5_api *pApi,750    const char *zName,751    void **ppUserData,752    fts5_tokenizer *pTokenizer753  );754 755  /* Create a new auxiliary function */756  int (*xCreateFunction)(757    fts5_api *pApi,758    const char *zName,759    void *pUserData,760    fts5_extension_function xFunction,761    void (*xDestroy)(void*)762  );763 764  /* APIs below this point are only available if iVersion>=3 */765 766  /* Create a new tokenizer */767  int (*xCreateTokenizer_v2)(768    fts5_api *pApi,769    const char *zName,770    void *pUserData,771    fts5_tokenizer_v2 *pTokenizer,772    void (*xDestroy)(void*)773  );774 775  /* Find an existing tokenizer */776  int (*xFindTokenizer_v2)(777    fts5_api *pApi,778    const char *zName,779    void **ppUserData,780    fts5_tokenizer_v2 **ppTokenizer781  );782};783 784/*785** END OF REGISTRATION API786*************************************************************************/787 788#ifdef __cplusplus789}  /* end of the 'extern "C"' block */790#endif791 792#endif /* _FTS5_H */793 794#line 1 "fts5Int.h"795/*796** 2014 May 31797**798** The author disclaims copyright to this source code.  In place of799** a legal notice, here is a blessing:800**801**    May you do good and not evil.802**    May you find forgiveness for yourself and forgive others.803**    May you share freely, never taking more than you give.804**805******************************************************************************806**807*/808#ifndef _FTS5INT_H809#define _FTS5INT_H810 811/* #include "fts5.h" */812#include "sqlite3ext.h"813SQLITE_EXTENSION_INIT1814 815#include <string.h>816#include <assert.h>817#include <stddef.h>818 819#ifndef SQLITE_AMALGAMATION820 821typedef unsigned char  u8;822typedef unsigned int   u32;823typedef unsigned short u16;824typedef short i16;825typedef sqlite3_int64 i64;826typedef sqlite3_uint64 u64;827 828#ifndef ArraySize829# define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0])))830#endif831 832#define testcase(x)833 834#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)835# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1836#endif837#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)838# define ALWAYS(X)      (1)839# define NEVER(X)       (0)840#elif !defined(NDEBUG)841# define ALWAYS(X)      ((X)?1:(assert(0),0))842# define NEVER(X)       ((X)?(assert(0),1):0)843#else844# define ALWAYS(X)      (X)845# define NEVER(X)       (X)846#endif847 848#define MIN(x,y) (((x) < (y)) ? (x) : (y))849#define MAX(x,y) (((x) > (y)) ? (x) : (y))850 851/*852** Constants for the largest and smallest possible 64-bit signed integers.853*/854# define LARGEST_INT64  (0xffffffff|(((i64)0x7fffffff)<<32))855# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)856 857/*858** This macro is used in a single assert() within fts5 to check that an859** allocation is aligned to an 8-byte boundary. But it is a complicated860** macro to get right for multiple platforms without generating warnings.861** So instead of reproducing the entire definition from sqliteInt.h, we862** just do without this assert() for the rare non-amalgamation builds.863*/864#define EIGHT_BYTE_ALIGNMENT(x) 1865 866/*867** Macros needed to provide flexible arrays in a portable way868*/869#ifndef offsetof870# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0))871#endif872#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)873# define FLEXARRAY874#else875# define FLEXARRAY 1876#endif877 878#endif879 880/* Truncate very long tokens to this many bytes. Hard limit is 881** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset882** field that occurs at the start of each leaf page (see fts5_index.c). */883#define FTS5_MAX_TOKEN_SIZE 32768884 885/*886** Maximum number of prefix indexes on single FTS5 table. This must be887** less than 32. If it is set to anything large than that, an #error888** directive in fts5_index.c will cause the build to fail.889*/890#define FTS5_MAX_PREFIX_INDEXES 31891 892/*893** Maximum segments permitted in a single index 894*/895#define FTS5_MAX_SEGMENT 2000896 897#define FTS5_DEFAULT_NEARDIST 10898#define FTS5_DEFAULT_RANK     "bm25"899 900/* Name of rank and rowid columns */901#define FTS5_RANK_NAME "rank"902#define FTS5_ROWID_NAME "rowid"903 904#ifdef SQLITE_DEBUG905# define FTS5_CORRUPT sqlite3Fts5Corrupt()906static int sqlite3Fts5Corrupt(void);907#else908# define FTS5_CORRUPT SQLITE_CORRUPT_VTAB909#endif910 911/*912** The assert_nc() macro is similar to the assert() macro, except that it913** is used for assert() conditions that are true only if it can be 914** guranteed that the database is not corrupt.915*/916#ifdef SQLITE_DEBUG917extern int sqlite3_fts5_may_be_corrupt;918# define assert_nc(x) assert(sqlite3_fts5_may_be_corrupt || (x))919#else920# define assert_nc(x) assert(x)921#endif922 923/*924** A version of memcmp() that does not cause asan errors if one of the pointer925** parameters is NULL and the number of bytes to compare is zero.926*/927#define fts5Memcmp(s1, s2, n) ((n)<=0 ? 0 : memcmp((s1), (s2), (n)))928 929/* Mark a function parameter as unused, to suppress nuisance compiler930** warnings. */931#ifndef UNUSED_PARAM932# define UNUSED_PARAM(X)  (void)(X)933#endif934 935#ifndef UNUSED_PARAM2936# define UNUSED_PARAM2(X, Y)  (void)(X), (void)(Y)937#endif938 939typedef struct Fts5Global Fts5Global;940typedef struct Fts5Colset Fts5Colset;941 942/* If a NEAR() clump or phrase may only match a specific set of columns, 943** then an object of the following type is used to record the set of columns.944** Each entry in the aiCol[] array is a column that may be matched.945**946** This object is used by fts5_expr.c and fts5_index.c.947*/948struct Fts5Colset {949  int nCol;950  int aiCol[FLEXARRAY];951};952 953/* Size (int bytes) of a complete Fts5Colset object with N columns. */954#define SZ_FTS5COLSET(N) (sizeof(i64)*((N+2)/2))955 956/**************************************************************************957** Interface to code in fts5_config.c. fts5_config.c contains contains code958** to parse the arguments passed to the CREATE VIRTUAL TABLE statement.959*/960 961typedef struct Fts5Config Fts5Config;962typedef struct Fts5TokenizerConfig Fts5TokenizerConfig;963 964struct Fts5TokenizerConfig {965  Fts5Tokenizer *pTok;966  fts5_tokenizer_v2 *pApi2;967  fts5_tokenizer *pApi1;968  const char **azArg;969  int nArg;970  int ePattern;                   /* FTS_PATTERN_XXX constant */971  const char *pLocale;            /* Current locale to use */972  int nLocale;                    /* Size of pLocale in bytes */973};974 975/*976** An instance of the following structure encodes all information that can977** be gleaned from the CREATE VIRTUAL TABLE statement.978**979** And all information loaded from the %_config table.980**981** nAutomerge:982**   The minimum number of segments that an auto-merge operation should983**   attempt to merge together. A value of 1 sets the object to use the 984**   compile time default. Zero disables auto-merge altogether.985**986** bContentlessDelete:987**   True if the contentless_delete option was present in the CREATE 988**   VIRTUAL TABLE statement.989**990** zContent:991**992** zContentRowid:993**   The value of the content_rowid= option, if one was specified. Or 994**   the string "rowid" otherwise. This text is not quoted - if it is995**   used as part of an SQL statement it needs to be quoted appropriately.996**997** zContentExprlist:998**999** pzErrmsg:1000**   This exists in order to allow the fts5_index.c module to return a 1001**   decent error message if it encounters a file-format version it does1002**   not understand.1003**1004** bColumnsize:1005**   True if the %_docsize table is created.1006**1007** bPrefixIndex:1008**   This is only used for debugging. If set to false, any prefix indexes1009**   are ignored. This value is configured using:1010**1011**       INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);1012**1013** bLocale:1014**   Set to true if locale=1 was specified when the table was created.1015*/1016struct Fts5Config {1017  sqlite3 *db;                    /* Database handle */1018  Fts5Global *pGlobal;            /* Global fts5 object for handle db */1019  char *zDb;                      /* Database holding FTS index (e.g. "main") */1020  char *zName;                    /* Name of FTS index */1021  int nCol;                       /* Number of columns */1022  char **azCol;                   /* Column names */1023  u8 *abUnindexed;                /* True for unindexed columns */1024  int nPrefix;                    /* Number of prefix indexes */1025  int *aPrefix;                   /* Sizes in bytes of nPrefix prefix indexes */1026  int eContent;                   /* An FTS5_CONTENT value */1027  int bContentlessDelete;         /* "contentless_delete=" option (dflt==0) */1028  int bContentlessUnindexed;      /* "contentless_unindexed=" option (dflt=0) */1029  char *zContent;                 /* content table */ 1030  char *zContentRowid;            /* "content_rowid=" option value */ 1031  int bColumnsize;                /* "columnsize=" option value (dflt==1) */1032  int bTokendata;                 /* "tokendata=" option value (dflt==0) */1033  int bLocale;                    /* "locale=" option value (dflt==0) */1034  int eDetail;                    /* FTS5_DETAIL_XXX value */1035  char *zContentExprlist;1036  Fts5TokenizerConfig t;1037  int bLock;                      /* True when table is preparing statement */1038  1039 1040  /* Values loaded from the %_config table */1041  int iVersion;                   /* fts5 file format 'version' */1042  int iCookie;                    /* Incremented when %_config is modified */1043  int pgsz;                       /* Approximate page size used in %_data */1044  int nAutomerge;                 /* 'automerge' setting */1045  int nCrisisMerge;               /* Maximum allowed segments per level */1046  int nUsermerge;                 /* 'usermerge' setting */1047  int nHashSize;                  /* Bytes of memory for in-memory hash */1048  char *zRank;                    /* Name of rank function */1049  char *zRankArgs;                /* Arguments to rank function */1050  int bSecureDelete;              /* 'secure-delete' */1051  int nDeleteMerge;               /* 'deletemerge' */1052  int bPrefixInsttoken;           /* 'prefix-insttoken' */1053 1054  /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */1055  char **pzErrmsg;1056 1057#ifdef SQLITE_DEBUG1058  int bPrefixIndex;               /* True to use prefix-indexes */1059#endif1060};1061 1062/* Current expected value of %_config table 'version' field. And1063** the expected version if the 'secure-delete' option has ever been1064** set on the table.  */1065#define FTS5_CURRENT_VERSION               41066#define FTS5_CURRENT_VERSION_SECUREDELETE  51067 1068#define FTS5_CONTENT_NORMAL    01069#define FTS5_CONTENT_NONE      11070#define FTS5_CONTENT_EXTERNAL  21071#define FTS5_CONTENT_UNINDEXED 31072 1073#define FTS5_DETAIL_FULL      01074#define FTS5_DETAIL_NONE      11075#define FTS5_DETAIL_COLUMNS   21076 1077#define FTS5_PATTERN_NONE     01078#define FTS5_PATTERN_LIKE     65  /* matches SQLITE_INDEX_CONSTRAINT_LIKE */1079#define FTS5_PATTERN_GLOB     66  /* matches SQLITE_INDEX_CONSTRAINT_GLOB */1080 1081static int sqlite3Fts5ConfigParse(1082    Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**1083);1084static void sqlite3Fts5ConfigFree(Fts5Config*);1085 1086static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig);1087 1088static int sqlite3Fts5Tokenize(1089  Fts5Config *pConfig,            /* FTS5 Configuration object */1090  int flags,                      /* FTS5_TOKENIZE_* flags */1091  const char *pText, int nText,   /* Text to tokenize */1092  void *pCtx,                     /* Context passed to xToken() */1093  int (*xToken)(void*, int, const char*, int, int, int)    /* Callback */1094);1095 1096static void sqlite3Fts5Dequote(char *z);1097 1098/* Load the contents of the %_config table */1099static int sqlite3Fts5ConfigLoad(Fts5Config*, int);1100 1101/* Set the value of a single config attribute */1102static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*);1103 1104static int sqlite3Fts5ConfigParseRank(const char*, char**, char**);1105 1106static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...);1107 1108/*1109** End of interface to code in fts5_config.c.1110**************************************************************************/1111 1112/**************************************************************************1113** Interface to code in fts5_buffer.c.1114*/1115 1116/*1117** Buffer object for the incremental building of string data.1118*/1119typedef struct Fts5Buffer Fts5Buffer;1120struct Fts5Buffer {1121  u8 *p;1122  int n;1123  int nSpace;1124};1125 1126static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32);1127static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64);1128static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*);1129static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*);1130static void sqlite3Fts5BufferFree(Fts5Buffer*);1131static void sqlite3Fts5BufferZero(Fts5Buffer*);1132static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);1133static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);1134 1135static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);1136 1137#define fts5BufferZero(x)             sqlite3Fts5BufferZero(x)1138#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,(i64)c)1139#define fts5BufferFree(a)             sqlite3Fts5BufferFree(a)1140#define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)1141#define fts5BufferSet(a,b,c,d)        sqlite3Fts5BufferSet(a,b,c,d)1142 1143#define fts5BufferGrow(pRc,pBuf,nn) ( \1144  (u32)((pBuf)->n) + (u32)(nn) <= (u32)((pBuf)->nSpace) ? 0 : \1145    sqlite3Fts5BufferSize((pRc),(pBuf),(nn)+(pBuf)->n) \1146)1147 1148/* Write and decode big-endian 32-bit integer values */1149static void sqlite3Fts5Put32(u8*, int);1150static int sqlite3Fts5Get32(const u8*);1151 1152#define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF)1153#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)1154 1155typedef struct Fts5PoslistReader Fts5PoslistReader;1156struct Fts5PoslistReader {1157  /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */1158  const u8 *a;                    /* Position list to iterate through */1159  int n;                          /* Size of buffer at a[] in bytes */1160  int i;                          /* Current offset in a[] */1161 1162  u8 bFlag;                       /* For client use (any custom purpose) */1163 1164  /* Output variables */1165  u8 bEof;                        /* Set to true at EOF */1166  i64 iPos;                       /* (iCol<<32) + iPos */1167};1168static int sqlite3Fts5PoslistReaderInit(1169  const u8 *a, int n,             /* Poslist buffer to iterate through */1170  Fts5PoslistReader *pIter        /* Iterator object to initialize */1171);1172static int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader*);1173 1174typedef struct Fts5PoslistWriter Fts5PoslistWriter;1175struct Fts5PoslistWriter {1176  i64 iPrev;1177};1178static int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64);1179static void sqlite3Fts5PoslistSafeAppend(Fts5Buffer*, i64*, i64);1180 1181static int sqlite3Fts5PoslistNext64(1182  const u8 *a, int n,             /* Buffer containing poslist */1183  int *pi,                        /* IN/OUT: Offset within a[] */1184  i64 *piOff                      /* IN/OUT: Current offset */1185);1186 1187/* Malloc utility */1188static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte);1189static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);1190 1191/* Character set tests (like isspace(), isalpha() etc.) */1192static int sqlite3Fts5IsBareword(char t);1193 1194 1195/* Bucket of terms object used by the integrity-check in offsets=0 mode. */1196typedef struct Fts5Termset Fts5Termset;1197static int sqlite3Fts5TermsetNew(Fts5Termset**);1198static int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent);1199static void sqlite3Fts5TermsetFree(Fts5Termset*);1200 

Showing the first 1,200 of 27998 lines. Download the file for the rest.