Modify the sqltclsh startup script to look for a properly formatted
[sqlite.git] / ext / fts5 / fts5_main.c
blobd59cd5b7ccb534a74074a797aedc282af9f413cf
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 int sqlite3_fts5_may_be_corrupt = 1;
28 typedef struct Fts5Auxdata Fts5Auxdata;
29 typedef struct Fts5Auxiliary Fts5Auxiliary;
30 typedef struct Fts5Cursor Fts5Cursor;
31 typedef struct Fts5Sorter Fts5Sorter;
32 typedef struct Fts5Table Fts5Table;
33 typedef struct Fts5TokenizerModule Fts5TokenizerModule;
36 ** NOTES ON TRANSACTIONS:
38 ** SQLite invokes the following virtual table methods as transactions are
39 ** opened and closed by the user:
41 ** xBegin(): Start of a new transaction.
42 ** xSync(): Initial part of two-phase commit.
43 ** xCommit(): Final part of two-phase commit.
44 ** xRollback(): Rollback the transaction.
46 ** Anything that is required as part of a commit that may fail is performed
47 ** in the xSync() callback. Current versions of SQLite ignore any errors
48 ** returned by xCommit().
50 ** And as sub-transactions are opened/closed:
52 ** xSavepoint(int S): Open savepoint S.
53 ** xRelease(int S): Commit and close savepoint S.
54 ** xRollbackTo(int S): Rollback to start of savepoint S.
56 ** During a write-transaction the fts5_index.c module may cache some data
57 ** in-memory. It is flushed to disk whenever xSync(), xRelease() or
58 ** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
59 ** is called.
61 ** Additionally, if SQLITE_DEBUG is defined, an instance of the following
62 ** structure is used to record the current transaction state. This information
63 ** is not required, but it is used in the assert() statements executed by
64 ** function fts5CheckTransactionState() (see below).
66 struct Fts5TransactionState {
67 int eState; /* 0==closed, 1==open, 2==synced */
68 int iSavepoint; /* Number of open savepoints (0 -> none) */
72 ** A single object of this type is allocated when the FTS5 module is
73 ** registered with a database handle. It is used to store pointers to
74 ** all registered FTS5 extensions - tokenizers and auxiliary functions.
76 struct Fts5Global {
77 fts5_api api; /* User visible part of object (see fts5.h) */
78 sqlite3 *db; /* Associated database connection */
79 i64 iNextId; /* Used to allocate unique cursor ids */
80 Fts5Auxiliary *pAux; /* First in list of all aux. functions */
81 Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
82 Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
83 Fts5Cursor *pCsr; /* First in list of all open cursors */
87 ** Each auxiliary function registered with the FTS5 module is represented
88 ** by an object of the following type. All such objects are stored as part
89 ** of the Fts5Global.pAux list.
91 struct Fts5Auxiliary {
92 Fts5Global *pGlobal; /* Global context for this function */
93 char *zFunc; /* Function name (nul-terminated) */
94 void *pUserData; /* User-data pointer */
95 fts5_extension_function xFunc; /* Callback function */
96 void (*xDestroy)(void*); /* Destructor function */
97 Fts5Auxiliary *pNext; /* Next registered auxiliary function */
101 ** Each tokenizer module registered with the FTS5 module is represented
102 ** by an object of the following type. All such objects are stored as part
103 ** of the Fts5Global.pTok list.
105 struct Fts5TokenizerModule {
106 char *zName; /* Name of tokenizer */
107 void *pUserData; /* User pointer passed to xCreate() */
108 fts5_tokenizer x; /* Tokenizer functions */
109 void (*xDestroy)(void*); /* Destructor function */
110 Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
114 ** Virtual-table object.
116 struct Fts5Table {
117 sqlite3_vtab base; /* Base class used by SQLite core */
118 Fts5Config *pConfig; /* Virtual table configuration */
119 Fts5Index *pIndex; /* Full-text index */
120 Fts5Storage *pStorage; /* Document store */
121 Fts5Global *pGlobal; /* Global (connection wide) data */
122 Fts5Cursor *pSortCsr; /* Sort data from this cursor */
123 #ifdef SQLITE_DEBUG
124 struct Fts5TransactionState ts;
125 #endif
128 struct Fts5MatchPhrase {
129 Fts5Buffer *pPoslist; /* Pointer to current poslist */
130 int nTerm; /* Size of phrase in terms */
134 ** pStmt:
135 ** SELECT rowid, <fts> FROM <fts> ORDER BY +rank;
137 ** aIdx[]:
138 ** There is one entry in the aIdx[] array for each phrase in the query,
139 ** the value of which is the offset within aPoslist[] following the last
140 ** byte of the position list for the corresponding phrase.
142 struct Fts5Sorter {
143 sqlite3_stmt *pStmt;
144 i64 iRowid; /* Current rowid */
145 const u8 *aPoslist; /* Position lists for current row */
146 int nIdx; /* Number of entries in aIdx[] */
147 int aIdx[1]; /* Offsets into aPoslist for current row */
152 ** Virtual-table cursor object.
154 ** iSpecial:
155 ** If this is a 'special' query (refer to function fts5SpecialMatch()),
156 ** then this variable contains the result of the query.
158 ** iFirstRowid, iLastRowid:
159 ** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
160 ** cursor iterates in ascending order of rowids, iFirstRowid is the lower
161 ** limit of rowids to return, and iLastRowid the upper. In other words, the
162 ** WHERE clause in the user's query might have been:
164 ** <tbl> MATCH <expr> AND rowid BETWEEN $iFirstRowid AND $iLastRowid
166 ** If the cursor iterates in descending order of rowid, iFirstRowid
167 ** is the upper limit (i.e. the "first" rowid visited) and iLastRowid
168 ** the lower.
170 struct Fts5Cursor {
171 sqlite3_vtab_cursor base; /* Base class used by SQLite core */
172 Fts5Cursor *pNext; /* Next cursor in Fts5Cursor.pCsr list */
173 int *aColumnSize; /* Values for xColumnSize() */
174 i64 iCsrId; /* Cursor id */
176 /* Zero from this point onwards on cursor reset */
177 int ePlan; /* FTS5_PLAN_XXX value */
178 int bDesc; /* True for "ORDER BY rowid DESC" queries */
179 i64 iFirstRowid; /* Return no rowids earlier than this */
180 i64 iLastRowid; /* Return no rowids later than this */
181 sqlite3_stmt *pStmt; /* Statement used to read %_content */
182 Fts5Expr *pExpr; /* Expression for MATCH queries */
183 Fts5Sorter *pSorter; /* Sorter for "ORDER BY rank" queries */
184 int csrflags; /* Mask of cursor flags (see below) */
185 i64 iSpecial; /* Result of special query */
187 /* "rank" function. Populated on demand from vtab.xColumn(). */
188 char *zRank; /* Custom rank function */
189 char *zRankArgs; /* Custom rank function args */
190 Fts5Auxiliary *pRank; /* Rank callback (or NULL) */
191 int nRankArg; /* Number of trailing arguments for rank() */
192 sqlite3_value **apRankArg; /* Array of trailing arguments */
193 sqlite3_stmt *pRankArgStmt; /* Origin of objects in apRankArg[] */
195 /* Auxiliary data storage */
196 Fts5Auxiliary *pAux; /* Currently executing extension function */
197 Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
199 /* Cache used by auxiliary functions xInst() and xInstCount() */
200 Fts5PoslistReader *aInstIter; /* One for each phrase */
201 int nInstAlloc; /* Size of aInst[] array (entries / 3) */
202 int nInstCount; /* Number of phrase instances */
203 int *aInst; /* 3 integers per phrase instance */
207 ** Bits that make up the "idxNum" parameter passed indirectly by
208 ** xBestIndex() to xFilter().
210 #define FTS5_BI_MATCH 0x0001 /* <tbl> MATCH ? */
211 #define FTS5_BI_RANK 0x0002 /* rank MATCH ? */
212 #define FTS5_BI_ROWID_EQ 0x0004 /* rowid == ? */
213 #define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */
214 #define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */
216 #define FTS5_BI_ORDER_RANK 0x0020
217 #define FTS5_BI_ORDER_ROWID 0x0040
218 #define FTS5_BI_ORDER_DESC 0x0080
221 ** Values for Fts5Cursor.csrflags
223 #define FTS5CSR_EOF 0x01
224 #define FTS5CSR_REQUIRE_CONTENT 0x02
225 #define FTS5CSR_REQUIRE_DOCSIZE 0x04
226 #define FTS5CSR_REQUIRE_INST 0x08
227 #define FTS5CSR_FREE_ZRANK 0x10
228 #define FTS5CSR_REQUIRE_RESEEK 0x20
229 #define FTS5CSR_REQUIRE_POSLIST 0x40
231 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
232 #define BitFlagTest(x,y) (((x) & (y))!=0)
236 ** Macros to Set(), Clear() and Test() cursor flags.
238 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
239 #define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag))
240 #define CsrFlagTest(pCsr, flag) ((pCsr)->csrflags & (flag))
242 struct Fts5Auxdata {
243 Fts5Auxiliary *pAux; /* Extension to which this belongs */
244 void *pPtr; /* Pointer value */
245 void(*xDelete)(void*); /* Destructor */
246 Fts5Auxdata *pNext; /* Next object in linked list */
249 #ifdef SQLITE_DEBUG
250 #define FTS5_BEGIN 1
251 #define FTS5_SYNC 2
252 #define FTS5_COMMIT 3
253 #define FTS5_ROLLBACK 4
254 #define FTS5_SAVEPOINT 5
255 #define FTS5_RELEASE 6
256 #define FTS5_ROLLBACKTO 7
257 static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
258 switch( op ){
259 case FTS5_BEGIN:
260 assert( p->ts.eState==0 );
261 p->ts.eState = 1;
262 p->ts.iSavepoint = -1;
263 break;
265 case FTS5_SYNC:
266 assert( p->ts.eState==1 );
267 p->ts.eState = 2;
268 break;
270 case FTS5_COMMIT:
271 assert( p->ts.eState==2 );
272 p->ts.eState = 0;
273 break;
275 case FTS5_ROLLBACK:
276 assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 );
277 p->ts.eState = 0;
278 break;
280 case FTS5_SAVEPOINT:
281 assert( p->ts.eState==1 );
282 assert( iSavepoint>=0 );
283 assert( iSavepoint>p->ts.iSavepoint );
284 p->ts.iSavepoint = iSavepoint;
285 break;
287 case FTS5_RELEASE:
288 assert( p->ts.eState==1 );
289 assert( iSavepoint>=0 );
290 assert( iSavepoint<=p->ts.iSavepoint );
291 p->ts.iSavepoint = iSavepoint-1;
292 break;
294 case FTS5_ROLLBACKTO:
295 assert( p->ts.eState==1 );
296 assert( iSavepoint>=0 );
297 assert( iSavepoint<=p->ts.iSavepoint );
298 p->ts.iSavepoint = iSavepoint;
299 break;
302 #else
303 # define fts5CheckTransactionState(x,y,z)
304 #endif
307 ** Return true if pTab is a contentless table.
309 static int fts5IsContentless(Fts5Table *pTab){
310 return pTab->pConfig->eContent==FTS5_CONTENT_NONE;
314 ** Delete a virtual table handle allocated by fts5InitVtab().
316 static void fts5FreeVtab(Fts5Table *pTab){
317 if( pTab ){
318 sqlite3Fts5IndexClose(pTab->pIndex);
319 sqlite3Fts5StorageClose(pTab->pStorage);
320 sqlite3Fts5ConfigFree(pTab->pConfig);
321 sqlite3_free(pTab);
326 ** The xDisconnect() virtual table method.
328 static int fts5DisconnectMethod(sqlite3_vtab *pVtab){
329 fts5FreeVtab((Fts5Table*)pVtab);
330 return SQLITE_OK;
334 ** The xDestroy() virtual table method.
336 static int fts5DestroyMethod(sqlite3_vtab *pVtab){
337 Fts5Table *pTab = (Fts5Table*)pVtab;
338 int rc = sqlite3Fts5DropAll(pTab->pConfig);
339 if( rc==SQLITE_OK ){
340 fts5FreeVtab((Fts5Table*)pVtab);
342 return rc;
346 ** This function is the implementation of both the xConnect and xCreate
347 ** methods of the FTS3 virtual table.
349 ** The argv[] array contains the following:
351 ** argv[0] -> module name ("fts5")
352 ** argv[1] -> database name
353 ** argv[2] -> table name
354 ** argv[...] -> "column name" and other module argument fields.
356 static int fts5InitVtab(
357 int bCreate, /* True for xCreate, false for xConnect */
358 sqlite3 *db, /* The SQLite database connection */
359 void *pAux, /* Hash table containing tokenizers */
360 int argc, /* Number of elements in argv array */
361 const char * const *argv, /* xCreate/xConnect argument array */
362 sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
363 char **pzErr /* Write any error message here */
365 Fts5Global *pGlobal = (Fts5Global*)pAux;
366 const char **azConfig = (const char**)argv;
367 int rc = SQLITE_OK; /* Return code */
368 Fts5Config *pConfig = 0; /* Results of parsing argc/argv */
369 Fts5Table *pTab = 0; /* New virtual table object */
371 /* Allocate the new vtab object and parse the configuration */
372 pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table));
373 if( rc==SQLITE_OK ){
374 rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
375 assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
377 if( rc==SQLITE_OK ){
378 pTab->pConfig = pConfig;
379 pTab->pGlobal = pGlobal;
382 /* Open the index sub-system */
383 if( rc==SQLITE_OK ){
384 rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr);
387 /* Open the storage sub-system */
388 if( rc==SQLITE_OK ){
389 rc = sqlite3Fts5StorageOpen(
390 pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr
394 /* Call sqlite3_declare_vtab() */
395 if( rc==SQLITE_OK ){
396 rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
399 /* Load the initial configuration */
400 if( rc==SQLITE_OK ){
401 assert( pConfig->pzErrmsg==0 );
402 pConfig->pzErrmsg = pzErr;
403 rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
404 sqlite3Fts5IndexRollback(pTab->pIndex);
405 pConfig->pzErrmsg = 0;
408 if( rc!=SQLITE_OK ){
409 fts5FreeVtab(pTab);
410 pTab = 0;
411 }else if( bCreate ){
412 fts5CheckTransactionState(pTab, FTS5_BEGIN, 0);
414 *ppVTab = (sqlite3_vtab*)pTab;
415 return rc;
419 ** The xConnect() and xCreate() methods for the virtual table. All the
420 ** work is done in function fts5InitVtab().
422 static int fts5ConnectMethod(
423 sqlite3 *db, /* Database connection */
424 void *pAux, /* Pointer to tokenizer hash table */
425 int argc, /* Number of elements in argv array */
426 const char * const *argv, /* xCreate/xConnect argument array */
427 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
428 char **pzErr /* OUT: sqlite3_malloc'd error message */
430 return fts5InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr);
432 static int fts5CreateMethod(
433 sqlite3 *db, /* Database connection */
434 void *pAux, /* Pointer to tokenizer hash table */
435 int argc, /* Number of elements in argv array */
436 const char * const *argv, /* xCreate/xConnect argument array */
437 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
438 char **pzErr /* OUT: sqlite3_malloc'd error message */
440 return fts5InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr);
444 ** The different query plans.
446 #define FTS5_PLAN_MATCH 1 /* (<tbl> MATCH ?) */
447 #define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */
448 #define FTS5_PLAN_SPECIAL 3 /* An internal query */
449 #define FTS5_PLAN_SORTED_MATCH 4 /* (<tbl> MATCH ? ORDER BY rank) */
450 #define FTS5_PLAN_SCAN 5 /* No usable constraint */
451 #define FTS5_PLAN_ROWID 6 /* (rowid = ?) */
454 ** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
455 ** extension is currently being used by a version of SQLite too old to
456 ** support index-info flags. In that case this function is a no-op.
458 static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
459 #if SQLITE_VERSION_NUMBER>=3008012
460 #ifndef SQLITE_CORE
461 if( sqlite3_libversion_number()>=3008012 )
462 #endif
464 pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
466 #endif
470 ** Implementation of the xBestIndex method for FTS5 tables. Within the
471 ** WHERE constraint, it searches for the following:
473 ** 1. A MATCH constraint against the special column.
474 ** 2. A MATCH constraint against the "rank" column.
475 ** 3. An == constraint against the rowid column.
476 ** 4. A < or <= constraint against the rowid column.
477 ** 5. A > or >= constraint against the rowid column.
479 ** Within the ORDER BY, either:
481 ** 5. ORDER BY rank [ASC|DESC]
482 ** 6. ORDER BY rowid [ASC|DESC]
484 ** Costs are assigned as follows:
486 ** a) If an unusable MATCH operator is present in the WHERE clause, the
487 ** cost is unconditionally set to 1e50 (a really big number).
489 ** a) If a MATCH operator is present, the cost depends on the other
490 ** constraints also present. As follows:
492 ** * No other constraints: cost=1000.0
493 ** * One rowid range constraint: cost=750.0
494 ** * Both rowid range constraints: cost=500.0
495 ** * An == rowid constraint: cost=100.0
497 ** b) Otherwise, if there is no MATCH:
499 ** * No other constraints: cost=1000000.0
500 ** * One rowid range constraint: cost=750000.0
501 ** * Both rowid range constraints: cost=250000.0
502 ** * An == rowid constraint: cost=10.0
504 ** Costs are not modified by the ORDER BY clause.
506 static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
507 Fts5Table *pTab = (Fts5Table*)pVTab;
508 Fts5Config *pConfig = pTab->pConfig;
509 const int nCol = pConfig->nCol;
510 int idxFlags = 0; /* Parameter passed through to xFilter() */
511 int bHasMatch;
512 int iNext;
513 int i;
515 struct Constraint {
516 int op; /* Mask against sqlite3_index_constraint.op */
517 int fts5op; /* FTS5 mask for idxFlags */
518 int iCol; /* 0==rowid, 1==tbl, 2==rank */
519 int omit; /* True to omit this if found */
520 int iConsIndex; /* Index in pInfo->aConstraint[] */
521 } aConstraint[] = {
522 {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
523 FTS5_BI_MATCH, 1, 1, -1},
524 {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
525 FTS5_BI_RANK, 2, 1, -1},
526 {SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1},
527 {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE,
528 FTS5_BI_ROWID_LE, 0, 0, -1},
529 {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE,
530 FTS5_BI_ROWID_GE, 0, 0, -1},
533 int aColMap[3];
534 aColMap[0] = -1;
535 aColMap[1] = nCol;
536 aColMap[2] = nCol+1;
538 /* Set idxFlags flags for all WHERE clause terms that will be used. */
539 for(i=0; i<pInfo->nConstraint; i++){
540 struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
541 int iCol = p->iColumn;
543 if( (p->op==SQLITE_INDEX_CONSTRAINT_MATCH && iCol>=0 && iCol<=nCol)
544 || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol)
546 /* A MATCH operator or equivalent */
547 if( p->usable ){
548 idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16);
549 aConstraint[0].iConsIndex = i;
550 }else{
551 /* As there exists an unusable MATCH constraint this is an
552 ** unusable plan. Set a prohibitively high cost. */
553 pInfo->estimatedCost = 1e50;
554 return SQLITE_OK;
556 }else{
557 int j;
558 for(j=1; j<ArraySize(aConstraint); j++){
559 struct Constraint *pC = &aConstraint[j];
560 if( iCol==aColMap[pC->iCol] && p->op & pC->op && p->usable ){
561 pC->iConsIndex = i;
562 idxFlags |= pC->fts5op;
568 /* Set idxFlags flags for the ORDER BY clause */
569 if( pInfo->nOrderBy==1 ){
570 int iSort = pInfo->aOrderBy[0].iColumn;
571 if( iSort==(pConfig->nCol+1) && BitFlagTest(idxFlags, FTS5_BI_MATCH) ){
572 idxFlags |= FTS5_BI_ORDER_RANK;
573 }else if( iSort==-1 ){
574 idxFlags |= FTS5_BI_ORDER_ROWID;
576 if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
577 pInfo->orderByConsumed = 1;
578 if( pInfo->aOrderBy[0].desc ){
579 idxFlags |= FTS5_BI_ORDER_DESC;
584 /* Calculate the estimated cost based on the flags set in idxFlags. */
585 bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH);
586 if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){
587 pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0;
588 if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo);
589 }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
590 pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0;
591 }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
592 pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0;
593 }else{
594 pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0;
597 /* Assign argvIndex values to each constraint in use. */
598 iNext = 1;
599 for(i=0; i<ArraySize(aConstraint); i++){
600 struct Constraint *pC = &aConstraint[i];
601 if( pC->iConsIndex>=0 ){
602 pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++;
603 pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit;
607 pInfo->idxNum = idxFlags;
608 return SQLITE_OK;
611 static int fts5NewTransaction(Fts5Table *pTab){
612 Fts5Cursor *pCsr;
613 for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
614 if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
616 return sqlite3Fts5StorageReset(pTab->pStorage);
620 ** Implementation of xOpen method.
622 static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
623 Fts5Table *pTab = (Fts5Table*)pVTab;
624 Fts5Config *pConfig = pTab->pConfig;
625 Fts5Cursor *pCsr = 0; /* New cursor object */
626 int nByte; /* Bytes of space to allocate */
627 int rc; /* Return code */
629 rc = fts5NewTransaction(pTab);
630 if( rc==SQLITE_OK ){
631 nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
632 pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
633 if( pCsr ){
634 Fts5Global *pGlobal = pTab->pGlobal;
635 memset(pCsr, 0, nByte);
636 pCsr->aColumnSize = (int*)&pCsr[1];
637 pCsr->pNext = pGlobal->pCsr;
638 pGlobal->pCsr = pCsr;
639 pCsr->iCsrId = ++pGlobal->iNextId;
640 }else{
641 rc = SQLITE_NOMEM;
644 *ppCsr = (sqlite3_vtab_cursor*)pCsr;
645 return rc;
648 static int fts5StmtType(Fts5Cursor *pCsr){
649 if( pCsr->ePlan==FTS5_PLAN_SCAN ){
650 return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC;
652 return FTS5_STMT_LOOKUP;
656 ** This function is called after the cursor passed as the only argument
657 ** is moved to point at a different row. It clears all cached data
658 ** specific to the previous row stored by the cursor object.
660 static void fts5CsrNewrow(Fts5Cursor *pCsr){
661 CsrFlagSet(pCsr,
662 FTS5CSR_REQUIRE_CONTENT
663 | FTS5CSR_REQUIRE_DOCSIZE
664 | FTS5CSR_REQUIRE_INST
665 | FTS5CSR_REQUIRE_POSLIST
669 static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
670 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
671 Fts5Auxdata *pData;
672 Fts5Auxdata *pNext;
674 sqlite3_free(pCsr->aInstIter);
675 sqlite3_free(pCsr->aInst);
676 if( pCsr->pStmt ){
677 int eStmt = fts5StmtType(pCsr);
678 sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
680 if( pCsr->pSorter ){
681 Fts5Sorter *pSorter = pCsr->pSorter;
682 sqlite3_finalize(pSorter->pStmt);
683 sqlite3_free(pSorter);
686 if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){
687 sqlite3Fts5ExprFree(pCsr->pExpr);
690 for(pData=pCsr->pAuxdata; pData; pData=pNext){
691 pNext = pData->pNext;
692 if( pData->xDelete ) pData->xDelete(pData->pPtr);
693 sqlite3_free(pData);
696 sqlite3_finalize(pCsr->pRankArgStmt);
697 sqlite3_free(pCsr->apRankArg);
699 if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){
700 sqlite3_free(pCsr->zRank);
701 sqlite3_free(pCsr->zRankArgs);
704 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr));
709 ** Close the cursor. For additional information see the documentation
710 ** on the xClose method of the virtual table interface.
712 static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
713 if( pCursor ){
714 Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
715 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
716 Fts5Cursor **pp;
718 fts5FreeCursorComponents(pCsr);
719 /* Remove the cursor from the Fts5Global.pCsr list */
720 for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext);
721 *pp = pCsr->pNext;
723 sqlite3_free(pCsr);
725 return SQLITE_OK;
728 static int fts5SorterNext(Fts5Cursor *pCsr){
729 Fts5Sorter *pSorter = pCsr->pSorter;
730 int rc;
732 rc = sqlite3_step(pSorter->pStmt);
733 if( rc==SQLITE_DONE ){
734 rc = SQLITE_OK;
735 CsrFlagSet(pCsr, FTS5CSR_EOF);
736 }else if( rc==SQLITE_ROW ){
737 const u8 *a;
738 const u8 *aBlob;
739 int nBlob;
740 int i;
741 int iOff = 0;
742 rc = SQLITE_OK;
744 pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0);
745 nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
746 aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
748 /* nBlob==0 in detail=none mode. */
749 if( nBlob>0 ){
750 for(i=0; i<(pSorter->nIdx-1); i++){
751 int iVal;
752 a += fts5GetVarint32(a, iVal);
753 iOff += iVal;
754 pSorter->aIdx[i] = iOff;
756 pSorter->aIdx[i] = &aBlob[nBlob] - a;
757 pSorter->aPoslist = a;
760 fts5CsrNewrow(pCsr);
763 return rc;
768 ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
769 ** open on table pTab.
771 static void fts5TripCursors(Fts5Table *pTab){
772 Fts5Cursor *pCsr;
773 for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
774 if( pCsr->ePlan==FTS5_PLAN_MATCH
775 && pCsr->base.pVtab==(sqlite3_vtab*)pTab
777 CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK);
783 ** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
784 ** argument, close and reopen all Fts5IndexIter iterators that the cursor
785 ** is using. Then attempt to move the cursor to a rowid equal to or laster
786 ** (in the cursors sort order - ASC or DESC) than the current rowid.
788 ** If the new rowid is not equal to the old, set output parameter *pbSkip
789 ** to 1 before returning. Otherwise, leave it unchanged.
791 ** Return SQLITE_OK if successful or if no reseek was required, or an
792 ** error code if an error occurred.
794 static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
795 int rc = SQLITE_OK;
796 assert( *pbSkip==0 );
797 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){
798 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
799 int bDesc = pCsr->bDesc;
800 i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
802 rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc);
803 if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
804 *pbSkip = 1;
807 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK);
808 fts5CsrNewrow(pCsr);
809 if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
810 CsrFlagSet(pCsr, FTS5CSR_EOF);
811 *pbSkip = 1;
814 return rc;
819 ** Advance the cursor to the next row in the table that matches the
820 ** search criteria.
822 ** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
823 ** even if we reach end-of-file. The fts5EofMethod() will be called
824 ** subsequently to determine whether or not an EOF was hit.
826 static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
827 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
828 int rc;
830 assert( (pCsr->ePlan<3)==
831 (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
833 assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
835 if( pCsr->ePlan<3 ){
836 int bSkip = 0;
837 if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
838 rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
839 CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
840 fts5CsrNewrow(pCsr);
841 }else{
842 switch( pCsr->ePlan ){
843 case FTS5_PLAN_SPECIAL: {
844 CsrFlagSet(pCsr, FTS5CSR_EOF);
845 rc = SQLITE_OK;
846 break;
849 case FTS5_PLAN_SORTED_MATCH: {
850 rc = fts5SorterNext(pCsr);
851 break;
854 default:
855 rc = sqlite3_step(pCsr->pStmt);
856 if( rc!=SQLITE_ROW ){
857 CsrFlagSet(pCsr, FTS5CSR_EOF);
858 rc = sqlite3_reset(pCsr->pStmt);
859 }else{
860 rc = SQLITE_OK;
862 break;
866 return rc;
870 static int fts5PrepareStatement(
871 sqlite3_stmt **ppStmt,
872 Fts5Config *pConfig,
873 const char *zFmt,
876 sqlite3_stmt *pRet = 0;
877 int rc;
878 char *zSql;
879 va_list ap;
881 va_start(ap, zFmt);
882 zSql = sqlite3_vmprintf(zFmt, ap);
883 if( zSql==0 ){
884 rc = SQLITE_NOMEM;
885 }else{
886 rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
887 SQLITE_PREPARE_PERSISTENT, &pRet, 0);
888 if( rc!=SQLITE_OK ){
889 *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
891 sqlite3_free(zSql);
894 va_end(ap);
895 *ppStmt = pRet;
896 return rc;
899 static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
900 Fts5Config *pConfig = pTab->pConfig;
901 Fts5Sorter *pSorter;
902 int nPhrase;
903 int nByte;
904 int rc;
905 const char *zRank = pCsr->zRank;
906 const char *zRankArgs = pCsr->zRankArgs;
908 nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
909 nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
910 pSorter = (Fts5Sorter*)sqlite3_malloc(nByte);
911 if( pSorter==0 ) return SQLITE_NOMEM;
912 memset(pSorter, 0, nByte);
913 pSorter->nIdx = nPhrase;
915 /* TODO: It would be better to have some system for reusing statement
916 ** handles here, rather than preparing a new one for each query. But that
917 ** is not possible as SQLite reference counts the virtual table objects.
918 ** And since the statement required here reads from this very virtual
919 ** table, saving it creates a circular reference.
921 ** If SQLite a built-in statement cache, this wouldn't be a problem. */
922 rc = fts5PrepareStatement(&pSorter->pStmt, pConfig,
923 "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
924 pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
925 (zRankArgs ? ", " : ""),
926 (zRankArgs ? zRankArgs : ""),
927 bDesc ? "DESC" : "ASC"
930 pCsr->pSorter = pSorter;
931 if( rc==SQLITE_OK ){
932 assert( pTab->pSortCsr==0 );
933 pTab->pSortCsr = pCsr;
934 rc = fts5SorterNext(pCsr);
935 pTab->pSortCsr = 0;
938 if( rc!=SQLITE_OK ){
939 sqlite3_finalize(pSorter->pStmt);
940 sqlite3_free(pSorter);
941 pCsr->pSorter = 0;
944 return rc;
947 static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
948 int rc;
949 Fts5Expr *pExpr = pCsr->pExpr;
950 rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc);
951 if( sqlite3Fts5ExprEof(pExpr) ){
952 CsrFlagSet(pCsr, FTS5CSR_EOF);
954 fts5CsrNewrow(pCsr);
955 return rc;
959 ** Process a "special" query. A special query is identified as one with a
960 ** MATCH expression that begins with a '*' character. The remainder of
961 ** the text passed to the MATCH operator are used as the special query
962 ** parameters.
964 static int fts5SpecialMatch(
965 Fts5Table *pTab,
966 Fts5Cursor *pCsr,
967 const char *zQuery
969 int rc = SQLITE_OK; /* Return code */
970 const char *z = zQuery; /* Special query text */
971 int n; /* Number of bytes in text at z */
973 while( z[0]==' ' ) z++;
974 for(n=0; z[n] && z[n]!=' '; n++);
976 assert( pTab->base.zErrMsg==0 );
977 pCsr->ePlan = FTS5_PLAN_SPECIAL;
979 if( 0==sqlite3_strnicmp("reads", z, n) ){
980 pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex);
982 else if( 0==sqlite3_strnicmp("id", z, n) ){
983 pCsr->iSpecial = pCsr->iCsrId;
985 else{
986 /* An unrecognized directive. Return an error message. */
987 pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
988 rc = SQLITE_ERROR;
991 return rc;
995 ** Search for an auxiliary function named zName that can be used with table
996 ** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
997 ** structure. Otherwise, if no such function exists, return NULL.
999 static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){
1000 Fts5Auxiliary *pAux;
1002 for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){
1003 if( sqlite3_stricmp(zName, pAux->zFunc)==0 ) return pAux;
1006 /* No function of the specified name was found. Return 0. */
1007 return 0;
1011 static int fts5FindRankFunction(Fts5Cursor *pCsr){
1012 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1013 Fts5Config *pConfig = pTab->pConfig;
1014 int rc = SQLITE_OK;
1015 Fts5Auxiliary *pAux = 0;
1016 const char *zRank = pCsr->zRank;
1017 const char *zRankArgs = pCsr->zRankArgs;
1019 if( zRankArgs ){
1020 char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs);
1021 if( zSql ){
1022 sqlite3_stmt *pStmt = 0;
1023 rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
1024 SQLITE_PREPARE_PERSISTENT, &pStmt, 0);
1025 sqlite3_free(zSql);
1026 assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
1027 if( rc==SQLITE_OK ){
1028 if( SQLITE_ROW==sqlite3_step(pStmt) ){
1029 int nByte;
1030 pCsr->nRankArg = sqlite3_column_count(pStmt);
1031 nByte = sizeof(sqlite3_value*)*pCsr->nRankArg;
1032 pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte);
1033 if( rc==SQLITE_OK ){
1034 int i;
1035 for(i=0; i<pCsr->nRankArg; i++){
1036 pCsr->apRankArg[i] = sqlite3_column_value(pStmt, i);
1039 pCsr->pRankArgStmt = pStmt;
1040 }else{
1041 rc = sqlite3_finalize(pStmt);
1042 assert( rc!=SQLITE_OK );
1048 if( rc==SQLITE_OK ){
1049 pAux = fts5FindAuxiliary(pTab, zRank);
1050 if( pAux==0 ){
1051 assert( pTab->base.zErrMsg==0 );
1052 pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
1053 rc = SQLITE_ERROR;
1057 pCsr->pRank = pAux;
1058 return rc;
1062 static int fts5CursorParseRank(
1063 Fts5Config *pConfig,
1064 Fts5Cursor *pCsr,
1065 sqlite3_value *pRank
1067 int rc = SQLITE_OK;
1068 if( pRank ){
1069 const char *z = (const char*)sqlite3_value_text(pRank);
1070 char *zRank = 0;
1071 char *zRankArgs = 0;
1073 if( z==0 ){
1074 if( sqlite3_value_type(pRank)==SQLITE_NULL ) rc = SQLITE_ERROR;
1075 }else{
1076 rc = sqlite3Fts5ConfigParseRank(z, &zRank, &zRankArgs);
1078 if( rc==SQLITE_OK ){
1079 pCsr->zRank = zRank;
1080 pCsr->zRankArgs = zRankArgs;
1081 CsrFlagSet(pCsr, FTS5CSR_FREE_ZRANK);
1082 }else if( rc==SQLITE_ERROR ){
1083 pCsr->base.pVtab->zErrMsg = sqlite3_mprintf(
1084 "parse error in rank function: %s", z
1087 }else{
1088 if( pConfig->zRank ){
1089 pCsr->zRank = (char*)pConfig->zRank;
1090 pCsr->zRankArgs = (char*)pConfig->zRankArgs;
1091 }else{
1092 pCsr->zRank = (char*)FTS5_DEFAULT_RANK;
1093 pCsr->zRankArgs = 0;
1096 return rc;
1099 static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
1100 if( pVal ){
1101 int eType = sqlite3_value_numeric_type(pVal);
1102 if( eType==SQLITE_INTEGER ){
1103 return sqlite3_value_int64(pVal);
1106 return iDefault;
1110 ** This is the xFilter interface for the virtual table. See
1111 ** the virtual table xFilter method documentation for additional
1112 ** information.
1114 ** There are three possible query strategies:
1116 ** 1. Full-text search using a MATCH operator.
1117 ** 2. A by-rowid lookup.
1118 ** 3. A full-table scan.
1120 static int fts5FilterMethod(
1121 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
1122 int idxNum, /* Strategy index */
1123 const char *zUnused, /* Unused */
1124 int nVal, /* Number of elements in apVal */
1125 sqlite3_value **apVal /* Arguments for the indexing scheme */
1127 Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
1128 Fts5Config *pConfig = pTab->pConfig;
1129 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1130 int rc = SQLITE_OK; /* Error code */
1131 int iVal = 0; /* Counter for apVal[] */
1132 int bDesc; /* True if ORDER BY [rank|rowid] DESC */
1133 int bOrderByRank; /* True if ORDER BY rank */
1134 sqlite3_value *pMatch = 0; /* <tbl> MATCH ? expression (or NULL) */
1135 sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */
1136 sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
1137 sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
1138 sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
1139 int iCol; /* Column on LHS of MATCH operator */
1140 char **pzErrmsg = pConfig->pzErrmsg;
1142 UNUSED_PARAM(zUnused);
1143 UNUSED_PARAM(nVal);
1145 if( pCsr->ePlan ){
1146 fts5FreeCursorComponents(pCsr);
1147 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
1150 assert( pCsr->pStmt==0 );
1151 assert( pCsr->pExpr==0 );
1152 assert( pCsr->csrflags==0 );
1153 assert( pCsr->pRank==0 );
1154 assert( pCsr->zRank==0 );
1155 assert( pCsr->zRankArgs==0 );
1157 assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg );
1158 pConfig->pzErrmsg = &pTab->base.zErrMsg;
1160 /* Decode the arguments passed through to this function.
1162 ** Note: The following set of if(...) statements must be in the same
1163 ** order as the corresponding entries in the struct at the top of
1164 ** fts5BestIndexMethod(). */
1165 if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++];
1166 if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++];
1167 if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
1168 if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
1169 if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
1170 iCol = (idxNum>>16);
1171 assert( iCol>=0 && iCol<=pConfig->nCol );
1172 assert( iVal==nVal );
1173 bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
1174 pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
1176 /* Set the cursor upper and lower rowid limits. Only some strategies
1177 ** actually use them. This is ok, as the xBestIndex() method leaves the
1178 ** sqlite3_index_constraint.omit flag clear for range constraints
1179 ** on the rowid field. */
1180 if( pRowidEq ){
1181 pRowidLe = pRowidGe = pRowidEq;
1183 if( bDesc ){
1184 pCsr->iFirstRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
1185 pCsr->iLastRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
1186 }else{
1187 pCsr->iLastRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
1188 pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
1191 if( pTab->pSortCsr ){
1192 /* If pSortCsr is non-NULL, then this call is being made as part of
1193 ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
1194 ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
1195 ** return results to the user for this query. The current cursor
1196 ** (pCursor) is used to execute the query issued by function
1197 ** fts5CursorFirstSorted() above. */
1198 assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 );
1199 assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 );
1200 assert( pCsr->iLastRowid==LARGEST_INT64 );
1201 assert( pCsr->iFirstRowid==SMALLEST_INT64 );
1202 pCsr->ePlan = FTS5_PLAN_SOURCE;
1203 pCsr->pExpr = pTab->pSortCsr->pExpr;
1204 rc = fts5CursorFirst(pTab, pCsr, bDesc);
1205 }else if( pMatch ){
1206 const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
1207 if( zExpr==0 ) zExpr = "";
1209 rc = fts5CursorParseRank(pConfig, pCsr, pRank);
1210 if( rc==SQLITE_OK ){
1211 if( zExpr[0]=='*' ){
1212 /* The user has issued a query of the form "MATCH '*...'". This
1213 ** indicates that the MATCH expression is not a full text query,
1214 ** but a request for an internal parameter. */
1215 rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
1216 }else{
1217 char **pzErr = &pTab->base.zErrMsg;
1218 rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr);
1219 if( rc==SQLITE_OK ){
1220 if( bOrderByRank ){
1221 pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
1222 rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
1223 }else{
1224 pCsr->ePlan = FTS5_PLAN_MATCH;
1225 rc = fts5CursorFirst(pTab, pCsr, bDesc);
1230 }else if( pConfig->zContent==0 ){
1231 *pConfig->pzErrmsg = sqlite3_mprintf(
1232 "%s: table does not support scanning", pConfig->zName
1234 rc = SQLITE_ERROR;
1235 }else{
1236 /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
1237 ** by rowid (ePlan==FTS5_PLAN_ROWID). */
1238 pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
1239 rc = sqlite3Fts5StorageStmt(
1240 pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg
1242 if( rc==SQLITE_OK ){
1243 if( pCsr->ePlan==FTS5_PLAN_ROWID ){
1244 sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
1245 }else{
1246 sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
1247 sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid);
1249 rc = fts5NextMethod(pCursor);
1253 pConfig->pzErrmsg = pzErrmsg;
1254 return rc;
1258 ** This is the xEof method of the virtual table. SQLite calls this
1259 ** routine to find out if it has reached the end of a result set.
1261 static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
1262 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1263 return (CsrFlagTest(pCsr, FTS5CSR_EOF) ? 1 : 0);
1267 ** Return the rowid that the cursor currently points to.
1269 static i64 fts5CursorRowid(Fts5Cursor *pCsr){
1270 assert( pCsr->ePlan==FTS5_PLAN_MATCH
1271 || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
1272 || pCsr->ePlan==FTS5_PLAN_SOURCE
1274 if( pCsr->pSorter ){
1275 return pCsr->pSorter->iRowid;
1276 }else{
1277 return sqlite3Fts5ExprRowid(pCsr->pExpr);
1282 ** This is the xRowid method. The SQLite core calls this routine to
1283 ** retrieve the rowid for the current row of the result set. fts5
1284 ** exposes %_content.rowid as the rowid for the virtual table. The
1285 ** rowid should be written to *pRowid.
1287 static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
1288 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1289 int ePlan = pCsr->ePlan;
1291 assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
1292 switch( ePlan ){
1293 case FTS5_PLAN_SPECIAL:
1294 *pRowid = 0;
1295 break;
1297 case FTS5_PLAN_SOURCE:
1298 case FTS5_PLAN_MATCH:
1299 case FTS5_PLAN_SORTED_MATCH:
1300 *pRowid = fts5CursorRowid(pCsr);
1301 break;
1303 default:
1304 *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
1305 break;
1308 return SQLITE_OK;
1312 ** If the cursor requires seeking (bSeekRequired flag is set), seek it.
1313 ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
1315 ** If argument bErrormsg is true and an error occurs, an error message may
1316 ** be left in sqlite3_vtab.zErrMsg.
1318 static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
1319 int rc = SQLITE_OK;
1321 /* If the cursor does not yet have a statement handle, obtain one now. */
1322 if( pCsr->pStmt==0 ){
1323 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1324 int eStmt = fts5StmtType(pCsr);
1325 rc = sqlite3Fts5StorageStmt(
1326 pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0)
1328 assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 );
1329 assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
1332 if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
1333 assert( pCsr->pExpr );
1334 sqlite3_reset(pCsr->pStmt);
1335 sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
1336 rc = sqlite3_step(pCsr->pStmt);
1337 if( rc==SQLITE_ROW ){
1338 rc = SQLITE_OK;
1339 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
1340 }else{
1341 rc = sqlite3_reset(pCsr->pStmt);
1342 if( rc==SQLITE_OK ){
1343 rc = FTS5_CORRUPT;
1347 return rc;
1350 static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
1351 va_list ap; /* ... printf arguments */
1352 va_start(ap, zFormat);
1353 assert( p->base.zErrMsg==0 );
1354 p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
1355 va_end(ap);
1359 ** This function is called to handle an FTS INSERT command. In other words,
1360 ** an INSERT statement of the form:
1362 ** INSERT INTO fts(fts) VALUES($pCmd)
1363 ** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
1365 ** Argument pVal is the value assigned to column "fts" by the INSERT
1366 ** statement. This function returns SQLITE_OK if successful, or an SQLite
1367 ** error code if an error occurs.
1369 ** The commands implemented by this function are documented in the "Special
1370 ** INSERT Directives" section of the documentation. It should be updated if
1371 ** more commands are added to this function.
1373 static int fts5SpecialInsert(
1374 Fts5Table *pTab, /* Fts5 table object */
1375 const char *zCmd, /* Text inserted into table-name column */
1376 sqlite3_value *pVal /* Value inserted into rank column */
1378 Fts5Config *pConfig = pTab->pConfig;
1379 int rc = SQLITE_OK;
1380 int bError = 0;
1382 if( 0==sqlite3_stricmp("delete-all", zCmd) ){
1383 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
1384 fts5SetVtabError(pTab,
1385 "'delete-all' may only be used with a "
1386 "contentless or external content fts5 table"
1388 rc = SQLITE_ERROR;
1389 }else{
1390 rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
1392 }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
1393 if( pConfig->eContent==FTS5_CONTENT_NONE ){
1394 fts5SetVtabError(pTab,
1395 "'rebuild' may not be used with a contentless fts5 table"
1397 rc = SQLITE_ERROR;
1398 }else{
1399 rc = sqlite3Fts5StorageRebuild(pTab->pStorage);
1401 }else if( 0==sqlite3_stricmp("optimize", zCmd) ){
1402 rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
1403 }else if( 0==sqlite3_stricmp("merge", zCmd) ){
1404 int nMerge = sqlite3_value_int(pVal);
1405 rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
1406 }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
1407 rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
1408 #ifdef SQLITE_DEBUG
1409 }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
1410 pConfig->bPrefixIndex = sqlite3_value_int(pVal);
1411 #endif
1412 }else{
1413 rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
1414 if( rc==SQLITE_OK ){
1415 rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError);
1417 if( rc==SQLITE_OK ){
1418 if( bError ){
1419 rc = SQLITE_ERROR;
1420 }else{
1421 rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0);
1425 return rc;
1428 static int fts5SpecialDelete(
1429 Fts5Table *pTab,
1430 sqlite3_value **apVal
1432 int rc = SQLITE_OK;
1433 int eType1 = sqlite3_value_type(apVal[1]);
1434 if( eType1==SQLITE_INTEGER ){
1435 sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
1436 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
1438 return rc;
1441 static void fts5StorageInsert(
1442 int *pRc,
1443 Fts5Table *pTab,
1444 sqlite3_value **apVal,
1445 i64 *piRowid
1447 int rc = *pRc;
1448 if( rc==SQLITE_OK ){
1449 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
1451 if( rc==SQLITE_OK ){
1452 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
1454 *pRc = rc;
1458 ** This function is the implementation of the xUpdate callback used by
1459 ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
1460 ** inserted, updated or deleted.
1462 ** A delete specifies a single argument - the rowid of the row to remove.
1464 ** Update and insert operations pass:
1466 ** 1. The "old" rowid, or NULL.
1467 ** 2. The "new" rowid.
1468 ** 3. Values for each of the nCol matchable columns.
1469 ** 4. Values for the two hidden columns (<tablename> and "rank").
1471 static int fts5UpdateMethod(
1472 sqlite3_vtab *pVtab, /* Virtual table handle */
1473 int nArg, /* Size of argument array */
1474 sqlite3_value **apVal, /* Array of arguments */
1475 sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */
1477 Fts5Table *pTab = (Fts5Table*)pVtab;
1478 Fts5Config *pConfig = pTab->pConfig;
1479 int eType0; /* value_type() of apVal[0] */
1480 int rc = SQLITE_OK; /* Return code */
1482 /* A transaction must be open when this is called. */
1483 assert( pTab->ts.eState==1 );
1485 assert( pVtab->zErrMsg==0 );
1486 assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
1487 assert( nArg==1
1488 || sqlite3_value_type(apVal[1])==SQLITE_INTEGER
1489 || sqlite3_value_type(apVal[1])==SQLITE_NULL
1491 assert( pTab->pConfig->pzErrmsg==0 );
1492 pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
1494 /* Put any active cursors into REQUIRE_SEEK state. */
1495 fts5TripCursors(pTab);
1497 eType0 = sqlite3_value_type(apVal[0]);
1498 if( eType0==SQLITE_NULL
1499 && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
1501 /* A "special" INSERT op. These are handled separately. */
1502 const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]);
1503 if( pConfig->eContent!=FTS5_CONTENT_NORMAL
1504 && 0==sqlite3_stricmp("delete", z)
1506 rc = fts5SpecialDelete(pTab, apVal);
1507 }else{
1508 rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
1510 }else{
1511 /* A regular INSERT, UPDATE or DELETE statement. The trick here is that
1512 ** any conflict on the rowid value must be detected before any
1513 ** modifications are made to the database file. There are 4 cases:
1515 ** 1) DELETE
1516 ** 2) UPDATE (rowid not modified)
1517 ** 3) UPDATE (rowid modified)
1518 ** 4) INSERT
1520 ** Cases 3 and 4 may violate the rowid constraint.
1522 int eConflict = SQLITE_ABORT;
1523 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
1524 eConflict = sqlite3_vtab_on_conflict(pConfig->db);
1527 assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
1528 assert( nArg!=1 || eType0==SQLITE_INTEGER );
1530 /* Filter out attempts to run UPDATE or DELETE on contentless tables.
1531 ** This is not suported. */
1532 if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
1533 pTab->base.zErrMsg = sqlite3_mprintf(
1534 "cannot %s contentless fts5 table: %s",
1535 (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
1537 rc = SQLITE_ERROR;
1540 /* DELETE */
1541 else if( nArg==1 ){
1542 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
1543 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
1546 /* INSERT */
1547 else if( eType0!=SQLITE_INTEGER ){
1548 /* If this is a REPLACE, first remove the current entry (if any) */
1549 if( eConflict==SQLITE_REPLACE
1550 && sqlite3_value_type(apVal[1])==SQLITE_INTEGER
1552 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
1553 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
1555 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1558 /* UPDATE */
1559 else{
1560 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
1561 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
1562 if( iOld!=iNew ){
1563 if( eConflict==SQLITE_REPLACE ){
1564 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1565 if( rc==SQLITE_OK ){
1566 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
1568 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1569 }else{
1570 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
1571 if( rc==SQLITE_OK ){
1572 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1574 if( rc==SQLITE_OK ){
1575 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
1578 }else{
1579 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
1580 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1585 pTab->pConfig->pzErrmsg = 0;
1586 return rc;
1590 ** Implementation of xSync() method.
1592 static int fts5SyncMethod(sqlite3_vtab *pVtab){
1593 int rc;
1594 Fts5Table *pTab = (Fts5Table*)pVtab;
1595 fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
1596 pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
1597 fts5TripCursors(pTab);
1598 rc = sqlite3Fts5StorageSync(pTab->pStorage);
1599 pTab->pConfig->pzErrmsg = 0;
1600 return rc;
1604 ** Implementation of xBegin() method.
1606 static int fts5BeginMethod(sqlite3_vtab *pVtab){
1607 fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
1608 fts5NewTransaction((Fts5Table*)pVtab);
1609 return SQLITE_OK;
1613 ** Implementation of xCommit() method. This is a no-op. The contents of
1614 ** the pending-terms hash-table have already been flushed into the database
1615 ** by fts5SyncMethod().
1617 static int fts5CommitMethod(sqlite3_vtab *pVtab){
1618 UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */
1619 fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
1620 return SQLITE_OK;
1624 ** Implementation of xRollback(). Discard the contents of the pending-terms
1625 ** hash-table. Any changes made to the database are reverted by SQLite.
1627 static int fts5RollbackMethod(sqlite3_vtab *pVtab){
1628 int rc;
1629 Fts5Table *pTab = (Fts5Table*)pVtab;
1630 fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
1631 rc = sqlite3Fts5StorageRollback(pTab->pStorage);
1632 return rc;
1635 static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*);
1637 static void *fts5ApiUserData(Fts5Context *pCtx){
1638 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1639 return pCsr->pAux->pUserData;
1642 static int fts5ApiColumnCount(Fts5Context *pCtx){
1643 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1644 return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol;
1647 static int fts5ApiColumnTotalSize(
1648 Fts5Context *pCtx,
1649 int iCol,
1650 sqlite3_int64 *pnToken
1652 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1653 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1654 return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken);
1657 static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
1658 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1659 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1660 return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
1663 static int fts5ApiTokenize(
1664 Fts5Context *pCtx,
1665 const char *pText, int nText,
1666 void *pUserData,
1667 int (*xToken)(void*, int, const char*, int, int, int)
1669 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1670 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1671 return sqlite3Fts5Tokenize(
1672 pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
1676 static int fts5ApiPhraseCount(Fts5Context *pCtx){
1677 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1678 return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
1681 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
1682 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1683 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
1686 static int fts5ApiColumnText(
1687 Fts5Context *pCtx,
1688 int iCol,
1689 const char **pz,
1690 int *pn
1692 int rc = SQLITE_OK;
1693 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1694 if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
1695 *pz = 0;
1696 *pn = 0;
1697 }else{
1698 rc = fts5SeekCursor(pCsr, 0);
1699 if( rc==SQLITE_OK ){
1700 *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
1701 *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
1704 return rc;
1707 static int fts5CsrPoslist(
1708 Fts5Cursor *pCsr,
1709 int iPhrase,
1710 const u8 **pa,
1711 int *pn
1713 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
1714 int rc = SQLITE_OK;
1715 int bLive = (pCsr->pSorter==0);
1717 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
1719 if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
1720 Fts5PoslistPopulator *aPopulator;
1721 int i;
1722 aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
1723 if( aPopulator==0 ) rc = SQLITE_NOMEM;
1724 for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
1725 int n; const char *z;
1726 rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
1727 if( rc==SQLITE_OK ){
1728 rc = sqlite3Fts5ExprPopulatePoslists(
1729 pConfig, pCsr->pExpr, aPopulator, i, z, n
1733 sqlite3_free(aPopulator);
1735 if( pCsr->pSorter ){
1736 sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
1739 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
1742 if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
1743 Fts5Sorter *pSorter = pCsr->pSorter;
1744 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
1745 *pn = pSorter->aIdx[iPhrase] - i1;
1746 *pa = &pSorter->aPoslist[i1];
1747 }else{
1748 *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
1751 return rc;
1755 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
1756 ** correctly for the current view. Return SQLITE_OK if successful, or an
1757 ** SQLite error code otherwise.
1759 static int fts5CacheInstArray(Fts5Cursor *pCsr){
1760 int rc = SQLITE_OK;
1761 Fts5PoslistReader *aIter; /* One iterator for each phrase */
1762 int nIter; /* Number of iterators/phrases */
1764 nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
1765 if( pCsr->aInstIter==0 ){
1766 int nByte = sizeof(Fts5PoslistReader) * nIter;
1767 pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
1769 aIter = pCsr->aInstIter;
1771 if( aIter ){
1772 int nInst = 0; /* Number instances seen so far */
1773 int i;
1775 /* Initialize all iterators */
1776 for(i=0; i<nIter && rc==SQLITE_OK; i++){
1777 const u8 *a;
1778 int n;
1779 rc = fts5CsrPoslist(pCsr, i, &a, &n);
1780 if( rc==SQLITE_OK ){
1781 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
1785 if( rc==SQLITE_OK ){
1786 while( 1 ){
1787 int *aInst;
1788 int iBest = -1;
1789 for(i=0; i<nIter; i++){
1790 if( (aIter[i].bEof==0)
1791 && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
1793 iBest = i;
1796 if( iBest<0 ) break;
1798 nInst++;
1799 if( nInst>=pCsr->nInstAlloc ){
1800 pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
1801 aInst = (int*)sqlite3_realloc(
1802 pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
1804 if( aInst ){
1805 pCsr->aInst = aInst;
1806 }else{
1807 rc = SQLITE_NOMEM;
1808 break;
1812 aInst = &pCsr->aInst[3 * (nInst-1)];
1813 aInst[0] = iBest;
1814 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
1815 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
1816 sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
1820 pCsr->nInstCount = nInst;
1821 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
1823 return rc;
1826 static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
1827 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1828 int rc = SQLITE_OK;
1829 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
1830 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
1831 *pnInst = pCsr->nInstCount;
1833 return rc;
1836 static int fts5ApiInst(
1837 Fts5Context *pCtx,
1838 int iIdx,
1839 int *piPhrase,
1840 int *piCol,
1841 int *piOff
1843 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1844 int rc = SQLITE_OK;
1845 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
1846 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
1848 if( iIdx<0 || iIdx>=pCsr->nInstCount ){
1849 rc = SQLITE_RANGE;
1850 #if 0
1851 }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
1852 *piPhrase = pCsr->aInst[iIdx*3];
1853 *piCol = pCsr->aInst[iIdx*3 + 2];
1854 *piOff = -1;
1855 #endif
1856 }else{
1857 *piPhrase = pCsr->aInst[iIdx*3];
1858 *piCol = pCsr->aInst[iIdx*3 + 1];
1859 *piOff = pCsr->aInst[iIdx*3 + 2];
1862 return rc;
1865 static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
1866 return fts5CursorRowid((Fts5Cursor*)pCtx);
1869 static int fts5ColumnSizeCb(
1870 void *pContext, /* Pointer to int */
1871 int tflags,
1872 const char *pUnused, /* Buffer containing token */
1873 int nUnused, /* Size of token in bytes */
1874 int iUnused1, /* Start offset of token */
1875 int iUnused2 /* End offset of token */
1877 int *pCnt = (int*)pContext;
1878 UNUSED_PARAM2(pUnused, nUnused);
1879 UNUSED_PARAM2(iUnused1, iUnused2);
1880 if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
1881 (*pCnt)++;
1883 return SQLITE_OK;
1886 static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
1887 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1888 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1889 Fts5Config *pConfig = pTab->pConfig;
1890 int rc = SQLITE_OK;
1892 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
1893 if( pConfig->bColumnsize ){
1894 i64 iRowid = fts5CursorRowid(pCsr);
1895 rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
1896 }else if( pConfig->zContent==0 ){
1897 int i;
1898 for(i=0; i<pConfig->nCol; i++){
1899 if( pConfig->abUnindexed[i]==0 ){
1900 pCsr->aColumnSize[i] = -1;
1903 }else{
1904 int i;
1905 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
1906 if( pConfig->abUnindexed[i]==0 ){
1907 const char *z; int n;
1908 void *p = (void*)(&pCsr->aColumnSize[i]);
1909 pCsr->aColumnSize[i] = 0;
1910 rc = fts5ApiColumnText(pCtx, i, &z, &n);
1911 if( rc==SQLITE_OK ){
1912 rc = sqlite3Fts5Tokenize(
1913 pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
1919 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
1921 if( iCol<0 ){
1922 int i;
1923 *pnToken = 0;
1924 for(i=0; i<pConfig->nCol; i++){
1925 *pnToken += pCsr->aColumnSize[i];
1927 }else if( iCol<pConfig->nCol ){
1928 *pnToken = pCsr->aColumnSize[iCol];
1929 }else{
1930 *pnToken = 0;
1931 rc = SQLITE_RANGE;
1933 return rc;
1937 ** Implementation of the xSetAuxdata() method.
1939 static int fts5ApiSetAuxdata(
1940 Fts5Context *pCtx, /* Fts5 context */
1941 void *pPtr, /* Pointer to save as auxdata */
1942 void(*xDelete)(void*) /* Destructor for pPtr (or NULL) */
1944 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1945 Fts5Auxdata *pData;
1947 /* Search through the cursors list of Fts5Auxdata objects for one that
1948 ** corresponds to the currently executing auxiliary function. */
1949 for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
1950 if( pData->pAux==pCsr->pAux ) break;
1953 if( pData ){
1954 if( pData->xDelete ){
1955 pData->xDelete(pData->pPtr);
1957 }else{
1958 int rc = SQLITE_OK;
1959 pData = (Fts5Auxdata*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Auxdata));
1960 if( pData==0 ){
1961 if( xDelete ) xDelete(pPtr);
1962 return rc;
1964 pData->pAux = pCsr->pAux;
1965 pData->pNext = pCsr->pAuxdata;
1966 pCsr->pAuxdata = pData;
1969 pData->xDelete = xDelete;
1970 pData->pPtr = pPtr;
1971 return SQLITE_OK;
1974 static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
1975 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1976 Fts5Auxdata *pData;
1977 void *pRet = 0;
1979 for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
1980 if( pData->pAux==pCsr->pAux ) break;
1983 if( pData ){
1984 pRet = pData->pPtr;
1985 if( bClear ){
1986 pData->pPtr = 0;
1987 pData->xDelete = 0;
1991 return pRet;
1994 static void fts5ApiPhraseNext(
1995 Fts5Context *pUnused,
1996 Fts5PhraseIter *pIter,
1997 int *piCol, int *piOff
1999 UNUSED_PARAM(pUnused);
2000 if( pIter->a>=pIter->b ){
2001 *piCol = -1;
2002 *piOff = -1;
2003 }else{
2004 int iVal;
2005 pIter->a += fts5GetVarint32(pIter->a, iVal);
2006 if( iVal==1 ){
2007 pIter->a += fts5GetVarint32(pIter->a, iVal);
2008 *piCol = iVal;
2009 *piOff = 0;
2010 pIter->a += fts5GetVarint32(pIter->a, iVal);
2012 *piOff += (iVal-2);
2016 static int fts5ApiPhraseFirst(
2017 Fts5Context *pCtx,
2018 int iPhrase,
2019 Fts5PhraseIter *pIter,
2020 int *piCol, int *piOff
2022 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2023 int n;
2024 int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
2025 if( rc==SQLITE_OK ){
2026 pIter->b = &pIter->a[n];
2027 *piCol = 0;
2028 *piOff = 0;
2029 fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
2031 return rc;
2034 static void fts5ApiPhraseNextColumn(
2035 Fts5Context *pCtx,
2036 Fts5PhraseIter *pIter,
2037 int *piCol
2039 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2040 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
2042 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
2043 if( pIter->a>=pIter->b ){
2044 *piCol = -1;
2045 }else{
2046 int iIncr;
2047 pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
2048 *piCol += (iIncr-2);
2050 }else{
2051 while( 1 ){
2052 int dummy;
2053 if( pIter->a>=pIter->b ){
2054 *piCol = -1;
2055 return;
2057 if( pIter->a[0]==0x01 ) break;
2058 pIter->a += fts5GetVarint32(pIter->a, dummy);
2060 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
2064 static int fts5ApiPhraseFirstColumn(
2065 Fts5Context *pCtx,
2066 int iPhrase,
2067 Fts5PhraseIter *pIter,
2068 int *piCol
2070 int rc = SQLITE_OK;
2071 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2072 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
2074 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
2075 Fts5Sorter *pSorter = pCsr->pSorter;
2076 int n;
2077 if( pSorter ){
2078 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
2079 n = pSorter->aIdx[iPhrase] - i1;
2080 pIter->a = &pSorter->aPoslist[i1];
2081 }else{
2082 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
2084 if( rc==SQLITE_OK ){
2085 pIter->b = &pIter->a[n];
2086 *piCol = 0;
2087 fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
2089 }else{
2090 int n;
2091 rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
2092 if( rc==SQLITE_OK ){
2093 pIter->b = &pIter->a[n];
2094 if( n<=0 ){
2095 *piCol = -1;
2096 }else if( pIter->a[0]==0x01 ){
2097 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
2098 }else{
2099 *piCol = 0;
2104 return rc;
2108 static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
2109 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
2112 static const Fts5ExtensionApi sFts5Api = {
2113 2, /* iVersion */
2114 fts5ApiUserData,
2115 fts5ApiColumnCount,
2116 fts5ApiRowCount,
2117 fts5ApiColumnTotalSize,
2118 fts5ApiTokenize,
2119 fts5ApiPhraseCount,
2120 fts5ApiPhraseSize,
2121 fts5ApiInstCount,
2122 fts5ApiInst,
2123 fts5ApiRowid,
2124 fts5ApiColumnText,
2125 fts5ApiColumnSize,
2126 fts5ApiQueryPhrase,
2127 fts5ApiSetAuxdata,
2128 fts5ApiGetAuxdata,
2129 fts5ApiPhraseFirst,
2130 fts5ApiPhraseNext,
2131 fts5ApiPhraseFirstColumn,
2132 fts5ApiPhraseNextColumn,
2136 ** Implementation of API function xQueryPhrase().
2138 static int fts5ApiQueryPhrase(
2139 Fts5Context *pCtx,
2140 int iPhrase,
2141 void *pUserData,
2142 int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
2144 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
2145 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
2146 int rc;
2147 Fts5Cursor *pNew = 0;
2149 rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
2150 if( rc==SQLITE_OK ){
2151 pNew->ePlan = FTS5_PLAN_MATCH;
2152 pNew->iFirstRowid = SMALLEST_INT64;
2153 pNew->iLastRowid = LARGEST_INT64;
2154 pNew->base.pVtab = (sqlite3_vtab*)pTab;
2155 rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr);
2158 if( rc==SQLITE_OK ){
2159 for(rc = fts5CursorFirst(pTab, pNew, 0);
2160 rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0;
2161 rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew)
2163 rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData);
2164 if( rc!=SQLITE_OK ){
2165 if( rc==SQLITE_DONE ) rc = SQLITE_OK;
2166 break;
2171 fts5CloseMethod((sqlite3_vtab_cursor*)pNew);
2172 return rc;
2175 static void fts5ApiInvoke(
2176 Fts5Auxiliary *pAux,
2177 Fts5Cursor *pCsr,
2178 sqlite3_context *context,
2179 int argc,
2180 sqlite3_value **argv
2182 assert( pCsr->pAux==0 );
2183 pCsr->pAux = pAux;
2184 pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
2185 pCsr->pAux = 0;
2188 static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
2189 Fts5Cursor *pCsr;
2190 for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
2191 if( pCsr->iCsrId==iCsrId ) break;
2193 return pCsr;
2196 static void fts5ApiCallback(
2197 sqlite3_context *context,
2198 int argc,
2199 sqlite3_value **argv
2202 Fts5Auxiliary *pAux;
2203 Fts5Cursor *pCsr;
2204 i64 iCsrId;
2206 assert( argc>=1 );
2207 pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
2208 iCsrId = sqlite3_value_int64(argv[0]);
2210 pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
2211 if( pCsr==0 ){
2212 char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
2213 sqlite3_result_error(context, zErr, -1);
2214 sqlite3_free(zErr);
2215 }else{
2216 fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
2222 ** Given cursor id iId, return a pointer to the corresponding Fts5Index
2223 ** object. Or NULL If the cursor id does not exist.
2225 ** If successful, set *ppConfig to point to the associated config object
2226 ** before returning.
2228 Fts5Index *sqlite3Fts5IndexFromCsrid(
2229 Fts5Global *pGlobal, /* FTS5 global context for db handle */
2230 i64 iCsrId, /* Id of cursor to find */
2231 Fts5Config **ppConfig /* OUT: Configuration object */
2233 Fts5Cursor *pCsr;
2234 Fts5Table *pTab;
2236 pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
2237 pTab = (Fts5Table*)pCsr->base.pVtab;
2238 *ppConfig = pTab->pConfig;
2240 return pTab->pIndex;
2244 ** Return a "position-list blob" corresponding to the current position of
2245 ** cursor pCsr via sqlite3_result_blob(). A position-list blob contains
2246 ** the current position-list for each phrase in the query associated with
2247 ** cursor pCsr.
2249 ** A position-list blob begins with (nPhrase-1) varints, where nPhrase is
2250 ** the number of phrases in the query. Following the varints are the
2251 ** concatenated position lists for each phrase, in order.
2253 ** The first varint (if it exists) contains the size of the position list
2254 ** for phrase 0. The second (same disclaimer) contains the size of position
2255 ** list 1. And so on. There is no size field for the final position list,
2256 ** as it can be derived from the total size of the blob.
2258 static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
2259 int i;
2260 int rc = SQLITE_OK;
2261 int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
2262 Fts5Buffer val;
2264 memset(&val, 0, sizeof(Fts5Buffer));
2265 switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){
2266 case FTS5_DETAIL_FULL:
2268 /* Append the varints */
2269 for(i=0; i<(nPhrase-1); i++){
2270 const u8 *dummy;
2271 int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
2272 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
2275 /* Append the position lists */
2276 for(i=0; i<nPhrase; i++){
2277 const u8 *pPoslist;
2278 int nPoslist;
2279 nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
2280 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
2282 break;
2284 case FTS5_DETAIL_COLUMNS:
2286 /* Append the varints */
2287 for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){
2288 const u8 *dummy;
2289 int nByte;
2290 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte);
2291 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
2294 /* Append the position lists */
2295 for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
2296 const u8 *pPoslist;
2297 int nPoslist;
2298 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist);
2299 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
2301 break;
2303 default:
2304 break;
2307 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
2308 return rc;
2312 ** This is the xColumn method, called by SQLite to request a value from
2313 ** the row that the supplied cursor currently points to.
2315 static int fts5ColumnMethod(
2316 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
2317 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
2318 int iCol /* Index of column to read value from */
2320 Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
2321 Fts5Config *pConfig = pTab->pConfig;
2322 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
2323 int rc = SQLITE_OK;
2325 assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
2327 if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){
2328 if( iCol==pConfig->nCol ){
2329 sqlite3_result_int64(pCtx, pCsr->iSpecial);
2331 }else
2333 if( iCol==pConfig->nCol ){
2334 /* User is requesting the value of the special column with the same name
2335 ** as the table. Return the cursor integer id number. This value is only
2336 ** useful in that it may be passed as the first argument to an FTS5
2337 ** auxiliary function. */
2338 sqlite3_result_int64(pCtx, pCsr->iCsrId);
2339 }else if( iCol==pConfig->nCol+1 ){
2341 /* The value of the "rank" column. */
2342 if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
2343 fts5PoslistBlob(pCtx, pCsr);
2344 }else if(
2345 pCsr->ePlan==FTS5_PLAN_MATCH
2346 || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
2348 if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
2349 fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
2352 }else if( !fts5IsContentless(pTab) ){
2353 rc = fts5SeekCursor(pCsr, 1);
2354 if( rc==SQLITE_OK ){
2355 sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
2358 return rc;
2363 ** This routine implements the xFindFunction method for the FTS3
2364 ** virtual table.
2366 static int fts5FindFunctionMethod(
2367 sqlite3_vtab *pVtab, /* Virtual table handle */
2368 int nUnused, /* Number of SQL function arguments */
2369 const char *zName, /* Name of SQL function */
2370 void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
2371 void **ppArg /* OUT: User data for *pxFunc */
2373 Fts5Table *pTab = (Fts5Table*)pVtab;
2374 Fts5Auxiliary *pAux;
2376 UNUSED_PARAM(nUnused);
2377 pAux = fts5FindAuxiliary(pTab, zName);
2378 if( pAux ){
2379 *pxFunc = fts5ApiCallback;
2380 *ppArg = (void*)pAux;
2381 return 1;
2384 /* No function of the specified name was found. Return 0. */
2385 return 0;
2389 ** Implementation of FTS5 xRename method. Rename an fts5 table.
2391 static int fts5RenameMethod(
2392 sqlite3_vtab *pVtab, /* Virtual table handle */
2393 const char *zName /* New name of table */
2395 Fts5Table *pTab = (Fts5Table*)pVtab;
2396 return sqlite3Fts5StorageRename(pTab->pStorage, zName);
2400 ** The xSavepoint() method.
2402 ** Flush the contents of the pending-terms table to disk.
2404 static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
2405 Fts5Table *pTab = (Fts5Table*)pVtab;
2406 UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
2407 fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
2408 fts5TripCursors(pTab);
2409 return sqlite3Fts5StorageSync(pTab->pStorage);
2413 ** The xRelease() method.
2415 ** This is a no-op.
2417 static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
2418 Fts5Table *pTab = (Fts5Table*)pVtab;
2419 UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
2420 fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
2421 fts5TripCursors(pTab);
2422 return sqlite3Fts5StorageSync(pTab->pStorage);
2426 ** The xRollbackTo() method.
2428 ** Discard the contents of the pending terms table.
2430 static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
2431 Fts5Table *pTab = (Fts5Table*)pVtab;
2432 UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
2433 fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
2434 fts5TripCursors(pTab);
2435 return sqlite3Fts5StorageRollback(pTab->pStorage);
2439 ** Register a new auxiliary function with global context pGlobal.
2441 static int fts5CreateAux(
2442 fts5_api *pApi, /* Global context (one per db handle) */
2443 const char *zName, /* Name of new function */
2444 void *pUserData, /* User data for aux. function */
2445 fts5_extension_function xFunc, /* Aux. function implementation */
2446 void(*xDestroy)(void*) /* Destructor for pUserData */
2448 Fts5Global *pGlobal = (Fts5Global*)pApi;
2449 int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
2450 if( rc==SQLITE_OK ){
2451 Fts5Auxiliary *pAux;
2452 int nName; /* Size of zName in bytes, including \0 */
2453 int nByte; /* Bytes of space to allocate */
2455 nName = (int)strlen(zName) + 1;
2456 nByte = sizeof(Fts5Auxiliary) + nName;
2457 pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte);
2458 if( pAux ){
2459 memset(pAux, 0, nByte);
2460 pAux->zFunc = (char*)&pAux[1];
2461 memcpy(pAux->zFunc, zName, nName);
2462 pAux->pGlobal = pGlobal;
2463 pAux->pUserData = pUserData;
2464 pAux->xFunc = xFunc;
2465 pAux->xDestroy = xDestroy;
2466 pAux->pNext = pGlobal->pAux;
2467 pGlobal->pAux = pAux;
2468 }else{
2469 rc = SQLITE_NOMEM;
2473 return rc;
2477 ** Register a new tokenizer. This is the implementation of the
2478 ** fts5_api.xCreateTokenizer() method.
2480 static int fts5CreateTokenizer(
2481 fts5_api *pApi, /* Global context (one per db handle) */
2482 const char *zName, /* Name of new function */
2483 void *pUserData, /* User data for aux. function */
2484 fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
2485 void(*xDestroy)(void*) /* Destructor for pUserData */
2487 Fts5Global *pGlobal = (Fts5Global*)pApi;
2488 Fts5TokenizerModule *pNew;
2489 int nName; /* Size of zName and its \0 terminator */
2490 int nByte; /* Bytes of space to allocate */
2491 int rc = SQLITE_OK;
2493 nName = (int)strlen(zName) + 1;
2494 nByte = sizeof(Fts5TokenizerModule) + nName;
2495 pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte);
2496 if( pNew ){
2497 memset(pNew, 0, nByte);
2498 pNew->zName = (char*)&pNew[1];
2499 memcpy(pNew->zName, zName, nName);
2500 pNew->pUserData = pUserData;
2501 pNew->x = *pTokenizer;
2502 pNew->xDestroy = xDestroy;
2503 pNew->pNext = pGlobal->pTok;
2504 pGlobal->pTok = pNew;
2505 if( pNew->pNext==0 ){
2506 pGlobal->pDfltTok = pNew;
2508 }else{
2509 rc = SQLITE_NOMEM;
2512 return rc;
2515 static Fts5TokenizerModule *fts5LocateTokenizer(
2516 Fts5Global *pGlobal,
2517 const char *zName
2519 Fts5TokenizerModule *pMod = 0;
2521 if( zName==0 ){
2522 pMod = pGlobal->pDfltTok;
2523 }else{
2524 for(pMod=pGlobal->pTok; pMod; pMod=pMod->pNext){
2525 if( sqlite3_stricmp(zName, pMod->zName)==0 ) break;
2529 return pMod;
2533 ** Find a tokenizer. This is the implementation of the
2534 ** fts5_api.xFindTokenizer() method.
2536 static int fts5FindTokenizer(
2537 fts5_api *pApi, /* Global context (one per db handle) */
2538 const char *zName, /* Name of new function */
2539 void **ppUserData,
2540 fts5_tokenizer *pTokenizer /* Populate this object */
2542 int rc = SQLITE_OK;
2543 Fts5TokenizerModule *pMod;
2545 pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
2546 if( pMod ){
2547 *pTokenizer = pMod->x;
2548 *ppUserData = pMod->pUserData;
2549 }else{
2550 memset(pTokenizer, 0, sizeof(fts5_tokenizer));
2551 rc = SQLITE_ERROR;
2554 return rc;
2557 int sqlite3Fts5GetTokenizer(
2558 Fts5Global *pGlobal,
2559 const char **azArg,
2560 int nArg,
2561 Fts5Tokenizer **ppTok,
2562 fts5_tokenizer **ppTokApi,
2563 char **pzErr
2565 Fts5TokenizerModule *pMod;
2566 int rc = SQLITE_OK;
2568 pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
2569 if( pMod==0 ){
2570 assert( nArg>0 );
2571 rc = SQLITE_ERROR;
2572 *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
2573 }else{
2574 rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok);
2575 *ppTokApi = &pMod->x;
2576 if( rc!=SQLITE_OK && pzErr ){
2577 *pzErr = sqlite3_mprintf("error in tokenizer constructor");
2581 if( rc!=SQLITE_OK ){
2582 *ppTokApi = 0;
2583 *ppTok = 0;
2586 return rc;
2589 static void fts5ModuleDestroy(void *pCtx){
2590 Fts5TokenizerModule *pTok, *pNextTok;
2591 Fts5Auxiliary *pAux, *pNextAux;
2592 Fts5Global *pGlobal = (Fts5Global*)pCtx;
2594 for(pAux=pGlobal->pAux; pAux; pAux=pNextAux){
2595 pNextAux = pAux->pNext;
2596 if( pAux->xDestroy ) pAux->xDestroy(pAux->pUserData);
2597 sqlite3_free(pAux);
2600 for(pTok=pGlobal->pTok; pTok; pTok=pNextTok){
2601 pNextTok = pTok->pNext;
2602 if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData);
2603 sqlite3_free(pTok);
2606 sqlite3_free(pGlobal);
2609 static void fts5Fts5Func(
2610 sqlite3_context *pCtx, /* Function call context */
2611 int nArg, /* Number of args */
2612 sqlite3_value **apArg /* Function arguments */
2614 Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
2615 fts5_api **ppApi;
2616 UNUSED_PARAM(nArg);
2617 assert( nArg==1 );
2618 ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr");
2619 if( ppApi ) *ppApi = &pGlobal->api;
2623 ** Implementation of fts5_source_id() function.
2625 static void fts5SourceIdFunc(
2626 sqlite3_context *pCtx, /* Function call context */
2627 int nArg, /* Number of args */
2628 sqlite3_value **apUnused /* Function arguments */
2630 assert( nArg==0 );
2631 UNUSED_PARAM2(nArg, apUnused);
2632 sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
2635 static int fts5Init(sqlite3 *db){
2636 static const sqlite3_module fts5Mod = {
2637 /* iVersion */ 2,
2638 /* xCreate */ fts5CreateMethod,
2639 /* xConnect */ fts5ConnectMethod,
2640 /* xBestIndex */ fts5BestIndexMethod,
2641 /* xDisconnect */ fts5DisconnectMethod,
2642 /* xDestroy */ fts5DestroyMethod,
2643 /* xOpen */ fts5OpenMethod,
2644 /* xClose */ fts5CloseMethod,
2645 /* xFilter */ fts5FilterMethod,
2646 /* xNext */ fts5NextMethod,
2647 /* xEof */ fts5EofMethod,
2648 /* xColumn */ fts5ColumnMethod,
2649 /* xRowid */ fts5RowidMethod,
2650 /* xUpdate */ fts5UpdateMethod,
2651 /* xBegin */ fts5BeginMethod,
2652 /* xSync */ fts5SyncMethod,
2653 /* xCommit */ fts5CommitMethod,
2654 /* xRollback */ fts5RollbackMethod,
2655 /* xFindFunction */ fts5FindFunctionMethod,
2656 /* xRename */ fts5RenameMethod,
2657 /* xSavepoint */ fts5SavepointMethod,
2658 /* xRelease */ fts5ReleaseMethod,
2659 /* xRollbackTo */ fts5RollbackToMethod,
2662 int rc;
2663 Fts5Global *pGlobal = 0;
2665 pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
2666 if( pGlobal==0 ){
2667 rc = SQLITE_NOMEM;
2668 }else{
2669 void *p = (void*)pGlobal;
2670 memset(pGlobal, 0, sizeof(Fts5Global));
2671 pGlobal->db = db;
2672 pGlobal->api.iVersion = 2;
2673 pGlobal->api.xCreateFunction = fts5CreateAux;
2674 pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
2675 pGlobal->api.xFindTokenizer = fts5FindTokenizer;
2676 rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
2677 if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
2678 if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
2679 if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
2680 if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
2681 if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
2682 if( rc==SQLITE_OK ){
2683 rc = sqlite3_create_function(
2684 db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
2687 if( rc==SQLITE_OK ){
2688 rc = sqlite3_create_function(
2689 db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
2694 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
2695 ** fts5_test_mi.c is compiled and linked into the executable. And call
2696 ** its entry point to enable the matchinfo() demo. */
2697 #ifdef SQLITE_FTS5_ENABLE_TEST_MI
2698 if( rc==SQLITE_OK ){
2699 extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
2700 rc = sqlite3Fts5TestRegisterMatchinfo(db);
2702 #endif
2704 return rc;
2708 ** The following functions are used to register the module with SQLite. If
2709 ** this module is being built as part of the SQLite core (SQLITE_CORE is
2710 ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
2712 ** Or, if this module is being built as a loadable extension,
2713 ** sqlite3Fts5Init() is omitted and the two standard entry points
2714 ** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
2716 #ifndef SQLITE_CORE
2717 #ifdef _WIN32
2718 __declspec(dllexport)
2719 #endif
2720 int sqlite3_fts_init(
2721 sqlite3 *db,
2722 char **pzErrMsg,
2723 const sqlite3_api_routines *pApi
2725 SQLITE_EXTENSION_INIT2(pApi);
2726 (void)pzErrMsg; /* Unused parameter */
2727 return fts5Init(db);
2730 #ifdef _WIN32
2731 __declspec(dllexport)
2732 #endif
2733 int sqlite3_fts5_init(
2734 sqlite3 *db,
2735 char **pzErrMsg,
2736 const sqlite3_api_routines *pApi
2738 SQLITE_EXTENSION_INIT2(pApi);
2739 (void)pzErrMsg; /* Unused parameter */
2740 return fts5Init(db);
2742 #else
2743 int sqlite3Fts5Init(sqlite3 *db){
2744 return fts5Init(db);
2746 #endif