Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_main.c

Issue 1610543003: [sql] Import reference version of SQLite 3.10.2. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 ** 2014 Jun 09
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
10 **
11 ******************************************************************************
12 **
13 ** This is an SQLite module implementing full-text search.
14 */
15
16
17 #include "fts5Int.h"
18
19 /*
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.
24 */
25 int sqlite3_fts5_may_be_corrupt = 1;
26
27
28 typedef struct Fts5Auxdata Fts5Auxdata;
29 typedef struct Fts5Auxiliary Fts5Auxiliary;
30 typedef struct Fts5Cursor Fts5Cursor;
31 typedef struct Fts5Sorter Fts5Sorter;
32 typedef struct Fts5Table Fts5Table;
33 typedef struct Fts5TokenizerModule Fts5TokenizerModule;
34
35 /*
36 ** NOTES ON TRANSACTIONS:
37 **
38 ** SQLite invokes the following virtual table methods as transactions are
39 ** opened and closed by the user:
40 **
41 ** xBegin(): Start of a new transaction.
42 ** xSync(): Initial part of two-phase commit.
43 ** xCommit(): Final part of two-phase commit.
44 ** xRollback(): Rollback the transaction.
45 **
46 ** Anything that is required as part of a commit that may fail is performed
47 ** in the xSync() callback. Current versions of SQLite ignore any errors
48 ** returned by xCommit().
49 **
50 ** And as sub-transactions are opened/closed:
51 **
52 ** xSavepoint(int S): Open savepoint S.
53 ** xRelease(int S): Commit and close savepoint S.
54 ** xRollbackTo(int S): Rollback to start of savepoint S.
55 **
56 ** During a write-transaction the fts5_index.c module may cache some data
57 ** in-memory. It is flushed to disk whenever xSync(), xRelease() or
58 ** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
59 ** is called.
60 **
61 ** Additionally, if SQLITE_DEBUG is defined, an instance of the following
62 ** structure is used to record the current transaction state. This information
63 ** is not required, but it is used in the assert() statements executed by
64 ** function fts5CheckTransactionState() (see below).
65 */
66 struct Fts5TransactionState {
67 int eState; /* 0==closed, 1==open, 2==synced */
68 int iSavepoint; /* Number of open savepoints (0 -> none) */
69 };
70
71 /*
72 ** A single object of this type is allocated when the FTS5 module is
73 ** registered with a database handle. It is used to store pointers to
74 ** all registered FTS5 extensions - tokenizers and auxiliary functions.
75 */
76 struct Fts5Global {
77 fts5_api api; /* User visible part of object (see fts5.h) */
78 sqlite3 *db; /* Associated database connection */
79 i64 iNextId; /* Used to allocate unique cursor ids */
80 Fts5Auxiliary *pAux; /* First in list of all aux. functions */
81 Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
82 Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
83 Fts5Cursor *pCsr; /* First in list of all open cursors */
84 };
85
86 /*
87 ** Each auxiliary function registered with the FTS5 module is represented
88 ** by an object of the following type. All such objects are stored as part
89 ** of the Fts5Global.pAux list.
90 */
91 struct Fts5Auxiliary {
92 Fts5Global *pGlobal; /* Global context for this function */
93 char *zFunc; /* Function name (nul-terminated) */
94 void *pUserData; /* User-data pointer */
95 fts5_extension_function xFunc; /* Callback function */
96 void (*xDestroy)(void*); /* Destructor function */
97 Fts5Auxiliary *pNext; /* Next registered auxiliary function */
98 };
99
100 /*
101 ** Each tokenizer module registered with the FTS5 module is represented
102 ** by an object of the following type. All such objects are stored as part
103 ** of the Fts5Global.pTok list.
104 */
105 struct Fts5TokenizerModule {
106 char *zName; /* Name of tokenizer */
107 void *pUserData; /* User pointer passed to xCreate() */
108 fts5_tokenizer x; /* Tokenizer functions */
109 void (*xDestroy)(void*); /* Destructor function */
110 Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
111 };
112
113 /*
114 ** Virtual-table object.
115 */
116 struct Fts5Table {
117 sqlite3_vtab base; /* Base class used by SQLite core */
118 Fts5Config *pConfig; /* Virtual table configuration */
119 Fts5Index *pIndex; /* Full-text index */
120 Fts5Storage *pStorage; /* Document store */
121 Fts5Global *pGlobal; /* Global (connection wide) data */
122 Fts5Cursor *pSortCsr; /* Sort data from this cursor */
123 #ifdef SQLITE_DEBUG
124 struct Fts5TransactionState ts;
125 #endif
126 };
127
128 struct Fts5MatchPhrase {
129 Fts5Buffer *pPoslist; /* Pointer to current poslist */
130 int nTerm; /* Size of phrase in terms */
131 };
132
133 /*
134 ** pStmt:
135 ** SELECT rowid, <fts> FROM <fts> ORDER BY +rank;
136 **
137 ** aIdx[]:
138 ** There is one entry in the aIdx[] array for each phrase in the query,
139 ** the value of which is the offset within aPoslist[] following the last
140 ** byte of the position list for the corresponding phrase.
141 */
142 struct Fts5Sorter {
143 sqlite3_stmt *pStmt;
144 i64 iRowid; /* Current rowid */
145 const u8 *aPoslist; /* Position lists for current row */
146 int nIdx; /* Number of entries in aIdx[] */
147 int aIdx[1]; /* Offsets into aPoslist for current row */
148 };
149
150
151 /*
152 ** Virtual-table cursor object.
153 **
154 ** iSpecial:
155 ** If this is a 'special' query (refer to function fts5SpecialMatch()),
156 ** then this variable contains the result of the query.
157 **
158 ** iFirstRowid, iLastRowid:
159 ** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
160 ** cursor iterates in ascending order of rowids, iFirstRowid is the lower
161 ** limit of rowids to return, and iLastRowid the upper. In other words, the
162 ** WHERE clause in the user's query might have been:
163 **
164 ** <tbl> MATCH <expr> AND rowid BETWEEN $iFirstRowid AND $iLastRowid
165 **
166 ** If the cursor iterates in descending order of rowid, iFirstRowid
167 ** is the upper limit (i.e. the "first" rowid visited) and iLastRowid
168 ** the lower.
169 */
170 struct Fts5Cursor {
171 sqlite3_vtab_cursor base; /* Base class used by SQLite core */
172 Fts5Cursor *pNext; /* Next cursor in Fts5Cursor.pCsr list */
173 int *aColumnSize; /* Values for xColumnSize() */
174 i64 iCsrId; /* Cursor id */
175
176 /* Zero from this point onwards on cursor reset */
177 int ePlan; /* FTS5_PLAN_XXX value */
178 int bDesc; /* True for "ORDER BY rowid DESC" queries */
179 i64 iFirstRowid; /* Return no rowids earlier than this */
180 i64 iLastRowid; /* Return no rowids later than this */
181 sqlite3_stmt *pStmt; /* Statement used to read %_content */
182 Fts5Expr *pExpr; /* Expression for MATCH queries */
183 Fts5Sorter *pSorter; /* Sorter for "ORDER BY rank" queries */
184 int csrflags; /* Mask of cursor flags (see below) */
185 i64 iSpecial; /* Result of special query */
186
187 /* "rank" function. Populated on demand from vtab.xColumn(). */
188 char *zRank; /* Custom rank function */
189 char *zRankArgs; /* Custom rank function args */
190 Fts5Auxiliary *pRank; /* Rank callback (or NULL) */
191 int nRankArg; /* Number of trailing arguments for rank() */
192 sqlite3_value **apRankArg; /* Array of trailing arguments */
193 sqlite3_stmt *pRankArgStmt; /* Origin of objects in apRankArg[] */
194
195 /* Auxiliary data storage */
196 Fts5Auxiliary *pAux; /* Currently executing extension function */
197 Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
198
199 /* Cache used by auxiliary functions xInst() and xInstCount() */
200 Fts5PoslistReader *aInstIter; /* One for each phrase */
201 int nInstAlloc; /* Size of aInst[] array (entries / 3) */
202 int nInstCount; /* Number of phrase instances */
203 int *aInst; /* 3 integers per phrase instance */
204 };
205
206 /*
207 ** Bits that make up the "idxNum" parameter passed indirectly by
208 ** xBestIndex() to xFilter().
209 */
210 #define FTS5_BI_MATCH 0x0001 /* <tbl> MATCH ? */
211 #define FTS5_BI_RANK 0x0002 /* rank MATCH ? */
212 #define FTS5_BI_ROWID_EQ 0x0004 /* rowid == ? */
213 #define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */
214 #define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */
215
216 #define FTS5_BI_ORDER_RANK 0x0020
217 #define FTS5_BI_ORDER_ROWID 0x0040
218 #define FTS5_BI_ORDER_DESC 0x0080
219
220 /*
221 ** Values for Fts5Cursor.csrflags
222 */
223 #define FTS5CSR_REQUIRE_CONTENT 0x01
224 #define FTS5CSR_REQUIRE_DOCSIZE 0x02
225 #define FTS5CSR_REQUIRE_INST 0x04
226 #define FTS5CSR_EOF 0x08
227 #define FTS5CSR_FREE_ZRANK 0x10
228 #define FTS5CSR_REQUIRE_RESEEK 0x20
229
230 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
231 #define BitFlagTest(x,y) (((x) & (y))!=0)
232
233
234 /*
235 ** Macros to Set(), Clear() and Test() cursor flags.
236 */
237 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
238 #define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag))
239 #define CsrFlagTest(pCsr, flag) ((pCsr)->csrflags & (flag))
240
241 struct Fts5Auxdata {
242 Fts5Auxiliary *pAux; /* Extension to which this belongs */
243 void *pPtr; /* Pointer value */
244 void(*xDelete)(void*); /* Destructor */
245 Fts5Auxdata *pNext; /* Next object in linked list */
246 };
247
248 #ifdef SQLITE_DEBUG
249 #define FTS5_BEGIN 1
250 #define FTS5_SYNC 2
251 #define FTS5_COMMIT 3
252 #define FTS5_ROLLBACK 4
253 #define FTS5_SAVEPOINT 5
254 #define FTS5_RELEASE 6
255 #define FTS5_ROLLBACKTO 7
256 static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
257 switch( op ){
258 case FTS5_BEGIN:
259 assert( p->ts.eState==0 );
260 p->ts.eState = 1;
261 p->ts.iSavepoint = -1;
262 break;
263
264 case FTS5_SYNC:
265 assert( p->ts.eState==1 );
266 p->ts.eState = 2;
267 break;
268
269 case FTS5_COMMIT:
270 assert( p->ts.eState==2 );
271 p->ts.eState = 0;
272 break;
273
274 case FTS5_ROLLBACK:
275 assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 );
276 p->ts.eState = 0;
277 break;
278
279 case FTS5_SAVEPOINT:
280 assert( p->ts.eState==1 );
281 assert( iSavepoint>=0 );
282 assert( iSavepoint>p->ts.iSavepoint );
283 p->ts.iSavepoint = iSavepoint;
284 break;
285
286 case FTS5_RELEASE:
287 assert( p->ts.eState==1 );
288 assert( iSavepoint>=0 );
289 assert( iSavepoint<=p->ts.iSavepoint );
290 p->ts.iSavepoint = iSavepoint-1;
291 break;
292
293 case FTS5_ROLLBACKTO:
294 assert( p->ts.eState==1 );
295 assert( iSavepoint>=0 );
296 assert( iSavepoint<=p->ts.iSavepoint );
297 p->ts.iSavepoint = iSavepoint;
298 break;
299 }
300 }
301 #else
302 # define fts5CheckTransactionState(x,y,z)
303 #endif
304
305 /*
306 ** Return true if pTab is a contentless table.
307 */
308 static int fts5IsContentless(Fts5Table *pTab){
309 return pTab->pConfig->eContent==FTS5_CONTENT_NONE;
310 }
311
312 /*
313 ** Delete a virtual table handle allocated by fts5InitVtab().
314 */
315 static void fts5FreeVtab(Fts5Table *pTab){
316 if( pTab ){
317 sqlite3Fts5IndexClose(pTab->pIndex);
318 sqlite3Fts5StorageClose(pTab->pStorage);
319 sqlite3Fts5ConfigFree(pTab->pConfig);
320 sqlite3_free(pTab);
321 }
322 }
323
324 /*
325 ** The xDisconnect() virtual table method.
326 */
327 static int fts5DisconnectMethod(sqlite3_vtab *pVtab){
328 fts5FreeVtab((Fts5Table*)pVtab);
329 return SQLITE_OK;
330 }
331
332 /*
333 ** The xDestroy() virtual table method.
334 */
335 static int fts5DestroyMethod(sqlite3_vtab *pVtab){
336 Fts5Table *pTab = (Fts5Table*)pVtab;
337 int rc = sqlite3Fts5DropAll(pTab->pConfig);
338 if( rc==SQLITE_OK ){
339 fts5FreeVtab((Fts5Table*)pVtab);
340 }
341 return rc;
342 }
343
344 /*
345 ** This function is the implementation of both the xConnect and xCreate
346 ** methods of the FTS3 virtual table.
347 **
348 ** The argv[] array contains the following:
349 **
350 ** argv[0] -> module name ("fts5")
351 ** argv[1] -> database name
352 ** argv[2] -> table name
353 ** argv[...] -> "column name" and other module argument fields.
354 */
355 static int fts5InitVtab(
356 int bCreate, /* True for xCreate, false for xConnect */
357 sqlite3 *db, /* The SQLite database connection */
358 void *pAux, /* Hash table containing tokenizers */
359 int argc, /* Number of elements in argv array */
360 const char * const *argv, /* xCreate/xConnect argument array */
361 sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
362 char **pzErr /* Write any error message here */
363 ){
364 Fts5Global *pGlobal = (Fts5Global*)pAux;
365 const char **azConfig = (const char**)argv;
366 int rc = SQLITE_OK; /* Return code */
367 Fts5Config *pConfig = 0; /* Results of parsing argc/argv */
368 Fts5Table *pTab = 0; /* New virtual table object */
369
370 /* Allocate the new vtab object and parse the configuration */
371 pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table));
372 if( rc==SQLITE_OK ){
373 rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
374 assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
375 }
376 if( rc==SQLITE_OK ){
377 pTab->pConfig = pConfig;
378 pTab->pGlobal = pGlobal;
379 }
380
381 /* Open the index sub-system */
382 if( rc==SQLITE_OK ){
383 rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr);
384 }
385
386 /* Open the storage sub-system */
387 if( rc==SQLITE_OK ){
388 rc = sqlite3Fts5StorageOpen(
389 pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr
390 );
391 }
392
393 /* Call sqlite3_declare_vtab() */
394 if( rc==SQLITE_OK ){
395 rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
396 }
397
398 /* Load the initial configuration */
399 if( rc==SQLITE_OK ){
400 assert( pConfig->pzErrmsg==0 );
401 pConfig->pzErrmsg = pzErr;
402 rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
403 sqlite3Fts5IndexRollback(pTab->pIndex);
404 pConfig->pzErrmsg = 0;
405 }
406
407 if( rc!=SQLITE_OK ){
408 fts5FreeVtab(pTab);
409 pTab = 0;
410 }else if( bCreate ){
411 fts5CheckTransactionState(pTab, FTS5_BEGIN, 0);
412 }
413 *ppVTab = (sqlite3_vtab*)pTab;
414 return rc;
415 }
416
417 /*
418 ** The xConnect() and xCreate() methods for the virtual table. All the
419 ** work is done in function fts5InitVtab().
420 */
421 static int fts5ConnectMethod(
422 sqlite3 *db, /* Database connection */
423 void *pAux, /* Pointer to tokenizer hash table */
424 int argc, /* Number of elements in argv array */
425 const char * const *argv, /* xCreate/xConnect argument array */
426 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
427 char **pzErr /* OUT: sqlite3_malloc'd error message */
428 ){
429 return fts5InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr);
430 }
431 static int fts5CreateMethod(
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 */
438 ){
439 return fts5InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr);
440 }
441
442 /*
443 ** The different query plans.
444 */
445 #define FTS5_PLAN_MATCH 1 /* (<tbl> MATCH ?) */
446 #define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */
447 #define FTS5_PLAN_SPECIAL 3 /* An internal query */
448 #define FTS5_PLAN_SORTED_MATCH 4 /* (<tbl> MATCH ? ORDER BY rank) */
449 #define FTS5_PLAN_SCAN 5 /* No usable constraint */
450 #define FTS5_PLAN_ROWID 6 /* (rowid = ?) */
451
452 /*
453 ** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
454 ** extension is currently being used by a version of SQLite too old to
455 ** support index-info flags. In that case this function is a no-op.
456 */
457 static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
458 #if SQLITE_VERSION_NUMBER>=3008012
459 #ifndef SQLITE_CORE
460 if( sqlite3_libversion_number()>=3008012 )
461 #endif
462 {
463 pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
464 }
465 #endif
466 }
467
468 /*
469 ** Implementation of the xBestIndex method for FTS5 tables. Within the
470 ** WHERE constraint, it searches for the following:
471 **
472 ** 1. A MATCH constraint against the special column.
473 ** 2. A MATCH constraint against the "rank" column.
474 ** 3. An == constraint against the rowid column.
475 ** 4. A < or <= constraint against the rowid column.
476 ** 5. A > or >= constraint against the rowid column.
477 **
478 ** Within the ORDER BY, either:
479 **
480 ** 5. ORDER BY rank [ASC|DESC]
481 ** 6. ORDER BY rowid [ASC|DESC]
482 **
483 ** Costs are assigned as follows:
484 **
485 ** a) If an unusable MATCH operator is present in the WHERE clause, the
486 ** cost is unconditionally set to 1e50 (a really big number).
487 **
488 ** a) If a MATCH operator is present, the cost depends on the other
489 ** constraints also present. As follows:
490 **
491 ** * No other constraints: cost=1000.0
492 ** * One rowid range constraint: cost=750.0
493 ** * Both rowid range constraints: cost=500.0
494 ** * An == rowid constraint: cost=100.0
495 **
496 ** b) Otherwise, if there is no MATCH:
497 **
498 ** * No other constraints: cost=1000000.0
499 ** * One rowid range constraint: cost=750000.0
500 ** * Both rowid range constraints: cost=250000.0
501 ** * An == rowid constraint: cost=10.0
502 **
503 ** Costs are not modified by the ORDER BY clause.
504 */
505 static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
506 Fts5Table *pTab = (Fts5Table*)pVTab;
507 Fts5Config *pConfig = pTab->pConfig;
508 int idxFlags = 0; /* Parameter passed through to xFilter() */
509 int bHasMatch;
510 int iNext;
511 int i;
512
513 struct Constraint {
514 int op; /* Mask against sqlite3_index_constraint.op */
515 int fts5op; /* FTS5 mask for idxFlags */
516 int iCol; /* 0==rowid, 1==tbl, 2==rank */
517 int omit; /* True to omit this if found */
518 int iConsIndex; /* Index in pInfo->aConstraint[] */
519 } aConstraint[] = {
520 {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
521 FTS5_BI_MATCH, 1, 1, -1},
522 {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
523 FTS5_BI_RANK, 2, 1, -1},
524 {SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1},
525 {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE,
526 FTS5_BI_ROWID_LE, 0, 0, -1},
527 {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE,
528 FTS5_BI_ROWID_GE, 0, 0, -1},
529 };
530
531 int aColMap[3];
532 aColMap[0] = -1;
533 aColMap[1] = pConfig->nCol;
534 aColMap[2] = pConfig->nCol+1;
535
536 /* Set idxFlags flags for all WHERE clause terms that will be used. */
537 for(i=0; i<pInfo->nConstraint; i++){
538 struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
539 int j;
540 for(j=0; j<(int)ArraySize(aConstraint); j++){
541 struct Constraint *pC = &aConstraint[j];
542 if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
543 if( p->usable ){
544 pC->iConsIndex = i;
545 idxFlags |= pC->fts5op;
546 }else if( j==0 ){
547 /* As there exists an unusable MATCH constraint this is an
548 ** unusable plan. Set a prohibitively high cost. */
549 pInfo->estimatedCost = 1e50;
550 return SQLITE_OK;
551 }
552 }
553 }
554 }
555
556 /* Set idxFlags flags for the ORDER BY clause */
557 if( pInfo->nOrderBy==1 ){
558 int iSort = pInfo->aOrderBy[0].iColumn;
559 if( iSort==(pConfig->nCol+1) && BitFlagTest(idxFlags, FTS5_BI_MATCH) ){
560 idxFlags |= FTS5_BI_ORDER_RANK;
561 }else if( iSort==-1 ){
562 idxFlags |= FTS5_BI_ORDER_ROWID;
563 }
564 if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
565 pInfo->orderByConsumed = 1;
566 if( pInfo->aOrderBy[0].desc ){
567 idxFlags |= FTS5_BI_ORDER_DESC;
568 }
569 }
570 }
571
572 /* Calculate the estimated cost based on the flags set in idxFlags. */
573 bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH);
574 if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){
575 pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0;
576 if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo);
577 }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
578 pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0;
579 }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
580 pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0;
581 }else{
582 pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0;
583 }
584
585 /* Assign argvIndex values to each constraint in use. */
586 iNext = 1;
587 for(i=0; i<(int)ArraySize(aConstraint); i++){
588 struct Constraint *pC = &aConstraint[i];
589 if( pC->iConsIndex>=0 ){
590 pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++;
591 pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit;
592 }
593 }
594
595 pInfo->idxNum = idxFlags;
596 return SQLITE_OK;
597 }
598
599 /*
600 ** Implementation of xOpen method.
601 */
602 static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
603 Fts5Table *pTab = (Fts5Table*)pVTab;
604 Fts5Config *pConfig = pTab->pConfig;
605 Fts5Cursor *pCsr; /* New cursor object */
606 int nByte; /* Bytes of space to allocate */
607 int rc = SQLITE_OK; /* Return code */
608
609 nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
610 pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
611 if( pCsr ){
612 Fts5Global *pGlobal = pTab->pGlobal;
613 memset(pCsr, 0, nByte);
614 pCsr->aColumnSize = (int*)&pCsr[1];
615 pCsr->pNext = pGlobal->pCsr;
616 pGlobal->pCsr = pCsr;
617 pCsr->iCsrId = ++pGlobal->iNextId;
618 }else{
619 rc = SQLITE_NOMEM;
620 }
621 *ppCsr = (sqlite3_vtab_cursor*)pCsr;
622 return rc;
623 }
624
625 static int fts5StmtType(Fts5Cursor *pCsr){
626 if( pCsr->ePlan==FTS5_PLAN_SCAN ){
627 return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC;
628 }
629 return FTS5_STMT_LOOKUP;
630 }
631
632 /*
633 ** This function is called after the cursor passed as the only argument
634 ** is moved to point at a different row. It clears all cached data
635 ** specific to the previous row stored by the cursor object.
636 */
637 static void fts5CsrNewrow(Fts5Cursor *pCsr){
638 CsrFlagSet(pCsr,
639 FTS5CSR_REQUIRE_CONTENT
640 | FTS5CSR_REQUIRE_DOCSIZE
641 | FTS5CSR_REQUIRE_INST
642 );
643 }
644
645 static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
646 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
647 Fts5Auxdata *pData;
648 Fts5Auxdata *pNext;
649
650 sqlite3_free(pCsr->aInstIter);
651 sqlite3_free(pCsr->aInst);
652 if( pCsr->pStmt ){
653 int eStmt = fts5StmtType(pCsr);
654 sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
655 }
656 if( pCsr->pSorter ){
657 Fts5Sorter *pSorter = pCsr->pSorter;
658 sqlite3_finalize(pSorter->pStmt);
659 sqlite3_free(pSorter);
660 }
661
662 if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){
663 sqlite3Fts5ExprFree(pCsr->pExpr);
664 }
665
666 for(pData=pCsr->pAuxdata; pData; pData=pNext){
667 pNext = pData->pNext;
668 if( pData->xDelete ) pData->xDelete(pData->pPtr);
669 sqlite3_free(pData);
670 }
671
672 sqlite3_finalize(pCsr->pRankArgStmt);
673 sqlite3_free(pCsr->apRankArg);
674
675 if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){
676 sqlite3_free(pCsr->zRank);
677 sqlite3_free(pCsr->zRankArgs);
678 }
679
680 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr));
681 }
682
683
684 /*
685 ** Close the cursor. For additional information see the documentation
686 ** on the xClose method of the virtual table interface.
687 */
688 static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
689 if( pCursor ){
690 Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
691 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
692 Fts5Cursor **pp;
693
694 fts5FreeCursorComponents(pCsr);
695 /* Remove the cursor from the Fts5Global.pCsr list */
696 for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext);
697 *pp = pCsr->pNext;
698
699 sqlite3_free(pCsr);
700 }
701 return SQLITE_OK;
702 }
703
704 static int fts5SorterNext(Fts5Cursor *pCsr){
705 Fts5Sorter *pSorter = pCsr->pSorter;
706 int rc;
707
708 rc = sqlite3_step(pSorter->pStmt);
709 if( rc==SQLITE_DONE ){
710 rc = SQLITE_OK;
711 CsrFlagSet(pCsr, FTS5CSR_EOF);
712 }else if( rc==SQLITE_ROW ){
713 const u8 *a;
714 const u8 *aBlob;
715 int nBlob;
716 int i;
717 int iOff = 0;
718 rc = SQLITE_OK;
719
720 pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0);
721 nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
722 aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
723
724 for(i=0; i<(pSorter->nIdx-1); i++){
725 int iVal;
726 a += fts5GetVarint32(a, iVal);
727 iOff += iVal;
728 pSorter->aIdx[i] = iOff;
729 }
730 pSorter->aIdx[i] = &aBlob[nBlob] - a;
731
732 pSorter->aPoslist = a;
733 fts5CsrNewrow(pCsr);
734 }
735
736 return rc;
737 }
738
739
740 /*
741 ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
742 ** open on table pTab.
743 */
744 static void fts5TripCursors(Fts5Table *pTab){
745 Fts5Cursor *pCsr;
746 for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
747 if( pCsr->ePlan==FTS5_PLAN_MATCH
748 && pCsr->base.pVtab==(sqlite3_vtab*)pTab
749 ){
750 CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK);
751 }
752 }
753 }
754
755 /*
756 ** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
757 ** argument, close and reopen all Fts5IndexIter iterators that the cursor
758 ** is using. Then attempt to move the cursor to a rowid equal to or laster
759 ** (in the cursors sort order - ASC or DESC) than the current rowid.
760 **
761 ** If the new rowid is not equal to the old, set output parameter *pbSkip
762 ** to 1 before returning. Otherwise, leave it unchanged.
763 **
764 ** Return SQLITE_OK if successful or if no reseek was required, or an
765 ** error code if an error occurred.
766 */
767 static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
768 int rc = SQLITE_OK;
769 assert( *pbSkip==0 );
770 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){
771 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
772 int bDesc = pCsr->bDesc;
773 i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
774
775 rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc);
776 if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
777 *pbSkip = 1;
778 }
779
780 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK);
781 fts5CsrNewrow(pCsr);
782 if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
783 CsrFlagSet(pCsr, FTS5CSR_EOF);
784 }
785 }
786 return rc;
787 }
788
789
790 /*
791 ** Advance the cursor to the next row in the table that matches the
792 ** search criteria.
793 **
794 ** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
795 ** even if we reach end-of-file. The fts5EofMethod() will be called
796 ** subsequently to determine whether or not an EOF was hit.
797 */
798 static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
799 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
800 int rc = SQLITE_OK;
801
802 assert( (pCsr->ePlan<3)==
803 (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
804 );
805
806 if( pCsr->ePlan<3 ){
807 int bSkip = 0;
808 if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
809 rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
810 if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
811 CsrFlagSet(pCsr, FTS5CSR_EOF);
812 }
813 fts5CsrNewrow(pCsr);
814 }else{
815 switch( pCsr->ePlan ){
816 case FTS5_PLAN_SPECIAL: {
817 CsrFlagSet(pCsr, FTS5CSR_EOF);
818 break;
819 }
820
821 case FTS5_PLAN_SORTED_MATCH: {
822 rc = fts5SorterNext(pCsr);
823 break;
824 }
825
826 default:
827 rc = sqlite3_step(pCsr->pStmt);
828 if( rc!=SQLITE_ROW ){
829 CsrFlagSet(pCsr, FTS5CSR_EOF);
830 rc = sqlite3_reset(pCsr->pStmt);
831 }else{
832 rc = SQLITE_OK;
833 }
834 break;
835 }
836 }
837
838 return rc;
839 }
840
841
842 static sqlite3_stmt *fts5PrepareStatement(
843 int *pRc,
844 Fts5Config *pConfig,
845 const char *zFmt,
846 ...
847 ){
848 sqlite3_stmt *pRet = 0;
849 va_list ap;
850 va_start(ap, zFmt);
851
852 if( *pRc==SQLITE_OK ){
853 int rc;
854 char *zSql = sqlite3_vmprintf(zFmt, ap);
855 if( zSql==0 ){
856 rc = SQLITE_NOMEM;
857 }else{
858 rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0);
859 if( rc!=SQLITE_OK ){
860 *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
861 }
862 sqlite3_free(zSql);
863 }
864 *pRc = rc;
865 }
866
867 va_end(ap);
868 return pRet;
869 }
870
871 static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
872 Fts5Config *pConfig = pTab->pConfig;
873 Fts5Sorter *pSorter;
874 int nPhrase;
875 int nByte;
876 int rc = SQLITE_OK;
877 const char *zRank = pCsr->zRank;
878 const char *zRankArgs = pCsr->zRankArgs;
879
880 nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
881 nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
882 pSorter = (Fts5Sorter*)sqlite3_malloc(nByte);
883 if( pSorter==0 ) return SQLITE_NOMEM;
884 memset(pSorter, 0, nByte);
885 pSorter->nIdx = nPhrase;
886
887 /* TODO: It would be better to have some system for reusing statement
888 ** handles here, rather than preparing a new one for each query. But that
889 ** is not possible as SQLite reference counts the virtual table objects.
890 ** And since the statement required here reads from this very virtual
891 ** table, saving it creates a circular reference.
892 **
893 ** If SQLite a built-in statement cache, this wouldn't be a problem. */
894 pSorter->pStmt = fts5PrepareStatement(&rc, pConfig,
895 "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
896 pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
897 (zRankArgs ? ", " : ""),
898 (zRankArgs ? zRankArgs : ""),
899 bDesc ? "DESC" : "ASC"
900 );
901
902 pCsr->pSorter = pSorter;
903 if( rc==SQLITE_OK ){
904 assert( pTab->pSortCsr==0 );
905 pTab->pSortCsr = pCsr;
906 rc = fts5SorterNext(pCsr);
907 pTab->pSortCsr = 0;
908 }
909
910 if( rc!=SQLITE_OK ){
911 sqlite3_finalize(pSorter->pStmt);
912 sqlite3_free(pSorter);
913 pCsr->pSorter = 0;
914 }
915
916 return rc;
917 }
918
919 static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
920 int rc;
921 Fts5Expr *pExpr = pCsr->pExpr;
922 rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc);
923 if( sqlite3Fts5ExprEof(pExpr) ){
924 CsrFlagSet(pCsr, FTS5CSR_EOF);
925 }
926 fts5CsrNewrow(pCsr);
927 return rc;
928 }
929
930 /*
931 ** Process a "special" query. A special query is identified as one with a
932 ** MATCH expression that begins with a '*' character. The remainder of
933 ** the text passed to the MATCH operator are used as the special query
934 ** parameters.
935 */
936 static int fts5SpecialMatch(
937 Fts5Table *pTab,
938 Fts5Cursor *pCsr,
939 const char *zQuery
940 ){
941 int rc = SQLITE_OK; /* Return code */
942 const char *z = zQuery; /* Special query text */
943 int n; /* Number of bytes in text at z */
944
945 while( z[0]==' ' ) z++;
946 for(n=0; z[n] && z[n]!=' '; n++);
947
948 assert( pTab->base.zErrMsg==0 );
949 pCsr->ePlan = FTS5_PLAN_SPECIAL;
950
951 if( 0==sqlite3_strnicmp("reads", z, n) ){
952 pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex);
953 }
954 else if( 0==sqlite3_strnicmp("id", z, n) ){
955 pCsr->iSpecial = pCsr->iCsrId;
956 }
957 else{
958 /* An unrecognized directive. Return an error message. */
959 pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
960 rc = SQLITE_ERROR;
961 }
962
963 return rc;
964 }
965
966 /*
967 ** Search for an auxiliary function named zName that can be used with table
968 ** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
969 ** structure. Otherwise, if no such function exists, return NULL.
970 */
971 static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){
972 Fts5Auxiliary *pAux;
973
974 for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){
975 if( sqlite3_stricmp(zName, pAux->zFunc)==0 ) return pAux;
976 }
977
978 /* No function of the specified name was found. Return 0. */
979 return 0;
980 }
981
982
983 static int fts5FindRankFunction(Fts5Cursor *pCsr){
984 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
985 Fts5Config *pConfig = pTab->pConfig;
986 int rc = SQLITE_OK;
987 Fts5Auxiliary *pAux = 0;
988 const char *zRank = pCsr->zRank;
989 const char *zRankArgs = pCsr->zRankArgs;
990
991 if( zRankArgs ){
992 char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs);
993 if( zSql ){
994 sqlite3_stmt *pStmt = 0;
995 rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0);
996 sqlite3_free(zSql);
997 assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
998 if( rc==SQLITE_OK ){
999 if( SQLITE_ROW==sqlite3_step(pStmt) ){
1000 int nByte;
1001 pCsr->nRankArg = sqlite3_column_count(pStmt);
1002 nByte = sizeof(sqlite3_value*)*pCsr->nRankArg;
1003 pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte);
1004 if( rc==SQLITE_OK ){
1005 int i;
1006 for(i=0; i<pCsr->nRankArg; i++){
1007 pCsr->apRankArg[i] = sqlite3_column_value(pStmt, i);
1008 }
1009 }
1010 pCsr->pRankArgStmt = pStmt;
1011 }else{
1012 rc = sqlite3_finalize(pStmt);
1013 assert( rc!=SQLITE_OK );
1014 }
1015 }
1016 }
1017 }
1018
1019 if( rc==SQLITE_OK ){
1020 pAux = fts5FindAuxiliary(pTab, zRank);
1021 if( pAux==0 ){
1022 assert( pTab->base.zErrMsg==0 );
1023 pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
1024 rc = SQLITE_ERROR;
1025 }
1026 }
1027
1028 pCsr->pRank = pAux;
1029 return rc;
1030 }
1031
1032
1033 static int fts5CursorParseRank(
1034 Fts5Config *pConfig,
1035 Fts5Cursor *pCsr,
1036 sqlite3_value *pRank
1037 ){
1038 int rc = SQLITE_OK;
1039 if( pRank ){
1040 const char *z = (const char*)sqlite3_value_text(pRank);
1041 char *zRank = 0;
1042 char *zRankArgs = 0;
1043
1044 if( z==0 ){
1045 if( sqlite3_value_type(pRank)==SQLITE_NULL ) rc = SQLITE_ERROR;
1046 }else{
1047 rc = sqlite3Fts5ConfigParseRank(z, &zRank, &zRankArgs);
1048 }
1049 if( rc==SQLITE_OK ){
1050 pCsr->zRank = zRank;
1051 pCsr->zRankArgs = zRankArgs;
1052 CsrFlagSet(pCsr, FTS5CSR_FREE_ZRANK);
1053 }else if( rc==SQLITE_ERROR ){
1054 pCsr->base.pVtab->zErrMsg = sqlite3_mprintf(
1055 "parse error in rank function: %s", z
1056 );
1057 }
1058 }else{
1059 if( pConfig->zRank ){
1060 pCsr->zRank = (char*)pConfig->zRank;
1061 pCsr->zRankArgs = (char*)pConfig->zRankArgs;
1062 }else{
1063 pCsr->zRank = (char*)FTS5_DEFAULT_RANK;
1064 pCsr->zRankArgs = 0;
1065 }
1066 }
1067 return rc;
1068 }
1069
1070 static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
1071 if( pVal ){
1072 int eType = sqlite3_value_numeric_type(pVal);
1073 if( eType==SQLITE_INTEGER ){
1074 return sqlite3_value_int64(pVal);
1075 }
1076 }
1077 return iDefault;
1078 }
1079
1080 /*
1081 ** This is the xFilter interface for the virtual table. See
1082 ** the virtual table xFilter method documentation for additional
1083 ** information.
1084 **
1085 ** There are three possible query strategies:
1086 **
1087 ** 1. Full-text search using a MATCH operator.
1088 ** 2. A by-rowid lookup.
1089 ** 3. A full-table scan.
1090 */
1091 static int fts5FilterMethod(
1092 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
1093 int idxNum, /* Strategy index */
1094 const char *idxStr, /* Unused */
1095 int nVal, /* Number of elements in apVal */
1096 sqlite3_value **apVal /* Arguments for the indexing scheme */
1097 ){
1098 Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
1099 Fts5Config *pConfig = pTab->pConfig;
1100 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1101 int rc = SQLITE_OK; /* Error code */
1102 int iVal = 0; /* Counter for apVal[] */
1103 int bDesc; /* True if ORDER BY [rank|rowid] DESC */
1104 int bOrderByRank; /* True if ORDER BY rank */
1105 sqlite3_value *pMatch = 0; /* <tbl> MATCH ? expression (or NULL) */
1106 sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */
1107 sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
1108 sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
1109 sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
1110 char **pzErrmsg = pConfig->pzErrmsg;
1111
1112 if( pCsr->ePlan ){
1113 fts5FreeCursorComponents(pCsr);
1114 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
1115 }
1116
1117 assert( pCsr->pStmt==0 );
1118 assert( pCsr->pExpr==0 );
1119 assert( pCsr->csrflags==0 );
1120 assert( pCsr->pRank==0 );
1121 assert( pCsr->zRank==0 );
1122 assert( pCsr->zRankArgs==0 );
1123
1124 assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg );
1125 pConfig->pzErrmsg = &pTab->base.zErrMsg;
1126
1127 /* Decode the arguments passed through to this function.
1128 **
1129 ** Note: The following set of if(...) statements must be in the same
1130 ** order as the corresponding entries in the struct at the top of
1131 ** fts5BestIndexMethod(). */
1132 if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++];
1133 if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++];
1134 if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
1135 if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
1136 if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
1137 assert( iVal==nVal );
1138 bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
1139 pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
1140
1141 /* Set the cursor upper and lower rowid limits. Only some strategies
1142 ** actually use them. This is ok, as the xBestIndex() method leaves the
1143 ** sqlite3_index_constraint.omit flag clear for range constraints
1144 ** on the rowid field. */
1145 if( pRowidEq ){
1146 pRowidLe = pRowidGe = pRowidEq;
1147 }
1148 if( bDesc ){
1149 pCsr->iFirstRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
1150 pCsr->iLastRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
1151 }else{
1152 pCsr->iLastRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
1153 pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
1154 }
1155
1156 if( pTab->pSortCsr ){
1157 /* If pSortCsr is non-NULL, then this call is being made as part of
1158 ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
1159 ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
1160 ** return results to the user for this query. The current cursor
1161 ** (pCursor) is used to execute the query issued by function
1162 ** fts5CursorFirstSorted() above. */
1163 assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 );
1164 assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 );
1165 assert( pCsr->iLastRowid==LARGEST_INT64 );
1166 assert( pCsr->iFirstRowid==SMALLEST_INT64 );
1167 pCsr->ePlan = FTS5_PLAN_SOURCE;
1168 pCsr->pExpr = pTab->pSortCsr->pExpr;
1169 rc = fts5CursorFirst(pTab, pCsr, bDesc);
1170 }else if( pMatch ){
1171 const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
1172 if( zExpr==0 ) zExpr = "";
1173
1174 rc = fts5CursorParseRank(pConfig, pCsr, pRank);
1175 if( rc==SQLITE_OK ){
1176 if( zExpr[0]=='*' ){
1177 /* The user has issued a query of the form "MATCH '*...'". This
1178 ** indicates that the MATCH expression is not a full text query,
1179 ** but a request for an internal parameter. */
1180 rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
1181 }else{
1182 char **pzErr = &pTab->base.zErrMsg;
1183 rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
1184 if( rc==SQLITE_OK ){
1185 if( bOrderByRank ){
1186 pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
1187 rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
1188 }else{
1189 pCsr->ePlan = FTS5_PLAN_MATCH;
1190 rc = fts5CursorFirst(pTab, pCsr, bDesc);
1191 }
1192 }
1193 }
1194 }
1195 }else if( pConfig->zContent==0 ){
1196 *pConfig->pzErrmsg = sqlite3_mprintf(
1197 "%s: table does not support scanning", pConfig->zName
1198 );
1199 rc = SQLITE_ERROR;
1200 }else{
1201 /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
1202 ** by rowid (ePlan==FTS5_PLAN_ROWID). */
1203 pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
1204 rc = sqlite3Fts5StorageStmt(
1205 pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg
1206 );
1207 if( rc==SQLITE_OK ){
1208 if( pCsr->ePlan==FTS5_PLAN_ROWID ){
1209 sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
1210 }else{
1211 sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
1212 sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid);
1213 }
1214 rc = fts5NextMethod(pCursor);
1215 }
1216 }
1217
1218 pConfig->pzErrmsg = pzErrmsg;
1219 return rc;
1220 }
1221
1222 /*
1223 ** This is the xEof method of the virtual table. SQLite calls this
1224 ** routine to find out if it has reached the end of a result set.
1225 */
1226 static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
1227 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1228 return (CsrFlagTest(pCsr, FTS5CSR_EOF) ? 1 : 0);
1229 }
1230
1231 /*
1232 ** Return the rowid that the cursor currently points to.
1233 */
1234 static i64 fts5CursorRowid(Fts5Cursor *pCsr){
1235 assert( pCsr->ePlan==FTS5_PLAN_MATCH
1236 || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
1237 || pCsr->ePlan==FTS5_PLAN_SOURCE
1238 );
1239 if( pCsr->pSorter ){
1240 return pCsr->pSorter->iRowid;
1241 }else{
1242 return sqlite3Fts5ExprRowid(pCsr->pExpr);
1243 }
1244 }
1245
1246 /*
1247 ** This is the xRowid method. The SQLite core calls this routine to
1248 ** retrieve the rowid for the current row of the result set. fts5
1249 ** exposes %_content.rowid as the rowid for the virtual table. The
1250 ** rowid should be written to *pRowid.
1251 */
1252 static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
1253 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
1254 int ePlan = pCsr->ePlan;
1255
1256 assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
1257 switch( ePlan ){
1258 case FTS5_PLAN_SPECIAL:
1259 *pRowid = 0;
1260 break;
1261
1262 case FTS5_PLAN_SOURCE:
1263 case FTS5_PLAN_MATCH:
1264 case FTS5_PLAN_SORTED_MATCH:
1265 *pRowid = fts5CursorRowid(pCsr);
1266 break;
1267
1268 default:
1269 *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
1270 break;
1271 }
1272
1273 return SQLITE_OK;
1274 }
1275
1276 /*
1277 ** If the cursor requires seeking (bSeekRequired flag is set), seek it.
1278 ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
1279 **
1280 ** If argument bErrormsg is true and an error occurs, an error message may
1281 ** be left in sqlite3_vtab.zErrMsg.
1282 */
1283 static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
1284 int rc = SQLITE_OK;
1285
1286 /* If the cursor does not yet have a statement handle, obtain one now. */
1287 if( pCsr->pStmt==0 ){
1288 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1289 int eStmt = fts5StmtType(pCsr);
1290 rc = sqlite3Fts5StorageStmt(
1291 pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0)
1292 );
1293 assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 );
1294 assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
1295 }
1296
1297 if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
1298 assert( pCsr->pExpr );
1299 sqlite3_reset(pCsr->pStmt);
1300 sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
1301 rc = sqlite3_step(pCsr->pStmt);
1302 if( rc==SQLITE_ROW ){
1303 rc = SQLITE_OK;
1304 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
1305 }else{
1306 rc = sqlite3_reset(pCsr->pStmt);
1307 if( rc==SQLITE_OK ){
1308 rc = FTS5_CORRUPT;
1309 }
1310 }
1311 }
1312 return rc;
1313 }
1314
1315 static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
1316 va_list ap; /* ... printf arguments */
1317 va_start(ap, zFormat);
1318 assert( p->base.zErrMsg==0 );
1319 p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
1320 va_end(ap);
1321 }
1322
1323 /*
1324 ** This function is called to handle an FTS INSERT command. In other words,
1325 ** an INSERT statement of the form:
1326 **
1327 ** INSERT INTO fts(fts) VALUES($pCmd)
1328 ** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
1329 **
1330 ** Argument pVal is the value assigned to column "fts" by the INSERT
1331 ** statement. This function returns SQLITE_OK if successful, or an SQLite
1332 ** error code if an error occurs.
1333 **
1334 ** The commands implemented by this function are documented in the "Special
1335 ** INSERT Directives" section of the documentation. It should be updated if
1336 ** more commands are added to this function.
1337 */
1338 static int fts5SpecialInsert(
1339 Fts5Table *pTab, /* Fts5 table object */
1340 const char *zCmd, /* Text inserted into table-name column */
1341 sqlite3_value *pVal /* Value inserted into rank column */
1342 ){
1343 Fts5Config *pConfig = pTab->pConfig;
1344 int rc = SQLITE_OK;
1345 int bError = 0;
1346
1347 if( 0==sqlite3_stricmp("delete-all", zCmd) ){
1348 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
1349 fts5SetVtabError(pTab,
1350 "'delete-all' may only be used with a "
1351 "contentless or external content fts5 table"
1352 );
1353 rc = SQLITE_ERROR;
1354 }else{
1355 rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
1356 }
1357 }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
1358 if( pConfig->eContent==FTS5_CONTENT_NONE ){
1359 fts5SetVtabError(pTab,
1360 "'rebuild' may not be used with a contentless fts5 table"
1361 );
1362 rc = SQLITE_ERROR;
1363 }else{
1364 rc = sqlite3Fts5StorageRebuild(pTab->pStorage);
1365 }
1366 }else if( 0==sqlite3_stricmp("optimize", zCmd) ){
1367 rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
1368 }else if( 0==sqlite3_stricmp("merge", zCmd) ){
1369 int nMerge = sqlite3_value_int(pVal);
1370 rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
1371 }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
1372 rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
1373 #ifdef SQLITE_DEBUG
1374 }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
1375 pConfig->bPrefixIndex = sqlite3_value_int(pVal);
1376 #endif
1377 }else{
1378 rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
1379 if( rc==SQLITE_OK ){
1380 rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError);
1381 }
1382 if( rc==SQLITE_OK ){
1383 if( bError ){
1384 rc = SQLITE_ERROR;
1385 }else{
1386 rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0);
1387 }
1388 }
1389 }
1390 return rc;
1391 }
1392
1393 static int fts5SpecialDelete(
1394 Fts5Table *pTab,
1395 sqlite3_value **apVal,
1396 sqlite3_int64 *piRowid
1397 ){
1398 int rc = SQLITE_OK;
1399 int eType1 = sqlite3_value_type(apVal[1]);
1400 if( eType1==SQLITE_INTEGER ){
1401 sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
1402 rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]);
1403 }
1404 return rc;
1405 }
1406
1407 static void fts5StorageInsert(
1408 int *pRc,
1409 Fts5Table *pTab,
1410 sqlite3_value **apVal,
1411 i64 *piRowid
1412 ){
1413 int rc = *pRc;
1414 if( rc==SQLITE_OK ){
1415 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
1416 }
1417 if( rc==SQLITE_OK ){
1418 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
1419 }
1420 *pRc = rc;
1421 }
1422
1423 /*
1424 ** This function is the implementation of the xUpdate callback used by
1425 ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
1426 ** inserted, updated or deleted.
1427 **
1428 ** A delete specifies a single argument - the rowid of the row to remove.
1429 **
1430 ** Update and insert operations pass:
1431 **
1432 ** 1. The "old" rowid, or NULL.
1433 ** 2. The "new" rowid.
1434 ** 3. Values for each of the nCol matchable columns.
1435 ** 4. Values for the two hidden columns (<tablename> and "rank").
1436 */
1437 static int fts5UpdateMethod(
1438 sqlite3_vtab *pVtab, /* Virtual table handle */
1439 int nArg, /* Size of argument array */
1440 sqlite3_value **apVal, /* Array of arguments */
1441 sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */
1442 ){
1443 Fts5Table *pTab = (Fts5Table*)pVtab;
1444 Fts5Config *pConfig = pTab->pConfig;
1445 int eType0; /* value_type() of apVal[0] */
1446 int rc = SQLITE_OK; /* Return code */
1447
1448 /* A transaction must be open when this is called. */
1449 assert( pTab->ts.eState==1 );
1450
1451 assert( pVtab->zErrMsg==0 );
1452 assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
1453 assert( nArg==1
1454 || sqlite3_value_type(apVal[1])==SQLITE_INTEGER
1455 || sqlite3_value_type(apVal[1])==SQLITE_NULL
1456 );
1457 assert( pTab->pConfig->pzErrmsg==0 );
1458 pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
1459
1460 /* Put any active cursors into REQUIRE_SEEK state. */
1461 fts5TripCursors(pTab);
1462
1463 eType0 = sqlite3_value_type(apVal[0]);
1464 if( eType0==SQLITE_NULL
1465 && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
1466 ){
1467 /* A "special" INSERT op. These are handled separately. */
1468 const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]);
1469 if( pConfig->eContent!=FTS5_CONTENT_NORMAL
1470 && 0==sqlite3_stricmp("delete", z)
1471 ){
1472 rc = fts5SpecialDelete(pTab, apVal, pRowid);
1473 }else{
1474 rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
1475 }
1476 }else{
1477 /* A regular INSERT, UPDATE or DELETE statement. The trick here is that
1478 ** any conflict on the rowid value must be detected before any
1479 ** modifications are made to the database file. There are 4 cases:
1480 **
1481 ** 1) DELETE
1482 ** 2) UPDATE (rowid not modified)
1483 ** 3) UPDATE (rowid modified)
1484 ** 4) INSERT
1485 **
1486 ** Cases 3 and 4 may violate the rowid constraint.
1487 */
1488 int eConflict = SQLITE_ABORT;
1489 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
1490 eConflict = sqlite3_vtab_on_conflict(pConfig->db);
1491 }
1492
1493 assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
1494 assert( nArg!=1 || eType0==SQLITE_INTEGER );
1495
1496 /* Filter out attempts to run UPDATE or DELETE on contentless tables.
1497 ** This is not suported. */
1498 if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
1499 pTab->base.zErrMsg = sqlite3_mprintf(
1500 "cannot %s contentless fts5 table: %s",
1501 (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
1502 );
1503 rc = SQLITE_ERROR;
1504 }
1505
1506 /* Case 1: DELETE */
1507 else if( nArg==1 ){
1508 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
1509 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
1510 }
1511
1512 /* Case 2: INSERT */
1513 else if( eType0!=SQLITE_INTEGER ){
1514 /* If this is a REPLACE, first remove the current entry (if any) */
1515 if( eConflict==SQLITE_REPLACE
1516 && sqlite3_value_type(apVal[1])==SQLITE_INTEGER
1517 ){
1518 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
1519 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
1520 }
1521 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1522 }
1523
1524 /* Case 2: UPDATE */
1525 else{
1526 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
1527 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
1528 if( iOld!=iNew ){
1529 if( eConflict==SQLITE_REPLACE ){
1530 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
1531 if( rc==SQLITE_OK ){
1532 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
1533 }
1534 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1535 }else{
1536 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
1537 if( rc==SQLITE_OK ){
1538 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
1539 }
1540 if( rc==SQLITE_OK ){
1541 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
1542 }
1543 }
1544 }else{
1545 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
1546 fts5StorageInsert(&rc, pTab, apVal, pRowid);
1547 }
1548 }
1549 }
1550
1551 pTab->pConfig->pzErrmsg = 0;
1552 return rc;
1553 }
1554
1555 /*
1556 ** Implementation of xSync() method.
1557 */
1558 static int fts5SyncMethod(sqlite3_vtab *pVtab){
1559 int rc;
1560 Fts5Table *pTab = (Fts5Table*)pVtab;
1561 fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
1562 pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
1563 fts5TripCursors(pTab);
1564 rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
1565 pTab->pConfig->pzErrmsg = 0;
1566 return rc;
1567 }
1568
1569 /*
1570 ** Implementation of xBegin() method.
1571 */
1572 static int fts5BeginMethod(sqlite3_vtab *pVtab){
1573 fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
1574 return SQLITE_OK;
1575 }
1576
1577 /*
1578 ** Implementation of xCommit() method. This is a no-op. The contents of
1579 ** the pending-terms hash-table have already been flushed into the database
1580 ** by fts5SyncMethod().
1581 */
1582 static int fts5CommitMethod(sqlite3_vtab *pVtab){
1583 fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
1584 return SQLITE_OK;
1585 }
1586
1587 /*
1588 ** Implementation of xRollback(). Discard the contents of the pending-terms
1589 ** hash-table. Any changes made to the database are reverted by SQLite.
1590 */
1591 static int fts5RollbackMethod(sqlite3_vtab *pVtab){
1592 int rc;
1593 Fts5Table *pTab = (Fts5Table*)pVtab;
1594 fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
1595 rc = sqlite3Fts5StorageRollback(pTab->pStorage);
1596 return rc;
1597 }
1598
1599 static void *fts5ApiUserData(Fts5Context *pCtx){
1600 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1601 return pCsr->pAux->pUserData;
1602 }
1603
1604 static int fts5ApiColumnCount(Fts5Context *pCtx){
1605 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1606 return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol;
1607 }
1608
1609 static int fts5ApiColumnTotalSize(
1610 Fts5Context *pCtx,
1611 int iCol,
1612 sqlite3_int64 *pnToken
1613 ){
1614 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1615 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1616 return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken);
1617 }
1618
1619 static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
1620 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1621 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1622 return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
1623 }
1624
1625 static int fts5ApiTokenize(
1626 Fts5Context *pCtx,
1627 const char *pText, int nText,
1628 void *pUserData,
1629 int (*xToken)(void*, int, const char*, int, int, int)
1630 ){
1631 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1632 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1633 return sqlite3Fts5Tokenize(
1634 pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
1635 );
1636 }
1637
1638 static int fts5ApiPhraseCount(Fts5Context *pCtx){
1639 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1640 return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
1641 }
1642
1643 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
1644 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1645 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
1646 }
1647
1648 static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){
1649 int n;
1650 if( pCsr->pSorter ){
1651 Fts5Sorter *pSorter = pCsr->pSorter;
1652 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
1653 n = pSorter->aIdx[iPhrase] - i1;
1654 *pa = &pSorter->aPoslist[i1];
1655 }else{
1656 n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
1657 }
1658 return n;
1659 }
1660
1661 /*
1662 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
1663 ** correctly for the current view. Return SQLITE_OK if successful, or an
1664 ** SQLite error code otherwise.
1665 */
1666 static int fts5CacheInstArray(Fts5Cursor *pCsr){
1667 int rc = SQLITE_OK;
1668 Fts5PoslistReader *aIter; /* One iterator for each phrase */
1669 int nIter; /* Number of iterators/phrases */
1670
1671 nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
1672 if( pCsr->aInstIter==0 ){
1673 int nByte = sizeof(Fts5PoslistReader) * nIter;
1674 pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
1675 }
1676 aIter = pCsr->aInstIter;
1677
1678 if( aIter ){
1679 int nInst = 0; /* Number instances seen so far */
1680 int i;
1681
1682 /* Initialize all iterators */
1683 for(i=0; i<nIter; i++){
1684 const u8 *a;
1685 int n = fts5CsrPoslist(pCsr, i, &a);
1686 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
1687 }
1688
1689 while( 1 ){
1690 int *aInst;
1691 int iBest = -1;
1692 for(i=0; i<nIter; i++){
1693 if( (aIter[i].bEof==0)
1694 && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
1695 ){
1696 iBest = i;
1697 }
1698 }
1699 if( iBest<0 ) break;
1700
1701 nInst++;
1702 if( nInst>=pCsr->nInstAlloc ){
1703 pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
1704 aInst = (int*)sqlite3_realloc(
1705 pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
1706 );
1707 if( aInst ){
1708 pCsr->aInst = aInst;
1709 }else{
1710 rc = SQLITE_NOMEM;
1711 break;
1712 }
1713 }
1714
1715 aInst = &pCsr->aInst[3 * (nInst-1)];
1716 aInst[0] = iBest;
1717 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
1718 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
1719 sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
1720 }
1721
1722 pCsr->nInstCount = nInst;
1723 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
1724 }
1725 return rc;
1726 }
1727
1728 static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
1729 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1730 int rc = SQLITE_OK;
1731 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
1732 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
1733 *pnInst = pCsr->nInstCount;
1734 }
1735 return rc;
1736 }
1737
1738 static int fts5ApiInst(
1739 Fts5Context *pCtx,
1740 int iIdx,
1741 int *piPhrase,
1742 int *piCol,
1743 int *piOff
1744 ){
1745 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1746 int rc = SQLITE_OK;
1747 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
1748 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
1749 ){
1750 if( iIdx<0 || iIdx>=pCsr->nInstCount ){
1751 rc = SQLITE_RANGE;
1752 }else{
1753 *piPhrase = pCsr->aInst[iIdx*3];
1754 *piCol = pCsr->aInst[iIdx*3 + 1];
1755 *piOff = pCsr->aInst[iIdx*3 + 2];
1756 }
1757 }
1758 return rc;
1759 }
1760
1761 static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
1762 return fts5CursorRowid((Fts5Cursor*)pCtx);
1763 }
1764
1765 static int fts5ApiColumnText(
1766 Fts5Context *pCtx,
1767 int iCol,
1768 const char **pz,
1769 int *pn
1770 ){
1771 int rc = SQLITE_OK;
1772 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1773 if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
1774 *pz = 0;
1775 *pn = 0;
1776 }else{
1777 rc = fts5SeekCursor(pCsr, 0);
1778 if( rc==SQLITE_OK ){
1779 *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
1780 *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
1781 }
1782 }
1783 return rc;
1784 }
1785
1786 static int fts5ColumnSizeCb(
1787 void *pContext, /* Pointer to int */
1788 int tflags,
1789 const char *pToken, /* Buffer containing token */
1790 int nToken, /* Size of token in bytes */
1791 int iStart, /* Start offset of token */
1792 int iEnd /* End offset of token */
1793 ){
1794 int *pCnt = (int*)pContext;
1795 if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
1796 (*pCnt)++;
1797 }
1798 return SQLITE_OK;
1799 }
1800
1801 static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
1802 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1803 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1804 Fts5Config *pConfig = pTab->pConfig;
1805 int rc = SQLITE_OK;
1806
1807 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
1808 if( pConfig->bColumnsize ){
1809 i64 iRowid = fts5CursorRowid(pCsr);
1810 rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
1811 }else if( pConfig->zContent==0 ){
1812 int i;
1813 for(i=0; i<pConfig->nCol; i++){
1814 if( pConfig->abUnindexed[i]==0 ){
1815 pCsr->aColumnSize[i] = -1;
1816 }
1817 }
1818 }else{
1819 int i;
1820 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
1821 if( pConfig->abUnindexed[i]==0 ){
1822 const char *z; int n;
1823 void *p = (void*)(&pCsr->aColumnSize[i]);
1824 pCsr->aColumnSize[i] = 0;
1825 rc = fts5ApiColumnText(pCtx, i, &z, &n);
1826 if( rc==SQLITE_OK ){
1827 rc = sqlite3Fts5Tokenize(
1828 pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
1829 );
1830 }
1831 }
1832 }
1833 }
1834 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
1835 }
1836 if( iCol<0 ){
1837 int i;
1838 *pnToken = 0;
1839 for(i=0; i<pConfig->nCol; i++){
1840 *pnToken += pCsr->aColumnSize[i];
1841 }
1842 }else if( iCol<pConfig->nCol ){
1843 *pnToken = pCsr->aColumnSize[iCol];
1844 }else{
1845 *pnToken = 0;
1846 rc = SQLITE_RANGE;
1847 }
1848 return rc;
1849 }
1850
1851 /*
1852 ** Implementation of the xSetAuxdata() method.
1853 */
1854 static int fts5ApiSetAuxdata(
1855 Fts5Context *pCtx, /* Fts5 context */
1856 void *pPtr, /* Pointer to save as auxdata */
1857 void(*xDelete)(void*) /* Destructor for pPtr (or NULL) */
1858 ){
1859 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1860 Fts5Auxdata *pData;
1861
1862 /* Search through the cursors list of Fts5Auxdata objects for one that
1863 ** corresponds to the currently executing auxiliary function. */
1864 for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
1865 if( pData->pAux==pCsr->pAux ) break;
1866 }
1867
1868 if( pData ){
1869 if( pData->xDelete ){
1870 pData->xDelete(pData->pPtr);
1871 }
1872 }else{
1873 int rc = SQLITE_OK;
1874 pData = (Fts5Auxdata*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Auxdata));
1875 if( pData==0 ){
1876 if( xDelete ) xDelete(pPtr);
1877 return rc;
1878 }
1879 pData->pAux = pCsr->pAux;
1880 pData->pNext = pCsr->pAuxdata;
1881 pCsr->pAuxdata = pData;
1882 }
1883
1884 pData->xDelete = xDelete;
1885 pData->pPtr = pPtr;
1886 return SQLITE_OK;
1887 }
1888
1889 static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
1890 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1891 Fts5Auxdata *pData;
1892 void *pRet = 0;
1893
1894 for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
1895 if( pData->pAux==pCsr->pAux ) break;
1896 }
1897
1898 if( pData ){
1899 pRet = pData->pPtr;
1900 if( bClear ){
1901 pData->pPtr = 0;
1902 pData->xDelete = 0;
1903 }
1904 }
1905
1906 return pRet;
1907 }
1908
1909 static void fts5ApiPhraseNext(
1910 Fts5Context *pCtx,
1911 Fts5PhraseIter *pIter,
1912 int *piCol, int *piOff
1913 ){
1914 if( pIter->a>=pIter->b ){
1915 *piCol = -1;
1916 *piOff = -1;
1917 }else{
1918 int iVal;
1919 pIter->a += fts5GetVarint32(pIter->a, iVal);
1920 if( iVal==1 ){
1921 pIter->a += fts5GetVarint32(pIter->a, iVal);
1922 *piCol = iVal;
1923 *piOff = 0;
1924 pIter->a += fts5GetVarint32(pIter->a, iVal);
1925 }
1926 *piOff += (iVal-2);
1927 }
1928 }
1929
1930 static void fts5ApiPhraseFirst(
1931 Fts5Context *pCtx,
1932 int iPhrase,
1933 Fts5PhraseIter *pIter,
1934 int *piCol, int *piOff
1935 ){
1936 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1937 int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a);
1938 pIter->b = &pIter->a[n];
1939 *piCol = 0;
1940 *piOff = 0;
1941 fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
1942 }
1943
1944 static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
1945 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
1946 );
1947
1948 static const Fts5ExtensionApi sFts5Api = {
1949 2, /* iVersion */
1950 fts5ApiUserData,
1951 fts5ApiColumnCount,
1952 fts5ApiRowCount,
1953 fts5ApiColumnTotalSize,
1954 fts5ApiTokenize,
1955 fts5ApiPhraseCount,
1956 fts5ApiPhraseSize,
1957 fts5ApiInstCount,
1958 fts5ApiInst,
1959 fts5ApiRowid,
1960 fts5ApiColumnText,
1961 fts5ApiColumnSize,
1962 fts5ApiQueryPhrase,
1963 fts5ApiSetAuxdata,
1964 fts5ApiGetAuxdata,
1965 fts5ApiPhraseFirst,
1966 fts5ApiPhraseNext,
1967 };
1968
1969
1970 /*
1971 ** Implementation of API function xQueryPhrase().
1972 */
1973 static int fts5ApiQueryPhrase(
1974 Fts5Context *pCtx,
1975 int iPhrase,
1976 void *pUserData,
1977 int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
1978 ){
1979 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
1980 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
1981 int rc;
1982 Fts5Cursor *pNew = 0;
1983
1984 rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
1985 if( rc==SQLITE_OK ){
1986 Fts5Config *pConf = pTab->pConfig;
1987 pNew->ePlan = FTS5_PLAN_MATCH;
1988 pNew->iFirstRowid = SMALLEST_INT64;
1989 pNew->iLastRowid = LARGEST_INT64;
1990 pNew->base.pVtab = (sqlite3_vtab*)pTab;
1991 rc = sqlite3Fts5ExprClonePhrase(pConf, pCsr->pExpr, iPhrase, &pNew->pExpr);
1992 }
1993
1994 if( rc==SQLITE_OK ){
1995 for(rc = fts5CursorFirst(pTab, pNew, 0);
1996 rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0;
1997 rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew)
1998 ){
1999 rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData);
2000 if( rc!=SQLITE_OK ){
2001 if( rc==SQLITE_DONE ) rc = SQLITE_OK;
2002 break;
2003 }
2004 }
2005 }
2006
2007 fts5CloseMethod((sqlite3_vtab_cursor*)pNew);
2008 return rc;
2009 }
2010
2011 static void fts5ApiInvoke(
2012 Fts5Auxiliary *pAux,
2013 Fts5Cursor *pCsr,
2014 sqlite3_context *context,
2015 int argc,
2016 sqlite3_value **argv
2017 ){
2018 assert( pCsr->pAux==0 );
2019 pCsr->pAux = pAux;
2020 pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
2021 pCsr->pAux = 0;
2022 }
2023
2024 static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
2025 Fts5Cursor *pCsr;
2026 for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
2027 if( pCsr->iCsrId==iCsrId ) break;
2028 }
2029 return pCsr;
2030 }
2031
2032 static void fts5ApiCallback(
2033 sqlite3_context *context,
2034 int argc,
2035 sqlite3_value **argv
2036 ){
2037
2038 Fts5Auxiliary *pAux;
2039 Fts5Cursor *pCsr;
2040 i64 iCsrId;
2041
2042 assert( argc>=1 );
2043 pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
2044 iCsrId = sqlite3_value_int64(argv[0]);
2045
2046 pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
2047 if( pCsr==0 ){
2048 char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
2049 sqlite3_result_error(context, zErr, -1);
2050 sqlite3_free(zErr);
2051 }else{
2052 fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
2053 }
2054 }
2055
2056
2057 /*
2058 ** Given cursor id iId, return a pointer to the corresponding Fts5Index
2059 ** object. Or NULL If the cursor id does not exist.
2060 **
2061 ** If successful, set *ppConfig to point to the associated config object
2062 ** before returning.
2063 */
2064 Fts5Index *sqlite3Fts5IndexFromCsrid(
2065 Fts5Global *pGlobal, /* FTS5 global context for db handle */
2066 i64 iCsrId, /* Id of cursor to find */
2067 Fts5Config **ppConfig /* OUT: Configuration object */
2068 ){
2069 Fts5Cursor *pCsr;
2070 Fts5Table *pTab;
2071
2072 pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
2073 pTab = (Fts5Table*)pCsr->base.pVtab;
2074 *ppConfig = pTab->pConfig;
2075
2076 return pTab->pIndex;
2077 }
2078
2079 /*
2080 ** Return a "position-list blob" corresponding to the current position of
2081 ** cursor pCsr via sqlite3_result_blob(). A position-list blob contains
2082 ** the current position-list for each phrase in the query associated with
2083 ** cursor pCsr.
2084 **
2085 ** A position-list blob begins with (nPhrase-1) varints, where nPhrase is
2086 ** the number of phrases in the query. Following the varints are the
2087 ** concatenated position lists for each phrase, in order.
2088 **
2089 ** The first varint (if it exists) contains the size of the position list
2090 ** for phrase 0. The second (same disclaimer) contains the size of position
2091 ** list 1. And so on. There is no size field for the final position list,
2092 ** as it can be derived from the total size of the blob.
2093 */
2094 static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
2095 int i;
2096 int rc = SQLITE_OK;
2097 int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
2098 Fts5Buffer val;
2099
2100 memset(&val, 0, sizeof(Fts5Buffer));
2101
2102 /* Append the varints */
2103 for(i=0; i<(nPhrase-1); i++){
2104 const u8 *dummy;
2105 int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
2106 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
2107 }
2108
2109 /* Append the position lists */
2110 for(i=0; i<nPhrase; i++){
2111 const u8 *pPoslist;
2112 int nPoslist;
2113 nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
2114 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
2115 }
2116
2117 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
2118 return rc;
2119 }
2120
2121 /*
2122 ** This is the xColumn method, called by SQLite to request a value from
2123 ** the row that the supplied cursor currently points to.
2124 */
2125 static int fts5ColumnMethod(
2126 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
2127 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
2128 int iCol /* Index of column to read value from */
2129 ){
2130 Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
2131 Fts5Config *pConfig = pTab->pConfig;
2132 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
2133 int rc = SQLITE_OK;
2134
2135 assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
2136
2137 if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){
2138 if( iCol==pConfig->nCol ){
2139 sqlite3_result_int64(pCtx, pCsr->iSpecial);
2140 }
2141 }else
2142
2143 if( iCol==pConfig->nCol ){
2144 /* User is requesting the value of the special column with the same name
2145 ** as the table. Return the cursor integer id number. This value is only
2146 ** useful in that it may be passed as the first argument to an FTS5
2147 ** auxiliary function. */
2148 sqlite3_result_int64(pCtx, pCsr->iCsrId);
2149 }else if( iCol==pConfig->nCol+1 ){
2150
2151 /* The value of the "rank" column. */
2152 if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
2153 fts5PoslistBlob(pCtx, pCsr);
2154 }else if(
2155 pCsr->ePlan==FTS5_PLAN_MATCH
2156 || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
2157 ){
2158 if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
2159 fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
2160 }
2161 }
2162 }else if( !fts5IsContentless(pTab) ){
2163 rc = fts5SeekCursor(pCsr, 1);
2164 if( rc==SQLITE_OK ){
2165 sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
2166 }
2167 }
2168 return rc;
2169 }
2170
2171
2172 /*
2173 ** This routine implements the xFindFunction method for the FTS3
2174 ** virtual table.
2175 */
2176 static int fts5FindFunctionMethod(
2177 sqlite3_vtab *pVtab, /* Virtual table handle */
2178 int nArg, /* Number of SQL function arguments */
2179 const char *zName, /* Name of SQL function */
2180 void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
2181 void **ppArg /* OUT: User data for *pxFunc */
2182 ){
2183 Fts5Table *pTab = (Fts5Table*)pVtab;
2184 Fts5Auxiliary *pAux;
2185
2186 pAux = fts5FindAuxiliary(pTab, zName);
2187 if( pAux ){
2188 *pxFunc = fts5ApiCallback;
2189 *ppArg = (void*)pAux;
2190 return 1;
2191 }
2192
2193 /* No function of the specified name was found. Return 0. */
2194 return 0;
2195 }
2196
2197 /*
2198 ** Implementation of FTS5 xRename method. Rename an fts5 table.
2199 */
2200 static int fts5RenameMethod(
2201 sqlite3_vtab *pVtab, /* Virtual table handle */
2202 const char *zName /* New name of table */
2203 ){
2204 Fts5Table *pTab = (Fts5Table*)pVtab;
2205 return sqlite3Fts5StorageRename(pTab->pStorage, zName);
2206 }
2207
2208 /*
2209 ** The xSavepoint() method.
2210 **
2211 ** Flush the contents of the pending-terms table to disk.
2212 */
2213 static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
2214 Fts5Table *pTab = (Fts5Table*)pVtab;
2215 fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
2216 fts5TripCursors(pTab);
2217 return sqlite3Fts5StorageSync(pTab->pStorage, 0);
2218 }
2219
2220 /*
2221 ** The xRelease() method.
2222 **
2223 ** This is a no-op.
2224 */
2225 static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
2226 Fts5Table *pTab = (Fts5Table*)pVtab;
2227 fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
2228 fts5TripCursors(pTab);
2229 return sqlite3Fts5StorageSync(pTab->pStorage, 0);
2230 }
2231
2232 /*
2233 ** The xRollbackTo() method.
2234 **
2235 ** Discard the contents of the pending terms table.
2236 */
2237 static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
2238 Fts5Table *pTab = (Fts5Table*)pVtab;
2239 fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
2240 fts5TripCursors(pTab);
2241 return sqlite3Fts5StorageRollback(pTab->pStorage);
2242 }
2243
2244 /*
2245 ** Register a new auxiliary function with global context pGlobal.
2246 */
2247 static int fts5CreateAux(
2248 fts5_api *pApi, /* Global context (one per db handle) */
2249 const char *zName, /* Name of new function */
2250 void *pUserData, /* User data for aux. function */
2251 fts5_extension_function xFunc, /* Aux. function implementation */
2252 void(*xDestroy)(void*) /* Destructor for pUserData */
2253 ){
2254 Fts5Global *pGlobal = (Fts5Global*)pApi;
2255 int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
2256 if( rc==SQLITE_OK ){
2257 Fts5Auxiliary *pAux;
2258 int nName; /* Size of zName in bytes, including \0 */
2259 int nByte; /* Bytes of space to allocate */
2260
2261 nName = (int)strlen(zName) + 1;
2262 nByte = sizeof(Fts5Auxiliary) + nName;
2263 pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte);
2264 if( pAux ){
2265 memset(pAux, 0, nByte);
2266 pAux->zFunc = (char*)&pAux[1];
2267 memcpy(pAux->zFunc, zName, nName);
2268 pAux->pGlobal = pGlobal;
2269 pAux->pUserData = pUserData;
2270 pAux->xFunc = xFunc;
2271 pAux->xDestroy = xDestroy;
2272 pAux->pNext = pGlobal->pAux;
2273 pGlobal->pAux = pAux;
2274 }else{
2275 rc = SQLITE_NOMEM;
2276 }
2277 }
2278
2279 return rc;
2280 }
2281
2282 /*
2283 ** Register a new tokenizer. This is the implementation of the
2284 ** fts5_api.xCreateTokenizer() method.
2285 */
2286 static int fts5CreateTokenizer(
2287 fts5_api *pApi, /* Global context (one per db handle) */
2288 const char *zName, /* Name of new function */
2289 void *pUserData, /* User data for aux. function */
2290 fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
2291 void(*xDestroy)(void*) /* Destructor for pUserData */
2292 ){
2293 Fts5Global *pGlobal = (Fts5Global*)pApi;
2294 Fts5TokenizerModule *pNew;
2295 int nName; /* Size of zName and its \0 terminator */
2296 int nByte; /* Bytes of space to allocate */
2297 int rc = SQLITE_OK;
2298
2299 nName = (int)strlen(zName) + 1;
2300 nByte = sizeof(Fts5TokenizerModule) + nName;
2301 pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte);
2302 if( pNew ){
2303 memset(pNew, 0, nByte);
2304 pNew->zName = (char*)&pNew[1];
2305 memcpy(pNew->zName, zName, nName);
2306 pNew->pUserData = pUserData;
2307 pNew->x = *pTokenizer;
2308 pNew->xDestroy = xDestroy;
2309 pNew->pNext = pGlobal->pTok;
2310 pGlobal->pTok = pNew;
2311 if( pNew->pNext==0 ){
2312 pGlobal->pDfltTok = pNew;
2313 }
2314 }else{
2315 rc = SQLITE_NOMEM;
2316 }
2317
2318 return rc;
2319 }
2320
2321 static Fts5TokenizerModule *fts5LocateTokenizer(
2322 Fts5Global *pGlobal,
2323 const char *zName
2324 ){
2325 Fts5TokenizerModule *pMod = 0;
2326
2327 if( zName==0 ){
2328 pMod = pGlobal->pDfltTok;
2329 }else{
2330 for(pMod=pGlobal->pTok; pMod; pMod=pMod->pNext){
2331 if( sqlite3_stricmp(zName, pMod->zName)==0 ) break;
2332 }
2333 }
2334
2335 return pMod;
2336 }
2337
2338 /*
2339 ** Find a tokenizer. This is the implementation of the
2340 ** fts5_api.xFindTokenizer() method.
2341 */
2342 static int fts5FindTokenizer(
2343 fts5_api *pApi, /* Global context (one per db handle) */
2344 const char *zName, /* Name of new function */
2345 void **ppUserData,
2346 fts5_tokenizer *pTokenizer /* Populate this object */
2347 ){
2348 int rc = SQLITE_OK;
2349 Fts5TokenizerModule *pMod;
2350
2351 pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
2352 if( pMod ){
2353 *pTokenizer = pMod->x;
2354 *ppUserData = pMod->pUserData;
2355 }else{
2356 memset(pTokenizer, 0, sizeof(fts5_tokenizer));
2357 rc = SQLITE_ERROR;
2358 }
2359
2360 return rc;
2361 }
2362
2363 int sqlite3Fts5GetTokenizer(
2364 Fts5Global *pGlobal,
2365 const char **azArg,
2366 int nArg,
2367 Fts5Tokenizer **ppTok,
2368 fts5_tokenizer **ppTokApi,
2369 char **pzErr
2370 ){
2371 Fts5TokenizerModule *pMod;
2372 int rc = SQLITE_OK;
2373
2374 pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
2375 if( pMod==0 ){
2376 assert( nArg>0 );
2377 rc = SQLITE_ERROR;
2378 *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
2379 }else{
2380 rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok);
2381 *ppTokApi = &pMod->x;
2382 if( rc!=SQLITE_OK && pzErr ){
2383 *pzErr = sqlite3_mprintf("error in tokenizer constructor");
2384 }
2385 }
2386
2387 if( rc!=SQLITE_OK ){
2388 *ppTokApi = 0;
2389 *ppTok = 0;
2390 }
2391
2392 return rc;
2393 }
2394
2395 static void fts5ModuleDestroy(void *pCtx){
2396 Fts5TokenizerModule *pTok, *pNextTok;
2397 Fts5Auxiliary *pAux, *pNextAux;
2398 Fts5Global *pGlobal = (Fts5Global*)pCtx;
2399
2400 for(pAux=pGlobal->pAux; pAux; pAux=pNextAux){
2401 pNextAux = pAux->pNext;
2402 if( pAux->xDestroy ) pAux->xDestroy(pAux->pUserData);
2403 sqlite3_free(pAux);
2404 }
2405
2406 for(pTok=pGlobal->pTok; pTok; pTok=pNextTok){
2407 pNextTok = pTok->pNext;
2408 if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData);
2409 sqlite3_free(pTok);
2410 }
2411
2412 sqlite3_free(pGlobal);
2413 }
2414
2415 static void fts5Fts5Func(
2416 sqlite3_context *pCtx, /* Function call context */
2417 int nArg, /* Number of args */
2418 sqlite3_value **apVal /* Function arguments */
2419 ){
2420 Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
2421 char buf[8];
2422 assert( nArg==0 );
2423 assert( sizeof(buf)>=sizeof(pGlobal) );
2424 memcpy(buf, (void*)&pGlobal, sizeof(pGlobal));
2425 sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT);
2426 }
2427
2428 /*
2429 ** Implementation of fts5_source_id() function.
2430 */
2431 static void fts5SourceIdFunc(
2432 sqlite3_context *pCtx, /* Function call context */
2433 int nArg, /* Number of args */
2434 sqlite3_value **apVal /* Function arguments */
2435 ){
2436 assert( nArg==0 );
2437 sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
2438 }
2439
2440 static int fts5Init(sqlite3 *db){
2441 static const sqlite3_module fts5Mod = {
2442 /* iVersion */ 2,
2443 /* xCreate */ fts5CreateMethod,
2444 /* xConnect */ fts5ConnectMethod,
2445 /* xBestIndex */ fts5BestIndexMethod,
2446 /* xDisconnect */ fts5DisconnectMethod,
2447 /* xDestroy */ fts5DestroyMethod,
2448 /* xOpen */ fts5OpenMethod,
2449 /* xClose */ fts5CloseMethod,
2450 /* xFilter */ fts5FilterMethod,
2451 /* xNext */ fts5NextMethod,
2452 /* xEof */ fts5EofMethod,
2453 /* xColumn */ fts5ColumnMethod,
2454 /* xRowid */ fts5RowidMethod,
2455 /* xUpdate */ fts5UpdateMethod,
2456 /* xBegin */ fts5BeginMethod,
2457 /* xSync */ fts5SyncMethod,
2458 /* xCommit */ fts5CommitMethod,
2459 /* xRollback */ fts5RollbackMethod,
2460 /* xFindFunction */ fts5FindFunctionMethod,
2461 /* xRename */ fts5RenameMethod,
2462 /* xSavepoint */ fts5SavepointMethod,
2463 /* xRelease */ fts5ReleaseMethod,
2464 /* xRollbackTo */ fts5RollbackToMethod,
2465 };
2466
2467 int rc;
2468 Fts5Global *pGlobal = 0;
2469
2470 pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
2471 if( pGlobal==0 ){
2472 rc = SQLITE_NOMEM;
2473 }else{
2474 void *p = (void*)pGlobal;
2475 memset(pGlobal, 0, sizeof(Fts5Global));
2476 pGlobal->db = db;
2477 pGlobal->api.iVersion = 2;
2478 pGlobal->api.xCreateFunction = fts5CreateAux;
2479 pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
2480 pGlobal->api.xFindTokenizer = fts5FindTokenizer;
2481 rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
2482 if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
2483 if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
2484 if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
2485 if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
2486 if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
2487 if( rc==SQLITE_OK ){
2488 rc = sqlite3_create_function(
2489 db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
2490 );
2491 }
2492 if( rc==SQLITE_OK ){
2493 rc = sqlite3_create_function(
2494 db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
2495 );
2496 }
2497 }
2498 return rc;
2499 }
2500
2501 /*
2502 ** The following functions are used to register the module with SQLite. If
2503 ** this module is being built as part of the SQLite core (SQLITE_CORE is
2504 ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
2505 **
2506 ** Or, if this module is being built as a loadable extension,
2507 ** sqlite3Fts5Init() is omitted and the two standard entry points
2508 ** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
2509 */
2510 #ifndef SQLITE_CORE
2511 #ifdef _WIN32
2512 __declspec(dllexport)
2513 #endif
2514 int sqlite3_fts_init(
2515 sqlite3 *db,
2516 char **pzErrMsg,
2517 const sqlite3_api_routines *pApi
2518 ){
2519 SQLITE_EXTENSION_INIT2(pApi);
2520 (void)pzErrMsg; /* Unused parameter */
2521 return fts5Init(db);
2522 }
2523
2524 #ifdef _WIN32
2525 __declspec(dllexport)
2526 #endif
2527 int sqlite3_fts5_init(
2528 sqlite3 *db,
2529 char **pzErrMsg,
2530 const sqlite3_api_routines *pApi
2531 ){
2532 SQLITE_EXTENSION_INIT2(pApi);
2533 (void)pzErrMsg; /* Unused parameter */
2534 return fts5Init(db);
2535 }
2536 #else
2537 int sqlite3Fts5Init(sqlite3 *db){
2538 return fts5Init(db);
2539 }
2540 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698