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>