Fixes default log output to console for macOS
[sqlcipher.git] / ext / fts5 / fts5_main.c
blob837ea4015d77dbba036c4f3c520d0f49c803a841
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);
1703 bUpdateOrDelete = 1;
1705 }else{
1706 rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
1708 }else{
1709 /* A regular INSERT, UPDATE or DELETE statement. The trick here is that
1710 ** any conflict on the rowid value must be detected before any
1711 ** modifications are made to the database file. There are 4 cases:
1713 ** 1) DELETE
1714 ** 2) UPDATE (rowid not modified)
1715 ** 3) UPDATE (rowid modified)
1716 ** 4) INSERT
1718 ** Cases 3 and 4 may violate the rowid constraint.
1720 int eConflict = SQLITE_ABORT;
1721 if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->bContentlessDelete ){
1722 eConflict = sqlite3_vtab_on_conflict(pConfig->db);
1725 assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
1726 assert( nArg!=1 || eType0==SQLITE_INTEGER );
1728 /* Filter out attempts to run UPDATE or DELETE on contentless tables.
1729 ** This is not suported. Except - they are both supported if the CREATE
1730 ** VIRTUAL TABLE statement contained "contentless_delete=1". */
1731 if( eType0==SQLITE_INTEGER
1732 && pConfig->eContent==FTS5_CONTENT_NONE
1733 && pConfig->bContentlessDelete==0
1735 pTab->p.base.zErrMsg = sqlite3_mprintf(
1736 "cannot %s contentless fts5 table: %s",
1737 (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
1739 rc = SQLITE_ERROR;
1742 /* DELETE */
1743 else if( nArg==1 ){
1744 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
1745 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
1746 bUpdateOrDelete = 1;
1749 /* INSERT or UPDATE */
1750 else{
1751 int eType1 = sqlite3_value_numeric_type(apVal[1]);
1753 if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
1754 rc = SQLITE_MISMATCH;
1757 else if( eType0!=SQLITE_INTEGER ){
1758 /* An INSERT statement. If the conflict-mode is REPLACE, first remove
1759 ** the current entry (if any). */
1760 if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
1761 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
1762 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
1763 bUpdateOrDelete = 1;
1765 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1768 /* UPDATE */
1769 else{
1770 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
1771 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
1772 if( eType1==SQLITE_INTEGER && iOld!=iNew ){
1773 if( eConflict==SQLITE_REPLACE ){
1774 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1775 if( rc==SQLITE_OK ){
1776 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
1778 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1779 }else{
1780 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
1781 if( rc==SQLITE_OK ){
1782 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1784 if( rc==SQLITE_OK ){
1785 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
1788 }else{
1789 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1790 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1792 bUpdateOrDelete = 1;
1797 if( rc==SQLITE_OK
1798 && bUpdateOrDelete
1799 && pConfig->bSecureDelete
1800 && pConfig->iVersion==FTS5_CURRENT_VERSION
1802 rc = sqlite3Fts5StorageConfigValue(
1803 pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
1805 if( rc==SQLITE_OK ){
1806 pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
1810 pTab->p.pConfig->pzErrmsg = 0;
1811 return rc;
1815 ** Implementation of xSync() method.
1817 static int fts5SyncMethod(sqlite3_vtab *pVtab){
1818 int rc;
1819 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
1820 fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
1821 pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
1822 rc = sqlite3Fts5FlushToDisk(&pTab->p);
1823 pTab->p.pConfig->pzErrmsg = 0;
1824 return rc;
1828 ** Implementation of xBegin() method.
1830 static int fts5BeginMethod(sqlite3_vtab *pVtab){
1831 fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
1832 fts5NewTransaction((Fts5FullTable*)pVtab);
1833 return SQLITE_OK;
1837 ** Implementation of xCommit() method. This is a no-op. The contents of
1838 ** the pending-terms hash-table have already been flushed into the database
1839 ** by fts5SyncMethod().
1841 static int fts5CommitMethod(sqlite3_vtab *pVtab){
1842 UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */
1843 fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_COMMIT, 0);
1844 return SQLITE_OK;
1848 ** Implementation of xRollback(). Discard the contents of the pending-terms
1849 ** hash-table. Any changes made to the database are reverted by SQLite.
1851 static int fts5RollbackMethod(sqlite3_vtab *pVtab){
1852 int rc;
1853 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
1854 fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
1855 rc = sqlite3Fts5StorageRollback(pTab->pStorage);
1856 return rc;
1859 static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*);
1861 static void *fts5ApiUserData(Fts5Context *pCtx){
1862 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1863 return pCsr->pAux->pUserData;
1866 static int fts5ApiColumnCount(Fts5Context *pCtx){
1867 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1868 return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol;
1871 static int fts5ApiColumnTotalSize(
1872 Fts5Context *pCtx,
1873 int iCol,
1874 sqlite3_int64 *pnToken
1876 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1877 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1878 return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken);
1881 static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
1882 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1883 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
1884 return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
1887 static int fts5ApiTokenize(
1888 Fts5Context *pCtx,
1889 const char *pText, int nText,
1890 void *pUserData,
1891 int (*xToken)(void*, int, const char*, int, int, int)
1893 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1894 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1895 return sqlite3Fts5Tokenize(
1896 pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
1900 static int fts5ApiPhraseCount(Fts5Context *pCtx){
1901 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1902 return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
1905 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
1906 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1907 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
1910 static int fts5ApiColumnText(
1911 Fts5Context *pCtx,
1912 int iCol,
1913 const char **pz,
1914 int *pn
1916 int rc = SQLITE_OK;
1917 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1918 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1919 if( iCol<0 || iCol>=pTab->pConfig->nCol ){
1920 rc = SQLITE_RANGE;
1921 }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
1922 || pCsr->ePlan==FTS5_PLAN_SPECIAL
1924 *pz = 0;
1925 *pn = 0;
1926 }else{
1927 rc = fts5SeekCursor(pCsr, 0);
1928 if( rc==SQLITE_OK ){
1929 *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
1930 *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
1933 return rc;
1936 static int fts5CsrPoslist(
1937 Fts5Cursor *pCsr,
1938 int iPhrase,
1939 const u8 **pa,
1940 int *pn
1942 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
1943 int rc = SQLITE_OK;
1944 int bLive = (pCsr->pSorter==0);
1946 if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
1947 rc = SQLITE_RANGE;
1948 }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
1949 if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
1950 Fts5PoslistPopulator *aPopulator;
1951 int i;
1952 aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
1953 if( aPopulator==0 ) rc = SQLITE_NOMEM;
1954 for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
1955 int n; const char *z;
1956 rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
1957 if( rc==SQLITE_OK ){
1958 rc = sqlite3Fts5ExprPopulatePoslists(
1959 pConfig, pCsr->pExpr, aPopulator, i, z, n
1963 sqlite3_free(aPopulator);
1965 if( pCsr->pSorter ){
1966 sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
1969 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
1972 if( rc==SQLITE_OK ){
1973 if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
1974 Fts5Sorter *pSorter = pCsr->pSorter;
1975 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
1976 *pn = pSorter->aIdx[iPhrase] - i1;
1977 *pa = &pSorter->aPoslist[i1];
1978 }else{
1979 *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
1981 }else{
1982 *pa = 0;
1983 *pn = 0;
1987 return rc;
1991 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
1992 ** correctly for the current view. Return SQLITE_OK if successful, or an
1993 ** SQLite error code otherwise.
1995 static int fts5CacheInstArray(Fts5Cursor *pCsr){
1996 int rc = SQLITE_OK;
1997 Fts5PoslistReader *aIter; /* One iterator for each phrase */
1998 int nIter; /* Number of iterators/phrases */
1999 int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol;
2001 nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
2002 if( pCsr->aInstIter==0 ){
2003 sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nIter;
2004 pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
2006 aIter = pCsr->aInstIter;
2008 if( aIter ){
2009 int nInst = 0; /* Number instances seen so far */
2010 int i;
2012 /* Initialize all iterators */
2013 for(i=0; i<nIter && rc==SQLITE_OK; i++){
2014 const u8 *a;
2015 int n;
2016 rc = fts5CsrPoslist(pCsr, i, &a, &n);
2017 if( rc==SQLITE_OK ){
2018 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
2022 if( rc==SQLITE_OK ){
2023 while( 1 ){
2024 int *aInst;
2025 int iBest = -1;
2026 for(i=0; i<nIter; i++){
2027 if( (aIter[i].bEof==0)
2028 && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
2030 iBest = i;
2033 if( iBest<0 ) break;
2035 nInst++;
2036 if( nInst>=pCsr->nInstAlloc ){
2037 int nNewSize = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
2038 aInst = (int*)sqlite3_realloc64(
2039 pCsr->aInst, nNewSize*sizeof(int)*3
2041 if( aInst ){
2042 pCsr->aInst = aInst;
2043 pCsr->nInstAlloc = nNewSize;
2044 }else{
2045 nInst--;
2046 rc = SQLITE_NOMEM;
2047 break;
2051 aInst = &pCsr->aInst[3 * (nInst-1)];
2052 aInst[0] = iBest;
2053 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
2054 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
2055 if( aInst[1]<0 || aInst[1]>=nCol ){
2056 rc = FTS5_CORRUPT;
2057 break;
2059 sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
2063 pCsr->nInstCount = nInst;
2064 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
2066 return rc;
2069 static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
2070 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2071 int rc = SQLITE_OK;
2072 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
2073 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
2074 *pnInst = pCsr->nInstCount;
2076 return rc;
2079 static int fts5ApiInst(
2080 Fts5Context *pCtx,
2081 int iIdx,
2082 int *piPhrase,
2083 int *piCol,
2084 int *piOff
2086 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2087 int rc = SQLITE_OK;
2088 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
2089 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
2091 if( iIdx<0 || iIdx>=pCsr->nInstCount ){
2092 rc = SQLITE_RANGE;
2093 }else{
2094 *piPhrase = pCsr->aInst[iIdx*3];
2095 *piCol = pCsr->aInst[iIdx*3 + 1];
2096 *piOff = pCsr->aInst[iIdx*3 + 2];
2099 return rc;
2102 static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
2103 return fts5CursorRowid((Fts5Cursor*)pCtx);
2106 static int fts5ColumnSizeCb(
2107 void *pContext, /* Pointer to int */
2108 int tflags,
2109 const char *pUnused, /* Buffer containing token */
2110 int nUnused, /* Size of token in bytes */
2111 int iUnused1, /* Start offset of token */
2112 int iUnused2 /* End offset of token */
2114 int *pCnt = (int*)pContext;
2115 UNUSED_PARAM2(pUnused, nUnused);
2116 UNUSED_PARAM2(iUnused1, iUnused2);
2117 if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
2118 (*pCnt)++;
2120 return SQLITE_OK;
2123 static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
2124 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2125 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
2126 Fts5Config *pConfig = pTab->p.pConfig;
2127 int rc = SQLITE_OK;
2129 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
2130 if( pConfig->bColumnsize ){
2131 i64 iRowid = fts5CursorRowid(pCsr);
2132 rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
2133 }else if( pConfig->zContent==0 ){
2134 int i;
2135 for(i=0; i<pConfig->nCol; i++){
2136 if( pConfig->abUnindexed[i]==0 ){
2137 pCsr->aColumnSize[i] = -1;
2140 }else{
2141 int i;
2142 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
2143 if( pConfig->abUnindexed[i]==0 ){
2144 const char *z; int n;
2145 void *p = (void*)(&pCsr->aColumnSize[i]);
2146 pCsr->aColumnSize[i] = 0;
2147 rc = fts5ApiColumnText(pCtx, i, &z, &n);
2148 if( rc==SQLITE_OK ){
2149 rc = sqlite3Fts5Tokenize(
2150 pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
2156 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
2158 if( iCol<0 ){
2159 int i;
2160 *pnToken = 0;
2161 for(i=0; i<pConfig->nCol; i++){
2162 *pnToken += pCsr->aColumnSize[i];
2164 }else if( iCol<pConfig->nCol ){
2165 *pnToken = pCsr->aColumnSize[iCol];
2166 }else{
2167 *pnToken = 0;
2168 rc = SQLITE_RANGE;
2170 return rc;
2174 ** Implementation of the xSetAuxdata() method.
2176 static int fts5ApiSetAuxdata(
2177 Fts5Context *pCtx, /* Fts5 context */
2178 void *pPtr, /* Pointer to save as auxdata */
2179 void(*xDelete)(void*) /* Destructor for pPtr (or NULL) */
2181 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2182 Fts5Auxdata *pData;
2184 /* Search through the cursors list of Fts5Auxdata objects for one that
2185 ** corresponds to the currently executing auxiliary function. */
2186 for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
2187 if( pData->pAux==pCsr->pAux ) break;
2190 if( pData ){
2191 if( pData->xDelete ){
2192 pData->xDelete(pData->pPtr);
2194 }else{
2195 int rc = SQLITE_OK;
2196 pData = (Fts5Auxdata*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Auxdata));
2197 if( pData==0 ){
2198 if( xDelete ) xDelete(pPtr);
2199 return rc;
2201 pData->pAux = pCsr->pAux;
2202 pData->pNext = pCsr->pAuxdata;
2203 pCsr->pAuxdata = pData;
2206 pData->xDelete = xDelete;
2207 pData->pPtr = pPtr;
2208 return SQLITE_OK;
2211 static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
2212 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2213 Fts5Auxdata *pData;
2214 void *pRet = 0;
2216 for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
2217 if( pData->pAux==pCsr->pAux ) break;
2220 if( pData ){
2221 pRet = pData->pPtr;
2222 if( bClear ){
2223 pData->pPtr = 0;
2224 pData->xDelete = 0;
2228 return pRet;
2231 static void fts5ApiPhraseNext(
2232 Fts5Context *pUnused,
2233 Fts5PhraseIter *pIter,
2234 int *piCol, int *piOff
2236 UNUSED_PARAM(pUnused);
2237 if( pIter->a>=pIter->b ){
2238 *piCol = -1;
2239 *piOff = -1;
2240 }else{
2241 int iVal;
2242 pIter->a += fts5GetVarint32(pIter->a, iVal);
2243 if( iVal==1 ){
2244 pIter->a += fts5GetVarint32(pIter->a, iVal);
2245 *piCol = iVal;
2246 *piOff = 0;
2247 pIter->a += fts5GetVarint32(pIter->a, iVal);
2249 *piOff += (iVal-2);
2253 static int fts5ApiPhraseFirst(
2254 Fts5Context *pCtx,
2255 int iPhrase,
2256 Fts5PhraseIter *pIter,
2257 int *piCol, int *piOff
2259 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2260 int n;
2261 int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
2262 if( rc==SQLITE_OK ){
2263 assert( pIter->a || n==0 );
2264 pIter->b = (pIter->a ? &pIter->a[n] : 0);
2265 *piCol = 0;
2266 *piOff = 0;
2267 fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
2269 return rc;
2272 static void fts5ApiPhraseNextColumn(
2273 Fts5Context *pCtx,
2274 Fts5PhraseIter *pIter,
2275 int *piCol
2277 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2278 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
2280 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
2281 if( pIter->a>=pIter->b ){
2282 *piCol = -1;
2283 }else{
2284 int iIncr;
2285 pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
2286 *piCol += (iIncr-2);
2288 }else{
2289 while( 1 ){
2290 int dummy;
2291 if( pIter->a>=pIter->b ){
2292 *piCol = -1;
2293 return;
2295 if( pIter->a[0]==0x01 ) break;
2296 pIter->a += fts5GetVarint32(pIter->a, dummy);
2298 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
2302 static int fts5ApiPhraseFirstColumn(
2303 Fts5Context *pCtx,
2304 int iPhrase,
2305 Fts5PhraseIter *pIter,
2306 int *piCol
2308 int rc = SQLITE_OK;
2309 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2310 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
2312 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
2313 Fts5Sorter *pSorter = pCsr->pSorter;
2314 int n;
2315 if( pSorter ){
2316 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
2317 n = pSorter->aIdx[iPhrase] - i1;
2318 pIter->a = &pSorter->aPoslist[i1];
2319 }else{
2320 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
2322 if( rc==SQLITE_OK ){
2323 assert( pIter->a || n==0 );
2324 pIter->b = (pIter->a ? &pIter->a[n] : 0);
2325 *piCol = 0;
2326 fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
2328 }else{
2329 int n;
2330 rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
2331 if( rc==SQLITE_OK ){
2332 assert( pIter->a || n==0 );
2333 pIter->b = (pIter->a ? &pIter->a[n] : 0);
2334 if( n<=0 ){
2335 *piCol = -1;
2336 }else if( pIter->a[0]==0x01 ){
2337 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
2338 }else{
2339 *piCol = 0;
2344 return rc;
2348 ** xQueryToken() API implemenetation.
2350 static int fts5ApiQueryToken(
2351 Fts5Context* pCtx,
2352 int iPhrase,
2353 int iToken,
2354 const char **ppOut,
2355 int *pnOut
2357 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2358 return sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut);
2362 ** xInstToken() API implemenetation.
2364 static int fts5ApiInstToken(
2365 Fts5Context *pCtx,
2366 int iIdx,
2367 int iToken,
2368 const char **ppOut, int *pnOut
2370 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2371 int rc = SQLITE_OK;
2372 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
2373 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
2375 if( iIdx<0 || iIdx>=pCsr->nInstCount ){
2376 rc = SQLITE_RANGE;
2377 }else{
2378 int iPhrase = pCsr->aInst[iIdx*3];
2379 int iCol = pCsr->aInst[iIdx*3 + 1];
2380 int iOff = pCsr->aInst[iIdx*3 + 2];
2381 i64 iRowid = fts5CursorRowid(pCsr);
2382 rc = sqlite3Fts5ExprInstToken(
2383 pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut
2387 return rc;
2391 static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
2392 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
2395 static const Fts5ExtensionApi sFts5Api = {
2396 3, /* iVersion */
2397 fts5ApiUserData,
2398 fts5ApiColumnCount,
2399 fts5ApiRowCount,
2400 fts5ApiColumnTotalSize,
2401 fts5ApiTokenize,
2402 fts5ApiPhraseCount,
2403 fts5ApiPhraseSize,
2404 fts5ApiInstCount,
2405 fts5ApiInst,
2406 fts5ApiRowid,
2407 fts5ApiColumnText,
2408 fts5ApiColumnSize,
2409 fts5ApiQueryPhrase,
2410 fts5ApiSetAuxdata,
2411 fts5ApiGetAuxdata,
2412 fts5ApiPhraseFirst,
2413 fts5ApiPhraseNext,
2414 fts5ApiPhraseFirstColumn,
2415 fts5ApiPhraseNextColumn,
2416 fts5ApiQueryToken,
2417 fts5ApiInstToken
2421 ** Implementation of API function xQueryPhrase().
2423 static int fts5ApiQueryPhrase(
2424 Fts5Context *pCtx,
2425 int iPhrase,
2426 void *pUserData,
2427 int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
2429 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2430 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
2431 int rc;
2432 Fts5Cursor *pNew = 0;
2434 rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
2435 if( rc==SQLITE_OK ){
2436 pNew->ePlan = FTS5_PLAN_MATCH;
2437 pNew->iFirstRowid = SMALLEST_INT64;
2438 pNew->iLastRowid = LARGEST_INT64;
2439 pNew->base.pVtab = (sqlite3_vtab*)pTab;
2440 rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr);
2443 if( rc==SQLITE_OK ){
2444 for(rc = fts5CursorFirst(pTab, pNew, 0);
2445 rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0;
2446 rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew)
2448 rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData);
2449 if( rc!=SQLITE_OK ){
2450 if( rc==SQLITE_DONE ) rc = SQLITE_OK;
2451 break;
2456 fts5CloseMethod((sqlite3_vtab_cursor*)pNew);
2457 return rc;
2460 static void fts5ApiInvoke(
2461 Fts5Auxiliary *pAux,
2462 Fts5Cursor *pCsr,
2463 sqlite3_context *context,
2464 int argc,
2465 sqlite3_value **argv
2467 assert( pCsr->pAux==0 );
2468 pCsr->pAux = pAux;
2469 pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
2470 pCsr->pAux = 0;
2473 static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
2474 Fts5Cursor *pCsr;
2475 for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
2476 if( pCsr->iCsrId==iCsrId ) break;
2478 return pCsr;
2481 static void fts5ApiCallback(
2482 sqlite3_context *context,
2483 int argc,
2484 sqlite3_value **argv
2487 Fts5Auxiliary *pAux;
2488 Fts5Cursor *pCsr;
2489 i64 iCsrId;
2491 assert( argc>=1 );
2492 pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
2493 iCsrId = sqlite3_value_int64(argv[0]);
2495 pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
2496 if( pCsr==0 || pCsr->ePlan==0 ){
2497 char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
2498 sqlite3_result_error(context, zErr, -1);
2499 sqlite3_free(zErr);
2500 }else{
2501 fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
2507 ** Given cursor id iId, return a pointer to the corresponding Fts5Table
2508 ** object. Or NULL If the cursor id does not exist.
2510 Fts5Table *sqlite3Fts5TableFromCsrid(
2511 Fts5Global *pGlobal, /* FTS5 global context for db handle */
2512 i64 iCsrId /* Id of cursor to find */
2514 Fts5Cursor *pCsr;
2515 pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
2516 if( pCsr ){
2517 return (Fts5Table*)pCsr->base.pVtab;
2519 return 0;
2523 ** Return a "position-list blob" corresponding to the current position of
2524 ** cursor pCsr via sqlite3_result_blob(). A position-list blob contains
2525 ** the current position-list for each phrase in the query associated with
2526 ** cursor pCsr.
2528 ** A position-list blob begins with (nPhrase-1) varints, where nPhrase is
2529 ** the number of phrases in the query. Following the varints are the
2530 ** concatenated position lists for each phrase, in order.
2532 ** The first varint (if it exists) contains the size of the position list
2533 ** for phrase 0. The second (same disclaimer) contains the size of position
2534 ** list 1. And so on. There is no size field for the final position list,
2535 ** as it can be derived from the total size of the blob.
2537 static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
2538 int i;
2539 int rc = SQLITE_OK;
2540 int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
2541 Fts5Buffer val;
2543 memset(&val, 0, sizeof(Fts5Buffer));
2544 switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){
2545 case FTS5_DETAIL_FULL:
2547 /* Append the varints */
2548 for(i=0; i<(nPhrase-1); i++){
2549 const u8 *dummy;
2550 int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
2551 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
2554 /* Append the position lists */
2555 for(i=0; i<nPhrase; i++){
2556 const u8 *pPoslist;
2557 int nPoslist;
2558 nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
2559 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
2561 break;
2563 case FTS5_DETAIL_COLUMNS:
2565 /* Append the varints */
2566 for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){
2567 const u8 *dummy;
2568 int nByte;
2569 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte);
2570 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
2573 /* Append the position lists */
2574 for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
2575 const u8 *pPoslist;
2576 int nPoslist;
2577 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist);
2578 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
2580 break;
2582 default:
2583 break;
2586 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
2587 return rc;
2591 ** This is the xColumn method, called by SQLite to request a value from
2592 ** the row that the supplied cursor currently points to.
2594 static int fts5ColumnMethod(
2595 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
2596 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
2597 int iCol /* Index of column to read value from */
2599 Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
2600 Fts5Config *pConfig = pTab->p.pConfig;
2601 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
2602 int rc = SQLITE_OK;
2604 assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
2606 if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){
2607 if( iCol==pConfig->nCol ){
2608 sqlite3_result_int64(pCtx, pCsr->iSpecial);
2610 }else
2612 if( iCol==pConfig->nCol ){
2613 /* User is requesting the value of the special column with the same name
2614 ** as the table. Return the cursor integer id number. This value is only
2615 ** useful in that it may be passed as the first argument to an FTS5
2616 ** auxiliary function. */
2617 sqlite3_result_int64(pCtx, pCsr->iCsrId);
2618 }else if( iCol==pConfig->nCol+1 ){
2620 /* The value of the "rank" column. */
2621 if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
2622 fts5PoslistBlob(pCtx, pCsr);
2623 }else if(
2624 pCsr->ePlan==FTS5_PLAN_MATCH
2625 || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
2627 if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
2628 fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
2631 }else if( !fts5IsContentless(pTab) ){
2632 pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
2633 rc = fts5SeekCursor(pCsr, 1);
2634 if( rc==SQLITE_OK ){
2635 sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
2637 pConfig->pzErrmsg = 0;
2638 }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){
2639 char *zErr = sqlite3_mprintf("cannot UPDATE a subset of "
2640 "columns on fts5 contentless-delete table: %s", pConfig->zName
2642 sqlite3_result_error(pCtx, zErr, -1);
2643 sqlite3_free(zErr);
2645 return rc;
2650 ** This routine implements the xFindFunction method for the FTS3
2651 ** virtual table.
2653 static int fts5FindFunctionMethod(
2654 sqlite3_vtab *pVtab, /* Virtual table handle */
2655 int nUnused, /* Number of SQL function arguments */
2656 const char *zName, /* Name of SQL function */
2657 void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
2658 void **ppArg /* OUT: User data for *pxFunc */
2660 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2661 Fts5Auxiliary *pAux;
2663 UNUSED_PARAM(nUnused);
2664 pAux = fts5FindAuxiliary(pTab, zName);
2665 if( pAux ){
2666 *pxFunc = fts5ApiCallback;
2667 *ppArg = (void*)pAux;
2668 return 1;
2671 /* No function of the specified name was found. Return 0. */
2672 return 0;
2676 ** Implementation of FTS5 xRename method. Rename an fts5 table.
2678 static int fts5RenameMethod(
2679 sqlite3_vtab *pVtab, /* Virtual table handle */
2680 const char *zName /* New name of table */
2682 int rc;
2683 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2684 rc = sqlite3Fts5StorageRename(pTab->pStorage, zName);
2685 return rc;
2688 int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
2689 fts5TripCursors((Fts5FullTable*)pTab);
2690 return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage);
2694 ** The xSavepoint() method.
2696 ** Flush the contents of the pending-terms table to disk.
2698 static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
2699 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2700 int rc = SQLITE_OK;
2702 fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
2703 rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
2704 if( rc==SQLITE_OK ){
2705 pTab->iSavepoint = iSavepoint+1;
2707 return rc;
2711 ** The xRelease() method.
2713 ** This is a no-op.
2715 static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
2716 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2717 int rc = SQLITE_OK;
2718 fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
2719 if( (iSavepoint+1)<pTab->iSavepoint ){
2720 rc = sqlite3Fts5FlushToDisk(&pTab->p);
2721 if( rc==SQLITE_OK ){
2722 pTab->iSavepoint = iSavepoint;
2725 return rc;
2729 ** The xRollbackTo() method.
2731 ** Discard the contents of the pending terms table.
2733 static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
2734 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2735 int rc = SQLITE_OK;
2736 fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
2737 fts5TripCursors(pTab);
2738 if( (iSavepoint+1)<=pTab->iSavepoint ){
2739 pTab->p.pConfig->pgsz = 0;
2740 rc = sqlite3Fts5StorageRollback(pTab->pStorage);
2742 return rc;
2746 ** Register a new auxiliary function with global context pGlobal.
2748 static int fts5CreateAux(
2749 fts5_api *pApi, /* Global context (one per db handle) */
2750 const char *zName, /* Name of new function */
2751 void *pUserData, /* User data for aux. function */
2752 fts5_extension_function xFunc, /* Aux. function implementation */
2753 void(*xDestroy)(void*) /* Destructor for pUserData */
2755 Fts5Global *pGlobal = (Fts5Global*)pApi;
2756 int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
2757 if( rc==SQLITE_OK ){
2758 Fts5Auxiliary *pAux;
2759 sqlite3_int64 nName; /* Size of zName in bytes, including \0 */
2760 sqlite3_int64 nByte; /* Bytes of space to allocate */
2762 nName = strlen(zName) + 1;
2763 nByte = sizeof(Fts5Auxiliary) + nName;
2764 pAux = (Fts5Auxiliary*)sqlite3_malloc64(nByte);
2765 if( pAux ){
2766 memset(pAux, 0, (size_t)nByte);
2767 pAux->zFunc = (char*)&pAux[1];
2768 memcpy(pAux->zFunc, zName, nName);
2769 pAux->pGlobal = pGlobal;
2770 pAux->pUserData = pUserData;
2771 pAux->xFunc = xFunc;
2772 pAux->xDestroy = xDestroy;
2773 pAux->pNext = pGlobal->pAux;
2774 pGlobal->pAux = pAux;
2775 }else{
2776 rc = SQLITE_NOMEM;
2780 return rc;
2784 ** Register a new tokenizer. This is the implementation of the
2785 ** fts5_api.xCreateTokenizer() method.
2787 static int fts5CreateTokenizer(
2788 fts5_api *pApi, /* Global context (one per db handle) */
2789 const char *zName, /* Name of new function */
2790 void *pUserData, /* User data for aux. function */
2791 fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
2792 void(*xDestroy)(void*) /* Destructor for pUserData */
2794 Fts5Global *pGlobal = (Fts5Global*)pApi;
2795 Fts5TokenizerModule *pNew;
2796 sqlite3_int64 nName; /* Size of zName and its \0 terminator */
2797 sqlite3_int64 nByte; /* Bytes of space to allocate */
2798 int rc = SQLITE_OK;
2800 nName = strlen(zName) + 1;
2801 nByte = sizeof(Fts5TokenizerModule) + nName;
2802 pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte);
2803 if( pNew ){
2804 memset(pNew, 0, (size_t)nByte);
2805 pNew->zName = (char*)&pNew[1];
2806 memcpy(pNew->zName, zName, nName);
2807 pNew->pUserData = pUserData;
2808 pNew->x = *pTokenizer;
2809 pNew->xDestroy = xDestroy;
2810 pNew->pNext = pGlobal->pTok;
2811 pGlobal->pTok = pNew;
2812 if( pNew->pNext==0 ){
2813 pGlobal->pDfltTok = pNew;
2815 }else{
2816 rc = SQLITE_NOMEM;
2819 return rc;
2822 static Fts5TokenizerModule *fts5LocateTokenizer(
2823 Fts5Global *pGlobal,
2824 const char *zName
2826 Fts5TokenizerModule *pMod = 0;
2828 if( zName==0 ){
2829 pMod = pGlobal->pDfltTok;
2830 }else{
2831 for(pMod=pGlobal->pTok; pMod; pMod=pMod->pNext){
2832 if( sqlite3_stricmp(zName, pMod->zName)==0 ) break;
2836 return pMod;
2840 ** Find a tokenizer. This is the implementation of the
2841 ** fts5_api.xFindTokenizer() method.
2843 static int fts5FindTokenizer(
2844 fts5_api *pApi, /* Global context (one per db handle) */
2845 const char *zName, /* Name of new function */
2846 void **ppUserData,
2847 fts5_tokenizer *pTokenizer /* Populate this object */
2849 int rc = SQLITE_OK;
2850 Fts5TokenizerModule *pMod;
2852 pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
2853 if( pMod ){
2854 *pTokenizer = pMod->x;
2855 *ppUserData = pMod->pUserData;
2856 }else{
2857 memset(pTokenizer, 0, sizeof(fts5_tokenizer));
2858 rc = SQLITE_ERROR;
2861 return rc;
2864 int sqlite3Fts5GetTokenizer(
2865 Fts5Global *pGlobal,
2866 const char **azArg,
2867 int nArg,
2868 Fts5Config *pConfig,
2869 char **pzErr
2871 Fts5TokenizerModule *pMod;
2872 int rc = SQLITE_OK;
2874 pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
2875 if( pMod==0 ){
2876 assert( nArg>0 );
2877 rc = SQLITE_ERROR;
2878 if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
2879 }else{
2880 rc = pMod->x.xCreate(
2881 pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
2883 pConfig->pTokApi = &pMod->x;
2884 if( rc!=SQLITE_OK ){
2885 if( pzErr && rc!=SQLITE_NOMEM ){
2886 *pzErr = sqlite3_mprintf("error in tokenizer constructor");
2888 }else{
2889 pConfig->ePattern = sqlite3Fts5TokenizerPattern(
2890 pMod->x.xCreate, pConfig->pTok
2895 if( rc!=SQLITE_OK ){
2896 pConfig->pTokApi = 0;
2897 pConfig->pTok = 0;
2900 return rc;
2903 static void fts5ModuleDestroy(void *pCtx){
2904 Fts5TokenizerModule *pTok, *pNextTok;
2905 Fts5Auxiliary *pAux, *pNextAux;
2906 Fts5Global *pGlobal = (Fts5Global*)pCtx;
2908 for(pAux=pGlobal->pAux; pAux; pAux=pNextAux){
2909 pNextAux = pAux->pNext;
2910 if( pAux->xDestroy ) pAux->xDestroy(pAux->pUserData);
2911 sqlite3_free(pAux);
2914 for(pTok=pGlobal->pTok; pTok; pTok=pNextTok){
2915 pNextTok = pTok->pNext;
2916 if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData);
2917 sqlite3_free(pTok);
2920 sqlite3_free(pGlobal);
2923 static void fts5Fts5Func(
2924 sqlite3_context *pCtx, /* Function call context */
2925 int nArg, /* Number of args */
2926 sqlite3_value **apArg /* Function arguments */
2928 Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
2929 fts5_api **ppApi;
2930 UNUSED_PARAM(nArg);
2931 assert( nArg==1 );
2932 ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr");
2933 if( ppApi ) *ppApi = &pGlobal->api;
2937 ** Implementation of fts5_source_id() function.
2939 static void fts5SourceIdFunc(
2940 sqlite3_context *pCtx, /* Function call context */
2941 int nArg, /* Number of args */
2942 sqlite3_value **apUnused /* Function arguments */
2944 assert( nArg==0 );
2945 UNUSED_PARAM2(nArg, apUnused);
2946 sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
2950 ** Return true if zName is the extension on one of the shadow tables used
2951 ** by this module.
2953 static int fts5ShadowName(const char *zName){
2954 static const char *azName[] = {
2955 "config", "content", "data", "docsize", "idx"
2957 unsigned int i;
2958 for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
2959 if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
2961 return 0;
2965 ** Run an integrity check on the FTS5 data structures. Return a string
2966 ** if anything is found amiss. Return a NULL pointer if everything is
2967 ** OK.
2969 static int fts5IntegrityMethod(
2970 sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */
2971 const char *zSchema, /* Name of schema in which this table lives */
2972 const char *zTabname, /* Name of the table itself */
2973 int isQuick, /* True if this is a quick-check */
2974 char **pzErr /* Write error message here */
2976 Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
2977 int rc;
2979 assert( pzErr!=0 && *pzErr==0 );
2980 UNUSED_PARAM(isQuick);
2981 assert( pTab->p.pConfig->pzErrmsg==0 );
2982 pTab->p.pConfig->pzErrmsg = pzErr;
2983 rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
2984 if( *pzErr==0 && rc!=SQLITE_OK ){
2985 if( (rc&0xff)==SQLITE_CORRUPT ){
2986 *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
2987 zSchema, zTabname);
2988 rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM;
2989 }else{
2990 *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
2991 " FTS5 table %s.%s: %s",
2992 zSchema, zTabname, sqlite3_errstr(rc));
2996 sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
2997 pTab->p.pConfig->pzErrmsg = 0;
2999 return rc;
3002 static int fts5Init(sqlite3 *db){
3003 static const sqlite3_module fts5Mod = {
3004 /* iVersion */ 4,
3005 /* xCreate */ fts5CreateMethod,
3006 /* xConnect */ fts5ConnectMethod,
3007 /* xBestIndex */ fts5BestIndexMethod,
3008 /* xDisconnect */ fts5DisconnectMethod,
3009 /* xDestroy */ fts5DestroyMethod,
3010 /* xOpen */ fts5OpenMethod,
3011 /* xClose */ fts5CloseMethod,
3012 /* xFilter */ fts5FilterMethod,
3013 /* xNext */ fts5NextMethod,
3014 /* xEof */ fts5EofMethod,
3015 /* xColumn */ fts5ColumnMethod,
3016 /* xRowid */ fts5RowidMethod,
3017 /* xUpdate */ fts5UpdateMethod,
3018 /* xBegin */ fts5BeginMethod,
3019 /* xSync */ fts5SyncMethod,
3020 /* xCommit */ fts5CommitMethod,
3021 /* xRollback */ fts5RollbackMethod,
3022 /* xFindFunction */ fts5FindFunctionMethod,
3023 /* xRename */ fts5RenameMethod,
3024 /* xSavepoint */ fts5SavepointMethod,
3025 /* xRelease */ fts5ReleaseMethod,
3026 /* xRollbackTo */ fts5RollbackToMethod,
3027 /* xShadowName */ fts5ShadowName,
3028 /* xIntegrity */ fts5IntegrityMethod
3031 int rc;
3032 Fts5Global *pGlobal = 0;
3034 pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
3035 if( pGlobal==0 ){
3036 rc = SQLITE_NOMEM;
3037 }else{
3038 void *p = (void*)pGlobal;
3039 memset(pGlobal, 0, sizeof(Fts5Global));
3040 pGlobal->db = db;
3041 pGlobal->api.iVersion = 2;
3042 pGlobal->api.xCreateFunction = fts5CreateAux;
3043 pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
3044 pGlobal->api.xFindTokenizer = fts5FindTokenizer;
3045 rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
3046 if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
3047 if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
3048 if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
3049 if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
3050 if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
3051 if( rc==SQLITE_OK ){
3052 rc = sqlite3_create_function(
3053 db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
3056 if( rc==SQLITE_OK ){
3057 rc = sqlite3_create_function(
3058 db, "fts5_source_id", 0,
3059 SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS,
3060 p, fts5SourceIdFunc, 0, 0
3065 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
3066 ** fts5_test_mi.c is compiled and linked into the executable. And call
3067 ** its entry point to enable the matchinfo() demo. */
3068 #ifdef SQLITE_FTS5_ENABLE_TEST_MI
3069 if( rc==SQLITE_OK ){
3070 extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
3071 rc = sqlite3Fts5TestRegisterMatchinfo(db);
3073 #endif
3075 return rc;
3079 ** The following functions are used to register the module with SQLite. If
3080 ** this module is being built as part of the SQLite core (SQLITE_CORE is
3081 ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
3083 ** Or, if this module is being built as a loadable extension,
3084 ** sqlite3Fts5Init() is omitted and the two standard entry points
3085 ** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
3087 #ifndef SQLITE_CORE
3088 #ifdef _WIN32
3089 __declspec(dllexport)
3090 #endif
3091 int sqlite3_fts_init(
3092 sqlite3 *db,
3093 char **pzErrMsg,
3094 const sqlite3_api_routines *pApi
3096 SQLITE_EXTENSION_INIT2(pApi);
3097 (void)pzErrMsg; /* Unused parameter */
3098 return fts5Init(db);
3101 #ifdef _WIN32
3102 __declspec(dllexport)
3103 #endif
3104 int sqlite3_fts5_init(
3105 sqlite3 *db,
3106 char **pzErrMsg,
3107 const sqlite3_api_routines *pApi
3109 SQLITE_EXTENSION_INIT2(pApi);
3110 (void)pzErrMsg; /* Unused parameter */
3111 return fts5Init(db);
3113 #else
3114 int sqlite3Fts5Init(sqlite3 *db){
3115 return fts5Init(db);
3117 #endif