fts3_term.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. ** 2011 Jan 27
  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 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.
  16. */
  17. #include "fts3Int.h"
  18. #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
  19. #ifdef SQLITE_TEST
  20. #include <string.h>
  21. #include <assert.h>
  22. #include <stdlib.h>
  23. typedef struct Fts3termTable Fts3termTable;
  24. typedef struct Fts3termCursor Fts3termCursor;
  25. struct Fts3termTable {
  26. sqlite3_vtab base; /* Base class used by SQLite core */
  27. int iIndex; /* Index for Fts3Table.aIndex[] */
  28. Fts3Table *pFts3Tab;
  29. };
  30. struct Fts3termCursor {
  31. sqlite3_vtab_cursor base; /* Base class used by SQLite core */
  32. Fts3MultiSegReader csr; /* Must be right after "base" */
  33. Fts3SegFilter filter;
  34. int isEof; /* True if cursor is at EOF */
  35. char *pNext;
  36. sqlite3_int64 iRowid; /* Current 'rowid' value */
  37. sqlite3_int64 iDocid; /* Current 'docid' value */
  38. int iCol; /* Current 'col' value */
  39. int iPos; /* Current 'pos' value */
  40. };
  41. /*
  42. ** Schema of the terms table.
  43. */
  44. #define FTS3_TERMS_SCHEMA "CREATE TABLE x(term, docid, col, pos)"
  45. /*
  46. ** This function does all the work for both the xConnect and xCreate methods.
  47. ** These tables have no persistent representation of their own, so xConnect
  48. ** and xCreate are identical operations.
  49. */
  50. static int fts3termConnectMethod(
  51. sqlite3 *db, /* Database connection */
  52. void *pCtx, /* Non-zero for an fts4prefix table */
  53. int argc, /* Number of elements in argv array */
  54. const char * const *argv, /* xCreate/xConnect argument array */
  55. sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
  56. char **pzErr /* OUT: sqlite3_malloc'd error message */
  57. ){
  58. char const *zDb; /* Name of database (e.g. "main") */
  59. char const *zFts3; /* Name of fts3 table */
  60. int nDb; /* Result of strlen(zDb) */
  61. int nFts3; /* Result of strlen(zFts3) */
  62. sqlite3_int64 nByte; /* Bytes of space to allocate here */
  63. int rc; /* value returned by declare_vtab() */
  64. Fts3termTable *p; /* Virtual table object to return */
  65. int iIndex = 0;
  66. UNUSED_PARAMETER(pCtx);
  67. if( argc==5 ){
  68. iIndex = atoi(argv[4]);
  69. argc--;
  70. }
  71. *ppVtab = 0;
  72. /* The user should specify a single argument - the name of an fts3 table. */
  73. if( argc!=4 ){
  74. sqlite3Fts3ErrMsg(pzErr,
  75. "wrong number of arguments to fts4term constructor"
  76. );
  77. return SQLITE_ERROR;
  78. }
  79. zDb = argv[1];
  80. nDb = (int)strlen(zDb);
  81. zFts3 = argv[3];
  82. nFts3 = (int)strlen(zFts3);
  83. rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
  84. if( rc!=SQLITE_OK ) return rc;
  85. nByte = sizeof(Fts3termTable);
  86. p = (Fts3termTable *)sqlite3Fts3MallocZero(nByte);
  87. if( !p ) return SQLITE_NOMEM;
  88. p->pFts3Tab = (Fts3Table*)sqlite3Fts3MallocZero(
  89. sizeof(Fts3Table) + nDb + nFts3 + 2
  90. );
  91. if( p->pFts3Tab==0 ){
  92. sqlite3_free(p);
  93. return SQLITE_NOMEM;
  94. }
  95. p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1];
  96. p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1];
  97. p->pFts3Tab->db = db;
  98. p->pFts3Tab->nIndex = iIndex+1;
  99. p->iIndex = iIndex;
  100. memcpy((char *)p->pFts3Tab->zDb, zDb, nDb);
  101. memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3);
  102. sqlite3Fts3Dequote((char *)p->pFts3Tab->zName);
  103. *ppVtab = (sqlite3_vtab *)p;
  104. return SQLITE_OK;
  105. }
  106. /*
  107. ** This function does the work for both the xDisconnect and xDestroy methods.
  108. ** These tables have no persistent representation of their own, so xDisconnect
  109. ** and xDestroy are identical operations.
  110. */
  111. static int fts3termDisconnectMethod(sqlite3_vtab *pVtab){
  112. Fts3termTable *p = (Fts3termTable *)pVtab;
  113. Fts3Table *pFts3 = p->pFts3Tab;
  114. int i;
  115. /* Free any prepared statements held */
  116. for(i=0; i<SizeofArray(pFts3->aStmt); i++){
  117. sqlite3_finalize(pFts3->aStmt[i]);
  118. }
  119. sqlite3_free(pFts3->zSegmentsTbl);
  120. sqlite3_free(pFts3);
  121. sqlite3_free(p);
  122. return SQLITE_OK;
  123. }
  124. #define FTS4AUX_EQ_CONSTRAINT 1
  125. #define FTS4AUX_GE_CONSTRAINT 2
  126. #define FTS4AUX_LE_CONSTRAINT 4
  127. /*
  128. ** xBestIndex - Analyze a WHERE and ORDER BY clause.
  129. */
  130. static int fts3termBestIndexMethod(
  131. sqlite3_vtab *pVTab,
  132. sqlite3_index_info *pInfo
  133. ){
  134. UNUSED_PARAMETER(pVTab);
  135. /* This vtab naturally does "ORDER BY term, docid, col, pos". */
  136. if( pInfo->nOrderBy ){
  137. int i;
  138. for(i=0; i<pInfo->nOrderBy; i++){
  139. if( pInfo->aOrderBy[i].iColumn!=i || pInfo->aOrderBy[i].desc ) break;
  140. }
  141. if( i==pInfo->nOrderBy ){
  142. pInfo->orderByConsumed = 1;
  143. }
  144. }
  145. return SQLITE_OK;
  146. }
  147. /*
  148. ** xOpen - Open a cursor.
  149. */
  150. static int fts3termOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
  151. Fts3termCursor *pCsr; /* Pointer to cursor object to return */
  152. UNUSED_PARAMETER(pVTab);
  153. pCsr = (Fts3termCursor *)sqlite3_malloc(sizeof(Fts3termCursor));
  154. if( !pCsr ) return SQLITE_NOMEM;
  155. memset(pCsr, 0, sizeof(Fts3termCursor));
  156. *ppCsr = (sqlite3_vtab_cursor *)pCsr;
  157. return SQLITE_OK;
  158. }
  159. /*
  160. ** xClose - Close a cursor.
  161. */
  162. static int fts3termCloseMethod(sqlite3_vtab_cursor *pCursor){
  163. Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab;
  164. Fts3termCursor *pCsr = (Fts3termCursor *)pCursor;
  165. sqlite3Fts3SegmentsClose(pFts3);
  166. sqlite3Fts3SegReaderFinish(&pCsr->csr);
  167. sqlite3_free(pCsr);
  168. return SQLITE_OK;
  169. }
  170. /*
  171. ** xNext - Advance the cursor to the next row, if any.
  172. */
  173. static int fts3termNextMethod(sqlite3_vtab_cursor *pCursor){
  174. Fts3termCursor *pCsr = (Fts3termCursor *)pCursor;
  175. Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab;
  176. int rc;
  177. sqlite3_int64 v;
  178. /* Increment our pretend rowid value. */
  179. pCsr->iRowid++;
  180. /* Advance to the next term in the full-text index. */
  181. if( pCsr->csr.aDoclist==0
  182. || pCsr->pNext>=&pCsr->csr.aDoclist[pCsr->csr.nDoclist-1]
  183. ){
  184. rc = sqlite3Fts3SegReaderStep(pFts3, &pCsr->csr);
  185. if( rc!=SQLITE_ROW ){
  186. pCsr->isEof = 1;
  187. return rc;
  188. }
  189. pCsr->iCol = 0;
  190. pCsr->iPos = 0;
  191. pCsr->iDocid = 0;
  192. pCsr->pNext = pCsr->csr.aDoclist;
  193. /* Read docid */
  194. pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &pCsr->iDocid);
  195. }
  196. pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v);
  197. if( v==0 ){
  198. pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v);
  199. pCsr->iDocid += v;
  200. pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v);
  201. pCsr->iCol = 0;
  202. pCsr->iPos = 0;
  203. }
  204. if( v==1 ){
  205. pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v);
  206. pCsr->iCol += (int)v;
  207. pCsr->iPos = 0;
  208. pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v);
  209. }
  210. pCsr->iPos += (int)(v - 2);
  211. return SQLITE_OK;
  212. }
  213. /*
  214. ** xFilter - Initialize a cursor to point at the start of its data.
  215. */
  216. static int fts3termFilterMethod(
  217. sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
  218. int idxNum, /* Strategy index */
  219. const char *idxStr, /* Unused */
  220. int nVal, /* Number of elements in apVal */
  221. sqlite3_value **apVal /* Arguments for the indexing scheme */
  222. ){
  223. Fts3termCursor *pCsr = (Fts3termCursor *)pCursor;
  224. Fts3termTable *p = (Fts3termTable *)pCursor->pVtab;
  225. Fts3Table *pFts3 = p->pFts3Tab;
  226. int rc;
  227. UNUSED_PARAMETER(nVal);
  228. UNUSED_PARAMETER(idxNum);
  229. UNUSED_PARAMETER(idxStr);
  230. UNUSED_PARAMETER(apVal);
  231. assert( idxStr==0 && idxNum==0 );
  232. /* In case this cursor is being reused, close and zero it. */
  233. testcase(pCsr->filter.zTerm);
  234. sqlite3Fts3SegReaderFinish(&pCsr->csr);
  235. memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr);
  236. pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY;
  237. pCsr->filter.flags |= FTS3_SEGMENT_SCAN;
  238. rc = sqlite3Fts3SegReaderCursor(pFts3, 0, p->iIndex, FTS3_SEGCURSOR_ALL,
  239. pCsr->filter.zTerm, pCsr->filter.nTerm, 0, 1, &pCsr->csr
  240. );
  241. if( rc==SQLITE_OK ){
  242. rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter);
  243. }
  244. if( rc==SQLITE_OK ){
  245. rc = fts3termNextMethod(pCursor);
  246. }
  247. return rc;
  248. }
  249. /*
  250. ** xEof - Return true if the cursor is at EOF, or false otherwise.
  251. */
  252. static int fts3termEofMethod(sqlite3_vtab_cursor *pCursor){
  253. Fts3termCursor *pCsr = (Fts3termCursor *)pCursor;
  254. return pCsr->isEof;
  255. }
  256. /*
  257. ** xColumn - Return a column value.
  258. */
  259. static int fts3termColumnMethod(
  260. sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
  261. sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
  262. int iCol /* Index of column to read value from */
  263. ){
  264. Fts3termCursor *p = (Fts3termCursor *)pCursor;
  265. assert( iCol>=0 && iCol<=3 );
  266. switch( iCol ){
  267. case 0:
  268. sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT);
  269. break;
  270. case 1:
  271. sqlite3_result_int64(pCtx, p->iDocid);
  272. break;
  273. case 2:
  274. sqlite3_result_int64(pCtx, p->iCol);
  275. break;
  276. default:
  277. sqlite3_result_int64(pCtx, p->iPos);
  278. break;
  279. }
  280. return SQLITE_OK;
  281. }
  282. /*
  283. ** xRowid - Return the current rowid for the cursor.
  284. */
  285. static int fts3termRowidMethod(
  286. sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
  287. sqlite_int64 *pRowid /* OUT: Rowid value */
  288. ){
  289. Fts3termCursor *pCsr = (Fts3termCursor *)pCursor;
  290. *pRowid = pCsr->iRowid;
  291. return SQLITE_OK;
  292. }
  293. /*
  294. ** Register the fts3term module with database connection db. Return SQLITE_OK
  295. ** if successful or an error code if sqlite3_create_module() fails.
  296. */
  297. int sqlite3Fts3InitTerm(sqlite3 *db){
  298. static const sqlite3_module fts3term_module = {
  299. 0, /* iVersion */
  300. fts3termConnectMethod, /* xCreate */
  301. fts3termConnectMethod, /* xConnect */
  302. fts3termBestIndexMethod, /* xBestIndex */
  303. fts3termDisconnectMethod, /* xDisconnect */
  304. fts3termDisconnectMethod, /* xDestroy */
  305. fts3termOpenMethod, /* xOpen */
  306. fts3termCloseMethod, /* xClose */
  307. fts3termFilterMethod, /* xFilter */
  308. fts3termNextMethod, /* xNext */
  309. fts3termEofMethod, /* xEof */
  310. fts3termColumnMethod, /* xColumn */
  311. fts3termRowidMethod, /* xRowid */
  312. 0, /* xUpdate */
  313. 0, /* xBegin */
  314. 0, /* xSync */
  315. 0, /* xCommit */
  316. 0, /* xRollback */
  317. 0, /* xFindFunction */
  318. 0, /* xRename */
  319. 0, /* xSavepoint */
  320. 0, /* xRelease */
  321. 0, /* xRollbackTo */
  322. 0, /* xShadowName */
  323. 0 /* xIntegrity */
  324. };
  325. int rc; /* Return code */
  326. rc = sqlite3_create_module(db, "fts4term", &fts3term_module, 0);
  327. return rc;
  328. }
  329. #endif
  330. #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */