/ Check-in [bc2498d6]
Login

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

Overview
Comment:Update this branch with latest trunk changes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | server-process-edition
Files: files | file ages | folders
SHA3-256: bc2498d60fa22b587ad463ec697abe82d1c87abb7fd0d2cb60cc7316cfd7cec7
User & Date: dan 2017-08-14 06:55:22
Context
2017-08-14
07:16
Remove code for PLL support in wal mode from this branch. check-in: 8e1b28ed user: dan tags: server-process-edition
06:55
Update this branch with latest trunk changes. check-in: bc2498d6 user: dan tags: server-process-edition
01:33
Properly dequote column names in tables constructed by an aggregate SELECT. check-in: 7e0d3e9c user: drh tags: trunk
2017-08-07
14:15
Update this branch with latest trunk changes. check-in: 17bc7ded user: dan tags: server-process-edition
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts5/fts5_vocab.c.

    25     25   ** row:
    26     26   **     CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term));
    27     27   **
    28     28   **   One row for each term in the database. The value of $doc is set to
    29     29   **   the number of fts5 rows that contain at least one instance of term
    30     30   **   $term. Field $cnt is set to the total number of instances of term 
    31     31   **   $term in the database.
           32  +**
           33  +** instance:
           34  +**     CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY(<all-fields>));
           35  +**
           36  +**   One row for each term instance in the database. 
    32     37   */
    33     38   
    34     39   
    35     40   #include "fts5Int.h"
    36     41   
    37     42   
    38     43   typedef struct Fts5VocabTable Fts5VocabTable;
................................................................................
    40     45   
    41     46   struct Fts5VocabTable {
    42     47     sqlite3_vtab base;
    43     48     char *zFts5Tbl;                 /* Name of fts5 table */
    44     49     char *zFts5Db;                  /* Db containing fts5 table */
    45     50     sqlite3 *db;                    /* Database handle */
    46     51     Fts5Global *pGlobal;            /* FTS5 global object for this database */
    47         -  int eType;                      /* FTS5_VOCAB_COL or ROW */
           52  +  int eType;                      /* FTS5_VOCAB_COL, ROW or INSTANCE */
    48     53   };
    49     54   
    50     55   struct Fts5VocabCursor {
    51     56     sqlite3_vtab_cursor base;
    52     57     sqlite3_stmt *pStmt;            /* Statement holding lock on pIndex */
    53     58     Fts5Index *pIndex;              /* Associated FTS5 index */
    54     59   
................................................................................
    60     65   
    61     66     /* These are used by 'col' tables only */
    62     67     Fts5Config *pConfig;            /* Fts5 table configuration */
    63     68     int iCol;
    64     69     i64 *aCnt;
    65     70     i64 *aDoc;
    66     71   
    67         -  /* Output values used by 'row' and 'col' tables */
           72  +  /* Output values used by all tables. */
    68     73     i64 rowid;                      /* This table's current rowid value */
    69     74     Fts5Buffer term;                /* Current value of 'term' column */
           75  +
           76  +  /* Output values Used by 'instance' tables only */
           77  +  i64 iInstPos;
           78  +  int iInstOff;
    70     79   };
    71     80   
    72         -#define FTS5_VOCAB_COL    0
    73         -#define FTS5_VOCAB_ROW    1
           81  +#define FTS5_VOCAB_COL      0
           82  +#define FTS5_VOCAB_ROW      1
           83  +#define FTS5_VOCAB_INSTANCE 2
    74     84   
    75     85   #define FTS5_VOCAB_COL_SCHEMA  "term, col, doc, cnt"
    76     86   #define FTS5_VOCAB_ROW_SCHEMA  "term, doc, cnt"
           87  +#define FTS5_VOCAB_INST_SCHEMA "term, doc, col, offset"
    77     88   
    78     89   /*
    79     90   ** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
    80     91   */
    81     92   #define FTS5_VOCAB_TERM_EQ 0x01
    82     93   #define FTS5_VOCAB_TERM_GE 0x02
    83     94   #define FTS5_VOCAB_TERM_LE 0x04
................................................................................
    96    107       sqlite3Fts5Dequote(zCopy);
    97    108       if( sqlite3_stricmp(zCopy, "col")==0 ){
    98    109         *peType = FTS5_VOCAB_COL;
    99    110       }else
   100    111   
   101    112       if( sqlite3_stricmp(zCopy, "row")==0 ){
   102    113         *peType = FTS5_VOCAB_ROW;
          114  +    }else
          115  +    if( sqlite3_stricmp(zCopy, "instance")==0 ){
          116  +      *peType = FTS5_VOCAB_INSTANCE;
   103    117       }else
   104    118       {
   105    119         *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
   106    120         rc = SQLITE_ERROR;
   107    121       }
   108    122       sqlite3_free(zCopy);
   109    123     }
................................................................................
   157    171     int argc,                       /* Number of elements in argv array */
   158    172     const char * const *argv,       /* xCreate/xConnect argument array */
   159    173     sqlite3_vtab **ppVTab,          /* Write the resulting vtab structure here */
   160    174     char **pzErr                    /* Write any error message here */
   161    175   ){
   162    176     const char *azSchema[] = { 
   163    177       "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA  ")", 
   164         -    "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA  ")"
          178  +    "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA  ")",
          179  +    "CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")"
   165    180     };
   166    181   
   167    182     Fts5VocabTable *pRet = 0;
   168    183     int rc = SQLITE_OK;             /* Return code */
   169    184     int bDb;
   170    185   
   171    186     bDb = (argc==6 && strlen(argv[1])==4 && memcmp("temp", argv[1], 4)==0);
................................................................................
   231    246     char **pzErr                    /* OUT: sqlite3_malloc'd error message */
   232    247   ){
   233    248     return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
   234    249   }
   235    250   
   236    251   /* 
   237    252   ** Implementation of the xBestIndex method.
          253  +**
          254  +** Only constraints of the form:
          255  +**
          256  +**     term <= ?
          257  +**     term == ?
          258  +**     term >= ?
          259  +**
          260  +** are interpreted. Less-than and less-than-or-equal are treated 
          261  +** identically, as are greater-than and greater-than-or-equal.
   238    262   */
   239    263   static int fts5VocabBestIndexMethod(
   240    264     sqlite3_vtab *pUnused,
   241    265     sqlite3_index_info *pInfo
   242    266   ){
   243    267     int i;
   244    268     int iTermEq = -1;
................................................................................
   374    398     fts5VocabResetCursor(pCsr);
   375    399     sqlite3Fts5BufferFree(&pCsr->term);
   376    400     sqlite3_finalize(pCsr->pStmt);
   377    401     sqlite3_free(pCsr);
   378    402     return SQLITE_OK;
   379    403   }
   380    404   
          405  +static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){
          406  +  int rc = SQLITE_OK;
          407  +  
          408  +  if( sqlite3Fts5IterEof(pCsr->pIter) ){
          409  +    pCsr->bEof = 1;
          410  +  }else{
          411  +    const char *zTerm;
          412  +    int nTerm;
          413  +    zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
          414  +    if( pCsr->nLeTerm>=0 ){
          415  +      int nCmp = MIN(nTerm, pCsr->nLeTerm);
          416  +      int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
          417  +      if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
          418  +        pCsr->bEof = 1;
          419  +      }
          420  +    }
          421  +
          422  +    sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
          423  +  }
          424  +  return rc;
          425  +}
          426  +
          427  +static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
          428  +  int eDetail = pCsr->pConfig->eDetail;
          429  +  int rc = SQLITE_OK;
          430  +  Fts5IndexIter *pIter = pCsr->pIter;
          431  +  i64 *pp = &pCsr->iInstPos;
          432  +  int *po = &pCsr->iInstOff;
          433  +  
          434  +  while( eDetail==FTS5_DETAIL_NONE
          435  +      || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp) 
          436  +  ){
          437  +    pCsr->iInstPos = 0;
          438  +    pCsr->iInstOff = 0;
          439  +
          440  +    rc = sqlite3Fts5IterNextScan(pCsr->pIter);
          441  +    if( rc==SQLITE_OK ){
          442  +      rc = fts5VocabInstanceNewTerm(pCsr);
          443  +      if( eDetail==FTS5_DETAIL_NONE ) break;
          444  +    }
          445  +    if( rc ){
          446  +      pCsr->bEof = 1;
          447  +      break;
          448  +    }
          449  +  }
          450  +
          451  +  return rc;
          452  +}
   381    453   
   382    454   /*
   383    455   ** Advance the cursor to the next row in the table.
   384    456   */
   385    457   static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
   386    458     Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
   387    459     Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
   388    460     int rc = SQLITE_OK;
   389    461     int nCol = pCsr->pConfig->nCol;
   390    462   
   391    463     pCsr->rowid++;
          464  +
          465  +  if( pTab->eType==FTS5_VOCAB_INSTANCE ){
          466  +    return fts5VocabInstanceNext(pCsr);
          467  +  }
   392    468   
   393    469     if( pTab->eType==FTS5_VOCAB_COL ){
   394    470       for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
   395    471         if( pCsr->aDoc[pCsr->iCol] ) break;
   396    472       }
   397    473     }
   398    474   
   399         -  if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
          475  +  if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){
   400    476       if( sqlite3Fts5IterEof(pCsr->pIter) ){
   401    477         pCsr->bEof = 1;
   402    478       }else{
   403    479         const char *zTerm;
   404    480         int nTerm;
   405    481   
   406    482         zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
................................................................................
   416    492         sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
   417    493         memset(pCsr->aCnt, 0, nCol * sizeof(i64));
   418    494         memset(pCsr->aDoc, 0, nCol * sizeof(i64));
   419    495         pCsr->iCol = 0;
   420    496   
   421    497         assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
   422    498         while( rc==SQLITE_OK ){
          499  +        int eDetail = pCsr->pConfig->eDetail;
   423    500           const u8 *pPos; int nPos;   /* Position list */
   424    501           i64 iPos = 0;               /* 64-bit position read from poslist */
   425    502           int iOff = 0;               /* Current offset within position list */
   426    503   
   427    504           pPos = pCsr->pIter->pData;
   428    505           nPos = pCsr->pIter->nData;
   429         -        switch( pCsr->pConfig->eDetail ){
   430         -          case FTS5_DETAIL_FULL:
   431         -            pPos = pCsr->pIter->pData;
   432         -            nPos = pCsr->pIter->nData;
   433         -            if( pTab->eType==FTS5_VOCAB_ROW ){
          506  +
          507  +        switch( pTab->eType ){
          508  +          case FTS5_VOCAB_ROW:
          509  +            if( eDetail==FTS5_DETAIL_FULL ){
   434    510                 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
   435    511                   pCsr->aCnt[0]++;
   436    512                 }
   437         -              pCsr->aDoc[0]++;
   438         -            }else{
          513  +            }
          514  +            pCsr->aDoc[0]++;
          515  +            break;
          516  +
          517  +          case FTS5_VOCAB_COL:
          518  +            if( eDetail==FTS5_DETAIL_FULL ){
   439    519                 int iCol = -1;
   440    520                 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
   441    521                   int ii = FTS5_POS2COLUMN(iPos);
   442    522                   pCsr->aCnt[ii]++;
   443    523                   if( iCol!=ii ){
   444    524                     if( ii>=nCol ){
   445    525                       rc = FTS5_CORRUPT;
   446    526                       break;
   447    527                     }
   448    528                     pCsr->aDoc[ii]++;
   449    529                     iCol = ii;
   450    530                   }
   451    531                 }
   452         -            }
   453         -            break;
   454         -
   455         -          case FTS5_DETAIL_COLUMNS:
   456         -            if( pTab->eType==FTS5_VOCAB_ROW ){
   457         -              pCsr->aDoc[0]++;
   458         -            }else{
          532  +            }else if( eDetail==FTS5_DETAIL_COLUMNS ){
   459    533                 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){
   460    534                   assert_nc( iPos>=0 && iPos<nCol );
   461    535                   if( iPos>=nCol ){
   462    536                     rc = FTS5_CORRUPT;
   463    537                     break;
   464    538                   }
   465    539                   pCsr->aDoc[iPos]++;
   466    540                 }
          541  +            }else{
          542  +              assert( eDetail==FTS5_DETAIL_NONE );
          543  +              pCsr->aDoc[0]++;
   467    544               }
   468    545               break;
   469    546   
   470         -          default: 
   471         -            assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE );
   472         -            pCsr->aDoc[0]++;
          547  +          default:
          548  +            assert( pTab->eType==FTS5_VOCAB_INSTANCE );
   473    549               break;
   474    550           }
   475    551   
   476    552           if( rc==SQLITE_OK ){
   477    553             rc = sqlite3Fts5IterNextScan(pCsr->pIter);
   478    554           }
          555  +        if( pTab->eType==FTS5_VOCAB_INSTANCE ) break;
   479    556   
   480    557           if( rc==SQLITE_OK ){
   481    558             zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
   482    559             if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){
   483    560               break;
   484    561             }
   485    562             if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
................................................................................
   501    578   static int fts5VocabFilterMethod(
   502    579     sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
   503    580     int idxNum,                     /* Strategy index */
   504    581     const char *zUnused,            /* Unused */
   505    582     int nUnused,                    /* Number of elements in apVal */
   506    583     sqlite3_value **apVal           /* Arguments for the indexing scheme */
   507    584   ){
          585  +  Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
   508    586     Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
          587  +  int eType = pTab->eType;
   509    588     int rc = SQLITE_OK;
   510    589   
   511    590     int iVal = 0;
   512    591     int f = FTS5INDEX_QUERY_SCAN;
   513    592     const char *zTerm = 0;
   514    593     int nTerm = 0;
   515    594   
................................................................................
   541    620           rc = SQLITE_NOMEM;
   542    621         }else{
   543    622           memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1);
   544    623         }
   545    624       }
   546    625     }
   547    626   
   548         -
   549    627     if( rc==SQLITE_OK ){
   550    628       rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
   551    629     }
   552         -  if( rc==SQLITE_OK ){
          630  +  if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
          631  +    rc = fts5VocabInstanceNewTerm(pCsr);
          632  +  }
          633  +  if( rc==SQLITE_OK 
          634  +   && !pCsr->bEof 
          635  +   && (eType!=FTS5_VOCAB_INSTANCE || pCsr->pConfig->eDetail!=FTS5_DETAIL_NONE)
          636  +  ){
   553    637       rc = fts5VocabNextMethod(pCursor);
   554    638     }
   555    639   
   556    640     return rc;
   557    641   }
   558    642   
   559    643   /* 
................................................................................
   587    671           sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
   588    672         }
   589    673       }else if( iCol==2 ){
   590    674         iVal = pCsr->aDoc[pCsr->iCol];
   591    675       }else{
   592    676         iVal = pCsr->aCnt[pCsr->iCol];
   593    677       }
   594         -  }else{
          678  +  }else if( eType==FTS5_VOCAB_ROW ){
   595    679       assert( iCol==1 || iCol==2 );
   596    680       if( iCol==1 ){
   597    681         iVal = pCsr->aDoc[0];
   598    682       }else{
   599    683         iVal = pCsr->aCnt[0];
          684  +    }
          685  +  }else{
          686  +    int eDetail = pCsr->pConfig->eDetail;
          687  +    assert( eType==FTS5_VOCAB_INSTANCE );
          688  +    switch( iCol ){
          689  +      case 1:
          690  +        sqlite3_result_int64(pCtx, pCsr->pIter->iRowid);
          691  +        break;
          692  +      case 2: {
          693  +        int ii = -1;
          694  +        if( eDetail==FTS5_DETAIL_FULL ){
          695  +          ii = FTS5_POS2COLUMN(pCsr->iInstPos);
          696  +        }else if( eDetail==FTS5_DETAIL_COLUMNS ){
          697  +          ii = pCsr->iInstPos;
          698  +        }
          699  +        if( ii>=0 && ii<pCsr->pConfig->nCol ){
          700  +          const char *z = pCsr->pConfig->azCol[ii];
          701  +          sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
          702  +        }
          703  +        break;
          704  +      }
          705  +      default: {
          706  +        assert( iCol==3 );
          707  +        if( eDetail==FTS5_DETAIL_FULL ){
          708  +          int ii = FTS5_POS2OFFSET(pCsr->iInstPos);
          709  +          sqlite3_result_int(pCtx, ii);
          710  +        }
          711  +        break;
          712  +      }
   600    713       }
   601    714     }
   602    715   
   603    716     if( iVal>0 ) sqlite3_result_int64(pCtx, iVal);
   604    717     return SQLITE_OK;
   605    718   }
   606    719   

Added ext/fts5/test/fts5vocab2.test.

            1  +# 2017 August 10
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +# The tests in this file focus on testing the fts5vocab module.
           13  +#
           14  +
           15  +source [file join [file dirname [info script]] fts5_common.tcl]
           16  +set testprefix fts5vocab
           17  +
           18  +# If SQLITE_ENABLE_FTS5 is defined, omit this file.
           19  +ifcapable !fts5 {
           20  +  finish_test
           21  +  return
           22  +}
           23  +
           24  +do_execsql_test 1.0 {
           25  +  CREATE VIRTUAL TABLE t1 USING fts5(a, b);
           26  +  CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance);
           27  +
           28  +  INSERT INTO t1 VALUES('one two', 'two three');
           29  +  INSERT INTO t1 VALUES('three four', 'four five five five');
           30  +}
           31  +
           32  +do_execsql_test 1.1 {
           33  +  SELECT * FROM v1;
           34  +} {
           35  +  five  2 b 1
           36  +  five  2 b 2
           37  +  five  2 b 3
           38  +  four  2 a 1
           39  +  four  2 b 0
           40  +  one   1 a 0
           41  +  three 1 b 1
           42  +  three 2 a 0
           43  +  two   1 a 1
           44  +  two   1 b 0
           45  +}
           46  +
           47  +do_execsql_test 1.2 {
           48  +  SELECT * FROM v1 WHERE term='three';
           49  +} {
           50  +  three 1 b 1
           51  +  three 2 a 0
           52  +}
           53  +
           54  +do_execsql_test 1.3 {
           55  +  BEGIN;
           56  +    DELETE FROM t1 WHERE rowid=2;
           57  +    SELECT * FROM v1;
           58  +  ROLLBACK;
           59  +} {
           60  +  one   1 a 0
           61  +  three 1 b 1
           62  +  two   1 a 1
           63  +  two   1 b 0
           64  +}
           65  +
           66  +do_execsql_test 1.4 {
           67  +  BEGIN;
           68  +    DELETE FROM t1 WHERE rowid=1;
           69  +    SELECT * FROM v1;
           70  +  ROLLBACK;
           71  +} {
           72  +  five  2 b 1
           73  +  five  2 b 2
           74  +  five  2 b 3
           75  +  four  2 a 1
           76  +  four  2 b 0
           77  +  three 2 a 0
           78  +}
           79  +
           80  +do_execsql_test 1.5 {
           81  +  DELETE FROM t1;
           82  +  SELECT * FROM v1;
           83  +} {
           84  +}
           85  +
           86  +#-------------------------------------------------------------------------
           87  +#
           88  +do_execsql_test 2.0 {
           89  +  DROP TABLE IF EXISTS t1;
           90  +  DROP TABLE IF EXISTS v1;
           91  +
           92  +  CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=column);
           93  +  CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance);
           94  +
           95  +  INSERT INTO t1 VALUES('one two', 'two three');
           96  +  INSERT INTO t1 VALUES('three four', 'four five five five');
           97  +}
           98  +
           99  +do_execsql_test 2.1 {
          100  +  SELECT * FROM v1;
          101  +} {
          102  +  five  2 b {}
          103  +  four  2 a {}
          104  +  four  2 b {}
          105  +  one   1 a {}
          106  +  three 1 b {}
          107  +  three 2 a {}
          108  +  two   1 a {}
          109  +  two   1 b {}
          110  +}
          111  +
          112  +do_execsql_test 2.2 {
          113  +  SELECT * FROM v1 WHERE term='three';
          114  +} {
          115  +  three 1 b {}
          116  +  three 2 a {}
          117  +}
          118  +
          119  +do_execsql_test 2.3 {
          120  +  BEGIN;
          121  +    DELETE FROM t1 WHERE rowid=2;
          122  +    SELECT * FROM v1;
          123  +  ROLLBACK;
          124  +} {
          125  +  one   1 a {}
          126  +  three 1 b {}
          127  +  two   1 a {}
          128  +  two   1 b {}
          129  +}
          130  +
          131  +do_execsql_test 2.4 {
          132  +  BEGIN;
          133  +    DELETE FROM t1 WHERE rowid=1;
          134  +    SELECT * FROM v1;
          135  +  ROLLBACK;
          136  +} {
          137  +  five  2 b {}
          138  +  four  2 a {}
          139  +  four  2 b {}
          140  +  three 2 a {}
          141  +}
          142  +
          143  +do_execsql_test 2.5 {
          144  +  DELETE FROM t1;
          145  +  SELECT * FROM v1;
          146  +} {
          147  +}
          148  +
          149  +#-------------------------------------------------------------------------
          150  +#
          151  +do_execsql_test 3.0 {
          152  +  DROP TABLE IF EXISTS t1;
          153  +  DROP TABLE IF EXISTS v1;
          154  +
          155  +  CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=none);
          156  +  CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance);
          157  +
          158  +  INSERT INTO t1 VALUES('one two', 'two three');
          159  +  INSERT INTO t1 VALUES('three four', 'four five five five');
          160  +}
          161  +
          162  +do_execsql_test 3.1 {
          163  +  SELECT * FROM v1;
          164  +} {
          165  +  five  2 {} {}
          166  +  four  2 {} {}
          167  +  one   1 {} {}
          168  +  three 1 {} {}
          169  +  three 2 {} {}
          170  +  two   1 {} {}
          171  +}
          172  +
          173  +do_execsql_test 3.2 {
          174  +  SELECT * FROM v1 WHERE term='three';
          175  +} {
          176  +  three 1 {} {}
          177  +  three 2 {} {}
          178  +}
          179  +
          180  +do_execsql_test 3.3 {
          181  +  BEGIN;
          182  +    DELETE FROM t1 WHERE rowid=2;
          183  +    SELECT * FROM v1;
          184  +  ROLLBACK;
          185  +} {
          186  +  one   1 {} {}
          187  +  three 1 {} {}
          188  +  two   1 {} {}
          189  +}
          190  +
          191  +do_execsql_test 3.4 {
          192  +  BEGIN;
          193  +    DELETE FROM t1 WHERE rowid=1;
          194  +    SELECT * FROM v1;
          195  +  ROLLBACK;
          196  +} {
          197  +  five  2 {} {}
          198  +  four  2 {} {}
          199  +  three 2 {} {}
          200  +}
          201  +
          202  +do_execsql_test 3.5 {
          203  +  DELETE FROM t1;
          204  +  SELECT * FROM v1;
          205  +} {
          206  +}
          207  +
          208  +finish_test
          209  +

Changes to ext/lsm1/lsm_vtab.c.

     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   **
    13         -** This file implements a simple virtual table wrapper around the LSM
           13  +** This file implements a virtual table for SQLite3 around the LSM
    14     14   ** storage engine from SQLite4.
           15  +**
           16  +** USAGE
           17  +**
           18  +**   CREATE VIRTUAL TABLE demo USING lsm1(filename,key,keytype,value1,...);
           19  +**
           20  +** The filename parameter is the name of the LSM database file, which is
           21  +** separate and distinct from the SQLite3 database file.
           22  +**
           23  +** The keytype must be one of: UINT, TEXT, BLOB.  All keys must be of that
           24  +** one type.  "UINT" means unsigned integer.  The values may be of any
           25  +** SQLite datatype: BLOB, TEXT, INTEGER, FLOAT, or NULL.
           26  +**
           27  +** The virtual table contains read-only hidden columns:
           28  +**
           29  +**     lsm1_key	      A BLOB which is the raw LSM key.  If the "keytype"
           30  +**                    is BLOB or TEXT then this column is exactly the
           31  +**                    same as the key.  For the UINT keytype, this column
           32  +**                    will be a variable-length integer encoding of the key.
           33  +**
           34  +**     lsm1_value     A BLOB which is the raw LSM value.  All of the value
           35  +**                    columns are packed into this BLOB using the encoding
           36  +**                    described below.
           37  +**
           38  +** Attempts to write values into the lsm1_key and lsm1_value columns are
           39  +** silently ignored.
           40  +**
           41  +** EXAMPLE
           42  +**
           43  +** The virtual table declared this way:
           44  +**
           45  +**    CREATE VIRTUAL TABLE demo2 USING lsm1('x.lsm',id,UINT,a,b,c,d);
           46  +**
           47  +** Results in a new virtual table named "demo2" that acts as if it has
           48  +** the following schema:
           49  +**
           50  +**    CREATE TABLE demo2(
           51  +**      id UINT PRIMARY KEY ON CONFLICT REPLACE,
           52  +**      a ANY,
           53  +**      b ANY,
           54  +**      c ANY,
           55  +**      d ANY,
           56  +**      lsm1_key BLOB HIDDEN,
           57  +**      lsm1_value BLOB HIDDEN
           58  +**    ) WITHOUT ROWID;
           59  +**
           60  +** 
           61  +**
           62  +** INTERNALS
           63  +**
           64  +** The key encoding for BLOB and TEXT is just a copy of the blob or text.
           65  +** UTF-8 is used for text.  The key encoding for UINT is the variable-length
           66  +** integer format at https://sqlite.org/src4/doc/trunk/www/varint.wiki.
           67  +**
           68  +** The values are encoded as a single blob (since that is what lsm stores as
           69  +** its content).  There is a "type integer" followed by "content" for each
           70  +** value, alternating back and forth.  The content might be empty.
           71  +**
           72  +**    TYPE1  CONTENT1  TYPE2  CONTENT2  TYPE3  CONTENT3 ....
           73  +**
           74  +** Each "type integer" is encoded as a variable-length integer in the
           75  +** format of the link above.  Let the type integer be T.  The actual
           76  +** datatype is an integer 0-5 equal to T%6.  Values 1 through 5 correspond
           77  +** to SQLITE_INTEGER through SQLITE_NULL.  The size of the content in bytes
           78  +** is T/6.  Type value 0 means that the value is an integer whose actual
           79  +** values is T/6 and there is no content.  The type-value-0 integer format
           80  +** only works for integers in the range of 0 through 40.
           81  +**
           82  +** There is no content for NULL or type-0 integers.  For BLOB and TEXT
           83  +** values, the content is the blob data or the UTF-8 text data.  For
           84  +** non-negative integers X, the content is a variable-length integer X*2.
           85  +** For negative integers Y, the content is varaible-length integer (1-Y)*2+1.
           86  +** For FLOAT values, the content is the IEEE754 floating point value in
           87  +** native byte-order.  This means that FLOAT values will be corrupted when
           88  +** database file is moved between big-endian and little-endian machines.
    15     89   */
    16     90   #include "sqlite3ext.h"
    17     91   SQLITE_EXTENSION_INIT1
    18     92   #include "lsm.h"
    19     93   #include <assert.h>
    20     94   #include <string.h>
    21     95   
    22     96   /* Forward declaration of subclasses of virtual table objects */
    23     97   typedef struct lsm1_vtab lsm1_vtab;
    24     98   typedef struct lsm1_cursor lsm1_cursor;
           99  +typedef struct lsm1_vblob lsm1_vblob;
    25    100   
    26    101   /* Primitive types */
    27    102   typedef unsigned char u8;
          103  +typedef unsigned int u32;
          104  +typedef sqlite3_uint64 u64;
    28    105   
    29    106   /* An open connection to an LSM table */
    30    107   struct lsm1_vtab {
    31    108     sqlite3_vtab base;          /* Base class - must be first */
    32    109     lsm_db *pDb;                /* Open connection to the LSM table */
          110  +  u8 keyType;                 /* SQLITE_BLOB, _TEXT, or _INTEGER */
          111  +  u32 nVal;                   /* Number of value columns */
    33    112   };
    34    113   
    35    114   
    36    115   /* lsm1_cursor is a subclass of sqlite3_vtab_cursor which will
    37    116   ** serve as the underlying representation of a cursor that scans
    38    117   ** over rows of the result
    39    118   */
    40    119   struct lsm1_cursor {
    41    120     sqlite3_vtab_cursor base;  /* Base class - must be first */
    42    121     lsm_cursor *pLsmCur;       /* The LSM cursor */
    43    122     u8 isDesc;                 /* 0: scan forward.  1: scan reverse */
    44    123     u8 atEof;                  /* True if the scan is complete */
    45    124     u8 bUnique;                /* True if no more than one row of output */
          125  +  u8 *zData;                 /* Content of the current row */
          126  +  u32 nData;                 /* Number of bytes in the current row */
          127  +  u8 *aeType;                /* Types for all column values */
          128  +  u32 *aiOfst;               /* Offsets to the various fields */
          129  +  u32 *aiLen;                /* Length of each field */
          130  +  u8 *pKey2;                 /* Loop termination key, or NULL */
          131  +  u32 nKey2;                 /* Length of the loop termination key */
          132  +};
          133  +
          134  +/* An extensible buffer object.
          135  +**
          136  +** Content can be appended.  Space to hold new content is automatically
          137  +** allocated.
          138  +*/
          139  +struct lsm1_vblob {
          140  +  u8 *a;             /* Space to hold content, from sqlite3_malloc64() */
          141  +  u64 n;             /* Bytes of space used */
          142  +  u64 nAlloc;        /* Bytes of space allocated */
          143  +  u8 errNoMem;       /* True if a memory allocation error has been seen */
    46    144   };
          145  +
          146  +#if defined(__GNUC__)
          147  +#  define LSM1_NOINLINE  __attribute__((noinline))
          148  +#elif defined(_MSC_VER) && _MSC_VER>=1310
          149  +#  define LSM1_NOINLINE  __declspec(noinline)
          150  +#else
          151  +#  define LSM1_NOINLINE
          152  +#endif
          153  +
          154  +
          155  +/* Increase the available space in the vblob object so that it can hold
          156  +** at least N more bytes.  Return the number of errors.
          157  +*/
          158  +static int lsm1VblobEnlarge(lsm1_vblob *p, u32 N){
          159  +  if( p->n+N>p->nAlloc ){
          160  +    if( p->errNoMem ) return 1;
          161  +    p->nAlloc += N + (p->nAlloc ? p->nAlloc : N);
          162  +    p->a = sqlite3_realloc64(p->a, p->nAlloc);
          163  +    if( p->a==0 ){
          164  +      p->n = 0;
          165  +      p->nAlloc = 0;
          166  +      p->errNoMem = 1;
          167  +      return 1;
          168  +    }
          169  +    p->nAlloc = sqlite3_msize(p->a);
          170  +  }
          171  +  return 0;
          172  +}
          173  +
          174  +/* Append N bytes to a vblob after first enlarging it */
          175  +static LSM1_NOINLINE void lsm1VblobEnlargeAndAppend(
          176  +  lsm1_vblob *p,
          177  +  const u8 *pData,
          178  +  u32 N
          179  +){
          180  +  if( p->n+N>p->nAlloc && lsm1VblobEnlarge(p, N) ) return;
          181  +  memcpy(p->a+p->n, pData, N);
          182  +  p->n += N;
          183  +}
          184  +
          185  +/* Append N bytes to a vblob */
          186  +static void lsm1VblobAppend(lsm1_vblob *p, const u8 *pData, u32 N){
          187  +  sqlite3_int64 n = p->n;
          188  +  if( n+N>p->nAlloc ){
          189  +    lsm1VblobEnlargeAndAppend(p, pData, N);
          190  +  }else{
          191  +    p->n += N;
          192  +    memcpy(p->a+n, pData, N);
          193  +  }
          194  +}
          195  +
          196  +/* append text to a vblob */
          197  +static void lsm1VblobAppendText(lsm1_vblob *p, const char *z){
          198  +  lsm1VblobAppend(p, (u8*)z, (u32)strlen(z));
          199  +}
    47    200   
    48    201   /* Dequote the string */
    49    202   static void lsm1Dequote(char *z){
    50    203     int j;
    51    204     char cQuote = z[0];
    52    205     size_t i, n;
    53    206   
................................................................................
    72    225     int argc, const char *const*argv,
    73    226     sqlite3_vtab **ppVtab,
    74    227     char **pzErr
    75    228   ){
    76    229     lsm1_vtab *pNew;
    77    230     int rc;
    78    231     char *zFilename;
          232  +  u8 keyType = 0;
          233  +  int i;
          234  +  lsm1_vblob sql;
          235  +  static const char *azTypes[] = { "UINT",         "TEXT",     "BLOB" };
          236  +  static const u8 aeTypes[] =    { SQLITE_INTEGER, SQLITE_TEXT, SQLITE_BLOB };
          237  +  static const char *azArgName[] = {"filename", "key", "key type", "value1" };
    79    238   
    80         -  if( argc!=4 || argv[3]==0 || argv[3][0]==0 ){
    81         -    *pzErr = sqlite3_mprintf("filename argument missing");
          239  +  for(i=0; i<sizeof(azArgName)/sizeof(azArgName[0]); i++){
          240  +    if( argc<i+4 || argv[i+3]==0 || argv[i+3][0]==0 ){
          241  +      *pzErr = sqlite3_mprintf("%s (%r) argument missing",
          242  +                               azArgName[i], i+1);
          243  +      return SQLITE_ERROR;
          244  +    }
          245  +  }
          246  +  for(i=0; i<sizeof(azTypes)/sizeof(azTypes[0]); i++){
          247  +    if( sqlite3_stricmp(azTypes[i],argv[5])==0 ){
          248  +      keyType = aeTypes[i];
          249  +      break;
          250  +    }
          251  +  }
          252  +  if( keyType==0 ){
          253  +    *pzErr = sqlite3_mprintf("key type should be INT, TEXT, or BLOB");
    82    254       return SQLITE_ERROR;
    83    255     }
    84    256     *ppVtab = sqlite3_malloc( sizeof(*pNew) );
    85    257     pNew = (lsm1_vtab*)*ppVtab;
    86    258     if( pNew==0 ){
    87    259       return SQLITE_NOMEM;
    88    260     }
    89    261     memset(pNew, 0, sizeof(*pNew));
          262  +  pNew->keyType = keyType;
    90    263     rc = lsm_new(0, &pNew->pDb);
    91    264     if( rc ){
    92    265       *pzErr = sqlite3_mprintf("lsm_new failed with error code %d",  rc);
    93    266       rc = SQLITE_ERROR;
    94    267       goto connect_failed;
    95    268     }
    96    269     zFilename = sqlite3_mprintf("%s", argv[3]);
................................................................................
    99    272     sqlite3_free(zFilename);
   100    273     if( rc ){
   101    274       *pzErr = sqlite3_mprintf("lsm_open failed with %d", rc);
   102    275       rc = SQLITE_ERROR;
   103    276       goto connect_failed;
   104    277     }
   105    278   
   106         -/* Column numbers */
   107         -#define LSM1_COLUMN_KEY         0
   108         -#define LSM1_COLUMN_BLOBKEY     1
   109         -#define LSM1_COLUMN_VALUE       2
   110         -#define LSM1_COLUMN_BLOBVALUE   3
   111         -#define LSM1_COLUMN_COMMAND     4
          279  +  memset(&sql, 0, sizeof(sql));
          280  +  lsm1VblobAppendText(&sql, "CREATE TABLE x(");
          281  +  lsm1VblobAppendText(&sql, argv[4]);
          282  +  lsm1VblobAppendText(&sql, " ");
          283  +  lsm1VblobAppendText(&sql, argv[5]);
          284  +  lsm1VblobAppendText(&sql, " PRIMARY KEY");
          285  +  for(i=6; i<argc; i++){
          286  +    lsm1VblobAppendText(&sql, ", ");
          287  +    lsm1VblobAppendText(&sql, argv[i]);
          288  +    pNew->nVal++;
          289  +  }
          290  +  lsm1VblobAppendText(&sql, 
          291  +      ", lsm1_command HIDDEN"
          292  +      ", lsm1_key HIDDEN"
          293  +      ", lsm1_value HIDDEN) WITHOUT ROWID");
          294  +  lsm1VblobAppend(&sql, (u8*)"", 1);
          295  +  if( sql.errNoMem ){
          296  +    rc = SQLITE_NOMEM;
          297  +    goto connect_failed;
          298  +  }
          299  +  rc = sqlite3_declare_vtab(db, (const char*)sql.a);
          300  +  sqlite3_free(sql.a);
   112    301   
   113         -  rc = sqlite3_declare_vtab(db,
   114         -     "CREATE TABLE x("
   115         -     "  key,"              /* The primary key.  Any non-NULL */
   116         -     "  blobkey,"          /* Pure BLOB primary key */
   117         -     "  value,"            /* The value associated with key.  Any non-NULL */
   118         -     "  blobvalue,"        /* Pure BLOB value */
   119         -     "  command hidden"    /* Insert here for control operations */
   120         -     ");"
   121         -  );
   122    302   connect_failed:
   123    303     if( rc!=SQLITE_OK ){
   124    304       if( pNew ){
   125    305         if( pNew->pDb ) lsm_close(pNew->pDb);
   126    306         sqlite3_free(pNew);
   127    307       }
   128    308       *ppVtab = 0;
................................................................................
   143    323   /*
   144    324   ** Constructor for a new lsm1_cursor object.
   145    325   */
   146    326   static int lsm1Open(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
   147    327     lsm1_vtab *p = (lsm1_vtab*)pVtab;
   148    328     lsm1_cursor *pCur;
   149    329     int rc;
   150         -  pCur = sqlite3_malloc( sizeof(*pCur) );
          330  +  pCur = sqlite3_malloc64( sizeof(*pCur)
          331  +                 + p->nVal*(sizeof(pCur->aiOfst)+sizeof(pCur->aiLen)+1) );
   151    332     if( pCur==0 ) return SQLITE_NOMEM;
   152    333     memset(pCur, 0, sizeof(*pCur));
          334  +  pCur->aiOfst = (u32*)&pCur[1];
          335  +  pCur->aiLen = &pCur->aiOfst[p->nVal];
          336  +  pCur->aeType = (u8*)&pCur->aiLen[p->nVal];
   153    337     *ppCursor = &pCur->base;
   154    338     rc = lsm_csr_open(p->pDb, &pCur->pLsmCur);
   155    339     if( rc==LSM_OK ){
   156    340       rc = SQLITE_OK;
   157    341     }else{
   158    342       sqlite3_free(pCur);
   159    343       *ppCursor = 0;
................................................................................
   163    347   }
   164    348   
   165    349   /*
   166    350   ** Destructor for a lsm1_cursor.
   167    351   */
   168    352   static int lsm1Close(sqlite3_vtab_cursor *cur){
   169    353     lsm1_cursor *pCur = (lsm1_cursor*)cur;
          354  +  sqlite3_free(pCur->pKey2);
   170    355     lsm_csr_close(pCur->pLsmCur);
   171    356     sqlite3_free(pCur);
   172    357     return SQLITE_OK;
   173    358   }
   174    359   
   175    360   
   176    361   /*
................................................................................
   186    371         rc = lsm_csr_prev(pCur->pLsmCur);
   187    372       }else{
   188    373         rc = lsm_csr_next(pCur->pLsmCur);
   189    374       }
   190    375       if( rc==LSM_OK && lsm_csr_valid(pCur->pLsmCur)==0 ){
   191    376         pCur->atEof = 1;
   192    377       }
          378  +    if( pCur->pKey2 && pCur->atEof==0 ){
          379  +      const u8 *pVal;
          380  +      u32 nVal;
          381  +      assert( pCur->isDesc==0 );
          382  +      rc = lsm_csr_key(pCur->pLsmCur, (const void**)&pVal, (int*)&nVal);
          383  +      if( rc==LSM_OK ){
          384  +        u32 len = pCur->nKey2;
          385  +        int c;
          386  +        if( len>nVal ) len = nVal;
          387  +        c = memcmp(pVal, pCur->pKey2, len);
          388  +        if( c==0 ) c = nVal - pCur->nKey2;
          389  +        if( c>0 ) pCur->atEof = 1;
          390  +      }
          391  +    }
          392  +    pCur->zData = 0;
   193    393     }
   194    394     return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
   195    395   }
   196    396   
   197    397   /*
   198    398   ** Return TRUE if the cursor has been moved off of the last
   199    399   ** row of output.
................................................................................
   290    490       return 8;
   291    491     }
   292    492     z[0] = 255;
   293    493     varintWrite32(z+1, w);
   294    494     varintWrite32(z+5, y);
   295    495     return 9;
   296    496   }
          497  +
          498  +/* Append non-negative integer x as a variable-length integer.
          499  +*/
          500  +static void lsm1VblobAppendVarint(lsm1_vblob *p, sqlite3_uint64 x){
          501  +  sqlite3_int64 n = p->n;
          502  +  if( n+9>p->nAlloc && lsm1VblobEnlarge(p, 9) ) return;
          503  +  p->n += lsm1PutVarint64(p->a+p->n, x);
          504  +}
   297    505   
   298    506   /*
   299    507   ** Decode the varint in the first n bytes z[].  Write the integer value
   300    508   ** into *pResult and return the number of bytes in the varint.
   301    509   **
   302    510   ** If the decode fails because there are not enough bytes in z[] then
   303    511   ** return 0;
................................................................................
   345    553       return 8;
   346    554     }
   347    555     *pResult = (((sqlite3_uint64)x)<<32) +
   348    556                  (0xffffffff & ((z[5]<<24) + (z[6]<<16) + (z[7]<<8) + z[8]));
   349    557     return 9;
   350    558   }
   351    559   
   352         -/*
   353         -** Generate a key encoding for pValue such that all keys compare in
   354         -** lexicographical order.  Return an SQLite error code or SQLITE_OK.
          560  +/* Encoded a signed integer as a varint.  Numbers close to zero uses fewer
          561  +** bytes than numbers far away from zero.  However, the result is not in
          562  +** lexicographical order.
   355    563   **
   356         -** The key encoding is *pnKey bytes in length written into *ppKey.
   357         -** Space to hold the key is taken from pSpace if sufficient, or else
   358         -** from sqlite3_malloc().  The caller is responsible for freeing malloced
   359         -** space.
          564  +** Encoding:  Non-negative integer X is encoding as an unsigned
          565  +** varint X*2.  Negative integer Y is encoding as an unsigned
          566  +** varint (1-Y)*2 + 1.
   360    567   */
   361         -static int lsm1EncodeKey(
   362         -  sqlite3_value *pValue,     /* Value to be encoded */
   363         -  unsigned char **ppKey,     /* Write the encoding here */
   364         -  int *pnKey,                /* Write the size of the encoding here */
   365         -  unsigned char *pSpace,     /* Use this space if it is large enough */
   366         -  int nSpace                 /* Size of pSpace[] */
          568  +static int lsm1PutSignedVarint64(u8 *z, sqlite3_int64 v){
          569  +  sqlite3_uint64 u;
          570  +  if( v>=0 ){
          571  +    u = (sqlite3_uint64)v;
          572  +    return lsm1PutVarint64(z, u*2);
          573  +  }else{
          574  +    u = (sqlite3_uint64)(-1-v);
          575  +    return lsm1PutVarint64(z, u*2+1);
          576  +  }
          577  +}
          578  +
          579  +/* Decoded a signed varint. */
          580  +static int lsm1GetSignedVarint64(
          581  +  const unsigned char *z,
          582  +  int n,
          583  +  sqlite3_int64 *pResult
   367    584   ){
   368         -  int eType = sqlite3_value_type(pValue);
   369         -  *ppKey = 0;
   370         -  *pnKey = 0;
   371         -  assert( nSpace>=32 );
   372         -  switch( eType ){
   373         -    default: {
   374         -      return SQLITE_ERROR;  /* We cannot handle NULL keys */
   375         -    }
   376         -    case SQLITE_BLOB:
   377         -    case SQLITE_TEXT: {
   378         -      int nVal = sqlite3_value_bytes(pValue);
   379         -      const void *pVal;
   380         -      if( eType==SQLITE_BLOB ){
   381         -        eType = LSM1_TYPE_BLOB;
   382         -        pVal = sqlite3_value_blob(pValue);
   383         -      }else{
   384         -        eType = LSM1_TYPE_TEXT;
   385         -        pVal = (const void*)sqlite3_value_text(pValue);
   386         -        if( pVal==0 ) return SQLITE_NOMEM;
   387         -      }
   388         -      if( nVal+1>nSpace ){
   389         -        pSpace = sqlite3_malloc( nVal+1 );
   390         -        if( pSpace==0 ) return SQLITE_NOMEM;
   391         -      }
   392         -      pSpace[0] = (unsigned char)eType;
   393         -      memcpy(&pSpace[1], pVal, nVal);
   394         -      *ppKey = pSpace;
   395         -      *pnKey = nVal+1;
   396         -      break;
          585  +  sqlite3_uint64 u = 0;
          586  +  n = lsm1GetVarint64(z, n, &u);
          587  +  if( u&1 ){
          588  +    *pResult = -1 - (sqlite3_int64)(u>>1);
          589  +  }else{
          590  +    *pResult = (sqlite3_int64)(u>>1);
          591  +  }
          592  +  return n;
          593  +}
          594  +
          595  +
          596  +/*
          597  +** Read the value part of the key-value pair and decode it into columns.
          598  +*/
          599  +static int lsm1DecodeValues(lsm1_cursor *pCur){
          600  +  lsm1_vtab *pTab = (lsm1_vtab*)(pCur->base.pVtab);
          601  +  int i, n;
          602  +  int rc;
          603  +  u8 eType;
          604  +  sqlite3_uint64 v;
          605  +
          606  +  if( pCur->zData ) return 1;
          607  +  rc = lsm_csr_value(pCur->pLsmCur, (const void**)&pCur->zData,
          608  +                     (int*)&pCur->nData);
          609  +  if( rc ) return 0;
          610  +  for(i=n=0; i<pTab->nVal; i++){
          611  +    v = 0;
          612  +    n += lsm1GetVarint64(pCur->zData+n, pCur->nData-n, &v);
          613  +    pCur->aeType[i] = eType = (u8)(v%6);
          614  +    if( eType==0 ){
          615  +      pCur->aiOfst[i] = (u32)(v/6);
          616  +      pCur->aiLen[i] = 0;
          617  +    }else{ 
          618  +      pCur->aiOfst[i] = n;
          619  +      n += (pCur->aiLen[i] = (u32)(v/6));
   397    620       }
   398         -    case SQLITE_INTEGER: {
   399         -      sqlite3_int64 iVal = sqlite3_value_int64(pValue);
   400         -      sqlite3_uint64 uVal;
   401         -      if( iVal<0 ){
   402         -        if( iVal==0xffffffffffffffffLL ) return SQLITE_ERROR;
   403         -        uVal = *(sqlite3_uint64*)&iVal;
   404         -        eType = LSM1_TYPE_NEGATIVE;
   405         -      }else{
   406         -        uVal = iVal;
   407         -        eType = LSM1_TYPE_POSITIVE;
   408         -      }
   409         -      pSpace[0] = (unsigned char)eType;
   410         -      *ppKey = pSpace;
   411         -      *pnKey = 1 + lsm1PutVarint64(&pSpace[1], uVal);
   412         -    }
          621  +    if( n>pCur->nData ) break;
   413    622     }
   414         -  return SQLITE_OK;
          623  +  if( i<pTab->nVal ){
          624  +    pCur->zData = 0;
          625  +    return 0;
          626  +  }
          627  +  return 1;
   415    628   }
   416    629   
   417    630   /*
   418    631   ** Return values of columns for the row at which the lsm1_cursor
   419    632   ** is currently pointing.
   420    633   */
   421    634   static int lsm1Column(
   422    635     sqlite3_vtab_cursor *cur,   /* The cursor */
   423    636     sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
   424    637     int i                       /* Which column to return */
   425    638   ){
   426    639     lsm1_cursor *pCur = (lsm1_cursor*)cur;
   427         -  switch( i ){
   428         -    case LSM1_COLUMN_BLOBKEY: {
          640  +  lsm1_vtab *pTab = (lsm1_vtab*)(cur->pVtab);
          641  +  if( i==0 ){
          642  +    /* The key column */
          643  +    const void *pVal;
          644  +    int nVal;
          645  +    if( lsm_csr_key(pCur->pLsmCur, &pVal, &nVal)==LSM_OK ){
          646  +      if( pTab->keyType==SQLITE_BLOB ){
          647  +        sqlite3_result_blob(ctx, pVal, nVal, SQLITE_TRANSIENT);
          648  +      }else if( pTab->keyType==SQLITE_TEXT ){
          649  +        sqlite3_result_text(ctx,(const char*)pVal, nVal, SQLITE_TRANSIENT);
          650  +      }else{
          651  +        const unsigned char *z = (const unsigned char*)pVal;
          652  +        sqlite3_uint64 v1;
          653  +        lsm1GetVarint64(z, nVal, &v1);
          654  +        sqlite3_result_int64(ctx, (sqlite3_int64)v1);
          655  +      }
          656  +    }
          657  +  }else if( i>pTab->nVal ){
          658  +    if( i==pTab->nVal+2 ){  /* lsm1_key */
   429    659         const void *pVal;
   430    660         int nVal;
   431    661         if( lsm_csr_key(pCur->pLsmCur, &pVal, &nVal)==LSM_OK ){
   432    662           sqlite3_result_blob(ctx, pVal, nVal, SQLITE_TRANSIENT);
   433    663         }
   434         -      break;
   435         -    }
   436         -    case LSM1_COLUMN_KEY: {
   437         -      const unsigned char *pVal;
   438         -      int nVal;
   439         -      if( lsm_csr_key(pCur->pLsmCur, (const void**)&pVal, &nVal)==LSM_OK
   440         -       && nVal>=1
   441         -      ){
   442         -        if( pVal[0]==LSM1_TYPE_BLOB ){
   443         -          sqlite3_result_blob(ctx, (const void*)&pVal[1],nVal-1,
   444         -                              SQLITE_TRANSIENT);
   445         -        }else if( pVal[0]==LSM1_TYPE_TEXT ){
   446         -          sqlite3_result_text(ctx, (const char*)&pVal[1],nVal-1,
   447         -                              SQLITE_TRANSIENT);
   448         -        }else if( nVal>=2 && nVal<=10 &&
   449         -           (pVal[0]==LSM1_TYPE_POSITIVE || pVal[0]==LSM1_TYPE_NEGATIVE)
   450         -        ){
   451         -          sqlite3_int64 iVal;
   452         -          lsm1GetVarint64(pVal+1, nVal-1, (sqlite3_uint64*)&iVal);
   453         -          sqlite3_result_int64(ctx, iVal);
   454         -        }         
   455         -      }
   456         -      break;
   457         -    }
   458         -    case LSM1_COLUMN_BLOBVALUE: {
          664  +    }else if( i==pTab->nVal+3 ){  /* lsm1_value */
   459    665         const void *pVal;
   460    666         int nVal;
   461         -      if( lsm_csr_value(pCur->pLsmCur, (const void**)&pVal, &nVal)==LSM_OK ){
          667  +      if( lsm_csr_value(pCur->pLsmCur, &pVal, &nVal)==LSM_OK ){
   462    668           sqlite3_result_blob(ctx, pVal, nVal, SQLITE_TRANSIENT);
   463    669         }
   464         -      break;
   465    670       }
   466         -    case LSM1_COLUMN_VALUE: {
   467         -      const unsigned char *aVal;
   468         -      int nVal;
   469         -      if( lsm_csr_value(pCur->pLsmCur, (const void**)&aVal, &nVal)==LSM_OK
   470         -          && nVal>=1
   471         -      ){
   472         -        switch( aVal[0] ){
   473         -          case SQLITE_FLOAT:
   474         -          case SQLITE_INTEGER: {
   475         -            sqlite3_uint64 x = 0;
   476         -            int j;
   477         -            for(j=1; j<nVal; j++){
   478         -              x = (x<<8) | aVal[j];
   479         -            }
   480         -            if( aVal[0]==SQLITE_INTEGER ){
   481         -              sqlite3_result_int64(ctx, *(sqlite3_int64*)&x);
   482         -            }else{
   483         -              double r;
   484         -              assert( sizeof(r)==sizeof(x) );
   485         -              memcpy(&r, &x, sizeof(r));
   486         -              sqlite3_result_double(ctx, r);
   487         -            }
   488         -            break;
   489         -          }
   490         -          case SQLITE_TEXT: {
   491         -            sqlite3_result_text(ctx, (char*)&aVal[1], nVal-1, SQLITE_TRANSIENT);
   492         -            break;
   493         -          }
   494         -          case SQLITE_BLOB: {
   495         -            sqlite3_result_blob(ctx, &aVal[1], nVal-1, SQLITE_TRANSIENT);
   496         -            break;
   497         -          }
          671  +  }else if( lsm1DecodeValues(pCur) ){
          672  +    /* The i-th value column (where leftmost is 1) */
          673  +    const u8 *zData;
          674  +    u32 nData;
          675  +    i--;
          676  +    zData = pCur->zData + pCur->aiOfst[i];
          677  +    nData = pCur->aiLen[i];
          678  +    switch( pCur->aeType[i] ){
          679  +      case 0: {  /* in-line integer */
          680  +        sqlite3_result_int(ctx, pCur->aiOfst[i]);
          681  +        break;
          682  +      }
          683  +      case SQLITE_INTEGER: {
          684  +        sqlite3_int64 v;
          685  +        lsm1GetSignedVarint64(zData, nData, &v);
          686  +        sqlite3_result_int64(ctx, v);
          687  +        break;
          688  +      }
          689  +      case SQLITE_FLOAT: {
          690  +        double v;
          691  +        if( nData==sizeof(v) ){
          692  +          memcpy(&v, zData, sizeof(v));
          693  +          sqlite3_result_double(ctx, v);
   498    694           }
          695  +        break;
          696  +      }
          697  +      case SQLITE_TEXT: {
          698  +        sqlite3_result_text(ctx, (const char*)zData, nData, SQLITE_TRANSIENT);
          699  +        break;
          700  +      }
          701  +      case SQLITE_BLOB: {
          702  +        sqlite3_result_blob(ctx, zData, nData, SQLITE_TRANSIENT);
          703  +        break;
   499    704         }
   500         -      break;
   501         -    }
   502         -    default: {
   503         -      break;
          705  +      default: {
          706  +         /* A NULL.  Do nothing */
          707  +      }
   504    708       }
   505    709     }
   506    710     return SQLITE_OK;
   507    711   }
          712  +
          713  +/* Parameter "pValue" contains an SQL value that is to be used as
          714  +** a key in an LSM table.  The type of the key is determined by
          715  +** "keyType".  Extract the raw bytes used for the key in LSM1.
          716  +*/
          717  +static void lsm1KeyFromValue(
          718  +  int keyType,                 /* The key type */
          719  +  sqlite3_value *pValue,       /* The key value */
          720  +  u8 *pBuf,                    /* Storage space for a generated key */
          721  +  const u8 **ppKey,            /* OUT: the bytes of the key */
          722  +  int *pnKey                   /* OUT: size of the key */
          723  +){
          724  +  if( keyType==SQLITE_BLOB ){
          725  +    *ppKey = (const u8*)sqlite3_value_blob(pValue);
          726  +    *pnKey = sqlite3_value_bytes(pValue);
          727  +  }else if( keyType==SQLITE_TEXT ){
          728  +    *ppKey = (const u8*)sqlite3_value_text(pValue);
          729  +    *pnKey = sqlite3_value_bytes(pValue);
          730  +  }else{
          731  +    sqlite3_int64 v = sqlite3_value_int64(pValue);
          732  +    if( v<0 ) v = 0;
          733  +    *pnKey = lsm1PutVarint64(pBuf, v);
          734  +    *ppKey = pBuf;
          735  +  }
          736  +}
   508    737   
   509    738   /* Move to the first row to return.
   510    739   */
   511    740   static int lsm1Filter(
   512    741     sqlite3_vtab_cursor *pVtabCursor, 
   513    742     int idxNum, const char *idxStr,
   514    743     int argc, sqlite3_value **argv
   515    744   ){
   516    745     lsm1_cursor *pCur = (lsm1_cursor *)pVtabCursor;
          746  +  lsm1_vtab *pTab = (lsm1_vtab*)(pCur->base.pVtab);
   517    747     int rc = LSM_OK;
          748  +  int seekType = -1;
          749  +  const u8 *pVal = 0;
          750  +  int nVal;
          751  +  u8 keyType = pTab->keyType;
          752  +  u8 aKey1[16];
          753  +
   518    754     pCur->atEof = 1;
   519         -  if( idxNum==1 ){
   520         -    assert( argc==1 );
   521         -    pCur->isDesc = 0;
   522         -    pCur->bUnique = 1;
   523         -    if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
   524         -      const void *pVal = sqlite3_value_blob(argv[0]);
   525         -      int nVal = sqlite3_value_bytes(argv[0]);
   526         -      rc = lsm_csr_seek(pCur->pLsmCur, pVal, nVal, LSM_SEEK_EQ);
          755  +  sqlite3_free(pCur->pKey2);
          756  +  pCur->pKey2 = 0;
          757  +  if( idxNum<99 ){
          758  +    lsm1KeyFromValue(keyType, argv[0], aKey1, &pVal, &nVal);
          759  +  }
          760  +  switch( idxNum ){
          761  +    case 0: {   /* key==argv[0] */
          762  +      assert( argc==1 );
          763  +      seekType = LSM_SEEK_EQ;
          764  +      pCur->isDesc = 0;
          765  +      pCur->bUnique = 1;
          766  +      break;
          767  +    }
          768  +    case 1: {  /* key>=argv[0] AND key<=argv[1] */
          769  +      u8 aKey[12];
          770  +      seekType = LSM_SEEK_GE;
          771  +      pCur->isDesc = 0;
          772  +      pCur->bUnique = 0;
          773  +      if( keyType==SQLITE_INTEGER ){
          774  +        sqlite3_int64 v = sqlite3_value_int64(argv[1]);
          775  +        if( v<0 ) v = 0;
          776  +        pCur->nKey2 = lsm1PutVarint64(aKey, (sqlite3_uint64)v);
          777  +        pCur->pKey2 = sqlite3_malloc( pCur->nKey2 );
          778  +        if( pCur->pKey2==0 ) return SQLITE_NOMEM;
          779  +        memcpy(pCur->pKey2, aKey, pCur->nKey2);
          780  +      }else{
          781  +        pCur->nKey2 = sqlite3_value_bytes(argv[1]);
          782  +        pCur->pKey2 = sqlite3_malloc( pCur->nKey2 );
          783  +        if( pCur->pKey2==0 ) return SQLITE_NOMEM;
          784  +        if( keyType==SQLITE_BLOB ){
          785  +          memcpy(pCur->pKey2, sqlite3_value_blob(argv[1]), pCur->nKey2);
          786  +        }else{
          787  +          memcpy(pCur->pKey2, sqlite3_value_text(argv[1]), pCur->nKey2);
          788  +        }
          789  +      }
          790  +      break;
          791  +    }
          792  +    case 2: {  /* key>=argv[0] */
          793  +      seekType = LSM_SEEK_GE;
          794  +      pCur->isDesc = 0;
          795  +      pCur->bUnique = 0;
          796  +      break;
          797  +    }
          798  +    case 3: {  /* key<=argv[0] */
          799  +      seekType = LSM_SEEK_LE;
          800  +      pCur->isDesc = 1;
          801  +      pCur->bUnique = 0;
          802  +      break;
          803  +    }
          804  +    default: { /* full table scan */
          805  +      pCur->isDesc = 0;
          806  +      pCur->bUnique = 0;
          807  +      break;
   527    808       }
          809  +  }
          810  +  if( pVal ){
          811  +    rc = lsm_csr_seek(pCur->pLsmCur, pVal, nVal, seekType);
   528    812     }else{
   529    813       rc = lsm_csr_first(pCur->pLsmCur);
   530         -    pCur->isDesc = 0;
   531         -    pCur->bUnique = 0;
   532    814     }
   533    815     if( rc==LSM_OK && lsm_csr_valid(pCur->pLsmCur)!=0 ){
   534    816       pCur->atEof = 0;
   535    817     }
   536    818     return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
   537    819   }
   538    820   
   539    821   /*
   540    822   ** Only comparisons against the key are allowed.  The idxNum defines
   541    823   ** which comparisons are available:
   542    824   **
   543         -**     0        Full table scan only
   544         -**   bit 1      key==?1  single argument for ?1
   545         -**   bit 2      key>?1
   546         -**   bit 3      key>=?1
   547         -**   bit 4      key<?N   (N==1 if bits 2,3 clear, or 2 if bits2,3 set)
   548         -**   bit 5      key<=?N  (N==1 if bits 2,3 clear, or 2 if bits2,3 set)
   549         -**   bit 6      Use blobkey instead of key
   550         -**
   551         -** To put it another way:
   552         -**
   553         -**     0        Full table scan.
   554         -**     1        key==?1
   555         -**     2        key>?1
   556         -**     4        key>=?1
   557         -**     8        key<?1
   558         -**     10       key>?1 AND key<?2
   559         -**     12       key>=?1 AND key<?2
   560         -**     16       key<=?1
   561         -**     18       key>?1 AND key<=?2
   562         -**     20       key>=?1 AND key<=?2
   563         -**     33..52   Use blobkey in place of key...
          825  +**     0        key==?1
          826  +**     1        key>=?1 AND key<=?2
          827  +**     2        key>?1 or key>=?1
          828  +**     3        key<?1 or key<=?1
          829  +**    99        Full table scan only
   564    830   */
   565    831   static int lsm1BestIndex(
   566    832     sqlite3_vtab *tab,
   567    833     sqlite3_index_info *pIdxInfo
   568    834   ){
   569    835     int i;                 /* Loop over constraints */
   570         -  int idxNum = 0;        /* The query plan bitmask */
          836  +  int idxNum = 99;       /* The query plan */
   571    837     int nArg = 0;          /* Number of arguments to xFilter */
   572         -  int eqIdx = -1;        /* Index of the key== constraint, or -1 if none */
          838  +  int argIdx = -1;       /* Index of the key== constraint, or -1 if none */
          839  +  int iIdx2 = -1;        /* The index of the second key */
          840  +  int omit1 = 0;
          841  +  int omit2 = 0;
   573    842   
   574    843     const struct sqlite3_index_constraint *pConstraint;
   575    844     pConstraint = pIdxInfo->aConstraint;
   576    845     for(i=0; i<pIdxInfo->nConstraint && idxNum<16; i++, pConstraint++){
   577    846       if( pConstraint->usable==0 ) continue;
   578         -    if( pConstraint->iColumn!=LSM1_COLUMN_KEY ) continue;
   579         -    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
          847  +    if( pConstraint->iColumn!=0 ) continue;
   580    848       switch( pConstraint->op ){
   581    849         case SQLITE_INDEX_CONSTRAINT_EQ: {
   582         -        eqIdx = i;
   583         -        idxNum = 1;
          850  +        if( idxNum>0 ){
          851  +          argIdx = i;
          852  +          iIdx2 = -1;
          853  +          idxNum = 0;
          854  +          omit1 = 1;
          855  +        }
          856  +        break;
          857  +      }
          858  +      case SQLITE_INDEX_CONSTRAINT_GE:
          859  +      case SQLITE_INDEX_CONSTRAINT_GT: {
          860  +        if( idxNum==99 ){
          861  +          argIdx = i;
          862  +          idxNum = 2;
          863  +          omit1 = pConstraint->op==SQLITE_INDEX_CONSTRAINT_GE;
          864  +        }else if( idxNum==3 ){
          865  +          iIdx2 = idxNum;
          866  +          omit2 = omit1;
          867  +          argIdx = i;
          868  +          idxNum = 1;
          869  +          omit1 = pConstraint->op==SQLITE_INDEX_CONSTRAINT_GE;
          870  +        }
          871  +        break;
          872  +      }
          873  +      case SQLITE_INDEX_CONSTRAINT_LE:
          874  +      case SQLITE_INDEX_CONSTRAINT_LT: {
          875  +        if( idxNum==99 ){
          876  +          argIdx = i;
          877  +          idxNum = 3;
          878  +          omit1 = pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE;
          879  +        }else if( idxNum==2 ){
          880  +          iIdx2 = i;
          881  +          idxNum = 1;
          882  +          omit1 = pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE;
          883  +        }
   584    884           break;
   585    885         }
   586    886       }
   587    887     }
   588         -  if( eqIdx>=0 ){
   589         -    pIdxInfo->aConstraintUsage[eqIdx].argvIndex = ++nArg;
   590         -    pIdxInfo->aConstraintUsage[eqIdx].omit = 1;
          888  +  if( argIdx>=0 ){
          889  +    pIdxInfo->aConstraintUsage[argIdx].argvIndex = ++nArg;
          890  +    pIdxInfo->aConstraintUsage[argIdx].omit = omit1;
          891  +  }
          892  +  if( iIdx2>=0 ){
          893  +    pIdxInfo->aConstraintUsage[iIdx2].argvIndex = ++nArg;
          894  +    pIdxInfo->aConstraintUsage[iIdx2].omit = omit2;
   591    895     }
   592         -  if( idxNum==1 ){
          896  +  if( idxNum==0 ){
   593    897       pIdxInfo->estimatedCost = (double)1;
   594    898       pIdxInfo->estimatedRows = 1;
   595    899       pIdxInfo->orderByConsumed = 1;
          900  +  }else if( idxNum==1 ){
          901  +    pIdxInfo->estimatedCost = (double)100;
          902  +    pIdxInfo->estimatedRows = 100;
          903  +  }else if( idxNum<99 ){
          904  +    pIdxInfo->estimatedCost = (double)5000;
          905  +    pIdxInfo->estimatedRows = 5000;
   596    906     }else{
   597    907       /* Full table scan */
   598    908       pIdxInfo->estimatedCost = (double)2147483647;
   599    909       pIdxInfo->estimatedRows = 2147483647;
   600    910     }
   601    911     pIdxInfo->idxNum = idxNum;
   602    912     return SQLITE_OK;
................................................................................
   611    921   int lsm1Update(
   612    922     sqlite3_vtab *pVTab,
   613    923     int argc,
   614    924     sqlite3_value **argv,
   615    925     sqlite_int64 *pRowid
   616    926   ){
   617    927     lsm1_vtab *p = (lsm1_vtab*)pVTab;
   618         -  const void *pKey;
   619         -  void *pFree = 0;
   620         -  int nKey;
   621         -  int eType;
          928  +  int nKey, nKey2;
          929  +  int i;
   622    930     int rc = LSM_OK;
   623         -  sqlite3_value *pValue;
   624         -  const unsigned char *pVal;
   625         -  unsigned char *pData;
   626         -  int nVal;
   627         -  unsigned char pSpace[100];
          931  +  const u8 *pKey, *pKey2;
          932  +  unsigned char aKey[16];
          933  +  unsigned char pSpace[16];
          934  +  lsm1_vblob val;
   628    935   
   629    936     if( argc==1 ){
   630         -    pVTab->zErrMsg = sqlite3_mprintf("cannot DELETE");
   631         -    return SQLITE_ERROR;
          937  +    /* DELETE the record whose key is argv[0] */
          938  +    lsm1KeyFromValue(p->keyType, argv[0], aKey, &pKey, &nKey);
          939  +    lsm_delete(p->pDb, pKey, nKey);
          940  +    return SQLITE_OK;
   632    941     }
          942  +
   633    943     if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){
   634         -    pVTab->zErrMsg = sqlite3_mprintf("cannot UPDATE");
   635         -    return SQLITE_ERROR;
          944  +    /* An UPDATE */
          945  +    lsm1KeyFromValue(p->keyType, argv[0], aKey, &pKey, &nKey);
          946  +    lsm1KeyFromValue(p->keyType, argv[1], pSpace, &pKey2, &nKey2);
          947  +    if( nKey!=nKey2 || memcmp(pKey, pKey2, nKey)!=0 ){
          948  +      /* The UPDATE changes the PRIMARY KEY value.  DELETE the old key */
          949  +      lsm_delete(p->pDb, pKey, nKey);
          950  +    }
          951  +    /* Fall through into the INSERT case to complete the UPDATE */
   636    952     }
   637    953   
   638         -  /* "INSERT INTO tab(command) VALUES('....')" is used to implement
          954  +  /* "INSERT INTO tab(lsm1_command) VALUES('....')" is used to implement
   639    955     ** special commands.
   640    956     */
   641         -  if( sqlite3_value_type(argv[2+LSM1_COLUMN_COMMAND])!=SQLITE_NULL ){
          957  +  if( sqlite3_value_type(argv[3+p->nVal])!=SQLITE_NULL ){
   642    958       return SQLITE_OK;
   643    959     }
   644         -  if( sqlite3_value_type(argv[2+LSM1_COLUMN_BLOBKEY])==SQLITE_BLOB ){
   645         -    /* Use the blob key exactly as supplied */
   646         -    pKey = sqlite3_value_blob(argv[2+LSM1_COLUMN_BLOBKEY]);
   647         -    nKey = sqlite3_value_bytes(argv[2+LSM1_COLUMN_BLOBKEY]);
   648         -  }else{
   649         -    /* Use a key encoding that sorts in lexicographical order */
   650         -    rc = lsm1EncodeKey(argv[2+LSM1_COLUMN_KEY],
   651         -                       (unsigned char**)&pKey,&nKey,
   652         -                       pSpace,sizeof(pSpace));
   653         -    if( rc ) return rc;
   654         -    if( pKey!=(const void*)pSpace ) pFree = (void*)pKey;
   655         -  }
   656         -  if( sqlite3_value_type(argv[2+LSM1_COLUMN_BLOBVALUE])==SQLITE_BLOB ){
   657         -    pVal = sqlite3_value_blob(argv[2+LSM1_COLUMN_BLOBVALUE]);
   658         -    nVal = sqlite3_value_bytes(argv[2+LSM1_COLUMN_BLOBVALUE]);
   659         -    rc = lsm_insert(p->pDb, pKey, nKey, pVal, nVal);
   660         -  }else{
   661         -    pValue = argv[2+LSM1_COLUMN_VALUE];
   662         -    eType = sqlite3_value_type(pValue);
          960  +  lsm1KeyFromValue(p->keyType, argv[2], aKey, &pKey, &nKey);
          961  +  memset(&val, 0, sizeof(val));
          962  +  for(i=0; i<p->nVal; i++){
          963  +    sqlite3_value *pArg = argv[3+i];
          964  +    u8 eType = sqlite3_value_type(pArg);
   663    965       switch( eType ){
   664    966         case SQLITE_NULL: {
   665         -        rc = lsm_delete(p->pDb, pKey, nKey);
          967  +        lsm1VblobAppendVarint(&val, SQLITE_NULL);
   666    968           break;
   667    969         }
   668         -      case SQLITE_BLOB:
   669         -      case SQLITE_TEXT: {
   670         -        if( eType==SQLITE_TEXT ){
   671         -          pVal = sqlite3_value_text(pValue);
          970  +      case SQLITE_INTEGER: {
          971  +        sqlite3_int64 v = sqlite3_value_int64(pArg);
          972  +        if( v>=0 && v<=240/6 ){
          973  +          lsm1VblobAppendVarint(&val, v*6);
   672    974           }else{
   673         -          pVal = (unsigned char*)sqlite3_value_blob(pValue);
   674         -        }
   675         -        nVal = sqlite3_value_bytes(pValue);
   676         -        pData = sqlite3_malloc( nVal+1 );
   677         -        if( pData==0 ){
   678         -          rc = SQLITE_NOMEM;
   679         -        }else{
   680         -          pData[0] = (unsigned char)eType;
   681         -          memcpy(&pData[1], pVal, nVal);
   682         -          rc = lsm_insert(p->pDb, pKey, nKey, pData, nVal+1);
   683         -          sqlite3_free(pData);
          975  +          int n = lsm1PutSignedVarint64(pSpace, v);
          976  +          lsm1VblobAppendVarint(&val, SQLITE_INTEGER + n*6);
          977  +          lsm1VblobAppend(&val, pSpace, n);
   684    978           }
   685    979           break;
   686    980         }
   687         -      case SQLITE_INTEGER:
   688    981         case SQLITE_FLOAT: {
   689         -        sqlite3_uint64 x;
   690         -        unsigned char aVal[9];
   691         -        int i;
   692         -        if( eType==SQLITE_INTEGER ){
   693         -          *(sqlite3_int64*)&x = sqlite3_value_int64(pValue);
   694         -        }else{
   695         -          double r = sqlite3_value_double(pValue);
   696         -          assert( sizeof(r)==sizeof(x) );
   697         -          memcpy(&x, &r, sizeof(r));
   698         -        }
   699         -        for(i=8; x>0 && i>=1; i--){
   700         -          aVal[i] = x & 0xff;
   701         -          x >>= 8;
   702         -        }
   703         -        aVal[i] = (unsigned char)eType;
   704         -        rc = lsm_insert(p->pDb, pKey, nKey, &aVal[i], 9-i);
          982  +        double r = sqlite3_value_double(pArg);
          983  +        lsm1VblobAppendVarint(&val, SQLITE_FLOAT + 8*6);
          984  +        lsm1VblobAppend(&val, (u8*)&r, sizeof(r));
          985  +        break;
          986  +      }
          987  +      case SQLITE_BLOB: {
          988  +        int n = sqlite3_value_bytes(pArg);
          989  +        lsm1VblobAppendVarint(&val, n*6 + SQLITE_BLOB);
          990  +        lsm1VblobAppend(&val, sqlite3_value_blob(pArg), n);
          991  +        break;
          992  +      }
          993  +      case SQLITE_TEXT: {
          994  +        int n = sqlite3_value_bytes(pArg);
          995  +        lsm1VblobAppendVarint(&val, n*6 + SQLITE_TEXT);
          996  +        lsm1VblobAppend(&val, sqlite3_value_text(pArg), n);
   705    997           break;
   706    998         }
   707    999       }
   708   1000     }
   709         -  sqlite3_free(pFree);
         1001  +  if( val.errNoMem ){
         1002  +    return SQLITE_NOMEM;
         1003  +  }
         1004  +  rc = lsm_insert(p->pDb, pKey, nKey, val.a, val.n);
         1005  +  sqlite3_free(val.a);
   710   1006     return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
   711   1007   }      
   712   1008   
   713   1009   /* Begin a transaction
   714   1010   */
   715   1011   static int lsm1Begin(sqlite3_vtab *pVtab){
   716   1012     lsm1_vtab *p = (lsm1_vtab*)pVtab;

Changes to ext/lsm1/test/lsm1_simple.test.

    15     15   source [file join [file dirname [info script]] lsm1_common.tcl]
    16     16   set testprefix lsm1_simple
    17     17   return_if_no_lsm1
    18     18   load_lsm1_vtab db
    19     19   
    20     20   forcedelete testlsm.db
    21     21   
    22         -do_execsql_test 1.0 {
    23         -  CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db);
           22  +do_execsql_test 100 {
           23  +  CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,UINT,b,c,d);
    24     24     PRAGMA table_info(x1);
    25     25   } {
    26         -  0 key       {} 0 {} 0 
    27         -  1 blobkey   {} 0 {} 0 
    28         -  2 value     {} 0 {} 0 
    29         -  3 blobvalue {} 0 {} 0
           26  +  0 a UINT 1 {} 1 
           27  +  1 b {} 0 {} 0 
           28  +  2 c {} 0 {} 0 
           29  +  3 d {} 0 {} 0
    30     30   }
    31     31   
    32         -do_execsql_test 1.1 {
    33         -  INSERT INTO x1(blobkey, blobvalue) VALUES(x'abcd', x'1234');
    34         -  SELECT quote(blobkey), quote(blobvalue) FROM x1;
    35         -} {X'ABCD' X'1234'}
           32  +do_execsql_test 110 {
           33  +  INSERT INTO x1(a,b,c,d) VALUES(15, 11, 22, 33),(8,'banjo',x'333231',NULL),
           34  +      (12,NULL,3.25,-559281390);
           35  +  SELECT a, quote(b), quote(c), quote(d) FROM x1;
           36  +} {8 'banjo' X'333231' NULL 12 NULL 3.25 -559281390 15 11 22 33}
           37  +do_execsql_test 111 {
           38  +  SELECT a, quote(lsm1_key), quote(lsm1_value) FROM x1;
           39  +} {8 X'08' X'2162616E6A6F1633323105' 12 X'0C' X'05320000000000000A401FFB42ABE9DB' 15 X'0F' X'4284C6'}
           40  +
           41  +do_execsql_test 120 {
           42  +  UPDATE x1 SET d = d+1.0 WHERE a=15;
           43  +  SELECT a, quote(b), quote(c), quote(d) FROM x1;
           44  +} {8 'banjo' X'333231' NULL 12 NULL 3.25 -559281390 15 11 22 34.0}
           45  +
           46  +do_execsql_test 130 {
           47  +  UPDATE x1 SET a=123456789 WHERE a=12;
           48  +  SELECT a, quote(b), quote(c), quote(d) FROM x1;
           49  +} {8 'banjo' X'333231' NULL 15 11 22 34.0 123456789 NULL 3.25 -559281390}
           50  +do_execsql_test 131 {
           51  +  SELECT quote(lsm1_key), printf('0x%x',a) FROM x1 WHERE a > 100000000;
           52  +} {X'FB075BCD15' 0x75bcd15}
    36     53   
    37         -do_catchsql_test 1.2 {
    38         -  UPDATE x1 SET blobvalue = x'7890' WHERE blobkey = x'abcd';
    39         -} {1 {cannot UPDATE}}
           54  +do_execsql_test 140 {
           55  +  DELETE FROM x1 WHERE a=15;
           56  +  SELECT a, quote(b), quote(c), quote(d) FROM x1;
           57  +} {8 'banjo' X'333231' NULL 123456789 NULL 3.25 -559281390}
    40     58   
    41         -do_catchsql_test 1.3 {
    42         -  DELETE FROM x1 WHERE blobkey = x'abcd'
    43         -} {1 {cannot DELETE}}
    44         -
    45         -do_test 1.4 {
           59  +do_test 150 {
    46     60     lsort [glob testlsm.db*]
    47     61   } {testlsm.db testlsm.db-log testlsm.db-shm}
    48     62   
    49     63   db close
    50         -do_test 1.5 {
           64  +do_test 160 {
    51     65     lsort [glob testlsm.db*]
    52     66   } {testlsm.db}
    53     67   
    54         -finish_test
           68  +forcedelete testlsm.db
           69  +forcedelete test.db
           70  +sqlite3 db test.db
           71  +load_lsm1_vtab db
           72  +
           73  +
           74  +do_execsql_test 200 {
           75  +  CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,TEXT,b,c,d);
           76  +  PRAGMA table_info(x1);
           77  +} {
           78  +  0 a TEXT 1 {} 1 
           79  +  1 b {} 0 {} 0 
           80  +  2 c {} 0 {} 0 
           81  +  3 d {} 0 {} 0
           82  +}
           83  +do_execsql_test 210 {
           84  +  INSERT INTO x1(a,b,c,d) VALUES(15, 11, 22, 33),(8,'banjo',x'333231',NULL),
           85  +      (12,NULL,3.25,-559281390);
           86  +  SELECT quote(a), quote(b), quote(c), quote(d), '|' FROM x1;
           87  +} {'12' NULL 3.25 -559281390 | '15' 11 22 33 | '8' 'banjo' X'333231' NULL |}
           88  +do_execsql_test 211 {
           89  +  SELECT quote(a), quote(lsm1_key), quote(lsm1_value), '|' FROM x1;
           90  +} {'12' X'3132' X'05320000000000000A401FFB42ABE9DB' | '15' X'3135' X'4284C6' | '8' X'38' X'2162616E6A6F1633323105' |}
    55     91   
    56     92   
           93  +finish_test

Changes to ext/misc/csv.c.

   676    676           pCur->azVal[i] = zNew;
   677    677           pCur->aLen[i] = pCur->rdr.n+1;
   678    678         }
   679    679         memcpy(pCur->azVal[i], z, pCur->rdr.n+1);
   680    680         i++;
   681    681       }
   682    682     }while( pCur->rdr.cTerm==',' );
   683         -  while( i<pTab->nCol ){
   684         -    sqlite3_free(pCur->azVal[i]);
   685         -    pCur->azVal[i] = 0;
   686         -    pCur->aLen[i] = 0;
   687         -    i++;
   688         -  }
   689         -  if( z==0 || pCur->rdr.cTerm==EOF ){
          683  +  if( z==0 || (pCur->rdr.cTerm==EOF && i<pTab->nCol) ){
   690    684       pCur->iRowid = -1;
   691    685     }else{
   692    686       pCur->iRowid++;
          687  +    while( i<pTab->nCol ){
          688  +      sqlite3_free(pCur->azVal[i]);
          689  +      pCur->azVal[i] = 0;
          690  +      pCur->aLen[i] = 0;
          691  +      i++;
          692  +    }
   693    693     }
   694    694     return SQLITE_OK;
   695    695   }
   696    696   
   697    697   /*
   698    698   ** Return values of columns for the row at which the CsvCursor
   699    699   ** is currently pointing.

Added ext/misc/vtablog.c.

            1  +/*
            2  +** 2017-08-10
            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 virtual table that prints diagnostic information
           14  +** on stdout when its key interfaces are called.  This is intended for
           15  +** interactive analysis and debugging of virtual table interfaces.
           16  +**
           17  +** Usage example:
           18  +**
           19  +**     .load ./vtablog
           20  +**     CREATE VIRTUAL TABLE temp.log USING vtablog(
           21  +**        schema='CREATE TABLE x(a,b,c)',
           22  +**        rows=25
           23  +**     );
           24  +**     SELECT * FROM log;
           25  +*/
           26  +#include "sqlite3ext.h"
           27  +SQLITE_EXTENSION_INIT1
           28  +#include <stdio.h>
           29  +#include <stdlib.h>
           30  +#include <assert.h>
           31  +#include <string.h>
           32  +#include <ctype.h>
           33  +
           34  +
           35  +/* vtablog_vtab is a subclass of sqlite3_vtab which will
           36  +** serve as the underlying representation of a vtablog virtual table
           37  +*/
           38  +typedef struct vtablog_vtab vtablog_vtab;
           39  +struct vtablog_vtab {
           40  +  sqlite3_vtab base;  /* Base class - must be first */
           41  +  int nRow;           /* Number of rows in the table */
           42  +  int iInst;          /* Instance number for this vtablog table */
           43  +  int nCursor;        /* Number of cursors created */
           44  +};
           45  +
           46  +/* vtablog_cursor is a subclass of sqlite3_vtab_cursor which will
           47  +** serve as the underlying representation of a cursor that scans
           48  +** over rows of the result
           49  +*/
           50  +typedef struct vtablog_cursor vtablog_cursor;
           51  +struct vtablog_cursor {
           52  +  sqlite3_vtab_cursor base;  /* Base class - must be first */
           53  +  int iCursor;               /* Cursor number */
           54  +  sqlite3_int64 iRowid;      /* The rowid */
           55  +};
           56  +
           57  +/* Skip leading whitespace.  Return a pointer to the first non-whitespace
           58  +** character, or to the zero terminator if the string has only whitespace */
           59  +static const char *vtablog_skip_whitespace(const char *z){
           60  +  while( isspace((unsigned char)z[0]) ) z++;
           61  +  return z;
           62  +}
           63  +
           64  +/* Remove trailing whitespace from the end of string z[] */
           65  +static void vtablog_trim_whitespace(char *z){
           66  +  size_t n = strlen(z);
           67  +  while( n>0 && isspace((unsigned char)z[n]) ) n--;
           68  +  z[n] = 0;
           69  +}
           70  +
           71  +/* Dequote the string */
           72  +static void vtablog_dequote(char *z){
           73  +  int j;
           74  +  char cQuote = z[0];
           75  +  size_t i, n;
           76  +
           77  +  if( cQuote!='\'' && cQuote!='"' ) return;
           78  +  n = strlen(z);
           79  +  if( n<2 || z[n-1]!=z[0] ) return;
           80  +  for(i=1, j=0; i<n-1; i++){
           81  +    if( z[i]==cQuote && z[i+1]==cQuote ) i++;
           82  +    z[j++] = z[i];
           83  +  }
           84  +  z[j] = 0;
           85  +}
           86  +
           87  +/* Check to see if the string is of the form:  "TAG = VALUE" with optional
           88  +** whitespace before and around tokens.  If it is, return a pointer to the
           89  +** first character of VALUE.  If it is not, return NULL.
           90  +*/
           91  +static const char *vtablog_parameter(const char *zTag, int nTag, const char *z){
           92  +  z = vtablog_skip_whitespace(z);
           93  +  if( strncmp(zTag, z, nTag)!=0 ) return 0;
           94  +  z = vtablog_skip_whitespace(z+nTag);
           95  +  if( z[0]!='=' ) return 0;
           96  +  return vtablog_skip_whitespace(z+1);
           97  +}
           98  +
           99  +/* Decode a parameter that requires a dequoted string.
          100  +**
          101  +** Return non-zero on an error.
          102  +*/
          103  +static int vtablog_string_parameter(
          104  +  char **pzErr,            /* Leave the error message here, if there is one */
          105  +  const char *zParam,      /* Parameter we are checking for */
          106  +  const char *zArg,        /* Raw text of the virtual table argment */
          107  +  char **pzVal             /* Write the dequoted string value here */
          108  +){
          109  +  const char *zValue;
          110  +  zValue = vtablog_parameter(zParam,(int)strlen(zParam),zArg);
          111  +  if( zValue==0 ) return 0;
          112  +  if( *pzVal ){
          113  +    *pzErr = sqlite3_mprintf("more than one '%s' parameter", zParam);
          114  +    return 1;
          115  +  }
          116  +  *pzVal = sqlite3_mprintf("%s", zValue);
          117  +  if( *pzVal==0 ){
          118  +    *pzErr = sqlite3_mprintf("out of memory");
          119  +    return 1;
          120  +  }
          121  +  vtablog_trim_whitespace(*pzVal);
          122  +  vtablog_dequote(*pzVal);
          123  +  return 0;
          124  +}
          125  +
          126  +#if 0 /* not used - yet */
          127  +/* Return 0 if the argument is false and 1 if it is true.  Return -1 if
          128  +** we cannot really tell.
          129  +*/
          130  +static int vtablog_boolean(const char *z){
          131  +  if( sqlite3_stricmp("yes",z)==0
          132  +   || sqlite3_stricmp("on",z)==0
          133  +   || sqlite3_stricmp("true",z)==0
          134  +   || (z[0]=='1' && z[1]==0)
          135  +  ){
          136  +    return 1;
          137  +  }
          138  +  if( sqlite3_stricmp("no",z)==0
          139  +   || sqlite3_stricmp("off",z)==0
          140  +   || sqlite3_stricmp("false",z)==0
          141  +   || (z[0]=='0' && z[1]==0)
          142  +  ){
          143  +    return 0;
          144  +  }
          145  +  return -1;
          146  +}
          147  +#endif
          148  +
          149  +/*
          150  +** The vtablogConnect() method is invoked to create a new
          151  +** vtablog_vtab that describes the vtablog virtual table.
          152  +**
          153  +** Think of this routine as the constructor for vtablog_vtab objects.
          154  +**
          155  +** All this routine needs to do is:
          156  +**
          157  +**    (1) Allocate the vtablog_vtab object and initialize all fields.
          158  +**
          159  +**    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
          160  +**        result set of queries against vtablog will look like.
          161  +*/
          162  +static int vtablogConnectCreate(
          163  +  sqlite3 *db,
          164  +  void *pAux,
          165  +  int argc, const char *const*argv,
          166  +  sqlite3_vtab **ppVtab,
          167  +  char **pzErr,
          168  +  int isCreate
          169  +){
          170  +  static int nInst = 0;
          171  +  vtablog_vtab *pNew;
          172  +  int i;
          173  +  int rc;
          174  +  int iInst = ++nInst;
          175  +  char *zSchema = 0;
          176  +  char *zNRow = 0;
          177  +
          178  +  printf("vtablog%s(tab=%d):\n", isCreate ? "Create" : "Connect", iInst);
          179  +  printf("  argc=%d\n", argc);
          180  +  for(i=0; i<argc; i++){
          181  +    printf("  argv[%d] = ", i);
          182  +    if( argv[i] ){
          183  +      printf("[%s]\n", argv[i]);
          184  +    }else{
          185  +      printf("NULL\n");
          186  +    }
          187  +  }
          188  +
          189  +  for(i=3; i<argc; i++){
          190  +    const char *z = argv[i];
          191  +    if( vtablog_string_parameter(pzErr, "schema", z, &zSchema) ){
          192  +      return SQLITE_ERROR;
          193  +    }
          194  +    if( vtablog_string_parameter(pzErr, "rows", z, &zNRow) ){
          195  +      return SQLITE_ERROR;
          196  +    }
          197  +  }
          198  +
          199  +  if( zSchema==0 ){
          200  +    *pzErr = sqlite3_mprintf("no schema defined");
          201  +    return SQLITE_ERROR;
          202  +  }
          203  +  rc = sqlite3_declare_vtab(db, zSchema);
          204  +  if( rc==SQLITE_OK ){
          205  +    pNew = sqlite3_malloc( sizeof(*pNew) );
          206  +    *ppVtab = (sqlite3_vtab*)pNew;
          207  +    if( pNew==0 ) return SQLITE_NOMEM;
          208  +    memset(pNew, 0, sizeof(*pNew));
          209  +    pNew->nRow = 10;
          210  +    if( zNRow ) pNew->nRow = atoi(zNRow);
          211  +    pNew->iInst = iInst;
          212  +  }
          213  +  return rc;
          214  +}
          215  +static int vtablogCreate(
          216  +  sqlite3 *db,
          217  +  void *pAux,
          218  +  int argc, const char *const*argv,
          219  +  sqlite3_vtab **ppVtab,
          220  +  char **pzErr
          221  +){
          222  +  return vtablogConnectCreate(db,pAux,argc,argv,ppVtab,pzErr,1);
          223  +}
          224  +static int vtablogConnect(
          225  +  sqlite3 *db,
          226  +  void *pAux,
          227  +  int argc, const char *const*argv,
          228  +  sqlite3_vtab **ppVtab,
          229  +  char **pzErr
          230  +){
          231  +  return vtablogConnectCreate(db,pAux,argc,argv,ppVtab,pzErr,0);
          232  +}
          233  +
          234  +
          235  +/*
          236  +** This method is the destructor for vtablog_cursor objects.
          237  +*/
          238  +static int vtablogDisconnect(sqlite3_vtab *pVtab){
          239  +  vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
          240  +  printf("vtablogDisconnect(%d)\n", pTab->iInst);
          241  +  sqlite3_free(pVtab);
          242  +  return SQLITE_OK;
          243  +}
          244  +
          245  +/*
          246  +** This method is the destructor for vtablog_cursor objects.
          247  +*/
          248  +static int vtablogDestroy(sqlite3_vtab *pVtab){
          249  +  vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
          250  +  printf("vtablogDestroy(%d)\n", pTab->iInst);
          251  +  sqlite3_free(pVtab);
          252  +  return SQLITE_OK;
          253  +}
          254  +
          255  +/*
          256  +** Constructor for a new vtablog_cursor object.
          257  +*/
          258  +static int vtablogOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
          259  +  vtablog_vtab *pTab = (vtablog_vtab*)p;
          260  +  vtablog_cursor *pCur;
          261  +  printf("vtablogOpen(tab=%d, cursor=%d)\n", pTab->iInst, ++pTab->nCursor);
          262  +  pCur = sqlite3_malloc( sizeof(*pCur) );
          263  +  if( pCur==0 ) return SQLITE_NOMEM;
          264  +  memset(pCur, 0, sizeof(*pCur));
          265  +  pCur->iCursor = pTab->nCursor;
          266  +  *ppCursor = &pCur->base;
          267  +  return SQLITE_OK;
          268  +}
          269  +
          270  +/*
          271  +** Destructor for a vtablog_cursor.
          272  +*/
          273  +static int vtablogClose(sqlite3_vtab_cursor *cur){
          274  +  vtablog_cursor *pCur = (vtablog_cursor*)cur;
          275  +  vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
          276  +  printf("vtablogClose(tab=%d, cursor=%d)\n", pTab->iInst, pCur->iCursor);
          277  +  sqlite3_free(cur);
          278  +  return SQLITE_OK;
          279  +}
          280  +
          281  +
          282  +/*
          283  +** Advance a vtablog_cursor to its next row of output.
          284  +*/
          285  +static int vtablogNext(sqlite3_vtab_cursor *cur){
          286  +  vtablog_cursor *pCur = (vtablog_cursor*)cur;
          287  +  vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
          288  +  printf("vtablogNext(tab=%d, cursor=%d)  rowid %d -> %d\n", 
          289  +         pTab->iInst, pCur->iCursor, (int)pCur->iRowid, (int)pCur->iRowid+1);
          290  +  pCur->iRowid++;
          291  +  return SQLITE_OK;
          292  +}
          293  +
          294  +/*
          295  +** Return values of columns for the row at which the vtablog_cursor
          296  +** is currently pointing.
          297  +*/
          298  +static int vtablogColumn(
          299  +  sqlite3_vtab_cursor *cur,   /* The cursor */
          300  +  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
          301  +  int i                       /* Which column to return */
          302  +){
          303  +  vtablog_cursor *pCur = (vtablog_cursor*)cur;
          304  +  vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
          305  +  char zVal[50];
          306  +
          307  +  if( i<26 ){
          308  +    sqlite3_snprintf(sizeof(zVal),zVal,"%c%d", 
          309  +                     "abcdefghijklmnopqrstuvwyz"[i], pCur->iRowid);
          310  +  }else{
          311  +    sqlite3_snprintf(sizeof(zVal),zVal,"{%d}%d", i, pCur->iRowid);
          312  +  }
          313  +  printf("vtablogColumn(tab=%d, cursor=%d, i=%d): [%s]\n",
          314  +         pTab->iInst, pCur->iCursor, i, zVal);
          315  +  sqlite3_result_text(ctx, zVal, -1, SQLITE_TRANSIENT);
          316  +  return SQLITE_OK;
          317  +}
          318  +
          319  +/*
          320  +** Return the rowid for the current row.  In this implementation, the
          321  +** rowid is the same as the output value.
          322  +*/
          323  +static int vtablogRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
          324  +  vtablog_cursor *pCur = (vtablog_cursor*)cur;
          325  +  vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
          326  +  printf("vtablogRowid(tab=%d, cursor=%d): %d\n",
          327  +         pTab->iInst, pCur->iCursor, (int)pCur->iRowid);
          328  +  *pRowid = pCur->iRowid;
          329  +  return SQLITE_OK;
          330  +}
          331  +
          332  +/*
          333  +** Return TRUE if the cursor has been moved off of the last
          334  +** row of output.
          335  +*/
          336  +static int vtablogEof(sqlite3_vtab_cursor *cur){
          337  +  vtablog_cursor *pCur = (vtablog_cursor*)cur;
          338  +  vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
          339  +  int rc = pCur->iRowid >= pTab->nRow;
          340  +  printf("vtablogEof(tab=%d, cursor=%d): %d\n",
          341  +         pTab->iInst, pCur->iCursor, rc);
          342  +  return rc;
          343  +}
          344  +
          345  +/*
          346  +** Output an sqlite3_value object's value as an SQL literal.
          347  +*/
          348  +static void vtablogQuote(sqlite3_value *p){
          349  +  char z[50];
          350  +  switch( sqlite3_value_type(p) ){
          351  +    case SQLITE_NULL: {
          352  +      printf("NULL");
          353  +      break;
          354  +    }
          355  +    case SQLITE_INTEGER: {
          356  +      sqlite3_snprintf(50,z,"%lld", sqlite3_value_int64(p));
          357  +      printf("%s", z);
          358  +      break;
          359  +    }
          360  +    case SQLITE_FLOAT: {
          361  +      sqlite3_snprintf(50,z,"%!.20g", sqlite3_value_double(p));
          362  +      printf("%s", z);
          363  +      break;
          364  +    }
          365  +    case SQLITE_BLOB: {
          366  +      int n = sqlite3_value_bytes(p);
          367  +      const unsigned char *z = (const unsigned char*)sqlite3_value_blob(p);
          368  +      int i;
          369  +      printf("x'");
          370  +      for(i=0; i<n; i++) printf("%02x", z[i]);
          371  +      printf("'");
          372  +      break;
          373  +    }
          374  +    case SQLITE_TEXT: {
          375  +      const char *z = (const char*)sqlite3_value_text(p);
          376  +      int i;
          377  +      char c;
          378  +      for(i=0; (c = z[i])!=0 && c!='\''; i++){}
          379  +      if( c==0 ){
          380  +        printf("'%s'",z);
          381  +      }else{
          382  +        printf("'");
          383  +        while( *z ){
          384  +          for(i=0; (c = z[i])!=0 && c!='\''; i++){}
          385  +          if( c=='\'' ) i++;
          386  +          if( i ){
          387  +            printf("%.*s", i, z);
          388  +            z += i;
          389  +          }
          390  +          if( c=='\'' ){
          391  +            printf("'");
          392  +            continue;
          393  +          }
          394  +          if( c==0 ){
          395  +            break;
          396  +          }
          397  +          z++;
          398  +        }
          399  +        printf("'");
          400  +      }
          401  +      break;
          402  +    }
          403  +  }
          404  +}
          405  +
          406  +
          407  +/*
          408  +** This method is called to "rewind" the vtablog_cursor object back
          409  +** to the first row of output.  This method is always called at least
          410  +** once prior to any call to vtablogColumn() or vtablogRowid() or 
          411  +** vtablogEof().
          412  +*/
          413  +static int vtablogFilter(
          414  +  sqlite3_vtab_cursor *cur,
          415  +  int idxNum, const char *idxStr,
          416  +  int argc, sqlite3_value **argv
          417  +){
          418  +  vtablog_cursor *pCur = (vtablog_cursor *)cur;
          419  +  vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
          420  +  printf("vtablogFilter(tab=%d, cursor=%d):\n", pTab->iInst, pCur->iCursor);
          421  +  pCur->iRowid = 0;
          422  +  return SQLITE_OK;
          423  +}
          424  +
          425  +/*
          426  +** SQLite will invoke this method one or more times while planning a query
          427  +** that uses the vtablog virtual table.  This routine needs to create
          428  +** a query plan for each invocation and compute an estimated cost for that
          429  +** plan.
          430  +*/
          431  +static int vtablogBestIndex(
          432  +  sqlite3_vtab *tab,
          433  +  sqlite3_index_info *pIdxInfo
          434  +){
          435  +  vtablog_vtab *pTab = (vtablog_vtab*)tab;
          436  +  printf("vtablogBestIndex(tab=%d):\n", pTab->iInst);
          437  +  pIdxInfo->estimatedCost = (double)500;
          438  +  pIdxInfo->estimatedRows = 500;
          439  +  return SQLITE_OK;
          440  +}
          441  +
          442  +/*
          443  +** SQLite invokes this method to INSERT, UPDATE, or DELETE content from
          444  +** the table. 
          445  +**
          446  +** This implementation does not actually make any changes to the table
          447  +** content.  It merely logs the fact that the method was invoked
          448  +*/
          449  +static int vtablogUpdate(
          450  +  sqlite3_vtab *tab,
          451  +  int argc,
          452  +  sqlite3_value **argv,
          453  +  sqlite_int64 *pRowid
          454  +){
          455  +  vtablog_vtab *pTab = (vtablog_vtab*)tab;
          456  +  int i;
          457  +  printf("vtablogUpdate(tab=%d):\n", pTab->iInst);
          458  +  printf("  argc=%d\n", argc);
          459  +  for(i=0; i<argc; i++){
          460  +    printf("  argv[%d]=", i);
          461  +    vtablogQuote(argv[i]);
          462  +    printf("\n");
          463  +  }
          464  +  return SQLITE_OK;
          465  +}
          466  +
          467  +/*
          468  +** This following structure defines all the methods for the 
          469  +** vtablog virtual table.
          470  +*/
          471  +static sqlite3_module vtablogModule = {
          472  +  0,                         /* iVersion */
          473  +  vtablogCreate,             /* xCreate */
          474  +  vtablogConnect,            /* xConnect */
          475  +  vtablogBestIndex,          /* xBestIndex */
          476  +  vtablogDisconnect,         /* xDisconnect */
          477  +  vtablogDestroy,            /* xDestroy */
          478  +  vtablogOpen,               /* xOpen - open a cursor */
          479  +  vtablogClose,              /* xClose - close a cursor */
          480  +  vtablogFilter,             /* xFilter - configure scan constraints */
          481  +  vtablogNext,               /* xNext - advance a cursor */
          482  +  vtablogEof,                /* xEof - check for end of scan */
          483  +  vtablogColumn,             /* xColumn - read data */
          484  +  vtablogRowid,              /* xRowid - read data */
          485  +  vtablogUpdate,             /* xUpdate */
          486  +  0,                         /* xBegin */
          487  +  0,                         /* xSync */
          488  +  0,                         /* xCommit */
          489  +  0,                         /* xRollback */
          490  +  0,                         /* xFindMethod */
          491  +  0,                         /* xRename */
          492  +  0,                         /* xSavepoint */
          493  +  0,                         /* xRelease */
          494  +  0,                         /* xRollbackTo */
          495  +};
          496  +
          497  +#ifdef _WIN32
          498  +__declspec(dllexport)
          499  +#endif
          500  +int sqlite3_vtablog_init(
          501  +  sqlite3 *db, 
          502  +  char **pzErrMsg, 
          503  +  const sqlite3_api_routines *pApi
          504  +){
          505  +  int rc;
          506  +  SQLITE_EXTENSION_INIT2(pApi);
          507  +  rc = sqlite3_create_module(db, "vtablog", &vtablogModule, 0);
          508  +  return rc;
          509  +}

Changes to ext/rtree/rtreeA.test.

   224    224   sqlite3 db test.db
   225    225   do_execsql_test rtreeA-7.100 { 
   226    226     UPDATE t1_node SET data=x'' WHERE rowid=1;
   227    227   } {}
   228    228   do_catchsql_test rtreeA-7.110 {
   229    229     SELECT * FROM t1 WHERE x1>0 AND x1<100 AND x2>0 AND x2<100;
   230    230   } {1 {undersize RTree blobs in "t1_node"}}
          231  +do_test rtreeA-7.120 {
          232  +  sqlite3_extended_errcode db
          233  +} {SQLITE_CORRUPT}
          234  +
   231    235   
   232    236   
   233    237   finish_test

Changes to src/build.c.

  3879   3879   
  3880   3880   /*
  3881   3881   ** Add an INDEXED BY or NOT INDEXED clause to the most recently added 
  3882   3882   ** element of the source-list passed as the second argument.
  3883   3883   */
  3884   3884   void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
  3885   3885     assert( pIndexedBy!=0 );
  3886         -  if( p && ALWAYS(p->nSrc>0) ){
  3887         -    struct SrcList_item *pItem = &p->a[p->nSrc-1];
         3886  +  if( p && pIndexedBy->n>0 ){
         3887  +    struct SrcList_item *pItem;
         3888  +    assert( p->nSrc>0 );
         3889  +    pItem = &p->a[p->nSrc-1];
  3888   3890       assert( pItem->fg.notIndexed==0 );
  3889   3891       assert( pItem->fg.isIndexedBy==0 );
  3890   3892       assert( pItem->fg.isTabFunc==0 );
  3891   3893       if( pIndexedBy->n==1 && !pIndexedBy->z ){
  3892   3894         /* A "NOT INDEXED" clause was supplied. See parse.y 
  3893   3895         ** construct "indexed_opt" for details. */
  3894   3896         pItem->fg.notIndexed = 1;
  3895   3897       }else{
  3896   3898         pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
  3897         -      pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0);
         3899  +      pItem->fg.isIndexedBy = 1;
  3898   3900       }
  3899   3901     }
  3900   3902   }
  3901   3903   
  3902   3904   /*
  3903   3905   ** Add the list of function arguments to the SrcList entry for a
  3904   3906   ** table-valued-function.

Changes to src/delete.c.

   498    498         if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){
   499    499           assert( pPk!=0 || pTab->pSelect!=0 );
   500    500           sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
   501    501           VdbeCoverage(v);
   502    502         }
   503    503       }else if( pPk ){
   504    504         addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
   505         -      sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
          505  +      if( IsVirtual(pTab) ){
          506  +        sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey);
          507  +      }else{
          508  +        sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
          509  +      }
   506    510         assert( nKey==0 );  /* OP_Found will use a composite key */
   507    511       }else{
   508    512         addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
   509    513         VdbeCoverage(v);
   510    514         assert( nKey==1 );
   511    515       }  
   512    516     

Changes to src/os_unix.c.

  3880   3880   #if SQLITE_MAX_MMAP_SIZE>0
  3881   3881       case SQLITE_FCNTL_MMAP_SIZE: {
  3882   3882         i64 newLimit = *(i64*)pArg;
  3883   3883         int rc = SQLITE_OK;
  3884   3884         if( newLimit>sqlite3GlobalConfig.mxMmap ){
  3885   3885           newLimit = sqlite3GlobalConfig.mxMmap;
  3886   3886         }
         3887  +
         3888  +      /* The value of newLimit may be eventually cast to (size_t) and passed
         3889  +      ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a
         3890  +      ** 64-bit type. */
         3891  +      if( newLimit>0 && sizeof(size_t)<8 ){
         3892  +        newLimit = (newLimit & 0x7FFFFFFF);
         3893  +      }
         3894  +
  3887   3895         *(i64*)pArg = pFile->mmapSizeMax;
  3888   3896         if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
  3889   3897           pFile->mmapSizeMax = newLimit;
  3890   3898           if( pFile->mmapSize>0 ){
  3891   3899             unixUnmapfile(pFile);
  3892   3900             rc = unixMapfile(pFile, -1);
  3893   3901           }

Changes to src/os_win.c.

  3555   3555   #if SQLITE_MAX_MMAP_SIZE>0
  3556   3556       case SQLITE_FCNTL_MMAP_SIZE: {
  3557   3557         i64 newLimit = *(i64*)pArg;
  3558   3558         int rc = SQLITE_OK;
  3559   3559         if( newLimit>sqlite3GlobalConfig.mxMmap ){
  3560   3560           newLimit = sqlite3GlobalConfig.mxMmap;
  3561   3561         }
         3562  +
         3563  +      /* The value of newLimit may be eventually cast to (SIZE_T) and passed
         3564  +      ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at
         3565  +      ** least a 64-bit type. */
         3566  +      if( newLimit>0 && sizeof(SIZE_T)<8 ){
         3567  +        newLimit = (newLimit & 0x7FFFFFFF);
         3568  +      }
         3569  +
  3562   3570         *(i64*)pArg = pFile->mmapSizeMax;
  3563   3571         if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
  3564   3572           pFile->mmapSizeMax = newLimit;
  3565   3573           if( pFile->mmapSize>0 ){
  3566   3574             winUnmapfile(pFile);
  3567   3575             rc = winMapfile(pFile, -1);
  3568   3576           }

Changes to src/pager.c.

   124    124   ** The following two macros are used within the PAGERTRACE() macros above
   125    125   ** to print out file-descriptors. 
   126    126   **
   127    127   ** PAGERID() takes a pointer to a Pager struct as its argument. The
   128    128   ** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
   129    129   ** struct as its argument.
   130    130   */
   131         -#define PAGERID(p) ((int)(p->fd))
   132         -#define FILEHANDLEID(fd) ((int)fd)
          131  +#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd))
          132  +#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd))
   133    133   
   134    134   /*
   135    135   ** The Pager.eState variable stores the current 'state' of a pager. A
   136    136   ** pager may be in any one of the seven states shown in the following
   137    137   ** state diagram.
   138    138   **
   139    139   **                            OPEN <------+------+

Changes to src/printf.c.

   778    778     if( p->mxAlloc==0 ){
   779    779       N = p->nAlloc - p->nChar - 1;
   780    780       setStrAccumError(p, STRACCUM_TOOBIG);
   781    781       return N;
   782    782     }else{
   783    783       char *zOld = isMalloced(p) ? p->zText : 0;
   784    784       i64 szNew = p->nChar;
   785         -    assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
   786    785       szNew += N + 1;
   787    786       if( szNew+p->nChar<=p->mxAlloc ){
   788    787         /* Force exponential buffer size growth as long as it does not overflow,
   789    788         ** to avoid having to call this routine too often */
   790    789         szNew += p->nChar;
   791    790       }
   792    791       if( szNew > p->mxAlloc ){
................................................................................
   820    819   ** Append N copies of character c to the given string buffer.
   821    820   */
   822    821   void sqlite3AppendChar(StrAccum *p, int N, char c){
   823    822     testcase( p->nChar + (i64)N > 0x7fffffff );
   824    823     if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
   825    824       return;
   826    825     }
   827         -  assert( (p->zText==p->zBase)==!isMalloced(p) );
   828    826     while( (N--)>0 ) p->zText[p->nChar++] = c;
   829    827   }
   830    828   
   831    829   /*
   832    830   ** The StrAccum "p" is not large enough to accept N new bytes of z[].
   833    831   ** So enlarge if first, then do the append.
   834    832   **
................................................................................
   838    836   */
   839    837   static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
   840    838     N = sqlite3StrAccumEnlarge(p, N);
   841    839     if( N>0 ){
   842    840       memcpy(&p->zText[p->nChar], z, N);
   843    841       p->nChar += N;
   844    842     }
   845         -  assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
   846    843   }
   847    844   
   848    845   /*
   849    846   ** Append N bytes of text from z to the StrAccum object.  Increase the
   850    847   ** size of the memory allocation for StrAccum if necessary.
   851    848   */
   852    849   void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
................................................................................
   873    870   
   874    871   /*
   875    872   ** Finish off a string by making sure it is zero-terminated.
   876    873   ** Return a pointer to the resulting string.  Return a NULL
   877    874   ** pointer if any kind of error was encountered.
   878    875   */
   879    876   static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
          877  +  char *zText;
   880    878     assert( p->mxAlloc>0 && !isMalloced(p) );
   881         -  p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
   882         -  if( p->zText ){
   883         -    memcpy(p->zText, p->zBase, p->nChar+1);
          879  +  zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
          880  +  if( zText ){
          881  +    memcpy(zText, p->zText, p->nChar+1);
   884    882       p->printfFlags |= SQLITE_PRINTF_MALLOCED;
   885    883     }else{
   886    884       setStrAccumError(p, STRACCUM_NOMEM);
   887    885     }
   888         -  return p->zText;
          886  +  p->zText = zText;
          887  +  return zText;
   889    888   }
   890    889   char *sqlite3StrAccumFinish(StrAccum *p){
   891    890     if( p->zText ){
   892         -    assert( (p->zText==p->zBase)==!isMalloced(p) );
   893    891       p->zText[p->nChar] = 0;
   894    892       if( p->mxAlloc>0 && !isMalloced(p) ){
   895    893         return strAccumFinishRealloc(p);
   896    894       }
   897    895     }
   898    896     return p->zText;
   899    897   }
   900    898   
   901    899   /*
   902    900   ** Reset an StrAccum string.  Reclaim all malloced memory.
   903    901   */
   904    902   void sqlite3StrAccumReset(StrAccum *p){
   905         -  assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
   906    903     if( isMalloced(p) ){
   907    904       sqlite3DbFree(p->db, p->zText);
   908    905       p->printfFlags &= ~SQLITE_PRINTF_MALLOCED;
   909    906     }
   910    907     p->zText = 0;
   911    908   }
   912    909   
................................................................................
   921    918   **        is malloced.
   922    919   ** n:     Size of zBase in bytes.  If total space requirements never exceed
   923    920   **        n then no memory allocations ever occur.
   924    921   ** mx:    Maximum number of bytes to accumulate.  If mx==0 then no memory
   925    922   **        allocations will ever occur.
   926    923   */
   927    924   void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
   928         -  p->zText = p->zBase = zBase;
          925  +  p->zText = zBase;
   929    926     p->db = db;
   930         -  p->nChar = 0;
   931    927     p->nAlloc = n;
   932    928     p->mxAlloc = mx;
          929  +  p->nChar = 0;
   933    930     p->accError = 0;
   934    931     p->printfFlags = 0;
   935    932   }
   936    933   
   937    934   /*
   938    935   ** Print into memory obtained from sqliteMalloc().  Use the internal
   939    936   ** %-conversion extensions.

Changes to src/select.c.

  1706   1706         /* If the column contains an "AS <name>" phrase, use <name> as the name */
  1707   1707       }else{
  1708   1708         Expr *pColExpr = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
  1709   1709         while( pColExpr->op==TK_DOT ){
  1710   1710           pColExpr = pColExpr->pRight;
  1711   1711           assert( pColExpr!=0 );
  1712   1712         }
  1713         -      if( pColExpr->op==TK_COLUMN && pColExpr->pTab!=0 ){
         1713  +      if( (pColExpr->op==TK_COLUMN || pColExpr->op==TK_AGG_COLUMN)
         1714  +       && pColExpr->pTab!=0 
         1715  +      ){
  1714   1716           /* For columns use the column name name */
  1715   1717           int iCol = pColExpr->iColumn;
  1716   1718           Table *pTab = pColExpr->pTab;
  1717   1719           if( iCol<0 ) iCol = pTab->iPKey;
  1718   1720           zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
  1719   1721         }else if( pColExpr->op==TK_ID ){
  1720   1722           assert( !ExprHasProperty(pColExpr, EP_IntValue) );

Changes to src/sqlite3ext.h.

   242    242     const char *(*errstr)(int);
   243    243     int (*stmt_busy)(sqlite3_stmt*);
   244    244     int (*stmt_readonly)(sqlite3_stmt*);
   245    245     int (*stricmp)(const char*,const char*);
   246    246     int (*uri_boolean)(const char*,const char*,int);
   247    247     sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
   248    248     const char *(*uri_parameter)(const char*,const char*);
   249         -  char *(*vsnprintf)(int,char*,const char*,va_list);
          249  +  char *(*xvsnprintf)(int,char*,const char*,va_list);
   250    250     int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
   251    251     /* Version 3.8.7 and later */
   252    252     int (*auto_extension)(void(*)(void));
   253    253     int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
   254    254                        void(*)(void*));
   255    255     int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
   256    256                         void(*)(void*),unsigned char);
................................................................................
   438    438   #define sqlite3_value_numeric_type     sqlite3_api->value_numeric_type
   439    439   #define sqlite3_value_text             sqlite3_api->value_text
   440    440   #define sqlite3_value_text16           sqlite3_api->value_text16
   441    441   #define sqlite3_value_text16be         sqlite3_api->value_text16be
   442    442   #define sqlite3_value_text16le         sqlite3_api->value_text16le
   443    443   #define sqlite3_value_type             sqlite3_api->value_type
   444    444   #define sqlite3_vmprintf               sqlite3_api->vmprintf
   445         -#define sqlite3_vsnprintf              sqlite3_api->vsnprintf
          445  +#define sqlite3_vsnprintf              sqlite3_api->xvsnprintf
   446    446   #define sqlite3_overload_function      sqlite3_api->overload_function
   447    447   #define sqlite3_prepare_v2             sqlite3_api->prepare_v2
   448    448   #define sqlite3_prepare16_v2           sqlite3_api->prepare16_v2
   449    449   #define sqlite3_clear_bindings         sqlite3_api->clear_bindings
   450    450   #define sqlite3_bind_zeroblob          sqlite3_api->bind_zeroblob
   451    451   #define sqlite3_blob_bytes             sqlite3_api->blob_bytes
   452    452   #define sqlite3_blob_close             sqlite3_api->blob_close
................................................................................
   514    514   #define sqlite3_errstr                 sqlite3_api->errstr
   515    515   #define sqlite3_stmt_busy              sqlite3_api->stmt_busy
   516    516   #define sqlite3_stmt_readonly          sqlite3_api->stmt_readonly
   517    517   #define sqlite3_stricmp                sqlite3_api->stricmp
   518    518   #define sqlite3_uri_boolean            sqlite3_api->uri_boolean
   519    519   #define sqlite3_uri_int64              sqlite3_api->uri_int64
   520    520   #define sqlite3_uri_parameter          sqlite3_api->uri_parameter
   521         -#define sqlite3_uri_vsnprintf          sqlite3_api->vsnprintf
          521  +#define sqlite3_uri_vsnprintf          sqlite3_api->xvsnprintf
   522    522   #define sqlite3_wal_checkpoint_v2      sqlite3_api->wal_checkpoint_v2
   523    523   /* Version 3.8.7 and later */
   524    524   #define sqlite3_auto_extension         sqlite3_api->auto_extension
   525    525   #define sqlite3_bind_blob64            sqlite3_api->bind_blob64
   526    526   #define sqlite3_bind_text64            sqlite3_api->bind_text64
   527    527   #define sqlite3_cancel_auto_extension  sqlite3_api->cancel_auto_extension
   528    528   #define sqlite3_load_extension         sqlite3_api->load_extension

Changes to src/sqliteInt.h.

  3225   3225   
  3226   3226   /*
  3227   3227   ** An objected used to accumulate the text of a string where we
  3228   3228   ** do not necessarily know how big the string will be in the end.
  3229   3229   */
  3230   3230   struct StrAccum {
  3231   3231     sqlite3 *db;         /* Optional database for lookaside.  Can be NULL */
  3232         -  char *zBase;         /* A base allocation.  Not from malloc. */
  3233   3232     char *zText;         /* The string collected so far */
  3234         -  u32  nChar;          /* Length of the string so far */
  3235   3233     u32  nAlloc;         /* Amount of space allocated in zText */
  3236   3234     u32  mxAlloc;        /* Maximum allowed allocation.  0 for no malloc usage */
         3235  +  u32  nChar;          /* Length of the string so far */
  3237   3236     u8   accError;       /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
  3238   3237     u8   printfFlags;    /* SQLITE_PRINTF flags below */
  3239   3238   };
  3240   3239   #define STRACCUM_NOMEM   1
  3241   3240   #define STRACCUM_TOOBIG  2
  3242   3241   #define SQLITE_PRINTF_INTERNAL 0x01  /* Internal-use-only converters allowed */
  3243   3242   #define SQLITE_PRINTF_SQLFUNC  0x02  /* SQL function arguments to VXPrintf */

Changes to src/test_tclvar.c.

    11     11   *************************************************************************
    12     12   ** Code for testing the virtual table interfaces.  This code
    13     13   ** is not included in the SQLite library.  It is used for automated
    14     14   ** testing of the SQLite library.
    15     15   **
    16     16   ** The emphasis of this file is a virtual table that provides
    17     17   ** access to TCL variables.
           18  +**
           19  +** The TCLVAR eponymous virtual table has a schema like this:
           20  +**
           21  +**    CREATE TABLE tclvar(
           22  +**       name TEXT,       -- base name of the variable:  "x" in "$x(y)"
           23  +**       arrayname TEXT,  -- array index name: "y" in "$x(y)"
           24  +**       value TEXT,      -- the value of the variable 
           25  +**       fullname TEXT,   -- the full name of the variable
           26  +**       PRIMARY KEY(fullname)
           27  +**    ) WITHOUT ROWID;
           28  +**
           29  +** DELETE, INSERT, and UPDATE operations use the "fullname" field to
           30  +** determine the variable to be modified.  Changing "value" to NULL
           31  +** deletes the variable.
           32  +**
           33  +** For SELECT operations, the "name" and "arrayname" fields will always
           34  +** match the "fullname" field.  For DELETE, INSERT, and UPDATE, the
           35  +** "name" and "arrayname" fields are ignored and the variable is modified
           36  +** according to "fullname" and "value" only.
    18     37   */
    19     38   #include "sqliteInt.h"
    20     39   #if defined(INCLUDE_SQLITE_TCL_H)
    21     40   #  include "sqlite_tcl.h"
    22     41   #else
    23     42   #  include "tcl.h"
    24     43   #endif
................................................................................
    63     82     void *pAux,
    64     83     int argc, const char *const*argv,
    65     84     sqlite3_vtab **ppVtab,
    66     85     char **pzErr
    67     86   ){
    68     87     tclvar_vtab *pVtab;
    69     88     static const char zSchema[] = 
    70         -     "CREATE TABLE whatever(name TEXT, arrayname TEXT, value TEXT)";
           89  +     "CREATE TABLE x("
           90  +     "  name TEXT,"                       /* Base name */
           91  +     "  arrayname TEXT,"                  /* Array index */
           92  +     "  value TEXT,"                      /* Value */
           93  +     "  fullname TEXT PRIMARY KEY"        /* base(index) name */
           94  +     ") WITHOUT ROWID";
    71     95     pVtab = sqlite3MallocZero( sizeof(*pVtab) );
    72     96     if( pVtab==0 ) return SQLITE_NOMEM;
    73     97     *ppVtab = &pVtab->base;
    74     98     pVtab->interp = (Tcl_Interp *)pAux;
    75     99     sqlite3_declare_vtab(db, zSchema);
    76    100     return SQLITE_OK;
    77    101   }
................................................................................
   247    271         break;
   248    272       }
   249    273       case 2: {
   250    274         Tcl_Obj *pVal = Tcl_GetVar2Ex(interp, z1, *z2?z2:0, TCL_GLOBAL_ONLY);
   251    275         sqlite3_result_text(ctx, Tcl_GetString(pVal), -1, SQLITE_TRANSIENT);
   252    276         break;
   253    277       }
          278  +    case 3: {
          279  +      char *z3;
          280  +      if( p2 ){
          281  +        z3 = sqlite3_mprintf("%s(%s)", z1, z2);
          282  +        sqlite3_result_text(ctx, z3, -1, sqlite3_free);
          283  +      }else{
          284  +        sqlite3_result_text(ctx, z1, -1, SQLITE_TRANSIENT);
          285  +      }
          286  +      break;
          287  +    }
   254    288     }
   255    289     return SQLITE_OK;
   256    290   }
   257    291   
   258    292   static int tclvarRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
   259    293     *pRowid = 0;
   260    294     return SQLITE_OK;
................................................................................
   371    405       }
   372    406     }
   373    407     pIdxInfo->idxStr = zStr;
   374    408     pIdxInfo->needToFreeIdxStr = 1;
   375    409   
   376    410     return SQLITE_OK;
   377    411   }
          412  +
          413  +/*
          414  +** Invoked for any UPDATE, INSERT, or DELETE against a tclvar table
          415  +*/
          416  +static int tclvarUpdate(
          417  +  sqlite3_vtab *tab,
          418  +  int argc,
          419  +  sqlite3_value **argv,
          420  +  sqlite_int64 *pRowid
          421  +){
          422  +  tclvar_vtab *pTab = (tclvar_vtab*)tab;
          423  +  if( argc==1 ){
          424  +    /* A DELETE operation.  The variable to be deleted is stored in argv[0] */
          425  +    const char *zVar = (const char*)sqlite3_value_text(argv[0]);
          426  +    Tcl_UnsetVar(pTab->interp, zVar, TCL_GLOBAL_ONLY);
          427  +    return SQLITE_OK;
          428  +  }
          429  +  if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
          430  +    /* An INSERT operation */
          431  +    const char *zValue = (const char*)sqlite3_value_text(argv[4]);
          432  +    const char *zName;
          433  +    if( sqlite3_value_type(argv[5])!=SQLITE_TEXT ){
          434  +      tab->zErrMsg = sqlite3_mprintf("the 'fullname' column must be TEXT");
          435  +      return SQLITE_ERROR;
          436  +    }
          437  +    zName = (const char*)sqlite3_value_text(argv[5]);
          438  +    if( zValue ){
          439  +      Tcl_SetVar(pTab->interp, zName, zValue, TCL_GLOBAL_ONLY);
          440  +    }else{
          441  +      Tcl_UnsetVar(pTab->interp, zName, TCL_GLOBAL_ONLY);
          442  +    }
          443  +    return SQLITE_OK;
          444  +  }
          445  +  if( sqlite3_value_type(argv[0])==SQLITE_TEXT
          446  +   && sqlite3_value_type(argv[1])==SQLITE_TEXT
          447  +  ){
          448  +    /* An UPDATE operation */
          449  +    const char *zOldName = (const char*)sqlite3_value_text(argv[0]);
          450  +    const char *zNewName = (const char*)sqlite3_value_text(argv[1]);
          451  +    const char *zValue = (const char*)sqlite3_value_text(argv[4]);
          452  +
          453  +    if( strcmp(zOldName, zNewName)!=0 || zValue==0 ){
          454  +      Tcl_UnsetVar(pTab->interp, zOldName, TCL_GLOBAL_ONLY);
          455  +    }
          456  +    if( zValue!=0 ){
          457  +      Tcl_SetVar(pTab->interp, zNewName, zValue, TCL_GLOBAL_ONLY);
          458  +    }
          459  +    return SQLITE_OK;
          460  +  }
          461  +  tab->zErrMsg = sqlite3_mprintf("prohibited TCL variable change");
          462  +  return SQLITE_ERROR;
          463  +}
   378    464   
   379    465   /*
   380    466   ** A virtual table module that provides read-only access to a
   381    467   ** Tcl global variable namespace.
   382    468   */
   383    469   static sqlite3_module tclvarModule = {
   384    470     0,                         /* iVersion */
................................................................................
   390    476     tclvarOpen,                  /* xOpen - open a cursor */
   391    477     tclvarClose,                 /* xClose - close a cursor */
   392    478     tclvarFilter,                /* xFilter - configure scan constraints */
   393    479     tclvarNext,                  /* xNext - advance a cursor */
   394    480     tclvarEof,                   /* xEof - check for end of scan */
   395    481     tclvarColumn,                /* xColumn - read data */
   396    482     tclvarRowid,                 /* xRowid - read data */
   397         -  0,                           /* xUpdate */
          483  +  tclvarUpdate,                /* xUpdate */
   398    484     0,                           /* xBegin */
   399    485     0,                           /* xSync */
   400    486     0,                           /* xCommit */
   401    487     0,                           /* xRollback */
   402    488     0,                           /* xFindMethod */
   403    489     0,                           /* xRename */
   404    490   };

Changes to src/update.c.

   799    799     regRowid = ++pParse->nMem;
   800    800   
   801    801     /* Start scanning the virtual table */
   802    802     pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
   803    803     if( pWInfo==0 ) return;
   804    804   
   805    805     /* Populate the argument registers. */
   806         -  sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
   807         -  if( pRowid ){
   808         -    sqlite3ExprCode(pParse, pRowid, regArg+1);
   809         -  }else{
   810         -    sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
   811         -  }
   812    806     for(i=0; i<pTab->nCol; i++){
   813    807       if( aXRef[i]>=0 ){
   814    808         sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
   815    809       }else{
   816    810         sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
   817    811       }
   818    812     }
          813  +  if( HasRowid(pTab) ){
          814  +    sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
          815  +    if( pRowid ){
          816  +      sqlite3ExprCode(pParse, pRowid, regArg+1);
          817  +    }else{
          818  +      sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
          819  +    }
          820  +  }else{
          821  +    Index *pPk;   /* PRIMARY KEY index */
          822  +    i16 iPk;      /* PRIMARY KEY column */
          823  +    pPk = sqlite3PrimaryKeyIndex(pTab);
          824  +    assert( pPk!=0 );
          825  +    assert( pPk->nKeyCol==1 );
          826  +    iPk = pPk->aiColumn[0];
          827  +    sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
          828  +    sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
          829  +  }
   819    830   
   820    831     bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
   821    832   
   822    833     if( bOnePass ){
   823    834       /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
   824    835       ** above. Also, if this is a top-level parse (not a trigger), clear the
   825    836       ** multi-write flag so that the VM does not open a statement journal */

Changes to src/vtab.c.

   640    640       sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
   641    641       rc = SQLITE_ERROR;
   642    642     }else{
   643    643       char *zErr = 0;
   644    644       rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
   645    645       if( rc!=SQLITE_OK ){
   646    646         sqlite3ErrorMsg(pParse, "%s", zErr);
          647  +      pParse->rc = rc;
   647    648       }
   648    649       sqlite3DbFree(db, zErr);
   649    650     }
   650    651   
   651    652     return rc;
   652    653   }
   653    654   /*
................................................................................
   768    769         Index *pIdx;
   769    770         pTab->aCol = pNew->aCol;
   770    771         pTab->nCol = pNew->nCol;
   771    772         pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
   772    773         pNew->nCol = 0;
   773    774         pNew->aCol = 0;
   774    775         assert( pTab->pIndex==0 );
   775         -      if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){
          776  +      assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 );
          777  +      if( !HasRowid(pNew)
          778  +       && pCtx->pVTable->pMod->pModule->xUpdate!=0
          779  +       && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1
          780  +      ){
          781  +        /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0)
          782  +        ** or else must have a single-column PRIMARY KEY */
   776    783           rc = SQLITE_ERROR;
   777    784         }
   778    785         pIdx = pNew->pIndex;
   779    786         if( pIdx ){
   780    787           assert( pIdx->pNext==0 );
   781    788           pTab->pIndex = pIdx;
   782    789           pNew->pIndex = 0;

Changes to src/whereexpr.c.

   190    190   static int isLikeOrGlob(
   191    191     Parse *pParse,    /* Parsing and code generating context */
   192    192     Expr *pExpr,      /* Test this expression */
   193    193     Expr **ppPrefix,  /* Pointer to TK_STRING expression with pattern prefix */
   194    194     int *pisComplete, /* True if the only wildcard is % in the last character */
   195    195     int *pnoCase      /* True if uppercase is equivalent to lowercase */
   196    196   ){
   197         -  const char *z = 0;         /* String on RHS of LIKE operator */
          197  +  const u8 *z = 0;         /* String on RHS of LIKE operator */
   198    198     Expr *pRight, *pLeft;      /* Right and left size of LIKE operator */
   199    199     ExprList *pList;           /* List of operands to the LIKE operator */
   200    200     int c;                     /* One character in z[] */
   201    201     int cnt;                   /* Number of non-wildcard prefix characters */
   202    202     char wc[4];                /* Wildcard characters */
   203    203     sqlite3 *db = pParse->db;  /* Database connection */
   204    204     sqlite3_value *pVal = 0;
................................................................................
   217    217     pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr);
   218    218     op = pRight->op;
   219    219     if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){
   220    220       Vdbe *pReprepare = pParse->pReprepare;
   221    221       int iCol = pRight->iColumn;
   222    222       pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB);
   223    223       if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
   224         -      z = (char *)sqlite3_value_text(pVal);
          224  +      z = sqlite3_value_text(pVal);
   225    225       }
   226    226       sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
   227    227       assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
   228    228     }else if( op==TK_STRING ){
   229         -    z = pRight->u.zToken;
          229  +    z = (u8*)pRight->u.zToken;
   230    230     }
   231    231     if( z ){
   232    232   
   233    233       /* If the RHS begins with a digit or a minus sign, then the LHS must
   234    234       ** be an ordinary column (not a virtual table column) with TEXT affinity.
   235    235       ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false
   236    236       ** even though "lhs LIKE rhs" is true.  But if the RHS does not start
................................................................................
   247    247         }
   248    248       }
   249    249   
   250    250       /* Count the number of prefix characters prior to the first wildcard */
   251    251       cnt = 0;
   252    252       while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
   253    253         cnt++;
   254         -      if( c==wc[3] && z[cnt]!=0 ){
   255         -        if( z[cnt++]>0xc0 ) while( (z[cnt]&0xc0)==0x80 ){ cnt++; }
   256         -      }
          254  +      if( c==wc[3] && z[cnt]!=0 ) cnt++;
   257    255       }
   258    256   
   259    257       /* The optimization is possible only if (1) the pattern does not begin
   260    258       ** with a wildcard and if (2) the non-wildcard prefix does not end with
   261    259       ** an (illegal 0xff) character.  The second condition is necessary so
   262    260       ** that we can increment the prefix key to find an upper bound for the
   263    261       ** range search. 
................................................................................
   265    263       if( cnt!=0 && 255!=(u8)z[cnt-1] ){
   266    264         Expr *pPrefix;
   267    265   
   268    266         /* A "complete" match if the pattern ends with "*" or "%" */
   269    267         *pisComplete = c==wc[0] && z[cnt+1]==0;
   270    268   
   271    269         /* Get the pattern prefix.  Remove all escapes from the prefix. */
   272         -      pPrefix = sqlite3Expr(db, TK_STRING, z);
          270  +      pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
   273    271         if( pPrefix ){
   274    272           int iFrom, iTo;
   275    273           char *zNew = pPrefix->u.zToken;
   276    274           zNew[cnt] = 0;
   277    275           for(iFrom=iTo=0; iFrom<cnt; iFrom++){
   278    276             if( zNew[iFrom]==wc[3] ) iFrom++;
   279    277             zNew[iTo++] = zNew[iFrom];

Added test/bigmmap.test.

            1  +# 2017 August 07
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this script testing the ability of SQLite to use mmap
           13  +# to access files larger than 4GiB.
           14  +#
           15  +
           16  +if {[file exists skip-big-file]} return
           17  +if {$tcl_platform(os)=="Darwin"} return
           18  +
           19  +set testdir [file dirname $argv0]
           20  +source $testdir/tester.tcl
           21  +set testprefix bigmmap
           22  +
           23  +ifcapable !mmap {
           24  +  finish_test
           25  +  return
           26  +}
           27  +
           28  +set mmap_limit 0
           29  +db eval { 
           30  +  SELECT compile_options AS x FROM pragma_compile_options 
           31  +  WHERE x LIKE 'max_mmap_size=%' 
           32  +} {
           33  +  regexp {MAX_MMAP_SIZE=([0-9]*)} $x -> mmap_limit
           34  +}
           35  +if {$mmap_limit < [expr 8 * 1<<30]} {
           36  +  puts "Skipping bigmmap.test - requires SQLITE_MAX_MMAP_SIZE >= 8G"
           37  +  finish_test
           38  +  return
           39  +}
           40  +
           41  +
           42  +#-------------------------------------------------------------------------
           43  +# Create the database file roughly 8GiB in size. Most pages are unused,
           44  +# except that there is a table and index clustered around each 1GiB
           45  +# boundary.
           46  +#
           47  +do_execsql_test 1.0 {
           48  +  PRAGMA page_size = 4096;
           49  +  CREATE TABLE t0(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
           50  +  WITH  s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 )
           51  +  INSERT INTO t0 SELECT i, 't0', randomblob(800) FROM s;
           52  +}
           53  +
           54  +for {set i 1} {$i < 8} {incr i} {
           55  +  fake_big_file [expr $i*1024] [get_pwd]/test.db
           56  +  hexio_write test.db 28 [format %.8x [expr ($i*1024*1024*1024/4096) - 5]]
           57  +
           58  +  do_execsql_test 1.$i "
           59  +    CREATE TABLE t$i (a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
           60  +    WITH  s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 )
           61  +      INSERT INTO t$i SELECT i, 't$i', randomblob(800) FROM s;
           62  +  "
           63  +}
           64  +
           65  +#-------------------------------------------------------------------------
           66  +# Check that data can be retrieved from the db with a variety of 
           67  +# configured mmap size limits.
           68  +#
           69  +for {set i 0} {$i < 9} {incr i} {
           70  +
           71  +  # Configure a memory mapping $i GB in size.
           72  +  #
           73  +  set val [expr $i*1024*1024*1024]
           74  +  execsql "PRAGMA main.mmap_size = $val"
           75  +  do_execsql_test 2.$i.0 {
           76  +    PRAGMA main.mmap_size
           77  +  } $val
           78  +
           79  +  for {set t 0} {$t < 8} {incr t} {
           80  +    do_execsql_test 2.$i.$t.1 "
           81  +      SELECT count(*) FROM t$t;
           82  +      SELECT count(b || c) FROM t$t GROUP BY b;
           83  +    " {100 100}
           84  +  
           85  +    do_execsql_test 2.$i.$t.2 "
           86  +      SELECT * FROM t$t AS o WHERE 
           87  +        NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
           88  +      ORDER BY b, c;
           89  +    " {}
           90  +    
           91  +    do_eqp_test 2.$i.$t.3 "
           92  +      SELECT * FROM t$t AS o WHERE 
           93  +        NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
           94  +      ORDER BY b, c;
           95  +    " "
           96  +      0 0 0 {SCAN TABLE t$t AS o USING COVERING INDEX sqlite_autoindex_t${t}_1}
           97  +      0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1}
           98  +      1 0 0 {SEARCH TABLE t$t AS i USING INTEGER PRIMARY KEY (rowid=?)}
           99  +    "
          100  +  }
          101  +}
          102  +
          103  +finish_test
          104  +

Changes to test/colname.test.

   373    373   } {a 1 n 3}
   374    374   do_test colname-9.211 {
   375    375     execsql2 {SELECT t1.a AS n, v3.a FROM t1 JOIN v3}
   376    376   } {n 1 a 3}
   377    377   do_test colname-9.210 {
   378    378     execsql2 {SELECT t1.a, v3.a AS n FROM t1 JOIN v3}
   379    379   } {a 1 n 3}
          380  +
          381  +# Make sure the quotation marks get removed from the column names
          382  +# when constructing a new table from an aggregate SELECT.
          383  +# Email from Juergen Palm on 2017-07-11.
          384  +#
          385  +do_execsql_test colname-10.100 {
          386  +  DROP TABLE IF EXISTS t1;
          387  +  CREATE TABLE t1("with space" TEXT);
          388  +  DROP TABLE IF EXISTS t2;
          389  +  CREATE TABLE t2 AS SELECT "with space" FROM t1;
          390  +  PRAGMA table_info(t2);
          391  +} {0 {with space} TEXT 0 {} 0}
          392  +do_execsql_test colname-10.110 {
          393  +  DROP TABLE IF EXISTS t3;
          394  +  CREATE TABLE t3 AS SELECT "with space" FROM t1 GROUP BY 1;
          395  +  PRAGMA table_info(t3);
          396  +} {0 {with space} TEXT 0 {} 0}
   380    397   
   381    398   
   382    399   finish_test

Changes to test/csv01.test.

    89     89   } {5 9}
    90     90   
    91     91   # The rowid column is not visible on a WITHOUT ROWID virtual table
    92     92   do_catchsql_test 3.2 {
    93     93     SELECT rowid, a FROM t3;
    94     94   } {1 {no such column: rowid}}
    95     95   
           96  +# Multi-column WITHOUT ROWID virtual tables may not be writable.
    96     97   do_catchsql_test 4.0 {
    97     98     DROP TABLE t3;
    98     99     CREATE VIRTUAL TABLE temp.t4 USING csv_wr(
    99    100       data=
   100    101   '1,2,3,4
   101    102   5,6,7,8
   102    103   9,10,11,12
   103         -13,14,15,16
   104         -',
          104  +13,14,15,16',
   105    105       columns=4,
   106    106       schema=
   107         -      'CREATE TABLE t3(a PRIMARY KEY,b TEXT,c TEXT,d TEXT) WITHOUT ROWID',
          107  +      'CREATE TABLE t3(a,b,c,d,PRIMARY KEY(a,b)) WITHOUT ROWID',
   108    108       testflags=1
   109    109     );
   110    110   } {1 {vtable constructor failed: t4}}
          111  +
          112  +# WITHOUT ROWID tables with a single-column PRIMARY KEY may be writable.
          113  +do_catchsql_test 4.1 {
          114  +  DROP TABLE IF EXISTS t4;
          115  +  CREATE VIRTUAL TABLE temp.t4 USING csv_wr(
          116  +    data=
          117  +'1,2,3,4
          118  +5,6,7,8
          119  +9,10,11,12
          120  +13,14,15,16',
          121  +    columns=4,
          122  +    schema=
          123  +      'CREATE TABLE t3(a,b,c,d,PRIMARY KEY(b)) WITHOUT ROWID',
          124  +    testflags=1
          125  +  );
          126  +} {0 {}}
          127  +
          128  +do_catchsql_test 4.2 {
          129  +  DROP TABLE IF EXISTS t5;
          130  +  CREATE VIRTUAL TABLE temp.t5 USING csv_wr(
          131  +      data=
          132  +      '1,2,3,4
          133  +      5,6,7,8
          134  +      9,10,11,12
          135  +      13,14,15,16',
          136  +      columns=4,
          137  +      schema=
          138  +      'CREATE TABLE t3(a,b,c,d) WITHOUT ROWID',
          139  +      testflags=1
          140  +      );
          141  +} {1 {vtable constructor failed: t5}}
          142  +
   111    143   
   112    144   finish_test

Changes to test/swarmvtab.test.

   234    234       'VALUES
   235    235           ("test.db1", "t1", 1, 10),
   236    236           ("test.db2", "t1", 11, 20)
   237    237       ', 'fetch_db'
   238    238     );
   239    239   } {}
   240    240   
   241         -do_catchsql_test 3.3 { SELECT * FROM xyz } {1 {fetch_db error!}}
          241  +do_catchsql_test 3.3.2 { SELECT * FROM xyz } {1 {fetch_db error!}}
   242    242   
   243    243   
   244    244   
   245    245   finish_test
   246    246   

Changes to test/vtab2.test.

    56     56   } {6}
    57     57   
    58     58   register_tclvar_module [sqlite3_connection_pointer db]
    59     59   do_test vtab2-2.1 {
    60     60     set ::abc 123
    61     61     execsql {
    62     62       CREATE VIRTUAL TABLE vars USING tclvar;
    63         -    SELECT * FROM vars WHERE name='abc';
           63  +    SELECT name, arrayname, value FROM vars WHERE name='abc';
    64     64     }
    65     65   } [list abc "" 123]
    66     66   do_test vtab2-2.2 {
    67     67     set A(1) 1
    68     68     set A(2) 4
    69     69     set A(3) 9
    70     70     execsql {
    71         -    SELECT * FROM vars WHERE name='A';
           71  +    SELECT name, arrayname, value FROM vars WHERE name='A';
    72     72     }
    73     73   } [list A 1 1 A 2 4 A 3 9]
    74     74   unset -nocomplain result
    75     75   unset -nocomplain var
    76     76   set result {}
    77     77   foreach var [lsort [info vars tcl_*]] {
    78     78     catch {lappend result $var [set $var]}

Changes to test/vtabE.test.

    35     35   set vtabE2(c) d
    36     36   
    37     37   do_test vtabE-1 {
    38     38     db eval {
    39     39       CREATE VIRTUAL TABLE t1 USING tclvar;
    40     40       CREATE VIRTUAL TABLE t2 USING tclvar;
    41     41       CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
    42         -    SELECT t1.*, t2.*, abs(t3.b + abs(t2.value + abs(t1.value)))
           42  +    SELECT t1.name, t1.arrayname, t1.value,
           43  +           t2.name, t2.arrayname, t2.value,
           44  +           abs(t3.b + abs(t2.value + abs(t1.value)))
    43     45         FROM t1 LEFT JOIN t2 ON t2.name = t1.arrayname
    44     46              LEFT JOIN t3 ON t3.a=t2.value
    45     47        WHERE t1.name = 'vtabE'
    46     48        ORDER BY t1.value, t2.value;
    47     49     }
    48     50   } {vtabE vtabE1 11 vtabE1 w x {} vtabE vtabE1 11 vtabE1 y z {} vtabE vtabE2 22 vtabE2 a b {} vtabE vtabE2 22 vtabE2 c d {}}
    49     51   
    50     52   finish_test

Changes to test/vtabH.test.

    51     51   
    52     52   #--------------------------------------------------------------------------
    53     53   
    54     54   register_tclvar_module db
    55     55   set ::xyz 10
    56     56   do_execsql_test 2.0 {
    57     57     CREATE VIRTUAL TABLE vars USING tclvar;
    58         -  SELECT * FROM vars WHERE name = 'xyz';
           58  +  SELECT name, arrayname, value FROM vars WHERE name = 'xyz';
    59     59   } {xyz {} 10}
    60     60   
    61     61   set x1 aback
    62     62   set x2 abaft
    63     63   set x3 abandon
    64     64   set x4 abandonint
    65     65   set x5 babble

Added test/vtabJ.test.

            1  +# 2017-08-10
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements tests of writing to WITHOUT ROWID virtual tables
           12  +# using the tclvar eponymous virtual table.
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +set testprefix vtabJ
           18  +
           19  +ifcapable !vtab {
           20  +  finish_test
           21  +  return
           22  +}
           23  +
           24  +register_tclvar_module db
           25  +
           26  +unset -nocomplain vtabJ
           27  +do_test 100 {
           28  +  set vtabJ(1) this
           29  +  set vtabJ(two) is
           30  +  set vtabJ(3) {a test}
           31  +  db eval {
           32  +    SELECT fullname, value FROM tclvar WHERE name='vtabJ' ORDER BY fullname;
           33  +  }
           34  +} {vtabJ(1) this vtabJ(3) {a test} vtabJ(two) is}
           35  +
           36  +do_execsql_test 110 {
           37  +  INSERT INTO tclvar(fullname, value)
           38  +    VALUES('vtabJ(4)',4),('vtabJ(five)',555);
           39  +  SELECT fullname, value FROM tclvar WHERE name='vtabJ' ORDER BY fullname;
           40  +} {vtabJ(1) this vtabJ(3) {a test} vtabJ(4) 4 vtabJ(five) 555 vtabJ(two) is}
           41  +do_test 111 {
           42  +  set res {}
           43  +  foreach vname [lsort [array names vtabJ]] {
           44  +    lappend res vtabJ($vname) $vtabJ($vname)
           45  +  }
           46  +  set res
           47  +} {vtabJ(1) this vtabJ(3) {a test} vtabJ(4) 4 vtabJ(five) 555 vtabJ(two) is}
           48  +
           49  +do_test 120 {
           50  +  db eval {
           51  +    INSERT INTO tclvar(fullname, value) VALUES('vtabJ(4)',444);
           52  +  }
           53  +  set vtabJ(4)
           54  +} {444}
           55  +
           56  +do_test 130 {
           57  +  db eval {
           58  +    INSERT INTO tclvar(fullname, value) VALUES('vtabJ(4)',NULL);
           59  +  }
           60  +  info exists vtabJ(4)
           61  +} {0}
           62  +
           63  +do_test 140 {
           64  +  db eval {
           65  +    UPDATE tclvar SET value=55 WHERE fullname='vtabJ(five)';
           66  +  }
           67  +  set vtabJ(five)
           68  +} {55}
           69  +
           70  +do_test 150 {
           71  +  db eval {
           72  +    UPDATE tclvar SET fullname='vtabJ(5)' WHERE fullname='vtabJ(five)';
           73  +  }
           74  +  set vtabJ(5)
           75  +} {55}
           76  +do_test 151 {
           77  +  info exists vtabJ(five)
           78  +} {0}
           79  +do_test 152 {
           80  +  set res {}
           81  +  foreach vname [lsort [array names vtabJ]] {
           82  +    lappend res vtabJ($vname) $vtabJ($vname)
           83  +  }
           84  +  set res
           85  +} {vtabJ(1) this vtabJ(3) {a test} vtabJ(5) 55 vtabJ(two) is}
           86  +
           87  +do_execsql_test 160 {
           88  +  SELECT fullname FROM tclvar WHERE arrayname='two'
           89  +} {vtabJ(two)}
           90  +do_execsql_test 161 {
           91  +  DELETE FROM tclvar WHERE arrayname='two';
           92  +  SELECT fullname, value FROM tclvar WHERE name='vtabJ' ORDER BY fullname;
           93  +} {vtabJ(1) this vtabJ(3) {a test} vtabJ(5) 55}
           94  +do_test 162 {
           95  +  set res {}
           96  +  foreach vname [lsort [array names vtabJ]] {
           97  +    lappend res vtabJ($vname) $vtabJ($vname)
           98  +  }
           99  +  set res
          100  +} {vtabJ(1) this vtabJ(3) {a test} vtabJ(5) 55}
          101  +
          102  +# Try to trick the module into updating the same variable twice for a
          103  +# single UPDATE statement.
          104  +#
          105  +do_execsql_test 171 {
          106  +  INSERT INTO tclvar(fullname, value) VALUES('xx', 'a');
          107  +  SELECT name, value FROM tclvar where name = 'xx';
          108  +} {xx a}
          109  +do_execsql_test 172 {
          110  +  UPDATE tclvar SET value = value || 't' 
          111  +  WHERE name = 'xx' OR name = 'x'||'x';
          112  +  SELECT name, value FROM tclvar where name = 'xx';
          113  +} {xx at}
          114  +do_execsql_test 173 {
          115  +  UPDATE tclvar SET value = value || 't' 
          116  +  WHERE name = 'xx' OR name BETWEEN 'xx' AND 'xx';
          117  +  SELECT name, value FROM tclvar where name = 'xx';
          118  +} {xx att}
          119  +
          120  +do_execsql_test 181 {
          121  +  DELETE FROM tclvar WHERE name BETWEEN 'xx' AND 'xx' OR name='xx';
          122  +  SELECT name, value FROM tclvar where name = 'xx';
          123  +} {}
          124  +
          125  +
          126  +finish_test

Changes to tool/speed-check.sh.

   143    143   else
   144    144     ./speedtest1 speedtest1.db $SPEEDTEST_OPTS 2>&1 | tee -a summary-$NAME.txt
   145    145   fi
   146    146   size sqlite3.o | tee -a summary-$NAME.txt
   147    147   wc sqlite3.c
   148    148   if test $doCachegrind -eq 1; then
   149    149     cg_anno.tcl cachegrind.out.* >cout-$NAME.txt
          150  +  echo '*****************************************************' >>cout-$NAME.txt
          151  +  sed 's/^[0-9=-]\{9\}/==00000==/' summary-$NAME.txt >>cout-$NAME.txt
   150    152   fi
   151    153   if test $doExplain -eq 1; then
   152    154     ./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt
   153    155   fi
   154    156   if test "$NAME" != "trunk"; then
   155    157     fossil test-diff --tk -c 20 cout-trunk.txt cout-$NAME.txt
   156    158   fi