4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ******************************************************************************
13 ** This file is not part of the production FTS code. It is only used for
14 ** testing. It contains a virtual table implementation that provides direct
15 ** access to the full-text index of an FTS table.
19 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
26 typedef struct Fts3termTable Fts3termTable
;
27 typedef struct Fts3termCursor Fts3termCursor
;
29 struct Fts3termTable
{
30 sqlite3_vtab base
; /* Base class used by SQLite core */
31 int iIndex
; /* Index for Fts3Table.aIndex[] */
35 struct Fts3termCursor
{
36 sqlite3_vtab_cursor base
; /* Base class used by SQLite core */
37 Fts3MultiSegReader csr
; /* Must be right after "base" */
40 int isEof
; /* True if cursor is at EOF */
43 sqlite3_int64 iRowid
; /* Current 'rowid' value */
44 sqlite3_int64 iDocid
; /* Current 'docid' value */
45 int iCol
; /* Current 'col' value */
46 int iPos
; /* Current 'pos' value */
50 ** Schema of the terms table.
52 #define FTS3_TERMS_SCHEMA "CREATE TABLE x(term, docid, col, pos)"
55 ** This function does all the work for both the xConnect and xCreate methods.
56 ** These tables have no persistent representation of their own, so xConnect
57 ** and xCreate are identical operations.
59 static int fts3termConnectMethod(
60 sqlite3
*db
, /* Database connection */
61 void *pCtx
, /* Non-zero for an fts4prefix table */
62 int argc
, /* Number of elements in argv array */
63 const char * const *argv
, /* xCreate/xConnect argument array */
64 sqlite3_vtab
**ppVtab
, /* OUT: New sqlite3_vtab object */
65 char **pzErr
/* OUT: sqlite3_malloc'd error message */
67 char const *zDb
; /* Name of database (e.g. "main") */
68 char const *zFts3
; /* Name of fts3 table */
69 int nDb
; /* Result of strlen(zDb) */
70 int nFts3
; /* Result of strlen(zFts3) */
71 int nByte
; /* Bytes of space to allocate here */
72 int rc
; /* value returned by declare_vtab() */
73 Fts3termTable
*p
; /* Virtual table object to return */
76 UNUSED_PARAMETER(pCtx
);
78 iIndex
= atoi(argv
[4]);
82 /* The user should specify a single argument - the name of an fts3 table. */
84 *pzErr
= sqlite3_mprintf(
85 "wrong number of arguments to fts4term constructor"
91 nDb
= (int)strlen(zDb
);
93 nFts3
= (int)strlen(zFts3
);
95 rc
= sqlite3_declare_vtab(db
, FTS3_TERMS_SCHEMA
);
96 if( rc
!=SQLITE_OK
) return rc
;
98 nByte
= sizeof(Fts3termTable
) + sizeof(Fts3Table
) + nDb
+ nFts3
+ 2;
99 p
= (Fts3termTable
*)sqlite3_malloc(nByte
);
100 if( !p
) return SQLITE_NOMEM
;
103 p
->pFts3Tab
= (Fts3Table
*)&p
[1];
104 p
->pFts3Tab
->zDb
= (char *)&p
->pFts3Tab
[1];
105 p
->pFts3Tab
->zName
= &p
->pFts3Tab
->zDb
[nDb
+1];
106 p
->pFts3Tab
->db
= db
;
107 p
->pFts3Tab
->nIndex
= iIndex
+1;
110 memcpy((char *)p
->pFts3Tab
->zDb
, zDb
, nDb
);
111 memcpy((char *)p
->pFts3Tab
->zName
, zFts3
, nFts3
);
112 sqlite3Fts3Dequote((char *)p
->pFts3Tab
->zName
);
114 *ppVtab
= (sqlite3_vtab
*)p
;
119 ** This function does the work for both the xDisconnect and xDestroy methods.
120 ** These tables have no persistent representation of their own, so xDisconnect
121 ** and xDestroy are identical operations.
123 static int fts3termDisconnectMethod(sqlite3_vtab
*pVtab
){
124 Fts3termTable
*p
= (Fts3termTable
*)pVtab
;
125 Fts3Table
*pFts3
= p
->pFts3Tab
;
128 /* Free any prepared statements held */
129 for(i
=0; i
<SizeofArray(pFts3
->aStmt
); i
++){
130 sqlite3_finalize(pFts3
->aStmt
[i
]);
132 sqlite3_free(pFts3
->zSegmentsTbl
);
137 #define FTS4AUX_EQ_CONSTRAINT 1
138 #define FTS4AUX_GE_CONSTRAINT 2
139 #define FTS4AUX_LE_CONSTRAINT 4
142 ** xBestIndex - Analyze a WHERE and ORDER BY clause.
144 static int fts3termBestIndexMethod(
146 sqlite3_index_info
*pInfo
148 UNUSED_PARAMETER(pVTab
);
150 /* This vtab naturally does "ORDER BY term, docid, col, pos". */
151 if( pInfo
->nOrderBy
){
153 for(i
=0; i
<pInfo
->nOrderBy
; i
++){
154 if( pInfo
->aOrderBy
[i
].iColumn
!=i
|| pInfo
->aOrderBy
[i
].desc
) break;
156 if( i
==pInfo
->nOrderBy
){
157 pInfo
->orderByConsumed
= 1;
165 ** xOpen - Open a cursor.
167 static int fts3termOpenMethod(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCsr
){
168 Fts3termCursor
*pCsr
; /* Pointer to cursor object to return */
170 UNUSED_PARAMETER(pVTab
);
172 pCsr
= (Fts3termCursor
*)sqlite3_malloc(sizeof(Fts3termCursor
));
173 if( !pCsr
) return SQLITE_NOMEM
;
174 memset(pCsr
, 0, sizeof(Fts3termCursor
));
176 *ppCsr
= (sqlite3_vtab_cursor
*)pCsr
;
181 ** xClose - Close a cursor.
183 static int fts3termCloseMethod(sqlite3_vtab_cursor
*pCursor
){
184 Fts3Table
*pFts3
= ((Fts3termTable
*)pCursor
->pVtab
)->pFts3Tab
;
185 Fts3termCursor
*pCsr
= (Fts3termCursor
*)pCursor
;
187 sqlite3Fts3SegmentsClose(pFts3
);
188 sqlite3Fts3SegReaderFinish(&pCsr
->csr
);
194 ** xNext - Advance the cursor to the next row, if any.
196 static int fts3termNextMethod(sqlite3_vtab_cursor
*pCursor
){
197 Fts3termCursor
*pCsr
= (Fts3termCursor
*)pCursor
;
198 Fts3Table
*pFts3
= ((Fts3termTable
*)pCursor
->pVtab
)->pFts3Tab
;
202 /* Increment our pretend rowid value. */
205 /* Advance to the next term in the full-text index. */
206 if( pCsr
->csr
.aDoclist
==0
207 || pCsr
->pNext
>=&pCsr
->csr
.aDoclist
[pCsr
->csr
.nDoclist
-1]
209 rc
= sqlite3Fts3SegReaderStep(pFts3
, &pCsr
->csr
);
210 if( rc
!=SQLITE_ROW
){
218 pCsr
->pNext
= pCsr
->csr
.aDoclist
;
221 pCsr
->pNext
+= sqlite3Fts3GetVarint(pCsr
->pNext
, &pCsr
->iDocid
);
224 pCsr
->pNext
+= sqlite3Fts3GetVarint(pCsr
->pNext
, &v
);
226 pCsr
->pNext
+= sqlite3Fts3GetVarint(pCsr
->pNext
, &v
);
228 pCsr
->pNext
+= sqlite3Fts3GetVarint(pCsr
->pNext
, &v
);
234 pCsr
->pNext
+= sqlite3Fts3GetVarint(pCsr
->pNext
, &v
);
235 pCsr
->iCol
+= (int)v
;
237 pCsr
->pNext
+= sqlite3Fts3GetVarint(pCsr
->pNext
, &v
);
240 pCsr
->iPos
+= (int)(v
- 2);
246 ** xFilter - Initialize a cursor to point at the start of its data.
248 static int fts3termFilterMethod(
249 sqlite3_vtab_cursor
*pCursor
, /* The cursor used for this query */
250 int idxNum
, /* Strategy index */
251 const char *idxStr
, /* Unused */
252 int nVal
, /* Number of elements in apVal */
253 sqlite3_value
**apVal
/* Arguments for the indexing scheme */
255 Fts3termCursor
*pCsr
= (Fts3termCursor
*)pCursor
;
256 Fts3termTable
*p
= (Fts3termTable
*)pCursor
->pVtab
;
257 Fts3Table
*pFts3
= p
->pFts3Tab
;
260 UNUSED_PARAMETER(nVal
);
261 UNUSED_PARAMETER(idxNum
);
262 UNUSED_PARAMETER(idxStr
);
263 UNUSED_PARAMETER(apVal
);
265 assert( idxStr
==0 && idxNum
==0 );
267 /* In case this cursor is being reused, close and zero it. */
268 testcase(pCsr
->filter
.zTerm
);
269 sqlite3Fts3SegReaderFinish(&pCsr
->csr
);
270 memset(&pCsr
->csr
, 0, ((u8
*)&pCsr
[1]) - (u8
*)&pCsr
->csr
);
272 pCsr
->filter
.flags
= FTS3_SEGMENT_REQUIRE_POS
|FTS3_SEGMENT_IGNORE_EMPTY
;
273 pCsr
->filter
.flags
|= FTS3_SEGMENT_SCAN
;
275 rc
= sqlite3Fts3SegReaderCursor(pFts3
, 0, p
->iIndex
, FTS3_SEGCURSOR_ALL
,
276 pCsr
->filter
.zTerm
, pCsr
->filter
.nTerm
, 0, 1, &pCsr
->csr
279 rc
= sqlite3Fts3SegReaderStart(pFts3
, &pCsr
->csr
, &pCsr
->filter
);
282 rc
= fts3termNextMethod(pCursor
);
288 ** xEof - Return true if the cursor is at EOF, or false otherwise.
290 static int fts3termEofMethod(sqlite3_vtab_cursor
*pCursor
){
291 Fts3termCursor
*pCsr
= (Fts3termCursor
*)pCursor
;
296 ** xColumn - Return a column value.
298 static int fts3termColumnMethod(
299 sqlite3_vtab_cursor
*pCursor
, /* Cursor to retrieve value from */
300 sqlite3_context
*pCtx
, /* Context for sqlite3_result_xxx() calls */
301 int iCol
/* Index of column to read value from */
303 Fts3termCursor
*p
= (Fts3termCursor
*)pCursor
;
305 assert( iCol
>=0 && iCol
<=3 );
308 sqlite3_result_text(pCtx
, p
->csr
.zTerm
, p
->csr
.nTerm
, SQLITE_TRANSIENT
);
311 sqlite3_result_int64(pCtx
, p
->iDocid
);
314 sqlite3_result_int64(pCtx
, p
->iCol
);
317 sqlite3_result_int64(pCtx
, p
->iPos
);
325 ** xRowid - Return the current rowid for the cursor.
327 static int fts3termRowidMethod(
328 sqlite3_vtab_cursor
*pCursor
, /* Cursor to retrieve value from */
329 sqlite_int64
*pRowid
/* OUT: Rowid value */
331 Fts3termCursor
*pCsr
= (Fts3termCursor
*)pCursor
;
332 *pRowid
= pCsr
->iRowid
;
337 ** Register the fts3term module with database connection db. Return SQLITE_OK
338 ** if successful or an error code if sqlite3_create_module() fails.
340 int sqlite3Fts3InitTerm(sqlite3
*db
){
341 static const sqlite3_module fts3term_module
= {
343 fts3termConnectMethod
, /* xCreate */
344 fts3termConnectMethod
, /* xConnect */
345 fts3termBestIndexMethod
, /* xBestIndex */
346 fts3termDisconnectMethod
, /* xDisconnect */
347 fts3termDisconnectMethod
, /* xDestroy */
348 fts3termOpenMethod
, /* xOpen */
349 fts3termCloseMethod
, /* xClose */
350 fts3termFilterMethod
, /* xFilter */
351 fts3termNextMethod
, /* xNext */
352 fts3termEofMethod
, /* xEof */
353 fts3termColumnMethod
, /* xColumn */
354 fts3termRowidMethod
, /* xRowid */
360 0, /* xFindFunction */
366 int rc
; /* Return code */
368 rc
= sqlite3_create_module(db
, "fts4term", &fts3term_module
, 0);
373 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */