/ Check-in [a32849d6]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:The virtual table compiles but does not work and is missing many features. This is an incremental check-in.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | lsm-vtab
Files: files | file ages | folders
SHA1: a32849d6bf66462d1f511714a00f24519d7b7079
User & Date: drh 2015-11-17 00:15:21
Context
2015-11-17
02:23
Basic functionality is now working. check-in: aa129c51 user: drh tags: lsm-vtab
00:15
The virtual table compiles but does not work and is missing many features. This is an incremental check-in. check-in: a32849d6 user: drh tags: lsm-vtab
2015-11-16
16:00
Import the LSM code from SQLite4 for use in an experimental virtual table. NB: This is a speculative experiment and could easily result in a dead-end branch. check-in: 3d930501 user: drh tags: lsm-vtab
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/lsm1/Makefile.

    14     14     lsm_mem.o \
    15     15     lsm_mutex.o \
    16     16     lsm_shared.o \
    17     17     lsm_sorted.o \
    18     18     lsm_str.o \
    19     19     lsm_tree.o \
    20     20     lsm_unix.o \
    21         -  lsm_varint.o
           21  +  lsm_varint.o \
           22  +  lsm_vtab.o
    22     23   
    23     24   LSMHDR   = \
    24     25     lsm.h \
    25     26     lsmInt.h
    26     27   
    27     28   all: lsm.so
    28     29   
    29     30   lsm.so:	$(LSMOBJ)
    30     31   	$(CC) $(CFLAGS) -shared -o lsm.so $(LSMOBJ)
    31     32   
    32     33   %.o:	%.c $(LSMHDR)
    33     34   	$(CC) $(CFLAGS) -c $<

Changes to ext/lsm1/lsm.h.

   616    616   ** successfully also depends on the most recent seek function called on
   617    617   ** the cursor. Specifically:
   618    618   **
   619    619   ** <ul>
   620    620   ** <li> At least one seek function must have been called on the cursor.
   621    621   ** <li> To call lsm_csr_next(), the most recent call to a seek function must
   622    622   ** have been either lsm_csr_first() or a call to lsm_csr_seek() specifying
   623         -** LSM_SEEK_GE. 
          623  +** LSM_SEEK_GE.
   624    624   ** <li> To call lsm_csr_prev(), the most recent call to a seek function must
   625         -** have been either lsm_csr_first() or a call to lsm_csr_seek() specifying
   626         -** LSM_SEEK_GE. 
          625  +** have been either lsm_csr_last() or a call to lsm_csr_seek() specifying
          626  +** LSM_SEEK_LE.
   627    627   ** </ul>
   628    628   **
   629    629   ** Otherwise, if the above conditions are not met when lsm_csr_next or 
   630    630   ** lsm_csr_prev is called, LSM_MISUSE is returned and the cursor position
   631    631   ** remains unchanged.
   632    632   */
   633    633   int lsm_csr_next(lsm_cursor *pCsr);

Changes to ext/lsm1/lsm_sorted.c.

    66     66   **   Finally, the blob of data containing the key, and for LSM_INSERT
    67     67   **   records, the value as well.
    68     68   */
    69     69   
    70     70   #ifndef _LSM_INT_H
    71     71   # include "lsmInt.h"
    72     72   #endif
    73         -#include "sqlite3.h"            /* only for sqlite3_snprintf() */
    74     73   
    75     74   #define LSM_LOG_STRUCTURE 0
    76     75   #define LSM_LOG_DATA      0
    77     76   
    78     77   /*
    79     78   ** Macros to help decode record types.
    80     79   */
................................................................................
  5466   5465     Segment *pSeg
  5467   5466   ){
  5468   5467     int i = 0;
  5469   5468     if( pSeg ){
  5470   5469       char *zSeg;
  5471   5470   
  5472   5471       zSeg = segToString(pDb->pEnv, pSeg, nMin);
  5473         -    sqlite3_snprintf(nBuf-i, &aBuf[i], "%s", zSeg);
         5472  +    snprintf(&aBuf[i], nBuf-i, "%s", zSeg);
  5474   5473       i += strlen(&aBuf[i]);
  5475   5474       lsmFree(pDb->pEnv, zSeg);
  5476   5475   
  5477   5476   #ifdef LSM_LOG_FREELIST
  5478   5477       lsmInfoArrayStructure(pDb, 1, pSeg->iFirst, &zSeg);
  5479         -    sqlite3_snprintf(nBuf-i, &aBuf[i], "    (%s)", zSeg);
         5478  +    snprintf(&aBuf[i], nBuf-1, "    (%s)", zSeg);
  5480   5479       i += strlen(&aBuf[i]);
  5481   5480       lsmFree(pDb->pEnv, zSeg);
  5482   5481   #endif
         5482  +    aBuf[nBuf] = 0;
  5483   5483     }else{
  5484   5484       aBuf[0] = '\0';
  5485   5485     }
  5486   5486   
  5487   5487     return i;
  5488   5488   }
  5489   5489   
................................................................................
  5876   5876             fileToString(pDb, zLeft, sizeof(zLeft), 24, aLeft[i]); 
  5877   5877           }
  5878   5878           if( i<nRight ){ 
  5879   5879             fileToString(pDb, zRight, sizeof(zRight), 24, aRight[i]); 
  5880   5880           }
  5881   5881   
  5882   5882           if( i==0 ){
  5883         -          sqlite3_snprintf(sizeof(zLevel), zLevel, "L%d: (age=%d) (flags=%.4x)",
         5883  +          snprintf(zLevel, sizeof(zLevel), "L%d: (age=%d) (flags=%.4x)",
  5884   5884                 iLevel, (int)pLevel->iAge, (int)pLevel->flags
  5885   5885             );
  5886   5886           }else{
  5887   5887             zLevel[0] = '\0';
  5888   5888           }
  5889   5889   
  5890   5890           if( nRight==0 ){

Added ext/lsm1/lsm_vtab.c.

            1  +/*
            2  +** 2015-11-16
            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 implements a simple virtual table wrapper around the LSM
           14  +** storage engine from SQLite4.
           15  +*/
           16  +#include "sqlite3ext.h"
           17  +SQLITE_EXTENSION_INIT1
           18  +#include "lsm.h"
           19  +#include <assert.h>
           20  +#include <string.h>
           21  +
           22  +/* Forward declaration of subclasses of virtual table objects */
           23  +typedef struct lsm1_vtab lsm1_vtab;
           24  +typedef struct lsm1_cursor lsm1_cursor;
           25  +
           26  +/* Primitive types */
           27  +typedef unsigned char u8;
           28  +
           29  +/* An open connection to an LSM table */
           30  +struct lsm1_vtab {
           31  +  sqlite3_vtab base;          /* Base class - must be first */
           32  +  lsm_db *pDb;                /* Open connection to the LSM table */
           33  +};
           34  +
           35  +
           36  +/* lsm1_cursor is a subclass of sqlite3_vtab_cursor which will
           37  +** serve as the underlying representation of a cursor that scans
           38  +** over rows of the result
           39  +*/
           40  +struct lsm1_cursor {
           41  +  sqlite3_vtab_cursor base;  /* Base class - must be first */
           42  +  lsm_cursor *pLsmCur;       /* The LSM cursor */
           43  +  u8 isDesc;                 /* 0: scan forward.  1: scan reverse */
           44  +  u8 atEof;                  /* True if the scan is complete */
           45  +  u8 bUnique;                /* True if no more than one row of output */
           46  +};
           47  +
           48  +/*
           49  +** The lsm1Connect() method is invoked to create a new
           50  +** lsm1_vtab that describes the virtual table.
           51  +*/
           52  +static int lsm1Connect(
           53  +  sqlite3 *db,
           54  +  void *pAux,
           55  +  int argc, const char *const*argv,
           56  +  sqlite3_vtab **ppVtab,
           57  +  char **pzErr
           58  +){
           59  +  lsm1_vtab *pNew;
           60  +  int rc;
           61  +
           62  +  if( argc!=4 || argv[3]==0 || argv[3][0]==0 ){
           63  +    *pzErr = sqlite3_mprintf("filename argument missing");
           64  +    return SQLITE_ERROR;
           65  +  }
           66  +  *ppVtab = sqlite3_malloc( sizeof(*pNew) );
           67  +  pNew = (lsm1_vtab*)*ppVtab;
           68  +  if( pNew==0 ){
           69  +    return SQLITE_NOMEM;
           70  +  }
           71  +  memset(pNew, 0, sizeof(*pNew));
           72  +  rc = lsm_new(0, &pNew->pDb);
           73  +  if( rc ){
           74  +    *pzErr = sqlite3_mprintf("lsm_new failed with error code %d",  rc);
           75  +    rc = SQLITE_ERROR;
           76  +    goto connect_failed;
           77  +  }
           78  +  rc = lsm_open(pNew->pDb, argv[0]);
           79  +  if( rc ){
           80  +    *pzErr = sqlite3_mprintf("lsm_open failed with %d", rc);
           81  +    rc = SQLITE_ERROR;
           82  +    goto connect_failed;
           83  +  }
           84  +
           85  +/* Column numbers */
           86  +#define LSM1_COLUMN_KEY      0
           87  +#define LSM1_COLUMN_VALUE    1
           88  +#define LSM1_COLUMN_COMMAND  2
           89  +
           90  +  rc = sqlite3_declare_vtab(db,
           91  +     "CREATE TABLE x(key,value,command hidden)");
           92  +connect_failed:
           93  +  if( rc!=SQLITE_OK ){
           94  +    if( pNew ){
           95  +      if( pNew->pDb ) lsm_close(pNew->pDb);
           96  +      sqlite3_free(pNew);
           97  +    }
           98  +    *ppVtab = 0;
           99  +  }
          100  +  return rc;
          101  +}
          102  +
          103  +/*
          104  +** This method is the destructor for lsm1_cursor objects.
          105  +*/
          106  +static int lsm1Disconnect(sqlite3_vtab *pVtab){
          107  +  lsm1_vtab *p = (lsm1_vtab*)pVtab;
          108  +  lsm_close(p->pDb);
          109  +  sqlite3_free(p);
          110  +  return SQLITE_OK;
          111  +}
          112  +
          113  +/*
          114  +** Constructor for a new lsm1_cursor object.
          115  +*/
          116  +static int lsm1Open(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
          117  +  lsm1_vtab *p = (lsm1_vtab*)pVtab;
          118  +  lsm1_cursor *pCur;
          119  +  int rc;
          120  +  pCur = sqlite3_malloc( sizeof(*pCur) );
          121  +  if( pCur==0 ) return SQLITE_NOMEM;
          122  +  memset(pCur, 0, sizeof(*pCur));
          123  +  *ppCursor = &pCur->base;
          124  +  rc = lsm_csr_open(p->pDb, &pCur->pLsmCur);
          125  +  if( rc==LSM_OK ){
          126  +    rc = SQLITE_OK;
          127  +  }else{
          128  +    sqlite3_free(pCur);
          129  +    *ppCursor = 0;
          130  +    rc = SQLITE_ERROR;
          131  +  }
          132  +  return rc;
          133  +}
          134  +
          135  +/*
          136  +** Destructor for a lsm1_cursor.
          137  +*/
          138  +static int lsm1Close(sqlite3_vtab_cursor *cur){
          139  +  lsm1_cursor *pCur = (lsm1_cursor*)cur;
          140  +  lsm_csr_close(pCur->pLsmCur);
          141  +  sqlite3_free(pCur);
          142  +  return SQLITE_OK;
          143  +}
          144  +
          145  +
          146  +/*
          147  +** Advance a lsm1_cursor to its next row of output.
          148  +*/
          149  +static int lsm1Next(sqlite3_vtab_cursor *cur){
          150  +  lsm1_cursor *pCur = (lsm1_cursor*)cur;
          151  +  int rc;
          152  +  if( pCur->bUnique ){
          153  +    pCur->atEof = 1;
          154  +  }else{
          155  +    if( pCur->isDesc ){
          156  +      rc = lsm_csr_prev(pCur->pLsmCur);
          157  +    }else{
          158  +      rc = lsm_csr_next(pCur->pLsmCur);
          159  +    }
          160  +    if( rc==LSM_OK && lsm_csr_valid(pCur->pLsmCur)==0 ){
          161  +      pCur->atEof = 1;
          162  +    }
          163  +  }
          164  +  return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
          165  +}
          166  +
          167  +/*
          168  +** Return TRUE if the cursor has been moved off of the last
          169  +** row of output.
          170  +*/
          171  +static int lsm1Eof(sqlite3_vtab_cursor *cur){
          172  +  lsm1_cursor *pCur = (lsm1_cursor*)cur;
          173  +  return pCur->atEof;
          174  +}
          175  +
          176  +/*
          177  +** Return values of columns for the row at which the lsm1_cursor
          178  +** is currently pointing.
          179  +*/
          180  +static int lsm1Column(
          181  +  sqlite3_vtab_cursor *cur,   /* The cursor */
          182  +  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
          183  +  int i                       /* Which column to return */
          184  +){
          185  +  lsm1_cursor *pCur = (lsm1_cursor*)cur;
          186  +  switch( i ){
          187  +    case LSM1_COLUMN_KEY: {
          188  +      const void *pVal;
          189  +      int nVal;
          190  +      if( lsm_csr_value(pCur->pLsmCur, (const void**)&pVal, &nVal)==LSM_OK ){
          191  +        sqlite3_result_blob(ctx, pVal, nVal, SQLITE_TRANSIENT);
          192  +      }
          193  +      break;
          194  +    }
          195  +    case LSM1_COLUMN_VALUE: {
          196  +      const unsigned char *aVal;
          197  +      int nVal;
          198  +      if( lsm_csr_value(pCur->pLsmCur, (const void**)&aVal, &nVal)==LSM_OK
          199  +          && nVal>=1
          200  +      ){
          201  +        switch( aVal[0] ){
          202  +          case SQLITE_FLOAT:
          203  +          case SQLITE_INTEGER: {
          204  +            sqlite3_uint64 x = 0;
          205  +            int j;
          206  +            for(j=1; j<=8; j++){
          207  +              x = (x<<8) | aVal[j];
          208  +            }
          209  +            if( aVal[0]==SQLITE_INTEGER ){
          210  +              sqlite3_result_int64(ctx, *(sqlite3_int64*)&x);
          211  +            }else{
          212  +              sqlite3_result_double(ctx, *(double*)&x);
          213  +            }
          214  +            break;
          215  +          }
          216  +          case SQLITE_TEXT: {
          217  +            sqlite3_result_text(ctx, (char*)&aVal[1], nVal-1, SQLITE_TRANSIENT);
          218  +            break;
          219  +          }
          220  +          case SQLITE_BLOB: {
          221  +            sqlite3_result_blob(ctx, &aVal[1], nVal-1, SQLITE_TRANSIENT);
          222  +            break;
          223  +          }
          224  +        }
          225  +      }
          226  +      break;
          227  +    }
          228  +    default: {
          229  +      break;
          230  +    }
          231  +  }
          232  +  return SQLITE_OK;
          233  +}
          234  +
          235  +/*
          236  +** Rowids are not supported by the underlying virtual table.  So always
          237  +** return 0 for the rowid.
          238  +*/
          239  +static int lsm1Rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
          240  +  *pRowid = 0;
          241  +  return SQLITE_OK;
          242  +}
          243  +
          244  +/* Move to the first row to return.
          245  +*/
          246  +static int lsm1Filter(
          247  +  sqlite3_vtab_cursor *pVtabCursor, 
          248  +  int idxNum, const char *idxStr,
          249  +  int argc, sqlite3_value **argv
          250  +){
          251  +  lsm1_cursor *pCur = (lsm1_cursor *)pVtabCursor;
          252  +  int rc;
          253  +  if( idxNum==1 ){
          254  +    assert( argc==1 );
          255  +    pCur->isDesc = 0;
          256  +    pCur->bUnique = 1;
          257  +    pCur->atEof = 1;
          258  +    if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
          259  +      const void *pVal = sqlite3_value_blob(argv[0]);
          260  +      int nVal = sqlite3_value_bytes(argv[0]);
          261  +      rc = lsm_csr_seek(pCur->pLsmCur, pVal, nVal, LSM_SEEK_EQ);
          262  +      if( rc==LSM_OK && lsm_csr_valid(pCur->pLsmCur)!=0 ){
          263  +        pCur->atEof = 0;
          264  +      }
          265  +    }
          266  +  }else{
          267  +    rc = lsm_csr_first(pCur->pLsmCur);
          268  +    pCur->atEof = 0;
          269  +    pCur->isDesc = 0;
          270  +    pCur->bUnique = 0;
          271  +  }
          272  +  return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
          273  +}
          274  +
          275  +/*
          276  +** Only comparisons against the key are allowed.  The idxNum defines
          277  +** which comparisons are available:
          278  +**
          279  +**     0      Full table scan only
          280  +**     1      key==?  single argument for ?
          281  +**    
          282  +*/
          283  +static int lsm1BestIndex(
          284  +  sqlite3_vtab *tab,
          285  +  sqlite3_index_info *pIdxInfo
          286  +){
          287  +  int i;                 /* Loop over constraints */
          288  +  int idxNum = 0;        /* The query plan bitmask */
          289  +  int nArg = 0;          /* Number of arguments to xFilter */
          290  +  int eqIdx = -1;        /* Index of the key== constraint, or -1 if none */
          291  +
          292  +  const struct sqlite3_index_constraint *pConstraint;
          293  +  pConstraint = pIdxInfo->aConstraint;
          294  +  for(i=0; i<pIdxInfo->nConstraint && idxNum<16; i++, pConstraint++){
          295  +    if( pConstraint->usable==0 ) continue;
          296  +    if( pConstraint->iColumn!=LSM1_COLUMN_KEY ) continue;
          297  +    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
          298  +    switch( pConstraint->op ){
          299  +      case SQLITE_INDEX_CONSTRAINT_EQ: {
          300  +        eqIdx = i;
          301  +        idxNum = 1;
          302  +        break;
          303  +      }
          304  +    }
          305  +  }
          306  +  if( eqIdx>=0 ){
          307  +    pIdxInfo->aConstraintUsage[eqIdx].argvIndex = ++nArg;
          308  +    pIdxInfo->aConstraintUsage[eqIdx].omit = 1;
          309  +  }
          310  +  if( idxNum==1 ){
          311  +    pIdxInfo->estimatedCost = (double)1;
          312  +    pIdxInfo->estimatedRows = 1;
          313  +    pIdxInfo->orderByConsumed = 1;
          314  +  }else{
          315  +    /* Full table scan */
          316  +    pIdxInfo->estimatedCost = (double)2147483647;
          317  +    pIdxInfo->estimatedRows = 2147483647;
          318  +  }
          319  +  pIdxInfo->idxNum = idxNum;
          320  +  return SQLITE_OK;
          321  +}
          322  +
          323  +/*
          324  +** The xUpdate method is normally used for INSERT, REPLACE, UPDATE, and
          325  +** DELETE.  But this virtual table only supports INSERT and REPLACE.
          326  +** DELETE is accomplished by inserting a record with a value of NULL.
          327  +** UPDATE is achieved by using REPLACE.
          328  +*/
          329  +int lsm1Update(
          330  +  sqlite3_vtab *pVTab,
          331  +  int argc,
          332  +  sqlite3_value **argv,
          333  +  sqlite_int64 *pRowid
          334  +){
          335  +  lsm1_vtab *p = (lsm1_vtab*)pVTab;
          336  +  const void *pKey;
          337  +  int nKey;
          338  +  int eType;
          339  +  int rc;
          340  +  sqlite3_value *pValue;
          341  +  if( argc==1 ){
          342  +    pVTab->zErrMsg = sqlite3_mprintf("cannot DELETE");
          343  +    return SQLITE_ERROR;
          344  +  }
          345  +  if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){
          346  +    pVTab->zErrMsg = sqlite3_mprintf("cannot UPDATE");
          347  +    return SQLITE_ERROR;
          348  +  }
          349  +
          350  +  /* "INSERT INTO tab(command) VALUES('....')" is used to implement
          351  +  ** special commands.
          352  +  */
          353  +  if( sqlite3_value_type(argv[2+LSM1_COLUMN_COMMAND])!=SQLITE_NULL ){
          354  +    return SQLITE_OK;
          355  +  }
          356  +  if( sqlite3_value_type(argv[2+LSM1_COLUMN_KEY])!=SQLITE_BLOB ){
          357  +    pVTab->zErrMsg = sqlite3_mprintf("BLOB keys only");
          358  +    return SQLITE_ERROR;
          359  +  }
          360  +  pKey = sqlite3_value_blob(argv[2+LSM1_COLUMN_KEY]);
          361  +  nKey = sqlite3_value_bytes(argv[2+LSM1_COLUMN_KEY]);
          362  +  pValue = argv[2+LSM1_COLUMN_VALUE];
          363  +  eType = sqlite3_value_type(pValue);
          364  +  switch( eType ){
          365  +    case SQLITE_NULL: {
          366  +      rc = lsm_delete(p->pDb, pKey, nKey);
          367  +      break;
          368  +    }
          369  +    case SQLITE_BLOB:
          370  +    case SQLITE_TEXT: {
          371  +      const unsigned char *pVal;
          372  +      unsigned char *pData;
          373  +      int nVal;
          374  +      if( eType==SQLITE_TEXT ){
          375  +        pVal = sqlite3_value_text(pValue);
          376  +      }else{
          377  +        pVal = (unsigned char*)sqlite3_value_blob(pValue);
          378  +      }
          379  +      nVal = sqlite3_value_bytes(pValue);
          380  +      pData = sqlite3_malloc( nVal+1 );
          381  +      if( pData==0 ){
          382  +        rc = SQLITE_NOMEM;
          383  +      }else{
          384  +        pData[0] = eType;
          385  +        memcpy(&pData[1], pVal, nVal);
          386  +        rc = lsm_insert(p->pDb, pKey, nKey, pData, nVal+1);
          387  +        sqlite3_free(pData);
          388  +      }
          389  +      break;
          390  +    }
          391  +    case SQLITE_INTEGER:
          392  +    case SQLITE_FLOAT: {
          393  +      sqlite3_uint64 x;
          394  +      unsigned char aVal[9];
          395  +      int i;
          396  +      if( eType==SQLITE_INTEGER ){
          397  +        *(sqlite3_int64*)&x = sqlite3_value_int64(pValue);
          398  +      }else{
          399  +        *(double*)&x = sqlite3_value_double(pValue);
          400  +      }
          401  +      for(i=9; i>=1; i--){
          402  +        aVal[i] = x & 0xff;
          403  +        x >>= 8;
          404  +      }
          405  +      aVal[0] = eType;
          406  +      rc = lsm_insert(p->pDb, pKey, nKey, aVal, 9);
          407  +      break;
          408  +    }
          409  +  }
          410  +  return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
          411  +}      
          412  +
          413  +/* Begin a transaction
          414  +*/
          415  +static int lsm1Begin(sqlite3_vtab *pVtab){
          416  +  lsm1_vtab *p = (lsm1_vtab*)pVtab;
          417  +  int rc = lsm_begin(p->pDb, 1);
          418  +  return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
          419  +}
          420  +
          421  +/* Phase 1 of a transaction commit.
          422  +*/
          423  +static int lsm1Sync(sqlite3_vtab *pVtab){
          424  +  return SQLITE_OK;
          425  +}
          426  +
          427  +/* Commit a transaction
          428  +*/
          429  +static int lsm1Commit(sqlite3_vtab *pVtab){
          430  +  lsm1_vtab *p = (lsm1_vtab*)pVtab;
          431  +  int rc = lsm_commit(p->pDb, 0);
          432  +  return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
          433  +}
          434  +
          435  +/* Rollback a transaction
          436  +*/
          437  +static int lsm1Rollback(sqlite3_vtab *pVtab){
          438  +  lsm1_vtab *p = (lsm1_vtab*)pVtab;
          439  +  int rc = lsm_rollback(p->pDb, 0);
          440  +  return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
          441  +}
          442  +
          443  +/*
          444  +** This following structure defines all the methods for the 
          445  +** generate_lsm1 virtual table.
          446  +*/
          447  +static sqlite3_module lsm1Module = {
          448  +  0,                       /* iVersion */
          449  +  lsm1Connect,             /* xCreate */
          450  +  lsm1Connect,             /* xConnect */
          451  +  lsm1BestIndex,           /* xBestIndex */
          452  +  lsm1Disconnect,          /* xDisconnect */
          453  +  lsm1Disconnect,          /* xDestroy */
          454  +  lsm1Open,                /* xOpen - open a cursor */
          455  +  lsm1Close,               /* xClose - close a cursor */
          456  +  lsm1Filter,              /* xFilter - configure scan constraints */
          457  +  lsm1Next,                /* xNext - advance a cursor */
          458  +  lsm1Eof,                 /* xEof - check for end of scan */
          459  +  lsm1Column,              /* xColumn - read data */
          460  +  lsm1Rowid,               /* xRowid - read data */
          461  +  lsm1Update,              /* xUpdate */
          462  +  lsm1Begin,               /* xBegin */
          463  +  lsm1Sync,                /* xSync */
          464  +  lsm1Commit,              /* xCommit */
          465  +  lsm1Rollback,            /* xRollback */
          466  +  0,                       /* xFindMethod */
          467  +  0,                       /* xRename */
          468  +};
          469  +
          470  +
          471  +#ifdef _WIN32
          472  +__declspec(dllexport)
          473  +#endif
          474  +int sqlite3_lsm_init(
          475  +  sqlite3 *db, 
          476  +  char **pzErrMsg, 
          477  +  const sqlite3_api_routines *pApi
          478  +){
          479  +  int rc = SQLITE_OK;
          480  +  SQLITE_EXTENSION_INIT2(pApi);
          481  +  rc = sqlite3_create_module(db, "lsm1", &lsm1Module, 0);
          482  +  return rc;
          483  +}