1
0

fts3_term.c 11 KB

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