| Index: third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_vocab.c
|
| diff --git a/third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_vocab.c b/third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_vocab.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..860cfedb9bc4b6a0ff4c069e9a6f50cec2a73415
|
| --- /dev/null
|
| +++ b/third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_vocab.c
|
| @@ -0,0 +1,600 @@
|
| +/*
|
| +** 2015 May 08
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +******************************************************************************
|
| +**
|
| +** This is an SQLite virtual table module implementing direct access to an
|
| +** existing FTS5 index. The module may create several different types of
|
| +** tables:
|
| +**
|
| +** col:
|
| +** CREATE TABLE vocab(term, col, doc, cnt, PRIMARY KEY(term, col));
|
| +**
|
| +** One row for each term/column combination. The value of $doc is set to
|
| +** the number of fts5 rows that contain at least one instance of term
|
| +** $term within column $col. Field $cnt is set to the total number of
|
| +** instances of term $term in column $col (in any row of the fts5 table).
|
| +**
|
| +** row:
|
| +** CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term));
|
| +**
|
| +** One row for each term in the database. The value of $doc is set to
|
| +** the number of fts5 rows that contain at least one instance of term
|
| +** $term. Field $cnt is set to the total number of instances of term
|
| +** $term in the database.
|
| +*/
|
| +
|
| +
|
| +#include "fts5Int.h"
|
| +
|
| +
|
| +typedef struct Fts5VocabTable Fts5VocabTable;
|
| +typedef struct Fts5VocabCursor Fts5VocabCursor;
|
| +
|
| +struct Fts5VocabTable {
|
| + sqlite3_vtab base;
|
| + char *zFts5Tbl; /* Name of fts5 table */
|
| + char *zFts5Db; /* Db containing fts5 table */
|
| + sqlite3 *db; /* Database handle */
|
| + Fts5Global *pGlobal; /* FTS5 global object for this database */
|
| + int eType; /* FTS5_VOCAB_COL or ROW */
|
| +};
|
| +
|
| +struct Fts5VocabCursor {
|
| + sqlite3_vtab_cursor base;
|
| + sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */
|
| + Fts5Index *pIndex; /* Associated FTS5 index */
|
| +
|
| + int bEof; /* True if this cursor is at EOF */
|
| + Fts5IndexIter *pIter; /* Term/rowid iterator object */
|
| +
|
| + int nLeTerm; /* Size of zLeTerm in bytes */
|
| + char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
|
| +
|
| + /* These are used by 'col' tables only */
|
| + Fts5Config *pConfig; /* Fts5 table configuration */
|
| + int iCol;
|
| + i64 *aCnt;
|
| + i64 *aDoc;
|
| +
|
| + /* Output values used by 'row' and 'col' tables */
|
| + i64 rowid; /* This table's current rowid value */
|
| + Fts5Buffer term; /* Current value of 'term' column */
|
| +};
|
| +
|
| +#define FTS5_VOCAB_COL 0
|
| +#define FTS5_VOCAB_ROW 1
|
| +
|
| +#define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt"
|
| +#define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt"
|
| +
|
| +/*
|
| +** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
|
| +*/
|
| +#define FTS5_VOCAB_TERM_EQ 0x01
|
| +#define FTS5_VOCAB_TERM_GE 0x02
|
| +#define FTS5_VOCAB_TERM_LE 0x04
|
| +
|
| +
|
| +/*
|
| +** Translate a string containing an fts5vocab table type to an
|
| +** FTS5_VOCAB_XXX constant. If successful, set *peType to the output
|
| +** value and return SQLITE_OK. Otherwise, set *pzErr to an error message
|
| +** and return SQLITE_ERROR.
|
| +*/
|
| +static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){
|
| + int rc = SQLITE_OK;
|
| + char *zCopy = sqlite3Fts5Strndup(&rc, zType, -1);
|
| + if( rc==SQLITE_OK ){
|
| + sqlite3Fts5Dequote(zCopy);
|
| + if( sqlite3_stricmp(zCopy, "col")==0 ){
|
| + *peType = FTS5_VOCAB_COL;
|
| + }else
|
| +
|
| + if( sqlite3_stricmp(zCopy, "row")==0 ){
|
| + *peType = FTS5_VOCAB_ROW;
|
| + }else
|
| + {
|
| + *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
|
| + rc = SQLITE_ERROR;
|
| + }
|
| + sqlite3_free(zCopy);
|
| + }
|
| +
|
| + return rc;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** The xDisconnect() virtual table method.
|
| +*/
|
| +static int fts5VocabDisconnectMethod(sqlite3_vtab *pVtab){
|
| + Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab;
|
| + sqlite3_free(pTab);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** The xDestroy() virtual table method.
|
| +*/
|
| +static int fts5VocabDestroyMethod(sqlite3_vtab *pVtab){
|
| + Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab;
|
| + sqlite3_free(pTab);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** This function is the implementation of both the xConnect and xCreate
|
| +** methods of the FTS3 virtual table.
|
| +**
|
| +** The argv[] array contains the following:
|
| +**
|
| +** argv[0] -> module name ("fts5vocab")
|
| +** argv[1] -> database name
|
| +** argv[2] -> table name
|
| +**
|
| +** then:
|
| +**
|
| +** argv[3] -> name of fts5 table
|
| +** argv[4] -> type of fts5vocab table
|
| +**
|
| +** or, for tables in the TEMP schema only.
|
| +**
|
| +** argv[3] -> name of fts5 tables database
|
| +** argv[4] -> name of fts5 table
|
| +** argv[5] -> type of fts5vocab table
|
| +*/
|
| +static int fts5VocabInitVtab(
|
| + sqlite3 *db, /* The SQLite database connection */
|
| + void *pAux, /* Pointer to Fts5Global object */
|
| + int argc, /* Number of elements in argv array */
|
| + const char * const *argv, /* xCreate/xConnect argument array */
|
| + sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
|
| + char **pzErr /* Write any error message here */
|
| +){
|
| + const char *azSchema[] = {
|
| + "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
|
| + "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")"
|
| + };
|
| +
|
| + Fts5VocabTable *pRet = 0;
|
| + int rc = SQLITE_OK; /* Return code */
|
| + int bDb;
|
| +
|
| + bDb = (argc==6 && strlen(argv[1])==4 && memcmp("temp", argv[1], 4)==0);
|
| +
|
| + if( argc!=5 && bDb==0 ){
|
| + *pzErr = sqlite3_mprintf("wrong number of vtable arguments");
|
| + rc = SQLITE_ERROR;
|
| + }else{
|
| + int nByte; /* Bytes of space to allocate */
|
| + const char *zDb = bDb ? argv[3] : argv[1];
|
| + const char *zTab = bDb ? argv[4] : argv[3];
|
| + const char *zType = bDb ? argv[5] : argv[4];
|
| + int nDb = (int)strlen(zDb)+1;
|
| + int nTab = (int)strlen(zTab)+1;
|
| + int eType = 0;
|
| +
|
| + rc = fts5VocabTableType(zType, pzErr, &eType);
|
| + if( rc==SQLITE_OK ){
|
| + assert( eType>=0 && eType<sizeof(azSchema)/sizeof(azSchema[0]) );
|
| + rc = sqlite3_declare_vtab(db, azSchema[eType]);
|
| + }
|
| +
|
| + nByte = sizeof(Fts5VocabTable) + nDb + nTab;
|
| + pRet = sqlite3Fts5MallocZero(&rc, nByte);
|
| + if( pRet ){
|
| + pRet->pGlobal = (Fts5Global*)pAux;
|
| + pRet->eType = eType;
|
| + pRet->db = db;
|
| + pRet->zFts5Tbl = (char*)&pRet[1];
|
| + pRet->zFts5Db = &pRet->zFts5Tbl[nTab];
|
| + memcpy(pRet->zFts5Tbl, zTab, nTab);
|
| + memcpy(pRet->zFts5Db, zDb, nDb);
|
| + sqlite3Fts5Dequote(pRet->zFts5Tbl);
|
| + sqlite3Fts5Dequote(pRet->zFts5Db);
|
| + }
|
| + }
|
| +
|
| + *ppVTab = (sqlite3_vtab*)pRet;
|
| + return rc;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** The xConnect() and xCreate() methods for the virtual table. All the
|
| +** work is done in function fts5VocabInitVtab().
|
| +*/
|
| +static int fts5VocabConnectMethod(
|
| + sqlite3 *db, /* Database connection */
|
| + void *pAux, /* Pointer to tokenizer hash table */
|
| + int argc, /* Number of elements in argv array */
|
| + const char * const *argv, /* xCreate/xConnect argument array */
|
| + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
|
| + char **pzErr /* OUT: sqlite3_malloc'd error message */
|
| +){
|
| + return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
|
| +}
|
| +static int fts5VocabCreateMethod(
|
| + sqlite3 *db, /* Database connection */
|
| + void *pAux, /* Pointer to tokenizer hash table */
|
| + int argc, /* Number of elements in argv array */
|
| + const char * const *argv, /* xCreate/xConnect argument array */
|
| + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
|
| + char **pzErr /* OUT: sqlite3_malloc'd error message */
|
| +){
|
| + return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
|
| +}
|
| +
|
| +/*
|
| +** Implementation of the xBestIndex method.
|
| +*/
|
| +static int fts5VocabBestIndexMethod(
|
| + sqlite3_vtab *pVTab,
|
| + sqlite3_index_info *pInfo
|
| +){
|
| + int i;
|
| + int iTermEq = -1;
|
| + int iTermGe = -1;
|
| + int iTermLe = -1;
|
| + int idxNum = 0;
|
| + int nArg = 0;
|
| +
|
| + for(i=0; i<pInfo->nConstraint; i++){
|
| + struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
|
| + if( p->usable==0 ) continue;
|
| + if( p->iColumn==0 ){ /* term column */
|
| + if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i;
|
| + if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i;
|
| + if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i;
|
| + if( p->op==SQLITE_INDEX_CONSTRAINT_GE ) iTermGe = i;
|
| + if( p->op==SQLITE_INDEX_CONSTRAINT_GT ) iTermGe = i;
|
| + }
|
| + }
|
| +
|
| + if( iTermEq>=0 ){
|
| + idxNum |= FTS5_VOCAB_TERM_EQ;
|
| + pInfo->aConstraintUsage[iTermEq].argvIndex = ++nArg;
|
| + pInfo->estimatedCost = 100;
|
| + }else{
|
| + pInfo->estimatedCost = 1000000;
|
| + if( iTermGe>=0 ){
|
| + idxNum |= FTS5_VOCAB_TERM_GE;
|
| + pInfo->aConstraintUsage[iTermGe].argvIndex = ++nArg;
|
| + pInfo->estimatedCost = pInfo->estimatedCost / 2;
|
| + }
|
| + if( iTermLe>=0 ){
|
| + idxNum |= FTS5_VOCAB_TERM_LE;
|
| + pInfo->aConstraintUsage[iTermLe].argvIndex = ++nArg;
|
| + pInfo->estimatedCost = pInfo->estimatedCost / 2;
|
| + }
|
| + }
|
| +
|
| + pInfo->idxNum = idxNum;
|
| +
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Implementation of xOpen method.
|
| +*/
|
| +static int fts5VocabOpenMethod(
|
| + sqlite3_vtab *pVTab,
|
| + sqlite3_vtab_cursor **ppCsr
|
| +){
|
| + Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
|
| + Fts5Index *pIndex = 0;
|
| + Fts5Config *pConfig = 0;
|
| + Fts5VocabCursor *pCsr = 0;
|
| + int rc = SQLITE_OK;
|
| + sqlite3_stmt *pStmt = 0;
|
| + char *zSql = 0;
|
| +
|
| + zSql = sqlite3Fts5Mprintf(&rc,
|
| + "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
|
| + pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
|
| + );
|
| + if( zSql ){
|
| + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
|
| + }
|
| + sqlite3_free(zSql);
|
| + assert( rc==SQLITE_OK || pStmt==0 );
|
| + if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
|
| +
|
| + if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
|
| + i64 iId = sqlite3_column_int64(pStmt, 0);
|
| + pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig);
|
| + }
|
| +
|
| + if( rc==SQLITE_OK && pIndex==0 ){
|
| + rc = sqlite3_finalize(pStmt);
|
| + pStmt = 0;
|
| + if( rc==SQLITE_OK ){
|
| + pVTab->zErrMsg = sqlite3_mprintf(
|
| + "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
|
| + );
|
| + rc = SQLITE_ERROR;
|
| + }
|
| + }
|
| +
|
| + if( rc==SQLITE_OK ){
|
| + int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
|
| + pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
|
| + }
|
| +
|
| + if( pCsr ){
|
| + pCsr->pIndex = pIndex;
|
| + pCsr->pStmt = pStmt;
|
| + pCsr->pConfig = pConfig;
|
| + pCsr->aCnt = (i64*)&pCsr[1];
|
| + pCsr->aDoc = &pCsr->aCnt[pConfig->nCol];
|
| + }else{
|
| + sqlite3_finalize(pStmt);
|
| + }
|
| +
|
| + *ppCsr = (sqlite3_vtab_cursor*)pCsr;
|
| + return rc;
|
| +}
|
| +
|
| +static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
| + pCsr->rowid = 0;
|
| + sqlite3Fts5IterClose(pCsr->pIter);
|
| + pCsr->pIter = 0;
|
| + sqlite3_free(pCsr->zLeTerm);
|
| + pCsr->nLeTerm = -1;
|
| + pCsr->zLeTerm = 0;
|
| +}
|
| +
|
| +/*
|
| +** Close the cursor. For additional information see the documentation
|
| +** on the xClose method of the virtual table interface.
|
| +*/
|
| +static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
|
| + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
| + fts5VocabResetCursor(pCsr);
|
| + sqlite3Fts5BufferFree(&pCsr->term);
|
| + sqlite3_finalize(pCsr->pStmt);
|
| + sqlite3_free(pCsr);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Advance the cursor to the next row in the table.
|
| +*/
|
| +static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
| + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
| + Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
|
| + int rc = SQLITE_OK;
|
| + int nCol = pCsr->pConfig->nCol;
|
| +
|
| + pCsr->rowid++;
|
| +
|
| + if( pTab->eType==FTS5_VOCAB_COL ){
|
| + for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
|
| + if( pCsr->aCnt[pCsr->iCol] ) break;
|
| + }
|
| + }
|
| +
|
| + if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
|
| + if( sqlite3Fts5IterEof(pCsr->pIter) ){
|
| + pCsr->bEof = 1;
|
| + }else{
|
| + const char *zTerm;
|
| + int nTerm;
|
| +
|
| + zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
|
| + if( pCsr->nLeTerm>=0 ){
|
| + int nCmp = MIN(nTerm, pCsr->nLeTerm);
|
| + int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
|
| + if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
|
| + pCsr->bEof = 1;
|
| + return SQLITE_OK;
|
| + }
|
| + }
|
| +
|
| + sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
|
| + memset(pCsr->aCnt, 0, nCol * sizeof(i64));
|
| + memset(pCsr->aDoc, 0, nCol * sizeof(i64));
|
| + pCsr->iCol = 0;
|
| +
|
| + assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
|
| + while( rc==SQLITE_OK ){
|
| + i64 dummy;
|
| + const u8 *pPos; int nPos; /* Position list */
|
| + i64 iPos = 0; /* 64-bit position read from poslist */
|
| + int iOff = 0; /* Current offset within position list */
|
| +
|
| + rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
|
| + if( rc==SQLITE_OK ){
|
| + if( pTab->eType==FTS5_VOCAB_ROW ){
|
| + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
|
| + pCsr->aCnt[0]++;
|
| + }
|
| + pCsr->aDoc[0]++;
|
| + }else{
|
| + int iCol = -1;
|
| + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
|
| + int ii = FTS5_POS2COLUMN(iPos);
|
| + pCsr->aCnt[ii]++;
|
| + if( iCol!=ii ){
|
| + pCsr->aDoc[ii]++;
|
| + iCol = ii;
|
| + }
|
| + }
|
| + }
|
| + rc = sqlite3Fts5IterNextScan(pCsr->pIter);
|
| + }
|
| +
|
| + if( rc==SQLITE_OK ){
|
| + zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
|
| + if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){
|
| + break;
|
| + }
|
| + if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
|
| + while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++;
|
| + assert( pCsr->iCol<pCsr->pConfig->nCol );
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** This is the xFilter implementation for the virtual table.
|
| +*/
|
| +static int fts5VocabFilterMethod(
|
| + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
|
| + int idxNum, /* Strategy index */
|
| + const char *idxStr, /* Unused */
|
| + int nVal, /* Number of elements in apVal */
|
| + sqlite3_value **apVal /* Arguments for the indexing scheme */
|
| +){
|
| + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
| + int rc = SQLITE_OK;
|
| +
|
| + int iVal = 0;
|
| + int f = FTS5INDEX_QUERY_SCAN;
|
| + const char *zTerm = 0;
|
| + int nTerm = 0;
|
| +
|
| + sqlite3_value *pEq = 0;
|
| + sqlite3_value *pGe = 0;
|
| + sqlite3_value *pLe = 0;
|
| +
|
| + fts5VocabResetCursor(pCsr);
|
| + if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
|
| + if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
|
| + if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];
|
| +
|
| + if( pEq ){
|
| + zTerm = (const char *)sqlite3_value_text(pEq);
|
| + nTerm = sqlite3_value_bytes(pEq);
|
| + f = 0;
|
| + }else{
|
| + if( pGe ){
|
| + zTerm = (const char *)sqlite3_value_text(pGe);
|
| + nTerm = sqlite3_value_bytes(pGe);
|
| + }
|
| + if( pLe ){
|
| + const char *zCopy = (const char *)sqlite3_value_text(pLe);
|
| + pCsr->nLeTerm = sqlite3_value_bytes(pLe);
|
| + pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
|
| + if( pCsr->zLeTerm==0 ){
|
| + rc = SQLITE_NOMEM;
|
| + }else{
|
| + memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1);
|
| + }
|
| + }
|
| + }
|
| +
|
| +
|
| + if( rc==SQLITE_OK ){
|
| + rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
|
| + }
|
| + if( rc==SQLITE_OK ){
|
| + rc = fts5VocabNextMethod(pCursor);
|
| + }
|
| +
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** This is the xEof method of the virtual table. SQLite calls this
|
| +** routine to find out if it has reached the end of a result set.
|
| +*/
|
| +static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){
|
| + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
| + return pCsr->bEof;
|
| +}
|
| +
|
| +static int fts5VocabColumnMethod(
|
| + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
|
| + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
|
| + int iCol /* Index of column to read value from */
|
| +){
|
| + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
| +
|
| + if( iCol==0 ){
|
| + sqlite3_result_text(
|
| + pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
|
| + );
|
| + }
|
| + else if( ((Fts5VocabTable*)(pCursor->pVtab))->eType==FTS5_VOCAB_COL ){
|
| + assert( iCol==1 || iCol==2 || iCol==3 );
|
| + if( iCol==1 ){
|
| + const char *z = pCsr->pConfig->azCol[pCsr->iCol];
|
| + sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
|
| + }else if( iCol==2 ){
|
| + sqlite3_result_int64(pCtx, pCsr->aDoc[pCsr->iCol]);
|
| + }else{
|
| + sqlite3_result_int64(pCtx, pCsr->aCnt[pCsr->iCol]);
|
| + }
|
| + }else{
|
| + assert( iCol==1 || iCol==2 );
|
| + if( iCol==1 ){
|
| + sqlite3_result_int64(pCtx, pCsr->aDoc[0]);
|
| + }else{
|
| + sqlite3_result_int64(pCtx, pCsr->aCnt[0]);
|
| + }
|
| + }
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** This is the xRowid method. The SQLite core calls this routine to
|
| +** retrieve the rowid for the current row of the result set. The
|
| +** rowid should be written to *pRowid.
|
| +*/
|
| +static int fts5VocabRowidMethod(
|
| + sqlite3_vtab_cursor *pCursor,
|
| + sqlite_int64 *pRowid
|
| +){
|
| + Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
| + *pRowid = pCsr->rowid;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
|
| + static const sqlite3_module fts5Vocab = {
|
| + /* iVersion */ 2,
|
| + /* xCreate */ fts5VocabCreateMethod,
|
| + /* xConnect */ fts5VocabConnectMethod,
|
| + /* xBestIndex */ fts5VocabBestIndexMethod,
|
| + /* xDisconnect */ fts5VocabDisconnectMethod,
|
| + /* xDestroy */ fts5VocabDestroyMethod,
|
| + /* xOpen */ fts5VocabOpenMethod,
|
| + /* xClose */ fts5VocabCloseMethod,
|
| + /* xFilter */ fts5VocabFilterMethod,
|
| + /* xNext */ fts5VocabNextMethod,
|
| + /* xEof */ fts5VocabEofMethod,
|
| + /* xColumn */ fts5VocabColumnMethod,
|
| + /* xRowid */ fts5VocabRowidMethod,
|
| + /* xUpdate */ 0,
|
| + /* xBegin */ 0,
|
| + /* xSync */ 0,
|
| + /* xCommit */ 0,
|
| + /* xRollback */ 0,
|
| + /* xFindFunction */ 0,
|
| + /* xRename */ 0,
|
| + /* xSavepoint */ 0,
|
| + /* xRelease */ 0,
|
| + /* xRollbackTo */ 0,
|
| + };
|
| + void *p = (void*)pGlobal;
|
| +
|
| + return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
|
| +}
|
| +
|
| +
|
|
|