modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/fts3/fts3_term.c (about)

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