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

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

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

Powered by Google App Engine
This is Rietveld 408576698