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