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