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

Side by Side Diff: third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_vocab.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 ** 2015 May 08
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 virtual table module implementing direct access to an
14 ** existing FTS5 index. The module may create several different types of
15 ** tables:
16 **
17 ** col:
18 ** CREATE TABLE vocab(term, col, doc, cnt, PRIMARY KEY(term, col));
19 **
20 ** One row for each term/column combination. The value of $doc is set to
21 ** the number of fts5 rows that contain at least one instance of term
22 ** $term within column $col. Field $cnt is set to the total number of
23 ** instances of term $term in column $col (in any row of the fts5 table).
24 **
25 ** row:
26 ** CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term));
27 **
28 ** One row for each term in the database. The value of $doc is set to
29 ** the number of fts5 rows that contain at least one instance of term
30 ** $term. Field $cnt is set to the total number of instances of term
31 ** $term in the database.
32 */
33
34
35 #include "fts5Int.h"
36
37
38 typedef struct Fts5VocabTable Fts5VocabTable;
39 typedef struct Fts5VocabCursor Fts5VocabCursor;
40
41 struct Fts5VocabTable {
42 sqlite3_vtab base;
43 char *zFts5Tbl; /* Name of fts5 table */
44 char *zFts5Db; /* Db containing fts5 table */
45 sqlite3 *db; /* Database handle */
46 Fts5Global *pGlobal; /* FTS5 global object for this database */
47 int eType; /* FTS5_VOCAB_COL or ROW */
48 };
49
50 struct Fts5VocabCursor {
51 sqlite3_vtab_cursor base;
52 sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */
53 Fts5Index *pIndex; /* Associated FTS5 index */
54
55 int bEof; /* True if this cursor is at EOF */
56 Fts5IndexIter *pIter; /* Term/rowid iterator object */
57
58 int nLeTerm; /* Size of zLeTerm in bytes */
59 char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
60
61 /* These are used by 'col' tables only */
62 Fts5Config *pConfig; /* Fts5 table configuration */
63 int iCol;
64 i64 *aCnt;
65 i64 *aDoc;
66
67 /* Output values used by 'row' and 'col' tables */
68 i64 rowid; /* This table's current rowid value */
69 Fts5Buffer term; /* Current value of 'term' column */
70 };
71
72 #define FTS5_VOCAB_COL 0
73 #define FTS5_VOCAB_ROW 1
74
75 #define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt"
76 #define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt"
77
78 /*
79 ** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
80 */
81 #define FTS5_VOCAB_TERM_EQ 0x01
82 #define FTS5_VOCAB_TERM_GE 0x02
83 #define FTS5_VOCAB_TERM_LE 0x04
84
85
86 /*
87 ** Translate a string containing an fts5vocab table type to an
88 ** FTS5_VOCAB_XXX constant. If successful, set *peType to the output
89 ** value and return SQLITE_OK. Otherwise, set *pzErr to an error message
90 ** and return SQLITE_ERROR.
91 */
92 static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){
93 int rc = SQLITE_OK;
94 char *zCopy = sqlite3Fts5Strndup(&rc, zType, -1);
95 if( rc==SQLITE_OK ){
96 sqlite3Fts5Dequote(zCopy);
97 if( sqlite3_stricmp(zCopy, "col")==0 ){
98 *peType = FTS5_VOCAB_COL;
99 }else
100
101 if( sqlite3_stricmp(zCopy, "row")==0 ){
102 *peType = FTS5_VOCAB_ROW;
103 }else
104 {
105 *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
106 rc = SQLITE_ERROR;
107 }
108 sqlite3_free(zCopy);
109 }
110
111 return rc;
112 }
113
114
115 /*
116 ** The xDisconnect() virtual table method.
117 */
118 static int fts5VocabDisconnectMethod(sqlite3_vtab *pVtab){
119 Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab;
120 sqlite3_free(pTab);
121 return SQLITE_OK;
122 }
123
124 /*
125 ** The xDestroy() virtual table method.
126 */
127 static int fts5VocabDestroyMethod(sqlite3_vtab *pVtab){
128 Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab;
129 sqlite3_free(pTab);
130 return SQLITE_OK;
131 }
132
133 /*
134 ** This function is the implementation of both the xConnect and xCreate
135 ** methods of the FTS3 virtual table.
136 **
137 ** The argv[] array contains the following:
138 **
139 ** argv[0] -> module name ("fts5vocab")
140 ** argv[1] -> database name
141 ** argv[2] -> table name
142 **
143 ** then:
144 **
145 ** argv[3] -> name of fts5 table
146 ** argv[4] -> type of fts5vocab table
147 **
148 ** or, for tables in the TEMP schema only.
149 **
150 ** argv[3] -> name of fts5 tables database
151 ** argv[4] -> name of fts5 table
152 ** argv[5] -> type of fts5vocab table
153 */
154 static int fts5VocabInitVtab(
155 sqlite3 *db, /* The SQLite database connection */
156 void *pAux, /* Pointer to Fts5Global object */
157 int argc, /* Number of elements in argv array */
158 const char * const *argv, /* xCreate/xConnect argument array */
159 sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
160 char **pzErr /* Write any error message here */
161 ){
162 const char *azSchema[] = {
163 "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
164 "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")"
165 };
166
167 Fts5VocabTable *pRet = 0;
168 int rc = SQLITE_OK; /* Return code */
169 int bDb;
170
171 bDb = (argc==6 && strlen(argv[1])==4 && memcmp("temp", argv[1], 4)==0);
172
173 if( argc!=5 && bDb==0 ){
174 *pzErr = sqlite3_mprintf("wrong number of vtable arguments");
175 rc = SQLITE_ERROR;
176 }else{
177 int nByte; /* Bytes of space to allocate */
178 const char *zDb = bDb ? argv[3] : argv[1];
179 const char *zTab = bDb ? argv[4] : argv[3];
180 const char *zType = bDb ? argv[5] : argv[4];
181 int nDb = (int)strlen(zDb)+1;
182 int nTab = (int)strlen(zTab)+1;
183 int eType = 0;
184
185 rc = fts5VocabTableType(zType, pzErr, &eType);
186 if( rc==SQLITE_OK ){
187 assert( eType>=0 && eType<sizeof(azSchema)/sizeof(azSchema[0]) );
188 rc = sqlite3_declare_vtab(db, azSchema[eType]);
189 }
190
191 nByte = sizeof(Fts5VocabTable) + nDb + nTab;
192 pRet = sqlite3Fts5MallocZero(&rc, nByte);
193 if( pRet ){
194 pRet->pGlobal = (Fts5Global*)pAux;
195 pRet->eType = eType;
196 pRet->db = db;
197 pRet->zFts5Tbl = (char*)&pRet[1];
198 pRet->zFts5Db = &pRet->zFts5Tbl[nTab];
199 memcpy(pRet->zFts5Tbl, zTab, nTab);
200 memcpy(pRet->zFts5Db, zDb, nDb);
201 sqlite3Fts5Dequote(pRet->zFts5Tbl);
202 sqlite3Fts5Dequote(pRet->zFts5Db);
203 }
204 }
205
206 *ppVTab = (sqlite3_vtab*)pRet;
207 return rc;
208 }
209
210
211 /*
212 ** The xConnect() and xCreate() methods for the virtual table. All the
213 ** work is done in function fts5VocabInitVtab().
214 */
215 static int fts5VocabConnectMethod(
216 sqlite3 *db, /* Database connection */
217 void *pAux, /* Pointer to tokenizer hash table */
218 int argc, /* Number of elements in argv array */
219 const char * const *argv, /* xCreate/xConnect argument array */
220 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
221 char **pzErr /* OUT: sqlite3_malloc'd error message */
222 ){
223 return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
224 }
225 static int fts5VocabCreateMethod(
226 sqlite3 *db, /* Database connection */
227 void *pAux, /* Pointer to tokenizer hash table */
228 int argc, /* Number of elements in argv array */
229 const char * const *argv, /* xCreate/xConnect argument array */
230 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
231 char **pzErr /* OUT: sqlite3_malloc'd error message */
232 ){
233 return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
234 }
235
236 /*
237 ** Implementation of the xBestIndex method.
238 */
239 static int fts5VocabBestIndexMethod(
240 sqlite3_vtab *pVTab,
241 sqlite3_index_info *pInfo
242 ){
243 int i;
244 int iTermEq = -1;
245 int iTermGe = -1;
246 int iTermLe = -1;
247 int idxNum = 0;
248 int nArg = 0;
249
250 for(i=0; i<pInfo->nConstraint; i++){
251 struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
252 if( p->usable==0 ) continue;
253 if( p->iColumn==0 ){ /* term column */
254 if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i;
255 if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i;
256 if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i;
257 if( p->op==SQLITE_INDEX_CONSTRAINT_GE ) iTermGe = i;
258 if( p->op==SQLITE_INDEX_CONSTRAINT_GT ) iTermGe = i;
259 }
260 }
261
262 if( iTermEq>=0 ){
263 idxNum |= FTS5_VOCAB_TERM_EQ;
264 pInfo->aConstraintUsage[iTermEq].argvIndex = ++nArg;
265 pInfo->estimatedCost = 100;
266 }else{
267 pInfo->estimatedCost = 1000000;
268 if( iTermGe>=0 ){
269 idxNum |= FTS5_VOCAB_TERM_GE;
270 pInfo->aConstraintUsage[iTermGe].argvIndex = ++nArg;
271 pInfo->estimatedCost = pInfo->estimatedCost / 2;
272 }
273 if( iTermLe>=0 ){
274 idxNum |= FTS5_VOCAB_TERM_LE;
275 pInfo->aConstraintUsage[iTermLe].argvIndex = ++nArg;
276 pInfo->estimatedCost = pInfo->estimatedCost / 2;
277 }
278 }
279
280 pInfo->idxNum = idxNum;
281
282 return SQLITE_OK;
283 }
284
285 /*
286 ** Implementation of xOpen method.
287 */
288 static int fts5VocabOpenMethod(
289 sqlite3_vtab *pVTab,
290 sqlite3_vtab_cursor **ppCsr
291 ){
292 Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
293 Fts5Index *pIndex = 0;
294 Fts5Config *pConfig = 0;
295 Fts5VocabCursor *pCsr = 0;
296 int rc = SQLITE_OK;
297 sqlite3_stmt *pStmt = 0;
298 char *zSql = 0;
299
300 zSql = sqlite3Fts5Mprintf(&rc,
301 "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
302 pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
303 );
304 if( zSql ){
305 rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
306 }
307 sqlite3_free(zSql);
308 assert( rc==SQLITE_OK || pStmt==0 );
309 if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
310
311 if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
312 i64 iId = sqlite3_column_int64(pStmt, 0);
313 pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig);
314 }
315
316 if( rc==SQLITE_OK && pIndex==0 ){
317 rc = sqlite3_finalize(pStmt);
318 pStmt = 0;
319 if( rc==SQLITE_OK ){
320 pVTab->zErrMsg = sqlite3_mprintf(
321 "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
322 );
323 rc = SQLITE_ERROR;
324 }
325 }
326
327 if( rc==SQLITE_OK ){
328 int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
329 pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
330 }
331
332 if( pCsr ){
333 pCsr->pIndex = pIndex;
334 pCsr->pStmt = pStmt;
335 pCsr->pConfig = pConfig;
336 pCsr->aCnt = (i64*)&pCsr[1];
337 pCsr->aDoc = &pCsr->aCnt[pConfig->nCol];
338 }else{
339 sqlite3_finalize(pStmt);
340 }
341
342 *ppCsr = (sqlite3_vtab_cursor*)pCsr;
343 return rc;
344 }
345
346 static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
347 pCsr->rowid = 0;
348 sqlite3Fts5IterClose(pCsr->pIter);
349 pCsr->pIter = 0;
350 sqlite3_free(pCsr->zLeTerm);
351 pCsr->nLeTerm = -1;
352 pCsr->zLeTerm = 0;
353 }
354
355 /*
356 ** Close the cursor. For additional information see the documentation
357 ** on the xClose method of the virtual table interface.
358 */
359 static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
360 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
361 fts5VocabResetCursor(pCsr);
362 sqlite3Fts5BufferFree(&pCsr->term);
363 sqlite3_finalize(pCsr->pStmt);
364 sqlite3_free(pCsr);
365 return SQLITE_OK;
366 }
367
368
369 /*
370 ** Advance the cursor to the next row in the table.
371 */
372 static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
373 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
374 Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
375 int rc = SQLITE_OK;
376 int nCol = pCsr->pConfig->nCol;
377
378 pCsr->rowid++;
379
380 if( pTab->eType==FTS5_VOCAB_COL ){
381 for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
382 if( pCsr->aCnt[pCsr->iCol] ) break;
383 }
384 }
385
386 if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
387 if( sqlite3Fts5IterEof(pCsr->pIter) ){
388 pCsr->bEof = 1;
389 }else{
390 const char *zTerm;
391 int nTerm;
392
393 zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
394 if( pCsr->nLeTerm>=0 ){
395 int nCmp = MIN(nTerm, pCsr->nLeTerm);
396 int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
397 if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
398 pCsr->bEof = 1;
399 return SQLITE_OK;
400 }
401 }
402
403 sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
404 memset(pCsr->aCnt, 0, nCol * sizeof(i64));
405 memset(pCsr->aDoc, 0, nCol * sizeof(i64));
406 pCsr->iCol = 0;
407
408 assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
409 while( rc==SQLITE_OK ){
410 i64 dummy;
411 const u8 *pPos; int nPos; /* Position list */
412 i64 iPos = 0; /* 64-bit position read from poslist */
413 int iOff = 0; /* Current offset within position list */
414
415 rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
416 if( rc==SQLITE_OK ){
417 if( pTab->eType==FTS5_VOCAB_ROW ){
418 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
419 pCsr->aCnt[0]++;
420 }
421 pCsr->aDoc[0]++;
422 }else{
423 int iCol = -1;
424 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
425 int ii = FTS5_POS2COLUMN(iPos);
426 pCsr->aCnt[ii]++;
427 if( iCol!=ii ){
428 pCsr->aDoc[ii]++;
429 iCol = ii;
430 }
431 }
432 }
433 rc = sqlite3Fts5IterNextScan(pCsr->pIter);
434 }
435
436 if( rc==SQLITE_OK ){
437 zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
438 if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){
439 break;
440 }
441 if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
442 }
443 }
444 }
445 }
446
447 if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
448 while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++;
449 assert( pCsr->iCol<pCsr->pConfig->nCol );
450 }
451 return rc;
452 }
453
454 /*
455 ** This is the xFilter implementation for the virtual table.
456 */
457 static int fts5VocabFilterMethod(
458 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
459 int idxNum, /* Strategy index */
460 const char *idxStr, /* Unused */
461 int nVal, /* Number of elements in apVal */
462 sqlite3_value **apVal /* Arguments for the indexing scheme */
463 ){
464 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
465 int rc = SQLITE_OK;
466
467 int iVal = 0;
468 int f = FTS5INDEX_QUERY_SCAN;
469 const char *zTerm = 0;
470 int nTerm = 0;
471
472 sqlite3_value *pEq = 0;
473 sqlite3_value *pGe = 0;
474 sqlite3_value *pLe = 0;
475
476 fts5VocabResetCursor(pCsr);
477 if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
478 if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
479 if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];
480
481 if( pEq ){
482 zTerm = (const char *)sqlite3_value_text(pEq);
483 nTerm = sqlite3_value_bytes(pEq);
484 f = 0;
485 }else{
486 if( pGe ){
487 zTerm = (const char *)sqlite3_value_text(pGe);
488 nTerm = sqlite3_value_bytes(pGe);
489 }
490 if( pLe ){
491 const char *zCopy = (const char *)sqlite3_value_text(pLe);
492 pCsr->nLeTerm = sqlite3_value_bytes(pLe);
493 pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
494 if( pCsr->zLeTerm==0 ){
495 rc = SQLITE_NOMEM;
496 }else{
497 memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1);
498 }
499 }
500 }
501
502
503 if( rc==SQLITE_OK ){
504 rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
505 }
506 if( rc==SQLITE_OK ){
507 rc = fts5VocabNextMethod(pCursor);
508 }
509
510 return rc;
511 }
512
513 /*
514 ** This is the xEof method of the virtual table. SQLite calls this
515 ** routine to find out if it has reached the end of a result set.
516 */
517 static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){
518 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
519 return pCsr->bEof;
520 }
521
522 static int fts5VocabColumnMethod(
523 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
524 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
525 int iCol /* Index of column to read value from */
526 ){
527 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
528
529 if( iCol==0 ){
530 sqlite3_result_text(
531 pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
532 );
533 }
534 else if( ((Fts5VocabTable*)(pCursor->pVtab))->eType==FTS5_VOCAB_COL ){
535 assert( iCol==1 || iCol==2 || iCol==3 );
536 if( iCol==1 ){
537 const char *z = pCsr->pConfig->azCol[pCsr->iCol];
538 sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
539 }else if( iCol==2 ){
540 sqlite3_result_int64(pCtx, pCsr->aDoc[pCsr->iCol]);
541 }else{
542 sqlite3_result_int64(pCtx, pCsr->aCnt[pCsr->iCol]);
543 }
544 }else{
545 assert( iCol==1 || iCol==2 );
546 if( iCol==1 ){
547 sqlite3_result_int64(pCtx, pCsr->aDoc[0]);
548 }else{
549 sqlite3_result_int64(pCtx, pCsr->aCnt[0]);
550 }
551 }
552 return SQLITE_OK;
553 }
554
555 /*
556 ** This is the xRowid method. The SQLite core calls this routine to
557 ** retrieve the rowid for the current row of the result set. The
558 ** rowid should be written to *pRowid.
559 */
560 static int fts5VocabRowidMethod(
561 sqlite3_vtab_cursor *pCursor,
562 sqlite_int64 *pRowid
563 ){
564 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
565 *pRowid = pCsr->rowid;
566 return SQLITE_OK;
567 }
568
569 int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
570 static const sqlite3_module fts5Vocab = {
571 /* iVersion */ 2,
572 /* xCreate */ fts5VocabCreateMethod,
573 /* xConnect */ fts5VocabConnectMethod,
574 /* xBestIndex */ fts5VocabBestIndexMethod,
575 /* xDisconnect */ fts5VocabDisconnectMethod,
576 /* xDestroy */ fts5VocabDestroyMethod,
577 /* xOpen */ fts5VocabOpenMethod,
578 /* xClose */ fts5VocabCloseMethod,
579 /* xFilter */ fts5VocabFilterMethod,
580 /* xNext */ fts5VocabNextMethod,
581 /* xEof */ fts5VocabEofMethod,
582 /* xColumn */ fts5VocabColumnMethod,
583 /* xRowid */ fts5VocabRowidMethod,
584 /* xUpdate */ 0,
585 /* xBegin */ 0,
586 /* xSync */ 0,
587 /* xCommit */ 0,
588 /* xRollback */ 0,
589 /* xFindFunction */ 0,
590 /* xRename */ 0,
591 /* xSavepoint */ 0,
592 /* xRelease */ 0,
593 /* xRollbackTo */ 0,
594 };
595 void *p = (void*)pGlobal;
596
597 return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
598 }
599
600
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698