-C Require\sthat\sthe\sdatabase\shandle\sbe\sin\sautocommit\smode\sfor\nsqlite3_snapshot_get()\sto\ssucceed.\sThis\sis\sbecause\sit\smay\sopen\sa\sread\ntransaction\son\sthe\sdatabase\sfile.
-D 2016-11-18T18:43:39.100
+C Add\sexperimental\ssqlite3_snapshot_recover()\sAPI.
+D 2016-11-18T20:49:43.736
F Makefile.in 6b572807415d3f0a379cebc9461416d8df4a12c8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc bb4d970894abbbe0e88d00aac29bd52af8bc95f4
F src/insert.c 0d6e59f9eea62db772eabc0f07901ec26fe01968
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
F src/loadext.c 5d6642d141c07d366e43d359e94ec9de47add41d
-F src/main.c 602d7179fda1879d688174dcd74c69c8579045b5
+F src/main.c de55e68145758d5512e9397728c9a8f4ff0ffa78
F src/malloc.c 5ee7c2d3dcb1b0a902c9c6d0115deef54736bdfa
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
F src/os_unix.c be9ca0f901a2b6c1bc93dc338f4863675180c189
F src/os_win.c cf90abd4e50d9f56d2c20ce8e005aff55d7bd8e9
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c a31e2c25563065ebfc9308f2ba3a061901fd60a8
-F src/pager.h 07d6938df0b74e4abe8f57807a8b0e1084321d8b
+F src/pager.c 4e4aea7ced5734753ccbff4cf4bb4d032cf2173e
+F src/pager.h d1e944291030351f362a0a7da9b5c3e34e603e39
F src/parse.y 0338f906b61e311c2b7e11a3f89b0092c780b664
F src/pcache.c 5ff2a08f76a9c1b22f43eb063b7068fb085465ac
F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 672b1af237ad257149fc5189f3277dcbca036eeb
F src/shell.c f04e4af75c5517735397d060ed0b4a874104bb41
-F src/sqlite.h.in cc6e3f38d4c1e4df4f569af49c5deb7c32f1ea10
+F src/sqlite.h.in d9b7b5942a18bb83b560c7699aff3925b4f9af90
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
F src/sqliteInt.h c471d791b10c0f2164c8b7a87adc338e703c09cc
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
F src/tclsqlite.c aef87dcd8cb66564d560ab48d43d19ac812a1eab
-F src/test1.c 58de30ed902f78531cf5cf52b883a26d107208c4
+F src/test1.c d6a047ea534fb68fedcb5a47f4db3baef6748294
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
F src/vtab.c e02cacb5c7ae742631edeb9ae9f53d399f093fd8
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c 88f8d8adcaecf6a225ae5098062fd151634fb672
-F src/wal.h bf03a23da3100ab25e5c0363450233cfee09cfc2
+F src/wal.c 5ef877f34c1becb8aaff337bb24544462117a79b
+F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
F src/walker.c 91a6df7435827e41cff6bb7df50ea00934ee78b0
F src/where.c 952f76e7a03727480b274b66ca6641b1657cd591
F src/whereInt.h 2bcc3d176e6091cb8f50a30b65c006e88a73614d
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b
F test/snapshot.test 85735bd997a4f6d710140c28fd860519a299649f
-F test/snapshot2.test 30bd95f6fefa8be7f29421e27745cac90b66c74d
+F test/snapshot2.test 26949814860534949672dc007877062719b57c39
F test/snapshot_fault.test 062ff0438a074978d45e9f9a92e7ad459b74ee73
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 1f7ee7af7b620262ae663d65889b6a87415d4a34
-R 94e3e6505e79390151b9cd467eca8236
+P 83b658dad091211ade3594d1e8d00ce525882506
+R 3db63b187961b7fe3d252e007ca73669
U dan
-Z 084fdf6a46a9563f3a18164c0feb0d49
+Z 5c1ddc1fb889cebc1f3b9de248414272
-83b658dad091211ade3594d1e8d00ce525882506
\ No newline at end of file
+174a6076a8d7bebe5efebf55f3fdc5d87c589cc7
\ No newline at end of file
return rc;
}
+/*
+** Recover as many snapshots as possible from the wal file associated with
+** schema zDb of database db.
+*/
+int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
+ int rc = SQLITE_ERROR;
+ int iDb;
+#ifndef SQLITE_OMIT_WAL
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+
+ sqlite3_mutex_enter(db->mutex);
+ iDb = sqlite3FindDbName(db, zDb);
+ if( iDb==0 || iDb>1 ){
+ Btree *pBt = db->aDb[iDb].pBt;
+ if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
+ rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
+ }
+ }
+ sqlite3_mutex_leave(db->mutex);
+#endif /* SQLITE_OMIT_WAL */
+ return rc;
+}
+
/*
** Free a snapshot handle obtained from sqlite3_snapshot_get().
*/
}
return rc;
}
+
+/*
+** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this
+** is not a WAL database, return an error.
+*/
+int sqlite3PagerSnapshotRecover(Pager *pPager){
+ int rc;
+ if( pPager->pWal ){
+ rc = sqlite3WalSnapshotRecover(pPager->pWal);
+ }else{
+ rc = SQLITE_ERROR;
+ }
+ return rc;
+}
#endif /* SQLITE_ENABLE_SNAPSHOT */
#endif /* !SQLITE_OMIT_WAL */
# ifdef SQLITE_ENABLE_SNAPSHOT
int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
+ int sqlite3PagerSnapshotRecover(Pager *pPager);
# endif
#else
# define sqlite3PagerUseWal(x) 0
sqlite3_snapshot *p2
);
+/*
+** CAPI3REF: Recover snapshots from a wal file
+** EXPERIMENTAL
+*/
+SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
+
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
}
#endif /* SQLITE_ENABLE_SNAPSHOT */
+#ifdef SQLITE_ENABLE_SNAPSHOT
+/*
+** Usage: sqlite3_snapshot_recover DB DBNAME
+*/
+static int SQLITE_TCLAPI test_snapshot_recover(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ int rc;
+ sqlite3 *db;
+ char *zName;
+
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ zName = Tcl_GetString(objv[2]);
+
+ rc = sqlite3_snapshot_recover(db, zName);
+ if( rc!=SQLITE_OK ){
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
+ return TCL_ERROR;
+ }else{
+ Tcl_ResetResult(interp);
+ }
+ return TCL_OK;
+}
+#endif /* SQLITE_ENABLE_SNAPSHOT */
+
#ifdef SQLITE_ENABLE_SNAPSHOT
/*
** Usage: sqlite3_snapshot_open DB DBNAME SNAPSHOT
{ "sqlite3_snapshot_open", test_snapshot_open, 0 },
{ "sqlite3_snapshot_free", test_snapshot_free, 0 },
{ "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
+ { "sqlite3_snapshot_recover", test_snapshot_recover, 0 },
{ "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 },
{ "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
{ "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
return rc;
}
+/*
+** Recover as many snapshots as possible from the wal file.
+*/
+int sqlite3WalSnapshotRecover(Wal *pWal){
+ int dummy;
+ int rc;
+
+ rc = sqlite3WalBeginReadTransaction(pWal, &dummy);
+ if( rc==SQLITE_OK ){
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ int szPage = (int)pWal->szPage;
+ void *pBuf1 = sqlite3_malloc(szPage);
+ void *pBuf2 = sqlite3_malloc(szPage);
+
+ if( pBuf1==0 || pBuf2==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ u32 i = pInfo->nBackfillAttempted;
+ for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){
+ volatile ht_slot *dummy;
+ volatile u32 *aPgno; /* Array of page numbers */
+ u32 iZero; /* Frame corresponding to aPgno[0] */
+ u32 pgno; /* Page number in db file */
+ i64 iDbOff; /* Offset of db file entry */
+ i64 iWalOff; /* Offset of wal file entry */
+ rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero);
+
+ if( rc==SQLITE_OK ){
+ pgno = aPgno[i-iZero];
+ iDbOff = (i64)(pgno-1) * szPage;
+ iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
+ rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
+ }
+
+ if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
+ break;
+ }
+
+ pInfo->nBackfillAttempted = i-1;
+ }
+ }
+
+ sqlite3_free(pBuf1);
+ sqlite3_free(pBuf2);
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ }
+
+ sqlite3WalEndReadTransaction(pWal);
+ }
+
+ return rc;
+}
+
/*
** Begin a read transaction on the database.
**
** has not yet set the pInfo->nBackfillAttempted variable to indicate
** its intent. To avoid the race condition this leads to, ensure that
** there is no checkpointer process by taking a shared CKPT lock
- ** before checking pInfo->nBackfillAttempted. */
+ ** before checking pInfo->nBackfillAttempted.
+ **
+ ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing
+ ** this already?
+ */
rc = walLockShared(pWal, WAL_CKPT_LOCK);
if( rc==SQLITE_OK ){
#ifdef SQLITE_ENABLE_SNAPSHOT
int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
+int sqlite3WalSnapshotRecover(Wal *pWal);
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
execsql COMMIT
db2 close
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 2.0 {
+ CREATE TABLE t1(x);
+ PRAGMA journal_mode = wal;
+ INSERT INTO t1 VALUES(1);
+ INSERT INTO t1 VALUES(2);
+} {wal}
+
+do_test 2.1 {
+ db trans { set snap [sqlite3_snapshot_get_blob db main] }
+ sqlite3_db_config db NO_CKPT_ON_CLOSE 1
+ db close
+ sqlite3 db test.db
+
+ execsql {SELECT * FROM sqlite_master}
+ execsql BEGIN
+ sqlite3_snapshot_open_blob db main $snap
+ execsql COMMIT;
+ execsql { INSERT INTO t1 VALUES(3); }
+} {}
+
+do_test 2.2 {
+ sqlite3_db_config db NO_CKPT_ON_CLOSE 1
+ db close
+ sqlite3 db test.db
+
+ execsql {SELECT * FROM sqlite_master}
+ execsql BEGIN
+ list [catch { sqlite3_snapshot_open_blob db main $snap } msg] $msg
+} {1 SQLITE_BUSY_SNAPSHOT}
+
+do_test 2.3 {
+ execsql COMMIT
+ sqlite3_snapshot_recover db main
+ execsql BEGIN
+ sqlite3_snapshot_open_blob db main $snap
+ execsql { SELECT * FROM t1 }
+} {1 2}
+
+do_test 2.4 {
+ execsql COMMIT
+ execsql { SELECT * FROM t1 }
+} {1 2 3}
+
+do_test 2.5 {
+ execsql { PRAGMA wal_checkpoint }
+ sqlite3_db_config db NO_CKPT_ON_CLOSE 1
+ db close
+ sqlite3 db test.db
+
+ execsql {SELECT * FROM sqlite_master}
+ sqlite3_snapshot_recover db main
+ execsql BEGIN
+ list [catch { sqlite3_snapshot_open_blob db main $snap } msg] $msg
+} {1 SQLITE_BUSY_SNAPSHOT}
+
finish_test
+
+