4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
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()
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.
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.
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 */
124 struct Fts5TransactionState ts
;
128 struct Fts5MatchPhrase
{
129 Fts5Buffer
*pPoslist
; /* Pointer to current poslist */
130 int nTerm
; /* Size of phrase in terms */
135 ** SELECT rowid, <fts> FROM <fts> ORDER BY +rank;
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.
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.
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
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))
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 */
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
){
260 assert( p
->ts
.eState
==0 );
262 p
->ts
.iSavepoint
= -1;
266 assert( p
->ts
.eState
==1 );
271 assert( p
->ts
.eState
==2 );
276 assert( p
->ts
.eState
==1 || p
->ts
.eState
==2 || p
->ts
.eState
==0 );
281 assert( p
->ts
.eState
==1 );
282 assert( iSavepoint
>=0 );
283 assert( iSavepoint
>p
->ts
.iSavepoint
);
284 p
->ts
.iSavepoint
= iSavepoint
;
288 assert( p
->ts
.eState
==1 );
289 assert( iSavepoint
>=0 );
290 assert( iSavepoint
<=p
->ts
.iSavepoint
);
291 p
->ts
.iSavepoint
= iSavepoint
-1;
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
;
303 # define fts5CheckTransactionState(x,y,z)
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
){
318 sqlite3Fts5IndexClose(pTab
->pIndex
);
319 sqlite3Fts5StorageClose(pTab
->pStorage
);
320 sqlite3Fts5ConfigFree(pTab
->pConfig
);
326 ** The xDisconnect() virtual table method.
328 static int fts5DisconnectMethod(sqlite3_vtab
*pVtab
){
329 fts5FreeVtab((Fts5Table
*)pVtab
);
334 ** The xDestroy() virtual table method.
336 static int fts5DestroyMethod(sqlite3_vtab
*pVtab
){
337 Fts5Table
*pTab
= (Fts5Table
*)pVtab
;
338 int rc
= sqlite3Fts5DropAll(pTab
->pConfig
);
340 fts5FreeVtab((Fts5Table
*)pVtab
);
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
));
374 rc
= sqlite3Fts5ConfigParse(pGlobal
, db
, argc
, azConfig
, &pConfig
, pzErr
);
375 assert( (rc
==SQLITE_OK
&& *pzErr
==0) || pConfig
==0 );
378 pTab
->pConfig
= pConfig
;
379 pTab
->pGlobal
= pGlobal
;
382 /* Open the index sub-system */
384 rc
= sqlite3Fts5IndexOpen(pConfig
, bCreate
, &pTab
->pIndex
, pzErr
);
387 /* Open the storage sub-system */
389 rc
= sqlite3Fts5StorageOpen(
390 pConfig
, pTab
->pIndex
, bCreate
, &pTab
->pStorage
, pzErr
394 /* Call sqlite3_declare_vtab() */
396 rc
= sqlite3Fts5ConfigDeclareVtab(pConfig
);
399 /* Load the initial configuration */
401 assert( pConfig
->pzErrmsg
==0 );
402 pConfig
->pzErrmsg
= pzErr
;
403 rc
= sqlite3Fts5IndexLoadConfig(pTab
->pIndex
);
404 sqlite3Fts5IndexRollback(pTab
->pIndex
);
405 pConfig
->pzErrmsg
= 0;
412 fts5CheckTransactionState(pTab
, FTS5_BEGIN
, 0);
414 *ppVTab
= (sqlite3_vtab
*)pTab
;
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
461 if( sqlite3_libversion_number()>=3008012 )
464 pIdxInfo
->idxFlags
|= SQLITE_INDEX_SCAN_UNIQUE
;
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() */
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[] */
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},
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 */
548 idxFlags
= (idxFlags
& 0xFFFF) | FTS5_BI_MATCH
| (iCol
<< 16);
549 aConstraint
[0].iConsIndex
= i
;
551 /* As there exists an unusable MATCH constraint this is an
552 ** unusable plan. Set a prohibitively high cost. */
553 pInfo
->estimatedCost
= 1e50
;
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
){
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;
594 pInfo
->estimatedCost
= bHasMatch
? 1000.0 : 1000000.0;
597 /* Assign argvIndex values to each constraint in use. */
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
;
611 static int fts5NewTransaction(Fts5Table
*pTab
){
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
);
631 nByte
= sizeof(Fts5Cursor
) + pConfig
->nCol
* sizeof(int);
632 pCsr
= (Fts5Cursor
*)sqlite3_malloc(nByte
);
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
;
644 *ppCsr
= (sqlite3_vtab_cursor
*)pCsr
;
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
){
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
);
674 sqlite3_free(pCsr
->aInstIter
);
675 sqlite3_free(pCsr
->aInst
);
677 int eStmt
= fts5StmtType(pCsr
);
678 sqlite3Fts5StorageStmtRelease(pTab
->pStorage
, eStmt
, pCsr
->pStmt
);
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
);
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
){
714 Fts5Table
*pTab
= (Fts5Table
*)(pCursor
->pVtab
);
715 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
718 fts5FreeCursorComponents(pCsr
);
719 /* Remove the cursor from the Fts5Global.pCsr list */
720 for(pp
=&pTab
->pGlobal
->pCsr
; (*pp
)!=pCsr
; pp
=&(*pp
)->pNext
);
728 static int fts5SorterNext(Fts5Cursor
*pCsr
){
729 Fts5Sorter
*pSorter
= pCsr
->pSorter
;
732 rc
= sqlite3_step(pSorter
->pStmt
);
733 if( rc
==SQLITE_DONE
){
735 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
736 }else if( rc
==SQLITE_ROW
){
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. */
750 for(i
=0; i
<(pSorter
->nIdx
-1); i
++){
752 a
+= fts5GetVarint32(a
, iVal
);
754 pSorter
->aIdx
[i
] = iOff
;
756 pSorter
->aIdx
[i
] = &aBlob
[nBlob
] - a
;
757 pSorter
->aPoslist
= a
;
768 ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
769 ** open on table pTab.
771 static void fts5TripCursors(Fts5Table
*pTab
){
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
){
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
) ){
807 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_RESEEK
);
809 if( sqlite3Fts5ExprEof(pCsr
->pExpr
) ){
810 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
819 ** Advance the cursor to the next row in the table that matches the
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
;
830 assert( (pCsr
->ePlan
<3)==
831 (pCsr
->ePlan
==FTS5_PLAN_MATCH
|| pCsr
->ePlan
==FTS5_PLAN_SOURCE
)
833 assert( !CsrFlagTest(pCsr
, FTS5CSR_EOF
) );
837 if( (rc
= fts5CursorReseek(pCsr
, &bSkip
)) || bSkip
) return rc
;
838 rc
= sqlite3Fts5ExprNext(pCsr
->pExpr
, pCsr
->iLastRowid
);
839 CsrFlagSet(pCsr
, sqlite3Fts5ExprEof(pCsr
->pExpr
));
842 switch( pCsr
->ePlan
){
843 case FTS5_PLAN_SPECIAL
: {
844 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
849 case FTS5_PLAN_SORTED_MATCH
: {
850 rc
= fts5SorterNext(pCsr
);
855 rc
= sqlite3_step(pCsr
->pStmt
);
856 if( rc
!=SQLITE_ROW
){
857 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
858 rc
= sqlite3_reset(pCsr
->pStmt
);
870 static int fts5PrepareStatement(
871 sqlite3_stmt
**ppStmt
,
876 sqlite3_stmt
*pRet
= 0;
882 zSql
= sqlite3_vmprintf(zFmt
, ap
);
886 rc
= sqlite3_prepare_v3(pConfig
->db
, zSql
, -1,
887 SQLITE_PREPARE_PERSISTENT
, &pRet
, 0);
889 *pConfig
->pzErrmsg
= sqlite3_mprintf("%s", sqlite3_errmsg(pConfig
->db
));
899 static int fts5CursorFirstSorted(Fts5Table
*pTab
, Fts5Cursor
*pCsr
, int bDesc
){
900 Fts5Config
*pConfig
= pTab
->pConfig
;
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
;
932 assert( pTab
->pSortCsr
==0 );
933 pTab
->pSortCsr
= pCsr
;
934 rc
= fts5SorterNext(pCsr
);
939 sqlite3_finalize(pSorter
->pStmt
);
940 sqlite3_free(pSorter
);
947 static int fts5CursorFirst(Fts5Table
*pTab
, Fts5Cursor
*pCsr
, int bDesc
){
949 Fts5Expr
*pExpr
= pCsr
->pExpr
;
950 rc
= sqlite3Fts5ExprFirst(pExpr
, pTab
->pIndex
, pCsr
->iFirstRowid
, bDesc
);
951 if( sqlite3Fts5ExprEof(pExpr
) ){
952 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
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
964 static int fts5SpecialMatch(
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
;
986 /* An unrecognized directive. Return an error message. */
987 pTab
->base
.zErrMsg
= sqlite3_mprintf("unknown special query: %.*s", n
, z
);
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. */
1011 static int fts5FindRankFunction(Fts5Cursor
*pCsr
){
1012 Fts5Table
*pTab
= (Fts5Table
*)(pCsr
->base
.pVtab
);
1013 Fts5Config
*pConfig
= pTab
->pConfig
;
1015 Fts5Auxiliary
*pAux
= 0;
1016 const char *zRank
= pCsr
->zRank
;
1017 const char *zRankArgs
= pCsr
->zRankArgs
;
1020 char *zSql
= sqlite3Fts5Mprintf(&rc
, "SELECT %s", zRankArgs
);
1022 sqlite3_stmt
*pStmt
= 0;
1023 rc
= sqlite3_prepare_v3(pConfig
->db
, zSql
, -1,
1024 SQLITE_PREPARE_PERSISTENT
, &pStmt
, 0);
1026 assert( rc
==SQLITE_OK
|| pCsr
->pRankArgStmt
==0 );
1027 if( rc
==SQLITE_OK
){
1028 if( SQLITE_ROW
==sqlite3_step(pStmt
) ){
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
){
1035 for(i
=0; i
<pCsr
->nRankArg
; i
++){
1036 pCsr
->apRankArg
[i
] = sqlite3_column_value(pStmt
, i
);
1039 pCsr
->pRankArgStmt
= pStmt
;
1041 rc
= sqlite3_finalize(pStmt
);
1042 assert( rc
!=SQLITE_OK
);
1048 if( rc
==SQLITE_OK
){
1049 pAux
= fts5FindAuxiliary(pTab
, zRank
);
1051 assert( pTab
->base
.zErrMsg
==0 );
1052 pTab
->base
.zErrMsg
= sqlite3_mprintf("no such function: %s", zRank
);
1062 static int fts5CursorParseRank(
1063 Fts5Config
*pConfig
,
1065 sqlite3_value
*pRank
1069 const char *z
= (const char*)sqlite3_value_text(pRank
);
1071 char *zRankArgs
= 0;
1074 if( sqlite3_value_type(pRank
)==SQLITE_NULL
) rc
= SQLITE_ERROR
;
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
1088 if( pConfig
->zRank
){
1089 pCsr
->zRank
= (char*)pConfig
->zRank
;
1090 pCsr
->zRankArgs
= (char*)pConfig
->zRankArgs
;
1092 pCsr
->zRank
= (char*)FTS5_DEFAULT_RANK
;
1093 pCsr
->zRankArgs
= 0;
1099 static i64
fts5GetRowidLimit(sqlite3_value
*pVal
, i64 iDefault
){
1101 int eType
= sqlite3_value_numeric_type(pVal
);
1102 if( eType
==SQLITE_INTEGER
){
1103 return sqlite3_value_int64(pVal
);
1110 ** This is the xFilter interface for the virtual table. See
1111 ** the virtual table xFilter method documentation for additional
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
);
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. */
1181 pRowidLe
= pRowidGe
= pRowidEq
;
1184 pCsr
->iFirstRowid
= fts5GetRowidLimit(pRowidLe
, LARGEST_INT64
);
1185 pCsr
->iLastRowid
= fts5GetRowidLimit(pRowidGe
, SMALLEST_INT64
);
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
);
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]);
1217 char **pzErr
= &pTab
->base
.zErrMsg
;
1218 rc
= sqlite3Fts5ExprNew(pConfig
, iCol
, zExpr
, &pCsr
->pExpr
, pzErr
);
1219 if( rc
==SQLITE_OK
){
1221 pCsr
->ePlan
= FTS5_PLAN_SORTED_MATCH
;
1222 rc
= fts5CursorFirstSorted(pTab
, pCsr
, bDesc
);
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
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]);
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
;
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
;
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 );
1293 case FTS5_PLAN_SPECIAL
:
1297 case FTS5_PLAN_SOURCE
:
1298 case FTS5_PLAN_MATCH
:
1299 case FTS5_PLAN_SORTED_MATCH
:
1300 *pRowid
= fts5CursorRowid(pCsr
);
1304 *pRowid
= sqlite3_column_int64(pCsr
->pStmt
, 0);
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
){
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
){
1339 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_CONTENT
);
1341 rc
= sqlite3_reset(pCsr
->pStmt
);
1342 if( rc
==SQLITE_OK
){
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
);
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
;
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"
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"
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
);
1409 }else if( 0==sqlite3_stricmp("prefix-index", zCmd
) ){
1410 pConfig
->bPrefixIndex
= sqlite3_value_int(pVal
);
1413 rc
= sqlite3Fts5IndexLoadConfig(pTab
->pIndex
);
1414 if( rc
==SQLITE_OK
){
1415 rc
= sqlite3Fts5ConfigSetValue(pTab
->pConfig
, zCmd
, pVal
, &bError
);
1417 if( rc
==SQLITE_OK
){
1421 rc
= sqlite3Fts5StorageConfigValue(pTab
->pStorage
, zCmd
, pVal
, 0);
1428 static int fts5SpecialDelete(
1430 sqlite3_value
**apVal
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]);
1441 static void fts5StorageInsert(
1444 sqlite3_value
**apVal
,
1448 if( rc
==SQLITE_OK
){
1449 rc
= sqlite3Fts5StorageContentInsert(pTab
->pStorage
, apVal
, piRowid
);
1451 if( rc
==SQLITE_OK
){
1452 rc
= sqlite3Fts5StorageIndexInsert(pTab
->pStorage
, apVal
, *piRowid
);
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) );
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
);
1508 rc
= fts5SpecialInsert(pTab
, z
, apVal
[2 + pConfig
->nCol
+ 1]);
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:
1516 ** 2) UPDATE (rowid not modified)
1517 ** 3) UPDATE (rowid modified)
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
1542 i64 iDel
= sqlite3_value_int64(apVal
[0]); /* Rowid to delete */
1543 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iDel
, 0);
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
);
1560 i64 iOld
= sqlite3_value_int64(apVal
[0]); /* Old rowid */
1561 i64 iNew
= sqlite3_value_int64(apVal
[1]); /* New rowid */
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
);
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
);
1579 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iOld
, 0);
1580 fts5StorageInsert(&rc
, pTab
, apVal
, pRowid
);
1585 pTab
->pConfig
->pzErrmsg
= 0;
1590 ** Implementation of xSync() method.
1592 static int fts5SyncMethod(sqlite3_vtab
*pVtab
){
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;
1604 ** Implementation of xBegin() method.
1606 static int fts5BeginMethod(sqlite3_vtab
*pVtab
){
1607 fts5CheckTransactionState((Fts5Table
*)pVtab
, FTS5_BEGIN
, 0);
1608 fts5NewTransaction((Fts5Table
*)pVtab
);
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);
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
){
1629 Fts5Table
*pTab
= (Fts5Table
*)pVtab
;
1630 fts5CheckTransactionState(pTab
, FTS5_ROLLBACK
, 0);
1631 rc
= sqlite3Fts5StorageRollback(pTab
->pStorage
);
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(
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(
1665 const char *pText
, int nText
,
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(
1693 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1694 if( fts5IsContentless((Fts5Table
*)(pCsr
->base
.pVtab
)) ){
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);
1707 static int fts5CsrPoslist(
1713 Fts5Config
*pConfig
= ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
;
1715 int bLive
= (pCsr
->pSorter
==0);
1717 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_POSLIST
) ){
1719 if( pConfig
->eDetail
!=FTS5_DETAIL_FULL
){
1720 Fts5PoslistPopulator
*aPopulator
;
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
];
1748 *pn
= sqlite3Fts5ExprPoslist(pCsr
->pExpr
, iPhrase
, pa
);
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
){
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
;
1772 int nInst
= 0; /* Number instances seen so far */
1775 /* Initialize all iterators */
1776 for(i
=0; i
<nIter
&& rc
==SQLITE_OK
; i
++){
1779 rc
= fts5CsrPoslist(pCsr
, i
, &a
, &n
);
1780 if( rc
==SQLITE_OK
){
1781 sqlite3Fts5PoslistReaderInit(a
, n
, &aIter
[i
]);
1785 if( rc
==SQLITE_OK
){
1789 for(i
=0; i
<nIter
; i
++){
1790 if( (aIter
[i
].bEof
==0)
1791 && (iBest
<0 || aIter
[i
].iPos
<aIter
[iBest
].iPos
)
1796 if( iBest
<0 ) break;
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
1805 pCsr
->aInst
= aInst
;
1812 aInst
= &pCsr
->aInst
[3 * (nInst
-1)];
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
);
1826 static int fts5ApiInstCount(Fts5Context
*pCtx
, int *pnInst
){
1827 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1829 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_INST
)==0
1830 || SQLITE_OK
==(rc
= fts5CacheInstArray(pCsr
)) ){
1831 *pnInst
= pCsr
->nInstCount
;
1836 static int fts5ApiInst(
1843 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1845 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_INST
)==0
1846 || SQLITE_OK
==(rc
= fts5CacheInstArray(pCsr
))
1848 if( iIdx
<0 || iIdx
>=pCsr
->nInstCount
){
1851 }else if( fts5IsOffsetless((Fts5Table
*)pCsr
->base
.pVtab
) ){
1852 *piPhrase
= pCsr
->aInst
[iIdx
*3];
1853 *piCol
= pCsr
->aInst
[iIdx
*3 + 2];
1857 *piPhrase
= pCsr
->aInst
[iIdx
*3];
1858 *piCol
= pCsr
->aInst
[iIdx
*3 + 1];
1859 *piOff
= pCsr
->aInst
[iIdx
*3 + 2];
1865 static sqlite3_int64
fts5ApiRowid(Fts5Context
*pCtx
){
1866 return fts5CursorRowid((Fts5Cursor
*)pCtx
);
1869 static int fts5ColumnSizeCb(
1870 void *pContext
, /* Pointer to int */
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 ){
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
;
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 ){
1898 for(i
=0; i
<pConfig
->nCol
; i
++){
1899 if( pConfig
->abUnindexed
[i
]==0 ){
1900 pCsr
->aColumnSize
[i
] = -1;
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
);
1924 for(i
=0; i
<pConfig
->nCol
; i
++){
1925 *pnToken
+= pCsr
->aColumnSize
[i
];
1927 }else if( iCol
<pConfig
->nCol
){
1928 *pnToken
= pCsr
->aColumnSize
[iCol
];
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
;
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;
1954 if( pData
->xDelete
){
1955 pData
->xDelete(pData
->pPtr
);
1959 pData
= (Fts5Auxdata
*)sqlite3Fts5MallocZero(&rc
, sizeof(Fts5Auxdata
));
1961 if( xDelete
) xDelete(pPtr
);
1964 pData
->pAux
= pCsr
->pAux
;
1965 pData
->pNext
= pCsr
->pAuxdata
;
1966 pCsr
->pAuxdata
= pData
;
1969 pData
->xDelete
= xDelete
;
1974 static void *fts5ApiGetAuxdata(Fts5Context
*pCtx
, int bClear
){
1975 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1979 for(pData
=pCsr
->pAuxdata
; pData
; pData
=pData
->pNext
){
1980 if( pData
->pAux
==pCsr
->pAux
) break;
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
){
2005 pIter
->a
+= fts5GetVarint32(pIter
->a
, iVal
);
2007 pIter
->a
+= fts5GetVarint32(pIter
->a
, iVal
);
2010 pIter
->a
+= fts5GetVarint32(pIter
->a
, iVal
);
2016 static int fts5ApiPhraseFirst(
2019 Fts5PhraseIter
*pIter
,
2020 int *piCol
, int *piOff
2022 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2024 int rc
= fts5CsrPoslist(pCsr
, iPhrase
, &pIter
->a
, &n
);
2025 if( rc
==SQLITE_OK
){
2026 pIter
->b
= &pIter
->a
[n
];
2029 fts5ApiPhraseNext(pCtx
, pIter
, piCol
, piOff
);
2034 static void fts5ApiPhraseNextColumn(
2036 Fts5PhraseIter
*pIter
,
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
){
2047 pIter
->a
+= fts5GetVarint32(&pIter
->a
[0], iIncr
);
2048 *piCol
+= (iIncr
-2);
2053 if( pIter
->a
>=pIter
->b
){
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(
2067 Fts5PhraseIter
*pIter
,
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
;
2078 int i1
= (iPhrase
==0 ? 0 : pSorter
->aIdx
[iPhrase
-1]);
2079 n
= pSorter
->aIdx
[iPhrase
] - i1
;
2080 pIter
->a
= &pSorter
->aPoslist
[i1
];
2082 rc
= sqlite3Fts5ExprPhraseCollist(pCsr
->pExpr
, iPhrase
, &pIter
->a
, &n
);
2084 if( rc
==SQLITE_OK
){
2085 pIter
->b
= &pIter
->a
[n
];
2087 fts5ApiPhraseNextColumn(pCtx
, pIter
, piCol
);
2091 rc
= fts5CsrPoslist(pCsr
, iPhrase
, &pIter
->a
, &n
);
2092 if( rc
==SQLITE_OK
){
2093 pIter
->b
= &pIter
->a
[n
];
2096 }else if( pIter
->a
[0]==0x01 ){
2097 pIter
->a
+= 1 + fts5GetVarint32(&pIter
->a
[1], *piCol
);
2108 static int fts5ApiQueryPhrase(Fts5Context
*, int, void*,
2109 int(*)(const Fts5ExtensionApi
*, Fts5Context
*, void*)
2112 static const Fts5ExtensionApi sFts5Api
= {
2117 fts5ApiColumnTotalSize
,
2131 fts5ApiPhraseFirstColumn
,
2132 fts5ApiPhraseNextColumn
,
2136 ** Implementation of API function xQueryPhrase().
2138 static int fts5ApiQueryPhrase(
2142 int(*xCallback
)(const Fts5ExtensionApi
*, Fts5Context
*, void*)
2144 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2145 Fts5Table
*pTab
= (Fts5Table
*)(pCsr
->base
.pVtab
);
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
;
2171 fts5CloseMethod((sqlite3_vtab_cursor
*)pNew
);
2175 static void fts5ApiInvoke(
2176 Fts5Auxiliary
*pAux
,
2178 sqlite3_context
*context
,
2180 sqlite3_value
**argv
2182 assert( pCsr
->pAux
==0 );
2184 pAux
->xFunc(&sFts5Api
, (Fts5Context
*)pCsr
, context
, argc
, argv
);
2188 static Fts5Cursor
*fts5CursorFromCsrid(Fts5Global
*pGlobal
, i64 iCsrId
){
2190 for(pCsr
=pGlobal
->pCsr
; pCsr
; pCsr
=pCsr
->pNext
){
2191 if( pCsr
->iCsrId
==iCsrId
) break;
2196 static void fts5ApiCallback(
2197 sqlite3_context
*context
,
2199 sqlite3_value
**argv
2202 Fts5Auxiliary
*pAux
;
2207 pAux
= (Fts5Auxiliary
*)sqlite3_user_data(context
);
2208 iCsrId
= sqlite3_value_int64(argv
[0]);
2210 pCsr
= fts5CursorFromCsrid(pAux
->pGlobal
, iCsrId
);
2212 char *zErr
= sqlite3_mprintf("no such cursor: %lld", iCsrId
);
2213 sqlite3_result_error(context
, zErr
, -1);
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 */
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
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
){
2261 int nPhrase
= sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
);
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
++){
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
++){
2279 nPoslist
= sqlite3Fts5ExprPoslist(pCsr
->pExpr
, i
, &pPoslist
);
2280 sqlite3Fts5BufferAppendBlob(&rc
, &val
, nPoslist
, pPoslist
);
2284 case FTS5_DETAIL_COLUMNS
:
2286 /* Append the varints */
2287 for(i
=0; rc
==SQLITE_OK
&& i
<(nPhrase
-1); i
++){
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
++){
2298 rc
= sqlite3Fts5ExprPhraseCollist(pCsr
->pExpr
, i
, &pPoslist
, &nPoslist
);
2299 sqlite3Fts5BufferAppendBlob(&rc
, &val
, nPoslist
, pPoslist
);
2307 sqlite3_result_blob(pCtx
, val
.p
, val
.n
, sqlite3_free
);
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
;
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
);
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
);
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));
2363 ** This routine implements the xFindFunction method for the FTS3
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
);
2379 *pxFunc
= fts5ApiCallback
;
2380 *ppArg
= (void*)pAux
;
2384 /* No function of the specified name was found. 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.
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
);
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
;
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 */
2493 nName
= (int)strlen(zName
) + 1;
2494 nByte
= sizeof(Fts5TokenizerModule
) + nName
;
2495 pNew
= (Fts5TokenizerModule
*)sqlite3_malloc(nByte
);
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
;
2515 static Fts5TokenizerModule
*fts5LocateTokenizer(
2516 Fts5Global
*pGlobal
,
2519 Fts5TokenizerModule
*pMod
= 0;
2522 pMod
= pGlobal
->pDfltTok
;
2524 for(pMod
=pGlobal
->pTok
; pMod
; pMod
=pMod
->pNext
){
2525 if( sqlite3_stricmp(zName
, pMod
->zName
)==0 ) break;
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 */
2540 fts5_tokenizer
*pTokenizer
/* Populate this object */
2543 Fts5TokenizerModule
*pMod
;
2545 pMod
= fts5LocateTokenizer((Fts5Global
*)pApi
, zName
);
2547 *pTokenizer
= pMod
->x
;
2548 *ppUserData
= pMod
->pUserData
;
2550 memset(pTokenizer
, 0, sizeof(fts5_tokenizer
));
2557 int sqlite3Fts5GetTokenizer(
2558 Fts5Global
*pGlobal
,
2561 Fts5Tokenizer
**ppTok
,
2562 fts5_tokenizer
**ppTokApi
,
2565 Fts5TokenizerModule
*pMod
;
2568 pMod
= fts5LocateTokenizer(pGlobal
, nArg
==0 ? 0 : azArg
[0]);
2572 *pzErr
= sqlite3_mprintf("no such tokenizer: %s", azArg
[0]);
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
){
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
);
2600 for(pTok
=pGlobal
->pTok
; pTok
; pTok
=pNextTok
){
2601 pNextTok
= pTok
->pNext
;
2602 if( pTok
->xDestroy
) pTok
->xDestroy(pTok
->pUserData
);
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
);
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 */
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
= {
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
,
2663 Fts5Global
*pGlobal
= 0;
2665 pGlobal
= (Fts5Global
*)sqlite3_malloc(sizeof(Fts5Global
));
2669 void *p
= (void*)pGlobal
;
2670 memset(pGlobal
, 0, sizeof(Fts5Global
));
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
);
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.
2718 __declspec(dllexport
)
2720 int sqlite3_fts_init(
2723 const sqlite3_api_routines
*pApi
2725 SQLITE_EXTENSION_INIT2(pApi
);
2726 (void)pzErrMsg
; /* Unused parameter */
2727 return fts5Init(db
);
2731 __declspec(dllexport
)
2733 int sqlite3_fts5_init(
2736 const sqlite3_api_routines
*pApi
2738 SQLITE_EXTENSION_INIT2(pApi
);
2739 (void)pzErrMsg
; /* Unused parameter */
2740 return fts5Init(db
);
2743 int sqlite3Fts5Init(sqlite3
*db
){
2744 return fts5Init(db
);