xref: /sqlite-3.40.0/ext/fts5/fts5_main.c (revision 7ef4d75b)
1 /*
2 ** 2014 Jun 09
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 ******************************************************************************
12 **
13 ** This is an SQLite module implementing full-text search.
14 */
15 
16 
17 #include "fts5Int.h"
18 
19 /*
20 ** This variable is set to false when running tests for which the on disk
21 ** structures should not be corrupt. Otherwise, true. If it is false, extra
22 ** assert() conditions in the fts5 code are activated - conditions that are
23 ** only true if it is guaranteed that the fts5 database is not corrupt.
24 */
25 #ifdef SQLITE_DEBUG
26 int sqlite3_fts5_may_be_corrupt = 1;
27 #endif
28 
29 
30 typedef struct Fts5Auxdata Fts5Auxdata;
31 typedef struct Fts5Auxiliary Fts5Auxiliary;
32 typedef struct Fts5Cursor Fts5Cursor;
33 typedef struct Fts5FullTable Fts5FullTable;
34 typedef struct Fts5Sorter Fts5Sorter;
35 typedef struct Fts5TokenizerModule Fts5TokenizerModule;
36 
37 /*
38 ** NOTES ON TRANSACTIONS:
39 **
40 ** SQLite invokes the following virtual table methods as transactions are
41 ** opened and closed by the user:
42 **
43 **     xBegin():    Start of a new transaction.
44 **     xSync():     Initial part of two-phase commit.
45 **     xCommit():   Final part of two-phase commit.
46 **     xRollback(): Rollback the transaction.
47 **
48 ** Anything that is required as part of a commit that may fail is performed
49 ** in the xSync() callback. Current versions of SQLite ignore any errors
50 ** returned by xCommit().
51 **
52 ** And as sub-transactions are opened/closed:
53 **
54 **     xSavepoint(int S):  Open savepoint S.
55 **     xRelease(int S):    Commit and close savepoint S.
56 **     xRollbackTo(int S): Rollback to start of savepoint S.
57 **
58 ** During a write-transaction the fts5_index.c module may cache some data
59 ** in-memory. It is flushed to disk whenever xSync(), xRelease() or
60 ** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
61 ** is called.
62 **
63 ** Additionally, if SQLITE_DEBUG is defined, an instance of the following
64 ** structure is used to record the current transaction state. This information
65 ** is not required, but it is used in the assert() statements executed by
66 ** function fts5CheckTransactionState() (see below).
67 */
68 struct Fts5TransactionState {
69   int eState;                     /* 0==closed, 1==open, 2==synced */
70   int iSavepoint;                 /* Number of open savepoints (0 -> none) */
71 };
72 
73 /*
74 ** A single object of this type is allocated when the FTS5 module is
75 ** registered with a database handle. It is used to store pointers to
76 ** all registered FTS5 extensions - tokenizers and auxiliary functions.
77 */
78 struct Fts5Global {
79   fts5_api api;                   /* User visible part of object (see fts5.h) */
80   sqlite3 *db;                    /* Associated database connection */
81   i64 iNextId;                    /* Used to allocate unique cursor ids */
82   Fts5Auxiliary *pAux;            /* First in list of all aux. functions */
83   Fts5TokenizerModule *pTok;      /* First in list of all tokenizer modules */
84   Fts5TokenizerModule *pDfltTok;  /* Default tokenizer module */
85   Fts5Cursor *pCsr;               /* First in list of all open cursors */
86 };
87 
88 /*
89 ** Each auxiliary function registered with the FTS5 module is represented
90 ** by an object of the following type. All such objects are stored as part
91 ** of the Fts5Global.pAux list.
92 */
93 struct Fts5Auxiliary {
94   Fts5Global *pGlobal;            /* Global context for this function */
95   char *zFunc;                    /* Function name (nul-terminated) */
96   void *pUserData;                /* User-data pointer */
97   fts5_extension_function xFunc;  /* Callback function */
98   void (*xDestroy)(void*);        /* Destructor function */
99   Fts5Auxiliary *pNext;           /* Next registered auxiliary function */
100 };
101 
102 /*
103 ** Each tokenizer module registered with the FTS5 module is represented
104 ** by an object of the following type. All such objects are stored as part
105 ** of the Fts5Global.pTok list.
106 */
107 struct Fts5TokenizerModule {
108   char *zName;                    /* Name of tokenizer */
109   void *pUserData;                /* User pointer passed to xCreate() */
110   fts5_tokenizer x;               /* Tokenizer functions */
111   void (*xDestroy)(void*);        /* Destructor function */
112   Fts5TokenizerModule *pNext;     /* Next registered tokenizer module */
113 };
114 
115 struct Fts5FullTable {
116   Fts5Table p;                    /* Public class members from fts5Int.h */
117   Fts5Storage *pStorage;          /* Document store */
118   Fts5Global *pGlobal;            /* Global (connection wide) data */
119   Fts5Cursor *pSortCsr;           /* Sort data from this cursor */
120 #ifdef SQLITE_DEBUG
121   struct Fts5TransactionState ts;
122 #endif
123 };
124 
125 struct Fts5MatchPhrase {
126   Fts5Buffer *pPoslist;           /* Pointer to current poslist */
127   int nTerm;                      /* Size of phrase in terms */
128 };
129 
130 /*
131 ** pStmt:
132 **   SELECT rowid, <fts> FROM <fts> ORDER BY +rank;
133 **
134 ** aIdx[]:
135 **   There is one entry in the aIdx[] array for each phrase in the query,
136 **   the value of which is the offset within aPoslist[] following the last
137 **   byte of the position list for the corresponding phrase.
138 */
139 struct Fts5Sorter {
140   sqlite3_stmt *pStmt;
141   i64 iRowid;                     /* Current rowid */
142   const u8 *aPoslist;             /* Position lists for current row */
143   int nIdx;                       /* Number of entries in aIdx[] */
144   int aIdx[1];                    /* Offsets into aPoslist for current row */
145 };
146 
147 
148 /*
149 ** Virtual-table cursor object.
150 **
151 ** iSpecial:
152 **   If this is a 'special' query (refer to function fts5SpecialMatch()),
153 **   then this variable contains the result of the query.
154 **
155 ** iFirstRowid, iLastRowid:
156 **   These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
157 **   cursor iterates in ascending order of rowids, iFirstRowid is the lower
158 **   limit of rowids to return, and iLastRowid the upper. In other words, the
159 **   WHERE clause in the user's query might have been:
160 **
161 **       <tbl> MATCH <expr> AND rowid BETWEEN $iFirstRowid AND $iLastRowid
162 **
163 **   If the cursor iterates in descending order of rowid, iFirstRowid
164 **   is the upper limit (i.e. the "first" rowid visited) and iLastRowid
165 **   the lower.
166 */
167 struct Fts5Cursor {
168   sqlite3_vtab_cursor base;       /* Base class used by SQLite core */
169   Fts5Cursor *pNext;              /* Next cursor in Fts5Cursor.pCsr list */
170   int *aColumnSize;               /* Values for xColumnSize() */
171   i64 iCsrId;                     /* Cursor id */
172 
173   /* Zero from this point onwards on cursor reset */
174   int ePlan;                      /* FTS5_PLAN_XXX value */
175   int bDesc;                      /* True for "ORDER BY rowid DESC" queries */
176   i64 iFirstRowid;                /* Return no rowids earlier than this */
177   i64 iLastRowid;                 /* Return no rowids later than this */
178   sqlite3_stmt *pStmt;            /* Statement used to read %_content */
179   Fts5Expr *pExpr;                /* Expression for MATCH queries */
180   Fts5Sorter *pSorter;            /* Sorter for "ORDER BY rank" queries */
181   int csrflags;                   /* Mask of cursor flags (see below) */
182   i64 iSpecial;                   /* Result of special query */
183 
184   /* "rank" function. Populated on demand from vtab.xColumn(). */
185   char *zRank;                    /* Custom rank function */
186   char *zRankArgs;                /* Custom rank function args */
187   Fts5Auxiliary *pRank;           /* Rank callback (or NULL) */
188   int nRankArg;                   /* Number of trailing arguments for rank() */
189   sqlite3_value **apRankArg;      /* Array of trailing arguments */
190   sqlite3_stmt *pRankArgStmt;     /* Origin of objects in apRankArg[] */
191 
192   /* Auxiliary data storage */
193   Fts5Auxiliary *pAux;            /* Currently executing extension function */
194   Fts5Auxdata *pAuxdata;          /* First in linked list of saved aux-data */
195 
196   /* Cache used by auxiliary functions xInst() and xInstCount() */
197   Fts5PoslistReader *aInstIter;   /* One for each phrase */
198   int nInstAlloc;                 /* Size of aInst[] array (entries / 3) */
199   int nInstCount;                 /* Number of phrase instances */
200   int *aInst;                     /* 3 integers per phrase instance */
201 };
202 
203 /*
204 ** Bits that make up the "idxNum" parameter passed indirectly by
205 ** xBestIndex() to xFilter().
206 */
207 #define FTS5_BI_MATCH        0x0001         /* <tbl> MATCH ? */
208 #define FTS5_BI_RANK         0x0002         /* rank MATCH ? */
209 #define FTS5_BI_ROWID_EQ     0x0004         /* rowid == ? */
210 #define FTS5_BI_ROWID_LE     0x0008         /* rowid <= ? */
211 #define FTS5_BI_ROWID_GE     0x0010         /* rowid >= ? */
212 
213 #define FTS5_BI_ORDER_RANK   0x0020
214 #define FTS5_BI_ORDER_ROWID  0x0040
215 #define FTS5_BI_ORDER_DESC   0x0080
216 
217 /*
218 ** Values for Fts5Cursor.csrflags
219 */
220 #define FTS5CSR_EOF               0x01
221 #define FTS5CSR_REQUIRE_CONTENT   0x02
222 #define FTS5CSR_REQUIRE_DOCSIZE   0x04
223 #define FTS5CSR_REQUIRE_INST      0x08
224 #define FTS5CSR_FREE_ZRANK        0x10
225 #define FTS5CSR_REQUIRE_RESEEK    0x20
226 #define FTS5CSR_REQUIRE_POSLIST   0x40
227 
228 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
229 #define BitFlagTest(x,y)    (((x) & (y))!=0)
230 
231 
232 /*
233 ** Macros to Set(), Clear() and Test() cursor flags.
234 */
235 #define CsrFlagSet(pCsr, flag)   ((pCsr)->csrflags |= (flag))
236 #define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag))
237 #define CsrFlagTest(pCsr, flag)  ((pCsr)->csrflags & (flag))
238 
239 struct Fts5Auxdata {
240   Fts5Auxiliary *pAux;            /* Extension to which this belongs */
241   void *pPtr;                     /* Pointer value */
242   void(*xDelete)(void*);          /* Destructor */
243   Fts5Auxdata *pNext;             /* Next object in linked list */
244 };
245 
246 #ifdef SQLITE_DEBUG
247 #define FTS5_BEGIN      1
248 #define FTS5_SYNC       2
249 #define FTS5_COMMIT     3
250 #define FTS5_ROLLBACK   4
251 #define FTS5_SAVEPOINT  5
252 #define FTS5_RELEASE    6
253 #define FTS5_ROLLBACKTO 7
fts5CheckTransactionState(Fts5FullTable * p,int op,int iSavepoint)254 static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
255   switch( op ){
256     case FTS5_BEGIN:
257       assert( p->ts.eState==0 );
258       p->ts.eState = 1;
259       p->ts.iSavepoint = -1;
260       break;
261 
262     case FTS5_SYNC:
263       assert( p->ts.eState==1 );
264       p->ts.eState = 2;
265       break;
266 
267     case FTS5_COMMIT:
268       assert( p->ts.eState==2 );
269       p->ts.eState = 0;
270       break;
271 
272     case FTS5_ROLLBACK:
273       assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 );
274       p->ts.eState = 0;
275       break;
276 
277     case FTS5_SAVEPOINT:
278       assert( p->ts.eState==1 );
279       assert( iSavepoint>=0 );
280       assert( iSavepoint>=p->ts.iSavepoint );
281       p->ts.iSavepoint = iSavepoint;
282       break;
283 
284     case FTS5_RELEASE:
285       assert( p->ts.eState==1 );
286       assert( iSavepoint>=0 );
287       assert( iSavepoint<=p->ts.iSavepoint );
288       p->ts.iSavepoint = iSavepoint-1;
289       break;
290 
291     case FTS5_ROLLBACKTO:
292       assert( p->ts.eState==1 );
293       assert( iSavepoint>=-1 );
294       /* The following assert() can fail if another vtab strikes an error
295       ** within an xSavepoint() call then SQLite calls xRollbackTo() - without
296       ** having called xSavepoint() on this vtab.  */
297       /* assert( iSavepoint<=p->ts.iSavepoint ); */
298       p->ts.iSavepoint = iSavepoint;
299       break;
300   }
301 }
302 #else
303 # define fts5CheckTransactionState(x,y,z)
304 #endif
305 
306 /*
307 ** Return true if pTab is a contentless table.
308 */
fts5IsContentless(Fts5FullTable * pTab)309 static int fts5IsContentless(Fts5FullTable *pTab){
310   return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
311 }
312 
313 /*
314 ** Delete a virtual table handle allocated by fts5InitVtab().
315 */
fts5FreeVtab(Fts5FullTable * pTab)316 static void fts5FreeVtab(Fts5FullTable *pTab){
317   if( pTab ){
318     sqlite3Fts5IndexClose(pTab->p.pIndex);
319     sqlite3Fts5StorageClose(pTab->pStorage);
320     sqlite3Fts5ConfigFree(pTab->p.pConfig);
321     sqlite3_free(pTab);
322   }
323 }
324 
325 /*
326 ** The xDisconnect() virtual table method.
327 */
fts5DisconnectMethod(sqlite3_vtab * pVtab)328 static int fts5DisconnectMethod(sqlite3_vtab *pVtab){
329   fts5FreeVtab((Fts5FullTable*)pVtab);
330   return SQLITE_OK;
331 }
332 
333 /*
334 ** The xDestroy() virtual table method.
335 */
fts5DestroyMethod(sqlite3_vtab * pVtab)336 static int fts5DestroyMethod(sqlite3_vtab *pVtab){
337   Fts5Table *pTab = (Fts5Table*)pVtab;
338   int rc = sqlite3Fts5DropAll(pTab->pConfig);
339   if( rc==SQLITE_OK ){
340     fts5FreeVtab((Fts5FullTable*)pVtab);
341   }
342   return rc;
343 }
344 
345 /*
346 ** This function is the implementation of both the xConnect and xCreate
347 ** methods of the FTS3 virtual table.
348 **
349 ** The argv[] array contains the following:
350 **
351 **   argv[0]   -> module name  ("fts5")
352 **   argv[1]   -> database name
353 **   argv[2]   -> table name
354 **   argv[...] -> "column name" and other module argument fields.
355 */
fts5InitVtab(int bCreate,sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVTab,char ** pzErr)356 static int fts5InitVtab(
357   int bCreate,                    /* True for xCreate, false for xConnect */
358   sqlite3 *db,                    /* The SQLite database connection */
359   void *pAux,                     /* Hash table containing tokenizers */
360   int argc,                       /* Number of elements in argv array */
361   const char * const *argv,       /* xCreate/xConnect argument array */
362   sqlite3_vtab **ppVTab,          /* Write the resulting vtab structure here */
363   char **pzErr                    /* Write any error message here */
364 ){
365   Fts5Global *pGlobal = (Fts5Global*)pAux;
366   const char **azConfig = (const char**)argv;
367   int rc = SQLITE_OK;             /* Return code */
368   Fts5Config *pConfig = 0;        /* Results of parsing argc/argv */
369   Fts5FullTable *pTab = 0;        /* New virtual table object */
370 
371   /* Allocate the new vtab object and parse the configuration */
372   pTab = (Fts5FullTable*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5FullTable));
373   if( rc==SQLITE_OK ){
374     rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
375     assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
376   }
377   if( rc==SQLITE_OK ){
378     pTab->p.pConfig = pConfig;
379     pTab->pGlobal = pGlobal;
380   }
381 
382   /* Open the index sub-system */
383   if( rc==SQLITE_OK ){
384     rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->p.pIndex, pzErr);
385   }
386 
387   /* Open the storage sub-system */
388   if( rc==SQLITE_OK ){
389     rc = sqlite3Fts5StorageOpen(
390         pConfig, pTab->p.pIndex, bCreate, &pTab->pStorage, pzErr
391     );
392   }
393 
394   /* Call sqlite3_declare_vtab() */
395   if( rc==SQLITE_OK ){
396     rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
397   }
398 
399   /* Load the initial configuration */
400   if( rc==SQLITE_OK ){
401     assert( pConfig->pzErrmsg==0 );
402     pConfig->pzErrmsg = pzErr;
403     rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
404     sqlite3Fts5IndexRollback(pTab->p.pIndex);
405     pConfig->pzErrmsg = 0;
406   }
407 
408   if( rc!=SQLITE_OK ){
409     fts5FreeVtab(pTab);
410     pTab = 0;
411   }else if( bCreate ){
412     fts5CheckTransactionState(pTab, FTS5_BEGIN, 0);
413   }
414   *ppVTab = (sqlite3_vtab*)pTab;
415   return rc;
416 }
417 
418 /*
419 ** The xConnect() and xCreate() methods for the virtual table. All the
420 ** work is done in function fts5InitVtab().
421 */
fts5ConnectMethod(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)422 static int fts5ConnectMethod(
423   sqlite3 *db,                    /* Database connection */
424   void *pAux,                     /* Pointer to tokenizer hash table */
425   int argc,                       /* Number of elements in argv array */
426   const char * const *argv,       /* xCreate/xConnect argument array */
427   sqlite3_vtab **ppVtab,          /* OUT: New sqlite3_vtab object */
428   char **pzErr                    /* OUT: sqlite3_malloc'd error message */
429 ){
430   return fts5InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr);
431 }
fts5CreateMethod(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)432 static int fts5CreateMethod(
433   sqlite3 *db,                    /* Database connection */
434   void *pAux,                     /* Pointer to tokenizer hash table */
435   int argc,                       /* Number of elements in argv array */
436   const char * const *argv,       /* xCreate/xConnect argument array */
437   sqlite3_vtab **ppVtab,          /* OUT: New sqlite3_vtab object */
438   char **pzErr                    /* OUT: sqlite3_malloc'd error message */
439 ){
440   return fts5InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr);
441 }
442 
443 /*
444 ** The different query plans.
445 */
446 #define FTS5_PLAN_MATCH          1       /* (<tbl> MATCH ?) */
447 #define FTS5_PLAN_SOURCE         2       /* A source cursor for SORTED_MATCH */
448 #define FTS5_PLAN_SPECIAL        3       /* An internal query */
449 #define FTS5_PLAN_SORTED_MATCH   4       /* (<tbl> MATCH ? ORDER BY rank) */
450 #define FTS5_PLAN_SCAN           5       /* No usable constraint */
451 #define FTS5_PLAN_ROWID          6       /* (rowid = ?) */
452 
453 /*
454 ** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
455 ** extension is currently being used by a version of SQLite too old to
456 ** support index-info flags. In that case this function is a no-op.
457 */
fts5SetUniqueFlag(sqlite3_index_info * pIdxInfo)458 static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
459 #if SQLITE_VERSION_NUMBER>=3008012
460 #ifndef SQLITE_CORE
461   if( sqlite3_libversion_number()>=3008012 )
462 #endif
463   {
464     pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
465   }
466 #endif
467 }
468 
fts5UsePatternMatch(Fts5Config * pConfig,struct sqlite3_index_constraint * p)469 static int fts5UsePatternMatch(
470   Fts5Config *pConfig,
471   struct sqlite3_index_constraint *p
472 ){
473   assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB );
474   assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE );
475   if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
476     return 1;
477   }
478   if( pConfig->ePattern==FTS5_PATTERN_LIKE
479    && (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB)
480   ){
481     return 1;
482   }
483   return 0;
484 }
485 
486 /*
487 ** Implementation of the xBestIndex method for FTS5 tables. Within the
488 ** WHERE constraint, it searches for the following:
489 **
490 **   1. A MATCH constraint against the table column.
491 **   2. A MATCH constraint against the "rank" column.
492 **   3. A MATCH constraint against some other column.
493 **   4. An == constraint against the rowid column.
494 **   5. A < or <= constraint against the rowid column.
495 **   6. A > or >= constraint against the rowid column.
496 **
497 ** Within the ORDER BY, the following are supported:
498 **
499 **   5. ORDER BY rank [ASC|DESC]
500 **   6. ORDER BY rowid [ASC|DESC]
501 **
502 ** Information for the xFilter call is passed via both the idxNum and
503 ** idxStr variables. Specifically, idxNum is a bitmask of the following
504 ** flags used to encode the ORDER BY clause:
505 **
506 **     FTS5_BI_ORDER_RANK
507 **     FTS5_BI_ORDER_ROWID
508 **     FTS5_BI_ORDER_DESC
509 **
510 ** idxStr is used to encode data from the WHERE clause. For each argument
511 ** passed to the xFilter method, the following is appended to idxStr:
512 **
513 **   Match against table column:            "m"
514 **   Match against rank column:             "r"
515 **   Match against other column:            "M<column-number>"
516 **   LIKE  against other column:            "L<column-number>"
517 **   GLOB  against other column:            "G<column-number>"
518 **   Equality constraint against the rowid: "="
519 **   A < or <= against the rowid:           "<"
520 **   A > or >= against the rowid:           ">"
521 **
522 ** This function ensures that there is at most one "r" or "=". And that if
523 ** there exists an "=" then there is no "<" or ">".
524 **
525 ** Costs are assigned as follows:
526 **
527 **  a) If an unusable MATCH operator is present in the WHERE clause, the
528 **     cost is unconditionally set to 1e50 (a really big number).
529 **
530 **  a) If a MATCH operator is present, the cost depends on the other
531 **     constraints also present. As follows:
532 **
533 **       * No other constraints:         cost=1000.0
534 **       * One rowid range constraint:   cost=750.0
535 **       * Both rowid range constraints: cost=500.0
536 **       * An == rowid constraint:       cost=100.0
537 **
538 **  b) Otherwise, if there is no MATCH:
539 **
540 **       * No other constraints:         cost=1000000.0
541 **       * One rowid range constraint:   cost=750000.0
542 **       * Both rowid range constraints: cost=250000.0
543 **       * An == rowid constraint:       cost=10.0
544 **
545 ** Costs are not modified by the ORDER BY clause.
546 */
fts5BestIndexMethod(sqlite3_vtab * pVTab,sqlite3_index_info * pInfo)547 static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
548   Fts5Table *pTab = (Fts5Table*)pVTab;
549   Fts5Config *pConfig = pTab->pConfig;
550   const int nCol = pConfig->nCol;
551   int idxFlags = 0;               /* Parameter passed through to xFilter() */
552   int i;
553 
554   char *idxStr;
555   int iIdxStr = 0;
556   int iCons = 0;
557 
558   int bSeenEq = 0;
559   int bSeenGt = 0;
560   int bSeenLt = 0;
561   int bSeenMatch = 0;
562   int bSeenRank = 0;
563 
564 
565   assert( SQLITE_INDEX_CONSTRAINT_EQ<SQLITE_INDEX_CONSTRAINT_MATCH );
566   assert( SQLITE_INDEX_CONSTRAINT_GT<SQLITE_INDEX_CONSTRAINT_MATCH );
567   assert( SQLITE_INDEX_CONSTRAINT_LE<SQLITE_INDEX_CONSTRAINT_MATCH );
568   assert( SQLITE_INDEX_CONSTRAINT_GE<SQLITE_INDEX_CONSTRAINT_MATCH );
569   assert( SQLITE_INDEX_CONSTRAINT_LE<SQLITE_INDEX_CONSTRAINT_MATCH );
570 
571   if( pConfig->bLock ){
572     pTab->base.zErrMsg = sqlite3_mprintf(
573         "recursively defined fts5 content table"
574     );
575     return SQLITE_ERROR;
576   }
577 
578   idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1);
579   if( idxStr==0 ) return SQLITE_NOMEM;
580   pInfo->idxStr = idxStr;
581   pInfo->needToFreeIdxStr = 1;
582 
583   for(i=0; i<pInfo->nConstraint; i++){
584     struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
585     int iCol = p->iColumn;
586     if( p->op==SQLITE_INDEX_CONSTRAINT_MATCH
587      || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol>=nCol)
588     ){
589       /* A MATCH operator or equivalent */
590       if( p->usable==0 || iCol<0 ){
591         /* As there exists an unusable MATCH constraint this is an
592         ** unusable plan. Set a prohibitively high cost. */
593         pInfo->estimatedCost = 1e50;
594         assert( iIdxStr < pInfo->nConstraint*6 + 1 );
595         idxStr[iIdxStr] = 0;
596         return SQLITE_OK;
597       }else{
598         if( iCol==nCol+1 ){
599           if( bSeenRank ) continue;
600           idxStr[iIdxStr++] = 'r';
601           bSeenRank = 1;
602         }else if( iCol>=0 ){
603           bSeenMatch = 1;
604           idxStr[iIdxStr++] = 'M';
605           sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
606           idxStr += strlen(&idxStr[iIdxStr]);
607           assert( idxStr[iIdxStr]=='\0' );
608         }
609         pInfo->aConstraintUsage[i].argvIndex = ++iCons;
610         pInfo->aConstraintUsage[i].omit = 1;
611       }
612     }else if( p->usable ){
613       if( iCol>=0 && iCol<nCol && fts5UsePatternMatch(pConfig, p) ){
614         assert( p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB );
615         idxStr[iIdxStr++] = p->op==FTS5_PATTERN_LIKE ? 'L' : 'G';
616         sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
617         idxStr += strlen(&idxStr[iIdxStr]);
618         pInfo->aConstraintUsage[i].argvIndex = ++iCons;
619         assert( idxStr[iIdxStr]=='\0' );
620       }else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){
621         idxStr[iIdxStr++] = '=';
622         bSeenEq = 1;
623         pInfo->aConstraintUsage[i].argvIndex = ++iCons;
624       }
625     }
626   }
627 
628   if( bSeenEq==0 ){
629     for(i=0; i<pInfo->nConstraint; i++){
630       struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
631       if( p->iColumn<0 && p->usable ){
632         int op = p->op;
633         if( op==SQLITE_INDEX_CONSTRAINT_LT || op==SQLITE_INDEX_CONSTRAINT_LE ){
634           if( bSeenLt ) continue;
635           idxStr[iIdxStr++] = '<';
636           pInfo->aConstraintUsage[i].argvIndex = ++iCons;
637           bSeenLt = 1;
638         }else
639         if( op==SQLITE_INDEX_CONSTRAINT_GT || op==SQLITE_INDEX_CONSTRAINT_GE ){
640           if( bSeenGt ) continue;
641           idxStr[iIdxStr++] = '>';
642           pInfo->aConstraintUsage[i].argvIndex = ++iCons;
643           bSeenGt = 1;
644         }
645       }
646     }
647   }
648   idxStr[iIdxStr] = '\0';
649 
650   /* Set idxFlags flags for the ORDER BY clause */
651   if( pInfo->nOrderBy==1 ){
652     int iSort = pInfo->aOrderBy[0].iColumn;
653     if( iSort==(pConfig->nCol+1) && bSeenMatch ){
654       idxFlags |= FTS5_BI_ORDER_RANK;
655     }else if( iSort==-1 ){
656       idxFlags |= FTS5_BI_ORDER_ROWID;
657     }
658     if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
659       pInfo->orderByConsumed = 1;
660       if( pInfo->aOrderBy[0].desc ){
661         idxFlags |= FTS5_BI_ORDER_DESC;
662       }
663     }
664   }
665 
666   /* Calculate the estimated cost based on the flags set in idxFlags. */
667   if( bSeenEq ){
668     pInfo->estimatedCost = bSeenMatch ? 100.0 : 10.0;
669     if( bSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
670   }else if( bSeenLt && bSeenGt ){
671     pInfo->estimatedCost = bSeenMatch ? 500.0 : 250000.0;
672   }else if( bSeenLt || bSeenGt ){
673     pInfo->estimatedCost = bSeenMatch ? 750.0 : 750000.0;
674   }else{
675     pInfo->estimatedCost = bSeenMatch ? 1000.0 : 1000000.0;
676   }
677 
678   pInfo->idxNum = idxFlags;
679   return SQLITE_OK;
680 }
681 
fts5NewTransaction(Fts5FullTable * pTab)682 static int fts5NewTransaction(Fts5FullTable *pTab){
683   Fts5Cursor *pCsr;
684   for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
685     if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
686   }
687   return sqlite3Fts5StorageReset(pTab->pStorage);
688 }
689 
690 /*
691 ** Implementation of xOpen method.
692 */
fts5OpenMethod(sqlite3_vtab * pVTab,sqlite3_vtab_cursor ** ppCsr)693 static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
694   Fts5FullTable *pTab = (Fts5FullTable*)pVTab;
695   Fts5Config *pConfig = pTab->p.pConfig;
696   Fts5Cursor *pCsr = 0;           /* New cursor object */
697   sqlite3_int64 nByte;            /* Bytes of space to allocate */
698   int rc;                         /* Return code */
699 
700   rc = fts5NewTransaction(pTab);
701   if( rc==SQLITE_OK ){
702     nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
703     pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte);
704     if( pCsr ){
705       Fts5Global *pGlobal = pTab->pGlobal;
706       memset(pCsr, 0, (size_t)nByte);
707       pCsr->aColumnSize = (int*)&pCsr[1];
708       pCsr->pNext = pGlobal->pCsr;
709       pGlobal->pCsr = pCsr;
710       pCsr->iCsrId = ++pGlobal->iNextId;
711     }else{
712       rc = SQLITE_NOMEM;
713     }
714   }
715   *ppCsr = (sqlite3_vtab_cursor*)pCsr;
716   return rc;
717 }
718 
fts5StmtType(Fts5Cursor * pCsr)719 static int fts5StmtType(Fts5Cursor *pCsr){
720   if( pCsr->ePlan==FTS5_PLAN_SCAN ){
721     return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC;
722   }
723   return FTS5_STMT_LOOKUP;
724 }
725 
726 /*
727 ** This function is called after the cursor passed as the only argument
728 ** is moved to point at a different row. It clears all cached data
729 ** specific to the previous row stored by the cursor object.
730 */
fts5CsrNewrow(Fts5Cursor * pCsr)731 static void fts5CsrNewrow(Fts5Cursor *pCsr){
732   CsrFlagSet(pCsr,
733       FTS5CSR_REQUIRE_CONTENT
734     | FTS5CSR_REQUIRE_DOCSIZE
735     | FTS5CSR_REQUIRE_INST
736     | FTS5CSR_REQUIRE_POSLIST
737   );
738 }
739 
fts5FreeCursorComponents(Fts5Cursor * pCsr)740 static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
741   Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
742   Fts5Auxdata *pData;
743   Fts5Auxdata *pNext;
744 
745   sqlite3_free(pCsr->aInstIter);
746   sqlite3_free(pCsr->aInst);
747   if( pCsr->pStmt ){
748     int eStmt = fts5StmtType(pCsr);
749     sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
750   }
751   if( pCsr->pSorter ){
752     Fts5Sorter *pSorter = pCsr->pSorter;
753     sqlite3_finalize(pSorter->pStmt);
754     sqlite3_free(pSorter);
755   }
756 
757   if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){
758     sqlite3Fts5ExprFree(pCsr->pExpr);
759   }
760 
761   for(pData=pCsr->pAuxdata; pData; pData=pNext){
762     pNext = pData->pNext;
763     if( pData->xDelete ) pData->xDelete(pData->pPtr);
764     sqlite3_free(pData);
765   }
766 
767   sqlite3_finalize(pCsr->pRankArgStmt);
768   sqlite3_free(pCsr->apRankArg);
769 
770   if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){
771     sqlite3_free(pCsr->zRank);
772     sqlite3_free(pCsr->zRankArgs);
773   }
774 
775   sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
776   memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr));
777 }
778 
779 
780 /*
781 ** Close the cursor.  For additional information see the documentation
782 ** on the xClose method of the virtual table interface.
783 */
fts5CloseMethod(sqlite3_vtab_cursor * pCursor)784 static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
785   if( pCursor ){
786     Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
787     Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
788     Fts5Cursor **pp;
789 
790     fts5FreeCursorComponents(pCsr);
791     /* Remove the cursor from the Fts5Global.pCsr list */
792     for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext);
793     *pp = pCsr->pNext;
794 
795     sqlite3_free(pCsr);
796   }
797   return SQLITE_OK;
798 }
799 
fts5SorterNext(Fts5Cursor * pCsr)800 static int fts5SorterNext(Fts5Cursor *pCsr){
801   Fts5Sorter *pSorter = pCsr->pSorter;
802   int rc;
803 
804   rc = sqlite3_step(pSorter->pStmt);
805   if( rc==SQLITE_DONE ){
806     rc = SQLITE_OK;
807     CsrFlagSet(pCsr, FTS5CSR_EOF|FTS5CSR_REQUIRE_CONTENT);
808   }else if( rc==SQLITE_ROW ){
809     const u8 *a;
810     const u8 *aBlob;
811     int nBlob;
812     int i;
813     int iOff = 0;
814     rc = SQLITE_OK;
815 
816     pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0);
817     nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
818     aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
819 
820     /* nBlob==0 in detail=none mode. */
821     if( nBlob>0 ){
822       for(i=0; i<(pSorter->nIdx-1); i++){
823         int iVal;
824         a += fts5GetVarint32(a, iVal);
825         iOff += iVal;
826         pSorter->aIdx[i] = iOff;
827       }
828       pSorter->aIdx[i] = &aBlob[nBlob] - a;
829       pSorter->aPoslist = a;
830     }
831 
832     fts5CsrNewrow(pCsr);
833   }
834 
835   return rc;
836 }
837 
838 
839 /*
840 ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
841 ** open on table pTab.
842 */
fts5TripCursors(Fts5FullTable * pTab)843 static void fts5TripCursors(Fts5FullTable *pTab){
844   Fts5Cursor *pCsr;
845   for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
846     if( pCsr->ePlan==FTS5_PLAN_MATCH
847      && pCsr->base.pVtab==(sqlite3_vtab*)pTab
848     ){
849       CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK);
850     }
851   }
852 }
853 
854 /*
855 ** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
856 ** argument, close and reopen all Fts5IndexIter iterators that the cursor
857 ** is using. Then attempt to move the cursor to a rowid equal to or laster
858 ** (in the cursors sort order - ASC or DESC) than the current rowid.
859 **
860 ** If the new rowid is not equal to the old, set output parameter *pbSkip
861 ** to 1 before returning. Otherwise, leave it unchanged.
862 **
863 ** Return SQLITE_OK if successful or if no reseek was required, or an
864 ** error code if an error occurred.
865 */
fts5CursorReseek(Fts5Cursor * pCsr,int * pbSkip)866 static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
867   int rc = SQLITE_OK;
868   assert( *pbSkip==0 );
869   if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){
870     Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
871     int bDesc = pCsr->bDesc;
872     i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
873 
874     rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc);
875     if( rc==SQLITE_OK &&  iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
876       *pbSkip = 1;
877     }
878 
879     CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK);
880     fts5CsrNewrow(pCsr);
881     if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
882       CsrFlagSet(pCsr, FTS5CSR_EOF);
883       *pbSkip = 1;
884     }
885   }
886   return rc;
887 }
888 
889 
890 /*
891 ** Advance the cursor to the next row in the table that matches the
892 ** search criteria.
893 **
894 ** Return SQLITE_OK if nothing goes wrong.  SQLITE_OK is returned
895 ** even if we reach end-of-file.  The fts5EofMethod() will be called
896 ** subsequently to determine whether or not an EOF was hit.
897 */
fts5NextMethod(sqlite3_vtab_cursor * pCursor)898 static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
899   Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
900   int rc;
901 
902   assert( (pCsr->ePlan<3)==
903           (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
904   );
905   assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
906 
907   if( pCsr->ePlan<3 ){
908     int bSkip = 0;
909     if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
910     rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
911     CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
912     fts5CsrNewrow(pCsr);
913   }else{
914     switch( pCsr->ePlan ){
915       case FTS5_PLAN_SPECIAL: {
916         CsrFlagSet(pCsr, FTS5CSR_EOF);
917         rc = SQLITE_OK;
918         break;
919       }
920 
921       case FTS5_PLAN_SORTED_MATCH: {
922         rc = fts5SorterNext(pCsr);
923         break;
924       }
925 
926       default: {
927         Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig;
928         pConfig->bLock++;
929         rc = sqlite3_step(pCsr->pStmt);
930         pConfig->bLock--;
931         if( rc!=SQLITE_ROW ){
932           CsrFlagSet(pCsr, FTS5CSR_EOF);
933           rc = sqlite3_reset(pCsr->pStmt);
934           if( rc!=SQLITE_OK ){
935             pCursor->pVtab->zErrMsg = sqlite3_mprintf(
936                 "%s", sqlite3_errmsg(pConfig->db)
937             );
938           }
939         }else{
940           rc = SQLITE_OK;
941         }
942         break;
943       }
944     }
945   }
946 
947   return rc;
948 }
949 
950 
fts5PrepareStatement(sqlite3_stmt ** ppStmt,Fts5Config * pConfig,const char * zFmt,...)951 static int fts5PrepareStatement(
952   sqlite3_stmt **ppStmt,
953   Fts5Config *pConfig,
954   const char *zFmt,
955   ...
956 ){
957   sqlite3_stmt *pRet = 0;
958   int rc;
959   char *zSql;
960   va_list ap;
961 
962   va_start(ap, zFmt);
963   zSql = sqlite3_vmprintf(zFmt, ap);
964   if( zSql==0 ){
965     rc = SQLITE_NOMEM;
966   }else{
967     rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
968                             SQLITE_PREPARE_PERSISTENT, &pRet, 0);
969     if( rc!=SQLITE_OK ){
970       *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
971     }
972     sqlite3_free(zSql);
973   }
974 
975   va_end(ap);
976   *ppStmt = pRet;
977   return rc;
978 }
979 
fts5CursorFirstSorted(Fts5FullTable * pTab,Fts5Cursor * pCsr,int bDesc)980 static int fts5CursorFirstSorted(
981   Fts5FullTable *pTab,
982   Fts5Cursor *pCsr,
983   int bDesc
984 ){
985   Fts5Config *pConfig = pTab->p.pConfig;
986   Fts5Sorter *pSorter;
987   int nPhrase;
988   sqlite3_int64 nByte;
989   int rc;
990   const char *zRank = pCsr->zRank;
991   const char *zRankArgs = pCsr->zRankArgs;
992 
993   nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
994   nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
995   pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte);
996   if( pSorter==0 ) return SQLITE_NOMEM;
997   memset(pSorter, 0, (size_t)nByte);
998   pSorter->nIdx = nPhrase;
999 
1000   /* TODO: It would be better to have some system for reusing statement
1001   ** handles here, rather than preparing a new one for each query. But that
1002   ** is not possible as SQLite reference counts the virtual table objects.
1003   ** And since the statement required here reads from this very virtual
1004   ** table, saving it creates a circular reference.
1005   **
1006   ** If SQLite a built-in statement cache, this wouldn't be a problem. */
1007   rc = fts5PrepareStatement(&pSorter->pStmt, pConfig,
1008       "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(\"%w\"%s%s) %s",
1009       pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
1010       (zRankArgs ? ", " : ""),
1011       (zRankArgs ? zRankArgs : ""),
1012       bDesc ? "DESC" : "ASC"
1013   );
1014 
1015   pCsr->pSorter = pSorter;
1016   if( rc==SQLITE_OK ){
1017     assert( pTab->pSortCsr==0 );
1018     pTab->pSortCsr = pCsr;
1019     rc = fts5SorterNext(pCsr);
1020     pTab->pSortCsr = 0;
1021   }
1022 
1023   if( rc!=SQLITE_OK ){
1024     sqlite3_finalize(pSorter->pStmt);
1025     sqlite3_free(pSorter);
1026     pCsr->pSorter = 0;
1027   }
1028 
1029   return rc;
1030 }
1031 
fts5CursorFirst(Fts5FullTable * pTab,Fts5Cursor * pCsr,int bDesc)1032 static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){
1033   int rc;
1034   Fts5Expr *pExpr = pCsr->pExpr;
1035   rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc);
1036   if( sqlite3Fts5ExprEof(pExpr) ){
1037     CsrFlagSet(pCsr, FTS5CSR_EOF);
1038   }
1039   fts5CsrNewrow(pCsr);
1040   return rc;
1041 }
1042 
1043 /*
1044 ** Process a "special" query. A special query is identified as one with a
1045 ** MATCH expression that begins with a '*' character. The remainder of
1046 ** the text passed to the MATCH operator are used as  the special query
1047 ** parameters.
1048 */
fts5SpecialMatch(Fts5FullTable * pTab,Fts5Cursor * pCsr,const char * zQuery)1049 static int fts5SpecialMatch(
1050   Fts5FullTable *pTab,
1051   Fts5Cursor *pCsr,
1052   const char *zQuery
1053 ){
1054   int rc = SQLITE_OK;             /* Return code */
1055   const char *z = zQuery;         /* Special query text */
1056   int n;                          /* Number of bytes in text at z */
1057 
1058   while( z[0]==' ' ) z++;
1059   for(n=0; z[n] && z[n]!=' '; n++);
1060 
1061   assert( pTab->p.base.zErrMsg==0 );
1062   pCsr->ePlan = FTS5_PLAN_SPECIAL;
1063 
1064   if( n==5 && 0==sqlite3_strnicmp("reads", z, n) ){
1065     pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->p.pIndex);
1066   }
1067   else if( n==2 && 0==sqlite3_strnicmp("id", z, n) ){
1068     pCsr->iSpecial = pCsr->iCsrId;
1069   }
1070   else{
1071     /* An unrecognized directive. Return an error message. */
1072     pTab->p.base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
1073     rc = SQLITE_ERROR;
1074   }
1075 
1076   return rc;
1077 }
1078 
1079 /*
1080 ** Search for an auxiliary function named zName that can be used with table
1081 ** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
1082 ** structure. Otherwise, if no such function exists, return NULL.
1083 */
fts5FindAuxiliary(Fts5FullTable * pTab,const char * zName)1084 static Fts5Auxiliary *fts5FindAuxiliary(Fts5FullTable *pTab, const char *zName){
1085   Fts5Auxiliary *pAux;
1086 
1087   for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){
1088     if( sqlite3_stricmp(zName, pAux->zFunc)==0 ) return pAux;
1089   }
1090 
1091   /* No function of the specified name was found. Return 0. */
1092   return 0;
1093 }
1094 
1095 
fts5FindRankFunction(Fts5Cursor * pCsr)1096 static int fts5FindRankFunction(Fts5Cursor *pCsr){
1097   Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1098   Fts5Config *pConfig = pTab->p.pConfig;
1099   int rc = SQLITE_OK;
1100   Fts5Auxiliary *pAux = 0;
1101   const char *zRank = pCsr->zRank;
1102   const char *zRankArgs = pCsr->zRankArgs;
1103 
1104   if( zRankArgs ){
1105     char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs);
1106     if( zSql ){
1107       sqlite3_stmt *pStmt = 0;
1108       rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
1109                               SQLITE_PREPARE_PERSISTENT, &pStmt, 0);
1110       sqlite3_free(zSql);
1111       assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
1112       if( rc==SQLITE_OK ){
1113         if( SQLITE_ROW==sqlite3_step(pStmt) ){
1114           sqlite3_int64 nByte;
1115           pCsr->nRankArg = sqlite3_column_count(pStmt);
1116           nByte = sizeof(sqlite3_value*)*pCsr->nRankArg;
1117           pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte);
1118           if( rc==SQLITE_OK ){
1119             int i;
1120             for(i=0; i<pCsr->nRankArg; i++){
1121               pCsr->apRankArg[i] = sqlite3_column_value(pStmt, i);
1122             }
1123           }
1124           pCsr->pRankArgStmt = pStmt;
1125         }else{
1126           rc = sqlite3_finalize(pStmt);
1127           assert( rc!=SQLITE_OK );
1128         }
1129       }
1130     }
1131   }
1132 
1133   if( rc==SQLITE_OK ){
1134     pAux = fts5FindAuxiliary(pTab, zRank);
1135     if( pAux==0 ){
1136       assert( pTab->p.base.zErrMsg==0 );
1137       pTab->p.base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
1138       rc = SQLITE_ERROR;
1139     }
1140   }
1141 
1142   pCsr->pRank = pAux;
1143   return rc;
1144 }
1145 
1146 
fts5CursorParseRank(Fts5Config * pConfig,Fts5Cursor * pCsr,sqlite3_value * pRank)1147 static int fts5CursorParseRank(
1148   Fts5Config *pConfig,
1149   Fts5Cursor *pCsr,
1150   sqlite3_value *pRank
1151 ){
1152   int rc = SQLITE_OK;
1153   if( pRank ){
1154     const char *z = (const char*)sqlite3_value_text(pRank);
1155     char *zRank = 0;
1156     char *zRankArgs = 0;
1157 
1158     if( z==0 ){
1159       if( sqlite3_value_type(pRank)==SQLITE_NULL ) rc = SQLITE_ERROR;
1160     }else{
1161       rc = sqlite3Fts5ConfigParseRank(z, &zRank, &zRankArgs);
1162     }
1163     if( rc==SQLITE_OK ){
1164       pCsr->zRank = zRank;
1165       pCsr->zRankArgs = zRankArgs;
1166       CsrFlagSet(pCsr, FTS5CSR_FREE_ZRANK);
1167     }else if( rc==SQLITE_ERROR ){
1168       pCsr->base.pVtab->zErrMsg = sqlite3_mprintf(
1169           "parse error in rank function: %s", z
1170       );
1171     }
1172   }else{
1173     if( pConfig->zRank ){
1174       pCsr->zRank = (char*)pConfig->zRank;
1175       pCsr->zRankArgs = (char*)pConfig->zRankArgs;
1176     }else{
1177       pCsr->zRank = (char*)FTS5_DEFAULT_RANK;
1178       pCsr->zRankArgs = 0;
1179     }
1180   }
1181   return rc;
1182 }
1183 
fts5GetRowidLimit(sqlite3_value * pVal,i64 iDefault)1184 static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
1185   if( pVal ){
1186     int eType = sqlite3_value_numeric_type(pVal);
1187     if( eType==SQLITE_INTEGER ){
1188       return sqlite3_value_int64(pVal);
1189     }
1190   }
1191   return iDefault;
1192 }
1193 
1194 /*
1195 ** This is the xFilter interface for the virtual table.  See
1196 ** the virtual table xFilter method documentation for additional
1197 ** information.
1198 **
1199 ** There are three possible query strategies:
1200 **
1201 **   1. Full-text search using a MATCH operator.
1202 **   2. A by-rowid lookup.
1203 **   3. A full-table scan.
1204 */
fts5FilterMethod(sqlite3_vtab_cursor * pCursor,int idxNum,const char * idxStr,int nVal,sqlite3_value ** apVal)1205 static int fts5FilterMethod(
1206   sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
1207   int idxNum,                     /* Strategy index */
1208   const char *idxStr,             /* Unused */
1209   int nVal,                       /* Number of elements in apVal */
1210   sqlite3_value **apVal           /* Arguments for the indexing scheme */
1211 ){
1212   Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
1213   Fts5Config *pConfig = pTab->p.pConfig;
1214   Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1215   int rc = SQLITE_OK;             /* Error code */
1216   int bDesc;                      /* True if ORDER BY [rank|rowid] DESC */
1217   int bOrderByRank;               /* True if ORDER BY rank */
1218   sqlite3_value *pRank = 0;       /* rank MATCH ? expression (or NULL) */
1219   sqlite3_value *pRowidEq = 0;    /* rowid = ? expression (or NULL) */
1220   sqlite3_value *pRowidLe = 0;    /* rowid <= ? expression (or NULL) */
1221   sqlite3_value *pRowidGe = 0;    /* rowid >= ? expression (or NULL) */
1222   int iCol;                       /* Column on LHS of MATCH operator */
1223   char **pzErrmsg = pConfig->pzErrmsg;
1224   int i;
1225   int iIdxStr = 0;
1226   Fts5Expr *pExpr = 0;
1227 
1228   if( pConfig->bLock ){
1229     pTab->p.base.zErrMsg = sqlite3_mprintf(
1230         "recursively defined fts5 content table"
1231     );
1232     return SQLITE_ERROR;
1233   }
1234 
1235   if( pCsr->ePlan ){
1236     fts5FreeCursorComponents(pCsr);
1237     memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
1238   }
1239 
1240   assert( pCsr->pStmt==0 );
1241   assert( pCsr->pExpr==0 );
1242   assert( pCsr->csrflags==0 );
1243   assert( pCsr->pRank==0 );
1244   assert( pCsr->zRank==0 );
1245   assert( pCsr->zRankArgs==0 );
1246   assert( pTab->pSortCsr==0 || nVal==0 );
1247 
1248   assert( pzErrmsg==0 || pzErrmsg==&pTab->p.base.zErrMsg );
1249   pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
1250 
1251   /* Decode the arguments passed through to this function. */
1252   for(i=0; i<nVal; i++){
1253     switch( idxStr[iIdxStr++] ){
1254       case 'r':
1255         pRank = apVal[i];
1256         break;
1257       case 'M': {
1258         const char *zText = (const char*)sqlite3_value_text(apVal[i]);
1259         if( zText==0 ) zText = "";
1260         iCol = 0;
1261         do{
1262           iCol = iCol*10 + (idxStr[iIdxStr]-'0');
1263           iIdxStr++;
1264         }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
1265 
1266         if( zText[0]=='*' ){
1267           /* The user has issued a query of the form "MATCH '*...'". This
1268           ** indicates that the MATCH expression is not a full text query,
1269           ** but a request for an internal parameter.  */
1270           rc = fts5SpecialMatch(pTab, pCsr, &zText[1]);
1271           goto filter_out;
1272         }else{
1273           char **pzErr = &pTab->p.base.zErrMsg;
1274           rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
1275           if( rc==SQLITE_OK ){
1276             rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
1277             pExpr = 0;
1278           }
1279           if( rc!=SQLITE_OK ) goto filter_out;
1280         }
1281 
1282         break;
1283       }
1284       case 'L':
1285       case 'G': {
1286         int bGlob = (idxStr[iIdxStr-1]=='G');
1287         const char *zText = (const char*)sqlite3_value_text(apVal[i]);
1288         iCol = 0;
1289         do{
1290           iCol = iCol*10 + (idxStr[iIdxStr]-'0');
1291           iIdxStr++;
1292         }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
1293         if( zText ){
1294           rc = sqlite3Fts5ExprPattern(pConfig, bGlob, iCol, zText, &pExpr);
1295         }
1296         if( rc==SQLITE_OK ){
1297           rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
1298           pExpr = 0;
1299         }
1300         if( rc!=SQLITE_OK ) goto filter_out;
1301         break;
1302       }
1303       case '=':
1304         pRowidEq = apVal[i];
1305         break;
1306       case '<':
1307         pRowidLe = apVal[i];
1308         break;
1309       default: assert( idxStr[iIdxStr-1]=='>' );
1310         pRowidGe = apVal[i];
1311         break;
1312     }
1313   }
1314   bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
1315   pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
1316 
1317   /* Set the cursor upper and lower rowid limits. Only some strategies
1318   ** actually use them. This is ok, as the xBestIndex() method leaves the
1319   ** sqlite3_index_constraint.omit flag clear for range constraints
1320   ** on the rowid field.  */
1321   if( pRowidEq ){
1322     pRowidLe = pRowidGe = pRowidEq;
1323   }
1324   if( bDesc ){
1325     pCsr->iFirstRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
1326     pCsr->iLastRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
1327   }else{
1328     pCsr->iLastRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
1329     pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
1330   }
1331 
1332   if( pTab->pSortCsr ){
1333     /* If pSortCsr is non-NULL, then this call is being made as part of
1334     ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
1335     ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
1336     ** return results to the user for this query. The current cursor
1337     ** (pCursor) is used to execute the query issued by function
1338     ** fts5CursorFirstSorted() above.  */
1339     assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 );
1340     assert( nVal==0 && bOrderByRank==0 && bDesc==0 );
1341     assert( pCsr->iLastRowid==LARGEST_INT64 );
1342     assert( pCsr->iFirstRowid==SMALLEST_INT64 );
1343     if( pTab->pSortCsr->bDesc ){
1344       pCsr->iLastRowid = pTab->pSortCsr->iFirstRowid;
1345       pCsr->iFirstRowid = pTab->pSortCsr->iLastRowid;
1346     }else{
1347       pCsr->iLastRowid = pTab->pSortCsr->iLastRowid;
1348       pCsr->iFirstRowid = pTab->pSortCsr->iFirstRowid;
1349     }
1350     pCsr->ePlan = FTS5_PLAN_SOURCE;
1351     pCsr->pExpr = pTab->pSortCsr->pExpr;
1352     rc = fts5CursorFirst(pTab, pCsr, bDesc);
1353   }else if( pCsr->pExpr ){
1354     rc = fts5CursorParseRank(pConfig, pCsr, pRank);
1355     if( rc==SQLITE_OK ){
1356       if( bOrderByRank ){
1357         pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
1358         rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
1359       }else{
1360         pCsr->ePlan = FTS5_PLAN_MATCH;
1361         rc = fts5CursorFirst(pTab, pCsr, bDesc);
1362       }
1363     }
1364   }else if( pConfig->zContent==0 ){
1365     *pConfig->pzErrmsg = sqlite3_mprintf(
1366         "%s: table does not support scanning", pConfig->zName
1367     );
1368     rc = SQLITE_ERROR;
1369   }else{
1370     /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
1371     ** by rowid (ePlan==FTS5_PLAN_ROWID).  */
1372     pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
1373     rc = sqlite3Fts5StorageStmt(
1374         pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg
1375     );
1376     if( rc==SQLITE_OK ){
1377       if( pRowidEq!=0 ){
1378         assert( pCsr->ePlan==FTS5_PLAN_ROWID );
1379         sqlite3_bind_value(pCsr->pStmt, 1, pRowidEq);
1380       }else{
1381         sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
1382         sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid);
1383       }
1384       rc = fts5NextMethod(pCursor);
1385     }
1386   }
1387 
1388  filter_out:
1389   sqlite3Fts5ExprFree(pExpr);
1390   pConfig->pzErrmsg = pzErrmsg;
1391   return rc;
1392 }
1393 
1394 /*
1395 ** This is the xEof method of the virtual table. SQLite calls this
1396 ** routine to find out if it has reached the end of a result set.
1397 */
fts5EofMethod(sqlite3_vtab_cursor * pCursor)1398 static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
1399   Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1400   return (CsrFlagTest(pCsr, FTS5CSR_EOF) ? 1 : 0);
1401 }
1402 
1403 /*
1404 ** Return the rowid that the cursor currently points to.
1405 */
fts5CursorRowid(Fts5Cursor * pCsr)1406 static i64 fts5CursorRowid(Fts5Cursor *pCsr){
1407   assert( pCsr->ePlan==FTS5_PLAN_MATCH
1408        || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
1409        || pCsr->ePlan==FTS5_PLAN_SOURCE
1410   );
1411   if( pCsr->pSorter ){
1412     return pCsr->pSorter->iRowid;
1413   }else{
1414     return sqlite3Fts5ExprRowid(pCsr->pExpr);
1415   }
1416 }
1417 
1418 /*
1419 ** This is the xRowid method. The SQLite core calls this routine to
1420 ** retrieve the rowid for the current row of the result set. fts5
1421 ** exposes %_content.rowid as the rowid for the virtual table. The
1422 ** rowid should be written to *pRowid.
1423 */
fts5RowidMethod(sqlite3_vtab_cursor * pCursor,sqlite_int64 * pRowid)1424 static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
1425   Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1426   int ePlan = pCsr->ePlan;
1427 
1428   assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
1429   switch( ePlan ){
1430     case FTS5_PLAN_SPECIAL:
1431       *pRowid = 0;
1432       break;
1433 
1434     case FTS5_PLAN_SOURCE:
1435     case FTS5_PLAN_MATCH:
1436     case FTS5_PLAN_SORTED_MATCH:
1437       *pRowid = fts5CursorRowid(pCsr);
1438       break;
1439 
1440     default:
1441       *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
1442       break;
1443   }
1444 
1445   return SQLITE_OK;
1446 }
1447 
1448 /*
1449 ** If the cursor requires seeking (bSeekRequired flag is set), seek it.
1450 ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
1451 **
1452 ** If argument bErrormsg is true and an error occurs, an error message may
1453 ** be left in sqlite3_vtab.zErrMsg.
1454 */
fts5SeekCursor(Fts5Cursor * pCsr,int bErrormsg)1455 static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
1456   int rc = SQLITE_OK;
1457 
1458   /* If the cursor does not yet have a statement handle, obtain one now. */
1459   if( pCsr->pStmt==0 ){
1460     Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1461     int eStmt = fts5StmtType(pCsr);
1462     rc = sqlite3Fts5StorageStmt(
1463         pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->p.base.zErrMsg:0)
1464     );
1465     assert( rc!=SQLITE_OK || pTab->p.base.zErrMsg==0 );
1466     assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
1467   }
1468 
1469   if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
1470     Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1471     assert( pCsr->pExpr );
1472     sqlite3_reset(pCsr->pStmt);
1473     sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
1474     pTab->pConfig->bLock++;
1475     rc = sqlite3_step(pCsr->pStmt);
1476     pTab->pConfig->bLock--;
1477     if( rc==SQLITE_ROW ){
1478       rc = SQLITE_OK;
1479       CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
1480     }else{
1481       rc = sqlite3_reset(pCsr->pStmt);
1482       if( rc==SQLITE_OK ){
1483         rc = FTS5_CORRUPT;
1484       }else if( pTab->pConfig->pzErrmsg ){
1485         *pTab->pConfig->pzErrmsg = sqlite3_mprintf(
1486             "%s", sqlite3_errmsg(pTab->pConfig->db)
1487         );
1488       }
1489     }
1490   }
1491   return rc;
1492 }
1493 
fts5SetVtabError(Fts5FullTable * p,const char * zFormat,...)1494 static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
1495   va_list ap;                     /* ... printf arguments */
1496   va_start(ap, zFormat);
1497   assert( p->p.base.zErrMsg==0 );
1498   p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
1499   va_end(ap);
1500 }
1501 
1502 /*
1503 ** This function is called to handle an FTS INSERT command. In other words,
1504 ** an INSERT statement of the form:
1505 **
1506 **     INSERT INTO fts(fts) VALUES($pCmd)
1507 **     INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
1508 **
1509 ** Argument pVal is the value assigned to column "fts" by the INSERT
1510 ** statement. This function returns SQLITE_OK if successful, or an SQLite
1511 ** error code if an error occurs.
1512 **
1513 ** The commands implemented by this function are documented in the "Special
1514 ** INSERT Directives" section of the documentation. It should be updated if
1515 ** more commands are added to this function.
1516 */
fts5SpecialInsert(Fts5FullTable * pTab,const char * zCmd,sqlite3_value * pVal)1517 static int fts5SpecialInsert(
1518   Fts5FullTable *pTab,            /* Fts5 table object */
1519   const char *zCmd,               /* Text inserted into table-name column */
1520   sqlite3_value *pVal             /* Value inserted into rank column */
1521 ){
1522   Fts5Config *pConfig = pTab->p.pConfig;
1523   int rc = SQLITE_OK;
1524   int bError = 0;
1525 
1526   if( 0==sqlite3_stricmp("delete-all", zCmd) ){
1527     if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
1528       fts5SetVtabError(pTab,
1529           "'delete-all' may only be used with a "
1530           "contentless or external content fts5 table"
1531       );
1532       rc = SQLITE_ERROR;
1533     }else{
1534       rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
1535     }
1536   }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
1537     if( pConfig->eContent==FTS5_CONTENT_NONE ){
1538       fts5SetVtabError(pTab,
1539           "'rebuild' may not be used with a contentless fts5 table"
1540       );
1541       rc = SQLITE_ERROR;
1542     }else{
1543       rc = sqlite3Fts5StorageRebuild(pTab->pStorage);
1544     }
1545   }else if( 0==sqlite3_stricmp("optimize", zCmd) ){
1546     rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
1547   }else if( 0==sqlite3_stricmp("merge", zCmd) ){
1548     int nMerge = sqlite3_value_int(pVal);
1549     rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
1550   }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
1551     int iArg = sqlite3_value_int(pVal);
1552     rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, iArg);
1553 #ifdef SQLITE_DEBUG
1554   }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
1555     pConfig->bPrefixIndex = sqlite3_value_int(pVal);
1556 #endif
1557   }else{
1558     rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
1559     if( rc==SQLITE_OK ){
1560       rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError);
1561     }
1562     if( rc==SQLITE_OK ){
1563       if( bError ){
1564         rc = SQLITE_ERROR;
1565       }else{
1566         rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0);
1567       }
1568     }
1569   }
1570   return rc;
1571 }
1572 
fts5SpecialDelete(Fts5FullTable * pTab,sqlite3_value ** apVal)1573 static int fts5SpecialDelete(
1574   Fts5FullTable *pTab,
1575   sqlite3_value **apVal
1576 ){
1577   int rc = SQLITE_OK;
1578   int eType1 = sqlite3_value_type(apVal[1]);
1579   if( eType1==SQLITE_INTEGER ){
1580     sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
1581     rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
1582   }
1583   return rc;
1584 }
1585 
fts5StorageInsert(int * pRc,Fts5FullTable * pTab,sqlite3_value ** apVal,i64 * piRowid)1586 static void fts5StorageInsert(
1587   int *pRc,
1588   Fts5FullTable *pTab,
1589   sqlite3_value **apVal,
1590   i64 *piRowid
1591 ){
1592   int rc = *pRc;
1593   if( rc==SQLITE_OK ){
1594     rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
1595   }
1596   if( rc==SQLITE_OK ){
1597     rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
1598   }
1599   *pRc = rc;
1600 }
1601 
1602 /*
1603 ** This function is the implementation of the xUpdate callback used by
1604 ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
1605 ** inserted, updated or deleted.
1606 **
1607 ** A delete specifies a single argument - the rowid of the row to remove.
1608 **
1609 ** Update and insert operations pass:
1610 **
1611 **   1. The "old" rowid, or NULL.
1612 **   2. The "new" rowid.
1613 **   3. Values for each of the nCol matchable columns.
1614 **   4. Values for the two hidden columns (<tablename> and "rank").
1615 */
fts5UpdateMethod(sqlite3_vtab * pVtab,int nArg,sqlite3_value ** apVal,sqlite_int64 * pRowid)1616 static int fts5UpdateMethod(
1617   sqlite3_vtab *pVtab,            /* Virtual table handle */
1618   int nArg,                       /* Size of argument array */
1619   sqlite3_value **apVal,          /* Array of arguments */
1620   sqlite_int64 *pRowid            /* OUT: The affected (or effected) rowid */
1621 ){
1622   Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
1623   Fts5Config *pConfig = pTab->p.pConfig;
1624   int eType0;                     /* value_type() of apVal[0] */
1625   int rc = SQLITE_OK;             /* Return code */
1626 
1627   /* A transaction must be open when this is called. */
1628   assert( pTab->ts.eState==1 );
1629 
1630   assert( pVtab->zErrMsg==0 );
1631   assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
1632   assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER
1633        || sqlite3_value_type(apVal[0])==SQLITE_NULL
1634   );
1635   assert( pTab->p.pConfig->pzErrmsg==0 );
1636   pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
1637 
1638   /* Put any active cursors into REQUIRE_SEEK state. */
1639   fts5TripCursors(pTab);
1640 
1641   eType0 = sqlite3_value_type(apVal[0]);
1642   if( eType0==SQLITE_NULL
1643    && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
1644   ){
1645     /* A "special" INSERT op. These are handled separately. */
1646     const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]);
1647     if( pConfig->eContent!=FTS5_CONTENT_NORMAL
1648       && 0==sqlite3_stricmp("delete", z)
1649     ){
1650       rc = fts5SpecialDelete(pTab, apVal);
1651     }else{
1652       rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
1653     }
1654   }else{
1655     /* A regular INSERT, UPDATE or DELETE statement. The trick here is that
1656     ** any conflict on the rowid value must be detected before any
1657     ** modifications are made to the database file. There are 4 cases:
1658     **
1659     **   1) DELETE
1660     **   2) UPDATE (rowid not modified)
1661     **   3) UPDATE (rowid modified)
1662     **   4) INSERT
1663     **
1664     ** Cases 3 and 4 may violate the rowid constraint.
1665     */
1666     int eConflict = SQLITE_ABORT;
1667     if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
1668       eConflict = sqlite3_vtab_on_conflict(pConfig->db);
1669     }
1670 
1671     assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
1672     assert( nArg!=1 || eType0==SQLITE_INTEGER );
1673 
1674     /* Filter out attempts to run UPDATE or DELETE on contentless tables.
1675     ** This is not suported.  */
1676     if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
1677       pTab->p.base.zErrMsg = sqlite3_mprintf(
1678           "cannot %s contentless fts5 table: %s",
1679           (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
1680       );
1681       rc = SQLITE_ERROR;
1682     }
1683 
1684     /* DELETE */
1685     else if( nArg==1 ){
1686       i64 iDel = sqlite3_value_int64(apVal[0]);  /* Rowid to delete */
1687       rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
1688     }
1689 
1690     /* INSERT or UPDATE */
1691     else{
1692       int eType1 = sqlite3_value_numeric_type(apVal[1]);
1693 
1694       if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
1695         rc = SQLITE_MISMATCH;
1696       }
1697 
1698       else if( eType0!=SQLITE_INTEGER ){
1699         /* If this is a REPLACE, first remove the current entry (if any) */
1700         if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
1701           i64 iNew = sqlite3_value_int64(apVal[1]);  /* Rowid to delete */
1702           rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
1703         }
1704         fts5StorageInsert(&rc, pTab, apVal, pRowid);
1705       }
1706 
1707       /* UPDATE */
1708       else{
1709         i64 iOld = sqlite3_value_int64(apVal[0]);  /* Old rowid */
1710         i64 iNew = sqlite3_value_int64(apVal[1]);  /* New rowid */
1711         if( eType1==SQLITE_INTEGER && iOld!=iNew ){
1712           if( eConflict==SQLITE_REPLACE ){
1713             rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1714             if( rc==SQLITE_OK ){
1715               rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
1716             }
1717             fts5StorageInsert(&rc, pTab, apVal, pRowid);
1718           }else{
1719             rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
1720             if( rc==SQLITE_OK ){
1721               rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1722             }
1723             if( rc==SQLITE_OK ){
1724               rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
1725             }
1726           }
1727         }else{
1728           rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1729           fts5StorageInsert(&rc, pTab, apVal, pRowid);
1730         }
1731       }
1732     }
1733   }
1734 
1735   pTab->p.pConfig->pzErrmsg = 0;
1736   return rc;
1737 }
1738 
1739 /*
1740 ** Implementation of xSync() method.
1741 */
fts5SyncMethod(sqlite3_vtab * pVtab)1742 static int fts5SyncMethod(sqlite3_vtab *pVtab){
1743   int rc;
1744   Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
1745   fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
1746   pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
1747   fts5TripCursors(pTab);
1748   rc = sqlite3Fts5StorageSync(pTab->pStorage);
1749   pTab->p.pConfig->pzErrmsg = 0;
1750   return rc;
1751 }
1752 
1753 /*
1754 ** Implementation of xBegin() method.
1755 */
fts5BeginMethod(sqlite3_vtab * pVtab)1756 static int fts5BeginMethod(sqlite3_vtab *pVtab){
1757   fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
1758   fts5NewTransaction((Fts5FullTable*)pVtab);
1759   return SQLITE_OK;
1760 }
1761 
1762 /*
1763 ** Implementation of xCommit() method. This is a no-op. The contents of
1764 ** the pending-terms hash-table have already been flushed into the database
1765 ** by fts5SyncMethod().
1766 */
fts5CommitMethod(sqlite3_vtab * pVtab)1767 static int fts5CommitMethod(sqlite3_vtab *pVtab){
1768   UNUSED_PARAM(pVtab);  /* Call below is a no-op for NDEBUG builds */
1769   fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_COMMIT, 0);
1770   return SQLITE_OK;
1771 }
1772 
1773 /*
1774 ** Implementation of xRollback(). Discard the contents of the pending-terms
1775 ** hash-table. Any changes made to the database are reverted by SQLite.
1776 */
fts5RollbackMethod(sqlite3_vtab * pVtab)1777 static int fts5RollbackMethod(sqlite3_vtab *pVtab){
1778   int rc;
1779   Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
1780   fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
1781   rc = sqlite3Fts5StorageRollback(pTab->pStorage);
1782   return rc;
1783 }
1784 
1785 static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*);
1786 
fts5ApiUserData(Fts5Context * pCtx)1787 static void *fts5ApiUserData(Fts5Context *pCtx){
1788   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1789   return pCsr->pAux->pUserData;
1790 }
1791 
fts5ApiColumnCount(Fts5Context * pCtx)1792 static int fts5ApiColumnCount(Fts5Context *pCtx){
1793   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1794   return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol;
1795 }
1796 
fts5ApiColumnTotalSize(Fts5Context * pCtx,int iCol,sqlite3_int64 * pnToken)1797 static int fts5ApiColumnTotalSize(
1798   Fts5Context *pCtx,
1799   int iCol,
1800   sqlite3_int64 *pnToken
1801 ){
1802   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1803   Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1804   return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken);
1805 }
1806 
fts5ApiRowCount(Fts5Context * pCtx,i64 * pnRow)1807 static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
1808   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1809   Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1810   return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
1811 }
1812 
fts5ApiTokenize(Fts5Context * pCtx,const char * pText,int nText,void * pUserData,int (* xToken)(void *,int,const char *,int,int,int))1813 static int fts5ApiTokenize(
1814   Fts5Context *pCtx,
1815   const char *pText, int nText,
1816   void *pUserData,
1817   int (*xToken)(void*, int, const char*, int, int, int)
1818 ){
1819   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1820   Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1821   return sqlite3Fts5Tokenize(
1822       pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
1823   );
1824 }
1825 
fts5ApiPhraseCount(Fts5Context * pCtx)1826 static int fts5ApiPhraseCount(Fts5Context *pCtx){
1827   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1828   return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
1829 }
1830 
fts5ApiPhraseSize(Fts5Context * pCtx,int iPhrase)1831 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
1832   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1833   return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
1834 }
1835 
fts5ApiColumnText(Fts5Context * pCtx,int iCol,const char ** pz,int * pn)1836 static int fts5ApiColumnText(
1837   Fts5Context *pCtx,
1838   int iCol,
1839   const char **pz,
1840   int *pn
1841 ){
1842   int rc = SQLITE_OK;
1843   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1844   if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
1845    || pCsr->ePlan==FTS5_PLAN_SPECIAL
1846   ){
1847     *pz = 0;
1848     *pn = 0;
1849   }else{
1850     rc = fts5SeekCursor(pCsr, 0);
1851     if( rc==SQLITE_OK ){
1852       *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
1853       *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
1854     }
1855   }
1856   return rc;
1857 }
1858 
fts5CsrPoslist(Fts5Cursor * pCsr,int iPhrase,const u8 ** pa,int * pn)1859 static int fts5CsrPoslist(
1860   Fts5Cursor *pCsr,
1861   int iPhrase,
1862   const u8 **pa,
1863   int *pn
1864 ){
1865   Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
1866   int rc = SQLITE_OK;
1867   int bLive = (pCsr->pSorter==0);
1868 
1869   if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
1870 
1871     if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
1872       Fts5PoslistPopulator *aPopulator;
1873       int i;
1874       aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
1875       if( aPopulator==0 ) rc = SQLITE_NOMEM;
1876       for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
1877         int n; const char *z;
1878         rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
1879         if( rc==SQLITE_OK ){
1880           rc = sqlite3Fts5ExprPopulatePoslists(
1881               pConfig, pCsr->pExpr, aPopulator, i, z, n
1882           );
1883         }
1884       }
1885       sqlite3_free(aPopulator);
1886 
1887       if( pCsr->pSorter ){
1888         sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
1889       }
1890     }
1891     CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
1892   }
1893 
1894   if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
1895     Fts5Sorter *pSorter = pCsr->pSorter;
1896     int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
1897     *pn = pSorter->aIdx[iPhrase] - i1;
1898     *pa = &pSorter->aPoslist[i1];
1899   }else{
1900     *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
1901   }
1902 
1903   return rc;
1904 }
1905 
1906 /*
1907 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
1908 ** correctly for the current view. Return SQLITE_OK if successful, or an
1909 ** SQLite error code otherwise.
1910 */
fts5CacheInstArray(Fts5Cursor * pCsr)1911 static int fts5CacheInstArray(Fts5Cursor *pCsr){
1912   int rc = SQLITE_OK;
1913   Fts5PoslistReader *aIter;       /* One iterator for each phrase */
1914   int nIter;                      /* Number of iterators/phrases */
1915   int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol;
1916 
1917   nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
1918   if( pCsr->aInstIter==0 ){
1919     sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nIter;
1920     pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
1921   }
1922   aIter = pCsr->aInstIter;
1923 
1924   if( aIter ){
1925     int nInst = 0;                /* Number instances seen so far */
1926     int i;
1927 
1928     /* Initialize all iterators */
1929     for(i=0; i<nIter && rc==SQLITE_OK; i++){
1930       const u8 *a;
1931       int n;
1932       rc = fts5CsrPoslist(pCsr, i, &a, &n);
1933       if( rc==SQLITE_OK ){
1934         sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
1935       }
1936     }
1937 
1938     if( rc==SQLITE_OK ){
1939       while( 1 ){
1940         int *aInst;
1941         int iBest = -1;
1942         for(i=0; i<nIter; i++){
1943           if( (aIter[i].bEof==0)
1944               && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
1945             ){
1946             iBest = i;
1947           }
1948         }
1949         if( iBest<0 ) break;
1950 
1951         nInst++;
1952         if( nInst>=pCsr->nInstAlloc ){
1953           int nNewSize = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
1954           aInst = (int*)sqlite3_realloc64(
1955               pCsr->aInst, nNewSize*sizeof(int)*3
1956               );
1957           if( aInst ){
1958             pCsr->aInst = aInst;
1959             pCsr->nInstAlloc = nNewSize;
1960           }else{
1961             nInst--;
1962             rc = SQLITE_NOMEM;
1963             break;
1964           }
1965         }
1966 
1967         aInst = &pCsr->aInst[3 * (nInst-1)];
1968         aInst[0] = iBest;
1969         aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
1970         aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
1971         if( aInst[1]<0 || aInst[1]>=nCol ){
1972           rc = FTS5_CORRUPT;
1973           break;
1974         }
1975         sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
1976       }
1977     }
1978 
1979     pCsr->nInstCount = nInst;
1980     CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
1981   }
1982   return rc;
1983 }
1984 
fts5ApiInstCount(Fts5Context * pCtx,int * pnInst)1985 static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
1986   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1987   int rc = SQLITE_OK;
1988   if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
1989    || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
1990     *pnInst = pCsr->nInstCount;
1991   }
1992   return rc;
1993 }
1994 
fts5ApiInst(Fts5Context * pCtx,int iIdx,int * piPhrase,int * piCol,int * piOff)1995 static int fts5ApiInst(
1996   Fts5Context *pCtx,
1997   int iIdx,
1998   int *piPhrase,
1999   int *piCol,
2000   int *piOff
2001 ){
2002   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2003   int rc = SQLITE_OK;
2004   if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
2005    || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
2006   ){
2007     if( iIdx<0 || iIdx>=pCsr->nInstCount ){
2008       rc = SQLITE_RANGE;
2009 #if 0
2010     }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
2011       *piPhrase = pCsr->aInst[iIdx*3];
2012       *piCol = pCsr->aInst[iIdx*3 + 2];
2013       *piOff = -1;
2014 #endif
2015     }else{
2016       *piPhrase = pCsr->aInst[iIdx*3];
2017       *piCol = pCsr->aInst[iIdx*3 + 1];
2018       *piOff = pCsr->aInst[iIdx*3 + 2];
2019     }
2020   }
2021   return rc;
2022 }
2023 
fts5ApiRowid(Fts5Context * pCtx)2024 static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
2025   return fts5CursorRowid((Fts5Cursor*)pCtx);
2026 }
2027 
fts5ColumnSizeCb(void * pContext,int tflags,const char * pUnused,int nUnused,int iUnused1,int iUnused2)2028 static int fts5ColumnSizeCb(
2029   void *pContext,                 /* Pointer to int */
2030   int tflags,
2031   const char *pUnused,            /* Buffer containing token */
2032   int nUnused,                    /* Size of token in bytes */
2033   int iUnused1,                   /* Start offset of token */
2034   int iUnused2                    /* End offset of token */
2035 ){
2036   int *pCnt = (int*)pContext;
2037   UNUSED_PARAM2(pUnused, nUnused);
2038   UNUSED_PARAM2(iUnused1, iUnused2);
2039   if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
2040     (*pCnt)++;
2041   }
2042   return SQLITE_OK;
2043 }
2044 
fts5ApiColumnSize(Fts5Context * pCtx,int iCol,int * pnToken)2045 static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
2046   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2047   Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
2048   Fts5Config *pConfig = pTab->p.pConfig;
2049   int rc = SQLITE_OK;
2050 
2051   if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
2052     if( pConfig->bColumnsize ){
2053       i64 iRowid = fts5CursorRowid(pCsr);
2054       rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
2055     }else if( pConfig->zContent==0 ){
2056       int i;
2057       for(i=0; i<pConfig->nCol; i++){
2058         if( pConfig->abUnindexed[i]==0 ){
2059           pCsr->aColumnSize[i] = -1;
2060         }
2061       }
2062     }else{
2063       int i;
2064       for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
2065         if( pConfig->abUnindexed[i]==0 ){
2066           const char *z; int n;
2067           void *p = (void*)(&pCsr->aColumnSize[i]);
2068           pCsr->aColumnSize[i] = 0;
2069           rc = fts5ApiColumnText(pCtx, i, &z, &n);
2070           if( rc==SQLITE_OK ){
2071             rc = sqlite3Fts5Tokenize(
2072                 pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
2073             );
2074           }
2075         }
2076       }
2077     }
2078     CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
2079   }
2080   if( iCol<0 ){
2081     int i;
2082     *pnToken = 0;
2083     for(i=0; i<pConfig->nCol; i++){
2084       *pnToken += pCsr->aColumnSize[i];
2085     }
2086   }else if( iCol<pConfig->nCol ){
2087     *pnToken = pCsr->aColumnSize[iCol];
2088   }else{
2089     *pnToken = 0;
2090     rc = SQLITE_RANGE;
2091   }
2092   return rc;
2093 }
2094 
2095 /*
2096 ** Implementation of the xSetAuxdata() method.
2097 */
fts5ApiSetAuxdata(Fts5Context * pCtx,void * pPtr,void (* xDelete)(void *))2098 static int fts5ApiSetAuxdata(
2099   Fts5Context *pCtx,              /* Fts5 context */
2100   void *pPtr,                     /* Pointer to save as auxdata */
2101   void(*xDelete)(void*)           /* Destructor for pPtr (or NULL) */
2102 ){
2103   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2104   Fts5Auxdata *pData;
2105 
2106   /* Search through the cursors list of Fts5Auxdata objects for one that
2107   ** corresponds to the currently executing auxiliary function.  */
2108   for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
2109     if( pData->pAux==pCsr->pAux ) break;
2110   }
2111 
2112   if( pData ){
2113     if( pData->xDelete ){
2114       pData->xDelete(pData->pPtr);
2115     }
2116   }else{
2117     int rc = SQLITE_OK;
2118     pData = (Fts5Auxdata*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Auxdata));
2119     if( pData==0 ){
2120       if( xDelete ) xDelete(pPtr);
2121       return rc;
2122     }
2123     pData->pAux = pCsr->pAux;
2124     pData->pNext = pCsr->pAuxdata;
2125     pCsr->pAuxdata = pData;
2126   }
2127 
2128   pData->xDelete = xDelete;
2129   pData->pPtr = pPtr;
2130   return SQLITE_OK;
2131 }
2132 
fts5ApiGetAuxdata(Fts5Context * pCtx,int bClear)2133 static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
2134   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2135   Fts5Auxdata *pData;
2136   void *pRet = 0;
2137 
2138   for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
2139     if( pData->pAux==pCsr->pAux ) break;
2140   }
2141 
2142   if( pData ){
2143     pRet = pData->pPtr;
2144     if( bClear ){
2145       pData->pPtr = 0;
2146       pData->xDelete = 0;
2147     }
2148   }
2149 
2150   return pRet;
2151 }
2152 
fts5ApiPhraseNext(Fts5Context * pUnused,Fts5PhraseIter * pIter,int * piCol,int * piOff)2153 static void fts5ApiPhraseNext(
2154   Fts5Context *pUnused,
2155   Fts5PhraseIter *pIter,
2156   int *piCol, int *piOff
2157 ){
2158   UNUSED_PARAM(pUnused);
2159   if( pIter->a>=pIter->b ){
2160     *piCol = -1;
2161     *piOff = -1;
2162   }else{
2163     int iVal;
2164     pIter->a += fts5GetVarint32(pIter->a, iVal);
2165     if( iVal==1 ){
2166       pIter->a += fts5GetVarint32(pIter->a, iVal);
2167       *piCol = iVal;
2168       *piOff = 0;
2169       pIter->a += fts5GetVarint32(pIter->a, iVal);
2170     }
2171     *piOff += (iVal-2);
2172   }
2173 }
2174 
fts5ApiPhraseFirst(Fts5Context * pCtx,int iPhrase,Fts5PhraseIter * pIter,int * piCol,int * piOff)2175 static int fts5ApiPhraseFirst(
2176   Fts5Context *pCtx,
2177   int iPhrase,
2178   Fts5PhraseIter *pIter,
2179   int *piCol, int *piOff
2180 ){
2181   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2182   int n;
2183   int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
2184   if( rc==SQLITE_OK ){
2185     assert( pIter->a || n==0 );
2186     pIter->b = (pIter->a ? &pIter->a[n] : 0);
2187     *piCol = 0;
2188     *piOff = 0;
2189     fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
2190   }
2191   return rc;
2192 }
2193 
fts5ApiPhraseNextColumn(Fts5Context * pCtx,Fts5PhraseIter * pIter,int * piCol)2194 static void fts5ApiPhraseNextColumn(
2195   Fts5Context *pCtx,
2196   Fts5PhraseIter *pIter,
2197   int *piCol
2198 ){
2199   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2200   Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
2201 
2202   if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
2203     if( pIter->a>=pIter->b ){
2204       *piCol = -1;
2205     }else{
2206       int iIncr;
2207       pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
2208       *piCol += (iIncr-2);
2209     }
2210   }else{
2211     while( 1 ){
2212       int dummy;
2213       if( pIter->a>=pIter->b ){
2214         *piCol = -1;
2215         return;
2216       }
2217       if( pIter->a[0]==0x01 ) break;
2218       pIter->a += fts5GetVarint32(pIter->a, dummy);
2219     }
2220     pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
2221   }
2222 }
2223 
fts5ApiPhraseFirstColumn(Fts5Context * pCtx,int iPhrase,Fts5PhraseIter * pIter,int * piCol)2224 static int fts5ApiPhraseFirstColumn(
2225   Fts5Context *pCtx,
2226   int iPhrase,
2227   Fts5PhraseIter *pIter,
2228   int *piCol
2229 ){
2230   int rc = SQLITE_OK;
2231   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2232   Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
2233 
2234   if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
2235     Fts5Sorter *pSorter = pCsr->pSorter;
2236     int n;
2237     if( pSorter ){
2238       int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
2239       n = pSorter->aIdx[iPhrase] - i1;
2240       pIter->a = &pSorter->aPoslist[i1];
2241     }else{
2242       rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
2243     }
2244     if( rc==SQLITE_OK ){
2245       assert( pIter->a || n==0 );
2246       pIter->b = (pIter->a ? &pIter->a[n] : 0);
2247       *piCol = 0;
2248       fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
2249     }
2250   }else{
2251     int n;
2252     rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
2253     if( rc==SQLITE_OK ){
2254       assert( pIter->a || n==0 );
2255       pIter->b = (pIter->a ? &pIter->a[n] : 0);
2256       if( n<=0 ){
2257         *piCol = -1;
2258       }else if( pIter->a[0]==0x01 ){
2259         pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
2260       }else{
2261         *piCol = 0;
2262       }
2263     }
2264   }
2265 
2266   return rc;
2267 }
2268 
2269 
2270 static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
2271     int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
2272 );
2273 
2274 static const Fts5ExtensionApi sFts5Api = {
2275   2,                            /* iVersion */
2276   fts5ApiUserData,
2277   fts5ApiColumnCount,
2278   fts5ApiRowCount,
2279   fts5ApiColumnTotalSize,
2280   fts5ApiTokenize,
2281   fts5ApiPhraseCount,
2282   fts5ApiPhraseSize,
2283   fts5ApiInstCount,
2284   fts5ApiInst,
2285   fts5ApiRowid,
2286   fts5ApiColumnText,
2287   fts5ApiColumnSize,
2288   fts5ApiQueryPhrase,
2289   fts5ApiSetAuxdata,
2290   fts5ApiGetAuxdata,
2291   fts5ApiPhraseFirst,
2292   fts5ApiPhraseNext,
2293   fts5ApiPhraseFirstColumn,
2294   fts5ApiPhraseNextColumn,
2295 };
2296 
2297 /*
2298 ** Implementation of API function xQueryPhrase().
2299 */
fts5ApiQueryPhrase(Fts5Context * pCtx,int iPhrase,void * pUserData,int (* xCallback)(const Fts5ExtensionApi *,Fts5Context *,void *))2300 static int fts5ApiQueryPhrase(
2301   Fts5Context *pCtx,
2302   int iPhrase,
2303   void *pUserData,
2304   int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
2305 ){
2306   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2307   Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
2308   int rc;
2309   Fts5Cursor *pNew = 0;
2310 
2311   rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
2312   if( rc==SQLITE_OK ){
2313     pNew->ePlan = FTS5_PLAN_MATCH;
2314     pNew->iFirstRowid = SMALLEST_INT64;
2315     pNew->iLastRowid = LARGEST_INT64;
2316     pNew->base.pVtab = (sqlite3_vtab*)pTab;
2317     rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr);
2318   }
2319 
2320   if( rc==SQLITE_OK ){
2321     for(rc = fts5CursorFirst(pTab, pNew, 0);
2322         rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0;
2323         rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew)
2324     ){
2325       rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData);
2326       if( rc!=SQLITE_OK ){
2327         if( rc==SQLITE_DONE ) rc = SQLITE_OK;
2328         break;
2329       }
2330     }
2331   }
2332 
2333   fts5CloseMethod((sqlite3_vtab_cursor*)pNew);
2334   return rc;
2335 }
2336 
fts5ApiInvoke(Fts5Auxiliary * pAux,Fts5Cursor * pCsr,sqlite3_context * context,int argc,sqlite3_value ** argv)2337 static void fts5ApiInvoke(
2338   Fts5Auxiliary *pAux,
2339   Fts5Cursor *pCsr,
2340   sqlite3_context *context,
2341   int argc,
2342   sqlite3_value **argv
2343 ){
2344   assert( pCsr->pAux==0 );
2345   pCsr->pAux = pAux;
2346   pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
2347   pCsr->pAux = 0;
2348 }
2349 
fts5CursorFromCsrid(Fts5Global * pGlobal,i64 iCsrId)2350 static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
2351   Fts5Cursor *pCsr;
2352   for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
2353     if( pCsr->iCsrId==iCsrId ) break;
2354   }
2355   return pCsr;
2356 }
2357 
fts5ApiCallback(sqlite3_context * context,int argc,sqlite3_value ** argv)2358 static void fts5ApiCallback(
2359   sqlite3_context *context,
2360   int argc,
2361   sqlite3_value **argv
2362 ){
2363 
2364   Fts5Auxiliary *pAux;
2365   Fts5Cursor *pCsr;
2366   i64 iCsrId;
2367 
2368   assert( argc>=1 );
2369   pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
2370   iCsrId = sqlite3_value_int64(argv[0]);
2371 
2372   pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
2373   if( pCsr==0 || pCsr->ePlan==0 ){
2374     char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
2375     sqlite3_result_error(context, zErr, -1);
2376     sqlite3_free(zErr);
2377   }else{
2378     fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
2379   }
2380 }
2381 
2382 
2383 /*
2384 ** Given cursor id iId, return a pointer to the corresponding Fts5Table
2385 ** object. Or NULL If the cursor id does not exist.
2386 */
sqlite3Fts5TableFromCsrid(Fts5Global * pGlobal,i64 iCsrId)2387 Fts5Table *sqlite3Fts5TableFromCsrid(
2388   Fts5Global *pGlobal,            /* FTS5 global context for db handle */
2389   i64 iCsrId                      /* Id of cursor to find */
2390 ){
2391   Fts5Cursor *pCsr;
2392   pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
2393   if( pCsr ){
2394     return (Fts5Table*)pCsr->base.pVtab;
2395   }
2396   return 0;
2397 }
2398 
2399 /*
2400 ** Return a "position-list blob" corresponding to the current position of
2401 ** cursor pCsr via sqlite3_result_blob(). A position-list blob contains
2402 ** the current position-list for each phrase in the query associated with
2403 ** cursor pCsr.
2404 **
2405 ** A position-list blob begins with (nPhrase-1) varints, where nPhrase is
2406 ** the number of phrases in the query. Following the varints are the
2407 ** concatenated position lists for each phrase, in order.
2408 **
2409 ** The first varint (if it exists) contains the size of the position list
2410 ** for phrase 0. The second (same disclaimer) contains the size of position
2411 ** list 1. And so on. There is no size field for the final position list,
2412 ** as it can be derived from the total size of the blob.
2413 */
fts5PoslistBlob(sqlite3_context * pCtx,Fts5Cursor * pCsr)2414 static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
2415   int i;
2416   int rc = SQLITE_OK;
2417   int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
2418   Fts5Buffer val;
2419 
2420   memset(&val, 0, sizeof(Fts5Buffer));
2421   switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){
2422     case FTS5_DETAIL_FULL:
2423 
2424       /* Append the varints */
2425       for(i=0; i<(nPhrase-1); i++){
2426         const u8 *dummy;
2427         int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
2428         sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
2429       }
2430 
2431       /* Append the position lists */
2432       for(i=0; i<nPhrase; i++){
2433         const u8 *pPoslist;
2434         int nPoslist;
2435         nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
2436         sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
2437       }
2438       break;
2439 
2440     case FTS5_DETAIL_COLUMNS:
2441 
2442       /* Append the varints */
2443       for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){
2444         const u8 *dummy;
2445         int nByte;
2446         rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte);
2447         sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
2448       }
2449 
2450       /* Append the position lists */
2451       for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
2452         const u8 *pPoslist;
2453         int nPoslist;
2454         rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist);
2455         sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
2456       }
2457       break;
2458 
2459     default:
2460       break;
2461   }
2462 
2463   sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
2464   return rc;
2465 }
2466 
2467 /*
2468 ** This is the xColumn method, called by SQLite to request a value from
2469 ** the row that the supplied cursor currently points to.
2470 */
fts5ColumnMethod(sqlite3_vtab_cursor * pCursor,sqlite3_context * pCtx,int iCol)2471 static int fts5ColumnMethod(
2472   sqlite3_vtab_cursor *pCursor,   /* Cursor to retrieve value from */
2473   sqlite3_context *pCtx,          /* Context for sqlite3_result_xxx() calls */
2474   int iCol                        /* Index of column to read value from */
2475 ){
2476   Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
2477   Fts5Config *pConfig = pTab->p.pConfig;
2478   Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
2479   int rc = SQLITE_OK;
2480 
2481   assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
2482 
2483   if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){
2484     if( iCol==pConfig->nCol ){
2485       sqlite3_result_int64(pCtx, pCsr->iSpecial);
2486     }
2487   }else
2488 
2489   if( iCol==pConfig->nCol ){
2490     /* User is requesting the value of the special column with the same name
2491     ** as the table. Return the cursor integer id number. This value is only
2492     ** useful in that it may be passed as the first argument to an FTS5
2493     ** auxiliary function.  */
2494     sqlite3_result_int64(pCtx, pCsr->iCsrId);
2495   }else if( iCol==pConfig->nCol+1 ){
2496 
2497     /* The value of the "rank" column. */
2498     if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
2499       fts5PoslistBlob(pCtx, pCsr);
2500     }else if(
2501         pCsr->ePlan==FTS5_PLAN_MATCH
2502      || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
2503     ){
2504       if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
2505         fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
2506       }
2507     }
2508   }else if( !fts5IsContentless(pTab) ){
2509     pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
2510     rc = fts5SeekCursor(pCsr, 1);
2511     if( rc==SQLITE_OK ){
2512       sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
2513     }
2514     pConfig->pzErrmsg = 0;
2515   }
2516   return rc;
2517 }
2518 
2519 
2520 /*
2521 ** This routine implements the xFindFunction method for the FTS3
2522 ** virtual table.
2523 */
fts5FindFunctionMethod(sqlite3_vtab * pVtab,int nUnused,const char * zName,void (** pxFunc)(sqlite3_context *,int,sqlite3_value **),void ** ppArg)2524 static int fts5FindFunctionMethod(
2525   sqlite3_vtab *pVtab,            /* Virtual table handle */
2526   int nUnused,                    /* Number of SQL function arguments */
2527   const char *zName,              /* Name of SQL function */
2528   void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
2529   void **ppArg                    /* OUT: User data for *pxFunc */
2530 ){
2531   Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2532   Fts5Auxiliary *pAux;
2533 
2534   UNUSED_PARAM(nUnused);
2535   pAux = fts5FindAuxiliary(pTab, zName);
2536   if( pAux ){
2537     *pxFunc = fts5ApiCallback;
2538     *ppArg = (void*)pAux;
2539     return 1;
2540   }
2541 
2542   /* No function of the specified name was found. Return 0. */
2543   return 0;
2544 }
2545 
2546 /*
2547 ** Implementation of FTS5 xRename method. Rename an fts5 table.
2548 */
fts5RenameMethod(sqlite3_vtab * pVtab,const char * zName)2549 static int fts5RenameMethod(
2550   sqlite3_vtab *pVtab,            /* Virtual table handle */
2551   const char *zName               /* New name of table */
2552 ){
2553   Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2554   return sqlite3Fts5StorageRename(pTab->pStorage, zName);
2555 }
2556 
sqlite3Fts5FlushToDisk(Fts5Table * pTab)2557 int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
2558   fts5TripCursors((Fts5FullTable*)pTab);
2559   return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage);
2560 }
2561 
2562 /*
2563 ** The xSavepoint() method.
2564 **
2565 ** Flush the contents of the pending-terms table to disk.
2566 */
fts5SavepointMethod(sqlite3_vtab * pVtab,int iSavepoint)2567 static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
2568   UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
2569   fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint);
2570   return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
2571 }
2572 
2573 /*
2574 ** The xRelease() method.
2575 **
2576 ** This is a no-op.
2577 */
fts5ReleaseMethod(sqlite3_vtab * pVtab,int iSavepoint)2578 static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
2579   UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
2580   fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint);
2581   return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
2582 }
2583 
2584 /*
2585 ** The xRollbackTo() method.
2586 **
2587 ** Discard the contents of the pending terms table.
2588 */
fts5RollbackToMethod(sqlite3_vtab * pVtab,int iSavepoint)2589 static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
2590   Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2591   UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
2592   fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
2593   fts5TripCursors(pTab);
2594   return sqlite3Fts5StorageRollback(pTab->pStorage);
2595 }
2596 
2597 /*
2598 ** Register a new auxiliary function with global context pGlobal.
2599 */
fts5CreateAux(fts5_api * pApi,const char * zName,void * pUserData,fts5_extension_function xFunc,void (* xDestroy)(void *))2600 static int fts5CreateAux(
2601   fts5_api *pApi,                 /* Global context (one per db handle) */
2602   const char *zName,              /* Name of new function */
2603   void *pUserData,                /* User data for aux. function */
2604   fts5_extension_function xFunc,  /* Aux. function implementation */
2605   void(*xDestroy)(void*)          /* Destructor for pUserData */
2606 ){
2607   Fts5Global *pGlobal = (Fts5Global*)pApi;
2608   int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
2609   if( rc==SQLITE_OK ){
2610     Fts5Auxiliary *pAux;
2611     sqlite3_int64 nName;            /* Size of zName in bytes, including \0 */
2612     sqlite3_int64 nByte;            /* Bytes of space to allocate */
2613 
2614     nName = strlen(zName) + 1;
2615     nByte = sizeof(Fts5Auxiliary) + nName;
2616     pAux = (Fts5Auxiliary*)sqlite3_malloc64(nByte);
2617     if( pAux ){
2618       memset(pAux, 0, (size_t)nByte);
2619       pAux->zFunc = (char*)&pAux[1];
2620       memcpy(pAux->zFunc, zName, nName);
2621       pAux->pGlobal = pGlobal;
2622       pAux->pUserData = pUserData;
2623       pAux->xFunc = xFunc;
2624       pAux->xDestroy = xDestroy;
2625       pAux->pNext = pGlobal->pAux;
2626       pGlobal->pAux = pAux;
2627     }else{
2628       rc = SQLITE_NOMEM;
2629     }
2630   }
2631 
2632   return rc;
2633 }
2634 
2635 /*
2636 ** Register a new tokenizer. This is the implementation of the
2637 ** fts5_api.xCreateTokenizer() method.
2638 */
fts5CreateTokenizer(fts5_api * pApi,const char * zName,void * pUserData,fts5_tokenizer * pTokenizer,void (* xDestroy)(void *))2639 static int fts5CreateTokenizer(
2640   fts5_api *pApi,                 /* Global context (one per db handle) */
2641   const char *zName,              /* Name of new function */
2642   void *pUserData,                /* User data for aux. function */
2643   fts5_tokenizer *pTokenizer,     /* Tokenizer implementation */
2644   void(*xDestroy)(void*)          /* Destructor for pUserData */
2645 ){
2646   Fts5Global *pGlobal = (Fts5Global*)pApi;
2647   Fts5TokenizerModule *pNew;
2648   sqlite3_int64 nName;            /* Size of zName and its \0 terminator */
2649   sqlite3_int64 nByte;            /* Bytes of space to allocate */
2650   int rc = SQLITE_OK;
2651 
2652   nName = strlen(zName) + 1;
2653   nByte = sizeof(Fts5TokenizerModule) + nName;
2654   pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte);
2655   if( pNew ){
2656     memset(pNew, 0, (size_t)nByte);
2657     pNew->zName = (char*)&pNew[1];
2658     memcpy(pNew->zName, zName, nName);
2659     pNew->pUserData = pUserData;
2660     pNew->x = *pTokenizer;
2661     pNew->xDestroy = xDestroy;
2662     pNew->pNext = pGlobal->pTok;
2663     pGlobal->pTok = pNew;
2664     if( pNew->pNext==0 ){
2665       pGlobal->pDfltTok = pNew;
2666     }
2667   }else{
2668     rc = SQLITE_NOMEM;
2669   }
2670 
2671   return rc;
2672 }
2673 
fts5LocateTokenizer(Fts5Global * pGlobal,const char * zName)2674 static Fts5TokenizerModule *fts5LocateTokenizer(
2675   Fts5Global *pGlobal,
2676   const char *zName
2677 ){
2678   Fts5TokenizerModule *pMod = 0;
2679 
2680   if( zName==0 ){
2681     pMod = pGlobal->pDfltTok;
2682   }else{
2683     for(pMod=pGlobal->pTok; pMod; pMod=pMod->pNext){
2684       if( sqlite3_stricmp(zName, pMod->zName)==0 ) break;
2685     }
2686   }
2687 
2688   return pMod;
2689 }
2690 
2691 /*
2692 ** Find a tokenizer. This is the implementation of the
2693 ** fts5_api.xFindTokenizer() method.
2694 */
fts5FindTokenizer(fts5_api * pApi,const char * zName,void ** ppUserData,fts5_tokenizer * pTokenizer)2695 static int fts5FindTokenizer(
2696   fts5_api *pApi,                 /* Global context (one per db handle) */
2697   const char *zName,              /* Name of new function */
2698   void **ppUserData,
2699   fts5_tokenizer *pTokenizer      /* Populate this object */
2700 ){
2701   int rc = SQLITE_OK;
2702   Fts5TokenizerModule *pMod;
2703 
2704   pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
2705   if( pMod ){
2706     *pTokenizer = pMod->x;
2707     *ppUserData = pMod->pUserData;
2708   }else{
2709     memset(pTokenizer, 0, sizeof(fts5_tokenizer));
2710     rc = SQLITE_ERROR;
2711   }
2712 
2713   return rc;
2714 }
2715 
sqlite3Fts5GetTokenizer(Fts5Global * pGlobal,const char ** azArg,int nArg,Fts5Config * pConfig,char ** pzErr)2716 int sqlite3Fts5GetTokenizer(
2717   Fts5Global *pGlobal,
2718   const char **azArg,
2719   int nArg,
2720   Fts5Config *pConfig,
2721   char **pzErr
2722 ){
2723   Fts5TokenizerModule *pMod;
2724   int rc = SQLITE_OK;
2725 
2726   pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
2727   if( pMod==0 ){
2728     assert( nArg>0 );
2729     rc = SQLITE_ERROR;
2730     *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
2731   }else{
2732     rc = pMod->x.xCreate(
2733         pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
2734     );
2735     pConfig->pTokApi = &pMod->x;
2736     if( rc!=SQLITE_OK ){
2737       if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor");
2738     }else{
2739       pConfig->ePattern = sqlite3Fts5TokenizerPattern(
2740           pMod->x.xCreate, pConfig->pTok
2741       );
2742     }
2743   }
2744 
2745   if( rc!=SQLITE_OK ){
2746     pConfig->pTokApi = 0;
2747     pConfig->pTok = 0;
2748   }
2749 
2750   return rc;
2751 }
2752 
fts5ModuleDestroy(void * pCtx)2753 static void fts5ModuleDestroy(void *pCtx){
2754   Fts5TokenizerModule *pTok, *pNextTok;
2755   Fts5Auxiliary *pAux, *pNextAux;
2756   Fts5Global *pGlobal = (Fts5Global*)pCtx;
2757 
2758   for(pAux=pGlobal->pAux; pAux; pAux=pNextAux){
2759     pNextAux = pAux->pNext;
2760     if( pAux->xDestroy ) pAux->xDestroy(pAux->pUserData);
2761     sqlite3_free(pAux);
2762   }
2763 
2764   for(pTok=pGlobal->pTok; pTok; pTok=pNextTok){
2765     pNextTok = pTok->pNext;
2766     if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData);
2767     sqlite3_free(pTok);
2768   }
2769 
2770   sqlite3_free(pGlobal);
2771 }
2772 
fts5Fts5Func(sqlite3_context * pCtx,int nArg,sqlite3_value ** apArg)2773 static void fts5Fts5Func(
2774   sqlite3_context *pCtx,          /* Function call context */
2775   int nArg,                       /* Number of args */
2776   sqlite3_value **apArg           /* Function arguments */
2777 ){
2778   Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
2779   fts5_api **ppApi;
2780   UNUSED_PARAM(nArg);
2781   assert( nArg==1 );
2782   ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr");
2783   if( ppApi ) *ppApi = &pGlobal->api;
2784 }
2785 
2786 /*
2787 ** Implementation of fts5_source_id() function.
2788 */
fts5SourceIdFunc(sqlite3_context * pCtx,int nArg,sqlite3_value ** apUnused)2789 static void fts5SourceIdFunc(
2790   sqlite3_context *pCtx,          /* Function call context */
2791   int nArg,                       /* Number of args */
2792   sqlite3_value **apUnused        /* Function arguments */
2793 ){
2794   assert( nArg==0 );
2795   UNUSED_PARAM2(nArg, apUnused);
2796   sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
2797 }
2798 
2799 /*
2800 ** Return true if zName is the extension on one of the shadow tables used
2801 ** by this module.
2802 */
fts5ShadowName(const char * zName)2803 static int fts5ShadowName(const char *zName){
2804   static const char *azName[] = {
2805     "config", "content", "data", "docsize", "idx"
2806   };
2807   unsigned int i;
2808   for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
2809     if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
2810   }
2811   return 0;
2812 }
2813 
fts5Init(sqlite3 * db)2814 static int fts5Init(sqlite3 *db){
2815   static const sqlite3_module fts5Mod = {
2816     /* iVersion      */ 3,
2817     /* xCreate       */ fts5CreateMethod,
2818     /* xConnect      */ fts5ConnectMethod,
2819     /* xBestIndex    */ fts5BestIndexMethod,
2820     /* xDisconnect   */ fts5DisconnectMethod,
2821     /* xDestroy      */ fts5DestroyMethod,
2822     /* xOpen         */ fts5OpenMethod,
2823     /* xClose        */ fts5CloseMethod,
2824     /* xFilter       */ fts5FilterMethod,
2825     /* xNext         */ fts5NextMethod,
2826     /* xEof          */ fts5EofMethod,
2827     /* xColumn       */ fts5ColumnMethod,
2828     /* xRowid        */ fts5RowidMethod,
2829     /* xUpdate       */ fts5UpdateMethod,
2830     /* xBegin        */ fts5BeginMethod,
2831     /* xSync         */ fts5SyncMethod,
2832     /* xCommit       */ fts5CommitMethod,
2833     /* xRollback     */ fts5RollbackMethod,
2834     /* xFindFunction */ fts5FindFunctionMethod,
2835     /* xRename       */ fts5RenameMethod,
2836     /* xSavepoint    */ fts5SavepointMethod,
2837     /* xRelease      */ fts5ReleaseMethod,
2838     /* xRollbackTo   */ fts5RollbackToMethod,
2839     /* xShadowName   */ fts5ShadowName
2840   };
2841 
2842   int rc;
2843   Fts5Global *pGlobal = 0;
2844 
2845   pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
2846   if( pGlobal==0 ){
2847     rc = SQLITE_NOMEM;
2848   }else{
2849     void *p = (void*)pGlobal;
2850     memset(pGlobal, 0, sizeof(Fts5Global));
2851     pGlobal->db = db;
2852     pGlobal->api.iVersion = 2;
2853     pGlobal->api.xCreateFunction = fts5CreateAux;
2854     pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
2855     pGlobal->api.xFindTokenizer = fts5FindTokenizer;
2856     rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
2857     if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
2858     if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
2859     if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
2860     if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
2861     if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
2862     if( rc==SQLITE_OK ){
2863       rc = sqlite3_create_function(
2864           db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
2865       );
2866     }
2867     if( rc==SQLITE_OK ){
2868       rc = sqlite3_create_function(
2869           db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
2870       );
2871     }
2872   }
2873 
2874   /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
2875   ** fts5_test_mi.c is compiled and linked into the executable. And call
2876   ** its entry point to enable the matchinfo() demo.  */
2877 #ifdef SQLITE_FTS5_ENABLE_TEST_MI
2878   if( rc==SQLITE_OK ){
2879     extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
2880     rc = sqlite3Fts5TestRegisterMatchinfo(db);
2881   }
2882 #endif
2883 
2884   return rc;
2885 }
2886 
2887 /*
2888 ** The following functions are used to register the module with SQLite. If
2889 ** this module is being built as part of the SQLite core (SQLITE_CORE is
2890 ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
2891 **
2892 ** Or, if this module is being built as a loadable extension,
2893 ** sqlite3Fts5Init() is omitted and the two standard entry points
2894 ** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
2895 */
2896 #ifndef SQLITE_CORE
2897 #ifdef _WIN32
2898 __declspec(dllexport)
2899 #endif
sqlite3_fts_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)2900 int sqlite3_fts_init(
2901   sqlite3 *db,
2902   char **pzErrMsg,
2903   const sqlite3_api_routines *pApi
2904 ){
2905   SQLITE_EXTENSION_INIT2(pApi);
2906   (void)pzErrMsg;  /* Unused parameter */
2907   return fts5Init(db);
2908 }
2909 
2910 #ifdef _WIN32
2911 __declspec(dllexport)
2912 #endif
sqlite3_fts5_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)2913 int sqlite3_fts5_init(
2914   sqlite3 *db,
2915   char **pzErrMsg,
2916   const sqlite3_api_routines *pApi
2917 ){
2918   SQLITE_EXTENSION_INIT2(pApi);
2919   (void)pzErrMsg;  /* Unused parameter */
2920   return fts5Init(db);
2921 }
2922 #else
sqlite3Fts5Init(sqlite3 * db)2923 int sqlite3Fts5Init(sqlite3 *db){
2924   return fts5Init(db);
2925 }
2926 #endif
2927