skip uneccesary sqlcipher_free calls
[sqlcipher.git] / ext / fts5 / fts5_main.c
blob7c818ce747ada571df91752d747117c02f4d9e32
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.
11 ******************************************************************************
13 ** This is an SQLite module implementing full-text search.
17 #include "fts5Int.h"
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.
25 #ifdef SQLITE_DEBUG
26 int sqlite3_fts5_may_be_corrupt = 1;
27 #endif
30 typedef struct Fts5Auxdata Fts5Auxdata;
31 typedef struct Fts5Auxiliary Fts5Auxiliary;
32 typedef struct Fts5Cursor Fts5Cursor;
33 typedef struct Fts5FullTable Fts5FullTable;
34 typedef struct Fts5Sorter Fts5Sorter;
35 typedef struct Fts5TokenizerModule Fts5TokenizerModule;
38 ** NOTES ON TRANSACTIONS:
40 ** SQLite invokes the following virtual table methods as transactions are
41 ** opened and closed by the user:
43 ** xBegin(): Start of a new transaction.
44 ** xSync(): Initial part of two-phase commit.
45 ** xCommit(): Final part of two-phase commit.
46 ** xRollback(): Rollback the transaction.
48 ** Anything that is required as part of a commit that may fail is performed
49 ** in the xSync() callback. Current versions of SQLite ignore any errors
50 ** returned by xCommit().
52 ** And as sub-transactions are opened/closed:
54 ** xSavepoint(int S): Open savepoint S.
55 ** xRelease(int S): Commit and close savepoint S.
56 ** xRollbackTo(int S): Rollback to start of savepoint S.
58 ** During a write-transaction the fts5_index.c module may cache some data
59 ** in-memory. It is flushed to disk whenever xSync(), xRelease() or
60 ** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
61 ** is called.
63 ** Additionally, if SQLITE_DEBUG is defined, an instance of the following
64 ** structure is used to record the current transaction state. This information
65 ** is not required, but it is used in the assert() statements executed by
66 ** function fts5CheckTransactionState() (see below).
68 struct Fts5TransactionState {
69 int eState; /* 0==closed, 1==open, 2==synced */
70 int iSavepoint; /* Number of open savepoints (0 -> none) */
74 ** A single object of this type is allocated when the FTS5 module is
75 ** registered with a database handle. It is used to store pointers to
76 ** all registered FTS5 extensions - tokenizers and auxiliary functions.
78 struct Fts5Global {
79 fts5_api api; /* User visible part of object (see fts5.h) */
80 sqlite3 *db; /* Associated database connection */
81 i64 iNextId; /* Used to allocate unique cursor ids */
82 Fts5Auxiliary *pAux; /* First in list of all aux. functions */
83 Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
84 Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
85 Fts5Cursor *pCsr; /* First in list of all open cursors */
89 ** Each auxiliary function registered with the FTS5 module is represented
90 ** by an object of the following type. All such objects are stored as part
91 ** of the Fts5Global.pAux list.
93 struct Fts5Auxiliary {
94 Fts5Global *pGlobal; /* Global context for this function */
95 char *zFunc; /* Function name (nul-terminated) */
96 void *pUserData; /* User-data pointer */
97 fts5_extension_function xFunc; /* Callback function */
98 void (*xDestroy)(void*); /* Destructor function */
99 Fts5Auxiliary *pNext; /* Next registered auxiliary function */
103 ** Each tokenizer module registered with the FTS5 module is represented
104 ** by an object of the following type. All such objects are stored as part
105 ** of the Fts5Global.pTok list.
107 struct Fts5TokenizerModule {
108 char *zName; /* Name of tokenizer */
109 void *pUserData; /* User pointer passed to xCreate() */
110 fts5_tokenizer x; /* Tokenizer functions */
111 void (*xDestroy)(void*); /* Destructor function */
112 Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
115 struct Fts5FullTable {
116 Fts5Table p; /* Public class members from fts5Int.h */
117 Fts5Storage *pStorage; /* Document store */
118 Fts5Global *pGlobal; /* Global (connection wide) data */
119 Fts5Cursor *pSortCsr; /* Sort data from this cursor */
120 int iSavepoint; /* Successful xSavepoint()+1 */
122 #ifdef SQLITE_DEBUG
123 struct Fts5TransactionState ts;
124 #endif
127 struct Fts5MatchPhrase {
128 Fts5Buffer *pPoslist; /* Pointer to current poslist */
129 int nTerm; /* Size of phrase in terms */
133 ** pStmt:
134 ** SELECT rowid, <fts> FROM <fts> ORDER BY +rank;
136 ** aIdx[]:
137 ** There is one entry in the aIdx[] array for each phrase in the query,
138 ** the value of which is the offset within aPoslist[] following the last
139 ** byte of the position list for the corresponding phrase.
141 struct Fts5Sorter {
142 sqlite3_stmt *pStmt;
143 i64 iRowid; /* Current rowid */
144 const u8 *aPoslist; /* Position lists for current row */
145 int nIdx; /* Number of entries in aIdx[] */
146 int aIdx[1]; /* Offsets into aPoslist for current row */
151 ** Virtual-table cursor object.
153 ** iSpecial:
154 ** If this is a 'special' query (refer to function fts5SpecialMatch()),
155 ** then this variable contains the result of the query.
157 ** iFirstRowid, iLastRowid:
158 ** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
159 ** cursor iterates in ascending order of rowids, iFirstRowid is the lower
160 ** limit of rowids to return, and iLastRowid the upper. In other words, the
161 ** WHERE clause in the user's query might have been:
163 ** <tbl> MATCH <expr> AND rowid BETWEEN $iFirstRowid AND $iLastRowid
165 ** If the cursor iterates in descending order of rowid, iFirstRowid
166 ** is the upper limit (i.e. the "first" rowid visited) and iLastRowid
167 ** the lower.
169 struct Fts5Cursor {
170 sqlite3_vtab_cursor base; /* Base class used by SQLite core */
171 Fts5Cursor *pNext; /* Next cursor in Fts5Cursor.pCsr list */
172 int *aColumnSize; /* Values for xColumnSize() */
173 i64 iCsrId; /* Cursor id */
175 /* Zero from this point onwards on cursor reset */
176 int ePlan; /* FTS5_PLAN_XXX value */
177 int bDesc; /* True for "ORDER BY rowid DESC" queries */
178 i64 iFirstRowid; /* Return no rowids earlier than this */
179 i64 iLastRowid; /* Return no rowids later than this */
180 sqlite3_stmt *pStmt; /* Statement used to read %_content */
181 Fts5Expr *pExpr; /* Expression for MATCH queries */
182 Fts5Sorter *pSorter; /* Sorter for "ORDER BY rank" queries */
183 int csrflags; /* Mask of cursor flags (see below) */
184 i64 iSpecial; /* Result of special query */
186 /* "rank" function. Populated on demand from vtab.xColumn(). */
187 char *zRank; /* Custom rank function */
188 char *zRankArgs; /* Custom rank function args */
189 Fts5Auxiliary *pRank; /* Rank callback (or NULL) */
190 int nRankArg; /* Number of trailing arguments for rank() */
191 sqlite3_value **apRankArg; /* Array of trailing arguments */
192 sqlite3_stmt *pRankArgStmt; /* Origin of objects in apRankArg[] */
194 /* Auxiliary data storage */
195 Fts5Auxiliary *pAux; /* Currently executing extension function */
196 Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
198 /* Cache used by auxiliary functions xInst() and xInstCount() */
199 Fts5PoslistReader *aInstIter; /* One for each phrase */
200 int nInstAlloc; /* Size of aInst[] array (entries / 3) */
201 int nInstCount; /* Number of phrase instances */
202 int *aInst; /* 3 integers per phrase instance */
206 ** Bits that make up the "idxNum" parameter passed indirectly by
207 ** xBestIndex() to xFilter().
209 #define FTS5_BI_MATCH 0x0001 /* <tbl> MATCH ? */
210 #define FTS5_BI_RANK 0x0002 /* rank MATCH ? */
211 #define FTS5_BI_ROWID_EQ 0x0004 /* rowid == ? */
212 #define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */
213 #define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */
215 #define FTS5_BI_ORDER_RANK 0x0020
216 #define FTS5_BI_ORDER_ROWID 0x0040
217 #define FTS5_BI_ORDER_DESC 0x0080
220 ** Values for Fts5Cursor.csrflags
222 #define FTS5CSR_EOF 0x01
223 #define FTS5CSR_REQUIRE_CONTENT 0x02
224 #define FTS5CSR_REQUIRE_DOCSIZE 0x04
225 #define FTS5CSR_REQUIRE_INST 0x08
226 #define FTS5CSR_FREE_ZRANK 0x10
227 #define FTS5CSR_REQUIRE_RESEEK 0x20
228 #define FTS5CSR_REQUIRE_POSLIST 0x40
230 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
231 #define BitFlagTest(x,y) (((x) & (y))!=0)
235 ** Macros to Set(), Clear() and Test() cursor flags.
237 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
238 #define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag))
239 #define CsrFlagTest(pCsr, flag) ((pCsr)->csrflags & (flag))
241 struct Fts5Auxdata {
242 Fts5Auxiliary *pAux; /* Extension to which this belongs */
243 void *pPtr; /* Pointer value */
244 void(*xDelete)(void*); /* Destructor */
245 Fts5Auxdata *pNext; /* Next object in linked list */
248 #ifdef SQLITE_DEBUG
249 #define FTS5_BEGIN 1
250 #define FTS5_SYNC 2
251 #define FTS5_COMMIT 3
252 #define FTS5_ROLLBACK 4
253 #define FTS5_SAVEPOINT 5
254 #define FTS5_RELEASE 6
255 #define FTS5_ROLLBACKTO 7
256 static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
257 switch( op ){
258 case FTS5_BEGIN:
259 assert( p->ts.eState==0 );
260 p->ts.eState = 1;
261 p->ts.iSavepoint = -1;
262 break;
264 case FTS5_SYNC:
265 assert( p->ts.eState==1 || p->ts.eState==2 );
266 p->ts.eState = 2;
267 break;
269 case FTS5_COMMIT:
270 assert( p->ts.eState==2 );
271 p->ts.eState = 0;
272 break;
274 case FTS5_ROLLBACK:
275 assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 );
276 p->ts.eState = 0;
277 break;
279 case FTS5_SAVEPOINT:
280 assert( p->ts.eState>=1 );
281 assert( iSavepoint>=0 );
282 assert( iSavepoint>=p->ts.iSavepoint );
283 p->ts.iSavepoint = iSavepoint;
284 break;
286 case FTS5_RELEASE:
287 assert( p->ts.eState>=1 );
288 assert( iSavepoint>=0 );
289 assert( iSavepoint<=p->ts.iSavepoint );
290 p->ts.iSavepoint = iSavepoint-1;
291 break;
293 case FTS5_ROLLBACKTO:
294 assert( p->ts.eState>=1 );
295 assert( iSavepoint>=-1 );
296 /* The following assert() can fail if another vtab strikes an error
297 ** within an xSavepoint() call then SQLite calls xRollbackTo() - without
298 ** having called xSavepoint() on this vtab. */
299 /* assert( iSavepoint<=p->ts.iSavepoint ); */
300 p->ts.iSavepoint = iSavepoint;
301 break;
304 #else
305 # define fts5CheckTransactionState(x,y,z)
306 #endif
309 ** Return true if pTab is a contentless table.
311 static int fts5IsContentless(Fts5FullTable *pTab){
312 return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
316 ** Delete a virtual table handle allocated by fts5InitVtab().
318 static void fts5FreeVtab(Fts5FullTable *pTab){
319 if( pTab ){
320 sqlite3Fts5IndexClose(pTab->p.pIndex);
321 sqlite3Fts5StorageClose(pTab->pStorage);
322 sqlite3Fts5ConfigFree(pTab->p.pConfig);
323 sqlite3_free(pTab);
328 ** The xDisconnect() virtual table method.
330 static int fts5DisconnectMethod(sqlite3_vtab *pVtab){
331 fts5FreeVtab((Fts5FullTable*)pVtab);
332 return SQLITE_OK;
336 ** The xDestroy() virtual table method.
338 static int fts5DestroyMethod(sqlite3_vtab *pVtab){
339 Fts5Table *pTab = (Fts5Table*)pVtab;
340 int rc = sqlite3Fts5DropAll(pTab->pConfig);
341 if( rc==SQLITE_OK ){
342 fts5FreeVtab((Fts5FullTable*)pVtab);
344 return rc;
348 ** This function is the implementation of both the xConnect and xCreate
349 ** methods of the FTS3 virtual table.
351 ** The argv[] array contains the following:
353 ** argv[0] -> module name ("fts5")
354 ** argv[1] -> database name
355 ** argv[2] -> table name
356 ** argv[...] -> "column name" and other module argument fields.
358 static int fts5InitVtab(
359 int bCreate, /* True for xCreate, false for xConnect */
360 sqlite3 *db, /* The SQLite database connection */
361 void *pAux, /* Hash table containing tokenizers */
362 int argc, /* Number of elements in argv array */
363 const char * const *argv, /* xCreate/xConnect argument array */
364 sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
365 char **pzErr /* Write any error message here */
367 Fts5Global *pGlobal = (Fts5Global*)pAux;
368 const char **azConfig = (const char**)argv;
369 int rc = SQLITE_OK; /* Return code */
370 Fts5Config *pConfig = 0; /* Results of parsing argc/argv */
371 Fts5FullTable *pTab = 0; /* New virtual table object */
373 /* Allocate the new vtab object and parse the configuration */
374 pTab = (Fts5FullTable*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5FullTable));
375 if( rc==SQLITE_OK ){
376 rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
377 assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
379 if( rc==SQLITE_OK ){
380 pTab->p.pConfig = pConfig;
381 pTab->pGlobal = pGlobal;
384 /* Open the index sub-system */
385 if( rc==SQLITE_OK ){
386 rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->p.pIndex, pzErr);
389 /* Open the storage sub-system */
390 if( rc==SQLITE_OK ){
391 rc = sqlite3Fts5StorageOpen(
392 pConfig, pTab->p.pIndex, bCreate, &pTab->pStorage, pzErr
396 /* Call sqlite3_declare_vtab() */
397 if( rc==SQLITE_OK ){
398 rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
401 /* Load the initial configuration */
402 if( rc==SQLITE_OK ){
403 assert( pConfig->pzErrmsg==0 );
404 pConfig->pzErrmsg = pzErr;
405 rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
406 sqlite3Fts5IndexRollback(pTab->p.pIndex);
407 pConfig->pzErrmsg = 0;
410 if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
411 rc = sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1);
413 if( rc==SQLITE_OK ){
414 rc = sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
417 if( rc!=SQLITE_OK ){
418 fts5FreeVtab(pTab);
419 pTab = 0;
420 }else if( bCreate ){
421 fts5CheckTransactionState(pTab, FTS5_BEGIN, 0);
423 *ppVTab = (sqlite3_vtab*)pTab;
424 return rc;
428 ** The xConnect() and xCreate() methods for the virtual table. All the
429 ** work is done in function fts5InitVtab().
431 static int fts5ConnectMethod(
432 sqlite3 *db, /* Database connection */
433 void *pAux, /* Pointer to tokenizer hash table */
434 int argc, /* Number of elements in argv array */
435 const char * const *argv, /* xCreate/xConnect argument array */
436 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
437 char **pzErr /* OUT: sqlite3_malloc'd error message */
439 return fts5InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr);
441 static int fts5CreateMethod(
442 sqlite3 *db, /* Database connection */
443 void *pAux, /* Pointer to tokenizer hash table */
444 int argc, /* Number of elements in argv array */
445 const char * const *argv, /* xCreate/xConnect argument array */
446 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
447 char **pzErr /* OUT: sqlite3_malloc'd error message */
449 return fts5InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr);
453 ** The different query plans.
455 #define FTS5_PLAN_MATCH 1 /* (<tbl> MATCH ?) */
456 #define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */
457 #define FTS5_PLAN_SPECIAL 3 /* An internal query */
458 #define FTS5_PLAN_SORTED_MATCH 4 /* (<tbl> MATCH ? ORDER BY rank) */
459 #define FTS5_PLAN_SCAN 5 /* No usable constraint */
460 #define FTS5_PLAN_ROWID 6 /* (rowid = ?) */
463 ** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
464 ** extension is currently being used by a version of SQLite too old to
465 ** support index-info flags. In that case this function is a no-op.
467 static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
468 #if SQLITE_VERSION_NUMBER>=3008012
469 #ifndef SQLITE_CORE
470 if( sqlite3_libversion_number()>=3008012 )
471 #endif
473 pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
475 #endif
478 static int fts5UsePatternMatch(
479 Fts5Config *pConfig,
480 struct sqlite3_index_constraint *p
482 assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB );
483 assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE );
484 if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
485 return 1;
487 if( pConfig->ePattern==FTS5_PATTERN_LIKE
488 && (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB)
490 return 1;
492 return 0;
496 ** Implementation of the xBestIndex method for FTS5 tables. Within the
497 ** WHERE constraint, it searches for the following:
499 ** 1. A MATCH constraint against the table column.
500 ** 2. A MATCH constraint against the "rank" column.
501 ** 3. A MATCH constraint against some other column.
502 ** 4. An == constraint against the rowid column.
503 ** 5. A < or <= constraint against the rowid column.
504 ** 6. A > or >= constraint against the rowid column.
506 ** Within the ORDER BY, the following are supported:
508 ** 5. ORDER BY rank [ASC|DESC]
509 ** 6. ORDER BY rowid [ASC|DESC]
511 ** Information for the xFilter call is passed via both the idxNum and
512 ** idxStr variables. Specifically, idxNum is a bitmask of the following
513 ** flags used to encode the ORDER BY clause:
515 ** FTS5_BI_ORDER_RANK
516 ** FTS5_BI_ORDER_ROWID
517 ** FTS5_BI_ORDER_DESC
519 ** idxStr is used to encode data from the WHERE clause. For each argument
520 ** passed to the xFilter method, the following is appended to idxStr:
522 ** Match against table column: "m"
523 ** Match against rank column: "r"
524 ** Match against other column: "M<column-number>"
525 ** LIKE against other column: "L<column-number>"
526 ** GLOB against other column: "G<column-number>"
527 ** Equality constraint against the rowid: "="
528 ** A < or <= against the rowid: "<"
529 ** A > or >= against the rowid: ">"
531 ** This function ensures that there is at most one "r" or "=". And that if
532 ** there exists an "=" then there is no "<" or ">".
534 ** Costs are assigned as follows:
536 ** a) If an unusable MATCH operator is present in the WHERE clause, the
537 ** cost is unconditionally set to 1e50 (a really big number).
539 ** a) If a MATCH operator is present, the cost depends on the other
540 ** constraints also present. As follows:
542 ** * No other constraints: cost=1000.0
543 ** * One rowid range constraint: cost=750.0
544 ** * Both rowid range constraints: cost=500.0
545 ** * An == rowid constraint: cost=100.0
547 ** b) Otherwise, if there is no MATCH:
549 ** * No other constraints: cost=1000000.0
550 ** * One rowid range constraint: cost=750000.0
551 ** * Both rowid range constraints: cost=250000.0
552 ** * An == rowid constraint: cost=10.0
554 ** Costs are not modified by the ORDER BY clause.
556 static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
557 Fts5Table *pTab = (Fts5Table*)pVTab;
558 Fts5Config *pConfig = pTab->pConfig;
559 const int nCol = pConfig->nCol;
560 int idxFlags = 0; /* Parameter passed through to xFilter() */
561 int i;
563 char *idxStr;
564 int iIdxStr = 0;
565 int iCons = 0;
567 int bSeenEq = 0;
568 int bSeenGt = 0;
569 int bSeenLt = 0;
570 int bSeenMatch = 0;
571 int bSeenRank = 0;
574 assert( SQLITE_INDEX_CONSTRAINT_EQ<SQLITE_INDEX_CONSTRAINT_MATCH );
575 assert( SQLITE_INDEX_CONSTRAINT_GT<SQLITE_INDEX_CONSTRAINT_MATCH );
576 assert( SQLITE_INDEX_CONSTRAINT_LE<SQLITE_INDEX_CONSTRAINT_MATCH );
577 assert( SQLITE_INDEX_CONSTRAINT_GE<SQLITE_INDEX_CONSTRAINT_MATCH );
578 assert( SQLITE_INDEX_CONSTRAINT_LE<SQLITE_INDEX_CONSTRAINT_MATCH );
580 if( pConfig->bLock ){
581 pTab->base.zErrMsg = sqlite3_mprintf(
582 "recursively defined fts5 content table"
584 return SQLITE_ERROR;
587 idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1);
588 if( idxStr==0 ) return SQLITE_NOMEM;
589 pInfo->idxStr = idxStr;
590 pInfo->needToFreeIdxStr = 1;
592 for(i=0; i<pInfo->nConstraint; i++){
593 struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
594 int iCol = p->iColumn;
595 if( p->op==SQLITE_INDEX_CONSTRAINT_MATCH
596 || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol>=nCol)
598 /* A MATCH operator or equivalent */
599 if( p->usable==0 || iCol<0 ){
600 /* As there exists an unusable MATCH constraint this is an
601 ** unusable plan. Set a prohibitively high cost. */
602 pInfo->estimatedCost = 1e50;
603 assert( iIdxStr < pInfo->nConstraint*6 + 1 );
604 idxStr[iIdxStr] = 0;
605 return SQLITE_OK;
606 }else{
607 if( iCol==nCol+1 ){
608 if( bSeenRank ) continue;
609 idxStr[iIdxStr++] = 'r';
610 bSeenRank = 1;
611 }else if( iCol>=0 ){
612 bSeenMatch = 1;
613 idxStr[iIdxStr++] = 'M';
614 sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
615 idxStr += strlen(&idxStr[iIdxStr]);
616 assert( idxStr[iIdxStr]=='\0' );
618 pInfo->aConstraintUsage[i].argvIndex = ++iCons;
619 pInfo->aConstraintUsage[i].omit = 1;
621 }else if( p->usable ){
622 if( iCol>=0 && iCol<nCol && fts5UsePatternMatch(pConfig, p) ){
623 assert( p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB );
624 idxStr[iIdxStr++] = p->op==FTS5_PATTERN_LIKE ? 'L' : 'G';
625 sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
626 idxStr += strlen(&idxStr[iIdxStr]);
627 pInfo->aConstraintUsage[i].argvIndex = ++iCons;
628 assert( idxStr[iIdxStr]=='\0' );
629 }else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){
630 idxStr[iIdxStr++] = '=';
631 bSeenEq = 1;
632 pInfo->aConstraintUsage[i].argvIndex = ++iCons;
637 if( bSeenEq==0 ){
638 for(i=0; i<pInfo->nConstraint; i++){
639 struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
640 if( p->iColumn<0 && p->usable ){
641 int op = p->op;
642 if( op==SQLITE_INDEX_CONSTRAINT_LT || op==SQLITE_INDEX_CONSTRAINT_LE ){
643 if( bSeenLt ) continue;
644 idxStr[iIdxStr++] = '<';
645 pInfo->aConstraintUsage[i].argvIndex = ++iCons;
646 bSeenLt = 1;
647 }else
648 if( op==SQLITE_INDEX_CONSTRAINT_GT || op==SQLITE_INDEX_CONSTRAINT_GE ){
649 if( bSeenGt ) continue;
650 idxStr[iIdxStr++] = '>';
651 pInfo->aConstraintUsage[i].argvIndex = ++iCons;
652 bSeenGt = 1;
657 idxStr[iIdxStr] = '\0';
659 /* Set idxFlags flags for the ORDER BY clause
661 ** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC".
663 if( pInfo->nOrderBy==1 ){
664 int iSort = pInfo->aOrderBy[0].iColumn;
665 if( iSort==(pConfig->nCol+1) && bSeenMatch ){
666 idxFlags |= FTS5_BI_ORDER_RANK;
667 }else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){
668 idxFlags |= FTS5_BI_ORDER_ROWID;
670 if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
671 pInfo->orderByConsumed = 1;
672 if( pInfo->aOrderBy[0].desc ){
673 idxFlags |= FTS5_BI_ORDER_DESC;
678 /* Calculate the estimated cost based on the flags set in idxFlags. */
679 if( bSeenEq ){
680 pInfo->estimatedCost = bSeenMatch ? 100.0 : 10.0;
681 if( bSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
682 }else if( bSeenLt && bSeenGt ){
683 pInfo->estimatedCost = bSeenMatch ? 500.0 : 250000.0;
684 }else if( bSeenLt || bSeenGt ){
685 pInfo->estimatedCost = bSeenMatch ? 750.0 : 750000.0;
686 }else{
687 pInfo->estimatedCost = bSeenMatch ? 1000.0 : 1000000.0;
690 pInfo->idxNum = idxFlags;
691 return SQLITE_OK;
694 static int fts5NewTransaction(Fts5FullTable *pTab){
695 Fts5Cursor *pCsr;
696 for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
697 if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
699 return sqlite3Fts5StorageReset(pTab->pStorage);
703 ** Implementation of xOpen method.
705 static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
706 Fts5FullTable *pTab = (Fts5FullTable*)pVTab;
707 Fts5Config *pConfig = pTab->p.pConfig;
708 Fts5Cursor *pCsr = 0; /* New cursor object */
709 sqlite3_int64 nByte; /* Bytes of space to allocate */
710 int rc; /* Return code */
712 rc = fts5NewTransaction(pTab);
713 if( rc==SQLITE_OK ){
714 nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
715 pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte);
716 if( pCsr ){
717 Fts5Global *pGlobal = pTab->pGlobal;
718 memset(pCsr, 0, (size_t)nByte);
719 pCsr->aColumnSize = (int*)&pCsr[1];
720 pCsr->pNext = pGlobal->pCsr;
721 pGlobal->pCsr = pCsr;
722 pCsr->iCsrId = ++pGlobal->iNextId;
723 }else{
724 rc = SQLITE_NOMEM;
727 *ppCsr = (sqlite3_vtab_cursor*)pCsr;
728 return rc;
731 static int fts5StmtType(Fts5Cursor *pCsr){
732 if( pCsr->ePlan==FTS5_PLAN_SCAN ){
733 return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC;
735 return FTS5_STMT_LOOKUP;
739 ** This function is called after the cursor passed as the only argument
740 ** is moved to point at a different row. It clears all cached data
741 ** specific to the previous row stored by the cursor object.
743 static void fts5CsrNewrow(Fts5Cursor *pCsr){
744 CsrFlagSet(pCsr,
745 FTS5CSR_REQUIRE_CONTENT
746 | FTS5CSR_REQUIRE_DOCSIZE
747 | FTS5CSR_REQUIRE_INST
748 | FTS5CSR_REQUIRE_POSLIST
752 static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
753 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
754 Fts5Auxdata *pData;
755 Fts5Auxdata *pNext;
757 sqlite3_free(pCsr->aInstIter);
758 sqlite3_free(pCsr->aInst);
759 if( pCsr->pStmt ){
760 int eStmt = fts5StmtType(pCsr);
761 sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
763 if( pCsr->pSorter ){
764 Fts5Sorter *pSorter = pCsr->pSorter;
765 sqlite3_finalize(pSorter->pStmt);
766 sqlite3_free(pSorter);
769 if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){
770 sqlite3Fts5ExprFree(pCsr->pExpr);
773 for(pData=pCsr->pAuxdata; pData; pData=pNext){
774 pNext = pData->pNext;
775 if( pData->xDelete ) pData->xDelete(pData->pPtr);
776 sqlite3_free(pData);
779 sqlite3_finalize(pCsr->pRankArgStmt);
780 sqlite3_free(pCsr->apRankArg);
782 if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){
783 sqlite3_free(pCsr->zRank);
784 sqlite3_free(pCsr->zRankArgs);
787 sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
788 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr));
793 ** Close the cursor. For additional information see the documentation
794 ** on the xClose method of the virtual table interface.
796 static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
797 if( pCursor ){
798 Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
799 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
800 Fts5Cursor **pp;
802 fts5FreeCursorComponents(pCsr);
803 /* Remove the cursor from the Fts5Global.pCsr list */
804 for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext);
805 *pp = pCsr->pNext;
807 sqlite3_free(pCsr);
809 return SQLITE_OK;
812 static int fts5SorterNext(Fts5Cursor *pCsr){
813 Fts5Sorter *pSorter = pCsr->pSorter;
814 int rc;
816 rc = sqlite3_step(pSorter->pStmt);
817 if( rc==SQLITE_DONE ){
818 rc = SQLITE_OK;
819 CsrFlagSet(pCsr, FTS5CSR_EOF|FTS5CSR_REQUIRE_CONTENT);
820 }else if( rc==SQLITE_ROW ){
821 const u8 *a;
822 const u8 *aBlob;
823 int nBlob;
824 int i;
825 int iOff = 0;
826 rc = SQLITE_OK;
828 pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0);
829 nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
830 aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
832 /* nBlob==0 in detail=none mode. */
833 if( nBlob>0 ){
834 for(i=0; i<(pSorter->nIdx-1); i++){
835 int iVal;
836 a += fts5GetVarint32(a, iVal);
837 iOff += iVal;
838 pSorter->aIdx[i] = iOff;
840 pSorter->aIdx[i] = &aBlob[nBlob] - a;
841 pSorter->aPoslist = a;
844 fts5CsrNewrow(pCsr);
847 return rc;
852 ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
853 ** open on table pTab.
855 static void fts5TripCursors(Fts5FullTable *pTab){
856 Fts5Cursor *pCsr;
857 for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
858 if( pCsr->ePlan==FTS5_PLAN_MATCH
859 && pCsr->base.pVtab==(sqlite3_vtab*)pTab
861 CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK);
867 ** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
868 ** argument, close and reopen all Fts5IndexIter iterators that the cursor
869 ** is using. Then attempt to move the cursor to a rowid equal to or laster
870 ** (in the cursors sort order - ASC or DESC) than the current rowid.
872 ** If the new rowid is not equal to the old, set output parameter *pbSkip
873 ** to 1 before returning. Otherwise, leave it unchanged.
875 ** Return SQLITE_OK if successful or if no reseek was required, or an
876 ** error code if an error occurred.
878 static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
879 int rc = SQLITE_OK;
880 assert( *pbSkip==0 );
881 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){
882 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
883 int bDesc = pCsr->bDesc;
884 i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
886 rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc);
887 if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
888 *pbSkip = 1;
891 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK);
892 fts5CsrNewrow(pCsr);
893 if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
894 CsrFlagSet(pCsr, FTS5CSR_EOF);
895 *pbSkip = 1;
898 return rc;
903 ** Advance the cursor to the next row in the table that matches the
904 ** search criteria.
906 ** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
907 ** even if we reach end-of-file. The fts5EofMethod() will be called
908 ** subsequently to determine whether or not an EOF was hit.
910 static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
911 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
912 int rc;
914 assert( (pCsr->ePlan<3)==
915 (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
917 assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
919 /* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table,
920 ** clear any token mappings accumulated at the fts5_index.c level. In
921 ** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH,
922 ** we need to retain the mappings for the entire query. */
923 if( pCsr->ePlan==FTS5_PLAN_MATCH
924 && ((Fts5Table*)pCursor->pVtab)->pConfig->bTokendata
926 sqlite3Fts5ExprClearTokens(pCsr->pExpr);
929 if( pCsr->ePlan<3 ){
930 int bSkip = 0;
931 if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
932 rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
933 CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
934 fts5CsrNewrow(pCsr);
935 }else{
936 switch( pCsr->ePlan ){
937 case FTS5_PLAN_SPECIAL: {
938 CsrFlagSet(pCsr, FTS5CSR_EOF);
939 rc = SQLITE_OK;
940 break;
943 case FTS5_PLAN_SORTED_MATCH: {
944 rc = fts5SorterNext(pCsr);
945 break;
948 default: {
949 Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig;
950 pConfig->bLock++;
951 rc = sqlite3_step(pCsr->pStmt);
952 pConfig->bLock--;
953 if( rc!=SQLITE_ROW ){
954 CsrFlagSet(pCsr, FTS5CSR_EOF);
955 rc = sqlite3_reset(pCsr->pStmt);
956 if( rc!=SQLITE_OK ){
957 pCursor->pVtab->zErrMsg = sqlite3_mprintf(
958 "%s", sqlite3_errmsg(pConfig->db)
961 }else{
962 rc = SQLITE_OK;
964 break;
969 return rc;
973 static int fts5PrepareStatement(
974 sqlite3_stmt **ppStmt,
975 Fts5Config *pConfig,
976 const char *zFmt,
979 sqlite3_stmt *pRet = 0;
980 int rc;
981 char *zSql;
982 va_list ap;
984 va_start(ap, zFmt);
985 zSql = sqlite3_vmprintf(zFmt, ap);
986 if( zSql==0 ){
987 rc = SQLITE_NOMEM;
988 }else{
989 rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
990 SQLITE_PREPARE_PERSISTENT, &pRet, 0);
991 if( rc!=SQLITE_OK ){
992 *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
994 sqlite3_free(zSql);
997 va_end(ap);
998 *ppStmt = pRet;
999 return rc;
1002 static int fts5CursorFirstSorted(
1003 Fts5FullTable *pTab,
1004 Fts5Cursor *pCsr,
1005 int bDesc
1007 Fts5Config *pConfig = pTab->p.pConfig;
1008 Fts5Sorter *pSorter;
1009 int nPhrase;
1010 sqlite3_int64 nByte;
1011 int rc;
1012 const char *zRank = pCsr->zRank;
1013 const char *zRankArgs = pCsr->zRankArgs;
1015 nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
1016 nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
1017 pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte);
1018 if( pSorter==0 ) return SQLITE_NOMEM;
1019 memset(pSorter, 0, (size_t)nByte);
1020 pSorter->nIdx = nPhrase;
1022 /* TODO: It would be better to have some system for reusing statement
1023 ** handles here, rather than preparing a new one for each query. But that
1024 ** is not possible as SQLite reference counts the virtual table objects.
1025 ** And since the statement required here reads from this very virtual
1026 ** table, saving it creates a circular reference.
1028 ** If SQLite a built-in statement cache, this wouldn't be a problem. */
1029 rc = fts5PrepareStatement(&pSorter->pStmt, pConfig,
1030 "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(\"%w\"%s%s) %s",
1031 pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
1032 (zRankArgs ? ", " : ""),
1033 (zRankArgs ? zRankArgs : ""),
1034 bDesc ? "DESC" : "ASC"
1037 pCsr->pSorter = pSorter;
1038 if( rc==SQLITE_OK ){
1039 assert( pTab->pSortCsr==0 );
1040 pTab->pSortCsr = pCsr;
1041 rc = fts5SorterNext(pCsr);
1042 pTab->pSortCsr = 0;
1045 if( rc!=SQLITE_OK ){
1046 sqlite3_finalize(pSorter->pStmt);
1047 sqlite3_free(pSorter);
1048 pCsr->pSorter = 0;
1051 return rc;
1054 static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){
1055 int rc;
1056 Fts5Expr *pExpr = pCsr->pExpr;
1057 rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc);
1058 if( sqlite3Fts5ExprEof(pExpr) ){
1059 CsrFlagSet(pCsr, FTS5CSR_EOF);
1061 fts5CsrNewrow(pCsr);
1062 return rc;
1066 ** Process a "special" query. A special query is identified as one with a
1067 ** MATCH expression that begins with a '*' character. The remainder of
1068 ** the text passed to the MATCH operator are used as the special query
1069 ** parameters.
1071 static int fts5SpecialMatch(
1072 Fts5FullTable *pTab,
1073 Fts5Cursor *pCsr,
1074 const char *zQuery
1076 int rc = SQLITE_OK; /* Return code */
1077 const char *z = zQuery; /* Special query text */
1078 int n; /* Number of bytes in text at z */
1080 while( z[0]==' ' ) z++;
1081 for(n=0; z[n] && z[n]!=' '; n++);
1083 assert( pTab->p.base.zErrMsg==0 );
1084 pCsr->ePlan = FTS5_PLAN_SPECIAL;
1086 if( n==5 && 0==sqlite3_strnicmp("reads", z, n) ){
1087 pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->p.pIndex);
1089 else if( n==2 && 0==sqlite3_strnicmp("id", z, n) ){
1090 pCsr->iSpecial = pCsr->iCsrId;
1092 else{
1093 /* An unrecognized directive. Return an error message. */
1094 pTab->p.base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
1095 rc = SQLITE_ERROR;
1098 return rc;
1102 ** Search for an auxiliary function named zName that can be used with table
1103 ** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
1104 ** structure. Otherwise, if no such function exists, return NULL.
1106 static Fts5Auxiliary *fts5FindAuxiliary(Fts5FullTable *pTab, const char *zName){
1107 Fts5Auxiliary *pAux;
1109 for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){
1110 if( sqlite3_stricmp(zName, pAux->zFunc)==0 ) return pAux;
1113 /* No function of the specified name was found. Return 0. */
1114 return 0;
1118 static int fts5FindRankFunction(Fts5Cursor *pCsr){
1119 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1120 Fts5Config *pConfig = pTab->p.pConfig;
1121 int rc = SQLITE_OK;
1122 Fts5Auxiliary *pAux = 0;
1123 const char *zRank = pCsr->zRank;
1124 const char *zRankArgs = pCsr->zRankArgs;
1126 if( zRankArgs ){
1127 char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs);
1128 if( zSql ){
1129 sqlite3_stmt *pStmt = 0;
1130 rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
1131 SQLITE_PREPARE_PERSISTENT, &pStmt, 0);
1132 sqlite3_free(zSql);
1133 assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
1134 if( rc==SQLITE_OK ){
1135 if( SQLITE_ROW==sqlite3_step(pStmt) ){
1136 sqlite3_int64 nByte;
1137 pCsr->nRankArg = sqlite3_column_count(pStmt);
1138 nByte = sizeof(sqlite3_value*)*pCsr->nRankArg;
1139 pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte);
1140 if( rc==SQLITE_OK ){
1141 int i;
1142 for(i=0; i<pCsr->nRankArg; i++){
1143 pCsr->apRankArg[i] = sqlite3_column_value(pStmt, i);
1146 pCsr->pRankArgStmt = pStmt;
1147 }else{
1148 rc = sqlite3_finalize(pStmt);
1149 assert( rc!=SQLITE_OK );
1155 if( rc==SQLITE_OK ){
1156 pAux = fts5FindAuxiliary(pTab, zRank);
1157 if( pAux==0 ){
1158 assert( pTab->p.base.zErrMsg==0 );
1159 pTab->p.base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
1160 rc = SQLITE_ERROR;
1164 pCsr->pRank = pAux;
1165 return rc;
1169 static int fts5CursorParseRank(
1170 Fts5Config *pConfig,
1171 Fts5Cursor *pCsr,
1172 sqlite3_value *pRank
1174 int rc = SQLITE_OK;
1175 if( pRank ){
1176 const char *z = (const char*)sqlite3_value_text(pRank);
1177 char *zRank = 0;
1178 char *zRankArgs = 0;
1180 if( z==0 ){
1181 if( sqlite3_value_type(pRank)==SQLITE_NULL ) rc = SQLITE_ERROR;
1182 }else{
1183 rc = sqlite3Fts5ConfigParseRank(z, &zRank, &zRankArgs);
1185 if( rc==SQLITE_OK ){
1186 pCsr->zRank = zRank;
1187 pCsr->zRankArgs = zRankArgs;
1188 CsrFlagSet(pCsr, FTS5CSR_FREE_ZRANK);
1189 }else if( rc==SQLITE_ERROR ){
1190 pCsr->base.pVtab->zErrMsg = sqlite3_mprintf(
1191 "parse error in rank function: %s", z
1194 }else{
1195 if( pConfig->zRank ){
1196 pCsr->zRank = (char*)pConfig->zRank;
1197 pCsr->zRankArgs = (char*)pConfig->zRankArgs;
1198 }else{
1199 pCsr->zRank = (char*)FTS5_DEFAULT_RANK;
1200 pCsr->zRankArgs = 0;
1203 return rc;
1206 static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
1207 if( pVal ){
1208 int eType = sqlite3_value_numeric_type(pVal);
1209 if( eType==SQLITE_INTEGER ){
1210 return sqlite3_value_int64(pVal);
1213 return iDefault;
1217 ** This is the xFilter interface for the virtual table. See
1218 ** the virtual table xFilter method documentation for additional
1219 ** information.
1221 ** There are three possible query strategies:
1223 ** 1. Full-text search using a MATCH operator.
1224 ** 2. A by-rowid lookup.
1225 ** 3. A full-table scan.
1227 static int fts5FilterMethod(
1228 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
1229 int idxNum, /* Strategy index */
1230 const char *idxStr, /* Unused */
1231 int nVal, /* Number of elements in apVal */
1232 sqlite3_value **apVal /* Arguments for the indexing scheme */
1234 Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
1235 Fts5Config *pConfig = pTab->p.pConfig;
1236 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1237 int rc = SQLITE_OK; /* Error code */
1238 int bDesc; /* True if ORDER BY [rank|rowid] DESC */
1239 int bOrderByRank; /* True if ORDER BY rank */
1240 sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */
1241 sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
1242 sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
1243 sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
1244 int iCol; /* Column on LHS of MATCH operator */
1245 char **pzErrmsg = pConfig->pzErrmsg;
1246 int i;
1247 int iIdxStr = 0;
1248 Fts5Expr *pExpr = 0;
1250 if( pConfig->bLock ){
1251 pTab->p.base.zErrMsg = sqlite3_mprintf(
1252 "recursively defined fts5 content table"
1254 return SQLITE_ERROR;
1257 if( pCsr->ePlan ){
1258 fts5FreeCursorComponents(pCsr);
1259 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
1262 assert( pCsr->pStmt==0 );
1263 assert( pCsr->pExpr==0 );
1264 assert( pCsr->csrflags==0 );
1265 assert( pCsr->pRank==0 );
1266 assert( pCsr->zRank==0 );
1267 assert( pCsr->zRankArgs==0 );
1268 assert( pTab->pSortCsr==0 || nVal==0 );
1270 assert( pzErrmsg==0 || pzErrmsg==&pTab->p.base.zErrMsg );
1271 pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
1273 /* Decode the arguments passed through to this function. */
1274 for(i=0; i<nVal; i++){
1275 switch( idxStr[iIdxStr++] ){
1276 case 'r':
1277 pRank = apVal[i];
1278 break;
1279 case 'M': {
1280 const char *zText = (const char*)sqlite3_value_text(apVal[i]);
1281 if( zText==0 ) zText = "";
1282 iCol = 0;
1284 iCol = iCol*10 + (idxStr[iIdxStr]-'0');
1285 iIdxStr++;
1286 }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
1288 if( zText[0]=='*' ){
1289 /* The user has issued a query of the form "MATCH '*...'". This
1290 ** indicates that the MATCH expression is not a full text query,
1291 ** but a request for an internal parameter. */
1292 rc = fts5SpecialMatch(pTab, pCsr, &zText[1]);
1293 goto filter_out;
1294 }else{
1295 char **pzErr = &pTab->p.base.zErrMsg;
1296 rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
1297 if( rc==SQLITE_OK ){
1298 rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
1299 pExpr = 0;
1301 if( rc!=SQLITE_OK ) goto filter_out;
1304 break;
1306 case 'L':
1307 case 'G': {
1308 int bGlob = (idxStr[iIdxStr-1]=='G');
1309 const char *zText = (const char*)sqlite3_value_text(apVal[i]);
1310 iCol = 0;
1312 iCol = iCol*10 + (idxStr[iIdxStr]-'0');
1313 iIdxStr++;
1314 }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
1315 if( zText ){
1316 rc = sqlite3Fts5ExprPattern(pConfig, bGlob, iCol, zText, &pExpr);
1318 if( rc==SQLITE_OK ){
1319 rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
1320 pExpr = 0;
1322 if( rc!=SQLITE_OK ) goto filter_out;
1323 break;
1325 case '=':
1326 pRowidEq = apVal[i];
1327 break;
1328 case '<':
1329 pRowidLe = apVal[i];
1330 break;
1331 default: assert( idxStr[iIdxStr-1]=='>' );
1332 pRowidGe = apVal[i];
1333 break;
1336 bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
1337 pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
1339 /* Set the cursor upper and lower rowid limits. Only some strategies
1340 ** actually use them. This is ok, as the xBestIndex() method leaves the
1341 ** sqlite3_index_constraint.omit flag clear for range constraints
1342 ** on the rowid field. */
1343 if( pRowidEq ){
1344 pRowidLe = pRowidGe = pRowidEq;
1346 if( bDesc ){
1347 pCsr->iFirstRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
1348 pCsr->iLastRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
1349 }else{
1350 pCsr->iLastRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
1351 pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
1354 rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
1355 if( rc!=SQLITE_OK ) goto filter_out;
1357 if( pTab->pSortCsr ){
1358 /* If pSortCsr is non-NULL, then this call is being made as part of
1359 ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
1360 ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
1361 ** return results to the user for this query. The current cursor
1362 ** (pCursor) is used to execute the query issued by function
1363 ** fts5CursorFirstSorted() above. */
1364 assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 );
1365 assert( nVal==0 && bOrderByRank==0 && bDesc==0 );
1366 assert( pCsr->iLastRowid==LARGEST_INT64 );
1367 assert( pCsr->iFirstRowid==SMALLEST_INT64 );
1368 if( pTab->pSortCsr->bDesc ){
1369 pCsr->iLastRowid = pTab->pSortCsr->iFirstRowid;
1370 pCsr->iFirstRowid = pTab->pSortCsr->iLastRowid;
1371 }else{
1372 pCsr->iLastRowid = pTab->pSortCsr->iLastRowid;
1373 pCsr->iFirstRowid = pTab->pSortCsr->iFirstRowid;
1375 pCsr->ePlan = FTS5_PLAN_SOURCE;
1376 pCsr->pExpr = pTab->pSortCsr->pExpr;
1377 rc = fts5CursorFirst(pTab, pCsr, bDesc);
1378 }else if( pCsr->pExpr ){
1379 assert( rc==SQLITE_OK );
1380 rc = fts5CursorParseRank(pConfig, pCsr, pRank);
1381 if( rc==SQLITE_OK ){
1382 if( bOrderByRank ){
1383 pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
1384 rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
1385 }else{
1386 pCsr->ePlan = FTS5_PLAN_MATCH;
1387 rc = fts5CursorFirst(pTab, pCsr, bDesc);
1390 }else if( pConfig->zContent==0 ){
1391 *pConfig->pzErrmsg = sqlite3_mprintf(
1392 "%s: table does not support scanning", pConfig->zName
1394 rc = SQLITE_ERROR;
1395 }else{
1396 /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
1397 ** by rowid (ePlan==FTS5_PLAN_ROWID). */
1398 pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
1399 rc = sqlite3Fts5StorageStmt(
1400 pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg
1402 if( rc==SQLITE_OK ){
1403 if( pRowidEq!=0 ){
1404 assert( pCsr->ePlan==FTS5_PLAN_ROWID );
1405 sqlite3_bind_value(pCsr->pStmt, 1, pRowidEq);
1406 }else{
1407 sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
1408 sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid);
1410 rc = fts5NextMethod(pCursor);
1414 filter_out:
1415 sqlite3Fts5ExprFree(pExpr);
1416 pConfig->pzErrmsg = pzErrmsg;
1417 return rc;
1421 ** This is the xEof method of the virtual table. SQLite calls this
1422 ** routine to find out if it has reached the end of a result set.
1424 static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
1425 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1426 return (CsrFlagTest(pCsr, FTS5CSR_EOF) ? 1 : 0);
1430 ** Return the rowid that the cursor currently points to.
1432 static i64 fts5CursorRowid(Fts5Cursor *pCsr){
1433 assert( pCsr->ePlan==FTS5_PLAN_MATCH
1434 || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
1435 || pCsr->ePlan==FTS5_PLAN_SOURCE
1437 if( pCsr->pSorter ){
1438 return pCsr->pSorter->iRowid;
1439 }else{
1440 return sqlite3Fts5ExprRowid(pCsr->pExpr);
1445 ** This is the xRowid method. The SQLite core calls this routine to
1446 ** retrieve the rowid for the current row of the result set. fts5
1447 ** exposes %_content.rowid as the rowid for the virtual table. The
1448 ** rowid should be written to *pRowid.
1450 static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
1451 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1452 int ePlan = pCsr->ePlan;
1454 assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
1455 switch( ePlan ){
1456 case FTS5_PLAN_SPECIAL:
1457 *pRowid = 0;
1458 break;
1460 case FTS5_PLAN_SOURCE:
1461 case FTS5_PLAN_MATCH:
1462 case FTS5_PLAN_SORTED_MATCH:
1463 *pRowid = fts5CursorRowid(pCsr);
1464 break;
1466 default:
1467 *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
1468 break;
1471 return SQLITE_OK;
1475 ** If the cursor requires seeking (bSeekRequired flag is set), seek it.
1476 ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
1478 ** If argument bErrormsg is true and an error occurs, an error message may
1479 ** be left in sqlite3_vtab.zErrMsg.
1481 static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
1482 int rc = SQLITE_OK;
1484 /* If the cursor does not yet have a statement handle, obtain one now. */
1485 if( pCsr->pStmt==0 ){
1486 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1487 int eStmt = fts5StmtType(pCsr);
1488 rc = sqlite3Fts5StorageStmt(
1489 pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->p.base.zErrMsg:0)
1491 assert( rc!=SQLITE_OK || pTab->p.base.zErrMsg==0 );
1492 assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
1495 if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
1496 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1497 assert( pCsr->pExpr );
1498 sqlite3_reset(pCsr->pStmt);
1499 sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
1500 pTab->pConfig->bLock++;
1501 rc = sqlite3_step(pCsr->pStmt);
1502 pTab->pConfig->bLock--;
1503 if( rc==SQLITE_ROW ){
1504 rc = SQLITE_OK;
1505 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
1506 }else{
1507 rc = sqlite3_reset(pCsr->pStmt);
1508 if( rc==SQLITE_OK ){
1509 rc = FTS5_CORRUPT;
1510 }else if( pTab->pConfig->pzErrmsg ){
1511 *pTab->pConfig->pzErrmsg = sqlite3_mprintf(
1512 "%s", sqlite3_errmsg(pTab->pConfig->db)
1517 return rc;
1520 static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
1521 va_list ap; /* ... printf arguments */
1522 va_start(ap, zFormat);
1523 assert( p->p.base.zErrMsg==0 );
1524 p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
1525 va_end(ap);
1529 ** This function is called to handle an FTS INSERT command. In other words,
1530 ** an INSERT statement of the form:
1532 ** INSERT INTO fts(fts) VALUES($pCmd)
1533 ** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
1535 ** Argument pVal is the value assigned to column "fts" by the INSERT
1536 ** statement. This function returns SQLITE_OK if successful, or an SQLite
1537 ** error code if an error occurs.
1539 ** The commands implemented by this function are documented in the "Special
1540 ** INSERT Directives" section of the documentation. It should be updated if
1541 ** more commands are added to this function.
1543 static int fts5SpecialInsert(
1544 Fts5FullTable *pTab, /* Fts5 table object */
1545 const char *zCmd, /* Text inserted into table-name column */
1546 sqlite3_value *pVal /* Value inserted into rank column */
1548 Fts5Config *pConfig = pTab->p.pConfig;
1549 int rc = SQLITE_OK;
1550 int bError = 0;
1551 int bLoadConfig = 0;
1553 if( 0==sqlite3_stricmp("delete-all", zCmd) ){
1554 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
1555 fts5SetVtabError(pTab,
1556 "'delete-all' may only be used with a "
1557 "contentless or external content fts5 table"
1559 rc = SQLITE_ERROR;
1560 }else{
1561 rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
1563 bLoadConfig = 1;
1564 }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
1565 if( pConfig->eContent==FTS5_CONTENT_NONE ){
1566 fts5SetVtabError(pTab,
1567 "'rebuild' may not be used with a contentless fts5 table"
1569 rc = SQLITE_ERROR;
1570 }else{
1571 rc = sqlite3Fts5StorageRebuild(pTab->pStorage);
1573 bLoadConfig = 1;
1574 }else if( 0==sqlite3_stricmp("optimize", zCmd) ){
1575 rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
1576 }else if( 0==sqlite3_stricmp("merge", zCmd) ){
1577 int nMerge = sqlite3_value_int(pVal);
1578 rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
1579 }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
1580 int iArg = sqlite3_value_int(pVal);
1581 rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, iArg);
1582 #ifdef SQLITE_DEBUG
1583 }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
1584 pConfig->bPrefixIndex = sqlite3_value_int(pVal);
1585 #endif
1586 }else if( 0==sqlite3_stricmp("flush", zCmd) ){
1587 rc = sqlite3Fts5FlushToDisk(&pTab->p);
1588 }else{
1589 rc = sqlite3Fts5FlushToDisk(&pTab->p);
1590 if( rc==SQLITE_OK ){
1591 rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
1593 if( rc==SQLITE_OK ){
1594 rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError);
1596 if( rc==SQLITE_OK ){
1597 if( bError ){
1598 rc = SQLITE_ERROR;
1599 }else{
1600 rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0);
1605 if( rc==SQLITE_OK && bLoadConfig ){
1606 pTab->p.pConfig->iCookie--;
1607 rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
1610 return rc;
1613 static int fts5SpecialDelete(
1614 Fts5FullTable *pTab,
1615 sqlite3_value **apVal
1617 int rc = SQLITE_OK;
1618 int eType1 = sqlite3_value_type(apVal[1]);
1619 if( eType1==SQLITE_INTEGER ){
1620 sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
1621 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
1623 return rc;
1626 static void fts5StorageInsert(
1627 int *pRc,
1628 Fts5FullTable *pTab,
1629 sqlite3_value **apVal,
1630 i64 *piRowid
1632 int rc = *pRc;
1633 if( rc==SQLITE_OK ){
1634 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
1636 if( rc==SQLITE_OK ){
1637 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
1639 *pRc = rc;
1643 ** This function is the implementation of the xUpdate callback used by
1644 ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
1645 ** inserted, updated or deleted.
1647 ** A delete specifies a single argument - the rowid of the row to remove.
1649 ** Update and insert operations pass:
1651 ** 1. The "old" rowid, or NULL.
1652 ** 2. The "new" rowid.
1653 ** 3. Values for each of the nCol matchable columns.
1654 ** 4. Values for the two hidden columns (<tablename> and "rank").
1656 static int fts5UpdateMethod(
1657 sqlite3_vtab *pVtab, /* Virtual table handle */
1658 int nArg, /* Size of argument array */
1659 sqlite3_value **apVal, /* Array of arguments */
1660 sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */
1662 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
1663 Fts5Config *pConfig = pTab->p.pConfig;
1664 int eType0; /* value_type() of apVal[0] */
1665 int rc = SQLITE_OK; /* Return code */
1666 int bUpdateOrDelete = 0;
1668 /* A transaction must be open when this is called. */
1669 assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
1671 assert( pVtab->zErrMsg==0 );
1672 assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
1673 assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER
1674 || sqlite3_value_type(apVal[0])==SQLITE_NULL
1676 assert( pTab->p.pConfig->pzErrmsg==0 );
1677 if( pConfig->pgsz==0 ){
1678 rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
1679 if( rc!=SQLITE_OK ) return rc;
1682 pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
1684 /* Put any active cursors into REQUIRE_SEEK state. */
1685 fts5TripCursors(pTab);
1687 eType0 = sqlite3_value_type(apVal[0]);
1688 if( eType0==SQLITE_NULL
1689 && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
1691 /* A "special" INSERT op. These are handled separately. */
1692 const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]);
1693 if( pConfig->eContent!=FTS5_CONTENT_NORMAL
1694 && 0==sqlite3_stricmp("delete", z)
1696 if( pConfig->bContentlessDelete ){
1697 fts5SetVtabError(pTab,
1698 "'delete' may not be used with a contentless_delete=1 table"
1700 rc = SQLITE_ERROR;
1701 }else{
1702 rc = fts5SpecialDelete(pTab, apVal);
1704 }else{
1705 rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
1707 }else{
1708 /* A regular INSERT, UPDATE or DELETE statement. The trick here is that
1709 ** any conflict on the rowid value must be detected before any
1710 ** modifications are made to the database file. There are 4 cases:
1712 ** 1) DELETE
1713 ** 2) UPDATE (rowid not modified)
1714 ** 3) UPDATE (rowid modified)
1715 ** 4) INSERT
1717 ** Cases 3 and 4 may violate the rowid constraint.
1719 int eConflict = SQLITE_ABORT;
1720 if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->bContentlessDelete ){
1721 eConflict = sqlite3_vtab_on_conflict(pConfig->db);
1724 assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
1725 assert( nArg!=1 || eType0==SQLITE_INTEGER );
1727 /* Filter out attempts to run UPDATE or DELETE on contentless tables.
1728 ** This is not suported. Except - they are both supported if the CREATE
1729 ** VIRTUAL TABLE statement contained "contentless_delete=1". */
1730 if( eType0==SQLITE_INTEGER
1731 && pConfig->eContent==FTS5_CONTENT_NONE
1732 && pConfig->bContentlessDelete==0
1734 pTab->p.base.zErrMsg = sqlite3_mprintf(
1735 "cannot %s contentless fts5 table: %s",
1736 (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
1738 rc = SQLITE_ERROR;
1741 /* DELETE */
1742 else if( nArg==1 ){
1743 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
1744 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
1745 bUpdateOrDelete = 1;
1748 /* INSERT or UPDATE */
1749 else{
1750 int eType1 = sqlite3_value_numeric_type(apVal[1]);
1752 if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
1753 rc = SQLITE_MISMATCH;
1756 else if( eType0!=SQLITE_INTEGER ){
1757 /* An INSERT statement. If the conflict-mode is REPLACE, first remove
1758 ** the current entry (if any). */
1759 if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
1760 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
1761 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
1762 bUpdateOrDelete = 1;
1764 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1767 /* UPDATE */
1768 else{
1769 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
1770 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
1771 if( eType1==SQLITE_INTEGER && iOld!=iNew ){
1772 if( eConflict==SQLITE_REPLACE ){
1773 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1774 if( rc==SQLITE_OK ){
1775 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
1777 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1778 }else{
1779 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
1780 if( rc==SQLITE_OK ){
1781 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1783 if( rc==SQLITE_OK ){
1784 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
1787 }else{
1788 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1789 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1791 bUpdateOrDelete = 1;
1796 if( rc==SQLITE_OK
1797 && bUpdateOrDelete
1798 && pConfig->bSecureDelete
1799 && pConfig->iVersion==FTS5_CURRENT_VERSION
1801 rc = sqlite3Fts5StorageConfigValue(
1802 pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
1804 if( rc==SQLITE_OK ){
1805 pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
1809 pTab->p.pConfig->pzErrmsg = 0;
1810 return rc;
1814 ** Implementation of xSync() method.
1816 static int fts5SyncMethod(sqlite3_vtab *pVtab){
1817 int rc;
1818 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
1819 fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
1820 pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
1821 rc = sqlite3Fts5FlushToDisk(&pTab->p);
1822 pTab->p.pConfig->pzErrmsg = 0;
1823 return rc;
1827 ** Implementation of xBegin() method.
1829 static int fts5BeginMethod(sqlite3_vtab *pVtab){
1830 fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
1831 fts5NewTransaction((Fts5FullTable*)pVtab);
1832 return SQLITE_OK;
1836 ** Implementation of xCommit() method. This is a no-op. The contents of
1837 ** the pending-terms hash-table have already been flushed into the database
1838 ** by fts5SyncMethod().
1840 static int fts5CommitMethod(sqlite3_vtab *pVtab){
1841 UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */
1842 fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_COMMIT, 0);
1843 return SQLITE_OK;
1847 ** Implementation of xRollback(). Discard the contents of the pending-terms
1848 ** hash-table. Any changes made to the database are reverted by SQLite.
1850 static int fts5RollbackMethod(sqlite3_vtab *pVtab){
1851 int rc;
1852 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
1853 fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
1854 rc = sqlite3Fts5StorageRollback(pTab->pStorage);
1855 return rc;
1858 static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*);
1860 static void *fts5ApiUserData(Fts5Context *pCtx){
1861 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1862 return pCsr->pAux->pUserData;
1865 static int fts5ApiColumnCount(Fts5Context *pCtx){
1866 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1867 return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol;
1870 static int fts5ApiColumnTotalSize(
1871 Fts5Context *pCtx,
1872 int iCol,
1873 sqlite3_int64 *pnToken
1875 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1876 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1877 return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken);
1880 static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
1881 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1882 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1883 return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
1886 static int fts5ApiTokenize(
1887 Fts5Context *pCtx,
1888 const char *pText, int nText,
1889 void *pUserData,
1890 int (*xToken)(void*, int, const char*, int, int, int)
1892 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1893 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1894 return sqlite3Fts5Tokenize(
1895 pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
1899 static int fts5ApiPhraseCount(Fts5Context *pCtx){
1900 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1901 return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
1904 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
1905 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1906 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
1909 static int fts5ApiColumnText(
1910 Fts5Context *pCtx,
1911 int iCol,
1912 const char **pz,
1913 int *pn
1915 int rc = SQLITE_OK;
1916 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1917 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1918 if( iCol<0 || iCol>=pTab->pConfig->nCol ){
1919 rc = SQLITE_RANGE;
1920 }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
1921 || pCsr->ePlan==FTS5_PLAN_SPECIAL
1923 *pz = 0;
1924 *pn = 0;
1925 }else{
1926 rc = fts5SeekCursor(pCsr, 0);
1927 if( rc==SQLITE_OK ){
1928 *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
1929 *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
1932 return rc;
1935 static int fts5CsrPoslist(
1936 Fts5Cursor *pCsr,
1937 int iPhrase,
1938 const u8 **pa,
1939 int *pn
1941 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
1942 int rc = SQLITE_OK;
1943 int bLive = (pCsr->pSorter==0);
1945 if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
1946 rc = SQLITE_RANGE;
1947 }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
1948 if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
1949 Fts5PoslistPopulator *aPopulator;
1950 int i;
1951 aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
1952 if( aPopulator==0 ) rc = SQLITE_NOMEM;
1953 for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
1954 int n; const char *z;
1955 rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
1956 if( rc==SQLITE_OK ){
1957 rc = sqlite3Fts5ExprPopulatePoslists(
1958 pConfig, pCsr->pExpr, aPopulator, i, z, n
1962 sqlite3_free(aPopulator);
1964 if( pCsr->pSorter ){
1965 sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
1968 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
1971 if( rc==SQLITE_OK ){
1972 if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
1973 Fts5Sorter *pSorter = pCsr->pSorter;
1974 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
1975 *pn = pSorter->aIdx[iPhrase] - i1;
1976 *pa = &pSorter->aPoslist[i1];
1977 }else{
1978 *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
1980 }else{
1981 *pa = 0;
1982 *pn = 0;
1986 return rc;
1990 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
1991 ** correctly for the current view. Return SQLITE_OK if successful, or an
1992 ** SQLite error code otherwise.
1994 static int fts5CacheInstArray(Fts5Cursor *pCsr){
1995 int rc = SQLITE_OK;
1996 Fts5PoslistReader *aIter; /* One iterator for each phrase */
1997 int nIter; /* Number of iterators/phrases */
1998 int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol;
2000 nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
2001 if( pCsr->aInstIter==0 ){
2002 sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nIter;
2003 pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
2005 aIter = pCsr->aInstIter;
2007 if( aIter ){
2008 int nInst = 0; /* Number instances seen so far */
2009 int i;
2011 /* Initialize all iterators */
2012 for(i=0; i<nIter && rc==SQLITE_OK; i++){
2013 const u8 *a;
2014 int n;
2015 rc = fts5CsrPoslist(pCsr, i, &a, &n);
2016 if( rc==SQLITE_OK ){
2017 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
2021 if( rc==SQLITE_OK ){
2022 while( 1 ){
2023 int *aInst;
2024 int iBest = -1;
2025 for(i=0; i<nIter; i++){
2026 if( (aIter[i].bEof==0)
2027 && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
2029 iBest = i;
2032 if( iBest<0 ) break;
2034 nInst++;
2035 if( nInst>=pCsr->nInstAlloc ){
2036 int nNewSize = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
2037 aInst = (int*)sqlite3_realloc64(
2038 pCsr->aInst, nNewSize*sizeof(int)*3
2040 if( aInst ){
2041 pCsr->aInst = aInst;
2042 pCsr->nInstAlloc = nNewSize;
2043 }else{
2044 nInst--;
2045 rc = SQLITE_NOMEM;
2046 break;
2050 aInst = &pCsr->aInst[3 * (nInst-1)];
2051 aInst[0] = iBest;
2052 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
2053 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
2054 if( aInst[1]<0 || aInst[1]>=nCol ){
2055 rc = FTS5_CORRUPT;
2056 break;
2058 sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
2062 pCsr->nInstCount = nInst;
2063 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
2065 return rc;
2068 static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
2069 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2070 int rc = SQLITE_OK;
2071 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
2072 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
2073 *pnInst = pCsr->nInstCount;
2075 return rc;
2078 static int fts5ApiInst(
2079 Fts5Context *pCtx,
2080 int iIdx,
2081 int *piPhrase,
2082 int *piCol,
2083 int *piOff
2085 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2086 int rc = SQLITE_OK;
2087 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
2088 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
2090 if( iIdx<0 || iIdx>=pCsr->nInstCount ){
2091 rc = SQLITE_RANGE;
2092 }else{
2093 *piPhrase = pCsr->aInst[iIdx*3];
2094 *piCol = pCsr->aInst[iIdx*3 + 1];
2095 *piOff = pCsr->aInst[iIdx*3 + 2];
2098 return rc;
2101 static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
2102 return fts5CursorRowid((Fts5Cursor*)pCtx);
2105 static int fts5ColumnSizeCb(
2106 void *pContext, /* Pointer to int */
2107 int tflags,
2108 const char *pUnused, /* Buffer containing token */
2109 int nUnused, /* Size of token in bytes */
2110 int iUnused1, /* Start offset of token */
2111 int iUnused2 /* End offset of token */
2113 int *pCnt = (int*)pContext;
2114 UNUSED_PARAM2(pUnused, nUnused);
2115 UNUSED_PARAM2(iUnused1, iUnused2);
2116 if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
2117 (*pCnt)++;
2119 return SQLITE_OK;
2122 static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
2123 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2124 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
2125 Fts5Config *pConfig = pTab->p.pConfig;
2126 int rc = SQLITE_OK;
2128 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
2129 if( pConfig->bColumnsize ){
2130 i64 iRowid = fts5CursorRowid(pCsr);
2131 rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
2132 }else if( pConfig->zContent==0 ){
2133 int i;
2134 for(i=0; i<pConfig->nCol; i++){
2135 if( pConfig->abUnindexed[i]==0 ){
2136 pCsr->aColumnSize[i] = -1;
2139 }else{
2140 int i;
2141 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
2142 if( pConfig->abUnindexed[i]==0 ){
2143 const char *z; int n;
2144 void *p = (void*)(&pCsr->aColumnSize[i]);
2145 pCsr->aColumnSize[i] = 0;
2146 rc = fts5ApiColumnText(pCtx, i, &z, &n);
2147 if( rc==SQLITE_OK ){
2148 rc = sqlite3Fts5Tokenize(
2149 pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
2155 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
2157 if( iCol<0 ){
2158 int i;
2159 *pnToken = 0;
2160 for(i=0; i<pConfig->nCol; i++){
2161 *pnToken += pCsr->aColumnSize[i];
2163 }else if( iCol<pConfig->nCol ){
2164 *pnToken = pCsr->aColumnSize[iCol];
2165 }else{
2166 *pnToken = 0;
2167 rc = SQLITE_RANGE;
2169 return rc;
2173 ** Implementation of the xSetAuxdata() method.
2175 static int fts5ApiSetAuxdata(
2176 Fts5Context *pCtx, /* Fts5 context */
2177 void *pPtr, /* Pointer to save as auxdata */
2178 void(*xDelete)(void*) /* Destructor for pPtr (or NULL) */
2180 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2181 Fts5Auxdata *pData;
2183 /* Search through the cursors list of Fts5Auxdata objects for one that
2184 ** corresponds to the currently executing auxiliary function. */
2185 for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
2186 if( pData->pAux==pCsr->pAux ) break;
2189 if( pData ){
2190 if( pData->xDelete ){
2191 pData->xDelete(pData->pPtr);
2193 }else{
2194 int rc = SQLITE_OK;
2195 pData = (Fts5Auxdata*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Auxdata));
2196 if( pData==0 ){
2197 if( xDelete ) xDelete(pPtr);
2198 return rc;
2200 pData->pAux = pCsr->pAux;
2201 pData->pNext = pCsr->pAuxdata;
2202 pCsr->pAuxdata = pData;
2205 pData->xDelete = xDelete;
2206 pData->pPtr = pPtr;
2207 return SQLITE_OK;
2210 static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
2211 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2212 Fts5Auxdata *pData;
2213 void *pRet = 0;
2215 for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
2216 if( pData->pAux==pCsr->pAux ) break;
2219 if( pData ){
2220 pRet = pData->pPtr;
2221 if( bClear ){
2222 pData->pPtr = 0;
2223 pData->xDelete = 0;
2227 return pRet;
2230 static void fts5ApiPhraseNext(
2231 Fts5Context *pUnused,
2232 Fts5PhraseIter *pIter,
2233 int *piCol, int *piOff
2235 UNUSED_PARAM(pUnused);
2236 if( pIter->a>=pIter->b ){
2237 *piCol = -1;
2238 *piOff = -1;
2239 }else{
2240 int iVal;
2241 pIter->a += fts5GetVarint32(pIter->a, iVal);
2242 if( iVal==1 ){
2243 pIter->a += fts5GetVarint32(pIter->a, iVal);
2244 *piCol = iVal;
2245 *piOff = 0;
2246 pIter->a += fts5GetVarint32(pIter->a, iVal);
2248 *piOff += (iVal-2);
2252 static int fts5ApiPhraseFirst(
2253 Fts5Context *pCtx,
2254 int iPhrase,
2255 Fts5PhraseIter *pIter,
2256 int *piCol, int *piOff
2258 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2259 int n;
2260 int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
2261 if( rc==SQLITE_OK ){
2262 assert( pIter->a || n==0 );
2263 pIter->b = (pIter->a ? &pIter->a[n] : 0);
2264 *piCol = 0;
2265 *piOff = 0;
2266 fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
2268 return rc;
2271 static void fts5ApiPhraseNextColumn(
2272 Fts5Context *pCtx,
2273 Fts5PhraseIter *pIter,
2274 int *piCol
2276 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2277 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
2279 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
2280 if( pIter->a>=pIter->b ){
2281 *piCol = -1;
2282 }else{
2283 int iIncr;
2284 pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
2285 *piCol += (iIncr-2);
2287 }else{
2288 while( 1 ){
2289 int dummy;
2290 if( pIter->a>=pIter->b ){
2291 *piCol = -1;
2292 return;
2294 if( pIter->a[0]==0x01 ) break;
2295 pIter->a += fts5GetVarint32(pIter->a, dummy);
2297 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
2301 static int fts5ApiPhraseFirstColumn(
2302 Fts5Context *pCtx,
2303 int iPhrase,
2304 Fts5PhraseIter *pIter,
2305 int *piCol
2307 int rc = SQLITE_OK;
2308 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2309 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
2311 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
2312 Fts5Sorter *pSorter = pCsr->pSorter;
2313 int n;
2314 if( pSorter ){
2315 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
2316 n = pSorter->aIdx[iPhrase] - i1;
2317 pIter->a = &pSorter->aPoslist[i1];
2318 }else{
2319 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
2321 if( rc==SQLITE_OK ){
2322 assert( pIter->a || n==0 );
2323 pIter->b = (pIter->a ? &pIter->a[n] : 0);
2324 *piCol = 0;
2325 fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
2327 }else{
2328 int n;
2329 rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
2330 if( rc==SQLITE_OK ){
2331 assert( pIter->a || n==0 );
2332 pIter->b = (pIter->a ? &pIter->a[n] : 0);
2333 if( n<=0 ){
2334 *piCol = -1;
2335 }else if( pIter->a[0]==0x01 ){
2336 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
2337 }else{
2338 *piCol = 0;
2343 return rc;
2347 ** xQueryToken() API implemenetation.
2349 static int fts5ApiQueryToken(
2350 Fts5Context* pCtx,
2351 int iPhrase,
2352 int iToken,
2353 const char **ppOut,
2354 int *pnOut
2356 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2357 return sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut);
2361 ** xInstToken() API implemenetation.
2363 static int fts5ApiInstToken(
2364 Fts5Context *pCtx,
2365 int iIdx,
2366 int iToken,
2367 const char **ppOut, int *pnOut
2369 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2370 int rc = SQLITE_OK;
2371 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
2372 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
2374 if( iIdx<0 || iIdx>=pCsr->nInstCount ){
2375 rc = SQLITE_RANGE;
2376 }else{
2377 int iPhrase = pCsr->aInst[iIdx*3];
2378 int iCol = pCsr->aInst[iIdx*3 + 1];
2379 int iOff = pCsr->aInst[iIdx*3 + 2];
2380 i64 iRowid = fts5CursorRowid(pCsr);
2381 rc = sqlite3Fts5ExprInstToken(
2382 pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut
2386 return rc;
2390 static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
2391 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
2394 static const Fts5ExtensionApi sFts5Api = {
2395 3, /* iVersion */
2396 fts5ApiUserData,
2397 fts5ApiColumnCount,
2398 fts5ApiRowCount,
2399 fts5ApiColumnTotalSize,
2400 fts5ApiTokenize,
2401 fts5ApiPhraseCount,
2402 fts5ApiPhraseSize,
2403 fts5ApiInstCount,
2404 fts5ApiInst,
2405 fts5ApiRowid,
2406 fts5ApiColumnText,
2407 fts5ApiColumnSize,
2408 fts5ApiQueryPhrase,
2409 fts5ApiSetAuxdata,
2410 fts5ApiGetAuxdata,
2411 fts5ApiPhraseFirst,
2412 fts5ApiPhraseNext,
2413 fts5ApiPhraseFirstColumn,
2414 fts5ApiPhraseNextColumn,
2415 fts5ApiQueryToken,
2416 fts5ApiInstToken
2420 ** Implementation of API function xQueryPhrase().
2422 static int fts5ApiQueryPhrase(
2423 Fts5Context *pCtx,
2424 int iPhrase,
2425 void *pUserData,
2426 int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
2428 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2429 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
2430 int rc;
2431 Fts5Cursor *pNew = 0;
2433 rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
2434 if( rc==SQLITE_OK ){
2435 pNew->ePlan = FTS5_PLAN_MATCH;
2436 pNew->iFirstRowid = SMALLEST_INT64;
2437 pNew->iLastRowid = LARGEST_INT64;
2438 pNew->base.pVtab = (sqlite3_vtab*)pTab;
2439 rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr);
2442 if( rc==SQLITE_OK ){
2443 for(rc = fts5CursorFirst(pTab, pNew, 0);
2444 rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0;
2445 rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew)
2447 rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData);
2448 if( rc!=SQLITE_OK ){
2449 if( rc==SQLITE_DONE ) rc = SQLITE_OK;
2450 break;
2455 fts5CloseMethod((sqlite3_vtab_cursor*)pNew);
2456 return rc;
2459 static void fts5ApiInvoke(
2460 Fts5Auxiliary *pAux,
2461 Fts5Cursor *pCsr,
2462 sqlite3_context *context,
2463 int argc,
2464 sqlite3_value **argv
2466 assert( pCsr->pAux==0 );
2467 pCsr->pAux = pAux;
2468 pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
2469 pCsr->pAux = 0;
2472 static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
2473 Fts5Cursor *pCsr;
2474 for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
2475 if( pCsr->iCsrId==iCsrId ) break;
2477 return pCsr;
2480 static void fts5ApiCallback(
2481 sqlite3_context *context,
2482 int argc,
2483 sqlite3_value **argv
2486 Fts5Auxiliary *pAux;
2487 Fts5Cursor *pCsr;
2488 i64 iCsrId;
2490 assert( argc>=1 );
2491 pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
2492 iCsrId = sqlite3_value_int64(argv[0]);
2494 pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
2495 if( pCsr==0 || pCsr->ePlan==0 ){
2496 char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
2497 sqlite3_result_error(context, zErr, -1);
2498 sqlite3_free(zErr);
2499 }else{
2500 fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
2506 ** Given cursor id iId, return a pointer to the corresponding Fts5Table
2507 ** object. Or NULL If the cursor id does not exist.
2509 Fts5Table *sqlite3Fts5TableFromCsrid(
2510 Fts5Global *pGlobal, /* FTS5 global context for db handle */
2511 i64 iCsrId /* Id of cursor to find */
2513 Fts5Cursor *pCsr;
2514 pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
2515 if( pCsr ){
2516 return (Fts5Table*)pCsr->base.pVtab;
2518 return 0;
2522 ** Return a "position-list blob" corresponding to the current position of
2523 ** cursor pCsr via sqlite3_result_blob(). A position-list blob contains
2524 ** the current position-list for each phrase in the query associated with
2525 ** cursor pCsr.
2527 ** A position-list blob begins with (nPhrase-1) varints, where nPhrase is
2528 ** the number of phrases in the query. Following the varints are the
2529 ** concatenated position lists for each phrase, in order.
2531 ** The first varint (if it exists) contains the size of the position list
2532 ** for phrase 0. The second (same disclaimer) contains the size of position
2533 ** list 1. And so on. There is no size field for the final position list,
2534 ** as it can be derived from the total size of the blob.
2536 static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
2537 int i;
2538 int rc = SQLITE_OK;
2539 int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
2540 Fts5Buffer val;
2542 memset(&val, 0, sizeof(Fts5Buffer));
2543 switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){
2544 case FTS5_DETAIL_FULL:
2546 /* Append the varints */
2547 for(i=0; i<(nPhrase-1); i++){
2548 const u8 *dummy;
2549 int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
2550 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
2553 /* Append the position lists */
2554 for(i=0; i<nPhrase; i++){
2555 const u8 *pPoslist;
2556 int nPoslist;
2557 nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
2558 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
2560 break;
2562 case FTS5_DETAIL_COLUMNS:
2564 /* Append the varints */
2565 for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){
2566 const u8 *dummy;
2567 int nByte;
2568 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte);
2569 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
2572 /* Append the position lists */
2573 for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
2574 const u8 *pPoslist;
2575 int nPoslist;
2576 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist);
2577 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
2579 break;
2581 default:
2582 break;
2585 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
2586 return rc;
2590 ** This is the xColumn method, called by SQLite to request a value from
2591 ** the row that the supplied cursor currently points to.
2593 static int fts5ColumnMethod(
2594 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
2595 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
2596 int iCol /* Index of column to read value from */
2598 Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
2599 Fts5Config *pConfig = pTab->p.pConfig;
2600 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
2601 int rc = SQLITE_OK;
2603 assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
2605 if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){
2606 if( iCol==pConfig->nCol ){
2607 sqlite3_result_int64(pCtx, pCsr->iSpecial);
2609 }else
2611 if( iCol==pConfig->nCol ){
2612 /* User is requesting the value of the special column with the same name
2613 ** as the table. Return the cursor integer id number. This value is only
2614 ** useful in that it may be passed as the first argument to an FTS5
2615 ** auxiliary function. */
2616 sqlite3_result_int64(pCtx, pCsr->iCsrId);
2617 }else if( iCol==pConfig->nCol+1 ){
2619 /* The value of the "rank" column. */
2620 if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
2621 fts5PoslistBlob(pCtx, pCsr);
2622 }else if(
2623 pCsr->ePlan==FTS5_PLAN_MATCH
2624 || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
2626 if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
2627 fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
2630 }else if( !fts5IsContentless(pTab) ){
2631 pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
2632 rc = fts5SeekCursor(pCsr, 1);
2633 if( rc==SQLITE_OK ){
2634 sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
2636 pConfig->pzErrmsg = 0;
2637 }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){
2638 char *zErr = sqlite3_mprintf("cannot UPDATE a subset of "
2639 "columns on fts5 contentless-delete table: %s", pConfig->zName
2641 sqlite3_result_error(pCtx, zErr, -1);
2642 sqlite3_free(zErr);
2644 return rc;
2649 ** This routine implements the xFindFunction method for the FTS3
2650 ** virtual table.
2652 static int fts5FindFunctionMethod(
2653 sqlite3_vtab *pVtab, /* Virtual table handle */
2654 int nUnused, /* Number of SQL function arguments */
2655 const char *zName, /* Name of SQL function */
2656 void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
2657 void **ppArg /* OUT: User data for *pxFunc */
2659 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2660 Fts5Auxiliary *pAux;
2662 UNUSED_PARAM(nUnused);
2663 pAux = fts5FindAuxiliary(pTab, zName);
2664 if( pAux ){
2665 *pxFunc = fts5ApiCallback;
2666 *ppArg = (void*)pAux;
2667 return 1;
2670 /* No function of the specified name was found. Return 0. */
2671 return 0;
2675 ** Implementation of FTS5 xRename method. Rename an fts5 table.
2677 static int fts5RenameMethod(
2678 sqlite3_vtab *pVtab, /* Virtual table handle */
2679 const char *zName /* New name of table */
2681 int rc;
2682 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2683 rc = sqlite3Fts5StorageRename(pTab->pStorage, zName);
2684 return rc;
2687 int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
2688 fts5TripCursors((Fts5FullTable*)pTab);
2689 return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage);
2693 ** The xSavepoint() method.
2695 ** Flush the contents of the pending-terms table to disk.
2697 static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
2698 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2699 int rc = SQLITE_OK;
2701 fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
2702 rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
2703 if( rc==SQLITE_OK ){
2704 pTab->iSavepoint = iSavepoint+1;
2706 return rc;
2710 ** The xRelease() method.
2712 ** This is a no-op.
2714 static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
2715 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2716 int rc = SQLITE_OK;
2717 fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
2718 if( (iSavepoint+1)<pTab->iSavepoint ){
2719 rc = sqlite3Fts5FlushToDisk(&pTab->p);
2720 if( rc==SQLITE_OK ){
2721 pTab->iSavepoint = iSavepoint;
2724 return rc;
2728 ** The xRollbackTo() method.
2730 ** Discard the contents of the pending terms table.
2732 static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
2733 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2734 int rc = SQLITE_OK;
2735 fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
2736 fts5TripCursors(pTab);
2737 if( (iSavepoint+1)<=pTab->iSavepoint ){
2738 pTab->p.pConfig->pgsz = 0;
2739 rc = sqlite3Fts5StorageRollback(pTab->pStorage);
2741 return rc;
2745 ** Register a new auxiliary function with global context pGlobal.
2747 static int fts5CreateAux(
2748 fts5_api *pApi, /* Global context (one per db handle) */
2749 const char *zName, /* Name of new function */
2750 void *pUserData, /* User data for aux. function */
2751 fts5_extension_function xFunc, /* Aux. function implementation */
2752 void(*xDestroy)(void*) /* Destructor for pUserData */
2754 Fts5Global *pGlobal = (Fts5Global*)pApi;
2755 int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
2756 if( rc==SQLITE_OK ){
2757 Fts5Auxiliary *pAux;
2758 sqlite3_int64 nName; /* Size of zName in bytes, including \0 */
2759 sqlite3_int64 nByte; /* Bytes of space to allocate */
2761 nName = strlen(zName) + 1;
2762 nByte = sizeof(Fts5Auxiliary) + nName;
2763 pAux = (Fts5Auxiliary*)sqlite3_malloc64(nByte);
2764 if( pAux ){
2765 memset(pAux, 0, (size_t)nByte);
2766 pAux->zFunc = (char*)&pAux[1];
2767 memcpy(pAux->zFunc, zName, nName);
2768 pAux->pGlobal = pGlobal;
2769 pAux->pUserData = pUserData;
2770 pAux->xFunc = xFunc;
2771 pAux->xDestroy = xDestroy;
2772 pAux->pNext = pGlobal->pAux;
2773 pGlobal->pAux = pAux;
2774 }else{
2775 rc = SQLITE_NOMEM;
2779 return rc;
2783 ** Register a new tokenizer. This is the implementation of the
2784 ** fts5_api.xCreateTokenizer() method.
2786 static int fts5CreateTokenizer(
2787 fts5_api *pApi, /* Global context (one per db handle) */
2788 const char *zName, /* Name of new function */
2789 void *pUserData, /* User data for aux. function */
2790 fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
2791 void(*xDestroy)(void*) /* Destructor for pUserData */
2793 Fts5Global *pGlobal = (Fts5Global*)pApi;
2794 Fts5TokenizerModule *pNew;
2795 sqlite3_int64 nName; /* Size of zName and its \0 terminator */
2796 sqlite3_int64 nByte; /* Bytes of space to allocate */
2797 int rc = SQLITE_OK;
2799 nName = strlen(zName) + 1;
2800 nByte = sizeof(Fts5TokenizerModule) + nName;
2801 pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte);
2802 if( pNew ){
2803 memset(pNew, 0, (size_t)nByte);
2804 pNew->zName = (char*)&pNew[1];
2805 memcpy(pNew->zName, zName, nName);
2806 pNew->pUserData = pUserData;
2807 pNew->x = *pTokenizer;
2808 pNew->xDestroy = xDestroy;
2809 pNew->pNext = pGlobal->pTok;
2810 pGlobal->pTok = pNew;
2811 if( pNew->pNext==0 ){
2812 pGlobal->pDfltTok = pNew;
2814 }else{
2815 rc = SQLITE_NOMEM;
2818 return rc;
2821 static Fts5TokenizerModule *fts5LocateTokenizer(
2822 Fts5Global *pGlobal,
2823 const char *zName
2825 Fts5TokenizerModule *pMod = 0;
2827 if( zName==0 ){
2828 pMod = pGlobal->pDfltTok;
2829 }else{
2830 for(pMod=pGlobal->pTok; pMod; pMod=pMod->pNext){
2831 if( sqlite3_stricmp(zName, pMod->zName)==0 ) break;
2835 return pMod;
2839 ** Find a tokenizer. This is the implementation of the
2840 ** fts5_api.xFindTokenizer() method.
2842 static int fts5FindTokenizer(
2843 fts5_api *pApi, /* Global context (one per db handle) */
2844 const char *zName, /* Name of new function */
2845 void **ppUserData,
2846 fts5_tokenizer *pTokenizer /* Populate this object */
2848 int rc = SQLITE_OK;
2849 Fts5TokenizerModule *pMod;
2851 pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
2852 if( pMod ){
2853 *pTokenizer = pMod->x;
2854 *ppUserData = pMod->pUserData;
2855 }else{
2856 memset(pTokenizer, 0, sizeof(fts5_tokenizer));
2857 rc = SQLITE_ERROR;
2860 return rc;
2863 int sqlite3Fts5GetTokenizer(
2864 Fts5Global *pGlobal,
2865 const char **azArg,
2866 int nArg,
2867 Fts5Config *pConfig,
2868 char **pzErr
2870 Fts5TokenizerModule *pMod;
2871 int rc = SQLITE_OK;
2873 pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
2874 if( pMod==0 ){
2875 assert( nArg>0 );
2876 rc = SQLITE_ERROR;
2877 *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
2878 }else{
2879 rc = pMod->x.xCreate(
2880 pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
2882 pConfig->pTokApi = &pMod->x;
2883 if( rc!=SQLITE_OK ){
2884 if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor");
2885 }else{
2886 pConfig->ePattern = sqlite3Fts5TokenizerPattern(
2887 pMod->x.xCreate, pConfig->pTok
2892 if( rc!=SQLITE_OK ){
2893 pConfig->pTokApi = 0;
2894 pConfig->pTok = 0;
2897 return rc;
2900 static void fts5ModuleDestroy(void *pCtx){
2901 Fts5TokenizerModule *pTok, *pNextTok;
2902 Fts5Auxiliary *pAux, *pNextAux;
2903 Fts5Global *pGlobal = (Fts5Global*)pCtx;
2905 for(pAux=pGlobal->pAux; pAux; pAux=pNextAux){
2906 pNextAux = pAux->pNext;
2907 if( pAux->xDestroy ) pAux->xDestroy(pAux->pUserData);
2908 sqlite3_free(pAux);
2911 for(pTok=pGlobal->pTok; pTok; pTok=pNextTok){
2912 pNextTok = pTok->pNext;
2913 if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData);
2914 sqlite3_free(pTok);
2917 sqlite3_free(pGlobal);
2920 static void fts5Fts5Func(
2921 sqlite3_context *pCtx, /* Function call context */
2922 int nArg, /* Number of args */
2923 sqlite3_value **apArg /* Function arguments */
2925 Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
2926 fts5_api **ppApi;
2927 UNUSED_PARAM(nArg);
2928 assert( nArg==1 );
2929 ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr");
2930 if( ppApi ) *ppApi = &pGlobal->api;
2934 ** Implementation of fts5_source_id() function.
2936 static void fts5SourceIdFunc(
2937 sqlite3_context *pCtx, /* Function call context */
2938 int nArg, /* Number of args */
2939 sqlite3_value **apUnused /* Function arguments */
2941 assert( nArg==0 );
2942 UNUSED_PARAM2(nArg, apUnused);
2943 sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
2947 ** Return true if zName is the extension on one of the shadow tables used
2948 ** by this module.
2950 static int fts5ShadowName(const char *zName){
2951 static const char *azName[] = {
2952 "config", "content", "data", "docsize", "idx"
2954 unsigned int i;
2955 for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
2956 if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
2958 return 0;
2962 ** Run an integrity check on the FTS5 data structures. Return a string
2963 ** if anything is found amiss. Return a NULL pointer if everything is
2964 ** OK.
2966 static int fts5IntegrityMethod(
2967 sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */
2968 const char *zSchema, /* Name of schema in which this table lives */
2969 const char *zTabname, /* Name of the table itself */
2970 int isQuick, /* True if this is a quick-check */
2971 char **pzErr /* Write error message here */
2973 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2974 int rc;
2976 assert( pzErr!=0 && *pzErr==0 );
2977 UNUSED_PARAM(isQuick);
2978 rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
2979 if( (rc&0xff)==SQLITE_CORRUPT ){
2980 *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
2981 zSchema, zTabname);
2982 }else if( rc!=SQLITE_OK ){
2983 *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
2984 " FTS5 table %s.%s: %s",
2985 zSchema, zTabname, sqlite3_errstr(rc));
2987 sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
2989 return SQLITE_OK;
2992 static int fts5Init(sqlite3 *db){
2993 static const sqlite3_module fts5Mod = {
2994 /* iVersion */ 4,
2995 /* xCreate */ fts5CreateMethod,
2996 /* xConnect */ fts5ConnectMethod,
2997 /* xBestIndex */ fts5BestIndexMethod,
2998 /* xDisconnect */ fts5DisconnectMethod,
2999 /* xDestroy */ fts5DestroyMethod,
3000 /* xOpen */ fts5OpenMethod,
3001 /* xClose */ fts5CloseMethod,
3002 /* xFilter */ fts5FilterMethod,
3003 /* xNext */ fts5NextMethod,
3004 /* xEof */ fts5EofMethod,
3005 /* xColumn */ fts5ColumnMethod,
3006 /* xRowid */ fts5RowidMethod,
3007 /* xUpdate */ fts5UpdateMethod,
3008 /* xBegin */ fts5BeginMethod,
3009 /* xSync */ fts5SyncMethod,
3010 /* xCommit */ fts5CommitMethod,
3011 /* xRollback */ fts5RollbackMethod,
3012 /* xFindFunction */ fts5FindFunctionMethod,
3013 /* xRename */ fts5RenameMethod,
3014 /* xSavepoint */ fts5SavepointMethod,
3015 /* xRelease */ fts5ReleaseMethod,
3016 /* xRollbackTo */ fts5RollbackToMethod,
3017 /* xShadowName */ fts5ShadowName,
3018 /* xIntegrity */ fts5IntegrityMethod
3021 int rc;
3022 Fts5Global *pGlobal = 0;
3024 pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
3025 if( pGlobal==0 ){
3026 rc = SQLITE_NOMEM;
3027 }else{
3028 void *p = (void*)pGlobal;
3029 memset(pGlobal, 0, sizeof(Fts5Global));
3030 pGlobal->db = db;
3031 pGlobal->api.iVersion = 2;
3032 pGlobal->api.xCreateFunction = fts5CreateAux;
3033 pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
3034 pGlobal->api.xFindTokenizer = fts5FindTokenizer;
3035 rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
3036 if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
3037 if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
3038 if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
3039 if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
3040 if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
3041 if( rc==SQLITE_OK ){
3042 rc = sqlite3_create_function(
3043 db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
3046 if( rc==SQLITE_OK ){
3047 rc = sqlite3_create_function(
3048 db, "fts5_source_id", 0,
3049 SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS,
3050 p, fts5SourceIdFunc, 0, 0
3055 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
3056 ** fts5_test_mi.c is compiled and linked into the executable. And call
3057 ** its entry point to enable the matchinfo() demo. */
3058 #ifdef SQLITE_FTS5_ENABLE_TEST_MI
3059 if( rc==SQLITE_OK ){
3060 extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
3061 rc = sqlite3Fts5TestRegisterMatchinfo(db);
3063 #endif
3065 return rc;
3069 ** The following functions are used to register the module with SQLite. If
3070 ** this module is being built as part of the SQLite core (SQLITE_CORE is
3071 ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
3073 ** Or, if this module is being built as a loadable extension,
3074 ** sqlite3Fts5Init() is omitted and the two standard entry points
3075 ** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
3077 #ifndef SQLITE_CORE
3078 #ifdef _WIN32
3079 __declspec(dllexport)
3080 #endif
3081 int sqlite3_fts_init(
3082 sqlite3 *db,
3083 char **pzErrMsg,
3084 const sqlite3_api_routines *pApi
3086 SQLITE_EXTENSION_INIT2(pApi);
3087 (void)pzErrMsg; /* Unused parameter */
3088 return fts5Init(db);
3091 #ifdef _WIN32
3092 __declspec(dllexport)
3093 #endif
3094 int sqlite3_fts5_init(
3095 sqlite3 *db,
3096 char **pzErrMsg,
3097 const sqlite3_api_routines *pApi
3099 SQLITE_EXTENSION_INIT2(pApi);
3100 (void)pzErrMsg; /* Unused parameter */
3101 return fts5Init(db);
3103 #else
3104 int sqlite3Fts5Init(sqlite3 *db){
3105 return fts5Init(db);
3107 #endif