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 */
120 int iSavepoint
; /* Successful xSavepoint()+1 */
123 struct Fts5TransactionState ts
;
127 struct Fts5MatchPhrase
{
128 Fts5Buffer
*pPoslist
; /* Pointer to current poslist */
129 int nTerm
; /* Size of phrase in terms */
134 ** SELECT rowid, <fts> FROM <fts> ORDER BY +rank;
137 ** There is one entry in the aIdx[] array for each phrase in the query,
138 ** the value of which is the offset within aPoslist[] following the last
139 ** byte of the position list for the corresponding phrase.
143 i64 iRowid
; /* Current rowid */
144 const u8
*aPoslist
; /* Position lists for current row */
145 int nIdx
; /* Number of entries in aIdx[] */
146 int aIdx
[1]; /* Offsets into aPoslist for current row */
151 ** Virtual-table cursor object.
154 ** If this is a 'special' query (refer to function fts5SpecialMatch()),
155 ** then this variable contains the result of the query.
157 ** iFirstRowid, iLastRowid:
158 ** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
159 ** cursor iterates in ascending order of rowids, iFirstRowid is the lower
160 ** limit of rowids to return, and iLastRowid the upper. In other words, the
161 ** WHERE clause in the user's query might have been:
163 ** <tbl> MATCH <expr> AND rowid BETWEEN $iFirstRowid AND $iLastRowid
165 ** If the cursor iterates in descending order of rowid, iFirstRowid
166 ** is the upper limit (i.e. the "first" rowid visited) and iLastRowid
170 sqlite3_vtab_cursor base
; /* Base class used by SQLite core */
171 Fts5Cursor
*pNext
; /* Next cursor in Fts5Cursor.pCsr list */
172 int *aColumnSize
; /* Values for xColumnSize() */
173 i64 iCsrId
; /* Cursor id */
175 /* Zero from this point onwards on cursor reset */
176 int ePlan
; /* FTS5_PLAN_XXX value */
177 int bDesc
; /* True for "ORDER BY rowid DESC" queries */
178 i64 iFirstRowid
; /* Return no rowids earlier than this */
179 i64 iLastRowid
; /* Return no rowids later than this */
180 sqlite3_stmt
*pStmt
; /* Statement used to read %_content */
181 Fts5Expr
*pExpr
; /* Expression for MATCH queries */
182 Fts5Sorter
*pSorter
; /* Sorter for "ORDER BY rank" queries */
183 int csrflags
; /* Mask of cursor flags (see below) */
184 i64 iSpecial
; /* Result of special query */
186 /* "rank" function. Populated on demand from vtab.xColumn(). */
187 char *zRank
; /* Custom rank function */
188 char *zRankArgs
; /* Custom rank function args */
189 Fts5Auxiliary
*pRank
; /* Rank callback (or NULL) */
190 int nRankArg
; /* Number of trailing arguments for rank() */
191 sqlite3_value
**apRankArg
; /* Array of trailing arguments */
192 sqlite3_stmt
*pRankArgStmt
; /* Origin of objects in apRankArg[] */
194 /* Auxiliary data storage */
195 Fts5Auxiliary
*pAux
; /* Currently executing extension function */
196 Fts5Auxdata
*pAuxdata
; /* First in linked list of saved aux-data */
198 /* Cache used by auxiliary functions xInst() and xInstCount() */
199 Fts5PoslistReader
*aInstIter
; /* One for each phrase */
200 int nInstAlloc
; /* Size of aInst[] array (entries / 3) */
201 int nInstCount
; /* Number of phrase instances */
202 int *aInst
; /* 3 integers per phrase instance */
206 ** Bits that make up the "idxNum" parameter passed indirectly by
207 ** xBestIndex() to xFilter().
209 #define FTS5_BI_MATCH 0x0001 /* <tbl> MATCH ? */
210 #define FTS5_BI_RANK 0x0002 /* rank MATCH ? */
211 #define FTS5_BI_ROWID_EQ 0x0004 /* rowid == ? */
212 #define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */
213 #define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */
215 #define FTS5_BI_ORDER_RANK 0x0020
216 #define FTS5_BI_ORDER_ROWID 0x0040
217 #define FTS5_BI_ORDER_DESC 0x0080
220 ** Values for Fts5Cursor.csrflags
222 #define FTS5CSR_EOF 0x01
223 #define FTS5CSR_REQUIRE_CONTENT 0x02
224 #define FTS5CSR_REQUIRE_DOCSIZE 0x04
225 #define FTS5CSR_REQUIRE_INST 0x08
226 #define FTS5CSR_FREE_ZRANK 0x10
227 #define FTS5CSR_REQUIRE_RESEEK 0x20
228 #define FTS5CSR_REQUIRE_POSLIST 0x40
230 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
231 #define BitFlagTest(x,y) (((x) & (y))!=0)
235 ** Macros to Set(), Clear() and Test() cursor flags.
237 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
238 #define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag))
239 #define CsrFlagTest(pCsr, flag) ((pCsr)->csrflags & (flag))
242 Fts5Auxiliary
*pAux
; /* Extension to which this belongs */
243 void *pPtr
; /* Pointer value */
244 void(*xDelete
)(void*); /* Destructor */
245 Fts5Auxdata
*pNext
; /* Next object in linked list */
251 #define FTS5_COMMIT 3
252 #define FTS5_ROLLBACK 4
253 #define FTS5_SAVEPOINT 5
254 #define FTS5_RELEASE 6
255 #define FTS5_ROLLBACKTO 7
256 static void fts5CheckTransactionState(Fts5FullTable
*p
, int op
, int iSavepoint
){
259 assert( p
->ts
.eState
==0 );
261 p
->ts
.iSavepoint
= -1;
265 assert( p
->ts
.eState
==1 || p
->ts
.eState
==2 );
270 assert( p
->ts
.eState
==2 );
275 assert( p
->ts
.eState
==1 || p
->ts
.eState
==2 || p
->ts
.eState
==0 );
280 assert( p
->ts
.eState
>=1 );
281 assert( iSavepoint
>=0 );
282 assert( iSavepoint
>=p
->ts
.iSavepoint
);
283 p
->ts
.iSavepoint
= iSavepoint
;
287 assert( p
->ts
.eState
>=1 );
288 assert( iSavepoint
>=0 );
289 assert( iSavepoint
<=p
->ts
.iSavepoint
);
290 p
->ts
.iSavepoint
= iSavepoint
-1;
293 case FTS5_ROLLBACKTO
:
294 assert( p
->ts
.eState
>=1 );
295 assert( iSavepoint
>=-1 );
296 /* The following assert() can fail if another vtab strikes an error
297 ** within an xSavepoint() call then SQLite calls xRollbackTo() - without
298 ** having called xSavepoint() on this vtab. */
299 /* assert( iSavepoint<=p->ts.iSavepoint ); */
300 p
->ts
.iSavepoint
= iSavepoint
;
305 # define fts5CheckTransactionState(x,y,z)
309 ** Return true if pTab is a contentless table.
311 static int fts5IsContentless(Fts5FullTable
*pTab
){
312 return pTab
->p
.pConfig
->eContent
==FTS5_CONTENT_NONE
;
316 ** Delete a virtual table handle allocated by fts5InitVtab().
318 static void fts5FreeVtab(Fts5FullTable
*pTab
){
320 sqlite3Fts5IndexClose(pTab
->p
.pIndex
);
321 sqlite3Fts5StorageClose(pTab
->pStorage
);
322 sqlite3Fts5ConfigFree(pTab
->p
.pConfig
);
328 ** The xDisconnect() virtual table method.
330 static int fts5DisconnectMethod(sqlite3_vtab
*pVtab
){
331 fts5FreeVtab((Fts5FullTable
*)pVtab
);
336 ** The xDestroy() virtual table method.
338 static int fts5DestroyMethod(sqlite3_vtab
*pVtab
){
339 Fts5Table
*pTab
= (Fts5Table
*)pVtab
;
340 int rc
= sqlite3Fts5DropAll(pTab
->pConfig
);
342 fts5FreeVtab((Fts5FullTable
*)pVtab
);
348 ** This function is the implementation of both the xConnect and xCreate
349 ** methods of the FTS3 virtual table.
351 ** The argv[] array contains the following:
353 ** argv[0] -> module name ("fts5")
354 ** argv[1] -> database name
355 ** argv[2] -> table name
356 ** argv[...] -> "column name" and other module argument fields.
358 static int fts5InitVtab(
359 int bCreate
, /* True for xCreate, false for xConnect */
360 sqlite3
*db
, /* The SQLite database connection */
361 void *pAux
, /* Hash table containing tokenizers */
362 int argc
, /* Number of elements in argv array */
363 const char * const *argv
, /* xCreate/xConnect argument array */
364 sqlite3_vtab
**ppVTab
, /* Write the resulting vtab structure here */
365 char **pzErr
/* Write any error message here */
367 Fts5Global
*pGlobal
= (Fts5Global
*)pAux
;
368 const char **azConfig
= (const char**)argv
;
369 int rc
= SQLITE_OK
; /* Return code */
370 Fts5Config
*pConfig
= 0; /* Results of parsing argc/argv */
371 Fts5FullTable
*pTab
= 0; /* New virtual table object */
373 /* Allocate the new vtab object and parse the configuration */
374 pTab
= (Fts5FullTable
*)sqlite3Fts5MallocZero(&rc
, sizeof(Fts5FullTable
));
376 rc
= sqlite3Fts5ConfigParse(pGlobal
, db
, argc
, azConfig
, &pConfig
, pzErr
);
377 assert( (rc
==SQLITE_OK
&& *pzErr
==0) || pConfig
==0 );
380 pTab
->p
.pConfig
= pConfig
;
381 pTab
->pGlobal
= pGlobal
;
384 /* Open the index sub-system */
386 rc
= sqlite3Fts5IndexOpen(pConfig
, bCreate
, &pTab
->p
.pIndex
, pzErr
);
389 /* Open the storage sub-system */
391 rc
= sqlite3Fts5StorageOpen(
392 pConfig
, pTab
->p
.pIndex
, bCreate
, &pTab
->pStorage
, pzErr
396 /* Call sqlite3_declare_vtab() */
398 rc
= sqlite3Fts5ConfigDeclareVtab(pConfig
);
401 /* Load the initial configuration */
403 assert( pConfig
->pzErrmsg
==0 );
404 pConfig
->pzErrmsg
= pzErr
;
405 rc
= sqlite3Fts5IndexLoadConfig(pTab
->p
.pIndex
);
406 sqlite3Fts5IndexRollback(pTab
->p
.pIndex
);
407 pConfig
->pzErrmsg
= 0;
410 if( rc
==SQLITE_OK
&& pConfig
->eContent
==FTS5_CONTENT_NORMAL
){
411 rc
= sqlite3_vtab_config(db
, SQLITE_VTAB_CONSTRAINT_SUPPORT
, (int)1);
414 rc
= sqlite3_vtab_config(db
, SQLITE_VTAB_INNOCUOUS
);
421 fts5CheckTransactionState(pTab
, FTS5_BEGIN
, 0);
423 *ppVTab
= (sqlite3_vtab
*)pTab
;
428 ** The xConnect() and xCreate() methods for the virtual table. All the
429 ** work is done in function fts5InitVtab().
431 static int fts5ConnectMethod(
432 sqlite3
*db
, /* Database connection */
433 void *pAux
, /* Pointer to tokenizer hash table */
434 int argc
, /* Number of elements in argv array */
435 const char * const *argv
, /* xCreate/xConnect argument array */
436 sqlite3_vtab
**ppVtab
, /* OUT: New sqlite3_vtab object */
437 char **pzErr
/* OUT: sqlite3_malloc'd error message */
439 return fts5InitVtab(0, db
, pAux
, argc
, argv
, ppVtab
, pzErr
);
441 static int fts5CreateMethod(
442 sqlite3
*db
, /* Database connection */
443 void *pAux
, /* Pointer to tokenizer hash table */
444 int argc
, /* Number of elements in argv array */
445 const char * const *argv
, /* xCreate/xConnect argument array */
446 sqlite3_vtab
**ppVtab
, /* OUT: New sqlite3_vtab object */
447 char **pzErr
/* OUT: sqlite3_malloc'd error message */
449 return fts5InitVtab(1, db
, pAux
, argc
, argv
, ppVtab
, pzErr
);
453 ** The different query plans.
455 #define FTS5_PLAN_MATCH 1 /* (<tbl> MATCH ?) */
456 #define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */
457 #define FTS5_PLAN_SPECIAL 3 /* An internal query */
458 #define FTS5_PLAN_SORTED_MATCH 4 /* (<tbl> MATCH ? ORDER BY rank) */
459 #define FTS5_PLAN_SCAN 5 /* No usable constraint */
460 #define FTS5_PLAN_ROWID 6 /* (rowid = ?) */
463 ** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
464 ** extension is currently being used by a version of SQLite too old to
465 ** support index-info flags. In that case this function is a no-op.
467 static void fts5SetUniqueFlag(sqlite3_index_info
*pIdxInfo
){
468 #if SQLITE_VERSION_NUMBER>=3008012
470 if( sqlite3_libversion_number()>=3008012 )
473 pIdxInfo
->idxFlags
|= SQLITE_INDEX_SCAN_UNIQUE
;
478 static int fts5UsePatternMatch(
480 struct sqlite3_index_constraint
*p
482 assert( FTS5_PATTERN_GLOB
==SQLITE_INDEX_CONSTRAINT_GLOB
);
483 assert( FTS5_PATTERN_LIKE
==SQLITE_INDEX_CONSTRAINT_LIKE
);
484 if( pConfig
->ePattern
==FTS5_PATTERN_GLOB
&& p
->op
==FTS5_PATTERN_GLOB
){
487 if( pConfig
->ePattern
==FTS5_PATTERN_LIKE
488 && (p
->op
==FTS5_PATTERN_LIKE
|| p
->op
==FTS5_PATTERN_GLOB
)
496 ** Implementation of the xBestIndex method for FTS5 tables. Within the
497 ** WHERE constraint, it searches for the following:
499 ** 1. A MATCH constraint against the table column.
500 ** 2. A MATCH constraint against the "rank" column.
501 ** 3. A MATCH constraint against some other column.
502 ** 4. An == constraint against the rowid column.
503 ** 5. A < or <= constraint against the rowid column.
504 ** 6. A > or >= constraint against the rowid column.
506 ** Within the ORDER BY, the following are supported:
508 ** 5. ORDER BY rank [ASC|DESC]
509 ** 6. ORDER BY rowid [ASC|DESC]
511 ** Information for the xFilter call is passed via both the idxNum and
512 ** idxStr variables. Specifically, idxNum is a bitmask of the following
513 ** flags used to encode the ORDER BY clause:
515 ** FTS5_BI_ORDER_RANK
516 ** FTS5_BI_ORDER_ROWID
517 ** FTS5_BI_ORDER_DESC
519 ** idxStr is used to encode data from the WHERE clause. For each argument
520 ** passed to the xFilter method, the following is appended to idxStr:
522 ** Match against table column: "m"
523 ** Match against rank column: "r"
524 ** Match against other column: "M<column-number>"
525 ** LIKE against other column: "L<column-number>"
526 ** GLOB against other column: "G<column-number>"
527 ** Equality constraint against the rowid: "="
528 ** A < or <= against the rowid: "<"
529 ** A > or >= against the rowid: ">"
531 ** This function ensures that there is at most one "r" or "=". And that if
532 ** there exists an "=" then there is no "<" or ">".
534 ** Costs are assigned as follows:
536 ** a) If an unusable MATCH operator is present in the WHERE clause, the
537 ** cost is unconditionally set to 1e50 (a really big number).
539 ** a) If a MATCH operator is present, the cost depends on the other
540 ** constraints also present. As follows:
542 ** * No other constraints: cost=1000.0
543 ** * One rowid range constraint: cost=750.0
544 ** * Both rowid range constraints: cost=500.0
545 ** * An == rowid constraint: cost=100.0
547 ** b) Otherwise, if there is no MATCH:
549 ** * No other constraints: cost=1000000.0
550 ** * One rowid range constraint: cost=750000.0
551 ** * Both rowid range constraints: cost=250000.0
552 ** * An == rowid constraint: cost=10.0
554 ** Costs are not modified by the ORDER BY clause.
556 static int fts5BestIndexMethod(sqlite3_vtab
*pVTab
, sqlite3_index_info
*pInfo
){
557 Fts5Table
*pTab
= (Fts5Table
*)pVTab
;
558 Fts5Config
*pConfig
= pTab
->pConfig
;
559 const int nCol
= pConfig
->nCol
;
560 int idxFlags
= 0; /* Parameter passed through to xFilter() */
574 assert( SQLITE_INDEX_CONSTRAINT_EQ
<SQLITE_INDEX_CONSTRAINT_MATCH
);
575 assert( SQLITE_INDEX_CONSTRAINT_GT
<SQLITE_INDEX_CONSTRAINT_MATCH
);
576 assert( SQLITE_INDEX_CONSTRAINT_LE
<SQLITE_INDEX_CONSTRAINT_MATCH
);
577 assert( SQLITE_INDEX_CONSTRAINT_GE
<SQLITE_INDEX_CONSTRAINT_MATCH
);
578 assert( SQLITE_INDEX_CONSTRAINT_LE
<SQLITE_INDEX_CONSTRAINT_MATCH
);
580 if( pConfig
->bLock
){
581 pTab
->base
.zErrMsg
= sqlite3_mprintf(
582 "recursively defined fts5 content table"
587 idxStr
= (char*)sqlite3_malloc(pInfo
->nConstraint
* 8 + 1);
588 if( idxStr
==0 ) return SQLITE_NOMEM
;
589 pInfo
->idxStr
= idxStr
;
590 pInfo
->needToFreeIdxStr
= 1;
592 for(i
=0; i
<pInfo
->nConstraint
; i
++){
593 struct sqlite3_index_constraint
*p
= &pInfo
->aConstraint
[i
];
594 int iCol
= p
->iColumn
;
595 if( p
->op
==SQLITE_INDEX_CONSTRAINT_MATCH
596 || (p
->op
==SQLITE_INDEX_CONSTRAINT_EQ
&& iCol
>=nCol
)
598 /* A MATCH operator or equivalent */
599 if( p
->usable
==0 || iCol
<0 ){
600 /* As there exists an unusable MATCH constraint this is an
601 ** unusable plan. Set a prohibitively high cost. */
602 pInfo
->estimatedCost
= 1e50
;
603 assert( iIdxStr
< pInfo
->nConstraint
*6 + 1 );
608 if( bSeenRank
) continue;
609 idxStr
[iIdxStr
++] = 'r';
613 idxStr
[iIdxStr
++] = 'M';
614 sqlite3_snprintf(6, &idxStr
[iIdxStr
], "%d", iCol
);
615 idxStr
+= strlen(&idxStr
[iIdxStr
]);
616 assert( idxStr
[iIdxStr
]=='\0' );
618 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
619 pInfo
->aConstraintUsage
[i
].omit
= 1;
621 }else if( p
->usable
){
622 if( iCol
>=0 && iCol
<nCol
&& fts5UsePatternMatch(pConfig
, p
) ){
623 assert( p
->op
==FTS5_PATTERN_LIKE
|| p
->op
==FTS5_PATTERN_GLOB
);
624 idxStr
[iIdxStr
++] = p
->op
==FTS5_PATTERN_LIKE
? 'L' : 'G';
625 sqlite3_snprintf(6, &idxStr
[iIdxStr
], "%d", iCol
);
626 idxStr
+= strlen(&idxStr
[iIdxStr
]);
627 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
628 assert( idxStr
[iIdxStr
]=='\0' );
629 }else if( bSeenEq
==0 && p
->op
==SQLITE_INDEX_CONSTRAINT_EQ
&& iCol
<0 ){
630 idxStr
[iIdxStr
++] = '=';
632 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
638 for(i
=0; i
<pInfo
->nConstraint
; i
++){
639 struct sqlite3_index_constraint
*p
= &pInfo
->aConstraint
[i
];
640 if( p
->iColumn
<0 && p
->usable
){
642 if( op
==SQLITE_INDEX_CONSTRAINT_LT
|| op
==SQLITE_INDEX_CONSTRAINT_LE
){
643 if( bSeenLt
) continue;
644 idxStr
[iIdxStr
++] = '<';
645 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
648 if( op
==SQLITE_INDEX_CONSTRAINT_GT
|| op
==SQLITE_INDEX_CONSTRAINT_GE
){
649 if( bSeenGt
) continue;
650 idxStr
[iIdxStr
++] = '>';
651 pInfo
->aConstraintUsage
[i
].argvIndex
= ++iCons
;
657 idxStr
[iIdxStr
] = '\0';
659 /* Set idxFlags flags for the ORDER BY clause
661 ** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC".
663 if( pInfo
->nOrderBy
==1 ){
664 int iSort
= pInfo
->aOrderBy
[0].iColumn
;
665 if( iSort
==(pConfig
->nCol
+1) && bSeenMatch
){
666 idxFlags
|= FTS5_BI_ORDER_RANK
;
667 }else if( iSort
==-1 && (!pInfo
->aOrderBy
[0].desc
|| !pConfig
->bTokendata
) ){
668 idxFlags
|= FTS5_BI_ORDER_ROWID
;
670 if( BitFlagTest(idxFlags
, FTS5_BI_ORDER_RANK
|FTS5_BI_ORDER_ROWID
) ){
671 pInfo
->orderByConsumed
= 1;
672 if( pInfo
->aOrderBy
[0].desc
){
673 idxFlags
|= FTS5_BI_ORDER_DESC
;
678 /* Calculate the estimated cost based on the flags set in idxFlags. */
680 pInfo
->estimatedCost
= bSeenMatch
? 100.0 : 10.0;
681 if( bSeenMatch
==0 ) fts5SetUniqueFlag(pInfo
);
682 }else if( bSeenLt
&& bSeenGt
){
683 pInfo
->estimatedCost
= bSeenMatch
? 500.0 : 250000.0;
684 }else if( bSeenLt
|| bSeenGt
){
685 pInfo
->estimatedCost
= bSeenMatch
? 750.0 : 750000.0;
687 pInfo
->estimatedCost
= bSeenMatch
? 1000.0 : 1000000.0;
690 pInfo
->idxNum
= idxFlags
;
694 static int fts5NewTransaction(Fts5FullTable
*pTab
){
696 for(pCsr
=pTab
->pGlobal
->pCsr
; pCsr
; pCsr
=pCsr
->pNext
){
697 if( pCsr
->base
.pVtab
==(sqlite3_vtab
*)pTab
) return SQLITE_OK
;
699 return sqlite3Fts5StorageReset(pTab
->pStorage
);
703 ** Implementation of xOpen method.
705 static int fts5OpenMethod(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCsr
){
706 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVTab
;
707 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
708 Fts5Cursor
*pCsr
= 0; /* New cursor object */
709 sqlite3_int64 nByte
; /* Bytes of space to allocate */
710 int rc
; /* Return code */
712 rc
= fts5NewTransaction(pTab
);
714 nByte
= sizeof(Fts5Cursor
) + pConfig
->nCol
* sizeof(int);
715 pCsr
= (Fts5Cursor
*)sqlite3_malloc64(nByte
);
717 Fts5Global
*pGlobal
= pTab
->pGlobal
;
718 memset(pCsr
, 0, (size_t)nByte
);
719 pCsr
->aColumnSize
= (int*)&pCsr
[1];
720 pCsr
->pNext
= pGlobal
->pCsr
;
721 pGlobal
->pCsr
= pCsr
;
722 pCsr
->iCsrId
= ++pGlobal
->iNextId
;
727 *ppCsr
= (sqlite3_vtab_cursor
*)pCsr
;
731 static int fts5StmtType(Fts5Cursor
*pCsr
){
732 if( pCsr
->ePlan
==FTS5_PLAN_SCAN
){
733 return (pCsr
->bDesc
) ? FTS5_STMT_SCAN_DESC
: FTS5_STMT_SCAN_ASC
;
735 return FTS5_STMT_LOOKUP
;
739 ** This function is called after the cursor passed as the only argument
740 ** is moved to point at a different row. It clears all cached data
741 ** specific to the previous row stored by the cursor object.
743 static void fts5CsrNewrow(Fts5Cursor
*pCsr
){
745 FTS5CSR_REQUIRE_CONTENT
746 | FTS5CSR_REQUIRE_DOCSIZE
747 | FTS5CSR_REQUIRE_INST
748 | FTS5CSR_REQUIRE_POSLIST
752 static void fts5FreeCursorComponents(Fts5Cursor
*pCsr
){
753 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
757 sqlite3_free(pCsr
->aInstIter
);
758 sqlite3_free(pCsr
->aInst
);
760 int eStmt
= fts5StmtType(pCsr
);
761 sqlite3Fts5StorageStmtRelease(pTab
->pStorage
, eStmt
, pCsr
->pStmt
);
764 Fts5Sorter
*pSorter
= pCsr
->pSorter
;
765 sqlite3_finalize(pSorter
->pStmt
);
766 sqlite3_free(pSorter
);
769 if( pCsr
->ePlan
!=FTS5_PLAN_SOURCE
){
770 sqlite3Fts5ExprFree(pCsr
->pExpr
);
773 for(pData
=pCsr
->pAuxdata
; pData
; pData
=pNext
){
774 pNext
= pData
->pNext
;
775 if( pData
->xDelete
) pData
->xDelete(pData
->pPtr
);
779 sqlite3_finalize(pCsr
->pRankArgStmt
);
780 sqlite3_free(pCsr
->apRankArg
);
782 if( CsrFlagTest(pCsr
, FTS5CSR_FREE_ZRANK
) ){
783 sqlite3_free(pCsr
->zRank
);
784 sqlite3_free(pCsr
->zRankArgs
);
787 sqlite3Fts5IndexCloseReader(pTab
->p
.pIndex
);
788 memset(&pCsr
->ePlan
, 0, sizeof(Fts5Cursor
) - ((u8
*)&pCsr
->ePlan
- (u8
*)pCsr
));
793 ** Close the cursor. For additional information see the documentation
794 ** on the xClose method of the virtual table interface.
796 static int fts5CloseMethod(sqlite3_vtab_cursor
*pCursor
){
798 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCursor
->pVtab
);
799 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
802 fts5FreeCursorComponents(pCsr
);
803 /* Remove the cursor from the Fts5Global.pCsr list */
804 for(pp
=&pTab
->pGlobal
->pCsr
; (*pp
)!=pCsr
; pp
=&(*pp
)->pNext
);
812 static int fts5SorterNext(Fts5Cursor
*pCsr
){
813 Fts5Sorter
*pSorter
= pCsr
->pSorter
;
816 rc
= sqlite3_step(pSorter
->pStmt
);
817 if( rc
==SQLITE_DONE
){
819 CsrFlagSet(pCsr
, FTS5CSR_EOF
|FTS5CSR_REQUIRE_CONTENT
);
820 }else if( rc
==SQLITE_ROW
){
828 pSorter
->iRowid
= sqlite3_column_int64(pSorter
->pStmt
, 0);
829 nBlob
= sqlite3_column_bytes(pSorter
->pStmt
, 1);
830 aBlob
= a
= sqlite3_column_blob(pSorter
->pStmt
, 1);
832 /* nBlob==0 in detail=none mode. */
834 for(i
=0; i
<(pSorter
->nIdx
-1); i
++){
836 a
+= fts5GetVarint32(a
, iVal
);
838 pSorter
->aIdx
[i
] = iOff
;
840 pSorter
->aIdx
[i
] = &aBlob
[nBlob
] - a
;
841 pSorter
->aPoslist
= a
;
852 ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
853 ** open on table pTab.
855 static void fts5TripCursors(Fts5FullTable
*pTab
){
857 for(pCsr
=pTab
->pGlobal
->pCsr
; pCsr
; pCsr
=pCsr
->pNext
){
858 if( pCsr
->ePlan
==FTS5_PLAN_MATCH
859 && pCsr
->base
.pVtab
==(sqlite3_vtab
*)pTab
861 CsrFlagSet(pCsr
, FTS5CSR_REQUIRE_RESEEK
);
867 ** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
868 ** argument, close and reopen all Fts5IndexIter iterators that the cursor
869 ** is using. Then attempt to move the cursor to a rowid equal to or laster
870 ** (in the cursors sort order - ASC or DESC) than the current rowid.
872 ** If the new rowid is not equal to the old, set output parameter *pbSkip
873 ** to 1 before returning. Otherwise, leave it unchanged.
875 ** Return SQLITE_OK if successful or if no reseek was required, or an
876 ** error code if an error occurred.
878 static int fts5CursorReseek(Fts5Cursor
*pCsr
, int *pbSkip
){
880 assert( *pbSkip
==0 );
881 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_RESEEK
) ){
882 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
883 int bDesc
= pCsr
->bDesc
;
884 i64 iRowid
= sqlite3Fts5ExprRowid(pCsr
->pExpr
);
886 rc
= sqlite3Fts5ExprFirst(pCsr
->pExpr
, pTab
->p
.pIndex
, iRowid
, bDesc
);
887 if( rc
==SQLITE_OK
&& iRowid
!=sqlite3Fts5ExprRowid(pCsr
->pExpr
) ){
891 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_RESEEK
);
893 if( sqlite3Fts5ExprEof(pCsr
->pExpr
) ){
894 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
903 ** Advance the cursor to the next row in the table that matches the
906 ** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
907 ** even if we reach end-of-file. The fts5EofMethod() will be called
908 ** subsequently to determine whether or not an EOF was hit.
910 static int fts5NextMethod(sqlite3_vtab_cursor
*pCursor
){
911 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
914 assert( (pCsr
->ePlan
<3)==
915 (pCsr
->ePlan
==FTS5_PLAN_MATCH
|| pCsr
->ePlan
==FTS5_PLAN_SOURCE
)
917 assert( !CsrFlagTest(pCsr
, FTS5CSR_EOF
) );
919 /* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table,
920 ** clear any token mappings accumulated at the fts5_index.c level. In
921 ** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH,
922 ** we need to retain the mappings for the entire query. */
923 if( pCsr
->ePlan
==FTS5_PLAN_MATCH
924 && ((Fts5Table
*)pCursor
->pVtab
)->pConfig
->bTokendata
926 sqlite3Fts5ExprClearTokens(pCsr
->pExpr
);
931 if( (rc
= fts5CursorReseek(pCsr
, &bSkip
)) || bSkip
) return rc
;
932 rc
= sqlite3Fts5ExprNext(pCsr
->pExpr
, pCsr
->iLastRowid
);
933 CsrFlagSet(pCsr
, sqlite3Fts5ExprEof(pCsr
->pExpr
));
936 switch( pCsr
->ePlan
){
937 case FTS5_PLAN_SPECIAL
: {
938 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
943 case FTS5_PLAN_SORTED_MATCH
: {
944 rc
= fts5SorterNext(pCsr
);
949 Fts5Config
*pConfig
= ((Fts5Table
*)pCursor
->pVtab
)->pConfig
;
951 rc
= sqlite3_step(pCsr
->pStmt
);
953 if( rc
!=SQLITE_ROW
){
954 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
955 rc
= sqlite3_reset(pCsr
->pStmt
);
957 pCursor
->pVtab
->zErrMsg
= sqlite3_mprintf(
958 "%s", sqlite3_errmsg(pConfig
->db
)
973 static int fts5PrepareStatement(
974 sqlite3_stmt
**ppStmt
,
979 sqlite3_stmt
*pRet
= 0;
985 zSql
= sqlite3_vmprintf(zFmt
, ap
);
989 rc
= sqlite3_prepare_v3(pConfig
->db
, zSql
, -1,
990 SQLITE_PREPARE_PERSISTENT
, &pRet
, 0);
992 *pConfig
->pzErrmsg
= sqlite3_mprintf("%s", sqlite3_errmsg(pConfig
->db
));
1002 static int fts5CursorFirstSorted(
1003 Fts5FullTable
*pTab
,
1007 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
1008 Fts5Sorter
*pSorter
;
1010 sqlite3_int64 nByte
;
1012 const char *zRank
= pCsr
->zRank
;
1013 const char *zRankArgs
= pCsr
->zRankArgs
;
1015 nPhrase
= sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
);
1016 nByte
= sizeof(Fts5Sorter
) + sizeof(int) * (nPhrase
-1);
1017 pSorter
= (Fts5Sorter
*)sqlite3_malloc64(nByte
);
1018 if( pSorter
==0 ) return SQLITE_NOMEM
;
1019 memset(pSorter
, 0, (size_t)nByte
);
1020 pSorter
->nIdx
= nPhrase
;
1022 /* TODO: It would be better to have some system for reusing statement
1023 ** handles here, rather than preparing a new one for each query. But that
1024 ** is not possible as SQLite reference counts the virtual table objects.
1025 ** And since the statement required here reads from this very virtual
1026 ** table, saving it creates a circular reference.
1028 ** If SQLite a built-in statement cache, this wouldn't be a problem. */
1029 rc
= fts5PrepareStatement(&pSorter
->pStmt
, pConfig
,
1030 "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(\"%w\"%s%s) %s",
1031 pConfig
->zDb
, pConfig
->zName
, zRank
, pConfig
->zName
,
1032 (zRankArgs
? ", " : ""),
1033 (zRankArgs
? zRankArgs
: ""),
1034 bDesc
? "DESC" : "ASC"
1037 pCsr
->pSorter
= pSorter
;
1038 if( rc
==SQLITE_OK
){
1039 assert( pTab
->pSortCsr
==0 );
1040 pTab
->pSortCsr
= pCsr
;
1041 rc
= fts5SorterNext(pCsr
);
1045 if( rc
!=SQLITE_OK
){
1046 sqlite3_finalize(pSorter
->pStmt
);
1047 sqlite3_free(pSorter
);
1054 static int fts5CursorFirst(Fts5FullTable
*pTab
, Fts5Cursor
*pCsr
, int bDesc
){
1056 Fts5Expr
*pExpr
= pCsr
->pExpr
;
1057 rc
= sqlite3Fts5ExprFirst(pExpr
, pTab
->p
.pIndex
, pCsr
->iFirstRowid
, bDesc
);
1058 if( sqlite3Fts5ExprEof(pExpr
) ){
1059 CsrFlagSet(pCsr
, FTS5CSR_EOF
);
1061 fts5CsrNewrow(pCsr
);
1066 ** Process a "special" query. A special query is identified as one with a
1067 ** MATCH expression that begins with a '*' character. The remainder of
1068 ** the text passed to the MATCH operator are used as the special query
1071 static int fts5SpecialMatch(
1072 Fts5FullTable
*pTab
,
1076 int rc
= SQLITE_OK
; /* Return code */
1077 const char *z
= zQuery
; /* Special query text */
1078 int n
; /* Number of bytes in text at z */
1080 while( z
[0]==' ' ) z
++;
1081 for(n
=0; z
[n
] && z
[n
]!=' '; n
++);
1083 assert( pTab
->p
.base
.zErrMsg
==0 );
1084 pCsr
->ePlan
= FTS5_PLAN_SPECIAL
;
1086 if( n
==5 && 0==sqlite3_strnicmp("reads", z
, n
) ){
1087 pCsr
->iSpecial
= sqlite3Fts5IndexReads(pTab
->p
.pIndex
);
1089 else if( n
==2 && 0==sqlite3_strnicmp("id", z
, n
) ){
1090 pCsr
->iSpecial
= pCsr
->iCsrId
;
1093 /* An unrecognized directive. Return an error message. */
1094 pTab
->p
.base
.zErrMsg
= sqlite3_mprintf("unknown special query: %.*s", n
, z
);
1102 ** Search for an auxiliary function named zName that can be used with table
1103 ** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
1104 ** structure. Otherwise, if no such function exists, return NULL.
1106 static Fts5Auxiliary
*fts5FindAuxiliary(Fts5FullTable
*pTab
, const char *zName
){
1107 Fts5Auxiliary
*pAux
;
1109 for(pAux
=pTab
->pGlobal
->pAux
; pAux
; pAux
=pAux
->pNext
){
1110 if( sqlite3_stricmp(zName
, pAux
->zFunc
)==0 ) return pAux
;
1113 /* No function of the specified name was found. Return 0. */
1118 static int fts5FindRankFunction(Fts5Cursor
*pCsr
){
1119 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
1120 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
1122 Fts5Auxiliary
*pAux
= 0;
1123 const char *zRank
= pCsr
->zRank
;
1124 const char *zRankArgs
= pCsr
->zRankArgs
;
1127 char *zSql
= sqlite3Fts5Mprintf(&rc
, "SELECT %s", zRankArgs
);
1129 sqlite3_stmt
*pStmt
= 0;
1130 rc
= sqlite3_prepare_v3(pConfig
->db
, zSql
, -1,
1131 SQLITE_PREPARE_PERSISTENT
, &pStmt
, 0);
1133 assert( rc
==SQLITE_OK
|| pCsr
->pRankArgStmt
==0 );
1134 if( rc
==SQLITE_OK
){
1135 if( SQLITE_ROW
==sqlite3_step(pStmt
) ){
1136 sqlite3_int64 nByte
;
1137 pCsr
->nRankArg
= sqlite3_column_count(pStmt
);
1138 nByte
= sizeof(sqlite3_value
*)*pCsr
->nRankArg
;
1139 pCsr
->apRankArg
= (sqlite3_value
**)sqlite3Fts5MallocZero(&rc
, nByte
);
1140 if( rc
==SQLITE_OK
){
1142 for(i
=0; i
<pCsr
->nRankArg
; i
++){
1143 pCsr
->apRankArg
[i
] = sqlite3_column_value(pStmt
, i
);
1146 pCsr
->pRankArgStmt
= pStmt
;
1148 rc
= sqlite3_finalize(pStmt
);
1149 assert( rc
!=SQLITE_OK
);
1155 if( rc
==SQLITE_OK
){
1156 pAux
= fts5FindAuxiliary(pTab
, zRank
);
1158 assert( pTab
->p
.base
.zErrMsg
==0 );
1159 pTab
->p
.base
.zErrMsg
= sqlite3_mprintf("no such function: %s", zRank
);
1169 static int fts5CursorParseRank(
1170 Fts5Config
*pConfig
,
1172 sqlite3_value
*pRank
1176 const char *z
= (const char*)sqlite3_value_text(pRank
);
1178 char *zRankArgs
= 0;
1181 if( sqlite3_value_type(pRank
)==SQLITE_NULL
) rc
= SQLITE_ERROR
;
1183 rc
= sqlite3Fts5ConfigParseRank(z
, &zRank
, &zRankArgs
);
1185 if( rc
==SQLITE_OK
){
1186 pCsr
->zRank
= zRank
;
1187 pCsr
->zRankArgs
= zRankArgs
;
1188 CsrFlagSet(pCsr
, FTS5CSR_FREE_ZRANK
);
1189 }else if( rc
==SQLITE_ERROR
){
1190 pCsr
->base
.pVtab
->zErrMsg
= sqlite3_mprintf(
1191 "parse error in rank function: %s", z
1195 if( pConfig
->zRank
){
1196 pCsr
->zRank
= (char*)pConfig
->zRank
;
1197 pCsr
->zRankArgs
= (char*)pConfig
->zRankArgs
;
1199 pCsr
->zRank
= (char*)FTS5_DEFAULT_RANK
;
1200 pCsr
->zRankArgs
= 0;
1206 static i64
fts5GetRowidLimit(sqlite3_value
*pVal
, i64 iDefault
){
1208 int eType
= sqlite3_value_numeric_type(pVal
);
1209 if( eType
==SQLITE_INTEGER
){
1210 return sqlite3_value_int64(pVal
);
1217 ** This is the xFilter interface for the virtual table. See
1218 ** the virtual table xFilter method documentation for additional
1221 ** There are three possible query strategies:
1223 ** 1. Full-text search using a MATCH operator.
1224 ** 2. A by-rowid lookup.
1225 ** 3. A full-table scan.
1227 static int fts5FilterMethod(
1228 sqlite3_vtab_cursor
*pCursor
, /* The cursor used for this query */
1229 int idxNum
, /* Strategy index */
1230 const char *idxStr
, /* Unused */
1231 int nVal
, /* Number of elements in apVal */
1232 sqlite3_value
**apVal
/* Arguments for the indexing scheme */
1234 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCursor
->pVtab
);
1235 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
1236 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
1237 int rc
= SQLITE_OK
; /* Error code */
1238 int bDesc
; /* True if ORDER BY [rank|rowid] DESC */
1239 int bOrderByRank
; /* True if ORDER BY rank */
1240 sqlite3_value
*pRank
= 0; /* rank MATCH ? expression (or NULL) */
1241 sqlite3_value
*pRowidEq
= 0; /* rowid = ? expression (or NULL) */
1242 sqlite3_value
*pRowidLe
= 0; /* rowid <= ? expression (or NULL) */
1243 sqlite3_value
*pRowidGe
= 0; /* rowid >= ? expression (or NULL) */
1244 int iCol
; /* Column on LHS of MATCH operator */
1245 char **pzErrmsg
= pConfig
->pzErrmsg
;
1248 Fts5Expr
*pExpr
= 0;
1250 if( pConfig
->bLock
){
1251 pTab
->p
.base
.zErrMsg
= sqlite3_mprintf(
1252 "recursively defined fts5 content table"
1254 return SQLITE_ERROR
;
1258 fts5FreeCursorComponents(pCsr
);
1259 memset(&pCsr
->ePlan
, 0, sizeof(Fts5Cursor
) - ((u8
*)&pCsr
->ePlan
-(u8
*)pCsr
));
1262 assert( pCsr
->pStmt
==0 );
1263 assert( pCsr
->pExpr
==0 );
1264 assert( pCsr
->csrflags
==0 );
1265 assert( pCsr
->pRank
==0 );
1266 assert( pCsr
->zRank
==0 );
1267 assert( pCsr
->zRankArgs
==0 );
1268 assert( pTab
->pSortCsr
==0 || nVal
==0 );
1270 assert( pzErrmsg
==0 || pzErrmsg
==&pTab
->p
.base
.zErrMsg
);
1271 pConfig
->pzErrmsg
= &pTab
->p
.base
.zErrMsg
;
1273 /* Decode the arguments passed through to this function. */
1274 for(i
=0; i
<nVal
; i
++){
1275 switch( idxStr
[iIdxStr
++] ){
1280 const char *zText
= (const char*)sqlite3_value_text(apVal
[i
]);
1281 if( zText
==0 ) zText
= "";
1284 iCol
= iCol
*10 + (idxStr
[iIdxStr
]-'0');
1286 }while( idxStr
[iIdxStr
]>='0' && idxStr
[iIdxStr
]<='9' );
1288 if( zText
[0]=='*' ){
1289 /* The user has issued a query of the form "MATCH '*...'". This
1290 ** indicates that the MATCH expression is not a full text query,
1291 ** but a request for an internal parameter. */
1292 rc
= fts5SpecialMatch(pTab
, pCsr
, &zText
[1]);
1295 char **pzErr
= &pTab
->p
.base
.zErrMsg
;
1296 rc
= sqlite3Fts5ExprNew(pConfig
, 0, iCol
, zText
, &pExpr
, pzErr
);
1297 if( rc
==SQLITE_OK
){
1298 rc
= sqlite3Fts5ExprAnd(&pCsr
->pExpr
, pExpr
);
1301 if( rc
!=SQLITE_OK
) goto filter_out
;
1308 int bGlob
= (idxStr
[iIdxStr
-1]=='G');
1309 const char *zText
= (const char*)sqlite3_value_text(apVal
[i
]);
1312 iCol
= iCol
*10 + (idxStr
[iIdxStr
]-'0');
1314 }while( idxStr
[iIdxStr
]>='0' && idxStr
[iIdxStr
]<='9' );
1316 rc
= sqlite3Fts5ExprPattern(pConfig
, bGlob
, iCol
, zText
, &pExpr
);
1318 if( rc
==SQLITE_OK
){
1319 rc
= sqlite3Fts5ExprAnd(&pCsr
->pExpr
, pExpr
);
1322 if( rc
!=SQLITE_OK
) goto filter_out
;
1326 pRowidEq
= apVal
[i
];
1329 pRowidLe
= apVal
[i
];
1331 default: assert( idxStr
[iIdxStr
-1]=='>' );
1332 pRowidGe
= apVal
[i
];
1336 bOrderByRank
= ((idxNum
& FTS5_BI_ORDER_RANK
) ? 1 : 0);
1337 pCsr
->bDesc
= bDesc
= ((idxNum
& FTS5_BI_ORDER_DESC
) ? 1 : 0);
1339 /* Set the cursor upper and lower rowid limits. Only some strategies
1340 ** actually use them. This is ok, as the xBestIndex() method leaves the
1341 ** sqlite3_index_constraint.omit flag clear for range constraints
1342 ** on the rowid field. */
1344 pRowidLe
= pRowidGe
= pRowidEq
;
1347 pCsr
->iFirstRowid
= fts5GetRowidLimit(pRowidLe
, LARGEST_INT64
);
1348 pCsr
->iLastRowid
= fts5GetRowidLimit(pRowidGe
, SMALLEST_INT64
);
1350 pCsr
->iLastRowid
= fts5GetRowidLimit(pRowidLe
, LARGEST_INT64
);
1351 pCsr
->iFirstRowid
= fts5GetRowidLimit(pRowidGe
, SMALLEST_INT64
);
1354 rc
= sqlite3Fts5IndexLoadConfig(pTab
->p
.pIndex
);
1355 if( rc
!=SQLITE_OK
) goto filter_out
;
1357 if( pTab
->pSortCsr
){
1358 /* If pSortCsr is non-NULL, then this call is being made as part of
1359 ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
1360 ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
1361 ** return results to the user for this query. The current cursor
1362 ** (pCursor) is used to execute the query issued by function
1363 ** fts5CursorFirstSorted() above. */
1364 assert( pRowidEq
==0 && pRowidLe
==0 && pRowidGe
==0 && pRank
==0 );
1365 assert( nVal
==0 && bOrderByRank
==0 && bDesc
==0 );
1366 assert( pCsr
->iLastRowid
==LARGEST_INT64
);
1367 assert( pCsr
->iFirstRowid
==SMALLEST_INT64
);
1368 if( pTab
->pSortCsr
->bDesc
){
1369 pCsr
->iLastRowid
= pTab
->pSortCsr
->iFirstRowid
;
1370 pCsr
->iFirstRowid
= pTab
->pSortCsr
->iLastRowid
;
1372 pCsr
->iLastRowid
= pTab
->pSortCsr
->iLastRowid
;
1373 pCsr
->iFirstRowid
= pTab
->pSortCsr
->iFirstRowid
;
1375 pCsr
->ePlan
= FTS5_PLAN_SOURCE
;
1376 pCsr
->pExpr
= pTab
->pSortCsr
->pExpr
;
1377 rc
= fts5CursorFirst(pTab
, pCsr
, bDesc
);
1378 }else if( pCsr
->pExpr
){
1379 assert( rc
==SQLITE_OK
);
1380 rc
= fts5CursorParseRank(pConfig
, pCsr
, pRank
);
1381 if( rc
==SQLITE_OK
){
1383 pCsr
->ePlan
= FTS5_PLAN_SORTED_MATCH
;
1384 rc
= fts5CursorFirstSorted(pTab
, pCsr
, bDesc
);
1386 pCsr
->ePlan
= FTS5_PLAN_MATCH
;
1387 rc
= fts5CursorFirst(pTab
, pCsr
, bDesc
);
1390 }else if( pConfig
->zContent
==0 ){
1391 *pConfig
->pzErrmsg
= sqlite3_mprintf(
1392 "%s: table does not support scanning", pConfig
->zName
1396 /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
1397 ** by rowid (ePlan==FTS5_PLAN_ROWID). */
1398 pCsr
->ePlan
= (pRowidEq
? FTS5_PLAN_ROWID
: FTS5_PLAN_SCAN
);
1399 rc
= sqlite3Fts5StorageStmt(
1400 pTab
->pStorage
, fts5StmtType(pCsr
), &pCsr
->pStmt
, &pTab
->p
.base
.zErrMsg
1402 if( rc
==SQLITE_OK
){
1404 assert( pCsr
->ePlan
==FTS5_PLAN_ROWID
);
1405 sqlite3_bind_value(pCsr
->pStmt
, 1, pRowidEq
);
1407 sqlite3_bind_int64(pCsr
->pStmt
, 1, pCsr
->iFirstRowid
);
1408 sqlite3_bind_int64(pCsr
->pStmt
, 2, pCsr
->iLastRowid
);
1410 rc
= fts5NextMethod(pCursor
);
1415 sqlite3Fts5ExprFree(pExpr
);
1416 pConfig
->pzErrmsg
= pzErrmsg
;
1421 ** This is the xEof method of the virtual table. SQLite calls this
1422 ** routine to find out if it has reached the end of a result set.
1424 static int fts5EofMethod(sqlite3_vtab_cursor
*pCursor
){
1425 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
1426 return (CsrFlagTest(pCsr
, FTS5CSR_EOF
) ? 1 : 0);
1430 ** Return the rowid that the cursor currently points to.
1432 static i64
fts5CursorRowid(Fts5Cursor
*pCsr
){
1433 assert( pCsr
->ePlan
==FTS5_PLAN_MATCH
1434 || pCsr
->ePlan
==FTS5_PLAN_SORTED_MATCH
1435 || pCsr
->ePlan
==FTS5_PLAN_SOURCE
1437 if( pCsr
->pSorter
){
1438 return pCsr
->pSorter
->iRowid
;
1440 return sqlite3Fts5ExprRowid(pCsr
->pExpr
);
1445 ** This is the xRowid method. The SQLite core calls this routine to
1446 ** retrieve the rowid for the current row of the result set. fts5
1447 ** exposes %_content.rowid as the rowid for the virtual table. The
1448 ** rowid should be written to *pRowid.
1450 static int fts5RowidMethod(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
1451 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
1452 int ePlan
= pCsr
->ePlan
;
1454 assert( CsrFlagTest(pCsr
, FTS5CSR_EOF
)==0 );
1456 case FTS5_PLAN_SPECIAL
:
1460 case FTS5_PLAN_SOURCE
:
1461 case FTS5_PLAN_MATCH
:
1462 case FTS5_PLAN_SORTED_MATCH
:
1463 *pRowid
= fts5CursorRowid(pCsr
);
1467 *pRowid
= sqlite3_column_int64(pCsr
->pStmt
, 0);
1475 ** If the cursor requires seeking (bSeekRequired flag is set), seek it.
1476 ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
1478 ** If argument bErrormsg is true and an error occurs, an error message may
1479 ** be left in sqlite3_vtab.zErrMsg.
1481 static int fts5SeekCursor(Fts5Cursor
*pCsr
, int bErrormsg
){
1484 /* If the cursor does not yet have a statement handle, obtain one now. */
1485 if( pCsr
->pStmt
==0 ){
1486 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
1487 int eStmt
= fts5StmtType(pCsr
);
1488 rc
= sqlite3Fts5StorageStmt(
1489 pTab
->pStorage
, eStmt
, &pCsr
->pStmt
, (bErrormsg
?&pTab
->p
.base
.zErrMsg
:0)
1491 assert( rc
!=SQLITE_OK
|| pTab
->p
.base
.zErrMsg
==0 );
1492 assert( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_CONTENT
) );
1495 if( rc
==SQLITE_OK
&& CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_CONTENT
) ){
1496 Fts5Table
*pTab
= (Fts5Table
*)(pCsr
->base
.pVtab
);
1497 assert( pCsr
->pExpr
);
1498 sqlite3_reset(pCsr
->pStmt
);
1499 sqlite3_bind_int64(pCsr
->pStmt
, 1, fts5CursorRowid(pCsr
));
1500 pTab
->pConfig
->bLock
++;
1501 rc
= sqlite3_step(pCsr
->pStmt
);
1502 pTab
->pConfig
->bLock
--;
1503 if( rc
==SQLITE_ROW
){
1505 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_CONTENT
);
1507 rc
= sqlite3_reset(pCsr
->pStmt
);
1508 if( rc
==SQLITE_OK
){
1510 }else if( pTab
->pConfig
->pzErrmsg
){
1511 *pTab
->pConfig
->pzErrmsg
= sqlite3_mprintf(
1512 "%s", sqlite3_errmsg(pTab
->pConfig
->db
)
1520 static void fts5SetVtabError(Fts5FullTable
*p
, const char *zFormat
, ...){
1521 va_list ap
; /* ... printf arguments */
1522 va_start(ap
, zFormat
);
1523 assert( p
->p
.base
.zErrMsg
==0 );
1524 p
->p
.base
.zErrMsg
= sqlite3_vmprintf(zFormat
, ap
);
1529 ** This function is called to handle an FTS INSERT command. In other words,
1530 ** an INSERT statement of the form:
1532 ** INSERT INTO fts(fts) VALUES($pCmd)
1533 ** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
1535 ** Argument pVal is the value assigned to column "fts" by the INSERT
1536 ** statement. This function returns SQLITE_OK if successful, or an SQLite
1537 ** error code if an error occurs.
1539 ** The commands implemented by this function are documented in the "Special
1540 ** INSERT Directives" section of the documentation. It should be updated if
1541 ** more commands are added to this function.
1543 static int fts5SpecialInsert(
1544 Fts5FullTable
*pTab
, /* Fts5 table object */
1545 const char *zCmd
, /* Text inserted into table-name column */
1546 sqlite3_value
*pVal
/* Value inserted into rank column */
1548 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
1551 int bLoadConfig
= 0;
1553 if( 0==sqlite3_stricmp("delete-all", zCmd
) ){
1554 if( pConfig
->eContent
==FTS5_CONTENT_NORMAL
){
1555 fts5SetVtabError(pTab
,
1556 "'delete-all' may only be used with a "
1557 "contentless or external content fts5 table"
1561 rc
= sqlite3Fts5StorageDeleteAll(pTab
->pStorage
);
1564 }else if( 0==sqlite3_stricmp("rebuild", zCmd
) ){
1565 if( pConfig
->eContent
==FTS5_CONTENT_NONE
){
1566 fts5SetVtabError(pTab
,
1567 "'rebuild' may not be used with a contentless fts5 table"
1571 rc
= sqlite3Fts5StorageRebuild(pTab
->pStorage
);
1574 }else if( 0==sqlite3_stricmp("optimize", zCmd
) ){
1575 rc
= sqlite3Fts5StorageOptimize(pTab
->pStorage
);
1576 }else if( 0==sqlite3_stricmp("merge", zCmd
) ){
1577 int nMerge
= sqlite3_value_int(pVal
);
1578 rc
= sqlite3Fts5StorageMerge(pTab
->pStorage
, nMerge
);
1579 }else if( 0==sqlite3_stricmp("integrity-check", zCmd
) ){
1580 int iArg
= sqlite3_value_int(pVal
);
1581 rc
= sqlite3Fts5StorageIntegrity(pTab
->pStorage
, iArg
);
1583 }else if( 0==sqlite3_stricmp("prefix-index", zCmd
) ){
1584 pConfig
->bPrefixIndex
= sqlite3_value_int(pVal
);
1586 }else if( 0==sqlite3_stricmp("flush", zCmd
) ){
1587 rc
= sqlite3Fts5FlushToDisk(&pTab
->p
);
1589 rc
= sqlite3Fts5FlushToDisk(&pTab
->p
);
1590 if( rc
==SQLITE_OK
){
1591 rc
= sqlite3Fts5IndexLoadConfig(pTab
->p
.pIndex
);
1593 if( rc
==SQLITE_OK
){
1594 rc
= sqlite3Fts5ConfigSetValue(pTab
->p
.pConfig
, zCmd
, pVal
, &bError
);
1596 if( rc
==SQLITE_OK
){
1600 rc
= sqlite3Fts5StorageConfigValue(pTab
->pStorage
, zCmd
, pVal
, 0);
1605 if( rc
==SQLITE_OK
&& bLoadConfig
){
1606 pTab
->p
.pConfig
->iCookie
--;
1607 rc
= sqlite3Fts5IndexLoadConfig(pTab
->p
.pIndex
);
1613 static int fts5SpecialDelete(
1614 Fts5FullTable
*pTab
,
1615 sqlite3_value
**apVal
1618 int eType1
= sqlite3_value_type(apVal
[1]);
1619 if( eType1
==SQLITE_INTEGER
){
1620 sqlite3_int64 iDel
= sqlite3_value_int64(apVal
[1]);
1621 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iDel
, &apVal
[2]);
1626 static void fts5StorageInsert(
1628 Fts5FullTable
*pTab
,
1629 sqlite3_value
**apVal
,
1633 if( rc
==SQLITE_OK
){
1634 rc
= sqlite3Fts5StorageContentInsert(pTab
->pStorage
, apVal
, piRowid
);
1636 if( rc
==SQLITE_OK
){
1637 rc
= sqlite3Fts5StorageIndexInsert(pTab
->pStorage
, apVal
, *piRowid
);
1643 ** This function is the implementation of the xUpdate callback used by
1644 ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
1645 ** inserted, updated or deleted.
1647 ** A delete specifies a single argument - the rowid of the row to remove.
1649 ** Update and insert operations pass:
1651 ** 1. The "old" rowid, or NULL.
1652 ** 2. The "new" rowid.
1653 ** 3. Values for each of the nCol matchable columns.
1654 ** 4. Values for the two hidden columns (<tablename> and "rank").
1656 static int fts5UpdateMethod(
1657 sqlite3_vtab
*pVtab
, /* Virtual table handle */
1658 int nArg
, /* Size of argument array */
1659 sqlite3_value
**apVal
, /* Array of arguments */
1660 sqlite_int64
*pRowid
/* OUT: The affected (or effected) rowid */
1662 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
1663 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
1664 int eType0
; /* value_type() of apVal[0] */
1665 int rc
= SQLITE_OK
; /* Return code */
1666 int bUpdateOrDelete
= 0;
1668 /* A transaction must be open when this is called. */
1669 assert( pTab
->ts
.eState
==1 || pTab
->ts
.eState
==2 );
1671 assert( pVtab
->zErrMsg
==0 );
1672 assert( nArg
==1 || nArg
==(2+pConfig
->nCol
+2) );
1673 assert( sqlite3_value_type(apVal
[0])==SQLITE_INTEGER
1674 || sqlite3_value_type(apVal
[0])==SQLITE_NULL
1676 assert( pTab
->p
.pConfig
->pzErrmsg
==0 );
1677 if( pConfig
->pgsz
==0 ){
1678 rc
= sqlite3Fts5IndexLoadConfig(pTab
->p
.pIndex
);
1679 if( rc
!=SQLITE_OK
) return rc
;
1682 pTab
->p
.pConfig
->pzErrmsg
= &pTab
->p
.base
.zErrMsg
;
1684 /* Put any active cursors into REQUIRE_SEEK state. */
1685 fts5TripCursors(pTab
);
1687 eType0
= sqlite3_value_type(apVal
[0]);
1688 if( eType0
==SQLITE_NULL
1689 && sqlite3_value_type(apVal
[2+pConfig
->nCol
])!=SQLITE_NULL
1691 /* A "special" INSERT op. These are handled separately. */
1692 const char *z
= (const char*)sqlite3_value_text(apVal
[2+pConfig
->nCol
]);
1693 if( pConfig
->eContent
!=FTS5_CONTENT_NORMAL
1694 && 0==sqlite3_stricmp("delete", z
)
1696 if( pConfig
->bContentlessDelete
){
1697 fts5SetVtabError(pTab
,
1698 "'delete' may not be used with a contentless_delete=1 table"
1702 rc
= fts5SpecialDelete(pTab
, apVal
);
1703 bUpdateOrDelete
= 1;
1706 rc
= fts5SpecialInsert(pTab
, z
, apVal
[2 + pConfig
->nCol
+ 1]);
1709 /* A regular INSERT, UPDATE or DELETE statement. The trick here is that
1710 ** any conflict on the rowid value must be detected before any
1711 ** modifications are made to the database file. There are 4 cases:
1714 ** 2) UPDATE (rowid not modified)
1715 ** 3) UPDATE (rowid modified)
1718 ** Cases 3 and 4 may violate the rowid constraint.
1720 int eConflict
= SQLITE_ABORT
;
1721 if( pConfig
->eContent
==FTS5_CONTENT_NORMAL
|| pConfig
->bContentlessDelete
){
1722 eConflict
= sqlite3_vtab_on_conflict(pConfig
->db
);
1725 assert( eType0
==SQLITE_INTEGER
|| eType0
==SQLITE_NULL
);
1726 assert( nArg
!=1 || eType0
==SQLITE_INTEGER
);
1728 /* Filter out attempts to run UPDATE or DELETE on contentless tables.
1729 ** This is not suported. Except - they are both supported if the CREATE
1730 ** VIRTUAL TABLE statement contained "contentless_delete=1". */
1731 if( eType0
==SQLITE_INTEGER
1732 && pConfig
->eContent
==FTS5_CONTENT_NONE
1733 && pConfig
->bContentlessDelete
==0
1735 pTab
->p
.base
.zErrMsg
= sqlite3_mprintf(
1736 "cannot %s contentless fts5 table: %s",
1737 (nArg
>1 ? "UPDATE" : "DELETE from"), pConfig
->zName
1744 i64 iDel
= sqlite3_value_int64(apVal
[0]); /* Rowid to delete */
1745 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iDel
, 0);
1746 bUpdateOrDelete
= 1;
1749 /* INSERT or UPDATE */
1751 int eType1
= sqlite3_value_numeric_type(apVal
[1]);
1753 if( eType1
!=SQLITE_INTEGER
&& eType1
!=SQLITE_NULL
){
1754 rc
= SQLITE_MISMATCH
;
1757 else if( eType0
!=SQLITE_INTEGER
){
1758 /* An INSERT statement. If the conflict-mode is REPLACE, first remove
1759 ** the current entry (if any). */
1760 if( eConflict
==SQLITE_REPLACE
&& eType1
==SQLITE_INTEGER
){
1761 i64 iNew
= sqlite3_value_int64(apVal
[1]); /* Rowid to delete */
1762 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iNew
, 0);
1763 bUpdateOrDelete
= 1;
1765 fts5StorageInsert(&rc
, pTab
, apVal
, pRowid
);
1770 i64 iOld
= sqlite3_value_int64(apVal
[0]); /* Old rowid */
1771 i64 iNew
= sqlite3_value_int64(apVal
[1]); /* New rowid */
1772 if( eType1
==SQLITE_INTEGER
&& iOld
!=iNew
){
1773 if( eConflict
==SQLITE_REPLACE
){
1774 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iOld
, 0);
1775 if( rc
==SQLITE_OK
){
1776 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iNew
, 0);
1778 fts5StorageInsert(&rc
, pTab
, apVal
, pRowid
);
1780 rc
= sqlite3Fts5StorageContentInsert(pTab
->pStorage
, apVal
, pRowid
);
1781 if( rc
==SQLITE_OK
){
1782 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iOld
, 0);
1784 if( rc
==SQLITE_OK
){
1785 rc
= sqlite3Fts5StorageIndexInsert(pTab
->pStorage
, apVal
,*pRowid
);
1789 rc
= sqlite3Fts5StorageDelete(pTab
->pStorage
, iOld
, 0);
1790 fts5StorageInsert(&rc
, pTab
, apVal
, pRowid
);
1792 bUpdateOrDelete
= 1;
1799 && pConfig
->bSecureDelete
1800 && pConfig
->iVersion
==FTS5_CURRENT_VERSION
1802 rc
= sqlite3Fts5StorageConfigValue(
1803 pTab
->pStorage
, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
1805 if( rc
==SQLITE_OK
){
1806 pConfig
->iVersion
= FTS5_CURRENT_VERSION_SECUREDELETE
;
1810 pTab
->p
.pConfig
->pzErrmsg
= 0;
1815 ** Implementation of xSync() method.
1817 static int fts5SyncMethod(sqlite3_vtab
*pVtab
){
1819 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
1820 fts5CheckTransactionState(pTab
, FTS5_SYNC
, 0);
1821 pTab
->p
.pConfig
->pzErrmsg
= &pTab
->p
.base
.zErrMsg
;
1822 rc
= sqlite3Fts5FlushToDisk(&pTab
->p
);
1823 pTab
->p
.pConfig
->pzErrmsg
= 0;
1828 ** Implementation of xBegin() method.
1830 static int fts5BeginMethod(sqlite3_vtab
*pVtab
){
1831 fts5CheckTransactionState((Fts5FullTable
*)pVtab
, FTS5_BEGIN
, 0);
1832 fts5NewTransaction((Fts5FullTable
*)pVtab
);
1837 ** Implementation of xCommit() method. This is a no-op. The contents of
1838 ** the pending-terms hash-table have already been flushed into the database
1839 ** by fts5SyncMethod().
1841 static int fts5CommitMethod(sqlite3_vtab
*pVtab
){
1842 UNUSED_PARAM(pVtab
); /* Call below is a no-op for NDEBUG builds */
1843 fts5CheckTransactionState((Fts5FullTable
*)pVtab
, FTS5_COMMIT
, 0);
1848 ** Implementation of xRollback(). Discard the contents of the pending-terms
1849 ** hash-table. Any changes made to the database are reverted by SQLite.
1851 static int fts5RollbackMethod(sqlite3_vtab
*pVtab
){
1853 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
1854 fts5CheckTransactionState(pTab
, FTS5_ROLLBACK
, 0);
1855 rc
= sqlite3Fts5StorageRollback(pTab
->pStorage
);
1859 static int fts5CsrPoslist(Fts5Cursor
*, int, const u8
**, int*);
1861 static void *fts5ApiUserData(Fts5Context
*pCtx
){
1862 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1863 return pCsr
->pAux
->pUserData
;
1866 static int fts5ApiColumnCount(Fts5Context
*pCtx
){
1867 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1868 return ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
->nCol
;
1871 static int fts5ApiColumnTotalSize(
1874 sqlite3_int64
*pnToken
1876 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1877 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
1878 return sqlite3Fts5StorageSize(pTab
->pStorage
, iCol
, pnToken
);
1881 static int fts5ApiRowCount(Fts5Context
*pCtx
, i64
*pnRow
){
1882 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1883 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
1884 return sqlite3Fts5StorageRowCount(pTab
->pStorage
, pnRow
);
1887 static int fts5ApiTokenize(
1889 const char *pText
, int nText
,
1891 int (*xToken
)(void*, int, const char*, int, int, int)
1893 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1894 Fts5Table
*pTab
= (Fts5Table
*)(pCsr
->base
.pVtab
);
1895 return sqlite3Fts5Tokenize(
1896 pTab
->pConfig
, FTS5_TOKENIZE_AUX
, pText
, nText
, pUserData
, xToken
1900 static int fts5ApiPhraseCount(Fts5Context
*pCtx
){
1901 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1902 return sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
);
1905 static int fts5ApiPhraseSize(Fts5Context
*pCtx
, int iPhrase
){
1906 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1907 return sqlite3Fts5ExprPhraseSize(pCsr
->pExpr
, iPhrase
);
1910 static int fts5ApiColumnText(
1917 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
1918 Fts5Table
*pTab
= (Fts5Table
*)(pCsr
->base
.pVtab
);
1919 if( iCol
<0 || iCol
>=pTab
->pConfig
->nCol
){
1921 }else if( fts5IsContentless((Fts5FullTable
*)(pCsr
->base
.pVtab
))
1922 || pCsr
->ePlan
==FTS5_PLAN_SPECIAL
1927 rc
= fts5SeekCursor(pCsr
, 0);
1928 if( rc
==SQLITE_OK
){
1929 *pz
= (const char*)sqlite3_column_text(pCsr
->pStmt
, iCol
+1);
1930 *pn
= sqlite3_column_bytes(pCsr
->pStmt
, iCol
+1);
1936 static int fts5CsrPoslist(
1942 Fts5Config
*pConfig
= ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
;
1944 int bLive
= (pCsr
->pSorter
==0);
1946 if( iPhrase
<0 || iPhrase
>=sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
) ){
1948 }else if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_POSLIST
) ){
1949 if( pConfig
->eDetail
!=FTS5_DETAIL_FULL
){
1950 Fts5PoslistPopulator
*aPopulator
;
1952 aPopulator
= sqlite3Fts5ExprClearPoslists(pCsr
->pExpr
, bLive
);
1953 if( aPopulator
==0 ) rc
= SQLITE_NOMEM
;
1954 for(i
=0; i
<pConfig
->nCol
&& rc
==SQLITE_OK
; i
++){
1955 int n
; const char *z
;
1956 rc
= fts5ApiColumnText((Fts5Context
*)pCsr
, i
, &z
, &n
);
1957 if( rc
==SQLITE_OK
){
1958 rc
= sqlite3Fts5ExprPopulatePoslists(
1959 pConfig
, pCsr
->pExpr
, aPopulator
, i
, z
, n
1963 sqlite3_free(aPopulator
);
1965 if( pCsr
->pSorter
){
1966 sqlite3Fts5ExprCheckPoslists(pCsr
->pExpr
, pCsr
->pSorter
->iRowid
);
1969 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_POSLIST
);
1972 if( rc
==SQLITE_OK
){
1973 if( pCsr
->pSorter
&& pConfig
->eDetail
==FTS5_DETAIL_FULL
){
1974 Fts5Sorter
*pSorter
= pCsr
->pSorter
;
1975 int i1
= (iPhrase
==0 ? 0 : pSorter
->aIdx
[iPhrase
-1]);
1976 *pn
= pSorter
->aIdx
[iPhrase
] - i1
;
1977 *pa
= &pSorter
->aPoslist
[i1
];
1979 *pn
= sqlite3Fts5ExprPoslist(pCsr
->pExpr
, iPhrase
, pa
);
1991 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
1992 ** correctly for the current view. Return SQLITE_OK if successful, or an
1993 ** SQLite error code otherwise.
1995 static int fts5CacheInstArray(Fts5Cursor
*pCsr
){
1997 Fts5PoslistReader
*aIter
; /* One iterator for each phrase */
1998 int nIter
; /* Number of iterators/phrases */
1999 int nCol
= ((Fts5Table
*)pCsr
->base
.pVtab
)->pConfig
->nCol
;
2001 nIter
= sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
);
2002 if( pCsr
->aInstIter
==0 ){
2003 sqlite3_int64 nByte
= sizeof(Fts5PoslistReader
) * nIter
;
2004 pCsr
->aInstIter
= (Fts5PoslistReader
*)sqlite3Fts5MallocZero(&rc
, nByte
);
2006 aIter
= pCsr
->aInstIter
;
2009 int nInst
= 0; /* Number instances seen so far */
2012 /* Initialize all iterators */
2013 for(i
=0; i
<nIter
&& rc
==SQLITE_OK
; i
++){
2016 rc
= fts5CsrPoslist(pCsr
, i
, &a
, &n
);
2017 if( rc
==SQLITE_OK
){
2018 sqlite3Fts5PoslistReaderInit(a
, n
, &aIter
[i
]);
2022 if( rc
==SQLITE_OK
){
2026 for(i
=0; i
<nIter
; i
++){
2027 if( (aIter
[i
].bEof
==0)
2028 && (iBest
<0 || aIter
[i
].iPos
<aIter
[iBest
].iPos
)
2033 if( iBest
<0 ) break;
2036 if( nInst
>=pCsr
->nInstAlloc
){
2037 int nNewSize
= pCsr
->nInstAlloc
? pCsr
->nInstAlloc
*2 : 32;
2038 aInst
= (int*)sqlite3_realloc64(
2039 pCsr
->aInst
, nNewSize
*sizeof(int)*3
2042 pCsr
->aInst
= aInst
;
2043 pCsr
->nInstAlloc
= nNewSize
;
2051 aInst
= &pCsr
->aInst
[3 * (nInst
-1)];
2053 aInst
[1] = FTS5_POS2COLUMN(aIter
[iBest
].iPos
);
2054 aInst
[2] = FTS5_POS2OFFSET(aIter
[iBest
].iPos
);
2055 if( aInst
[1]<0 || aInst
[1]>=nCol
){
2059 sqlite3Fts5PoslistReaderNext(&aIter
[iBest
]);
2063 pCsr
->nInstCount
= nInst
;
2064 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_INST
);
2069 static int fts5ApiInstCount(Fts5Context
*pCtx
, int *pnInst
){
2070 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2072 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_INST
)==0
2073 || SQLITE_OK
==(rc
= fts5CacheInstArray(pCsr
)) ){
2074 *pnInst
= pCsr
->nInstCount
;
2079 static int fts5ApiInst(
2086 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2088 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_INST
)==0
2089 || SQLITE_OK
==(rc
= fts5CacheInstArray(pCsr
))
2091 if( iIdx
<0 || iIdx
>=pCsr
->nInstCount
){
2094 *piPhrase
= pCsr
->aInst
[iIdx
*3];
2095 *piCol
= pCsr
->aInst
[iIdx
*3 + 1];
2096 *piOff
= pCsr
->aInst
[iIdx
*3 + 2];
2102 static sqlite3_int64
fts5ApiRowid(Fts5Context
*pCtx
){
2103 return fts5CursorRowid((Fts5Cursor
*)pCtx
);
2106 static int fts5ColumnSizeCb(
2107 void *pContext
, /* Pointer to int */
2109 const char *pUnused
, /* Buffer containing token */
2110 int nUnused
, /* Size of token in bytes */
2111 int iUnused1
, /* Start offset of token */
2112 int iUnused2
/* End offset of token */
2114 int *pCnt
= (int*)pContext
;
2115 UNUSED_PARAM2(pUnused
, nUnused
);
2116 UNUSED_PARAM2(iUnused1
, iUnused2
);
2117 if( (tflags
& FTS5_TOKEN_COLOCATED
)==0 ){
2123 static int fts5ApiColumnSize(Fts5Context
*pCtx
, int iCol
, int *pnToken
){
2124 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2125 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
2126 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
2129 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_DOCSIZE
) ){
2130 if( pConfig
->bColumnsize
){
2131 i64 iRowid
= fts5CursorRowid(pCsr
);
2132 rc
= sqlite3Fts5StorageDocsize(pTab
->pStorage
, iRowid
, pCsr
->aColumnSize
);
2133 }else if( pConfig
->zContent
==0 ){
2135 for(i
=0; i
<pConfig
->nCol
; i
++){
2136 if( pConfig
->abUnindexed
[i
]==0 ){
2137 pCsr
->aColumnSize
[i
] = -1;
2142 for(i
=0; rc
==SQLITE_OK
&& i
<pConfig
->nCol
; i
++){
2143 if( pConfig
->abUnindexed
[i
]==0 ){
2144 const char *z
; int n
;
2145 void *p
= (void*)(&pCsr
->aColumnSize
[i
]);
2146 pCsr
->aColumnSize
[i
] = 0;
2147 rc
= fts5ApiColumnText(pCtx
, i
, &z
, &n
);
2148 if( rc
==SQLITE_OK
){
2149 rc
= sqlite3Fts5Tokenize(
2150 pConfig
, FTS5_TOKENIZE_AUX
, z
, n
, p
, fts5ColumnSizeCb
2156 CsrFlagClear(pCsr
, FTS5CSR_REQUIRE_DOCSIZE
);
2161 for(i
=0; i
<pConfig
->nCol
; i
++){
2162 *pnToken
+= pCsr
->aColumnSize
[i
];
2164 }else if( iCol
<pConfig
->nCol
){
2165 *pnToken
= pCsr
->aColumnSize
[iCol
];
2174 ** Implementation of the xSetAuxdata() method.
2176 static int fts5ApiSetAuxdata(
2177 Fts5Context
*pCtx
, /* Fts5 context */
2178 void *pPtr
, /* Pointer to save as auxdata */
2179 void(*xDelete
)(void*) /* Destructor for pPtr (or NULL) */
2181 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2184 /* Search through the cursors list of Fts5Auxdata objects for one that
2185 ** corresponds to the currently executing auxiliary function. */
2186 for(pData
=pCsr
->pAuxdata
; pData
; pData
=pData
->pNext
){
2187 if( pData
->pAux
==pCsr
->pAux
) break;
2191 if( pData
->xDelete
){
2192 pData
->xDelete(pData
->pPtr
);
2196 pData
= (Fts5Auxdata
*)sqlite3Fts5MallocZero(&rc
, sizeof(Fts5Auxdata
));
2198 if( xDelete
) xDelete(pPtr
);
2201 pData
->pAux
= pCsr
->pAux
;
2202 pData
->pNext
= pCsr
->pAuxdata
;
2203 pCsr
->pAuxdata
= pData
;
2206 pData
->xDelete
= xDelete
;
2211 static void *fts5ApiGetAuxdata(Fts5Context
*pCtx
, int bClear
){
2212 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2216 for(pData
=pCsr
->pAuxdata
; pData
; pData
=pData
->pNext
){
2217 if( pData
->pAux
==pCsr
->pAux
) break;
2231 static void fts5ApiPhraseNext(
2232 Fts5Context
*pUnused
,
2233 Fts5PhraseIter
*pIter
,
2234 int *piCol
, int *piOff
2236 UNUSED_PARAM(pUnused
);
2237 if( pIter
->a
>=pIter
->b
){
2242 pIter
->a
+= fts5GetVarint32(pIter
->a
, iVal
);
2244 pIter
->a
+= fts5GetVarint32(pIter
->a
, iVal
);
2247 pIter
->a
+= fts5GetVarint32(pIter
->a
, iVal
);
2253 static int fts5ApiPhraseFirst(
2256 Fts5PhraseIter
*pIter
,
2257 int *piCol
, int *piOff
2259 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2261 int rc
= fts5CsrPoslist(pCsr
, iPhrase
, &pIter
->a
, &n
);
2262 if( rc
==SQLITE_OK
){
2263 assert( pIter
->a
|| n
==0 );
2264 pIter
->b
= (pIter
->a
? &pIter
->a
[n
] : 0);
2267 fts5ApiPhraseNext(pCtx
, pIter
, piCol
, piOff
);
2272 static void fts5ApiPhraseNextColumn(
2274 Fts5PhraseIter
*pIter
,
2277 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2278 Fts5Config
*pConfig
= ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
;
2280 if( pConfig
->eDetail
==FTS5_DETAIL_COLUMNS
){
2281 if( pIter
->a
>=pIter
->b
){
2285 pIter
->a
+= fts5GetVarint32(&pIter
->a
[0], iIncr
);
2286 *piCol
+= (iIncr
-2);
2291 if( pIter
->a
>=pIter
->b
){
2295 if( pIter
->a
[0]==0x01 ) break;
2296 pIter
->a
+= fts5GetVarint32(pIter
->a
, dummy
);
2298 pIter
->a
+= 1 + fts5GetVarint32(&pIter
->a
[1], *piCol
);
2302 static int fts5ApiPhraseFirstColumn(
2305 Fts5PhraseIter
*pIter
,
2309 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2310 Fts5Config
*pConfig
= ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
;
2312 if( pConfig
->eDetail
==FTS5_DETAIL_COLUMNS
){
2313 Fts5Sorter
*pSorter
= pCsr
->pSorter
;
2316 int i1
= (iPhrase
==0 ? 0 : pSorter
->aIdx
[iPhrase
-1]);
2317 n
= pSorter
->aIdx
[iPhrase
] - i1
;
2318 pIter
->a
= &pSorter
->aPoslist
[i1
];
2320 rc
= sqlite3Fts5ExprPhraseCollist(pCsr
->pExpr
, iPhrase
, &pIter
->a
, &n
);
2322 if( rc
==SQLITE_OK
){
2323 assert( pIter
->a
|| n
==0 );
2324 pIter
->b
= (pIter
->a
? &pIter
->a
[n
] : 0);
2326 fts5ApiPhraseNextColumn(pCtx
, pIter
, piCol
);
2330 rc
= fts5CsrPoslist(pCsr
, iPhrase
, &pIter
->a
, &n
);
2331 if( rc
==SQLITE_OK
){
2332 assert( pIter
->a
|| n
==0 );
2333 pIter
->b
= (pIter
->a
? &pIter
->a
[n
] : 0);
2336 }else if( pIter
->a
[0]==0x01 ){
2337 pIter
->a
+= 1 + fts5GetVarint32(&pIter
->a
[1], *piCol
);
2348 ** xQueryToken() API implemenetation.
2350 static int fts5ApiQueryToken(
2357 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2358 return sqlite3Fts5ExprQueryToken(pCsr
->pExpr
, iPhrase
, iToken
, ppOut
, pnOut
);
2362 ** xInstToken() API implemenetation.
2364 static int fts5ApiInstToken(
2368 const char **ppOut
, int *pnOut
2370 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2372 if( CsrFlagTest(pCsr
, FTS5CSR_REQUIRE_INST
)==0
2373 || SQLITE_OK
==(rc
= fts5CacheInstArray(pCsr
))
2375 if( iIdx
<0 || iIdx
>=pCsr
->nInstCount
){
2378 int iPhrase
= pCsr
->aInst
[iIdx
*3];
2379 int iCol
= pCsr
->aInst
[iIdx
*3 + 1];
2380 int iOff
= pCsr
->aInst
[iIdx
*3 + 2];
2381 i64 iRowid
= fts5CursorRowid(pCsr
);
2382 rc
= sqlite3Fts5ExprInstToken(
2383 pCsr
->pExpr
, iRowid
, iPhrase
, iCol
, iOff
, iToken
, ppOut
, pnOut
2391 static int fts5ApiQueryPhrase(Fts5Context
*, int, void*,
2392 int(*)(const Fts5ExtensionApi
*, Fts5Context
*, void*)
2395 static const Fts5ExtensionApi sFts5Api
= {
2400 fts5ApiColumnTotalSize
,
2414 fts5ApiPhraseFirstColumn
,
2415 fts5ApiPhraseNextColumn
,
2421 ** Implementation of API function xQueryPhrase().
2423 static int fts5ApiQueryPhrase(
2427 int(*xCallback
)(const Fts5ExtensionApi
*, Fts5Context
*, void*)
2429 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCtx
;
2430 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCsr
->base
.pVtab
);
2432 Fts5Cursor
*pNew
= 0;
2434 rc
= fts5OpenMethod(pCsr
->base
.pVtab
, (sqlite3_vtab_cursor
**)&pNew
);
2435 if( rc
==SQLITE_OK
){
2436 pNew
->ePlan
= FTS5_PLAN_MATCH
;
2437 pNew
->iFirstRowid
= SMALLEST_INT64
;
2438 pNew
->iLastRowid
= LARGEST_INT64
;
2439 pNew
->base
.pVtab
= (sqlite3_vtab
*)pTab
;
2440 rc
= sqlite3Fts5ExprClonePhrase(pCsr
->pExpr
, iPhrase
, &pNew
->pExpr
);
2443 if( rc
==SQLITE_OK
){
2444 for(rc
= fts5CursorFirst(pTab
, pNew
, 0);
2445 rc
==SQLITE_OK
&& CsrFlagTest(pNew
, FTS5CSR_EOF
)==0;
2446 rc
= fts5NextMethod((sqlite3_vtab_cursor
*)pNew
)
2448 rc
= xCallback(&sFts5Api
, (Fts5Context
*)pNew
, pUserData
);
2449 if( rc
!=SQLITE_OK
){
2450 if( rc
==SQLITE_DONE
) rc
= SQLITE_OK
;
2456 fts5CloseMethod((sqlite3_vtab_cursor
*)pNew
);
2460 static void fts5ApiInvoke(
2461 Fts5Auxiliary
*pAux
,
2463 sqlite3_context
*context
,
2465 sqlite3_value
**argv
2467 assert( pCsr
->pAux
==0 );
2469 pAux
->xFunc(&sFts5Api
, (Fts5Context
*)pCsr
, context
, argc
, argv
);
2473 static Fts5Cursor
*fts5CursorFromCsrid(Fts5Global
*pGlobal
, i64 iCsrId
){
2475 for(pCsr
=pGlobal
->pCsr
; pCsr
; pCsr
=pCsr
->pNext
){
2476 if( pCsr
->iCsrId
==iCsrId
) break;
2481 static void fts5ApiCallback(
2482 sqlite3_context
*context
,
2484 sqlite3_value
**argv
2487 Fts5Auxiliary
*pAux
;
2492 pAux
= (Fts5Auxiliary
*)sqlite3_user_data(context
);
2493 iCsrId
= sqlite3_value_int64(argv
[0]);
2495 pCsr
= fts5CursorFromCsrid(pAux
->pGlobal
, iCsrId
);
2496 if( pCsr
==0 || pCsr
->ePlan
==0 ){
2497 char *zErr
= sqlite3_mprintf("no such cursor: %lld", iCsrId
);
2498 sqlite3_result_error(context
, zErr
, -1);
2501 fts5ApiInvoke(pAux
, pCsr
, context
, argc
-1, &argv
[1]);
2507 ** Given cursor id iId, return a pointer to the corresponding Fts5Table
2508 ** object. Or NULL If the cursor id does not exist.
2510 Fts5Table
*sqlite3Fts5TableFromCsrid(
2511 Fts5Global
*pGlobal
, /* FTS5 global context for db handle */
2512 i64 iCsrId
/* Id of cursor to find */
2515 pCsr
= fts5CursorFromCsrid(pGlobal
, iCsrId
);
2517 return (Fts5Table
*)pCsr
->base
.pVtab
;
2523 ** Return a "position-list blob" corresponding to the current position of
2524 ** cursor pCsr via sqlite3_result_blob(). A position-list blob contains
2525 ** the current position-list for each phrase in the query associated with
2528 ** A position-list blob begins with (nPhrase-1) varints, where nPhrase is
2529 ** the number of phrases in the query. Following the varints are the
2530 ** concatenated position lists for each phrase, in order.
2532 ** The first varint (if it exists) contains the size of the position list
2533 ** for phrase 0. The second (same disclaimer) contains the size of position
2534 ** list 1. And so on. There is no size field for the final position list,
2535 ** as it can be derived from the total size of the blob.
2537 static int fts5PoslistBlob(sqlite3_context
*pCtx
, Fts5Cursor
*pCsr
){
2540 int nPhrase
= sqlite3Fts5ExprPhraseCount(pCsr
->pExpr
);
2543 memset(&val
, 0, sizeof(Fts5Buffer
));
2544 switch( ((Fts5Table
*)(pCsr
->base
.pVtab
))->pConfig
->eDetail
){
2545 case FTS5_DETAIL_FULL
:
2547 /* Append the varints */
2548 for(i
=0; i
<(nPhrase
-1); i
++){
2550 int nByte
= sqlite3Fts5ExprPoslist(pCsr
->pExpr
, i
, &dummy
);
2551 sqlite3Fts5BufferAppendVarint(&rc
, &val
, nByte
);
2554 /* Append the position lists */
2555 for(i
=0; i
<nPhrase
; i
++){
2558 nPoslist
= sqlite3Fts5ExprPoslist(pCsr
->pExpr
, i
, &pPoslist
);
2559 sqlite3Fts5BufferAppendBlob(&rc
, &val
, nPoslist
, pPoslist
);
2563 case FTS5_DETAIL_COLUMNS
:
2565 /* Append the varints */
2566 for(i
=0; rc
==SQLITE_OK
&& i
<(nPhrase
-1); i
++){
2569 rc
= sqlite3Fts5ExprPhraseCollist(pCsr
->pExpr
, i
, &dummy
, &nByte
);
2570 sqlite3Fts5BufferAppendVarint(&rc
, &val
, nByte
);
2573 /* Append the position lists */
2574 for(i
=0; rc
==SQLITE_OK
&& i
<nPhrase
; i
++){
2577 rc
= sqlite3Fts5ExprPhraseCollist(pCsr
->pExpr
, i
, &pPoslist
, &nPoslist
);
2578 sqlite3Fts5BufferAppendBlob(&rc
, &val
, nPoslist
, pPoslist
);
2586 sqlite3_result_blob(pCtx
, val
.p
, val
.n
, sqlite3_free
);
2591 ** This is the xColumn method, called by SQLite to request a value from
2592 ** the row that the supplied cursor currently points to.
2594 static int fts5ColumnMethod(
2595 sqlite3_vtab_cursor
*pCursor
, /* Cursor to retrieve value from */
2596 sqlite3_context
*pCtx
, /* Context for sqlite3_result_xxx() calls */
2597 int iCol
/* Index of column to read value from */
2599 Fts5FullTable
*pTab
= (Fts5FullTable
*)(pCursor
->pVtab
);
2600 Fts5Config
*pConfig
= pTab
->p
.pConfig
;
2601 Fts5Cursor
*pCsr
= (Fts5Cursor
*)pCursor
;
2604 assert( CsrFlagTest(pCsr
, FTS5CSR_EOF
)==0 );
2606 if( pCsr
->ePlan
==FTS5_PLAN_SPECIAL
){
2607 if( iCol
==pConfig
->nCol
){
2608 sqlite3_result_int64(pCtx
, pCsr
->iSpecial
);
2612 if( iCol
==pConfig
->nCol
){
2613 /* User is requesting the value of the special column with the same name
2614 ** as the table. Return the cursor integer id number. This value is only
2615 ** useful in that it may be passed as the first argument to an FTS5
2616 ** auxiliary function. */
2617 sqlite3_result_int64(pCtx
, pCsr
->iCsrId
);
2618 }else if( iCol
==pConfig
->nCol
+1 ){
2620 /* The value of the "rank" column. */
2621 if( pCsr
->ePlan
==FTS5_PLAN_SOURCE
){
2622 fts5PoslistBlob(pCtx
, pCsr
);
2624 pCsr
->ePlan
==FTS5_PLAN_MATCH
2625 || pCsr
->ePlan
==FTS5_PLAN_SORTED_MATCH
2627 if( pCsr
->pRank
|| SQLITE_OK
==(rc
= fts5FindRankFunction(pCsr
)) ){
2628 fts5ApiInvoke(pCsr
->pRank
, pCsr
, pCtx
, pCsr
->nRankArg
, pCsr
->apRankArg
);
2631 }else if( !fts5IsContentless(pTab
) ){
2632 pConfig
->pzErrmsg
= &pTab
->p
.base
.zErrMsg
;
2633 rc
= fts5SeekCursor(pCsr
, 1);
2634 if( rc
==SQLITE_OK
){
2635 sqlite3_result_value(pCtx
, sqlite3_column_value(pCsr
->pStmt
, iCol
+1));
2637 pConfig
->pzErrmsg
= 0;
2638 }else if( pConfig
->bContentlessDelete
&& sqlite3_vtab_nochange(pCtx
) ){
2639 char *zErr
= sqlite3_mprintf("cannot UPDATE a subset of "
2640 "columns on fts5 contentless-delete table: %s", pConfig
->zName
2642 sqlite3_result_error(pCtx
, zErr
, -1);
2650 ** This routine implements the xFindFunction method for the FTS3
2653 static int fts5FindFunctionMethod(
2654 sqlite3_vtab
*pVtab
, /* Virtual table handle */
2655 int nUnused
, /* Number of SQL function arguments */
2656 const char *zName
, /* Name of SQL function */
2657 void (**pxFunc
)(sqlite3_context
*,int,sqlite3_value
**), /* OUT: Result */
2658 void **ppArg
/* OUT: User data for *pxFunc */
2660 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
2661 Fts5Auxiliary
*pAux
;
2663 UNUSED_PARAM(nUnused
);
2664 pAux
= fts5FindAuxiliary(pTab
, zName
);
2666 *pxFunc
= fts5ApiCallback
;
2667 *ppArg
= (void*)pAux
;
2671 /* No function of the specified name was found. Return 0. */
2676 ** Implementation of FTS5 xRename method. Rename an fts5 table.
2678 static int fts5RenameMethod(
2679 sqlite3_vtab
*pVtab
, /* Virtual table handle */
2680 const char *zName
/* New name of table */
2683 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
2684 rc
= sqlite3Fts5StorageRename(pTab
->pStorage
, zName
);
2688 int sqlite3Fts5FlushToDisk(Fts5Table
*pTab
){
2689 fts5TripCursors((Fts5FullTable
*)pTab
);
2690 return sqlite3Fts5StorageSync(((Fts5FullTable
*)pTab
)->pStorage
);
2694 ** The xSavepoint() method.
2696 ** Flush the contents of the pending-terms table to disk.
2698 static int fts5SavepointMethod(sqlite3_vtab
*pVtab
, int iSavepoint
){
2699 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
2702 fts5CheckTransactionState(pTab
, FTS5_SAVEPOINT
, iSavepoint
);
2703 rc
= sqlite3Fts5FlushToDisk((Fts5Table
*)pVtab
);
2704 if( rc
==SQLITE_OK
){
2705 pTab
->iSavepoint
= iSavepoint
+1;
2711 ** The xRelease() method.
2715 static int fts5ReleaseMethod(sqlite3_vtab
*pVtab
, int iSavepoint
){
2716 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
2718 fts5CheckTransactionState(pTab
, FTS5_RELEASE
, iSavepoint
);
2719 if( (iSavepoint
+1)<pTab
->iSavepoint
){
2720 rc
= sqlite3Fts5FlushToDisk(&pTab
->p
);
2721 if( rc
==SQLITE_OK
){
2722 pTab
->iSavepoint
= iSavepoint
;
2729 ** The xRollbackTo() method.
2731 ** Discard the contents of the pending terms table.
2733 static int fts5RollbackToMethod(sqlite3_vtab
*pVtab
, int iSavepoint
){
2734 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
2736 fts5CheckTransactionState(pTab
, FTS5_ROLLBACKTO
, iSavepoint
);
2737 fts5TripCursors(pTab
);
2738 if( (iSavepoint
+1)<=pTab
->iSavepoint
){
2739 pTab
->p
.pConfig
->pgsz
= 0;
2740 rc
= sqlite3Fts5StorageRollback(pTab
->pStorage
);
2746 ** Register a new auxiliary function with global context pGlobal.
2748 static int fts5CreateAux(
2749 fts5_api
*pApi
, /* Global context (one per db handle) */
2750 const char *zName
, /* Name of new function */
2751 void *pUserData
, /* User data for aux. function */
2752 fts5_extension_function xFunc
, /* Aux. function implementation */
2753 void(*xDestroy
)(void*) /* Destructor for pUserData */
2755 Fts5Global
*pGlobal
= (Fts5Global
*)pApi
;
2756 int rc
= sqlite3_overload_function(pGlobal
->db
, zName
, -1);
2757 if( rc
==SQLITE_OK
){
2758 Fts5Auxiliary
*pAux
;
2759 sqlite3_int64 nName
; /* Size of zName in bytes, including \0 */
2760 sqlite3_int64 nByte
; /* Bytes of space to allocate */
2762 nName
= strlen(zName
) + 1;
2763 nByte
= sizeof(Fts5Auxiliary
) + nName
;
2764 pAux
= (Fts5Auxiliary
*)sqlite3_malloc64(nByte
);
2766 memset(pAux
, 0, (size_t)nByte
);
2767 pAux
->zFunc
= (char*)&pAux
[1];
2768 memcpy(pAux
->zFunc
, zName
, nName
);
2769 pAux
->pGlobal
= pGlobal
;
2770 pAux
->pUserData
= pUserData
;
2771 pAux
->xFunc
= xFunc
;
2772 pAux
->xDestroy
= xDestroy
;
2773 pAux
->pNext
= pGlobal
->pAux
;
2774 pGlobal
->pAux
= pAux
;
2784 ** Register a new tokenizer. This is the implementation of the
2785 ** fts5_api.xCreateTokenizer() method.
2787 static int fts5CreateTokenizer(
2788 fts5_api
*pApi
, /* Global context (one per db handle) */
2789 const char *zName
, /* Name of new function */
2790 void *pUserData
, /* User data for aux. function */
2791 fts5_tokenizer
*pTokenizer
, /* Tokenizer implementation */
2792 void(*xDestroy
)(void*) /* Destructor for pUserData */
2794 Fts5Global
*pGlobal
= (Fts5Global
*)pApi
;
2795 Fts5TokenizerModule
*pNew
;
2796 sqlite3_int64 nName
; /* Size of zName and its \0 terminator */
2797 sqlite3_int64 nByte
; /* Bytes of space to allocate */
2800 nName
= strlen(zName
) + 1;
2801 nByte
= sizeof(Fts5TokenizerModule
) + nName
;
2802 pNew
= (Fts5TokenizerModule
*)sqlite3_malloc64(nByte
);
2804 memset(pNew
, 0, (size_t)nByte
);
2805 pNew
->zName
= (char*)&pNew
[1];
2806 memcpy(pNew
->zName
, zName
, nName
);
2807 pNew
->pUserData
= pUserData
;
2808 pNew
->x
= *pTokenizer
;
2809 pNew
->xDestroy
= xDestroy
;
2810 pNew
->pNext
= pGlobal
->pTok
;
2811 pGlobal
->pTok
= pNew
;
2812 if( pNew
->pNext
==0 ){
2813 pGlobal
->pDfltTok
= pNew
;
2822 static Fts5TokenizerModule
*fts5LocateTokenizer(
2823 Fts5Global
*pGlobal
,
2826 Fts5TokenizerModule
*pMod
= 0;
2829 pMod
= pGlobal
->pDfltTok
;
2831 for(pMod
=pGlobal
->pTok
; pMod
; pMod
=pMod
->pNext
){
2832 if( sqlite3_stricmp(zName
, pMod
->zName
)==0 ) break;
2840 ** Find a tokenizer. This is the implementation of the
2841 ** fts5_api.xFindTokenizer() method.
2843 static int fts5FindTokenizer(
2844 fts5_api
*pApi
, /* Global context (one per db handle) */
2845 const char *zName
, /* Name of new function */
2847 fts5_tokenizer
*pTokenizer
/* Populate this object */
2850 Fts5TokenizerModule
*pMod
;
2852 pMod
= fts5LocateTokenizer((Fts5Global
*)pApi
, zName
);
2854 *pTokenizer
= pMod
->x
;
2855 *ppUserData
= pMod
->pUserData
;
2857 memset(pTokenizer
, 0, sizeof(fts5_tokenizer
));
2864 int sqlite3Fts5GetTokenizer(
2865 Fts5Global
*pGlobal
,
2868 Fts5Config
*pConfig
,
2871 Fts5TokenizerModule
*pMod
;
2874 pMod
= fts5LocateTokenizer(pGlobal
, nArg
==0 ? 0 : azArg
[0]);
2878 if( pzErr
) *pzErr
= sqlite3_mprintf("no such tokenizer: %s", azArg
[0]);
2880 rc
= pMod
->x
.xCreate(
2881 pMod
->pUserData
, (azArg
?&azArg
[1]:0), (nArg
?nArg
-1:0), &pConfig
->pTok
2883 pConfig
->pTokApi
= &pMod
->x
;
2884 if( rc
!=SQLITE_OK
){
2885 if( pzErr
&& rc
!=SQLITE_NOMEM
){
2886 *pzErr
= sqlite3_mprintf("error in tokenizer constructor");
2889 pConfig
->ePattern
= sqlite3Fts5TokenizerPattern(
2890 pMod
->x
.xCreate
, pConfig
->pTok
2895 if( rc
!=SQLITE_OK
){
2896 pConfig
->pTokApi
= 0;
2903 static void fts5ModuleDestroy(void *pCtx
){
2904 Fts5TokenizerModule
*pTok
, *pNextTok
;
2905 Fts5Auxiliary
*pAux
, *pNextAux
;
2906 Fts5Global
*pGlobal
= (Fts5Global
*)pCtx
;
2908 for(pAux
=pGlobal
->pAux
; pAux
; pAux
=pNextAux
){
2909 pNextAux
= pAux
->pNext
;
2910 if( pAux
->xDestroy
) pAux
->xDestroy(pAux
->pUserData
);
2914 for(pTok
=pGlobal
->pTok
; pTok
; pTok
=pNextTok
){
2915 pNextTok
= pTok
->pNext
;
2916 if( pTok
->xDestroy
) pTok
->xDestroy(pTok
->pUserData
);
2920 sqlite3_free(pGlobal
);
2923 static void fts5Fts5Func(
2924 sqlite3_context
*pCtx
, /* Function call context */
2925 int nArg
, /* Number of args */
2926 sqlite3_value
**apArg
/* Function arguments */
2928 Fts5Global
*pGlobal
= (Fts5Global
*)sqlite3_user_data(pCtx
);
2932 ppApi
= (fts5_api
**)sqlite3_value_pointer(apArg
[0], "fts5_api_ptr");
2933 if( ppApi
) *ppApi
= &pGlobal
->api
;
2937 ** Implementation of fts5_source_id() function.
2939 static void fts5SourceIdFunc(
2940 sqlite3_context
*pCtx
, /* Function call context */
2941 int nArg
, /* Number of args */
2942 sqlite3_value
**apUnused
/* Function arguments */
2945 UNUSED_PARAM2(nArg
, apUnused
);
2946 sqlite3_result_text(pCtx
, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT
);
2950 ** Return true if zName is the extension on one of the shadow tables used
2953 static int fts5ShadowName(const char *zName
){
2954 static const char *azName
[] = {
2955 "config", "content", "data", "docsize", "idx"
2958 for(i
=0; i
<sizeof(azName
)/sizeof(azName
[0]); i
++){
2959 if( sqlite3_stricmp(zName
, azName
[i
])==0 ) return 1;
2965 ** Run an integrity check on the FTS5 data structures. Return a string
2966 ** if anything is found amiss. Return a NULL pointer if everything is
2969 static int fts5IntegrityMethod(
2970 sqlite3_vtab
*pVtab
, /* the FTS5 virtual table to check */
2971 const char *zSchema
, /* Name of schema in which this table lives */
2972 const char *zTabname
, /* Name of the table itself */
2973 int isQuick
, /* True if this is a quick-check */
2974 char **pzErr
/* Write error message here */
2976 Fts5FullTable
*pTab
= (Fts5FullTable
*)pVtab
;
2979 assert( pzErr
!=0 && *pzErr
==0 );
2980 UNUSED_PARAM(isQuick
);
2981 assert( pTab
->p
.pConfig
->pzErrmsg
==0 );
2982 pTab
->p
.pConfig
->pzErrmsg
= pzErr
;
2983 rc
= sqlite3Fts5StorageIntegrity(pTab
->pStorage
, 0);
2984 if( *pzErr
==0 && rc
!=SQLITE_OK
){
2985 if( (rc
&0xff)==SQLITE_CORRUPT
){
2986 *pzErr
= sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
2988 rc
= (*pzErr
) ? SQLITE_OK
: SQLITE_NOMEM
;
2990 *pzErr
= sqlite3_mprintf("unable to validate the inverted index for"
2991 " FTS5 table %s.%s: %s",
2992 zSchema
, zTabname
, sqlite3_errstr(rc
));
2996 sqlite3Fts5IndexCloseReader(pTab
->p
.pIndex
);
2997 pTab
->p
.pConfig
->pzErrmsg
= 0;
3002 static int fts5Init(sqlite3
*db
){
3003 static const sqlite3_module fts5Mod
= {
3005 /* xCreate */ fts5CreateMethod
,
3006 /* xConnect */ fts5ConnectMethod
,
3007 /* xBestIndex */ fts5BestIndexMethod
,
3008 /* xDisconnect */ fts5DisconnectMethod
,
3009 /* xDestroy */ fts5DestroyMethod
,
3010 /* xOpen */ fts5OpenMethod
,
3011 /* xClose */ fts5CloseMethod
,
3012 /* xFilter */ fts5FilterMethod
,
3013 /* xNext */ fts5NextMethod
,
3014 /* xEof */ fts5EofMethod
,
3015 /* xColumn */ fts5ColumnMethod
,
3016 /* xRowid */ fts5RowidMethod
,
3017 /* xUpdate */ fts5UpdateMethod
,
3018 /* xBegin */ fts5BeginMethod
,
3019 /* xSync */ fts5SyncMethod
,
3020 /* xCommit */ fts5CommitMethod
,
3021 /* xRollback */ fts5RollbackMethod
,
3022 /* xFindFunction */ fts5FindFunctionMethod
,
3023 /* xRename */ fts5RenameMethod
,
3024 /* xSavepoint */ fts5SavepointMethod
,
3025 /* xRelease */ fts5ReleaseMethod
,
3026 /* xRollbackTo */ fts5RollbackToMethod
,
3027 /* xShadowName */ fts5ShadowName
,
3028 /* xIntegrity */ fts5IntegrityMethod
3032 Fts5Global
*pGlobal
= 0;
3034 pGlobal
= (Fts5Global
*)sqlite3_malloc(sizeof(Fts5Global
));
3038 void *p
= (void*)pGlobal
;
3039 memset(pGlobal
, 0, sizeof(Fts5Global
));
3041 pGlobal
->api
.iVersion
= 2;
3042 pGlobal
->api
.xCreateFunction
= fts5CreateAux
;
3043 pGlobal
->api
.xCreateTokenizer
= fts5CreateTokenizer
;
3044 pGlobal
->api
.xFindTokenizer
= fts5FindTokenizer
;
3045 rc
= sqlite3_create_module_v2(db
, "fts5", &fts5Mod
, p
, fts5ModuleDestroy
);
3046 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5IndexInit(db
);
3047 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5ExprInit(pGlobal
, db
);
3048 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5AuxInit(&pGlobal
->api
);
3049 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5TokenizerInit(&pGlobal
->api
);
3050 if( rc
==SQLITE_OK
) rc
= sqlite3Fts5VocabInit(pGlobal
, db
);
3051 if( rc
==SQLITE_OK
){
3052 rc
= sqlite3_create_function(
3053 db
, "fts5", 1, SQLITE_UTF8
, p
, fts5Fts5Func
, 0, 0
3056 if( rc
==SQLITE_OK
){
3057 rc
= sqlite3_create_function(
3058 db
, "fts5_source_id", 0,
3059 SQLITE_UTF8
|SQLITE_DETERMINISTIC
|SQLITE_INNOCUOUS
,
3060 p
, fts5SourceIdFunc
, 0, 0
3065 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
3066 ** fts5_test_mi.c is compiled and linked into the executable. And call
3067 ** its entry point to enable the matchinfo() demo. */
3068 #ifdef SQLITE_FTS5_ENABLE_TEST_MI
3069 if( rc
==SQLITE_OK
){
3070 extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3
*);
3071 rc
= sqlite3Fts5TestRegisterMatchinfo(db
);
3079 ** The following functions are used to register the module with SQLite. If
3080 ** this module is being built as part of the SQLite core (SQLITE_CORE is
3081 ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
3083 ** Or, if this module is being built as a loadable extension,
3084 ** sqlite3Fts5Init() is omitted and the two standard entry points
3085 ** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
3089 __declspec(dllexport
)
3091 int sqlite3_fts_init(
3094 const sqlite3_api_routines
*pApi
3096 SQLITE_EXTENSION_INIT2(pApi
);
3097 (void)pzErrMsg
; /* Unused parameter */
3098 return fts5Init(db
);
3102 __declspec(dllexport
)
3104 int sqlite3_fts5_init(
3107 const sqlite3_api_routines
*pApi
3109 SQLITE_EXTENSION_INIT2(pApi
);
3110 (void)pzErrMsg
; /* Unused parameter */
3111 return fts5Init(db
);
3114 int sqlite3Fts5Init(sqlite3
*db
){
3115 return fts5Init(db
);