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.
26 int sqlite3_fts5_may_be_corrupt
= 1;
30 typedef struct Fts5Auxdata Fts5Auxdata
;
31 typedef struct Fts5Auxiliary Fts5Auxiliary
;
32 typedef struct Fts5Cursor Fts5Cursor
;
33 typedef struct Fts5FullTable Fts5FullTable
;
34 typedef struct Fts5Sorter Fts5Sorter
;
35 typedef struct Fts5TokenizerModule Fts5TokenizerModule
;
38 ** NOTES ON TRANSACTIONS:
40 ** SQLite invokes the following virtual table methods as transactions are
41 ** opened and closed by the user:
43 ** xBegin(): Start of a new transaction.
44 ** xSync(): Initial part of two-phase commit.
45 ** xCommit(): Final part of two-phase commit.
46 ** xRollback(): Rollback the transaction.
48 ** Anything that is required as part of a commit that may fail is performed
49 ** in the xSync() callback. Current versions of SQLite ignore any errors
50 ** returned by xCommit().
52 ** And as sub-transactions are opened/closed:
54 ** xSavepoint(int S): Open savepoint S.
55 ** xRelease(int S): Commit and close savepoint S.
56 ** xRollbackTo(int S): Rollback to start of savepoint S.
58 ** During a write-transaction the fts5_index.c module may cache some data
59 ** in-memory. It is flushed to disk whenever xSync(), xRelease() or
60 ** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
63 ** Additionally, if SQLITE_DEBUG is defined, an instance of the following
64 ** structure is used to record the current transaction state. This information
65 ** is not required, but it is used in the assert() statements executed by
66 ** function fts5CheckTransactionState() (see below).
68 struct Fts5TransactionState
{
69 int eState
; /* 0==closed, 1==open, 2==synced */
70 int iSavepoint
; /* Number of open savepoints (0 -> none) */
74 ** A single object of this type is allocated when the FTS5 module is
75 ** registered with a database handle. It is used to store pointers to
76 ** all registered FTS5 extensions - tokenizers and auxiliary functions.
79 fts5_api api
; /* User visible part of object (see fts5.h) */
80 sqlite3
*db
; /* Associated database connection */
81 i64 iNextId
; /* Used to allocate unique cursor ids */
82 Fts5Auxiliary
*pAux
; /* First in list of all aux. functions */
83 Fts5TokenizerModule
*pTok
; /* First in list of all tokenizer modules */
84 Fts5TokenizerModule
*pDfltTok
; /* Default tokenizer module */
85 Fts5Cursor
*pCsr
; /* First in list of all open cursors */
89 ** Each auxiliary function registered with the FTS5 module is represented
90 ** by an object of the following type. All such objects are stored as part
91 ** of the Fts5Global.pAux list.
93 struct Fts5Auxiliary
{
94 Fts5Global
*pGlobal
; /* Global context for this function */
95 char *zFunc
; /* Function name (nul-terminated) */
96 void *pUserData
; /* User-data pointer */
97 fts5_extension_function xFunc
; /* Callback function */
98 void (*xDestroy
)(void*); /* Destructor function */
99 Fts5Auxiliary
*pNext
; /* Next registered auxiliary function */
103 ** Each tokenizer module registered with the FTS5 module is represented
104 ** by an object of the following type. All such objects are stored as part
105 ** of the Fts5Global.pTok list.
107 struct Fts5TokenizerModule
{
108 char *zName
; /* Name of tokenizer */
109 void *pUserData
; /* User pointer passed to xCreate() */
110 fts5_tokenizer x
; /* Tokenizer functions */
111 void (*xDestroy
)(void*); /* Destructor function */
112 Fts5TokenizerModule
*pNext
; /* Next registered tokenizer module */
115 struct Fts5FullTable
{
116 Fts5Table p
; /* Public class members from fts5Int.h */
117 Fts5Storage
*pStorage
; /* Document store */
118 Fts5Global
*pGlobal
; /* Global (connection wide) data */
119 Fts5Cursor
*pSortCsr
; /* Sort data from this cursor */
121 struct Fts5TransactionState ts
;
125 struct Fts5MatchPhrase
{
126 Fts5Buffer
*pPoslist
; /* Pointer to current poslist */
127 int nTerm
; /* Size of phrase in terms */
132 ** SELECT rowid, <fts> FROM <fts> ORDER BY +rank;
135 ** There is one entry in the aIdx[] array for each phrase in the query,
136 ** the value of which is the offset within aPoslist[] following the last
137 ** byte of the position list for the corresponding phrase.
141 i64 iRowid
; /* Current rowid */
142 const u8
*aPoslist
; /* Position lists for current row */
143 int nIdx
; /* Number of entries in aIdx[] */
144 int aIdx
[1]; /* Offsets into aPoslist for current row */
149 ** Virtual-table cursor object.
152 ** If this is a 'special' query (refer to function fts5SpecialMatch()),
153 ** then this variable contains the result of the query.
155 ** iFirstRowid, iLastRowid:
156 ** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
157 ** cursor iterates in ascending order of rowids, iFirstRowid is the lower
158 ** limit of rowids to return, and iLastRowid the upper. In other words, the
159 ** WHERE clause in the user's query might have been:
161 ** <tbl> MATCH <expr> AND rowid BETWEEN $iFirstRowid AND $iLastRowid
163 ** If the cursor iterates in descending order of rowid, iFirstRowid
164 ** is the upper limit (i.e. the "first" rowid visited) and iLastRowid
168 sqlite3_vtab_cursor base
; /* Base class used by SQLite core */
169 Fts5Cursor
*pNext
; /* Next cursor in Fts5Cursor.pCsr list */
170 int *aColumnSize
; /* Values for xColumnSize() */
171 i64 iCsrId
; /* Cursor id */
173 /* Zero from this point onwards on cursor reset */
174 int ePlan
; /* FTS5_PLAN_XXX value */
175 int bDesc
; /* True for "ORDER BY rowid DESC" queries */
176 i64 iFirstRowid
; /* Return no rowids earlier than this */
177 i64 iLastRowid
; /* Return no rowids later than this */
178 sqlite3_stmt
*pStmt
; /* Statement used to read %_content */
179 Fts5Expr
*pExpr
; /* Expression for MATCH queries */
180 Fts5Sorter
*pSorter
; /* Sorter for "ORDER BY rank" queries */
181 int csrflags
; /* Mask of cursor flags (see below) */
182 i64 iSpecial
; /* Result of special query */
184 /* "rank" function. Populated on demand from vtab.xColumn(). */
185 char *zRank
; /* Custom rank function */
186 char *zRankArgs
; /* Custom rank function args */
187 Fts5Auxiliary
*pRank
; /* Rank callback (or NULL) */
188 int nRankArg
; /* Number of trailing arguments for rank() */
189 sqlite3_value
**apRankArg
; /* Array of trailing arguments */
190 sqlite3_stmt
*pRankArgStmt
; /* Origin of objects in apRankArg[] */
192 /* Auxiliary data storage */
193 Fts5Auxiliary
*pAux
; /* Currently executing extension function */
194 Fts5Auxdata
*pAuxdata
; /* First in linked list of saved aux-data */
196 /* Cache used by auxiliary functions xInst() and xInstCount() */
197 Fts5PoslistReader
*aInstIter
; /* One for each phrase */
198 int nInstAlloc
; /* Size of aInst[] array (entries / 3) */
199 int nInstCount
; /* Number of phrase instances */
200 int *aInst
; /* 3 integers per phrase instance */
204 ** Bits that make up the "idxNum" parameter passed indirectly by
205 ** xBestIndex() to xFilter().
207 #define FTS5_BI_MATCH 0x0001 /* <tbl> MATCH ? */
208 #define FTS5_BI_RANK 0x0002 /* rank MATCH ? */
209 #define FTS5_BI_ROWID_EQ 0x0004 /* rowid == ? */
210 #define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */
211 #define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */
213 #define FTS5_BI_ORDER_RANK 0x0020
214 #define FTS5_BI_ORDER_ROWID 0x0040
215 #define FTS5_BI_ORDER_DESC 0x0080
218 ** Values for Fts5Cursor.csrflags
220 #define FTS5CSR_EOF 0x01
221 #define FTS5CSR_REQUIRE_CONTENT 0x02
222 #define FTS5CSR_REQUIRE_DOCSIZE 0x04
223 #define FTS5CSR_REQUIRE_INST 0x08
224 #define FTS5CSR_FREE_ZRANK 0x10
225 #define FTS5CSR_REQUIRE_RESEEK 0x20
226 #define FTS5CSR_REQUIRE_POSLIST 0x40
228 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
229 #define BitFlagTest(x,y) (((x) & (y))!=0)
233 ** Macros to Set(), Clear() and Test() cursor flags.
235 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
236 #define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag))
237 #define CsrFlagTest(pCsr, flag) ((pCsr)->csrflags & (flag))
240 Fts5Auxiliary
*pAux
; /* Extension to which this belongs */
241 void *pPtr
; /* Pointer value */
242 void(*xDelete
)(void*); /* Destructor */
243 Fts5Auxdata
*pNext
; /* Next object in linked list */
249 #define FTS5_COMMIT 3
250 #define FTS5_ROLLBACK 4
251 #define FTS5_SAVEPOINT 5
252 #define FTS5_RELEASE 6
253 #define FTS5_ROLLBACKTO 7
254 static void fts5CheckTransactionState(Fts5FullTable
*p
, int op
, int iSavepoint
){
257 assert( p
->ts
.eState
==0 );
259 p
->ts
.iSavepoint
= -1;
263 assert( p
->ts
.eState
==1 || p
->ts
.eState
==2 );
268 assert( p
->ts
.eState
==2 );
273 assert( p
->ts
.eState
==1 || p
->ts
.eState
==2 || p
->ts
.eState
==0 );
278 assert( p
->ts
.eState
>=1 );
279 assert( iSavepoint
>=0 );
280 assert( iSavepoint
>=p
->ts
.iSavepoint
);
281 p
->ts
.iSavepoint
= iSavepoint
;
285 assert( p
->ts
.eState
>=1 );
286 assert( iSavepoint
>=0 );
287 assert( iSavepoint
<=p
->ts
.iSavepoint
);
288 p
->ts
.iSavepoint
= iSavepoint
-1;
291 case FTS5_ROLLBACKTO
:
292 assert( p
->ts
.eState
>=1 );
293 assert( iSavepoint
>=-1 );
294 /* The following assert() can fail if another vtab strikes an error
295 ** within an xSavepoint() call then SQLite calls xRollbackTo() - without
296 ** having called xSavepoint() on this vtab. */
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(Fts5FullTable
*pTab
){
310 return pTab
->p
.pConfig
->eContent
==FTS5_CONTENT_NONE
;
314 ** Delete a virtual table handle allocated by fts5InitVtab().
316 static void fts5FreeVtab(Fts5FullTable
*pTab
){
318 sqlite3Fts5IndexClose(pTab
->p
.pIndex
);
319 sqlite3Fts5StorageClose(pTab
->pStorage
);
320 sqlite3Fts5ConfigFree(pTab
->p
.pConfig
);
326 ** The xDisconnect() virtual table method.
328 static int fts5DisconnectMethod(sqlite3_vtab
*pVtab
){
329 fts5FreeVtab((Fts5FullTable
*)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((Fts5FullTable
*)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 Fts5FullTable
*pTab
= 0; /* New virtual table object */
371 /* Allocate the new vtab object and parse the configuration */
372 pTab
= (Fts5FullTable
*)sqlite3Fts5MallocZero(&rc
, sizeof(Fts5FullTable
));
374 rc
= sqlite3Fts5ConfigParse(pGlobal
, db
, argc
, azConfig
, &pConfig
, pzErr
);
375 assert( (rc
==SQLITE_OK
&& *pzErr
==0) || pConfig
==0 );
378 pTab
->p
.pConfig
= pConfig
;
379 pTab
->pGlobal
= pGlobal
;
382 /* Open the index sub-system */
384 rc
= sqlite3Fts5IndexOpen(pConfig
, bCreate
, &pTab
->p
.pIndex
, pzErr
);
387 /* Open the storage sub-system */
389 rc
= sqlite3Fts5StorageOpen(
390 pConfig
, pTab
->p
.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
->p
.pIndex
);
404 sqlite3Fts5IndexRollback(pTab
->p
.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
;
469 static int fts5UsePatternMatch(
471 struct sqlite3_index_constraint
*p
473 assert( FTS5_PATTERN_GLOB
==SQLITE_INDEX_CONSTRAINT_GLOB
);
474 assert( FTS5_PATTERN_LIKE
==SQLITE_INDEX_CONSTRAINT_LIKE
);
475 if( pConfig
->ePattern
==FTS5_PATTERN_GLOB
&& p
->op
==FTS5_PATTERN_GLOB
){
478 if( pConfig
->ePattern
==FTS5_PATTERN_LIKE
479 && (p
->op
==FTS5_PATTERN_LIKE
|| p
->op
==FTS5_PATTERN_GLOB
)
487 ** Implementation of the xBestIndex method for FTS5 tables. Within the
488 ** WHERE constraint, it searches for the following:
490 ** 1. A MATCH constraint against the table column.
491 ** 2. A MATCH constraint against the "rank" column.
492 ** 3. A MATCH constraint against some other column.
493 ** 4. An == constraint against the rowid column.
494 ** 5. A < or <= constraint against the rowid column.
495 ** 6. A > or >= constraint against the rowid column.
497 ** Within the ORDER BY, the following are supported:
499 ** 5. ORDER BY rank [ASC|DESC]
500 ** 6. ORDER BY rowid [ASC|DESC]
502 ** Information for the xFilter call is passed via both the idxNum and
503 ** idxStr variables. Specifically, idxNum is a bitmask of the following
504 ** flags used to encode the ORDER BY clause:
506 ** FTS5_BI_ORDER_RANK
507 ** FTS5_BI_ORDER_ROWID
508 ** FTS5_BI_ORDER_DESC
510 ** idxStr is used to encode data from the WHERE clause. For each argument
511 ** passed to the xFilter method, the following is appended to idxStr:
513 ** Match against table column: "m"
514 ** Match against rank column: "r"
515 ** Match against other column: "M<column-number>"
516 ** LIKE against other column: "L<column-number>"
517 ** GLOB against other column: "G<column-number>"
518 ** Equality constraint against the rowid: "="
519 ** A < or <= against the rowid: "<"
520 ** A > or >= against the rowid: ">"
522 ** This function ensures that there is at most one "r" or "=". And that if
523 ** there exists an "=" then there is no "<" or ">".
525 ** Costs are assigned as follows:
527 ** a) If an unusable MATCH operator is present in the WHERE clause, the
528 ** cost is unconditionally set to 1e50 (a really big number).
530 ** a) If a MATCH operator is present, the cost depends on the other
531 ** constraints also present. As follows:
533 ** * No other constraints: cost=1000.0
534 ** * One rowid range constraint: cost=750.0
535 ** * Both rowid range constraints: cost=500.0
536 ** * An == rowid constraint: cost=100.0
538 ** b) Otherwise, if there is no MATCH:
540 ** * No other constraints: cost=1000000.0
541 ** * One rowid range constraint: cost=750000.0
542 ** * Both rowid range constraints: cost=250000.0
543 ** * An == rowid constraint: cost=10.0
545 ** Costs are not modified by the ORDER BY clause.
547 static int fts5BestIndexMethod(sqlite3_vtab
*pVTab
, sqlite3_index_info
*pInfo
){
548 Fts5Table
*pTab
= (Fts5Table
*)pVTab
;
549 Fts5Config
*pConfig
= pTab
->pConfig
;
550 const int nCol
= pConfig
->nCol
;
551 int idxFlags
= 0; /* Parameter passed through to xFilter() */
565 assert( SQLITE_INDEX_CONSTRAINT_EQ
<SQLITE_INDEX_CONSTRAINT_MATCH
);
566 assert( SQLITE_INDEX_CONSTRAINT_GT
<SQLITE_INDEX_CONSTRAINT_MATCH
);
567 assert( SQLITE_INDEX_CONSTRAINT_LE
<SQLITE_INDEX_CONSTRAINT_MATCH
);
568 assert( SQLITE_INDEX_CONSTRAINT_GE
<SQLITE_INDEX_CONSTRAINT_MATCH
);
569 assert( SQLITE_INDEX_CONSTRAINT_LE
<SQLITE_INDEX_CONSTRAINT_MATCH
);
571 if( pConfig
->bLock
){
572 pTab
->base
.zErrMsg
= sqlite3_mprintf(
573 "recursively defined fts5 content table"
578 idxStr
= (char*)sqlite3_malloc(pInfo
->nConstraint
* 8 + 1);
579 if( idxStr
==0 ) return SQLITE_NOMEM
;
580 pInfo
->idxStr
= idxStr
;
581 pInfo
->needToFreeIdxStr
= 1;
583 for(i
=0; i
<pInfo
->nConstraint
; i
++){
584 struct sqlite3_index_constraint
*p
= &pInfo
->aConstraint
[i
];
585 int iCol
= p
->iColumn
;
586 if( p
->op
==SQLITE_INDEX_CONSTRAINT_MATCH
587 || (p
->op
==SQLITE_INDEX_CONSTRAINT_EQ
&& iCol
>=nCol
)
589 /* A MATCH operator or equivalent */
590 if( p
->usable
==0 || iCol
<0 ){
591 /* As there exists an unusable MATCH constraint this is an
592 ** unusable plan. Set a prohibitively high cost. */
593 pInfo
->estimatedCost
= 1e50
;
594 assert( iIdxStr
< pInfo
->nConstraint
*6 + 1 );
599 if( bSeenRank
) continue;
600 idxStr
[iIdxStr
++] = 'r';
604 idxStr
[iIdxStr
++] = 'M';
605 sqlite3_snprintf(6, &idxStr
[iIdxStr
], "%d", iCol
);
606 idxStr
+= strlen(&idxStr
[iIdxStr
]);
607 assert( idxStr
[iIdxStr
]=='\0' );
609 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
610 pInfo
->aConstraintUsage
[i
].omit
= 1;
612 }else if( p
->usable
){
613 if( iCol
>=0 && iCol
<nCol
&& fts5UsePatternMatch(pConfig
, p
) ){
614 assert( p
->op
==FTS5_PATTERN_LIKE
|| p
->op
==FTS5_PATTERN_GLOB
);
615 idxStr
[iIdxStr
++] = p
->op
==FTS5_PATTERN_LIKE
? 'L' : 'G';
616 sqlite3_snprintf(6, &idxStr
[iIdxStr
], "%d", iCol
);
617 idxStr
+= strlen(&idxStr
[iIdxStr
]);
618 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
619 assert( idxStr
[iIdxStr
]=='\0' );
620 }else if( bSeenEq
==0 && p
->op
==SQLITE_INDEX_CONSTRAINT_EQ
&& iCol
<0 ){
621 idxStr
[iIdxStr
++] = '=';
623 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
629 for(i
=0; i
<pInfo
->nConstraint
; i
++){
630 struct sqlite3_index_constraint
*p
= &pInfo
->aConstraint
[i
];
631 if( p
->iColumn
<0 && p
->usable
){
633 if( op
==SQLITE_INDEX_CONSTRAINT_LT
|| op
==SQLITE_INDEX_CONSTRAINT_LE
){
634 if( bSeenLt
) continue;
635 idxStr
[iIdxStr
++] = '<';
636 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
639 if( op
==SQLITE_INDEX_CONSTRAINT_GT
|| op
==SQLITE_INDEX_CONSTRAINT_GE
){
640 if( bSeenGt
) continue;
641 idxStr
[iIdxStr
++] = '>';
642 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
648 idxStr
[iIdxStr
] = '\0';
650 /* Set idxFlags flags for the ORDER BY clause */
651 if( pInfo
->nOrderBy
==1 ){
652 int iSort
= pInfo
->aOrderBy
[0].iColumn
;
653 if( iSort
==(pConfig
->nCol
+1) && bSeenMatch
){
654 idxFlags
|= FTS5_BI_ORDER_RANK
;
655 }else if( iSort
==-1 ){
656 idxFlags
|= FTS5_BI_ORDER_ROWID
;
658 if( BitFlagTest(idxFlags
, FTS5_BI_ORDER_RANK
|FTS5_BI_ORDER_ROWID
) ){
659 pInfo
->orderByConsumed
= 1;
660 if( pInfo
->aOrderBy
[0].desc
){
661 idxFlags
|= FTS5_BI_ORDER_DESC
;
666 /* Calculate the estimated cost based on the flags set in idxFlags. */
668 pInfo
->estimatedCost
= bSeenMatch
? 100.0 : 10.0;
669 if( bSeenMatch
==0 ) fts5SetUniqueFlag(pInfo
);
670 }else if( bSeenLt
&& bSeenGt
){
671 pInfo
->estimatedCost
= bSeenMatch
? 500.0 : 250000.0;
672 }else if( bSeenLt
|| bSeenGt
){
673 pInfo
->estimatedCost
= bSeenMatch
? 750.0 : 750000.0;
675 pInfo
->estimatedCost
= bSeenMatch
? 1000.0 : 1000000.0;
678 pInfo
->idxNum
= idxFlags
;
682 static int fts5NewTransaction(Fts5FullTable
*pTab
){
684 for(pCsr
=pTab
->pGlobal
->pCsr
; pCsr
; pCsr
=pCsr
->pNext
){
685 if( pCsr
->base
.pVtab
==(sqlite3_vtab
*)pTab
) return SQLITE_OK
;
687 return sqlite3Fts5StorageReset(pTab
->pStorage
);
691 ** Implementation of xOpen method.
693 static int fts5OpenMethod(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCsr
){
694 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVTab
;
695 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
696 Fts5Cursor
*pCsr
= 0; /* New cursor object */
697 sqlite3_int64 nByte
; /* Bytes of space to allocate */
698 int rc
; /* Return code */
700 rc
= fts5NewTransaction(pTab
);
702 nByte
= sizeof(Fts5Cursor
) + pConfig
->nCol
* sizeof(int);
703 pCsr
= (Fts5Cursor
*)sqlite3_malloc64(nByte
);
705 Fts5Global
*pGlobal
= pTab
->pGlobal
;
706 memset(pCsr
, 0, (size_t)nByte
);
707 pCsr
->aColumnSize
= (int*)&pCsr
[1];
708 pCsr
->pNext
= pGlobal
->pCsr
;
709 pGlobal
->pCsr
= pCsr
;
710 pCsr
->iCsrId
= ++pGlobal
->iNextId
;
715 *ppCsr
= (sqlite3_vtab_cursor
*)pCsr
;
719 static int fts5StmtType(Fts5Cursor
*pCsr
){
720 if( pCsr
->ePlan
==FTS5_PLAN_SCAN
){
721 return (pCsr
->bDesc
) ? FTS5_STMT_SCAN_DESC
: FTS5_STMT_SCAN_ASC
;
723 return FTS5_STMT_LOOKUP
;
727 ** This function is called after the cursor passed as the only argument
728 ** is moved to point at a different row. It clears all cached data
729 ** specific to the previous row stored by the cursor object.
731 static void fts5CsrNewrow(Fts5Cursor
*pCsr
){
733 FTS5CSR_REQUIRE_CONTENT
734 | FTS5CSR_REQUIRE_DOCSIZE
735 | FTS5CSR_REQUIRE_INST
736 | FTS5CSR_REQUIRE_POSLIST
740 static void fts5FreeCursorComponents(Fts5Cursor
*pCsr
){
741 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
745 sqlite3_free(pCsr
->aInstIter
);
746 sqlite3_free(pCsr
->aInst
);
748 int eStmt
= fts5StmtType(pCsr
);
749 sqlite3Fts5StorageStmtRelease(pTab
->pStorage
, eStmt
, pCsr
->pStmt
);
752 Fts5Sorter
*pSorter
= pCsr
->pSorter
;
753 sqlite3_finalize(pSorter
->pStmt
);
754 sqlite3_free(pSorter
);
757 if( pCsr
->ePlan
!=FTS5_PLAN_SOURCE
){
758 sqlite3Fts5ExprFree(pCsr
->pExpr
);
761 for(pData
=pCsr
->pAuxdata
; pData
; pData
=pNext
){
762 pNext
= pData
->pNext
;
763 if( pData
->xDelete
) pData
->xDelete(pData
->pPtr
);
767 sqlite3_finalize(pCsr
->pRankArgStmt
);
768 sqlite3_free(pCsr
->apRankArg
);
770 if( CsrFlagTest(pCsr
, FTS5CSR_FREE_ZRANK
) ){
771 sqlite3_free(pCsr
->zRank
);
772 sqlite3_free(pCsr
->zRankArgs
);
775 sqlite3Fts5IndexCloseReader(pTab
->p
.pIndex
);
776 memset(&pCsr
->ePlan
, 0, sizeof(Fts5Cursor
) - ((u8
*)&pCsr
->ePlan
- (u8
*)pCsr
));
781 ** Close the cursor. For additional information see the documentation
782 ** on the xClose method of the virtual table interface.
784 static int fts5CloseMethod(sqlite3_vtab_cursor
*pCursor
){
786 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCursor
->pVtab
);
787 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
790 fts5FreeCursorComponents(pCsr
);
791 /* Remove the cursor from the Fts5Global.pCsr list */
792 for(pp
=&pTab
->pGlobal
->pCsr
; (*pp
)!=pCsr
; pp
=&(*pp
)->pNext
);
800 static int fts5SorterNext(Fts5Cursor
*pCsr
){
801 Fts5Sorter
*pSorter
= pCsr
->pSorter
;
804 rc
= sqlite3_step(pSorter
->pStmt
);
805 if( rc
==SQLITE_DONE
){
807 CsrFlagSet(pCsr
, FTS5CSR_EOF
|FTS5CSR_REQUIRE_CONTENT
);
808 }else if( rc
==SQLITE_ROW
){
816 pSorter
->iRowid
= sqlite3_column_int64(pSorter
->pStmt
, 0);
817 nBlob
= sqlite3_column_bytes(pSorter
->pStmt
, 1);
818 aBlob
= a
= sqlite3_column_blob(pSorter
->pStmt
, 1);
820 /* nBlob==0 in detail=none mode. */
822 for(i
=0; i
<(pSorter
->nIdx
-1); i
++){
824 a
+= fts5GetVarint32(a
, iVal
);
826 pSorter
->aIdx
[i
] = iOff
;
828 pSorter
->aIdx
[i
] = &aBlob
[nBlob
] - a
;
829 pSorter
->aPoslist
= a
;
840 ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
841 ** open on table pTab.
843 static void fts5TripCursors(Fts5FullTable
*pTab
){
845 for(pCsr
=pTab
->pGlobal
->pCsr
; pCsr
; pCsr
=pCsr
->pNext
){
846 if( pCsr
->ePlan
==FTS5_PLAN_MATCH
847 && pCsr
->base
.pVtab
==(sqlite3_vtab
*)pTab
849 CsrFlagSet(pCsr
, FTS5CSR_REQUIRE_RESEEK
);
855 ** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
856 ** argument, close and reopen all Fts5IndexIter iterators that the cursor
857 ** is using. Then attempt to move the cursor to a rowid equal to or laster
858 ** (in the cursors sort order - ASC or DESC) than the current rowid.
860 ** If the new rowid is not equal to the old, set output parameter *pbSkip
861 ** to 1 before returning. Otherwise, leave it unchanged.
863 ** Return SQLITE_OK if successful or if no reseek was required, or an
864 ** error code if an error occurred.
866 static int fts5CursorReseek(Fts5Cursor
*pCsr
, int *pbSkip
){
868 assert( *pbSkip
==0 );
869 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_RESEEK
) ){
870 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
871 int bDesc
= pCsr
->bDesc
;
872 i64 iRowid
= sqlite3Fts5ExprRowid(pCsr
->pExpr
);
874 rc
= sqlite3Fts5ExprFirst(pCsr
->pExpr
, pTab
->p
.pIndex
, iRowid
, bDesc
);
875 if( rc
==SQLITE_OK
&& iRowid
!=sqlite3Fts5ExprRowid(pCsr
->pExpr
) ){
879 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_RESEEK
);
881 if( sqlite3Fts5ExprEof(pCsr
->pExpr
) ){
882 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
891 ** Advance the cursor to the next row in the table that matches the
894 ** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
895 ** even if we reach end-of-file. The fts5EofMethod() will be called
896 ** subsequently to determine whether or not an EOF was hit.
898 static int fts5NextMethod(sqlite3_vtab_cursor
*pCursor
){
899 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
902 assert( (pCsr
->ePlan
<3)==
903 (pCsr
->ePlan
==FTS5_PLAN_MATCH
|| pCsr
->ePlan
==FTS5_PLAN_SOURCE
)
905 assert( !CsrFlagTest(pCsr
, FTS5CSR_EOF
) );
909 if( (rc
= fts5CursorReseek(pCsr
, &bSkip
)) || bSkip
) return rc
;
910 rc
= sqlite3Fts5ExprNext(pCsr
->pExpr
, pCsr
->iLastRowid
);
911 CsrFlagSet(pCsr
, sqlite3Fts5ExprEof(pCsr
->pExpr
));
914 switch( pCsr
->ePlan
){
915 case FTS5_PLAN_SPECIAL
: {
916 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
921 case FTS5_PLAN_SORTED_MATCH
: {
922 rc
= fts5SorterNext(pCsr
);
927 Fts5Config
*pConfig
= ((Fts5Table
*)pCursor
->pVtab
)->pConfig
;
929 rc
= sqlite3_step(pCsr
->pStmt
);
931 if( rc
!=SQLITE_ROW
){
932 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
933 rc
= sqlite3_reset(pCsr
->pStmt
);
935 pCursor
->pVtab
->zErrMsg
= sqlite3_mprintf(
936 "%s", sqlite3_errmsg(pConfig
->db
)
951 static int fts5PrepareStatement(
952 sqlite3_stmt
**ppStmt
,
957 sqlite3_stmt
*pRet
= 0;
963 zSql
= sqlite3_vmprintf(zFmt
, ap
);
967 rc
= sqlite3_prepare_v3(pConfig
->db
, zSql
, -1,
968 SQLITE_PREPARE_PERSISTENT
, &pRet
, 0);
970 *pConfig
->pzErrmsg
= sqlite3_mprintf("%s", sqlite3_errmsg(pConfig
->db
));
980 static int fts5CursorFirstSorted(
985 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
990 const char *zRank
= pCsr
->zRank
;
991 const char *zRankArgs
= pCsr
->zRankArgs
;
993 nPhrase
= sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
);
994 nByte
= sizeof(Fts5Sorter
) + sizeof(int) * (nPhrase
-1);
995 pSorter
= (Fts5Sorter
*)sqlite3_malloc64(nByte
);
996 if( pSorter
==0 ) return SQLITE_NOMEM
;
997 memset(pSorter
, 0, (size_t)nByte
);
998 pSorter
->nIdx
= nPhrase
;
1000 /* TODO: It would be better to have some system for reusing statement
1001 ** handles here, rather than preparing a new one for each query. But that
1002 ** is not possible as SQLite reference counts the virtual table objects.
1003 ** And since the statement required here reads from this very virtual
1004 ** table, saving it creates a circular reference.
1006 ** If SQLite a built-in statement cache, this wouldn't be a problem. */
1007 rc
= fts5PrepareStatement(&pSorter
->pStmt
, pConfig
,
1008 "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(\"%w\"%s%s) %s",
1009 pConfig
->zDb
, pConfig
->zName
, zRank
, pConfig
->zName
,
1010 (zRankArgs
? ", " : ""),
1011 (zRankArgs
? zRankArgs
: ""),
1012 bDesc
? "DESC" : "ASC"
1015 pCsr
->pSorter
= pSorter
;
1016 if( rc
==SQLITE_OK
){
1017 assert( pTab
->pSortCsr
==0 );
1018 pTab
->pSortCsr
= pCsr
;
1019 rc
= fts5SorterNext(pCsr
);
1023 if( rc
!=SQLITE_OK
){
1024 sqlite3_finalize(pSorter
->pStmt
);
1025 sqlite3_free(pSorter
);
1032 static int fts5CursorFirst(Fts5FullTable
*pTab
, Fts5Cursor
*pCsr
, int bDesc
){
1034 Fts5Expr
*pExpr
= pCsr
->pExpr
;
1035 rc
= sqlite3Fts5ExprFirst(pExpr
, pTab
->p
.pIndex
, pCsr
->iFirstRowid
, bDesc
);
1036 if( sqlite3Fts5ExprEof(pExpr
) ){
1037 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
1039 fts5CsrNewrow(pCsr
);
1044 ** Process a "special" query. A special query is identified as one with a
1045 ** MATCH expression that begins with a '*' character. The remainder of
1046 ** the text passed to the MATCH operator are used as the special query
1049 static int fts5SpecialMatch(
1050 Fts5FullTable
*pTab
,
1054 int rc
= SQLITE_OK
; /* Return code */
1055 const char *z
= zQuery
; /* Special query text */
1056 int n
; /* Number of bytes in text at z */
1058 while( z
[0]==' ' ) z
++;
1059 for(n
=0; z
[n
] && z
[n
]!=' '; n
++);
1061 assert( pTab
->p
.base
.zErrMsg
==0 );
1062 pCsr
->ePlan
= FTS5_PLAN_SPECIAL
;
1064 if( n
==5 && 0==sqlite3_strnicmp("reads", z
, n
) ){
1065 pCsr
->iSpecial
= sqlite3Fts5IndexReads(pTab
->p
.pIndex
);
1067 else if( n
==2 && 0==sqlite3_strnicmp("id", z
, n
) ){
1068 pCsr
->iSpecial
= pCsr
->iCsrId
;
1071 /* An unrecognized directive. Return an error message. */
1072 pTab
->p
.base
.zErrMsg
= sqlite3_mprintf("unknown special query: %.*s", n
, z
);
1080 ** Search for an auxiliary function named zName that can be used with table
1081 ** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
1082 ** structure. Otherwise, if no such function exists, return NULL.
1084 static Fts5Auxiliary
*fts5FindAuxiliary(Fts5FullTable
*pTab
, const char *zName
){
1085 Fts5Auxiliary
*pAux
;
1087 for(pAux
=pTab
->pGlobal
->pAux
; pAux
; pAux
=pAux
->pNext
){
1088 if( sqlite3_stricmp(zName
, pAux
->zFunc
)==0 ) return pAux
;
1091 /* No function of the specified name was found. Return 0. */
1096 static int fts5FindRankFunction(Fts5Cursor
*pCsr
){
1097 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
1098 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
1100 Fts5Auxiliary
*pAux
= 0;
1101 const char *zRank
= pCsr
->zRank
;
1102 const char *zRankArgs
= pCsr
->zRankArgs
;
1105 char *zSql
= sqlite3Fts5Mprintf(&rc
, "SELECT %s", zRankArgs
);
1107 sqlite3_stmt
*pStmt
= 0;
1108 rc
= sqlite3_prepare_v3(pConfig
->db
, zSql
, -1,
1109 SQLITE_PREPARE_PERSISTENT
, &pStmt
, 0);
1111 assert( rc
==SQLITE_OK
|| pCsr
->pRankArgStmt
==0 );
1112 if( rc
==SQLITE_OK
){
1113 if( SQLITE_ROW
==sqlite3_step(pStmt
) ){
1114 sqlite3_int64 nByte
;
1115 pCsr
->nRankArg
= sqlite3_column_count(pStmt
);
1116 nByte
= sizeof(sqlite3_value
*)*pCsr
->nRankArg
;
1117 pCsr
->apRankArg
= (sqlite3_value
**)sqlite3Fts5MallocZero(&rc
, nByte
);
1118 if( rc
==SQLITE_OK
){
1120 for(i
=0; i
<pCsr
->nRankArg
; i
++){
1121 pCsr
->apRankArg
[i
] = sqlite3_column_value(pStmt
, i
);
1124 pCsr
->pRankArgStmt
= pStmt
;
1126 rc
= sqlite3_finalize(pStmt
);
1127 assert( rc
!=SQLITE_OK
);
1133 if( rc
==SQLITE_OK
){
1134 pAux
= fts5FindAuxiliary(pTab
, zRank
);
1136 assert( pTab
->p
.base
.zErrMsg
==0 );
1137 pTab
->p
.base
.zErrMsg
= sqlite3_mprintf("no such function: %s", zRank
);
1147 static int fts5CursorParseRank(
1148 Fts5Config
*pConfig
,
1150 sqlite3_value
*pRank
1154 const char *z
= (const char*)sqlite3_value_text(pRank
);
1156 char *zRankArgs
= 0;
1159 if( sqlite3_value_type(pRank
)==SQLITE_NULL
) rc
= SQLITE_ERROR
;
1161 rc
= sqlite3Fts5ConfigParseRank(z
, &zRank
, &zRankArgs
);
1163 if( rc
==SQLITE_OK
){
1164 pCsr
->zRank
= zRank
;
1165 pCsr
->zRankArgs
= zRankArgs
;
1166 CsrFlagSet(pCsr
, FTS5CSR_FREE_ZRANK
);
1167 }else if( rc
==SQLITE_ERROR
){
1168 pCsr
->base
.pVtab
->zErrMsg
= sqlite3_mprintf(
1169 "parse error in rank function: %s", z
1173 if( pConfig
->zRank
){
1174 pCsr
->zRank
= (char*)pConfig
->zRank
;
1175 pCsr
->zRankArgs
= (char*)pConfig
->zRankArgs
;
1177 pCsr
->zRank
= (char*)FTS5_DEFAULT_RANK
;
1178 pCsr
->zRankArgs
= 0;
1184 static i64
fts5GetRowidLimit(sqlite3_value
*pVal
, i64 iDefault
){
1186 int eType
= sqlite3_value_numeric_type(pVal
);
1187 if( eType
==SQLITE_INTEGER
){
1188 return sqlite3_value_int64(pVal
);
1195 ** This is the xFilter interface for the virtual table. See
1196 ** the virtual table xFilter method documentation for additional
1199 ** There are three possible query strategies:
1201 ** 1. Full-text search using a MATCH operator.
1202 ** 2. A by-rowid lookup.
1203 ** 3. A full-table scan.
1205 static int fts5FilterMethod(
1206 sqlite3_vtab_cursor
*pCursor
, /* The cursor used for this query */
1207 int idxNum
, /* Strategy index */
1208 const char *idxStr
, /* Unused */
1209 int nVal
, /* Number of elements in apVal */
1210 sqlite3_value
**apVal
/* Arguments for the indexing scheme */
1212 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCursor
->pVtab
);
1213 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
1214 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
1215 int rc
= SQLITE_OK
; /* Error code */
1216 int bDesc
; /* True if ORDER BY [rank|rowid] DESC */
1217 int bOrderByRank
; /* True if ORDER BY rank */
1218 sqlite3_value
*pRank
= 0; /* rank MATCH ? expression (or NULL) */
1219 sqlite3_value
*pRowidEq
= 0; /* rowid = ? expression (or NULL) */
1220 sqlite3_value
*pRowidLe
= 0; /* rowid <= ? expression (or NULL) */
1221 sqlite3_value
*pRowidGe
= 0; /* rowid >= ? expression (or NULL) */
1222 int iCol
; /* Column on LHS of MATCH operator */
1223 char **pzErrmsg
= pConfig
->pzErrmsg
;
1226 Fts5Expr
*pExpr
= 0;
1228 if( pConfig
->bLock
){
1229 pTab
->p
.base
.zErrMsg
= sqlite3_mprintf(
1230 "recursively defined fts5 content table"
1232 return SQLITE_ERROR
;
1236 fts5FreeCursorComponents(pCsr
);
1237 memset(&pCsr
->ePlan
, 0, sizeof(Fts5Cursor
) - ((u8
*)&pCsr
->ePlan
-(u8
*)pCsr
));
1240 assert( pCsr
->pStmt
==0 );
1241 assert( pCsr
->pExpr
==0 );
1242 assert( pCsr
->csrflags
==0 );
1243 assert( pCsr
->pRank
==0 );
1244 assert( pCsr
->zRank
==0 );
1245 assert( pCsr
->zRankArgs
==0 );
1246 assert( pTab
->pSortCsr
==0 || nVal
==0 );
1248 assert( pzErrmsg
==0 || pzErrmsg
==&pTab
->p
.base
.zErrMsg
);
1249 pConfig
->pzErrmsg
= &pTab
->p
.base
.zErrMsg
;
1251 /* Decode the arguments passed through to this function. */
1252 for(i
=0; i
<nVal
; i
++){
1253 switch( idxStr
[iIdxStr
++] ){
1258 const char *zText
= (const char*)sqlite3_value_text(apVal
[i
]);
1259 if( zText
==0 ) zText
= "";
1262 iCol
= iCol
*10 + (idxStr
[iIdxStr
]-'0');
1264 }while( idxStr
[iIdxStr
]>='0' && idxStr
[iIdxStr
]<='9' );
1266 if( zText
[0]=='*' ){
1267 /* The user has issued a query of the form "MATCH '*...'". This
1268 ** indicates that the MATCH expression is not a full text query,
1269 ** but a request for an internal parameter. */
1270 rc
= fts5SpecialMatch(pTab
, pCsr
, &zText
[1]);
1273 char **pzErr
= &pTab
->p
.base
.zErrMsg
;
1274 rc
= sqlite3Fts5ExprNew(pConfig
, 0, iCol
, zText
, &pExpr
, pzErr
);
1275 if( rc
==SQLITE_OK
){
1276 rc
= sqlite3Fts5ExprAnd(&pCsr
->pExpr
, pExpr
);
1279 if( rc
!=SQLITE_OK
) goto filter_out
;
1286 int bGlob
= (idxStr
[iIdxStr
-1]=='G');
1287 const char *zText
= (const char*)sqlite3_value_text(apVal
[i
]);
1290 iCol
= iCol
*10 + (idxStr
[iIdxStr
]-'0');
1292 }while( idxStr
[iIdxStr
]>='0' && idxStr
[iIdxStr
]<='9' );
1294 rc
= sqlite3Fts5ExprPattern(pConfig
, bGlob
, iCol
, zText
, &pExpr
);
1296 if( rc
==SQLITE_OK
){
1297 rc
= sqlite3Fts5ExprAnd(&pCsr
->pExpr
, pExpr
);
1300 if( rc
!=SQLITE_OK
) goto filter_out
;
1304 pRowidEq
= apVal
[i
];
1307 pRowidLe
= apVal
[i
];
1309 default: assert( idxStr
[iIdxStr
-1]=='>' );
1310 pRowidGe
= apVal
[i
];
1314 bOrderByRank
= ((idxNum
& FTS5_BI_ORDER_RANK
) ? 1 : 0);
1315 pCsr
->bDesc
= bDesc
= ((idxNum
& FTS5_BI_ORDER_DESC
) ? 1 : 0);
1317 /* Set the cursor upper and lower rowid limits. Only some strategies
1318 ** actually use them. This is ok, as the xBestIndex() method leaves the
1319 ** sqlite3_index_constraint.omit flag clear for range constraints
1320 ** on the rowid field. */
1322 pRowidLe
= pRowidGe
= pRowidEq
;
1325 pCsr
->iFirstRowid
= fts5GetRowidLimit(pRowidLe
, LARGEST_INT64
);
1326 pCsr
->iLastRowid
= fts5GetRowidLimit(pRowidGe
, SMALLEST_INT64
);
1328 pCsr
->iLastRowid
= fts5GetRowidLimit(pRowidLe
, LARGEST_INT64
);
1329 pCsr
->iFirstRowid
= fts5GetRowidLimit(pRowidGe
, SMALLEST_INT64
);
1332 if( pTab
->pSortCsr
){
1333 /* If pSortCsr is non-NULL, then this call is being made as part of
1334 ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
1335 ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
1336 ** return results to the user for this query. The current cursor
1337 ** (pCursor) is used to execute the query issued by function
1338 ** fts5CursorFirstSorted() above. */
1339 assert( pRowidEq
==0 && pRowidLe
==0 && pRowidGe
==0 && pRank
==0 );
1340 assert( nVal
==0 && bOrderByRank
==0 && bDesc
==0 );
1341 assert( pCsr
->iLastRowid
==LARGEST_INT64
);
1342 assert( pCsr
->iFirstRowid
==SMALLEST_INT64
);
1343 if( pTab
->pSortCsr
->bDesc
){
1344 pCsr
->iLastRowid
= pTab
->pSortCsr
->iFirstRowid
;
1345 pCsr
->iFirstRowid
= pTab
->pSortCsr
->iLastRowid
;
1347 pCsr
->iLastRowid
= pTab
->pSortCsr
->iLastRowid
;
1348 pCsr
->iFirstRowid
= pTab
->pSortCsr
->iFirstRowid
;
1350 pCsr
->ePlan
= FTS5_PLAN_SOURCE
;
1351 pCsr
->pExpr
= pTab
->pSortCsr
->pExpr
;
1352 rc
= fts5CursorFirst(pTab
, pCsr
, bDesc
);
1353 }else if( pCsr
->pExpr
){
1354 rc
= fts5CursorParseRank(pConfig
, pCsr
, pRank
);
1355 if( rc
==SQLITE_OK
){
1357 pCsr
->ePlan
= FTS5_PLAN_SORTED_MATCH
;
1358 rc
= fts5CursorFirstSorted(pTab
, pCsr
, bDesc
);
1360 pCsr
->ePlan
= FTS5_PLAN_MATCH
;
1361 rc
= fts5CursorFirst(pTab
, pCsr
, bDesc
);
1364 }else if( pConfig
->zContent
==0 ){
1365 *pConfig
->pzErrmsg
= sqlite3_mprintf(
1366 "%s: table does not support scanning", pConfig
->zName
1370 /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
1371 ** by rowid (ePlan==FTS5_PLAN_ROWID). */
1372 pCsr
->ePlan
= (pRowidEq
? FTS5_PLAN_ROWID
: FTS5_PLAN_SCAN
);
1373 rc
= sqlite3Fts5StorageStmt(
1374 pTab
->pStorage
, fts5StmtType(pCsr
), &pCsr
->pStmt
, &pTab
->p
.base
.zErrMsg
1376 if( rc
==SQLITE_OK
){
1378 assert( pCsr
->ePlan
==FTS5_PLAN_ROWID
);
1379 sqlite3_bind_value(pCsr
->pStmt
, 1, pRowidEq
);
1381 sqlite3_bind_int64(pCsr
->pStmt
, 1, pCsr
->iFirstRowid
);
1382 sqlite3_bind_int64(pCsr
->pStmt
, 2, pCsr
->iLastRowid
);
1384 rc
= fts5NextMethod(pCursor
);
1389 sqlite3Fts5ExprFree(pExpr
);
1390 pConfig
->pzErrmsg
= pzErrmsg
;
1395 ** This is the xEof method of the virtual table. SQLite calls this
1396 ** routine to find out if it has reached the end of a result set.
1398 static int fts5EofMethod(sqlite3_vtab_cursor
*pCursor
){
1399 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
1400 return (CsrFlagTest(pCsr
, FTS5CSR_EOF
) ? 1 : 0);
1404 ** Return the rowid that the cursor currently points to.
1406 static i64
fts5CursorRowid(Fts5Cursor
*pCsr
){
1407 assert( pCsr
->ePlan
==FTS5_PLAN_MATCH
1408 || pCsr
->ePlan
==FTS5_PLAN_SORTED_MATCH
1409 || pCsr
->ePlan
==FTS5_PLAN_SOURCE
1411 if( pCsr
->pSorter
){
1412 return pCsr
->pSorter
->iRowid
;
1414 return sqlite3Fts5ExprRowid(pCsr
->pExpr
);
1419 ** This is the xRowid method. The SQLite core calls this routine to
1420 ** retrieve the rowid for the current row of the result set. fts5
1421 ** exposes %_content.rowid as the rowid for the virtual table. The
1422 ** rowid should be written to *pRowid.
1424 static int fts5RowidMethod(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
1425 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
1426 int ePlan
= pCsr
->ePlan
;
1428 assert( CsrFlagTest(pCsr
, FTS5CSR_EOF
)==0 );
1430 case FTS5_PLAN_SPECIAL
:
1434 case FTS5_PLAN_SOURCE
:
1435 case FTS5_PLAN_MATCH
:
1436 case FTS5_PLAN_SORTED_MATCH
:
1437 *pRowid
= fts5CursorRowid(pCsr
);
1441 *pRowid
= sqlite3_column_int64(pCsr
->pStmt
, 0);
1449 ** If the cursor requires seeking (bSeekRequired flag is set), seek it.
1450 ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
1452 ** If argument bErrormsg is true and an error occurs, an error message may
1453 ** be left in sqlite3_vtab.zErrMsg.
1455 static int fts5SeekCursor(Fts5Cursor
*pCsr
, int bErrormsg
){
1458 /* If the cursor does not yet have a statement handle, obtain one now. */
1459 if( pCsr
->pStmt
==0 ){
1460 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
1461 int eStmt
= fts5StmtType(pCsr
);
1462 rc
= sqlite3Fts5StorageStmt(
1463 pTab
->pStorage
, eStmt
, &pCsr
->pStmt
, (bErrormsg
?&pTab
->p
.base
.zErrMsg
:0)
1465 assert( rc
!=SQLITE_OK
|| pTab
->p
.base
.zErrMsg
==0 );
1466 assert( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_CONTENT
) );
1469 if( rc
==SQLITE_OK
&& CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_CONTENT
) ){
1470 Fts5Table
*pTab
= (Fts5Table
*)(pCsr
->base
.pVtab
);
1471 assert( pCsr
->pExpr
);
1472 sqlite3_reset(pCsr
->pStmt
);
1473 sqlite3_bind_int64(pCsr
->pStmt
, 1, fts5CursorRowid(pCsr
));
1474 pTab
->pConfig
->bLock
++;
1475 rc
= sqlite3_step(pCsr
->pStmt
);
1476 pTab
->pConfig
->bLock
--;
1477 if( rc
==SQLITE_ROW
){
1479 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_CONTENT
);
1481 rc
= sqlite3_reset(pCsr
->pStmt
);
1482 if( rc
==SQLITE_OK
){
1484 }else if( pTab
->pConfig
->pzErrmsg
){
1485 *pTab
->pConfig
->pzErrmsg
= sqlite3_mprintf(
1486 "%s", sqlite3_errmsg(pTab
->pConfig
->db
)
1494 static void fts5SetVtabError(Fts5FullTable
*p
, const char *zFormat
, ...){
1495 va_list ap
; /* ... printf arguments */
1496 va_start(ap
, zFormat
);
1497 assert( p
->p
.base
.zErrMsg
==0 );
1498 p
->p
.base
.zErrMsg
= sqlite3_vmprintf(zFormat
, ap
);
1503 ** This function is called to handle an FTS INSERT command. In other words,
1504 ** an INSERT statement of the form:
1506 ** INSERT INTO fts(fts) VALUES($pCmd)
1507 ** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
1509 ** Argument pVal is the value assigned to column "fts" by the INSERT
1510 ** statement. This function returns SQLITE_OK if successful, or an SQLite
1511 ** error code if an error occurs.
1513 ** The commands implemented by this function are documented in the "Special
1514 ** INSERT Directives" section of the documentation. It should be updated if
1515 ** more commands are added to this function.
1517 static int fts5SpecialInsert(
1518 Fts5FullTable
*pTab
, /* Fts5 table object */
1519 const char *zCmd
, /* Text inserted into table-name column */
1520 sqlite3_value
*pVal
/* Value inserted into rank column */
1522 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
1526 if( 0==sqlite3_stricmp("delete-all", zCmd
) ){
1527 if( pConfig
->eContent
==FTS5_CONTENT_NORMAL
){
1528 fts5SetVtabError(pTab
,
1529 "'delete-all' may only be used with a "
1530 "contentless or external content fts5 table"
1534 rc
= sqlite3Fts5StorageDeleteAll(pTab
->pStorage
);
1536 }else if( 0==sqlite3_stricmp("rebuild", zCmd
) ){
1537 if( pConfig
->eContent
==FTS5_CONTENT_NONE
){
1538 fts5SetVtabError(pTab
,
1539 "'rebuild' may not be used with a contentless fts5 table"
1543 rc
= sqlite3Fts5StorageRebuild(pTab
->pStorage
);
1545 }else if( 0==sqlite3_stricmp("optimize", zCmd
) ){
1546 rc
= sqlite3Fts5StorageOptimize(pTab
->pStorage
);
1547 }else if( 0==sqlite3_stricmp("merge", zCmd
) ){
1548 int nMerge
= sqlite3_value_int(pVal
);
1549 rc
= sqlite3Fts5StorageMerge(pTab
->pStorage
, nMerge
);
1550 }else if( 0==sqlite3_stricmp("integrity-check", zCmd
) ){
1551 int iArg
= sqlite3_value_int(pVal
);
1552 rc
= sqlite3Fts5StorageIntegrity(pTab
->pStorage
, iArg
);
1554 }else if( 0==sqlite3_stricmp("prefix-index", zCmd
) ){
1555 pConfig
->bPrefixIndex
= sqlite3_value_int(pVal
);
1558 rc
= sqlite3Fts5IndexLoadConfig(pTab
->p
.pIndex
);
1559 if( rc
==SQLITE_OK
){
1560 rc
= sqlite3Fts5ConfigSetValue(pTab
->p
.pConfig
, zCmd
, pVal
, &bError
);
1562 if( rc
==SQLITE_OK
){
1566 rc
= sqlite3Fts5StorageConfigValue(pTab
->pStorage
, zCmd
, pVal
, 0);
1573 static int fts5SpecialDelete(
1574 Fts5FullTable
*pTab
,
1575 sqlite3_value
**apVal
1578 int eType1
= sqlite3_value_type(apVal
[1]);
1579 if( eType1
==SQLITE_INTEGER
){
1580 sqlite3_int64 iDel
= sqlite3_value_int64(apVal
[1]);
1581 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iDel
, &apVal
[2]);
1586 static void fts5StorageInsert(
1588 Fts5FullTable
*pTab
,
1589 sqlite3_value
**apVal
,
1593 if( rc
==SQLITE_OK
){
1594 rc
= sqlite3Fts5StorageContentInsert(pTab
->pStorage
, apVal
, piRowid
);
1596 if( rc
==SQLITE_OK
){
1597 rc
= sqlite3Fts5StorageIndexInsert(pTab
->pStorage
, apVal
, *piRowid
);
1603 ** This function is the implementation of the xUpdate callback used by
1604 ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
1605 ** inserted, updated or deleted.
1607 ** A delete specifies a single argument - the rowid of the row to remove.
1609 ** Update and insert operations pass:
1611 ** 1. The "old" rowid, or NULL.
1612 ** 2. The "new" rowid.
1613 ** 3. Values for each of the nCol matchable columns.
1614 ** 4. Values for the two hidden columns (<tablename> and "rank").
1616 static int fts5UpdateMethod(
1617 sqlite3_vtab
*pVtab
, /* Virtual table handle */
1618 int nArg
, /* Size of argument array */
1619 sqlite3_value
**apVal
, /* Array of arguments */
1620 sqlite_int64
*pRowid
/* OUT: The affected (or effected) rowid */
1622 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
1623 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
1624 int eType0
; /* value_type() of apVal[0] */
1625 int rc
= SQLITE_OK
; /* Return code */
1627 /* A transaction must be open when this is called. */
1628 assert( pTab
->ts
.eState
==1 || pTab
->ts
.eState
==2 );
1630 assert( pVtab
->zErrMsg
==0 );
1631 assert( nArg
==1 || nArg
==(2+pConfig
->nCol
+2) );
1632 assert( sqlite3_value_type(apVal
[0])==SQLITE_INTEGER
1633 || sqlite3_value_type(apVal
[0])==SQLITE_NULL
1635 assert( pTab
->p
.pConfig
->pzErrmsg
==0 );
1636 pTab
->p
.pConfig
->pzErrmsg
= &pTab
->p
.base
.zErrMsg
;
1638 /* Put any active cursors into REQUIRE_SEEK state. */
1639 fts5TripCursors(pTab
);
1641 eType0
= sqlite3_value_type(apVal
[0]);
1642 if( eType0
==SQLITE_NULL
1643 && sqlite3_value_type(apVal
[2+pConfig
->nCol
])!=SQLITE_NULL
1645 /* A "special" INSERT op. These are handled separately. */
1646 const char *z
= (const char*)sqlite3_value_text(apVal
[2+pConfig
->nCol
]);
1647 if( pConfig
->eContent
!=FTS5_CONTENT_NORMAL
1648 && 0==sqlite3_stricmp("delete", z
)
1650 rc
= fts5SpecialDelete(pTab
, apVal
);
1652 rc
= fts5SpecialInsert(pTab
, z
, apVal
[2 + pConfig
->nCol
+ 1]);
1655 /* A regular INSERT, UPDATE or DELETE statement. The trick here is that
1656 ** any conflict on the rowid value must be detected before any
1657 ** modifications are made to the database file. There are 4 cases:
1660 ** 2) UPDATE (rowid not modified)
1661 ** 3) UPDATE (rowid modified)
1664 ** Cases 3 and 4 may violate the rowid constraint.
1666 int eConflict
= SQLITE_ABORT
;
1667 if( pConfig
->eContent
==FTS5_CONTENT_NORMAL
){
1668 eConflict
= sqlite3_vtab_on_conflict(pConfig
->db
);
1671 assert( eType0
==SQLITE_INTEGER
|| eType0
==SQLITE_NULL
);
1672 assert( nArg
!=1 || eType0
==SQLITE_INTEGER
);
1674 /* Filter out attempts to run UPDATE or DELETE on contentless tables.
1675 ** This is not suported. */
1676 if( eType0
==SQLITE_INTEGER
&& fts5IsContentless(pTab
) ){
1677 pTab
->p
.base
.zErrMsg
= sqlite3_mprintf(
1678 "cannot %s contentless fts5 table: %s",
1679 (nArg
>1 ? "UPDATE" : "DELETE from"), pConfig
->zName
1686 i64 iDel
= sqlite3_value_int64(apVal
[0]); /* Rowid to delete */
1687 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iDel
, 0);
1690 /* INSERT or UPDATE */
1692 int eType1
= sqlite3_value_numeric_type(apVal
[1]);
1694 if( eType1
!=SQLITE_INTEGER
&& eType1
!=SQLITE_NULL
){
1695 rc
= SQLITE_MISMATCH
;
1698 else if( eType0
!=SQLITE_INTEGER
){
1699 /* If this is a REPLACE, first remove the current entry (if any) */
1700 if( eConflict
==SQLITE_REPLACE
&& eType1
==SQLITE_INTEGER
){
1701 i64 iNew
= sqlite3_value_int64(apVal
[1]); /* Rowid to delete */
1702 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iNew
, 0);
1704 fts5StorageInsert(&rc
, pTab
, apVal
, pRowid
);
1709 i64 iOld
= sqlite3_value_int64(apVal
[0]); /* Old rowid */
1710 i64 iNew
= sqlite3_value_int64(apVal
[1]); /* New rowid */
1711 if( eType1
==SQLITE_INTEGER
&& iOld
!=iNew
){
1712 if( eConflict
==SQLITE_REPLACE
){
1713 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iOld
, 0);
1714 if( rc
==SQLITE_OK
){
1715 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iNew
, 0);
1717 fts5StorageInsert(&rc
, pTab
, apVal
, pRowid
);
1719 rc
= sqlite3Fts5StorageContentInsert(pTab
->pStorage
, apVal
, pRowid
);
1720 if( rc
==SQLITE_OK
){
1721 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iOld
, 0);
1723 if( rc
==SQLITE_OK
){
1724 rc
= sqlite3Fts5StorageIndexInsert(pTab
->pStorage
, apVal
,*pRowid
);
1728 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iOld
, 0);
1729 fts5StorageInsert(&rc
, pTab
, apVal
, pRowid
);
1735 pTab
->p
.pConfig
->pzErrmsg
= 0;
1740 ** Implementation of xSync() method.
1742 static int fts5SyncMethod(sqlite3_vtab
*pVtab
){
1744 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
1745 fts5CheckTransactionState(pTab
, FTS5_SYNC
, 0);
1746 pTab
->p
.pConfig
->pzErrmsg
= &pTab
->p
.base
.zErrMsg
;
1747 fts5TripCursors(pTab
);
1748 rc
= sqlite3Fts5StorageSync(pTab
->pStorage
);
1749 pTab
->p
.pConfig
->pzErrmsg
= 0;
1754 ** Implementation of xBegin() method.
1756 static int fts5BeginMethod(sqlite3_vtab
*pVtab
){
1757 fts5CheckTransactionState((Fts5FullTable
*)pVtab
, FTS5_BEGIN
, 0);
1758 fts5NewTransaction((Fts5FullTable
*)pVtab
);
1763 ** Implementation of xCommit() method. This is a no-op. The contents of
1764 ** the pending-terms hash-table have already been flushed into the database
1765 ** by fts5SyncMethod().
1767 static int fts5CommitMethod(sqlite3_vtab
*pVtab
){
1768 UNUSED_PARAM(pVtab
); /* Call below is a no-op for NDEBUG builds */
1769 fts5CheckTransactionState((Fts5FullTable
*)pVtab
, FTS5_COMMIT
, 0);
1774 ** Implementation of xRollback(). Discard the contents of the pending-terms
1775 ** hash-table. Any changes made to the database are reverted by SQLite.
1777 static int fts5RollbackMethod(sqlite3_vtab
*pVtab
){
1779 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
1780 fts5CheckTransactionState(pTab
, FTS5_ROLLBACK
, 0);
1781 rc
= sqlite3Fts5StorageRollback(pTab
->pStorage
);
1785 static int fts5CsrPoslist(Fts5Cursor
*, int, const u8
**, int*);
1787 static void *fts5ApiUserData(Fts5Context
*pCtx
){
1788 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1789 return pCsr
->pAux
->pUserData
;
1792 static int fts5ApiColumnCount(Fts5Context
*pCtx
){
1793 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1794 return ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
->nCol
;
1797 static int fts5ApiColumnTotalSize(
1800 sqlite3_int64
*pnToken
1802 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1803 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
1804 return sqlite3Fts5StorageSize(pTab
->pStorage
, iCol
, pnToken
);
1807 static int fts5ApiRowCount(Fts5Context
*pCtx
, i64
*pnRow
){
1808 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1809 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
1810 return sqlite3Fts5StorageRowCount(pTab
->pStorage
, pnRow
);
1813 static int fts5ApiTokenize(
1815 const char *pText
, int nText
,
1817 int (*xToken
)(void*, int, const char*, int, int, int)
1819 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1820 Fts5Table
*pTab
= (Fts5Table
*)(pCsr
->base
.pVtab
);
1821 return sqlite3Fts5Tokenize(
1822 pTab
->pConfig
, FTS5_TOKENIZE_AUX
, pText
, nText
, pUserData
, xToken
1826 static int fts5ApiPhraseCount(Fts5Context
*pCtx
){
1827 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1828 return sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
);
1831 static int fts5ApiPhraseSize(Fts5Context
*pCtx
, int iPhrase
){
1832 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1833 return sqlite3Fts5ExprPhraseSize(pCsr
->pExpr
, iPhrase
);
1836 static int fts5ApiColumnText(
1843 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1844 if( fts5IsContentless((Fts5FullTable
*)(pCsr
->base
.pVtab
))
1845 || pCsr
->ePlan
==FTS5_PLAN_SPECIAL
1850 rc
= fts5SeekCursor(pCsr
, 0);
1851 if( rc
==SQLITE_OK
){
1852 *pz
= (const char*)sqlite3_column_text(pCsr
->pStmt
, iCol
+1);
1853 *pn
= sqlite3_column_bytes(pCsr
->pStmt
, iCol
+1);
1859 static int fts5CsrPoslist(
1865 Fts5Config
*pConfig
= ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
;
1867 int bLive
= (pCsr
->pSorter
==0);
1869 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_POSLIST
) ){
1871 if( pConfig
->eDetail
!=FTS5_DETAIL_FULL
){
1872 Fts5PoslistPopulator
*aPopulator
;
1874 aPopulator
= sqlite3Fts5ExprClearPoslists(pCsr
->pExpr
, bLive
);
1875 if( aPopulator
==0 ) rc
= SQLITE_NOMEM
;
1876 for(i
=0; i
<pConfig
->nCol
&& rc
==SQLITE_OK
; i
++){
1877 int n
; const char *z
;
1878 rc
= fts5ApiColumnText((Fts5Context
*)pCsr
, i
, &z
, &n
);
1879 if( rc
==SQLITE_OK
){
1880 rc
= sqlite3Fts5ExprPopulatePoslists(
1881 pConfig
, pCsr
->pExpr
, aPopulator
, i
, z
, n
1885 sqlite3_free(aPopulator
);
1887 if( pCsr
->pSorter
){
1888 sqlite3Fts5ExprCheckPoslists(pCsr
->pExpr
, pCsr
->pSorter
->iRowid
);
1891 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_POSLIST
);
1894 if( pCsr
->pSorter
&& pConfig
->eDetail
==FTS5_DETAIL_FULL
){
1895 Fts5Sorter
*pSorter
= pCsr
->pSorter
;
1896 int i1
= (iPhrase
==0 ? 0 : pSorter
->aIdx
[iPhrase
-1]);
1897 *pn
= pSorter
->aIdx
[iPhrase
] - i1
;
1898 *pa
= &pSorter
->aPoslist
[i1
];
1900 *pn
= sqlite3Fts5ExprPoslist(pCsr
->pExpr
, iPhrase
, pa
);
1907 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
1908 ** correctly for the current view. Return SQLITE_OK if successful, or an
1909 ** SQLite error code otherwise.
1911 static int fts5CacheInstArray(Fts5Cursor
*pCsr
){
1913 Fts5PoslistReader
*aIter
; /* One iterator for each phrase */
1914 int nIter
; /* Number of iterators/phrases */
1915 int nCol
= ((Fts5Table
*)pCsr
->base
.pVtab
)->pConfig
->nCol
;
1917 nIter
= sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
);
1918 if( pCsr
->aInstIter
==0 ){
1919 sqlite3_int64 nByte
= sizeof(Fts5PoslistReader
) * nIter
;
1920 pCsr
->aInstIter
= (Fts5PoslistReader
*)sqlite3Fts5MallocZero(&rc
, nByte
);
1922 aIter
= pCsr
->aInstIter
;
1925 int nInst
= 0; /* Number instances seen so far */
1928 /* Initialize all iterators */
1929 for(i
=0; i
<nIter
&& rc
==SQLITE_OK
; i
++){
1932 rc
= fts5CsrPoslist(pCsr
, i
, &a
, &n
);
1933 if( rc
==SQLITE_OK
){
1934 sqlite3Fts5PoslistReaderInit(a
, n
, &aIter
[i
]);
1938 if( rc
==SQLITE_OK
){
1942 for(i
=0; i
<nIter
; i
++){
1943 if( (aIter
[i
].bEof
==0)
1944 && (iBest
<0 || aIter
[i
].iPos
<aIter
[iBest
].iPos
)
1949 if( iBest
<0 ) break;
1952 if( nInst
>=pCsr
->nInstAlloc
){
1953 int nNewSize
= pCsr
->nInstAlloc
? pCsr
->nInstAlloc
*2 : 32;
1954 aInst
= (int*)sqlite3_realloc64(
1955 pCsr
->aInst
, nNewSize
*sizeof(int)*3
1958 pCsr
->aInst
= aInst
;
1959 pCsr
->nInstAlloc
= nNewSize
;
1967 aInst
= &pCsr
->aInst
[3 * (nInst
-1)];
1969 aInst
[1] = FTS5_POS2COLUMN(aIter
[iBest
].iPos
);
1970 aInst
[2] = FTS5_POS2OFFSET(aIter
[iBest
].iPos
);
1971 if( aInst
[1]<0 || aInst
[1]>=nCol
){
1975 sqlite3Fts5PoslistReaderNext(&aIter
[iBest
]);
1979 pCsr
->nInstCount
= nInst
;
1980 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_INST
);
1985 static int fts5ApiInstCount(Fts5Context
*pCtx
, int *pnInst
){
1986 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1988 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_INST
)==0
1989 || SQLITE_OK
==(rc
= fts5CacheInstArray(pCsr
)) ){
1990 *pnInst
= pCsr
->nInstCount
;
1995 static int fts5ApiInst(
2002 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2004 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_INST
)==0
2005 || SQLITE_OK
==(rc
= fts5CacheInstArray(pCsr
))
2007 if( iIdx
<0 || iIdx
>=pCsr
->nInstCount
){
2010 }else if( fts5IsOffsetless((Fts5Table
*)pCsr
->base
.pVtab
) ){
2011 *piPhrase
= pCsr
->aInst
[iIdx
*3];
2012 *piCol
= pCsr
->aInst
[iIdx
*3 + 2];
2016 *piPhrase
= pCsr
->aInst
[iIdx
*3];
2017 *piCol
= pCsr
->aInst
[iIdx
*3 + 1];
2018 *piOff
= pCsr
->aInst
[iIdx
*3 + 2];
2024 static sqlite3_int64
fts5ApiRowid(Fts5Context
*pCtx
){
2025 return fts5CursorRowid((Fts5Cursor
*)pCtx
);
2028 static int fts5ColumnSizeCb(
2029 void *pContext
, /* Pointer to int */
2031 const char *pUnused
, /* Buffer containing token */
2032 int nUnused
, /* Size of token in bytes */
2033 int iUnused1
, /* Start offset of token */
2034 int iUnused2
/* End offset of token */
2036 int *pCnt
= (int*)pContext
;
2037 UNUSED_PARAM2(pUnused
, nUnused
);
2038 UNUSED_PARAM2(iUnused1
, iUnused2
);
2039 if( (tflags
& FTS5_TOKEN_COLOCATED
)==0 ){
2045 static int fts5ApiColumnSize(Fts5Context
*pCtx
, int iCol
, int *pnToken
){
2046 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2047 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
2048 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
2051 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_DOCSIZE
) ){
2052 if( pConfig
->bColumnsize
){
2053 i64 iRowid
= fts5CursorRowid(pCsr
);
2054 rc
= sqlite3Fts5StorageDocsize(pTab
->pStorage
, iRowid
, pCsr
->aColumnSize
);
2055 }else if( pConfig
->zContent
==0 ){
2057 for(i
=0; i
<pConfig
->nCol
; i
++){
2058 if( pConfig
->abUnindexed
[i
]==0 ){
2059 pCsr
->aColumnSize
[i
] = -1;
2064 for(i
=0; rc
==SQLITE_OK
&& i
<pConfig
->nCol
; i
++){
2065 if( pConfig
->abUnindexed
[i
]==0 ){
2066 const char *z
; int n
;
2067 void *p
= (void*)(&pCsr
->aColumnSize
[i
]);
2068 pCsr
->aColumnSize
[i
] = 0;
2069 rc
= fts5ApiColumnText(pCtx
, i
, &z
, &n
);
2070 if( rc
==SQLITE_OK
){
2071 rc
= sqlite3Fts5Tokenize(
2072 pConfig
, FTS5_TOKENIZE_AUX
, z
, n
, p
, fts5ColumnSizeCb
2078 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_DOCSIZE
);
2083 for(i
=0; i
<pConfig
->nCol
; i
++){
2084 *pnToken
+= pCsr
->aColumnSize
[i
];
2086 }else if( iCol
<pConfig
->nCol
){
2087 *pnToken
= pCsr
->aColumnSize
[iCol
];
2096 ** Implementation of the xSetAuxdata() method.
2098 static int fts5ApiSetAuxdata(
2099 Fts5Context
*pCtx
, /* Fts5 context */
2100 void *pPtr
, /* Pointer to save as auxdata */
2101 void(*xDelete
)(void*) /* Destructor for pPtr (or NULL) */
2103 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2106 /* Search through the cursors list of Fts5Auxdata objects for one that
2107 ** corresponds to the currently executing auxiliary function. */
2108 for(pData
=pCsr
->pAuxdata
; pData
; pData
=pData
->pNext
){
2109 if( pData
->pAux
==pCsr
->pAux
) break;
2113 if( pData
->xDelete
){
2114 pData
->xDelete(pData
->pPtr
);
2118 pData
= (Fts5Auxdata
*)sqlite3Fts5MallocZero(&rc
, sizeof(Fts5Auxdata
));
2120 if( xDelete
) xDelete(pPtr
);
2123 pData
->pAux
= pCsr
->pAux
;
2124 pData
->pNext
= pCsr
->pAuxdata
;
2125 pCsr
->pAuxdata
= pData
;
2128 pData
->xDelete
= xDelete
;
2133 static void *fts5ApiGetAuxdata(Fts5Context
*pCtx
, int bClear
){
2134 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2138 for(pData
=pCsr
->pAuxdata
; pData
; pData
=pData
->pNext
){
2139 if( pData
->pAux
==pCsr
->pAux
) break;
2153 static void fts5ApiPhraseNext(
2154 Fts5Context
*pUnused
,
2155 Fts5PhraseIter
*pIter
,
2156 int *piCol
, int *piOff
2158 UNUSED_PARAM(pUnused
);
2159 if( pIter
->a
>=pIter
->b
){
2164 pIter
->a
+= fts5GetVarint32(pIter
->a
, iVal
);
2166 pIter
->a
+= fts5GetVarint32(pIter
->a
, iVal
);
2169 pIter
->a
+= fts5GetVarint32(pIter
->a
, iVal
);
2175 static int fts5ApiPhraseFirst(
2178 Fts5PhraseIter
*pIter
,
2179 int *piCol
, int *piOff
2181 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2183 int rc
= fts5CsrPoslist(pCsr
, iPhrase
, &pIter
->a
, &n
);
2184 if( rc
==SQLITE_OK
){
2185 assert( pIter
->a
|| n
==0 );
2186 pIter
->b
= (pIter
->a
? &pIter
->a
[n
] : 0);
2189 fts5ApiPhraseNext(pCtx
, pIter
, piCol
, piOff
);
2194 static void fts5ApiPhraseNextColumn(
2196 Fts5PhraseIter
*pIter
,
2199 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2200 Fts5Config
*pConfig
= ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
;
2202 if( pConfig
->eDetail
==FTS5_DETAIL_COLUMNS
){
2203 if( pIter
->a
>=pIter
->b
){
2207 pIter
->a
+= fts5GetVarint32(&pIter
->a
[0], iIncr
);
2208 *piCol
+= (iIncr
-2);
2213 if( pIter
->a
>=pIter
->b
){
2217 if( pIter
->a
[0]==0x01 ) break;
2218 pIter
->a
+= fts5GetVarint32(pIter
->a
, dummy
);
2220 pIter
->a
+= 1 + fts5GetVarint32(&pIter
->a
[1], *piCol
);
2224 static int fts5ApiPhraseFirstColumn(
2227 Fts5PhraseIter
*pIter
,
2231 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2232 Fts5Config
*pConfig
= ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
;
2234 if( pConfig
->eDetail
==FTS5_DETAIL_COLUMNS
){
2235 Fts5Sorter
*pSorter
= pCsr
->pSorter
;
2238 int i1
= (iPhrase
==0 ? 0 : pSorter
->aIdx
[iPhrase
-1]);
2239 n
= pSorter
->aIdx
[iPhrase
] - i1
;
2240 pIter
->a
= &pSorter
->aPoslist
[i1
];
2242 rc
= sqlite3Fts5ExprPhraseCollist(pCsr
->pExpr
, iPhrase
, &pIter
->a
, &n
);
2244 if( rc
==SQLITE_OK
){
2245 assert( pIter
->a
|| n
==0 );
2246 pIter
->b
= (pIter
->a
? &pIter
->a
[n
] : 0);
2248 fts5ApiPhraseNextColumn(pCtx
, pIter
, piCol
);
2252 rc
= fts5CsrPoslist(pCsr
, iPhrase
, &pIter
->a
, &n
);
2253 if( rc
==SQLITE_OK
){
2254 assert( pIter
->a
|| n
==0 );
2255 pIter
->b
= (pIter
->a
? &pIter
->a
[n
] : 0);
2258 }else if( pIter
->a
[0]==0x01 ){
2259 pIter
->a
+= 1 + fts5GetVarint32(&pIter
->a
[1], *piCol
);
2270 static int fts5ApiQueryPhrase(Fts5Context
*, int, void*,
2271 int(*)(const Fts5ExtensionApi
*, Fts5Context
*, void*)
2274 static const Fts5ExtensionApi sFts5Api
= {
2279 fts5ApiColumnTotalSize
,
2293 fts5ApiPhraseFirstColumn
,
2294 fts5ApiPhraseNextColumn
,
2298 ** Implementation of API function xQueryPhrase().
2300 static int fts5ApiQueryPhrase(
2304 int(*xCallback
)(const Fts5ExtensionApi
*, Fts5Context
*, void*)
2306 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2307 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
2309 Fts5Cursor
*pNew
= 0;
2311 rc
= fts5OpenMethod(pCsr
->base
.pVtab
, (sqlite3_vtab_cursor
**)&pNew
);
2312 if( rc
==SQLITE_OK
){
2313 pNew
->ePlan
= FTS5_PLAN_MATCH
;
2314 pNew
->iFirstRowid
= SMALLEST_INT64
;
2315 pNew
->iLastRowid
= LARGEST_INT64
;
2316 pNew
->base
.pVtab
= (sqlite3_vtab
*)pTab
;
2317 rc
= sqlite3Fts5ExprClonePhrase(pCsr
->pExpr
, iPhrase
, &pNew
->pExpr
);
2320 if( rc
==SQLITE_OK
){
2321 for(rc
= fts5CursorFirst(pTab
, pNew
, 0);
2322 rc
==SQLITE_OK
&& CsrFlagTest(pNew
, FTS5CSR_EOF
)==0;
2323 rc
= fts5NextMethod((sqlite3_vtab_cursor
*)pNew
)
2325 rc
= xCallback(&sFts5Api
, (Fts5Context
*)pNew
, pUserData
);
2326 if( rc
!=SQLITE_OK
){
2327 if( rc
==SQLITE_DONE
) rc
= SQLITE_OK
;
2333 fts5CloseMethod((sqlite3_vtab_cursor
*)pNew
);
2337 static void fts5ApiInvoke(
2338 Fts5Auxiliary
*pAux
,
2340 sqlite3_context
*context
,
2342 sqlite3_value
**argv
2344 assert( pCsr
->pAux
==0 );
2346 pAux
->xFunc(&sFts5Api
, (Fts5Context
*)pCsr
, context
, argc
, argv
);
2350 static Fts5Cursor
*fts5CursorFromCsrid(Fts5Global
*pGlobal
, i64 iCsrId
){
2352 for(pCsr
=pGlobal
->pCsr
; pCsr
; pCsr
=pCsr
->pNext
){
2353 if( pCsr
->iCsrId
==iCsrId
) break;
2358 static void fts5ApiCallback(
2359 sqlite3_context
*context
,
2361 sqlite3_value
**argv
2364 Fts5Auxiliary
*pAux
;
2369 pAux
= (Fts5Auxiliary
*)sqlite3_user_data(context
);
2370 iCsrId
= sqlite3_value_int64(argv
[0]);
2372 pCsr
= fts5CursorFromCsrid(pAux
->pGlobal
, iCsrId
);
2373 if( pCsr
==0 || pCsr
->ePlan
==0 ){
2374 char *zErr
= sqlite3_mprintf("no such cursor: %lld", iCsrId
);
2375 sqlite3_result_error(context
, zErr
, -1);
2378 fts5ApiInvoke(pAux
, pCsr
, context
, argc
-1, &argv
[1]);
2384 ** Given cursor id iId, return a pointer to the corresponding Fts5Table
2385 ** object. Or NULL If the cursor id does not exist.
2387 Fts5Table
*sqlite3Fts5TableFromCsrid(
2388 Fts5Global
*pGlobal
, /* FTS5 global context for db handle */
2389 i64 iCsrId
/* Id of cursor to find */
2392 pCsr
= fts5CursorFromCsrid(pGlobal
, iCsrId
);
2394 return (Fts5Table
*)pCsr
->base
.pVtab
;
2400 ** Return a "position-list blob" corresponding to the current position of
2401 ** cursor pCsr via sqlite3_result_blob(). A position-list blob contains
2402 ** the current position-list for each phrase in the query associated with
2405 ** A position-list blob begins with (nPhrase-1) varints, where nPhrase is
2406 ** the number of phrases in the query. Following the varints are the
2407 ** concatenated position lists for each phrase, in order.
2409 ** The first varint (if it exists) contains the size of the position list
2410 ** for phrase 0. The second (same disclaimer) contains the size of position
2411 ** list 1. And so on. There is no size field for the final position list,
2412 ** as it can be derived from the total size of the blob.
2414 static int fts5PoslistBlob(sqlite3_context
*pCtx
, Fts5Cursor
*pCsr
){
2417 int nPhrase
= sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
);
2420 memset(&val
, 0, sizeof(Fts5Buffer
));
2421 switch( ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
->eDetail
){
2422 case FTS5_DETAIL_FULL
:
2424 /* Append the varints */
2425 for(i
=0; i
<(nPhrase
-1); i
++){
2427 int nByte
= sqlite3Fts5ExprPoslist(pCsr
->pExpr
, i
, &dummy
);
2428 sqlite3Fts5BufferAppendVarint(&rc
, &val
, nByte
);
2431 /* Append the position lists */
2432 for(i
=0; i
<nPhrase
; i
++){
2435 nPoslist
= sqlite3Fts5ExprPoslist(pCsr
->pExpr
, i
, &pPoslist
);
2436 sqlite3Fts5BufferAppendBlob(&rc
, &val
, nPoslist
, pPoslist
);
2440 case FTS5_DETAIL_COLUMNS
:
2442 /* Append the varints */
2443 for(i
=0; rc
==SQLITE_OK
&& i
<(nPhrase
-1); i
++){
2446 rc
= sqlite3Fts5ExprPhraseCollist(pCsr
->pExpr
, i
, &dummy
, &nByte
);
2447 sqlite3Fts5BufferAppendVarint(&rc
, &val
, nByte
);
2450 /* Append the position lists */
2451 for(i
=0; rc
==SQLITE_OK
&& i
<nPhrase
; i
++){
2454 rc
= sqlite3Fts5ExprPhraseCollist(pCsr
->pExpr
, i
, &pPoslist
, &nPoslist
);
2455 sqlite3Fts5BufferAppendBlob(&rc
, &val
, nPoslist
, pPoslist
);
2463 sqlite3_result_blob(pCtx
, val
.p
, val
.n
, sqlite3_free
);
2468 ** This is the xColumn method, called by SQLite to request a value from
2469 ** the row that the supplied cursor currently points to.
2471 static int fts5ColumnMethod(
2472 sqlite3_vtab_cursor
*pCursor
, /* Cursor to retrieve value from */
2473 sqlite3_context
*pCtx
, /* Context for sqlite3_result_xxx() calls */
2474 int iCol
/* Index of column to read value from */
2476 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCursor
->pVtab
);
2477 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
2478 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
2481 assert( CsrFlagTest(pCsr
, FTS5CSR_EOF
)==0 );
2483 if( pCsr
->ePlan
==FTS5_PLAN_SPECIAL
){
2484 if( iCol
==pConfig
->nCol
){
2485 sqlite3_result_int64(pCtx
, pCsr
->iSpecial
);
2489 if( iCol
==pConfig
->nCol
){
2490 /* User is requesting the value of the special column with the same name
2491 ** as the table. Return the cursor integer id number. This value is only
2492 ** useful in that it may be passed as the first argument to an FTS5
2493 ** auxiliary function. */
2494 sqlite3_result_int64(pCtx
, pCsr
->iCsrId
);
2495 }else if( iCol
==pConfig
->nCol
+1 ){
2497 /* The value of the "rank" column. */
2498 if( pCsr
->ePlan
==FTS5_PLAN_SOURCE
){
2499 fts5PoslistBlob(pCtx
, pCsr
);
2501 pCsr
->ePlan
==FTS5_PLAN_MATCH
2502 || pCsr
->ePlan
==FTS5_PLAN_SORTED_MATCH
2504 if( pCsr
->pRank
|| SQLITE_OK
==(rc
= fts5FindRankFunction(pCsr
)) ){
2505 fts5ApiInvoke(pCsr
->pRank
, pCsr
, pCtx
, pCsr
->nRankArg
, pCsr
->apRankArg
);
2508 }else if( !fts5IsContentless(pTab
) ){
2509 pConfig
->pzErrmsg
= &pTab
->p
.base
.zErrMsg
;
2510 rc
= fts5SeekCursor(pCsr
, 1);
2511 if( rc
==SQLITE_OK
){
2512 sqlite3_result_value(pCtx
, sqlite3_column_value(pCsr
->pStmt
, iCol
+1));
2514 pConfig
->pzErrmsg
= 0;
2521 ** This routine implements the xFindFunction method for the FTS3
2524 static int fts5FindFunctionMethod(
2525 sqlite3_vtab
*pVtab
, /* Virtual table handle */
2526 int nUnused
, /* Number of SQL function arguments */
2527 const char *zName
, /* Name of SQL function */
2528 void (**pxFunc
)(sqlite3_context
*,int,sqlite3_value
**), /* OUT: Result */
2529 void **ppArg
/* OUT: User data for *pxFunc */
2531 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
2532 Fts5Auxiliary
*pAux
;
2534 UNUSED_PARAM(nUnused
);
2535 pAux
= fts5FindAuxiliary(pTab
, zName
);
2537 *pxFunc
= fts5ApiCallback
;
2538 *ppArg
= (void*)pAux
;
2542 /* No function of the specified name was found. Return 0. */
2547 ** Implementation of FTS5 xRename method. Rename an fts5 table.
2549 static int fts5RenameMethod(
2550 sqlite3_vtab
*pVtab
, /* Virtual table handle */
2551 const char *zName
/* New name of table */
2553 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
2554 return sqlite3Fts5StorageRename(pTab
->pStorage
, zName
);
2557 int sqlite3Fts5FlushToDisk(Fts5Table
*pTab
){
2558 fts5TripCursors((Fts5FullTable
*)pTab
);
2559 return sqlite3Fts5StorageSync(((Fts5FullTable
*)pTab
)->pStorage
);
2563 ** The xSavepoint() method.
2565 ** Flush the contents of the pending-terms table to disk.
2567 static int fts5SavepointMethod(sqlite3_vtab
*pVtab
, int iSavepoint
){
2568 UNUSED_PARAM(iSavepoint
); /* Call below is a no-op for NDEBUG builds */
2569 fts5CheckTransactionState((Fts5FullTable
*)pVtab
, FTS5_SAVEPOINT
, iSavepoint
);
2570 return sqlite3Fts5FlushToDisk((Fts5Table
*)pVtab
);
2574 ** The xRelease() method.
2578 static int fts5ReleaseMethod(sqlite3_vtab
*pVtab
, int iSavepoint
){
2579 UNUSED_PARAM(iSavepoint
); /* Call below is a no-op for NDEBUG builds */
2580 fts5CheckTransactionState((Fts5FullTable
*)pVtab
, FTS5_RELEASE
, iSavepoint
);
2581 return sqlite3Fts5FlushToDisk((Fts5Table
*)pVtab
);
2585 ** The xRollbackTo() method.
2587 ** Discard the contents of the pending terms table.
2589 static int fts5RollbackToMethod(sqlite3_vtab
*pVtab
, int iSavepoint
){
2590 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
2591 UNUSED_PARAM(iSavepoint
); /* Call below is a no-op for NDEBUG builds */
2592 fts5CheckTransactionState(pTab
, FTS5_ROLLBACKTO
, iSavepoint
);
2593 fts5TripCursors(pTab
);
2594 return sqlite3Fts5StorageRollback(pTab
->pStorage
);
2598 ** Register a new auxiliary function with global context pGlobal.
2600 static int fts5CreateAux(
2601 fts5_api
*pApi
, /* Global context (one per db handle) */
2602 const char *zName
, /* Name of new function */
2603 void *pUserData
, /* User data for aux. function */
2604 fts5_extension_function xFunc
, /* Aux. function implementation */
2605 void(*xDestroy
)(void*) /* Destructor for pUserData */
2607 Fts5Global
*pGlobal
= (Fts5Global
*)pApi
;
2608 int rc
= sqlite3_overload_function(pGlobal
->db
, zName
, -1);
2609 if( rc
==SQLITE_OK
){
2610 Fts5Auxiliary
*pAux
;
2611 sqlite3_int64 nName
; /* Size of zName in bytes, including \0 */
2612 sqlite3_int64 nByte
; /* Bytes of space to allocate */
2614 nName
= strlen(zName
) + 1;
2615 nByte
= sizeof(Fts5Auxiliary
) + nName
;
2616 pAux
= (Fts5Auxiliary
*)sqlite3_malloc64(nByte
);
2618 memset(pAux
, 0, (size_t)nByte
);
2619 pAux
->zFunc
= (char*)&pAux
[1];
2620 memcpy(pAux
->zFunc
, zName
, nName
);
2621 pAux
->pGlobal
= pGlobal
;
2622 pAux
->pUserData
= pUserData
;
2623 pAux
->xFunc
= xFunc
;
2624 pAux
->xDestroy
= xDestroy
;
2625 pAux
->pNext
= pGlobal
->pAux
;
2626 pGlobal
->pAux
= pAux
;
2636 ** Register a new tokenizer. This is the implementation of the
2637 ** fts5_api.xCreateTokenizer() method.
2639 static int fts5CreateTokenizer(
2640 fts5_api
*pApi
, /* Global context (one per db handle) */
2641 const char *zName
, /* Name of new function */
2642 void *pUserData
, /* User data for aux. function */
2643 fts5_tokenizer
*pTokenizer
, /* Tokenizer implementation */
2644 void(*xDestroy
)(void*) /* Destructor for pUserData */
2646 Fts5Global
*pGlobal
= (Fts5Global
*)pApi
;
2647 Fts5TokenizerModule
*pNew
;
2648 sqlite3_int64 nName
; /* Size of zName and its \0 terminator */
2649 sqlite3_int64 nByte
; /* Bytes of space to allocate */
2652 nName
= strlen(zName
) + 1;
2653 nByte
= sizeof(Fts5TokenizerModule
) + nName
;
2654 pNew
= (Fts5TokenizerModule
*)sqlite3_malloc64(nByte
);
2656 memset(pNew
, 0, (size_t)nByte
);
2657 pNew
->zName
= (char*)&pNew
[1];
2658 memcpy(pNew
->zName
, zName
, nName
);
2659 pNew
->pUserData
= pUserData
;
2660 pNew
->x
= *pTokenizer
;
2661 pNew
->xDestroy
= xDestroy
;
2662 pNew
->pNext
= pGlobal
->pTok
;
2663 pGlobal
->pTok
= pNew
;
2664 if( pNew
->pNext
==0 ){
2665 pGlobal
->pDfltTok
= pNew
;
2674 static Fts5TokenizerModule
*fts5LocateTokenizer(
2675 Fts5Global
*pGlobal
,
2678 Fts5TokenizerModule
*pMod
= 0;
2681 pMod
= pGlobal
->pDfltTok
;
2683 for(pMod
=pGlobal
->pTok
; pMod
; pMod
=pMod
->pNext
){
2684 if( sqlite3_stricmp(zName
, pMod
->zName
)==0 ) break;
2692 ** Find a tokenizer. This is the implementation of the
2693 ** fts5_api.xFindTokenizer() method.
2695 static int fts5FindTokenizer(
2696 fts5_api
*pApi
, /* Global context (one per db handle) */
2697 const char *zName
, /* Name of new function */
2699 fts5_tokenizer
*pTokenizer
/* Populate this object */
2702 Fts5TokenizerModule
*pMod
;
2704 pMod
= fts5LocateTokenizer((Fts5Global
*)pApi
, zName
);
2706 *pTokenizer
= pMod
->x
;
2707 *ppUserData
= pMod
->pUserData
;
2709 memset(pTokenizer
, 0, sizeof(fts5_tokenizer
));
2716 int sqlite3Fts5GetTokenizer(
2717 Fts5Global
*pGlobal
,
2720 Fts5Config
*pConfig
,
2723 Fts5TokenizerModule
*pMod
;
2726 pMod
= fts5LocateTokenizer(pGlobal
, nArg
==0 ? 0 : azArg
[0]);
2730 *pzErr
= sqlite3_mprintf("no such tokenizer: %s", azArg
[0]);
2732 rc
= pMod
->x
.xCreate(
2733 pMod
->pUserData
, (azArg
?&azArg
[1]:0), (nArg
?nArg
-1:0), &pConfig
->pTok
2735 pConfig
->pTokApi
= &pMod
->x
;
2736 if( rc
!=SQLITE_OK
){
2737 if( pzErr
) *pzErr
= sqlite3_mprintf("error in tokenizer constructor");
2739 pConfig
->ePattern
= sqlite3Fts5TokenizerPattern(
2740 pMod
->x
.xCreate
, pConfig
->pTok
2745 if( rc
!=SQLITE_OK
){
2746 pConfig
->pTokApi
= 0;
2753 static void fts5ModuleDestroy(void *pCtx
){
2754 Fts5TokenizerModule
*pTok
, *pNextTok
;
2755 Fts5Auxiliary
*pAux
, *pNextAux
;
2756 Fts5Global
*pGlobal
= (Fts5Global
*)pCtx
;
2758 for(pAux
=pGlobal
->pAux
; pAux
; pAux
=pNextAux
){
2759 pNextAux
= pAux
->pNext
;
2760 if( pAux
->xDestroy
) pAux
->xDestroy(pAux
->pUserData
);
2764 for(pTok
=pGlobal
->pTok
; pTok
; pTok
=pNextTok
){
2765 pNextTok
= pTok
->pNext
;
2766 if( pTok
->xDestroy
) pTok
->xDestroy(pTok
->pUserData
);
2770 sqlite3_free(pGlobal
);
2773 static void fts5Fts5Func(
2774 sqlite3_context
*pCtx
, /* Function call context */
2775 int nArg
, /* Number of args */
2776 sqlite3_value
**apArg
/* Function arguments */
2778 Fts5Global
*pGlobal
= (Fts5Global
*)sqlite3_user_data(pCtx
);
2782 ppApi
= (fts5_api
**)sqlite3_value_pointer(apArg
[0], "fts5_api_ptr");
2783 if( ppApi
) *ppApi
= &pGlobal
->api
;
2787 ** Implementation of fts5_source_id() function.
2789 static void fts5SourceIdFunc(
2790 sqlite3_context
*pCtx
, /* Function call context */
2791 int nArg
, /* Number of args */
2792 sqlite3_value
**apUnused
/* Function arguments */
2795 UNUSED_PARAM2(nArg
, apUnused
);
2796 sqlite3_result_text(pCtx
, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT
);
2800 ** Return true if zName is the extension on one of the shadow tables used
2803 static int fts5ShadowName(const char *zName
){
2804 static const char *azName
[] = {
2805 "config", "content", "data", "docsize", "idx"
2808 for(i
=0; i
<sizeof(azName
)/sizeof(azName
[0]); i
++){
2809 if( sqlite3_stricmp(zName
, azName
[i
])==0 ) return 1;
2814 static int fts5Init(sqlite3
*db
){
2815 static const sqlite3_module fts5Mod
= {
2817 /* xCreate */ fts5CreateMethod
,
2818 /* xConnect */ fts5ConnectMethod
,
2819 /* xBestIndex */ fts5BestIndexMethod
,
2820 /* xDisconnect */ fts5DisconnectMethod
,
2821 /* xDestroy */ fts5DestroyMethod
,
2822 /* xOpen */ fts5OpenMethod
,
2823 /* xClose */ fts5CloseMethod
,
2824 /* xFilter */ fts5FilterMethod
,
2825 /* xNext */ fts5NextMethod
,
2826 /* xEof */ fts5EofMethod
,
2827 /* xColumn */ fts5ColumnMethod
,
2828 /* xRowid */ fts5RowidMethod
,
2829 /* xUpdate */ fts5UpdateMethod
,
2830 /* xBegin */ fts5BeginMethod
,
2831 /* xSync */ fts5SyncMethod
,
2832 /* xCommit */ fts5CommitMethod
,
2833 /* xRollback */ fts5RollbackMethod
,
2834 /* xFindFunction */ fts5FindFunctionMethod
,
2835 /* xRename */ fts5RenameMethod
,
2836 /* xSavepoint */ fts5SavepointMethod
,
2837 /* xRelease */ fts5ReleaseMethod
,
2838 /* xRollbackTo */ fts5RollbackToMethod
,
2839 /* xShadowName */ fts5ShadowName
2843 Fts5Global
*pGlobal
= 0;
2845 pGlobal
= (Fts5Global
*)sqlite3_malloc(sizeof(Fts5Global
));
2849 void *p
= (void*)pGlobal
;
2850 memset(pGlobal
, 0, sizeof(Fts5Global
));
2852 pGlobal
->api
.iVersion
= 2;
2853 pGlobal
->api
.xCreateFunction
= fts5CreateAux
;
2854 pGlobal
->api
.xCreateTokenizer
= fts5CreateTokenizer
;
2855 pGlobal
->api
.xFindTokenizer
= fts5FindTokenizer
;
2856 rc
= sqlite3_create_module_v2(db
, "fts5", &fts5Mod
, p
, fts5ModuleDestroy
);
2857 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5IndexInit(db
);
2858 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5ExprInit(pGlobal
, db
);
2859 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5AuxInit(&pGlobal
->api
);
2860 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5TokenizerInit(&pGlobal
->api
);
2861 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5VocabInit(pGlobal
, db
);
2862 if( rc
==SQLITE_OK
){
2863 rc
= sqlite3_create_function(
2864 db
, "fts5", 1, SQLITE_UTF8
, p
, fts5Fts5Func
, 0, 0
2867 if( rc
==SQLITE_OK
){
2868 rc
= sqlite3_create_function(
2869 db
, "fts5_source_id", 0, SQLITE_UTF8
, p
, fts5SourceIdFunc
, 0, 0
2874 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
2875 ** fts5_test_mi.c is compiled and linked into the executable. And call
2876 ** its entry point to enable the matchinfo() demo. */
2877 #ifdef SQLITE_FTS5_ENABLE_TEST_MI
2878 if( rc
==SQLITE_OK
){
2879 extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3
*);
2880 rc
= sqlite3Fts5TestRegisterMatchinfo(db
);
2888 ** The following functions are used to register the module with SQLite. If
2889 ** this module is being built as part of the SQLite core (SQLITE_CORE is
2890 ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
2892 ** Or, if this module is being built as a loadable extension,
2893 ** sqlite3Fts5Init() is omitted and the two standard entry points
2894 ** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
2898 __declspec(dllexport
)
2900 int sqlite3_fts_init(
2903 const sqlite3_api_routines
*pApi
2905 SQLITE_EXTENSION_INIT2(pApi
);
2906 (void)pzErrMsg
; /* Unused parameter */
2907 return fts5Init(db
);
2911 __declspec(dllexport
)
2913 int sqlite3_fts5_init(
2916 const sqlite3_api_routines
*pApi
2918 SQLITE_EXTENSION_INIT2(pApi
);
2919 (void)pzErrMsg
; /* Unused parameter */
2920 return fts5Init(db
);
2923 int sqlite3Fts5Init(sqlite3
*db
){
2924 return fts5Init(db
);