SQLite4
Changes On Branch experimental
Not logged in

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

Changes In Branch experimental Excluding Merge-Ins

This is equivalent to a diff from 1f0129ac39 to 35af051367

2013-03-04
17:09
Merge xPutMeta and xGetMeta related changes from experimental branch. check-in: 03550f6b28 user: dan tags: trunk
14:18
Add dedicated get/set functions for the schema cookie to the sqlite4_kv_methods structure. Leaf check-in: 35af051367 user: dan tags: experimental
10:24
When in non-mmap mode, cache some page-data in memory. As sqlite does. check-in: 1f0129ac39 user: dan tags: trunk
2013-03-02
09:09
Remove a couple of unused variables from sqltest.c. check-in: e423d6c4bc user: dan tags: trunk

Changes to src/kv.c.

369
370
371
372
373
374
375

















376
377
378
379
380
381
382
      }
      while( i<nMeta ) a[i++] = 0;
    }
    sqlite4KVCursorClose(pCur);
  }
  return rc;
}


















/*
** Write nMeta unsigned 32-bit integers beginning with iStart.
*/
int sqlite4KVStorePutMeta(
  sqlite4 *db,            /* Database connection.  Needed to malloc */
  KVStore *p,             /* Write to this database */







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







369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
      }
      while( i<nMeta ) a[i++] = 0;
    }
    sqlite4KVCursorClose(pCur);
  }
  return rc;
}

/*
** Store schema cookie value iVal.
*/
int sqlite4KVStorePutSchema(KVStore *p, unsigned int iVal){
  kvTrace(p, "xPutMeta(%d,%d) -> %s", p->kvId, (int)iVal);
  return p->pStoreVfunc->xPutMeta(p, iVal);
}

/*
** Read the schema cookie value into *piVal.
*/
int sqlite4KVStoreGetSchema(KVStore *p, unsigned int *piVal){
  int rc = p->pStoreVfunc->xGetMeta(p, piVal);
  kvTrace(p, "xGetMeta(%d) -> %d", p->kvId, (int)*piVal);
  return rc;
}

/*
** Write nMeta unsigned 32-bit integers beginning with iStart.
*/
int sqlite4KVStorePutMeta(
  sqlite4 *db,            /* Database connection.  Needed to malloc */
  KVStore *p,             /* Write to this database */

Changes to src/kv.h.

170
171
172
173
174
175
176




177
178
179
int sqlite4KVStoreCommit(KVStore *p, int iLevel);
int sqlite4KVStoreRollback(KVStore *p, int iLevel);
int sqlite4KVStoreRevert(KVStore *p, int iLevel);
int sqlite4KVStoreClose(KVStore *p);

int sqlite4KVStoreGetMeta(KVStore *p, int, int, unsigned int*);
int sqlite4KVStorePutMeta(sqlite4*, KVStore *p, int, int, unsigned int*);




#ifdef SQLITE4_DEBUG
  void sqlite4KVStoreDump(KVStore *p);
#endif







>
>
>
>



170
171
172
173
174
175
176
177
178
179
180
181
182
183
int sqlite4KVStoreCommit(KVStore *p, int iLevel);
int sqlite4KVStoreRollback(KVStore *p, int iLevel);
int sqlite4KVStoreRevert(KVStore *p, int iLevel);
int sqlite4KVStoreClose(KVStore *p);

int sqlite4KVStoreGetMeta(KVStore *p, int, int, unsigned int*);
int sqlite4KVStorePutMeta(sqlite4*, KVStore *p, int, int, unsigned int*);

int sqlite4KVStorePutSchema(KVStore *p, unsigned int iVal);
int sqlite4KVStoreGetSchema(KVStore *p, unsigned int *piVal);

#ifdef SQLITE4_DEBUG
  void sqlite4KVStoreDump(KVStore *p);
#endif

Changes to src/kvlsm.c.

404
405
406
407
408
409
410










411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442


443
444
445
446
447
448
449
    default:
      rc = SQLITE4_NOTFOUND;
      break;
  }

  return rc;
}











/*
** Create a new in-memory storage engine and return a pointer to it.
*/
int sqlite4KVStoreOpenLsm(
  sqlite4_env *pEnv,          /* Run-time environment */
  KVStore **ppKVStore,        /* OUT: write the new KVStore here */
  const char *zName,          /* Name of the file to open */
  unsigned openFlags          /* Flags */
){

  /* Virtual methods for an LSM data store */
  static const KVStoreMethods kvlsmMethods = {
    1,                          /* iVersion */
    sizeof(KVStoreMethods),     /* szSelf */
    kvlsmReplace,               /* xReplace */
    kvlsmOpenCursor,            /* xOpenCursor */
    kvlsmSeek,                  /* xSeek */
    kvlsmNextEntry,             /* xNext */
    kvlsmPrevEntry,             /* xPrev */
    kvlsmDelete,                /* xDelete */
    kvlsmKey,                   /* xKey */
    kvlsmData,                  /* xData */
    kvlsmReset,                 /* xReset */
    kvlsmCloseCursor,           /* xCloseCursor */
    kvlsmBegin,                 /* xBegin */
    kvlsmCommitPhaseOne,        /* xCommitPhaseOne */
    kvlsmCommitPhaseTwo,        /* xCommitPhaseTwo */
    kvlsmRollback,              /* xRollback */
    kvlsmRevert,                /* xRevert */
    kvlsmClose,                 /* xClose */
    kvlsmControl                /* xControl */


  };

  KVLsm *pNew;
  int rc = SQLITE4_OK;

  pNew = (KVLsm *)sqlite4_malloc(pEnv, sizeof(KVLsm));
  if( pNew==0 ){







>
>
>
>
>
>
>
>
>
>













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







404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
    default:
      rc = SQLITE4_NOTFOUND;
      break;
  }

  return rc;
}

static int kvlsmGetMeta(KVStore *pKVStore, unsigned int *piVal){
  KVLsm *p = (KVLsm *)pKVStore;
  return lsm_get_user_version(p->pDb, piVal);
}

static int kvlsmPutMeta(KVStore *pKVStore, unsigned int iVal){
  KVLsm *p = (KVLsm *)pKVStore;
  return lsm_set_user_version(p->pDb, iVal);
}

/*
** Create a new in-memory storage engine and return a pointer to it.
*/
int sqlite4KVStoreOpenLsm(
  sqlite4_env *pEnv,          /* Run-time environment */
  KVStore **ppKVStore,        /* OUT: write the new KVStore here */
  const char *zName,          /* Name of the file to open */
  unsigned openFlags          /* Flags */
){

  /* Virtual methods for an LSM data store */
  static const KVStoreMethods kvlsmMethods = {
    1,                            /* iVersion */
    sizeof(KVStoreMethods),       /* szSelf */
    kvlsmReplace,                 /* xReplace */
    kvlsmOpenCursor,              /* xOpenCursor */
    kvlsmSeek,                    /* xSeek */
    kvlsmNextEntry,               /* xNext */
    kvlsmPrevEntry,               /* xPrev */
    kvlsmDelete,                  /* xDelete */
    kvlsmKey,                     /* xKey */
    kvlsmData,                    /* xData */
    kvlsmReset,                   /* xReset */
    kvlsmCloseCursor,             /* xCloseCursor */
    kvlsmBegin,                   /* xBegin */
    kvlsmCommitPhaseOne,          /* xCommitPhaseOne */
    kvlsmCommitPhaseTwo,          /* xCommitPhaseTwo */
    kvlsmRollback,                /* xRollback */
    kvlsmRevert,                  /* xRevert */
    kvlsmClose,                   /* xClose */
    kvlsmControl,                 /* xControl */
    kvlsmGetMeta,                 /* xGetMeta */
    kvlsmPutMeta                  /* xPutMeta */
  };

  KVLsm *pNew;
  int rc = SQLITE4_OK;

  pNew = (KVLsm *)sqlite4_malloc(pEnv, sizeof(KVLsm));
  if( pNew==0 ){

Changes to src/kvmem.c.

66
67
68
69
70
71
72

73
74
75
76
77
78
79
struct KVMem {
  KVStore base;         /* Base class, must be first */
  KVMemNode *pRoot;     /* Root of the tree of content */
  unsigned openFlags;   /* Flags used at open */
  KVMemChng **apLog;    /* Array of transaction logs */
  int nCursor;          /* Number of outstanding cursors */
  int iMagicKVMemBase;  /* Magic number of sanity */

};
#define SQLITE4_KVMEMBASE_MAGIC  0xbfcd47d0

/*
** A cursor used for scanning through the tree
*/
struct KVMemCursor {







>







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
struct KVMem {
  KVStore base;         /* Base class, must be first */
  KVMemNode *pRoot;     /* Root of the tree of content */
  unsigned openFlags;   /* Flags used at open */
  KVMemChng **apLog;    /* Array of transaction logs */
  int nCursor;          /* Number of outstanding cursors */
  int iMagicKVMemBase;  /* Magic number of sanity */
  unsigned int iMeta;   /* Schema cookie value */
};
#define SQLITE4_KVMEMBASE_MAGIC  0xbfcd47d0

/*
** A cursor used for scanning through the tree
*/
struct KVMemCursor {
911
912
913
914
915
916
917












918
919
920
921
922
923
924
  sqlite4_free(pEnv, p);
  return SQLITE4_OK;
}

static int kvmemControl(KVStore *pKVStore, int op, void *pArg){
  return SQLITE4_NOTFOUND;
}













/* Virtual methods for the in-memory storage engine */
static const KVStoreMethods kvmemMethods = {
  1,                        /* iVersion */
  sizeof(KVStoreMethods),   /* szSelf */
  kvmemReplace,             /* xReplace */
  kvmemOpenCursor,          /* xOpenCursor */







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







912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
  sqlite4_free(pEnv, p);
  return SQLITE4_OK;
}

static int kvmemControl(KVStore *pKVStore, int op, void *pArg){
  return SQLITE4_NOTFOUND;
}

static int kvmemGetMeta(KVStore *pKVStore, unsigned int *piVal){
  KVMem *p = (KVMem*)pKVStore;
  *piVal = p->iMeta;
  return SQLITE4_OK;
}

static int kvmemPutMeta(KVStore *pKVStore, unsigned int iVal){
  KVMem *p = (KVMem*)pKVStore;
  p->iMeta = iVal;
  return SQLITE4_OK;
}

/* Virtual methods for the in-memory storage engine */
static const KVStoreMethods kvmemMethods = {
  1,                        /* iVersion */
  sizeof(KVStoreMethods),   /* szSelf */
  kvmemReplace,             /* xReplace */
  kvmemOpenCursor,          /* xOpenCursor */
932
933
934
935
936
937
938
939


940
941
942
943
944
945
946
  kvmemCloseCursor,         /* xCloseCursor */
  kvmemBegin,               /* xBegin */
  kvmemCommitPhaseOne,      /* xCommitPhaseOne */
  kvmemCommitPhaseTwo,      /* xCommitPhaseTwo */
  kvmemRollback,            /* xRollback */
  kvmemRevert,              /* xRevert */
  kvmemClose,               /* xClose */
  kvmemControl              /* xControl */


};

/*
** Create a new in-memory storage engine and return a pointer to it.
*/
int sqlite4KVStoreOpenMem(
  sqlite4_env *pEnv,              /* Runtime environment */







|
>
>







945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
  kvmemCloseCursor,         /* xCloseCursor */
  kvmemBegin,               /* xBegin */
  kvmemCommitPhaseOne,      /* xCommitPhaseOne */
  kvmemCommitPhaseTwo,      /* xCommitPhaseTwo */
  kvmemRollback,            /* xRollback */
  kvmemRevert,              /* xRevert */
  kvmemClose,               /* xClose */
  kvmemControl,             /* xControl */
  kvmemGetMeta,             /* xGetMeta */
  kvmemPutMeta              /* xPutMeta */
};

/*
** Create a new in-memory storage engine and return a pointer to it.
*/
int sqlite4KVStoreOpenMem(
  sqlite4_env *pEnv,              /* Runtime environment */

Changes to src/lsm.h.

329
330
331
332
333
334
335



336
337
338
339
340
341
342

/*
** CAPI: Querying a Connection For Operational Data
**
** Query a database connection for operational statistics or data.
*/
int lsm_info(lsm_db *, int, ...);




/*
** The following values may be passed as the second argument to lsm_info().
**
** LSM_INFO_NWRITE:
**   The third parameter should be of type (int *). The location pointed
**   to by the third parameter is set to the number of 4KB pages written to







>
>
>







329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345

/*
** CAPI: Querying a Connection For Operational Data
**
** Query a database connection for operational statistics or data.
*/
int lsm_info(lsm_db *, int, ...);

int lsm_get_user_version(lsm_db *, unsigned int *);
int lsm_set_user_version(lsm_db *, unsigned int);

/*
** The following values may be passed as the second argument to lsm_info().
**
** LSM_INFO_NWRITE:
**   The third parameter should be of type (int *). The location pointed
**   to by the third parameter is set to the number of 4KB pages written to

Changes to src/lsmInt.h.

277
278
279
280
281
282
283

284
285
286
287
288
289
290
  u32 iNextShmid;                 /* Shm-id of next chunk allocated */
  u32 iFirst;                     /* Chunk number of smallest shm-id */
  u32 nChunk;                     /* Number of chunks in shared-memory file */
  TreeRoot root;                  /* Root and height of current tree */
  u32 iWrite;                     /* Write offset in shm file */
  TreeRoot oldroot;               /* Root and height of the previous tree */
  u32 iOldShmid;                  /* Last shm-id used by previous tree */

  i64 iOldLog;                    /* Log offset associated with old tree */
  u32 oldcksum0;
  u32 oldcksum1;
  DbLog log;                      /* Current layout of log file */ 
  u32 aCksum[2];                  /* Checksums 1 and 2. */
};








>







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  u32 iNextShmid;                 /* Shm-id of next chunk allocated */
  u32 iFirst;                     /* Chunk number of smallest shm-id */
  u32 nChunk;                     /* Number of chunks in shared-memory file */
  TreeRoot root;                  /* Root and height of current tree */
  u32 iWrite;                     /* Write offset in shm file */
  TreeRoot oldroot;               /* Root and height of the previous tree */
  u32 iOldShmid;                  /* Last shm-id used by previous tree */
  u32 iUsrVersion;                /* get/set_user_version() value */
  i64 iOldLog;                    /* Log offset associated with old tree */
  u32 oldcksum0;
  u32 oldcksum1;
  DbLog log;                      /* Current layout of log file */ 
  u32 aCksum[2];                  /* Checksums 1 and 2. */
};

Changes to src/lsm_file.c.

889
890
891
892
893
894
895

896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912

913
914
915
916
917
918
919
}


/*
** Purge the page cache of all entries with nRef==0.
*/
void lsmFsPurgeCache(FileSystem *pFS){

  Page *pPg;

  pPg = pFS->pLruFirst;
  while( pPg ){
    Page *pNext = pPg->pLruNext;
    fsPageRemoveFromHash(pFS, pPg);
    if( pPg->flags & PAGE_FREE ){
      lsmFree(pFS->pEnv, pPg->aData);
    }
    lsmFree(pFS->pEnv, pPg);
    pPg = pNext;
    pFS->nCacheAlloc--;
  }
  pFS->pLruFirst = 0;
  pFS->pLruLast = 0;

  assert( pFS->nCacheAlloc<=pFS->nOut && pFS->nCacheAlloc>=0 );

}

/*
** Search the hash-table for page iPg. If an entry is round, return a pointer
** to it. Otherwise, return NULL.
**
** Either way, if argument piHash is not NULL set *piHash to the hash slot







>
|

|
|
|
|
|
|
|
|
|
|
|
|
|

|
>







889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
}


/*
** Purge the page cache of all entries with nRef==0.
*/
void lsmFsPurgeCache(FileSystem *pFS){
  if( pFS->bUseMmap==0 ){
    Page *pPg;

    pPg = pFS->pLruFirst;
    while( pPg ){
      Page *pNext = pPg->pLruNext;
      fsPageRemoveFromHash(pFS, pPg);
      if( pPg->flags & PAGE_FREE ){
        lsmFree(pFS->pEnv, pPg->aData);
      }
      lsmFree(pFS->pEnv, pPg);
      pPg = pNext;
      pFS->nCacheAlloc--;
    }
    pFS->pLruFirst = 0;
    pFS->pLruLast = 0;

    assert( pFS->nCacheAlloc<=pFS->nOut && pFS->nCacheAlloc>=0 );
  }
}

/*
** Search the hash-table for page iPg. If an entry is round, return a pointer
** to it. Otherwise, return NULL.
**
** Either way, if argument piHash is not NULL set *piHash to the hash slot

Changes to src/lsm_main.c.

952
953
954
955
956
957
958
















































959
960
961
962
963
    }

    if( pDb->nTransOpen==0 ){
      lsmFinishWriteTrans(pDb, 0);
    }
    dbReleaseClientSnapshot(pDb);
  }

















































  return rc;
}









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





952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
    }

    if( pDb->nTransOpen==0 ){
      lsmFinishWriteTrans(pDb, 0);
    }
    dbReleaseClientSnapshot(pDb);
  }

  return rc;
}

int lsm_get_user_version(lsm_db *pDb, unsigned int *piUsr){
  int rc = LSM_OK;                /* Return code */

  /* Open a read transaction if one is not already open. */
  assert_db_state(pDb);
  if( pDb->pShmhdr==0 ){
    assert( pDb->bReadonly );
    rc = lsmBeginRoTrans(pDb);
  }else if( pDb->iReader<0 ){
    rc = lsmBeginReadTrans(pDb);
  }

  /* Allocate the multi-cursor. */
  if( rc==LSM_OK ){
    *piUsr = pDb->treehdr.iUsrVersion;
  }

  dbReleaseClientSnapshot(pDb);
  assert_db_state(pDb);
  return rc;
}

int lsm_set_user_version(lsm_db *pDb, unsigned int iUsr){
  int rc = LSM_OK;                /* Return code */
  int bCommit = 0;                /* True to commit before returning */

  if( pDb->nTransOpen==0 ){
    bCommit = 1;
    rc = lsm_begin(pDb, 1);
  }

  if( rc==LSM_OK ){
    pDb->treehdr.iUsrVersion = iUsr;
  }

  /* If a transaction was opened at the start of this function, commit it. 
  ** Or, if an error has occurred, roll it back.  */
  if( bCommit ){
    if( rc==LSM_OK ){
      rc = lsm_commit(pDb, 0);
    }else{
      lsm_rollback(pDb, 0);
    }
  }

  return rc;
}


Changes to src/prepare.c.

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
** indicate success or failure.
*/
static int sqlite4InitOne(sqlite4 *db, int iDb, char **pzErrMsg){
  int rc;
  Table *pTab;
  Db *pDb;
  char const *azArg[4];
  unsigned int meta[5];
  InitData initData;
  char const *zMasterSchema;
  char const *zMasterName;
  int openedTransaction = 0;

  /*
  ** The master database table has a structure like this







<







132
133
134
135
136
137
138

139
140
141
142
143
144
145
** indicate success or failure.
*/
static int sqlite4InitOne(sqlite4 *db, int iDb, char **pzErrMsg){
  int rc;
  Table *pTab;
  Db *pDb;
  char const *azArg[4];

  InitData initData;
  char const *zMasterSchema;
  char const *zMasterName;
  int openedTransaction = 0;

  /*
  ** The master database table has a structure like this
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
    if( rc!=SQLITE4_OK ){
      sqlite4SetString(pzErrMsg, db, "%s", sqlite4ErrStr(rc));
      goto initone_error_out;
    }
    openedTransaction = 1;
  }

  /* Get the database meta information.
  **
  ** Meta values are as follows:
  **    meta[0]   Schema cookie.  Changes with each schema change.
  **    meta[1]   unused
  **    meta[2]   unused
  **    meta[3]   unused
  **    meta[4]   unused
  **    meta[5]   unused
  **    meta[6]   unused
  **    meta[7]   unused
  **    meta[8]   unused
  **    meta[9]   unused
  **
  ** Note: The #defined SQLITE4_UTF* symbols in sqliteInt.h correspond to
  ** the possible values of meta[4].
  */
  sqlite4KVStoreGetMeta(pDb->pKV, 0, ArraySize(meta), meta);
  pDb->pSchema->schema_cookie = meta[0];

  /* Read the schema information out of the schema tables
  */
  assert( db->init.busy );
  {
    char *zSql;
    zSql = sqlite4MPrintf(db, 







|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

|
<







219
220
221
222
223
224
225
226















227
228

229
230
231
232
233
234
235
    if( rc!=SQLITE4_OK ){
      sqlite4SetString(pzErrMsg, db, "%s", sqlite4ErrStr(rc));
      goto initone_error_out;
    }
    openedTransaction = 1;
  }

  /* Get the database schema version.















  */
  sqlite4KVStoreGetSchema(pDb->pKV, (u32 *)&pDb->pSchema->schema_cookie);


  /* Read the schema information out of the schema tables
  */
  assert( db->init.busy );
  {
    char *zSql;
    zSql = sqlite4MPrintf(db, 
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
      if( rc!=SQLITE4_OK ) return;
      openedTransaction = 1;
    }

    /* Read the schema cookie from the database. If it does not match the 
    ** value stored as part of the in-memory schema representation,
    ** set Parse.rc to SQLITE4_SCHEMA. */
    sqlite4KVStoreGetMeta(pKV, 0, 1, (u32 *)&cookie);
    if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
      sqlite4ResetInternalSchema(db, iDb);
      pParse->rc = SQLITE4_SCHEMA;
    }

    /* Close the transaction, if one was opened. */
    if( openedTransaction ){







|







381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
      if( rc!=SQLITE4_OK ) return;
      openedTransaction = 1;
    }

    /* Read the schema cookie from the database. If it does not match the 
    ** value stored as part of the in-memory schema representation,
    ** set Parse.rc to SQLITE4_SCHEMA. */
    sqlite4KVStoreGetSchema(pKV, (u32 *)&cookie);
    if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
      sqlite4ResetInternalSchema(db, iDb);
      pParse->rc = SQLITE4_SCHEMA;
    }

    /* Close the transaction, if one was opened. */
    if( openedTransaction ){

Changes to src/sqlite.h.in.

4227
4228
4229
4230
4231
4232
4233


4234
4235
4236
4237
4238
4239
4240
  int (*xBegin)(sqlite4_kvstore*, int);
  int (*xCommitPhaseOne)(sqlite4_kvstore*, int);
  int (*xCommitPhaseTwo)(sqlite4_kvstore*, int);
  int (*xRollback)(sqlite4_kvstore*, int);
  int (*xRevert)(sqlite4_kvstore*, int);
  int (*xClose)(sqlite4_kvstore*);
  int (*xControl)(sqlite4_kvstore*, int, void*);


};
typedef struct sqlite4_kv_methods sqlite4_kv_methods;

/*
** CAPI4REF: Key-value storage engine open flags
**
** Allowed values to the flags parameter of an [sqlite4_kvfactory] object.







>
>







4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
  int (*xBegin)(sqlite4_kvstore*, int);
  int (*xCommitPhaseOne)(sqlite4_kvstore*, int);
  int (*xCommitPhaseTwo)(sqlite4_kvstore*, int);
  int (*xRollback)(sqlite4_kvstore*, int);
  int (*xRevert)(sqlite4_kvstore*, int);
  int (*xClose)(sqlite4_kvstore*);
  int (*xControl)(sqlite4_kvstore*, int, void*);
  int (*xGetMeta)(sqlite4_kvstore*, unsigned int *);
  int (*xPutMeta)(sqlite4_kvstore*, unsigned int);
};
typedef struct sqlite4_kv_methods sqlite4_kv_methods;

/*
** CAPI4REF: Key-value storage engine open flags
**
** Allowed values to the flags parameter of an [sqlite4_kvfactory] object.

Changes to src/vdbe.c.

2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
  u32 v;

  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  pDb = &db->aDb[pOp->p1];
  pIn3 = &aMem[pOp->p3];
  sqlite4VdbeMemIntegerify(pIn3);
  v = (u32)pIn3->u.i;
  rc = sqlite4KVStorePutMeta(db, pDb->pKV, 0, 1, &v);
  pDb->pSchema->schema_cookie = (int)pIn3->u.i;
  db->flags |= SQLITE4_InternChanges;
  if( pOp->p1==1 ){
    /* Invalidate all prepared statements whenever the TEMP database
    ** schema is changed.  Ticket #1644 */
    sqlite4ExpirePreparedStatements(db);
    p->expired = 0;







|







2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
  u32 v;

  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  pDb = &db->aDb[pOp->p1];
  pIn3 = &aMem[pOp->p3];
  sqlite4VdbeMemIntegerify(pIn3);
  v = (u32)pIn3->u.i;
  rc = sqlite4KVStorePutSchema(pDb->pKV, v);
  pDb->pSchema->schema_cookie = (int)pIn3->u.i;
  db->flags |= SQLITE4_InternChanges;
  if( pOp->p1==1 ){
    /* Invalidate all prepared statements whenever the TEMP database
    ** schema is changed.  Ticket #1644 */
    sqlite4ExpirePreparedStatements(db);
    p->expired = 0;
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
  unsigned int iMeta;
  int iGen;
  KVStore *pKV;

  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  pKV = db->aDb[pOp->p1].pKV;
  if( pKV ){
    rc = sqlite4KVStoreGetMeta(pKV, 0, 1, &iMeta);
    if( rc ) break;
    iGen = db->aDb[pOp->p1].pSchema->iGeneration;
  }else{
    iGen = iMeta = 0;
  }
  if( iMeta!=pOp->p2 || iGen!=pOp->p3 ){
    sqlite4DbFree(db, p->zErrMsg);







|







2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
  unsigned int iMeta;
  int iGen;
  KVStore *pKV;

  assert( pOp->p1>=0 && pOp->p1<db->nDb );
  pKV = db->aDb[pOp->p1].pKV;
  if( pKV ){
    rc = sqlite4KVStoreGetSchema(pKV, &iMeta);
    if( rc ) break;
    iGen = db->aDb[pOp->p1].pSchema->iGeneration;
  }else{
    iGen = iMeta = 0;
  }
  if( iMeta!=pOp->p2 || iGen!=pOp->p3 ){
    sqlite4DbFree(db, p->zErrMsg);

Changes to test/test_kv2.c.

229
230
231
232
233
234
235










236
237
238
239
240
241
242
/*
** Invoke the xControl() method of the underlying KVStore object.
*/
static int kvwrapControl(KVStore *pKVStore, int op, void *pArg){
  KVWrap *p = (KVWrap *)pKVStore;
  return p->pReal->pStoreVfunc->xControl(p->pReal, op, pArg);
}











static int newFileStorage(
  sqlite4_env *pEnv,
  KVStore **ppKVStore,
  const char *zName,
  unsigned openFlags
){







>
>
>
>
>
>
>
>
>
>







229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
** Invoke the xControl() method of the underlying KVStore object.
*/
static int kvwrapControl(KVStore *pKVStore, int op, void *pArg){
  KVWrap *p = (KVWrap *)pKVStore;
  return p->pReal->pStoreVfunc->xControl(p->pReal, op, pArg);
}

static int kvwrapGetMeta(KVStore *pKVStore, unsigned int *piVal){
  KVWrap *p = (KVWrap *)pKVStore;
  return p->pReal->pStoreVfunc->xGetMeta(p->pReal, piVal);
}

static int kvwrapPutMeta(KVStore *pKVStore, unsigned int iVal){
  KVWrap *p = (KVWrap *)pKVStore;
  return p->pReal->pStoreVfunc->xPutMeta(p->pReal, iVal);
}

static int newFileStorage(
  sqlite4_env *pEnv,
  KVStore **ppKVStore,
  const char *zName,
  unsigned openFlags
){
257
258
259
260
261
262
263
264


265
266
267
268
269
270
271
    kvwrapCloseCursor,
    kvwrapBegin,
    kvwrapCommitPhaseOne,
    kvwrapCommitPhaseTwo,
    kvwrapRollback,
    kvwrapRevert,
    kvwrapClose,
    kvwrapControl


  };

  KVWrap *pNew;
  int rc = SQLITE4_OK;

  pNew = (KVWrap *)sqlite4_malloc(0, sizeof(KVWrap));
  if( pNew==0 ){







|
>
>







267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
    kvwrapCloseCursor,
    kvwrapBegin,
    kvwrapCommitPhaseOne,
    kvwrapCommitPhaseTwo,
    kvwrapRollback,
    kvwrapRevert,
    kvwrapClose,
    kvwrapControl,
    kvwrapGetMeta,
    kvwrapPutMeta
  };

  KVWrap *pNew;
  int rc = SQLITE4_OK;

  pNew = (KVWrap *)sqlite4_malloc(0, sizeof(KVWrap));
  if( pNew==0 ){