Allow sqlite3_snapshot_open() to be called to change the snapshot after a

read transaction is already open on database.

FossilOrigin-Name: 051ac0152048ef52723196c26ca5f2629dafb782aec1c66fc30531bf54335043
This commit is contained in:
dan 2018-08-06 17:12:36 +00:00
parent f018fd5284
commit fa3d4c19a9
11 changed files with 343 additions and 36 deletions

View File

@ -1,5 +1,5 @@
C Enhance\sthe\sedit()\sfunction\sso\sthat\sit\sconverts\stext\sfrom\s\\r\\n\sback\sinto\s\\n\nonly\sif\sthe\soriginal\sunedited\scopy\scontained\sno\s\\r\\n\svalues.
D 2018-08-06T02:08:53.886
C Allow\ssqlite3_snapshot_open()\sto\sbe\scalled\sto\schange\sthe\ssnapshot\safter\sa\nread\stransaction\sis\salready\sopen\son\sdatabase.
D 2018-08-06T17:12:36.835
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
@ -462,7 +462,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 894594952bcda1dc6e1549871e4022517563545ffc7a3f4e9e5f3faa788893fd
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
F src/main.c dc023f468eda20aed1fb7c300673cbb40617607b5771840e4229ec239dade250
F src/main.c 3c7f2159687af1b1b0d0e0776f888adb94534e0bc52e7a1a1509f83e24cb6297
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@ -485,8 +485,8 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c d9cf5ae0c79f31019d8325e8736c83914aeed64d8327a8d91a62b6439b748948
F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 76d29b8a960dcb8b67210f095899d91e4a90673a6674ea58cfd1115b705a7fb9
F src/pager.h c571b064df842ec8f2e90855dead9acf4cbe0d1b2c05afe0ef0d0145f7fd0388
F src/pager.c 705de01dff9c3df9739c37a6d3b58cd2b1734fdabcef829b16cdc7721a9eeaa4
F src/pager.h ecc554a55bc55d1c4ba5e17137b72e238e00bd81e72ff2662d8b9c8c10ae3963
F src/parse.y 704c94624d41d7d46a5467574130e55aa8029a563f4df538f0121475eae46e34
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
@ -500,7 +500,7 @@ F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04
F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f
F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95
F src/sqlite.h.in 82b5768e36ce796ecf93c73bd88bad99def831ce7d470138e213ac693bf4ceab
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
F src/sqliteInt.h a5d212bb7ae5cfc0540af6fb09eee2092a45fe083fac4191ee64ff70e7d4d78a
@ -508,7 +508,7 @@ F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/tclsqlite.c e0bf71a6d24b8c23393c000abffab05979bbca2a72d0b0f79260e2cf1527fda5
F src/test1.c 55424c026dd93c06ad84ff4e46cec64aa3e12e767d50c31886e6a69ee53fe81e
F src/test1.c 31c491ccb536bd9916a084e732ffe783b3c8973f2586d5a56aed0e3a9701dfff
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
@ -580,8 +580,8 @@ F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c d44a0811afd2155b1157c38b33141d4ac028fda6232485bed664015bb05819ca
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
F src/wal.c d0d541116c378937fad99d89737cf36cfc67ff94ba1d29b2bf93bc7333e07e25
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4
F src/where.c 155809967fbab889374dedf970ea6561b8fb519fcb165d6ba00776552ecc5cde
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
@ -1269,10 +1269,11 @@ F test/skipscan2.test ef143c6e4a5ba4f19c1d1e3f517811f7942bdf2142736cc568feb34e0b
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
F test/skipscan6.test 0b4cd1b4ac9f84d91454df513c99a4932fa07e8f27b8049bea605068b3e34ac7
F test/snapshot.test 85735bd997a4f6d710140c28fd860519a299649f
F test/snapshot.test fef12fc5c16ff21c4748509401cfba7d9a3d91156f1bfe23fb881d3bfc65ddfe
F test/snapshot2.test 925e42427e923262db63c9d7155183f889e3e99feaedec4075f659e51608344f
F test/snapshot3.test 9719443594a04778861bd20d12596c5f880af177d6cd62f111da3198cafc6096
F test/snapshot_fault.test 52c5e97ebd218846a8ae2da4d147d3e77d71f963
F test/snapshot_up.test b778a04561a67b8bfde828f473a8d31dbde23e3f648e36237e0369421e08f23c
F test/soak.test 18944cf21b94a7fe0df02016a6ee1e9632bc4e8d095a0cb49d95e15d5cca2d5c
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
F test/sort.test c2adc635c2564241fefec0b3a68391ef6868fd3b
@ -1754,7 +1755,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 1caaaaa70f21fe71fbe0af227eea8d1367870e2575eedf248cc2a0b515783390
R 599391bf767ca60a524e57a614c06c9d
U drh
Z e1c623c52da1d23ca607e4f314a88bce
P 20c995d3f0f4de5410962172cb59da0f25edf0c62e199420186cc59ea874e981
R 462315bcd4a2eb76f7dc221ad2f185d1
T *branch * exp-snapshot-open
T *sym-exp-snapshot-open *
T -sym-trunk *
U dan
Z f721373f748dbb5b0d3c5c4f1daf5230

View File

@ -1 +1 @@
20c995d3f0f4de5410962172cb59da0f25edf0c62e199420186cc59ea874e981
051ac0152048ef52723196c26ca5f2629dafb782aec1c66fc30531bf54335043

View File

@ -4209,11 +4209,29 @@ int sqlite3_snapshot_open(
iDb = sqlite3FindDbName(db, zDb);
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot);
if( sqlite3BtreeIsInTrans(pBt)==0 ){
Pager *pPager = sqlite3BtreePager(pBt);
int bUnlock = 0;
if( sqlite3BtreeIsInReadTrans(pBt) ){
if( db->nVdbeActive==0 ){
rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot);
if( rc==SQLITE_OK ){
bUnlock = 1;
rc = sqlite3BtreeCommit(pBt);
}
}
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot);
}
if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0);
sqlite3PagerSnapshotOpen(pPager, 0);
}
if( bUnlock ){
sqlite3PagerSnapshotUnlock(pPager);
}
}
}

View File

@ -7653,6 +7653,38 @@ int sqlite3PagerSnapshotRecover(Pager *pPager){
}
return rc;
}
/*
** The caller currently has a read transaction open on the database.
** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise,
** this function takes a SHARED lock on the CHECKPOINTER slot and then
** checks if the snapshot passed as the second argument is still
** available. If so, SQLITE_OK is returned.
**
** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error
** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER
** lock is released before returning.
*/
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){
int rc;
if( pPager->pWal ){
rc = sqlite3WalSnapshotCheck(pPager->pWal, pSnapshot);
}else{
rc = SQLITE_ERROR;
}
return rc;
}
/*
** Release a lock obtained by an earlier successful call to
** sqlite3PagerSnapshotCheck().
*/
void sqlite3PagerSnapshotUnlock(Pager *pPager){
assert( pPager->pWal );
return sqlite3WalSnapshotUnlock(pPager->pWal);
}
#endif /* SQLITE_ENABLE_SNAPSHOT */
#endif /* !SQLITE_OMIT_WAL */

View File

@ -186,6 +186,8 @@ int sqlite3PagerSharedLock(Pager *pPager);
int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
int sqlite3PagerSnapshotRecover(Pager *pPager);
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
void sqlite3PagerSnapshotUnlock(Pager *pPager);
# endif
#else
# define sqlite3PagerUseWal(x,y) 0

View File

@ -9035,22 +9035,33 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
** CAPI3REF: Start a read transaction on an historical snapshot
** METHOD: sqlite3_snapshot
**
** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
** read transaction for schema S of
** [database connection] D such that the read transaction
** refers to historical [snapshot] P, rather than the most
** recent change to the database.
** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
** or an appropriate [error code] if it fails.
** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read
** transaction or upgrades an existing one for schema S of
** [database connection] D such that the read transaction refers to
** historical [snapshot] P, rather than the most recent change to the
** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK
** on success or an appropriate [error code] if it fails.
**
** ^In order to succeed, the database connection must not be in
** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there
** is already a read transaction open on schema S, then the database handle
** must have no active statements (SELECT statements that have been passed
** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()).
** SQLITE_ERROR is returned if either of these conditions is violated, or
** if schema S does not exist, or if the snapshot object is invalid.
**
** ^A call to sqlite3_snapshot_open() will fail to open if the specified
** snapshot has been overwritten by a [checkpoint]. In this case
** SQLITE_BUSY_SNAPSHOT is returned.
**
** If there is already a read transaction open when this function is
** invoked, then the same read transaction remains open (on the same
** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_BUSY_SNAPSHOT
** is returned. If another error code - for example SQLITE_PROTOCOL or an
** SQLITE_IOERR error code - is returned, then the final state of the
** read transaction is undefined. If SQLITE_OK is returned, then the
** read transaction is now open on database snapshot P.
**
** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
** the first operation following the [BEGIN] that takes the schema S
** out of [autocommit mode].
** ^In other words, schema S must not currently be in
** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
** database connection D must be out of [autocommit mode].
** ^A [snapshot] will fail to open if it has been overwritten by a
** [checkpoint].
** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
** database connection D does not know that the database file for
** schema S is in [WAL mode]. A database connection might not know

View File

@ -2393,6 +2393,8 @@ static int SQLITE_TCLAPI test_snapshot_open(
if( rc!=SQLITE_OK ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
return TCL_ERROR;
}else{
Tcl_ResetResult(interp);
}
return TCL_OK;
}

View File

@ -3769,6 +3769,43 @@ int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
return 0;
}
/*
** The caller currently has a read transaction open on the database.
** This function takes a SHARED lock on the CHECKPOINTER slot and then
** checks if the snapshot passed as the second argument is still
** available. If so, SQLITE_OK is returned.
**
** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error
** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER
** lock is released before returning.
*/
int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){
int rc;
rc = walLockShared(pWal, WAL_CKPT_LOCK);
if( rc==SQLITE_OK ){
WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
|| pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
){
rc = SQLITE_BUSY_SNAPSHOT;
walUnlockShared(pWal, WAL_CKPT_LOCK);
}
}
return rc;
}
/*
** Release a lock obtained by an earlier successful call to
** sqlite3WalSnapshotCheck().
*/
void sqlite3WalSnapshotUnlock(Wal *pWal){
assert( pWal );
walUnlockShared(pWal, WAL_CKPT_LOCK);
}
#endif /* SQLITE_ENABLE_SNAPSHOT */
#ifdef SQLITE_ENABLE_ZIPVFS

View File

@ -132,6 +132,8 @@ int sqlite3WalHeapMemory(Wal *pWal);
int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
int sqlite3WalSnapshotRecover(Wal *pWal);
int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot);
void sqlite3WalSnapshotUnlock(Wal *pWal);
#endif
#ifdef SQLITE_ENABLE_ZIPVFS

View File

@ -217,9 +217,19 @@ foreach {tn tcl} {
SELECT * FROM t2;
}
} {a b c d e f}
do_test $tn.3.2.2 {
list [catch {snapshot_open db main $snapshot } msg] $msg
# Update - it is no longer an error to have a read-transaction open,
# provided there are no active SELECT statements.
do_test $tn.3.2.2a {
db eval "SELECT * FROM t2" {
set res [list [catch {snapshot_open db main $snapshot } msg] $msg]
break
}
set res
} {1 SQLITE_ERROR}
do_test $tn.3.2.2b {
snapshot_open db main $snapshot
} {}
do_test $tn.3.2.3 {
execsql {
@ -231,12 +241,17 @@ foreach {tn tcl} {
} {1 SQLITE_ERROR}
do_execsql_test $tn.3.2.4 COMMIT
do_test $tn.3.3.1 {
do_test $tn.3.3.1a {
execsql { PRAGMA journal_mode = DELETE }
execsql { BEGIN }
list [catch {snapshot_open db main $snapshot } msg] $msg
} {1 SQLITE_ERROR}
do_test $tn.3.3.1b {
execsql { COMMIT ; BEGIN ; SELECT * FROM t2 }
list [catch {snapshot_open db main $snapshot } msg] $msg
} {1 SQLITE_ERROR}
do_test $tn.$tn.3.3.2 {
snapshot_free $snapshot
execsql COMMIT

184
test/snapshot_up.test Normal file
View File

@ -0,0 +1,184 @@
# 2018 August 6
#
# 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.
#
#***********************************************************************
#
# Tests for calling sqlite3_snapshot_open() when there is already
# a read transaction open on the database.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !snapshot {finish_test; return}
set testprefix snapshot_up
# This test does not work with the inmemory_journal permutation. The reason
# is that each connection opened as part of this permutation executes
# "PRAGMA journal_mode=memory", which fails if the database is in wal mode
# and there are one or more existing connections.
if {[permutation]=="inmemory_journal"} {
finish_test
return
}
do_execsql_test 1.0 {
CREATE TABLE t1(a, b, c);
PRAGMA journal_mode = wal;
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES(4, 5, 6);
INSERT INTO t1 VALUES(7, 8, 9);
} {wal}
do_test 1.1 {
execsql BEGIN
set ::snap1 [sqlite3_snapshot_get db main]
execsql COMMIT
execsql { INSERT INTO t1 VALUES(10, 11, 12); }
execsql BEGIN
set ::snap2 [sqlite3_snapshot_get db main]
execsql COMMIT
execsql { INSERT INTO t1 VALUES(13, 14, 15); }
execsql BEGIN
set ::snap3 [sqlite3_snapshot_get db main]
execsql COMMIT
} {}
do_execsql_test 1.2 {
BEGIN;
SELECT * FROM t1
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15}
do_test 1.3 {
sqlite3_snapshot_open db main $::snap1
execsql { SELECT * FROM t1 }
} {1 2 3 4 5 6 7 8 9}
do_test 1.4 {
sqlite3_snapshot_open db main $::snap2
execsql { SELECT * FROM t1 }
} {1 2 3 4 5 6 7 8 9 10 11 12}
do_test 1.5 {
sqlite3 db2 test.db
execsql { PRAGMA wal_checkpoint } db2
} {0 5 4}
do_execsql_test 1.6 {
SELECT * FROM t1
} {1 2 3 4 5 6 7 8 9 10 11 12}
do_test 1.7 {
list [catch { sqlite3_snapshot_open db main $::snap1 } msg] $msg
} {1 SQLITE_BUSY_SNAPSHOT}
do_execsql_test 1.8 {
SELECT * FROM t1
} {1 2 3 4 5 6 7 8 9 10 11 12}
do_test 1.9 {
execsql { COMMIT ; BEGIN }
list [catch { sqlite3_snapshot_open db main $::snap1 } msg] $msg
} {1 SQLITE_BUSY_SNAPSHOT}
do_test 1.10 {
execsql { COMMIT }
execsql {
PRAGMA wal_checkpoint;
DELETE FROM t1 WHERE a = 1;
} db2
execsql BEGIN
set ::snap4 [sqlite3_snapshot_get db main]
execsql COMMIT
execsql {
DELETE FROM t1 WHERE a = 4;
} db2
} {}
do_test 1.11 {
execsql {
BEGIN;
SELECT * FROM t1
}
} {7 8 9 10 11 12 13 14 15}
do_test 1.12 {
sqlite3_snapshot_open db main $::snap4
execsql { SELECT * FROM t1 }
} {4 5 6 7 8 9 10 11 12 13 14 15}
do_test 1.13 {
list [catch { sqlite3_snapshot_open db main $::snap3 } msg] $msg
} {1 SQLITE_BUSY_SNAPSHOT}
do_test 1.14 {
execsql { SELECT * FROM t1 }
} {4 5 6 7 8 9 10 11 12 13 14 15}
db close
db2 close
sqlite3 db test.db
do_execsql_test 1.15 {
BEGIN;
SELECT * FROM t1
} {7 8 9 10 11 12 13 14 15}
do_test 1.16 {
list [catch { sqlite3_snapshot_open db main $::snap4 } msg] $msg
} {1 SQLITE_BUSY_SNAPSHOT}
do_execsql_test 1.17 { COMMIT }
sqlite3_snapshot_free $::snap1
sqlite3_snapshot_free $::snap2
sqlite3_snapshot_free $::snap3
sqlite3_snapshot_free $::snap4
#-------------------------------------------------------------------------
catch { db close }
sqlite3 db test.db
sqlite3 db2 test.db
sqlite3 db3 test.db
proc xBusy {args} { return 1 }
db3 busy xBusy
do_test 2.1 {
execsql { INSERT INTO t1 VALUES(16, 17, 18) } db2
execsql BEGIN
set ::snap1 [sqlite3_snapshot_get db main]
execsql COMMIT
execsql { INSERT INTO t1 VALUES(19, 20, 21) } db2
execsql BEGIN
set ::snap2 [sqlite3_snapshot_get db main]
execsql COMMIT
set {} {}
} {}
do_execsql_test -db db2 2.2 {
BEGIN;
INSERT INTO t1 VALUES(19, 20, 21);
}
do_test 2.3 {
execsql BEGIN
sqlite3_snapshot_open db main $::snap1
execsql { SELECT * FROM t1 }
} {7 8 9 10 11 12 13 14 15 16 17 18}
proc xBusy {args} {
set ::res [list [catch { sqlite3_snapshot_open db main $::snap2 } msg] $msg]
return 1
}
db3 busy xBusy
do_test 2.4 {
execsql {PRAGMA wal_checkpoint = restart} db3
set ::res
} {1 SQLITE_BUSY}
sqlite3_snapshot_free $::snap1
sqlite3_snapshot_free $::snap2
finish_test