Allow sqlite3_snapshot_open() to be called to change the snapshot after a read
transaction is already open on database. FossilOrigin-Name: 41399169954f9bef53c3fa89879f39823b80bd127f76cf60abbe24217878a571
This commit is contained in:
commit
588032fe33
30
manifest
30
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\sUPSERT\sso\sthat\sit\schecks\sthe\starget-constraint\sfirst\sand\sfires\sthe\nDO\sUPDATE\sif\sthat\sconstraint\sis\sviolated\sregardless\sof\swhether\sor\snot\nother\sconstraints\sare\sin\sviolation.\s\sThis\saligns\sSQLite\sbehavior\swith\nwhat\sPostgreSQL\sdoes.\sFix\sfor\sticket\s[908f001483982c43cdb476dfb590a1a].
|
||||
D 2018-08-14T15:12:52.710
|
||||
C Allow\ssqlite3_snapshot_open()\sto\sbe\scalled\sto\schange\sthe\ssnapshot\safter\sa\sread\ntransaction\sis\salready\sopen\son\sdatabase.
|
||||
D 2018-08-15T14:03:26.955
|
||||
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 c723716f0de7aa0a679300f7d3541c89645f4a9882161cecdb3093fc07f8cc4b
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
|
||||
F src/main.c df233667bbb6f05a8492ea93e0995abbeb816eab53e51e638a0dece1de0e83a3
|
||||
F src/main.c 187011ff7a091ff4b8bea9481a42789c0fa094715b4e5d89352fb63377673490
|
||||
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 e681b2a3ab1085be3eb2e81254449782ca0bd0c38b73c48cb0c2480b8f2f25b9
|
||||
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 c617d78715e85d81fe5719b276d32186a37eb47a49d07a3d55ddbc541de043c9
|
||||
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
||||
F src/wal.c e4bcbd90072e9626126d6f3b8411159a0b984c1b9628d15237776578d5eda12d
|
||||
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,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P e3ea43dabf099dc2954c23d348638e7b2a8b9122d2994154bc649a2c09260c46
|
||||
R 57b28032d1f7240227e60efc94d5cf5d
|
||||
U drh
|
||||
Z f4b7118e2c3ed77a16d581f95e6f4881
|
||||
P 529fb55e3d00472f13446117527b0896827b11e870b581af7fe7cbb7392ef3cd 051ac0152048ef52723196c26ca5f2629dafb782aec1c66fc30531bf54335043
|
||||
R f512847bc3fbc8f671b8d43110416970
|
||||
T +closed 051ac0152048ef52723196c26ca5f2629dafb782aec1c66fc30531bf54335043
|
||||
U dan
|
||||
Z 161902ccd44d5b310812ea403a55d987
|
||||
|
@ -1 +1 @@
|
||||
529fb55e3d00472f13446117527b0896827b11e870b581af7fe7cbb7392ef3cd
|
||||
41399169954f9bef53c3fa89879f39823b80bd127f76cf60abbe24217878a571
|
24
src/main.c
24
src/main.c
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
32
src/pager.c
32
src/pager.c
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
37
src/wal.c
37
src/wal.c
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
184
test/snapshot_up.test
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user