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