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

Overview
Comment:Add experimental sqlite_kvstore table. Currently read-only.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c13692183a5ea0526e6e1b0f5aa6b48127c62957
User & Date: dan 2013-07-30 20:01:49.913
Context
2013-07-30
20:27
Combine the OP_MakeIdxKey and OP_MakeKey opcodes into a single OP_MakeKey that does the work of both. Standardize the parameter meanings on OP_MakeRecord and OP_MakeKey. Remove the unused OP_Seek opcode. Other related code simplifications and cleanup. check-in: ed5d6992cd user: drh tags: trunk
20:01
Add experimental sqlite_kvstore table. Currently read-only. check-in: c13692183a user: dan tags: trunk
16:57
Remove an unnecessary function call in lsm_sorted.c slowing down xNext() operations. check-in: 48d0585fff user: dan tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/build.c.
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    Schema *pSchema;
    HashElem *p;
    int maxTab = 1;

    pSchema = pParse->db->aDb[iDb].pSchema;
    for(p=sqliteHashFirst(&pSchema->idxHash); p;p=sqliteHashNext(p)){
      Index *pIdx = (Index*)sqliteHashData(p);
      if( pIdx->tnum > maxTab ) maxTab = pIdx->tnum;
    }

    pParse->iNewidxReg = ++pParse->nMem;
    sqlite4VdbeAddOp2(v, OP_Integer, maxTab, pParse->iNewidxReg);
  }

  sqlite4VdbeAddOp2(v, OP_NewIdxid, pParse->iNewidxReg, iDb);







|







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    Schema *pSchema;
    HashElem *p;
    int maxTab = 1;

    pSchema = pParse->db->aDb[iDb].pSchema;
    for(p=sqliteHashFirst(&pSchema->idxHash); p;p=sqliteHashNext(p)){
      Index *pIdx = (Index*)sqliteHashData(p);
      if( pIdx->tnum!=KVSTORE_ROOT && pIdx->tnum > maxTab ) maxTab = pIdx->tnum;
    }

    pParse->iNewidxReg = ++pParse->nMem;
    sqlite4VdbeAddOp2(v, OP_Integer, maxTab, pParse->iNewidxReg);
  }

  sqlite4VdbeAddOp2(v, OP_NewIdxid, pParse->iNewidxReg, iDb);
Changes to src/expr.c.
2174
2175
2176
2177
2178
2179
2180




2181
2182
2183
2184
2185
2186
2187
  Table *pTab,    /* The table containing the value */
  int iTabCur,    /* The cursor for this table */
  int iCol,       /* Index of the column to extract */
  int regOut      /* Extract the valud into this register */
){
  if( iCol<0 ){
    sqlite4VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);




  }else{
    int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
    sqlite4VdbeAddOp3(v, op, iTabCur, iCol, regOut);
  }
  if( iCol>=0 ){
    sqlite4ColumnDefault(v, pTab, iCol, regOut);
  }







>
>
>
>







2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
  Table *pTab,    /* The table containing the value */
  int iTabCur,    /* The cursor for this table */
  int iCol,       /* Index of the column to extract */
  int regOut      /* Extract the valud into this register */
){
  if( iCol<0 ){
    sqlite4VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
  }else if( IsKvstore(pTab) ){
    int aOp[2] = { OP_RowKey, OP_RowData };
    assert( iCol==0 || iCol==1 );
    sqlite4VdbeAddOp2(v, aOp[iCol], iTabCur, regOut);
  }else{
    int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
    sqlite4VdbeAddOp3(v, op, iTabCur, iCol, regOut);
  }
  if( iCol>=0 ){
    sqlite4ColumnDefault(v, pTab, iCol, regOut);
  }
Changes to src/pragma.c.
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
        Table *pTab = (Table *)sqliteHashData(x);
        int addrRewind;
        int nIdx = 0;
        int iPkCsr;
        Index *pPk;
        int iCsr;

        /* Do nothing for views */
        if( IsView(pTab) ) continue;

        /* Open all indexes for table pTab. */
        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
          if( pIdx->eIndexType==SQLITE4_INDEX_PRIMARYKEY ){
            pPk = pIdx;
            iPkCsr = nIdx+baseCsr;
          }







|
|







713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
        Table *pTab = (Table *)sqliteHashData(x);
        int addrRewind;
        int nIdx = 0;
        int iPkCsr;
        Index *pPk;
        int iCsr;

        /* Do nothing for views or sqlite_kvstore */
        if( IsView(pTab) || IsKvstore(pTab) ) continue;

        /* Open all indexes for table pTab. */
        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
          if( pIdx->eIndexType==SQLITE4_INDEX_PRIMARYKEY ){
            pPk = pIdx;
            iPkCsr = nIdx+baseCsr;
          }
Changes to src/prepare.c.
155
156
157
158
159
160
161















162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202










203
204


205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

220
221
222
223
224
225
226

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
          sqlite4_value_text(apVal[2], 0)     /* Text of CREATE statement */
      );
    }
  }

  return 0;
}
















/*
** Attempt to read the database schema and initialize internal
** data structures for a single database file.  The index of the
** database file is given by iDb.  iDb==0 is used for the main
** database.  iDb==1 should never be used.  iDb>=2 is used for
** auxiliary databases.  Return one of the SQLITE4_ error codes to
** indicate success or failure.
*/
static int sqlite4InitOne(sqlite4 *db, int iDb, char **pzErrMsg){
  int rc;
  Table *pTab;
  Db *pDb;
  InitData initData;
  char const *zMasterSchema;
  char const *zMasterName;

  int openedTransaction = 0;

  /*
  ** The master database table has a structure like this
  */
  static const char master_schema[] = 
     "CREATE TABLE sqlite_master(\n"
     "  type text,\n"
     "  name text,\n"
     "  tbl_name text,\n"
     "  rootpage integer,\n"
     "  sql text\n"
     ")"
  ;
#ifndef SQLITE4_OMIT_TEMPDB
  static const char temp_master_schema[] = 
     "CREATE TEMP TABLE sqlite_temp_master(\n"
     "  type text,\n"
     "  name text,\n"
     "  tbl_name text,\n"
     "  rootpage integer,\n"
     "  sql text\n"
     ")"
  ;
#else










  #define temp_master_schema 0
#endif



  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pSchema );
  assert( sqlite4_mutex_held(db->mutex) );

  /* zMasterSchema and zInitScript are set to point at the master schema
  ** and initialisation script appropriate for the database being
  ** initialised. zMasterName is the name of the master table.
  */
  if( !OMIT_TEMPDB && iDb==1 ){
    zMasterSchema = temp_master_schema;
  }else{
    zMasterSchema = master_schema;
  }
  zMasterName = SCHEMA_TABLE(iDb);


  /* Construct the schema tables.  */
  initData.db = db;
  initData.iDb = iDb;
  initData.rc = SQLITE4_OK;
  initData.pzErrMsg = pzErrMsg;
  initCallback(&initData, zMasterName, 1, zMasterSchema);

  if( initData.rc ){
    rc = initData.rc;
    goto error_out;
  }
  pTab = sqlite4FindTable(db, zMasterName, db->aDb[iDb].zName);
  if( ALWAYS(pTab) ){
    pTab->tabFlags |= TF_Readonly;
  }

  /* Create a cursor to hold the database open
  */
  pDb = &db->aDb[iDb];
  if( pDb->pKV==0 ){
    if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
      DbSetProperty(db, 1, DB_SchemaLoaded);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
















>


<
<
<
|






|
<

<







<
|
>
>
>
>
>
>
>
>
>
>
|

>
>





<
<
|
<
<
<
<
<
<

>






|
>
|



<
<
<
<







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195



196
197
198
199
200
201
202
203

204

205
206
207
208
209
210
211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231


232






233
234
235
236
237
238
239
240
241
242
243
244
245
246




247
248
249
250
251
252
253
          sqlite4_value_text(apVal[2], 0)     /* Text of CREATE statement */
      );
    }
  }

  return 0;
}

static int createSchemaTable(
  InitData *pInit,
  const char *zName,
  i64 iRoot,
  const char *zSchema
){
  Table *pTab;
  initCallback(pInit, zName, iRoot, zSchema);
  if( pInit->rc ) return 1;
  pTab = sqlite4FindTable(pInit->db, zName, pInit->db->aDb[pInit->iDb].zName);
  if( ALWAYS(pTab) ) pTab->tabFlags |= TF_Readonly;
  return 0;
}


/*
** Attempt to read the database schema and initialize internal
** data structures for a single database file.  The index of the
** database file is given by iDb.  iDb==0 is used for the main
** database.  iDb==1 should never be used.  iDb>=2 is used for
** auxiliary databases.  Return one of the SQLITE4_ error codes to
** indicate success or failure.
*/
static int sqlite4InitOne(sqlite4 *db, int iDb, char **pzErrMsg){
  int rc;
  Table *pTab;
  Db *pDb;
  InitData initData;
  char const *zMasterSchema;
  char const *zMasterName;
  char const *zKvstoreName;
  int openedTransaction = 0;




  static const char *aMaster[] = {
     "CREATE TABLE sqlite_master(\n"
     "  type text,\n"
     "  name text,\n"
     "  tbl_name text,\n"
     "  rootpage integer,\n"
     "  sql text\n"
     ")", 

#ifndef SQLITE4_OMIT_TEMPDB

     "CREATE TEMP TABLE sqlite_temp_master(\n"
     "  type text,\n"
     "  name text,\n"
     "  tbl_name text,\n"
     "  rootpage integer,\n"
     "  sql text\n"
     ")"

#endif
  };
  static const char *aKvstore[] = {
     "CREATE TABLE sqlite_kvstore(key BLOB PRIMARY KEY, value BLOB)",
#ifndef SQLITE4_OMIT_TEMPDB
     "CREATE TABLE sqlite_temp_kvstore(key BLOB PRIMARY KEY, value BLOB)"
#endif
  };
  static const char *aKvstoreName[] = {
     "sqlite_kvstore",
#ifndef SQLITE4_OMIT_TEMPDB
     "sqlite_temp_kvstore"
#endif
  };


  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pSchema );
  assert( sqlite4_mutex_held(db->mutex) );



  /* zMasterName is the name of the master table.  */






  zMasterName = SCHEMA_TABLE(iDb);
  zKvstoreName = aKvstoreName[iDb==1];

  /* Construct the schema tables.  */
  initData.db = db;
  initData.iDb = iDb;
  initData.rc = SQLITE4_OK;
  initData.pzErrMsg = pzErrMsg;
  if( createSchemaTable(&initData, zMasterName, 1, aMaster[iDb==1])
   || createSchemaTable(&initData, zKvstoreName, KVSTORE_ROOT, aKvstore[iDb==1])
  ){
    rc = initData.rc;
    goto error_out;
  }





  /* Create a cursor to hold the database open
  */
  pDb = &db->aDb[iDb];
  if( pDb->pKV==0 ){
    if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
      DbSetProperty(db, 1, DB_SchemaLoaded);
Changes to src/sqliteInt.h.
521
522
523
524
525
526
527



528
529
530
531
532
533
534
#define MASTER_NAME       "sqlite_master"
#define TEMP_MASTER_NAME  "sqlite_temp_master"

/*
** The root-page of the master database table.
*/
#define MASTER_ROOT       1




/*
** The name of the schema table.
*/
#define SCHEMA_TABLE(x)  ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME)

/*







>
>
>







521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
#define MASTER_NAME       "sqlite_master"
#define TEMP_MASTER_NAME  "sqlite_temp_master"

/*
** The root-page of the master database table.
*/
#define MASTER_ROOT       1
#define KVSTORE_ROOT      0x7fffffff

#define IsKvstore(pTab) ((pTab)->pIndex && (pTab)->pIndex->tnum==KVSTORE_ROOT)

/*
** The name of the schema table.
*/
#define SCHEMA_TABLE(x)  ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME)

/*
Changes to src/vdbe.c.
2110
2111
2112
2113
2114
2115
2116

2117
2118
2119
2120
2121
2122
2123
  p1 = pOp->p1;
  assert( p1<p->nCursor );
  assert( pOp->p3>0 && pOp->p3<=p->nMem );
  pDest = &aMem[pOp->p3];
  memAboutToChange(p, pDest);
  pC = p->apCsr[p1];
  assert( pC!=0 );

#ifndef SQLITE4_OMIT_VIRTUALTABLE
  assert( pC->pVtabCursor==0 );
#endif
  if( pC->pDecoder==0 ){
    mxField = pC->nField;
    if( pC->pKeyInfo && pC->pKeyInfo->nData ) mxField = pC->pKeyInfo->nData;
    rc = sqlite4VdbeDecoderCreate(db, pC, 0, mxField, &pC->pDecoder);







>







2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
  p1 = pOp->p1;
  assert( p1<p->nCursor );
  assert( pOp->p3>0 && pOp->p3<=p->nMem );
  pDest = &aMem[pOp->p3];
  memAboutToChange(p, pDest);
  pC = p->apCsr[p1];
  assert( pC!=0 );
  assert( pC->iRoot!=KVSTORE_ROOT );
#ifndef SQLITE4_OMIT_VIRTUALTABLE
  assert( pC->pVtabCursor==0 );
#endif
  if( pC->pDecoder==0 ){
    mxField = pC->nField;
    if( pC->pKeyInfo && pC->pKeyInfo->nData ) mxField = pC->pKeyInfo->nData;
    rc = sqlite4VdbeDecoderCreate(db, pC, 0, mxField, &pC->pDecoder);
2946
2947
2948
2949
2950
2951
2952




2953
2954
2955
2956
2957
2958

2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975






2976
2977
2978
2979
2980
2981
2982
2983
2984
2985

2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998




2999
3000
3001
3002
3003
3004
3005
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pOp->p2!=0 );
  assert( pC!=0 );
  assert( OP_SeekLe == OP_SeekLt+1 );
  assert( OP_SeekGe == OP_SeekLt+2 );
  assert( OP_SeekGt == OP_SeekLt+3 );





  /* Encode a database key consisting of the contents of the P4 registers
  ** starting at register P3. Have the vdbecodec module allocate an extra
  ** free byte at the end of the database key (see below).  */
  op = pOp->opcode;
  nField = pOp->p4.i;
  pIn3 = &aMem[pOp->p3];

  rc = sqlite4VdbeEncodeKey(
      db, pIn3, nField, nField+(pOp->p5 & OPFLAG_PARTIALKEY),
      pC->iRoot, pC->pKeyInfo, &aProbe, &nProbe, 1
  );

  /*   Opcode    search-dir    increment-key
  **  --------------------------------------
  **   SeekLt    -1            no
  **   SeekLe    -1            yes
  **   SeekGe    +1            no
  **   SeekGt    +1            yes
  */
  dir = +1;
  if( op==OP_SeekLe || op==OP_SeekLt ) dir = -1;
  if( op==OP_SeekLe || op==OP_SeekGt ) aProbe[nProbe++] = 0xFF;
  if( rc==SQLITE4_OK ){
    rc = sqlite4KVCursorSeek(pC->pKVCur, aProbe, nProbe, dir);






  }

  if( rc==SQLITE4_OK ){
    if( op==OP_SeekLt ){
      rc = sqlite4KVCursorPrev(pC->pKVCur);
    }else if( op==OP_SeekGt ){
      rc = sqlite4KVCursorNext(pC->pKVCur);
    }
  }


  /* Check that the KV cursor currently points to an entry belonging
  ** to index pC->iRoot (and not an entry that is part of some other 
  ** index).  */
  if( rc==SQLITE4_OK || rc==SQLITE4_INEXACT ){
    rc = sqlite4KVCursorKey(pC->pKVCur, &aKey, &nKey);
    if( rc==SQLITE4_OK && memcmp(aKey, aProbe, sqlite4VarintLen(pC->iRoot)) ){
      rc = SQLITE4_NOTFOUND;
    }
  }

  /* Free the key allocated above. If no error has occurred but the cursor 
  ** does not currently point to a valid entry, jump to instruction P2.  */
  sqlite4DbFree(db, aProbe);




  if( rc==SQLITE4_NOTFOUND ){
    rc = SQLITE4_OK;
    pc = pOp->p2 - 1;
  }
  break;
}








>
>
>
>



<


>
|
|
|
|

|
|
|
|
|
|
|
<
<
|
|
|
>
>
>
>
>
>










>
|
|
|
|
|
|
|
|
|

|
|
|
>
>
>
>







2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960

2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975


2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pOp->p2!=0 );
  assert( pC!=0 );
  assert( OP_SeekLe == OP_SeekLt+1 );
  assert( OP_SeekGe == OP_SeekLt+2 );
  assert( OP_SeekGt == OP_SeekLt+3 );

  dir = +1;
  op = pOp->opcode;
  if( op==OP_SeekLe || op==OP_SeekLt ) dir = -1;

  /* Encode a database key consisting of the contents of the P4 registers
  ** starting at register P3. Have the vdbecodec module allocate an extra
  ** free byte at the end of the database key (see below).  */

  nField = pOp->p4.i;
  pIn3 = &aMem[pOp->p3];
  if( pC->iRoot!=KVSTORE_ROOT ){
    rc = sqlite4VdbeEncodeKey(
        db, pIn3, nField, nField+(pOp->p5 & OPFLAG_PARTIALKEY),
        pC->iRoot, pC->pKeyInfo, &aProbe, &nProbe, 1
    );

    /*   Opcode    search-dir    increment-key
    **  --------------------------------------
    **   SeekLt    -1            no
    **   SeekLe    -1            yes
    **   SeekGe    +1            no
    **   SeekGt    +1            yes
    */


    if( op==OP_SeekLe || op==OP_SeekGt ) aProbe[nProbe++] = 0xFF;
    if( rc==SQLITE4_OK ){
      rc = sqlite4KVCursorSeek(pC->pKVCur, aProbe, nProbe, dir);
    }
  }else{
    Stringify(pIn3, encoding);
    rc = sqlite4KVCursorSeek(
        pC->pKVCur, (const KVByteArray *)pIn3->z, pIn3->n, dir
    );
  }

  if( rc==SQLITE4_OK ){
    if( op==OP_SeekLt ){
      rc = sqlite4KVCursorPrev(pC->pKVCur);
    }else if( op==OP_SeekGt ){
      rc = sqlite4KVCursorNext(pC->pKVCur);
    }
  }

  if( pC->iRoot!=KVSTORE_ROOT ){
    /* Check that the KV cursor currently points to an entry belonging
    ** to index pC->iRoot (and not an entry that is part of some other 
    ** index).  */
    if( rc==SQLITE4_OK || rc==SQLITE4_INEXACT ){
      rc = sqlite4KVCursorKey(pC->pKVCur, &aKey, &nKey);
      if( rc==SQLITE4_OK && memcmp(aKey, aProbe, sqlite4VarintLen(pC->iRoot)) ){
        rc = SQLITE4_NOTFOUND;
      }
    }

    /* Free the key allocated above. If no error has occurred but the cursor 
    ** does not currently point to a valid entry, jump to instruction P2.  */
    sqlite4DbFree(db, aProbe);
  }else if( rc==SQLITE4_INEXACT ){
    rc = SQLITE4_OK;
  }

  if( rc==SQLITE4_NOTFOUND ){
    rc = SQLITE4_OK;
    pc = pOp->p2 - 1;
  }
  break;
}

Changes to src/vdbecursor.c.
29
30
31
32
33
34
35
36
37
38
39
40
41
42












43
44
45
46
47
48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
** first element is sought if iEnd==+1 and the last element if iEnd==-1.
**
** Return SQLITE4_OK on success. Return SQLITE4_NOTFOUND if the table is empty.
*  Other error codes are also possible for various kinds of errors.
*/
int sqlite4VdbeSeekEnd(VdbeCursor *pC, int iEnd){
  KVCursor *pCur = pC->pKVCur;
  const KVByteArray *aKey;
  KVSize nKey;
  KVSize nProbe;
  int rc;
  KVByteArray aProbe[16];

  assert( iEnd==(+1) || iEnd==(-1) || iEnd==(-2) );  












  nProbe = sqlite4PutVarint64(aProbe, pC->iRoot);
  aProbe[nProbe] = 0xFF;

  rc = sqlite4KVCursorSeek(pCur, aProbe, nProbe+(iEnd<0), iEnd);
  if( rc==SQLITE4_OK ){
    rc = SQLITE4_CORRUPT_BKPT;
  }else if( rc==SQLITE4_INEXACT ){
    rc = sqlite4KVCursorKey(pCur, &aKey, &nKey);
    if( rc==SQLITE4_OK && (nKey<nProbe || memcmp(aKey, aProbe, nProbe)!=0) ){
      rc = SQLITE4_NOTFOUND;
    }
  }
  pC->rowChnged = 1;


  return rc;
}

/*
** Move a VDBE cursor to the next element in its table.
** Return SQLITE4_NOTFOUND if the seek falls of the end of the table.
*/
int sqlite4VdbeNext(VdbeCursor *pC){
  KVCursor *pCur = pC->pKVCur;
  const KVByteArray *aKey;
  KVSize nKey;
  int rc;
  sqlite4_uint64 iTabno;

  rc = sqlite4KVCursorNext(pCur);
  if( rc==SQLITE4_OK ){
    rc = sqlite4KVCursorKey(pCur, &aKey, &nKey);
    if( rc==SQLITE4_OK ){
      iTabno = 0;
      sqlite4GetVarint64(aKey, nKey, &iTabno);
      if( iTabno!=pC->iRoot ) rc = SQLITE4_NOTFOUND;
    }
  }







|
<

<



>
>
>
>
>
>
>
>
>
>
>
>
|
|

|
|
|
|
|
|
|
|
|
|
>
















|







29
30
31
32
33
34
35
36

37

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
** first element is sought if iEnd==+1 and the last element if iEnd==-1.
**
** Return SQLITE4_OK on success. Return SQLITE4_NOTFOUND if the table is empty.
*  Other error codes are also possible for various kinds of errors.
*/
int sqlite4VdbeSeekEnd(VdbeCursor *pC, int iEnd){
  KVCursor *pCur = pC->pKVCur;
  int rc;

  KVSize nProbe;

  KVByteArray aProbe[16];

  assert( iEnd==(+1) || iEnd==(-1) || iEnd==(-2) );  
  if( pC->iRoot==KVSTORE_ROOT ){
    if( iEnd>0 ){
      rc = sqlite4KVCursorSeek(pCur, (const KVByteArray *)"\00", 1, iEnd);
    }else{
      nProbe = sqlite4PutVarint64(aProbe, LARGEST_INT64);
      rc = sqlite4KVCursorSeek(pCur, aProbe, nProbe, iEnd);
    }
    if( rc==SQLITE4_INEXACT ) rc = SQLITE4_OK;
  }else{
    const KVByteArray *aKey;
    KVSize nKey;

    nProbe = sqlite4PutVarint64(aProbe, pC->iRoot);
    aProbe[nProbe] = 0xFF;

    rc = sqlite4KVCursorSeek(pCur, aProbe, nProbe+(iEnd<0), iEnd);
    if( rc==SQLITE4_OK ){
      rc = SQLITE4_CORRUPT_BKPT;
    }else if( rc==SQLITE4_INEXACT ){
      rc = sqlite4KVCursorKey(pCur, &aKey, &nKey);
      if( rc==SQLITE4_OK && (nKey<nProbe || memcmp(aKey, aProbe, nProbe)!=0) ){
        rc = SQLITE4_NOTFOUND;
      }
    }
    pC->rowChnged = 1;
  }

  return rc;
}

/*
** Move a VDBE cursor to the next element in its table.
** Return SQLITE4_NOTFOUND if the seek falls of the end of the table.
*/
int sqlite4VdbeNext(VdbeCursor *pC){
  KVCursor *pCur = pC->pKVCur;
  const KVByteArray *aKey;
  KVSize nKey;
  int rc;
  sqlite4_uint64 iTabno;

  rc = sqlite4KVCursorNext(pCur);
  if( rc==SQLITE4_OK && pC->iRoot!=KVSTORE_ROOT ){
    rc = sqlite4KVCursorKey(pCur, &aKey, &nKey);
    if( rc==SQLITE4_OK ){
      iTabno = 0;
      sqlite4GetVarint64(aKey, nKey, &iTabno);
      if( iTabno!=pC->iRoot ) rc = SQLITE4_NOTFOUND;
    }
  }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  KVCursor *pCur = pC->pKVCur;
  const KVByteArray *aKey;
  KVSize nKey;
  int rc;
  sqlite4_uint64 iTabno;

  rc = sqlite4KVCursorPrev(pCur);
  if( rc==SQLITE4_OK ){
    rc = sqlite4KVCursorKey(pCur, &aKey, &nKey);
    if( rc==SQLITE4_OK ){
      iTabno = 0;
      sqlite4GetVarint64(aKey, nKey, &iTabno);
      if( iTabno!=pC->iRoot ) rc = SQLITE4_NOTFOUND;
    }
  }







|







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  KVCursor *pCur = pC->pKVCur;
  const KVByteArray *aKey;
  KVSize nKey;
  int rc;
  sqlite4_uint64 iTabno;

  rc = sqlite4KVCursorPrev(pCur);
  if( rc==SQLITE4_OK && pC->iRoot!=KVSTORE_ROOT ){
    rc = sqlite4KVCursorKey(pCur, &aKey, &nKey);
    if( rc==SQLITE4_OK ){
      iTabno = 0;
      sqlite4GetVarint64(aKey, nKey, &iTabno);
      if( iTabno!=pC->iRoot ) rc = SQLITE4_NOTFOUND;
    }
  }
Changes to src/where.c.
3668
3669
3670
3671
3672
3673
3674




3675
3676
3677

3678
3679
3680
3681
3682
3683
3684
        codeApplyAffinity(pParse, regBase, nEq+1, zEndAff);
        nConstraint++;
        testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
      }

      /* Now compute an end-key using OP_MakeIdxKey */
      regEndKey = ++pParse->nMem;




      sqlite4VdbeAddOp4Int(
          v, OP_MakeIdxKey, iIdxCur, regBase, regEndKey, nConstraint
      );


    }

    sqlite4DbFree(pParse->db, zStartAff);
    sqlite4DbFree(pParse->db, zEndAff);

    /* Top of the loop body */







>
>
>
>
|
|
|
>







3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
        codeApplyAffinity(pParse, regBase, nEq+1, zEndAff);
        nConstraint++;
        testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
      }

      /* Now compute an end-key using OP_MakeIdxKey */
      regEndKey = ++pParse->nMem;
      if( pIdx->tnum==KVSTORE_ROOT ){
        sqlite4VdbeAddOp2(v, OP_Copy, regBase, regEndKey);
        sqlite4VdbeAddOp1(v, OP_ToBlob, regEndKey);
      }else{
        sqlite4VdbeAddOp4Int(
            v, OP_MakeIdxKey, iIdxCur, regBase, regEndKey, nConstraint
        );
      }

    }

    sqlite4DbFree(pParse->db, zStartAff);
    sqlite4DbFree(pParse->db, zEndAff);

    /* Top of the loop body */
Added test/kvstore.test.


















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# 2013 Jul 31
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the SELECT statement.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

set ::testprefix kvstore


do_execsql_test 1.1 { 
  SELECT * FROM sqlite_kvstore ;
  CREATE TABLE t1(x);
} {}

do_execsql_test 1.2 { 
  SELECT quote(key), quote(value) FROM sqlite_kvstore ;
} [list     \
  x'011802' \
  x'052a1e1e035e7461626c657431743102435245415445205441424c45207431287829'
]

do_execsql_test 1.3 { 
  SELECT quote(key), quote(value) FROM sqlite_temp_kvstore ;
} {}


do_execsql_test 2.1 {
  CREATE TABLE t2(x PRIMARY KEY, y UNIQUE);
  INSERT INTO t2 VALUES(1, 2);
  INSERT INTO t2 VALUES(3, 4);
  CREATE INDEX i1 ON t2(y DESC, x DESC);
}
array unset ::data
db eval { SELECT quote(key) AS k, quote(value) AS v FROM sqlite_kvstore } {
  set ::data($k) $v
}
do_execsql_test 2.2 { 
  SELECT quote(key) FROM sqlite_kvstore ORDER BY key DESC;
} [lsort -decreasing [array names ::data]]
do_execsql_test 2.3 { 
  SELECT quote(key) FROM sqlite_kvstore ORDER BY key ASC;
} [lsort -incr [array names ::data]]

set i 0
foreach k [array names ::data] {
  do_execsql_test 2.4.$i "
    SELECT quote(value) FROM sqlite_kvstore WHERE key = $k
  " $::data($k)
  incr i
}

proc key_range {a b} {
  set res [list]
  foreach k [lsort [array names ::data]] {
    if {[string compare $k $a]>=0 && [string compare $k $b]<=0} {
      lappend res $k
    }
  }
  set res
}

set sorted_keys [lsort [array names ::data]]
set nKey [llength $sorted_keys]
for {set i 0} {$i < $nKey} {incr i} {
  for {set i2 $i} {$i2 < $nKey} {incr i2} {
    set k1 [lindex $sorted_keys $i]
    set k2 [lindex $sorted_keys $i2]

    set sql "SELECT quote(key) FROM sqlite_kvstore WHERE key>=$k1 AND key<=$k2"
    set s1 [lsort [key_range $k1 $k2]]
    set s2 [lsort -decr [key_range $k1 $k2]]

    do_execsql_test 2.4.1.$i.$i2.asc " $sql ORDER BY key ASC " $s1
    do_execsql_test 2.4.1.$i.$i2.desc " $sql ORDER BY key DESC " $s2

    set sql "SELECT quote(key) FROM sqlite_kvstore WHERE key>$k1 AND key<=$k2"
    set s1 [lrange [lsort [key_range $k1 $k2]] 1 end]
    set s2 [lsort -decr $s1]

    do_execsql_test 2.4.2.$i.$i2.asc " $sql ORDER BY key ASC " $s1
    do_execsql_test 2.4.2.$i.$i2.desc " $sql ORDER BY key DESC " $s2

    set sql "SELECT quote(key) FROM sqlite_kvstore WHERE key>=$k1 AND key<$k2"
    set s1 [lrange [lsort [key_range $k1 $k2]] 0 end-1]
    set s2 [lsort -decr $s1]

    do_execsql_test 2.4.3.$i.$i2.asc " $sql ORDER BY key ASC " $s1
    do_execsql_test 2.4.3.$i.$i2.desc " $sql ORDER BY key DESC " $s2

    set sql "SELECT quote(key) FROM sqlite_kvstore WHERE key>$k1 AND key<$k2"
    set s1 [lrange [lsort [key_range $k1 $k2]] 1 end-1]
    set s2 [lsort -decr $s1]

    do_execsql_test 2.4.4.$i.$i2.asc " $sql ORDER BY key ASC " $s1
    do_execsql_test 2.4.4.$i.$i2.desc " $sql ORDER BY key DESC " $s2
    do_execsql_test 2.4.4.$i.$i2.asc " $sql ORDER BY key ASC " $s1
    do_execsql_test 2.4.4.$i.$i2.desc " $sql ORDER BY key DESC " $s2

  }
}


 





finish_test

Changes to test/permutations.test.
184
185
186
187
188
189
190

191
192
193
194
195
196
197
  func.test func2.test func3.test 
  fuzz.test fuzz2.test 
  in.test in2.test in3.test in4.test
  index.test index2.test index3.test index4.test 
  insert.test insert2.test insert3.test insert5.test
  join.test join2.test join3.test join4.test join5.test join6.test
  keyword1.test

  laststmtchanges.test
  limit.test
  like.test like2.test
  main.test
  manydb.test
  misc5.test misc6.test
  misuse.test







>







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  func.test func2.test func3.test 
  fuzz.test fuzz2.test 
  in.test in2.test in3.test in4.test
  index.test index2.test index3.test index4.test 
  insert.test insert2.test insert3.test insert5.test
  join.test join2.test join3.test join4.test join5.test join6.test
  keyword1.test
  kvstore.test
  laststmtchanges.test
  limit.test
  like.test like2.test
  main.test
  manydb.test
  misc5.test misc6.test
  misuse.test