mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-18 10:21:03 +03:00
Merge the experimental UNDELETABLE_WHEN_OPEN optimization into the trunk.
FossilOrigin-Name: ee0acef1faffd480fd2136f81fb2b6f6a17b5388
This commit is contained in:
46
manifest
46
manifest
@@ -1,8 +1,8 @@
|
|||||||
-----BEGIN PGP SIGNED MESSAGE-----
|
-----BEGIN PGP SIGNED MESSAGE-----
|
||||||
Hash: SHA1
|
Hash: SHA1
|
||||||
|
|
||||||
C Fix\san\suninitialized\svariable\sin\sos_unix.c.
|
C Merge\sthe\sexperimental\sUNDELETABLE_WHEN_OPEN\soptimization\sinto\sthe\strunk.
|
||||||
D 2010-06-19T23:53:11
|
D 2010-06-21T12:47:41
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -157,9 +157,9 @@ F src/os.c 9c4a2f82a50306a33907678ec0187b6ad1486bfe
|
|||||||
F src/os.h d7775504a51e6e0d40315aa427b3e229ff9ff9ca
|
F src/os.h d7775504a51e6e0d40315aa427b3e229ff9ff9ca
|
||||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||||
F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19
|
F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19
|
||||||
F src/os_unix.c 838e0c0cabb722ac573c8cbd666b47bdf44eb8f9
|
F src/os_unix.c 5231a75a3799872b1250bc70c0e6a1a5960bc865
|
||||||
F src/os_win.c dfde7d33c446e89dd9a277c036f2c4cc564b3138
|
F src/os_win.c 73608839342de32280cb378d3c2fc85a5dd80bd2
|
||||||
F src/pager.c 4fe451d68950002eb985e6325d666ab54956a37f
|
F src/pager.c 9f138b79b47090c1e31efe3d9ea191cc92981643
|
||||||
F src/pager.h ca1f23c0cf137ac26f8908df2427c8b308361efd
|
F src/pager.h ca1f23c0cf137ac26f8908df2427c8b308361efd
|
||||||
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
||||||
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
|
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
|
||||||
@@ -173,7 +173,7 @@ F src/resolve.c ac5f1a713cd1ae77f08b83cc69581e11bf5ae6f9
|
|||||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||||
F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b
|
F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b
|
||||||
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
|
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
|
||||||
F src/sqlite.h.in 46c01e55cea31b91565ae41276c6310ee4032be8
|
F src/sqlite.h.in 301476d8556cbb1c5d4bc906370b2dafe4d98a44
|
||||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||||
F src/sqliteInt.h 242987ebd2366ea36650a09cdab04a9163c62109
|
F src/sqliteInt.h 242987ebd2366ea36650a09cdab04a9163c62109
|
||||||
F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
|
F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
|
||||||
@@ -212,7 +212,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
|||||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||||
F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
|
F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
|
||||||
F src/test_vfs.c 001c34e08748a4a02cd1c2d5531c160a007a84d8
|
F src/test_vfs.c 9ba0bb227f5fa08d7e3533ff21063c5acf13dabb
|
||||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||||
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
||||||
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
|
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
|
||||||
@@ -220,12 +220,12 @@ F src/update.c 9859f2056c7739a1db0d9774ccb6c2f0cee6d1de
|
|||||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||||
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
|
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
|
||||||
F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f
|
F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f
|
||||||
F src/vdbe.c e115585b14d2cc4128cb53a7e42f207750e80f55
|
F src/vdbe.c 290d20ed92b560dc0b602ac50b252f9553a2d8e8
|
||||||
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
|
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
|
||||||
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
|
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
|
||||||
F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d
|
F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d
|
||||||
F src/vdbeaux.c 4e96a5169b988a8697d4a417f902277b4152e43e
|
F src/vdbeaux.c 4e96a5169b988a8697d4a417f902277b4152e43e
|
||||||
F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
|
F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
|
||||||
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
||||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||||
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
||||||
@@ -469,8 +469,9 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
|||||||
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
|
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
|
||||||
F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
|
F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
|
||||||
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
|
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
|
||||||
|
F test/journal2.test a08ea6545d987385e7cbb1d4e7dc2eaacd83b00b
|
||||||
F test/jrnlmode.test 76f94d61528c5ff32102a12f8cf34f4cc36f7849
|
F test/jrnlmode.test 76f94d61528c5ff32102a12f8cf34f4cc36f7849
|
||||||
F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd
|
F test/jrnlmode2.test a19e28de1a6ec898067e46a122f1b71c9323bf00
|
||||||
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
|
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
|
||||||
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
|
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
|
||||||
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
|
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
|
||||||
@@ -511,7 +512,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
|||||||
F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d
|
F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d
|
||||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||||
F test/malloc_common.tcl fbf369eb2828825c5f319c101917aff91ea87556
|
F test/malloc_common.tcl 58caffc4be307b56c5b1438b5eba3eb278bd81f5
|
||||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||||
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
||||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||||
@@ -536,13 +537,14 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db
|
|||||||
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
|
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
|
||||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||||
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
|
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
|
||||||
F test/pager1.test 60dec408563461f9fbf04d4d301b1b4db23f7525
|
F test/pager1.test 86d034bf3ffe4e99648714443776440d0555f705
|
||||||
F test/pagerfault.test 16e560bc4332d5b089b369d82ae4b65b8805b5eb
|
F test/pager2.test ad062a51030dc1e2749f506528db4cc5bae6474c
|
||||||
|
F test/pagerfault.test e67e9c18bf7b4bb8cc8d458d3a5ecc980f18a225
|
||||||
F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
|
F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
|
||||||
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
||||||
F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58
|
F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58
|
||||||
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
||||||
F test/permutations.test f044eaba204ff13d530ceb72a22b0ed2c43562ef
|
F test/permutations.test 9296368f1d14d9e042f146a804ca38f551d35435
|
||||||
F test/pragma.test 6960f9efbce476f70ba9ee2171daf5042f9e3d8a
|
F test/pragma.test 6960f9efbce476f70ba9ee2171daf5042f9e3d8a
|
||||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||||
@@ -613,7 +615,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
|
|||||||
F test/tempdb.test 800c36623d67a2ad1f58784b9c5644e0405af6e6
|
F test/tempdb.test 800c36623d67a2ad1f58784b9c5644e0405af6e6
|
||||||
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
||||||
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
|
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
|
||||||
F test/tester.tcl 7912c3c8768320fd7bcb217637c2f0a607fbbc24
|
F test/tester.tcl ab89e8e592ff26e2b65ff3cae9de5f26863ae766
|
||||||
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
|
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
|
||||||
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
|
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
|
||||||
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
|
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
|
||||||
@@ -780,7 +782,7 @@ F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
|
|||||||
F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
|
F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
|
||||||
F test/walfault.test c2b524299dede269282a0795e11396cc446ca9af
|
F test/walfault.test c2b524299dede269282a0795e11396cc446ca9af
|
||||||
F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
|
F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
|
||||||
F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
|
F test/walmode.test b54e2f91f34179c65cab02a6916578617a33eef0
|
||||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||||
F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
|
F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
|
||||||
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
||||||
@@ -826,14 +828,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
|||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||||
P 2241788bc85fbc48e9cfecb95fe0a858338e37cb
|
P 822a0283c6bc1c75001f3d1c528a4ff89c6b039c a64d96db09ef2b7651fa4e98d3c7bf3ae5d3fe96
|
||||||
R 519d2c82f8071bfeedb3eae3a50de5e0
|
R aa81338105a8066f92038016780c9df7
|
||||||
U drh
|
U drh
|
||||||
Z fb28c7b4632831ff9010ebcbf771882d
|
Z e0549d09ee79c82d436d5aa9bbd618a3
|
||||||
-----BEGIN PGP SIGNATURE-----
|
-----BEGIN PGP SIGNATURE-----
|
||||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||||
|
|
||||||
iD8DBQFMHVhqoxKgR168RlERAl0KAJ0Yf2pBemdWub4Zh3gc9Vg3H0bRrgCfb73m
|
iD8DBQFMH19xoxKgR168RlERAt6AAJ96RqboVXAAENNG3NTV/9NSo4zbEgCghTxO
|
||||||
7DvKYVz1pMDVAwrfS/3PYDY=
|
GuKlnNnL+XTagpq68iLKUhk=
|
||||||
=DvU8
|
=R4ik
|
||||||
-----END PGP SIGNATURE-----
|
-----END PGP SIGNATURE-----
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
822a0283c6bc1c75001f3d1c528a4ff89c6b039c
|
ee0acef1faffd480fd2136f81fb2b6f6a17b5388
|
||||||
@@ -4604,6 +4604,12 @@ static int unixAccess(
|
|||||||
assert(!"Invalid flags argument");
|
assert(!"Invalid flags argument");
|
||||||
}
|
}
|
||||||
*pResOut = (access(zPath, amode)==0);
|
*pResOut = (access(zPath, amode)==0);
|
||||||
|
if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
|
||||||
|
struct stat buf;
|
||||||
|
if( 0==stat(zPath, &buf) && buf.st_size==0 ){
|
||||||
|
*pResOut = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1151,7 +1151,7 @@ static int winSectorSize(sqlite3_file *id){
|
|||||||
*/
|
*/
|
||||||
static int winDeviceCharacteristics(sqlite3_file *id){
|
static int winDeviceCharacteristics(sqlite3_file *id){
|
||||||
UNUSED_PARAMETER(id);
|
UNUSED_PARAMETER(id);
|
||||||
return 0;
|
return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|||||||
28
src/pager.c
28
src/pager.c
@@ -1219,12 +1219,24 @@ static int pagerUseWal(Pager *pPager){
|
|||||||
static void pager_unlock(Pager *pPager){
|
static void pager_unlock(Pager *pPager){
|
||||||
if( !pPager->exclusiveMode ){
|
if( !pPager->exclusiveMode ){
|
||||||
int rc = SQLITE_OK; /* Return code */
|
int rc = SQLITE_OK; /* Return code */
|
||||||
|
int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0;
|
||||||
|
|
||||||
/* Always close the journal file when dropping the database lock.
|
/* Always close the journal file when dropping the database lock.
|
||||||
** Otherwise, another connection with journal_mode=delete might
|
** Otherwise, another connection with journal_mode=delete might
|
||||||
** delete the file out from under us.
|
** delete the file out from under us.
|
||||||
*/
|
*/
|
||||||
|
assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 );
|
||||||
|
assert( (PAGER_JOURNALMODE_OFF & 5)!=1 );
|
||||||
|
assert( (PAGER_JOURNALMODE_WAL & 5)!=1 );
|
||||||
|
assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 );
|
||||||
|
assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
|
||||||
|
assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
|
||||||
|
if( 0==(iDc & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN)
|
||||||
|
|| 1!=(pPager->journalMode & 5)
|
||||||
|
){
|
||||||
sqlite3OsClose(pPager->jfd);
|
sqlite3OsClose(pPager->jfd);
|
||||||
|
}
|
||||||
|
|
||||||
sqlite3BitvecDestroy(pPager->pInJournal);
|
sqlite3BitvecDestroy(pPager->pInJournal);
|
||||||
pPager->pInJournal = 0;
|
pPager->pInJournal = 0;
|
||||||
releaseAllSavepoints(pPager);
|
releaseAllSavepoints(pPager);
|
||||||
@@ -3115,6 +3127,7 @@ int sqlite3PagerClose(Pager *pPager){
|
|||||||
enable_simulated_io_errors();
|
enable_simulated_io_errors();
|
||||||
PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
|
PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
|
||||||
IOTRACE(("CLOSE %p\n", pPager))
|
IOTRACE(("CLOSE %p\n", pPager))
|
||||||
|
sqlite3OsClose(pPager->jfd);
|
||||||
sqlite3OsClose(pPager->fd);
|
sqlite3OsClose(pPager->fd);
|
||||||
sqlite3PageFree(pTmp);
|
sqlite3PageFree(pTmp);
|
||||||
sqlite3PcacheClose(pPager->pPCache);
|
sqlite3PcacheClose(pPager->pPCache);
|
||||||
@@ -3908,17 +3921,22 @@ int sqlite3PagerOpen(
|
|||||||
*/
|
*/
|
||||||
static int hasHotJournal(Pager *pPager, int *pExists){
|
static int hasHotJournal(Pager *pPager, int *pExists){
|
||||||
sqlite3_vfs * const pVfs = pPager->pVfs;
|
sqlite3_vfs * const pVfs = pPager->pVfs;
|
||||||
int rc; /* Return code */
|
int rc = SQLITE_OK; /* Return code */
|
||||||
int exists; /* True if a journal file is present */
|
int exists = 1; /* True if a journal file is present */
|
||||||
|
int jrnlOpen = !!isOpen(pPager->jfd);
|
||||||
|
|
||||||
assert( pPager!=0 );
|
assert( pPager!=0 );
|
||||||
assert( pPager->useJournal );
|
assert( pPager->useJournal );
|
||||||
assert( isOpen(pPager->fd) );
|
assert( isOpen(pPager->fd) );
|
||||||
assert( !isOpen(pPager->jfd) );
|
|
||||||
assert( pPager->state <= PAGER_SHARED );
|
assert( pPager->state <= PAGER_SHARED );
|
||||||
|
assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
|
||||||
|
SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
|
||||||
|
));
|
||||||
|
|
||||||
*pExists = 0;
|
*pExists = 0;
|
||||||
|
if( !jrnlOpen ){
|
||||||
rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
|
rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
|
||||||
|
}
|
||||||
if( rc==SQLITE_OK && exists ){
|
if( rc==SQLITE_OK && exists ){
|
||||||
int locked; /* True if some process holds a RESERVED lock */
|
int locked; /* True if some process holds a RESERVED lock */
|
||||||
|
|
||||||
@@ -3956,15 +3974,19 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
|||||||
** If there is, then we consider this journal to be hot. If not,
|
** If there is, then we consider this journal to be hot. If not,
|
||||||
** it can be ignored.
|
** it can be ignored.
|
||||||
*/
|
*/
|
||||||
|
if( !jrnlOpen ){
|
||||||
int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
|
int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
|
||||||
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
|
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
|
||||||
|
}
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
u8 first = 0;
|
u8 first = 0;
|
||||||
rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
|
rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
|
||||||
if( rc==SQLITE_IOERR_SHORT_READ ){
|
if( rc==SQLITE_IOERR_SHORT_READ ){
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
if( !jrnlOpen ){
|
||||||
sqlite3OsClose(pPager->jfd);
|
sqlite3OsClose(pPager->jfd);
|
||||||
|
}
|
||||||
*pExists = (first!=0);
|
*pExists = (first!=0);
|
||||||
}else if( rc==SQLITE_CANTOPEN ){
|
}else if( rc==SQLITE_CANTOPEN ){
|
||||||
/* If we cannot open the rollback journal file in order to see if
|
/* If we cannot open the rollback journal file in order to see if
|
||||||
|
|||||||
@@ -508,6 +508,7 @@ int sqlite3_exec(
|
|||||||
#define SQLITE_IOCAP_ATOMIC64K 0x00000100
|
#define SQLITE_IOCAP_ATOMIC64K 0x00000100
|
||||||
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
|
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
|
||||||
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
|
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
|
||||||
|
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: File Locking Levels
|
** CAPI3REF: File Locking Levels
|
||||||
|
|||||||
263
src/test_vfs.c
263
src/test_vfs.c
@@ -58,6 +58,13 @@ struct Testvfs {
|
|||||||
int iIoerrCnt;
|
int iIoerrCnt;
|
||||||
int ioerr;
|
int ioerr;
|
||||||
int nIoerrFail;
|
int nIoerrFail;
|
||||||
|
|
||||||
|
int iFullCnt;
|
||||||
|
int fullerr;
|
||||||
|
int nFullFail;
|
||||||
|
|
||||||
|
int iDevchar;
|
||||||
|
int iSectorsize;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -77,7 +84,10 @@ struct Testvfs {
|
|||||||
#define TESTVFS_OPEN_MASK 0x00000100
|
#define TESTVFS_OPEN_MASK 0x00000100
|
||||||
#define TESTVFS_SYNC_MASK 0x00000200
|
#define TESTVFS_SYNC_MASK 0x00000200
|
||||||
#define TESTVFS_DELETE_MASK 0x00000400
|
#define TESTVFS_DELETE_MASK 0x00000400
|
||||||
#define TESTVFS_ALL_MASK 0x000007FF
|
#define TESTVFS_CLOSE_MASK 0x00000800
|
||||||
|
#define TESTVFS_WRITE_MASK 0x00001000
|
||||||
|
#define TESTVFS_TRUNCATE_MASK 0x00002000
|
||||||
|
#define TESTVFS_ALL_MASK 0x00003FFF
|
||||||
|
|
||||||
|
|
||||||
#define TESTVFS_MAX_PAGES 256
|
#define TESTVFS_MAX_PAGES 256
|
||||||
@@ -187,6 +197,30 @@ static int tvfsResultCode(Testvfs *p, int *pRc){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tvfsInjectIoerr(Testvfs *p){
|
||||||
|
int ret = 0;
|
||||||
|
if( p->ioerr ){
|
||||||
|
p->iIoerrCnt--;
|
||||||
|
if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){
|
||||||
|
ret = 1;
|
||||||
|
p->nIoerrFail++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tvfsInjectFullerr(Testvfs *p){
|
||||||
|
int ret = 0;
|
||||||
|
if( p->fullerr ){
|
||||||
|
p->iFullCnt--;
|
||||||
|
if( p->iFullCnt<=0 ){
|
||||||
|
ret = 1;
|
||||||
|
p->nFullFail++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void tvfsExecTcl(
|
static void tvfsExecTcl(
|
||||||
Testvfs *p,
|
Testvfs *p,
|
||||||
@@ -245,15 +279,23 @@ static void tvfsExecTcl(
|
|||||||
** Close an tvfs-file.
|
** Close an tvfs-file.
|
||||||
*/
|
*/
|
||||||
static int tvfsClose(sqlite3_file *pFile){
|
static int tvfsClose(sqlite3_file *pFile){
|
||||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||||
if( p->pShmId ){
|
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
|
||||||
Tcl_DecrRefCount(p->pShmId);
|
|
||||||
p->pShmId = 0;
|
if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){
|
||||||
|
tvfsExecTcl(p, "xClose",
|
||||||
|
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pFd->pShmId ){
|
||||||
|
Tcl_DecrRefCount(pFd->pShmId);
|
||||||
|
pFd->pShmId = 0;
|
||||||
}
|
}
|
||||||
if( pFile->pMethods ){
|
if( pFile->pMethods ){
|
||||||
ckfree((char *)pFile->pMethods);
|
ckfree((char *)pFile->pMethods);
|
||||||
}
|
}
|
||||||
return sqlite3OsClose(p->pReal);
|
return sqlite3OsClose(pFd->pReal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -278,16 +320,44 @@ static int tvfsWrite(
|
|||||||
int iAmt,
|
int iAmt,
|
||||||
sqlite_int64 iOfst
|
sqlite_int64 iOfst
|
||||||
){
|
){
|
||||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
int rc = SQLITE_OK;
|
||||||
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
|
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||||
|
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
|
||||||
|
|
||||||
|
if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){
|
||||||
|
tvfsExecTcl(p, "xWrite",
|
||||||
|
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0
|
||||||
|
);
|
||||||
|
tvfsResultCode(p, &rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL;
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Truncate an tvfs-file.
|
** Truncate an tvfs-file.
|
||||||
*/
|
*/
|
||||||
static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
int rc = SQLITE_OK;
|
||||||
return sqlite3OsTruncate(p->pReal, size);
|
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||||
|
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
|
||||||
|
|
||||||
|
if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){
|
||||||
|
tvfsExecTcl(p, "xTruncate",
|
||||||
|
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0
|
||||||
|
);
|
||||||
|
tvfsResultCode(p, &rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = sqlite3OsTruncate(pFd->pReal, size);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -325,6 +395,8 @@ static int tvfsSync(sqlite3_file *pFile, int flags){
|
|||||||
tvfsResultCode(p, &rc);
|
tvfsResultCode(p, &rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL;
|
||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3OsSync(pFd->pReal, flags);
|
rc = sqlite3OsSync(pFd->pReal, flags);
|
||||||
}
|
}
|
||||||
@@ -376,16 +448,24 @@ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
|
|||||||
** Return the sector-size in bytes for an tvfs-file.
|
** Return the sector-size in bytes for an tvfs-file.
|
||||||
*/
|
*/
|
||||||
static int tvfsSectorSize(sqlite3_file *pFile){
|
static int tvfsSectorSize(sqlite3_file *pFile){
|
||||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||||
return sqlite3OsSectorSize(p->pReal);
|
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
|
||||||
|
if( p->iSectorsize>=0 ){
|
||||||
|
return p->iSectorsize;
|
||||||
|
}
|
||||||
|
return sqlite3OsSectorSize(pFd->pReal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return the device characteristic flags supported by an tvfs-file.
|
** Return the device characteristic flags supported by an tvfs-file.
|
||||||
*/
|
*/
|
||||||
static int tvfsDeviceCharacteristics(sqlite3_file *pFile){
|
static int tvfsDeviceCharacteristics(sqlite3_file *pFile){
|
||||||
TestvfsFile *p = (TestvfsFile *)pFile;
|
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||||
return sqlite3OsDeviceCharacteristics(p->pReal);
|
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
|
||||||
|
if( p->iDevchar>=0 ){
|
||||||
|
return p->iDevchar;
|
||||||
|
}
|
||||||
|
return sqlite3OsDeviceCharacteristics(pFd->pReal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -555,18 +635,6 @@ static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
|||||||
return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut);
|
return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tvfsInjectIoerr(Testvfs *p){
|
|
||||||
int ret = 0;
|
|
||||||
if( p->ioerr ){
|
|
||||||
p->iIoerrCnt--;
|
|
||||||
if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){
|
|
||||||
ret = 1;
|
|
||||||
p->nIoerrFail++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tvfsShmOpen(
|
static int tvfsShmOpen(
|
||||||
sqlite3_file *pFileDes
|
sqlite3_file *pFileDes
|
||||||
){
|
){
|
||||||
@@ -782,25 +850,38 @@ static int testvfs_obj_cmd(
|
|||||||
){
|
){
|
||||||
Testvfs *p = (Testvfs *)cd;
|
Testvfs *p = (Testvfs *)cd;
|
||||||
|
|
||||||
static const char *CMD_strs[] = {
|
|
||||||
"shm", "delete", "filter", "ioerr", "script", 0
|
|
||||||
};
|
|
||||||
enum DB_enum {
|
enum DB_enum {
|
||||||
CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT
|
CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT,
|
||||||
|
CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR
|
||||||
|
};
|
||||||
|
struct TestvfsSubcmd {
|
||||||
|
char *zName;
|
||||||
|
enum DB_enum eCmd;
|
||||||
|
} aSubcmd[] = {
|
||||||
|
{ "shm", CMD_SHM },
|
||||||
|
{ "delete", CMD_DELETE },
|
||||||
|
{ "filter", CMD_FILTER },
|
||||||
|
{ "ioerr", CMD_IOERR },
|
||||||
|
{ "fullerr", CMD_FULLERR },
|
||||||
|
{ "script", CMD_SCRIPT },
|
||||||
|
{ "devchar", CMD_DEVCHAR },
|
||||||
|
{ "sectorsize", CMD_SECTORSIZE },
|
||||||
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( objc<2 ){
|
if( objc<2 ){
|
||||||
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
|
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
if( Tcl_GetIndexFromObj(interp, objv[1], CMD_strs, "subcommand", 0, &i) ){
|
if( Tcl_GetIndexFromObjStruct(
|
||||||
|
interp, objv[1], aSubcmd, sizeof(aSubcmd[0]), "subcommand", 0, &i)
|
||||||
|
){
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
Tcl_ResetResult(interp);
|
Tcl_ResetResult(interp);
|
||||||
|
|
||||||
switch( (enum DB_enum)i ){
|
switch( aSubcmd[i].eCmd ){
|
||||||
case CMD_SHM: {
|
case CMD_SHM: {
|
||||||
Tcl_Obj *pObj;
|
Tcl_Obj *pObj;
|
||||||
int i;
|
int i;
|
||||||
@@ -857,7 +938,10 @@ static int testvfs_obj_cmd(
|
|||||||
{ "xShmMap", TESTVFS_SHMMAP_MASK },
|
{ "xShmMap", TESTVFS_SHMMAP_MASK },
|
||||||
{ "xSync", TESTVFS_SYNC_MASK },
|
{ "xSync", TESTVFS_SYNC_MASK },
|
||||||
{ "xDelete", TESTVFS_DELETE_MASK },
|
{ "xDelete", TESTVFS_DELETE_MASK },
|
||||||
|
{ "xWrite", TESTVFS_WRITE_MASK },
|
||||||
|
{ "xTruncate", TESTVFS_TRUNCATE_MASK },
|
||||||
{ "xOpen", TESTVFS_OPEN_MASK },
|
{ "xOpen", TESTVFS_OPEN_MASK },
|
||||||
|
{ "xClose", TESTVFS_CLOSE_MASK },
|
||||||
};
|
};
|
||||||
Tcl_Obj **apElem = 0;
|
Tcl_Obj **apElem = 0;
|
||||||
int nElem = 0;
|
int nElem = 0;
|
||||||
@@ -915,6 +999,34 @@ static int testvfs_obj_cmd(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** TESTVFS fullerr ?IFAIL?
|
||||||
|
**
|
||||||
|
** Where IFAIL is an integer.
|
||||||
|
*/
|
||||||
|
case CMD_FULLERR: {
|
||||||
|
int iRet = p->nFullFail;
|
||||||
|
|
||||||
|
p->nFullFail = 0;
|
||||||
|
p->fullerr = 0;
|
||||||
|
p->iFullCnt = 0;
|
||||||
|
|
||||||
|
if( objc==3 ){
|
||||||
|
int iCnt;
|
||||||
|
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt) ){
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
p->fullerr = (iCnt>0);
|
||||||
|
p->iFullCnt = iCnt;
|
||||||
|
}else if( objc!=2 ){
|
||||||
|
Tcl_AppendResult(interp, "Bad args", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** TESTVFS ioerr ?IFAIL PERSIST?
|
** TESTVFS ioerr ?IFAIL PERSIST?
|
||||||
**
|
**
|
||||||
@@ -948,6 +1060,89 @@ static int testvfs_obj_cmd(
|
|||||||
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
|
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CMD_DEVCHAR: {
|
||||||
|
struct DeviceFlag {
|
||||||
|
char *zName;
|
||||||
|
int iValue;
|
||||||
|
} aFlag[] = {
|
||||||
|
{ "default", -1 },
|
||||||
|
{ "atomic", SQLITE_IOCAP_ATOMIC },
|
||||||
|
{ "atomic512", SQLITE_IOCAP_ATOMIC512 },
|
||||||
|
{ "atomic1k", SQLITE_IOCAP_ATOMIC1K },
|
||||||
|
{ "atomic2k", SQLITE_IOCAP_ATOMIC2K },
|
||||||
|
{ "atomic4k", SQLITE_IOCAP_ATOMIC4K },
|
||||||
|
{ "atomic8k", SQLITE_IOCAP_ATOMIC8K },
|
||||||
|
{ "atomic16k", SQLITE_IOCAP_ATOMIC16K },
|
||||||
|
{ "atomic32k", SQLITE_IOCAP_ATOMIC32K },
|
||||||
|
{ "atomic64k", SQLITE_IOCAP_ATOMIC64K },
|
||||||
|
{ "sequential", SQLITE_IOCAP_SEQUENTIAL },
|
||||||
|
{ "safe_append", SQLITE_IOCAP_SAFE_APPEND },
|
||||||
|
{ "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN },
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
Tcl_Obj *pRet;
|
||||||
|
int iFlag;
|
||||||
|
|
||||||
|
if( objc>3 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( objc==3 ){
|
||||||
|
int j;
|
||||||
|
int iNew = 0;
|
||||||
|
Tcl_Obj **flags = 0;
|
||||||
|
int nFlags = 0;
|
||||||
|
|
||||||
|
if( Tcl_ListObjGetElements(interp, objv[2], &nFlags, &flags) ){
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j=0; j<nFlags; j++){
|
||||||
|
int idx = 0;
|
||||||
|
if( Tcl_GetIndexFromObjStruct(interp, flags[j], aFlag,
|
||||||
|
sizeof(aFlag[0]), "flag", 0, &idx)
|
||||||
|
){
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( aFlag[idx].iValue<0 && nFlags>1 ){
|
||||||
|
Tcl_AppendResult(interp, "bad flags: ", Tcl_GetString(objv[2]), 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
iNew |= aFlag[idx].iValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->iDevchar = iNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRet = Tcl_NewObj();
|
||||||
|
for(iFlag=0; iFlag<sizeof(aFlag)/sizeof(aFlag[0]); iFlag++){
|
||||||
|
if( p->iDevchar & aFlag[iFlag].iValue ){
|
||||||
|
Tcl_ListObjAppendElement(
|
||||||
|
interp, pRet, Tcl_NewStringObj(aFlag[iFlag].zName, -1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tcl_SetObjResult(interp, pRet);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_SECTORSIZE: {
|
||||||
|
if( objc>3 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 2, objv, "?VALUE?");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( objc==3 ){
|
||||||
|
int iNew = 0;
|
||||||
|
if( Tcl_GetIntFromObj(interp, objv[2], &iNew) ){
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
p->iSectorsize = iNew;
|
||||||
|
}
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewIntObj(p->iSectorsize));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
@@ -1067,6 +1262,8 @@ static int testvfs_cmd(
|
|||||||
nByte = sizeof(Testvfs) + strlen(zVfs)+1;
|
nByte = sizeof(Testvfs) + strlen(zVfs)+1;
|
||||||
p = (Testvfs *)ckalloc(nByte);
|
p = (Testvfs *)ckalloc(nByte);
|
||||||
memset(p, 0, nByte);
|
memset(p, 0, nByte);
|
||||||
|
p->iDevchar = -1;
|
||||||
|
p->iSectorsize = -1;
|
||||||
|
|
||||||
/* Create the new object command before querying SQLite for a default VFS
|
/* Create the new object command before querying SQLite for a default VFS
|
||||||
** to use for 'real' IO operations. This is because creating the new VFS
|
** to use for 'real' IO operations. This is because creating the new VFS
|
||||||
|
|||||||
11
src/vdbe.c
11
src/vdbe.c
@@ -5248,8 +5248,6 @@ case OP_JournalMode: { /* out2-prerelease */
|
|||||||
rc = sqlite3PagerCloseWal(pPager);
|
rc = sqlite3PagerCloseWal(pPager);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
sqlite3PagerSetJournalMode(pPager, eNew);
|
sqlite3PagerSetJournalMode(pPager, eNew);
|
||||||
}else if( rc==SQLITE_BUSY && pOp->p5==0 ){
|
|
||||||
goto abort_due_to_error;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5259,16 +5257,15 @@ case OP_JournalMode: { /* out2-prerelease */
|
|||||||
assert( sqlite3BtreeIsInTrans(pBt)==0 );
|
assert( sqlite3BtreeIsInTrans(pBt)==0 );
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
|
rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
|
||||||
if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error;
|
|
||||||
}
|
|
||||||
if( rc==SQLITE_BUSY ){
|
|
||||||
eNew = eOld;
|
|
||||||
rc = SQLITE_OK;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* ifndef SQLITE_OMIT_WAL */
|
#endif /* ifndef SQLITE_OMIT_WAL */
|
||||||
|
|
||||||
|
if( rc ){
|
||||||
|
if( rc==SQLITE_BUSY && pOp->p5!=0 ) rc = SQLITE_OK;
|
||||||
|
eNew = eOld;
|
||||||
|
}
|
||||||
eNew = sqlite3PagerSetJournalMode(pPager, eNew);
|
eNew = sqlite3PagerSetJournalMode(pPager, eNew);
|
||||||
|
|
||||||
pOut = &aMem[pOp->p2];
|
pOut = &aMem[pOp->p2];
|
||||||
|
|||||||
@@ -191,10 +191,14 @@ int sqlite3_blob_open(
|
|||||||
sqlite3VdbeUsesBtree(v, iDb);
|
sqlite3VdbeUsesBtree(v, iDb);
|
||||||
|
|
||||||
/* Configure the OP_TableLock instruction */
|
/* Configure the OP_TableLock instruction */
|
||||||
|
#ifdef SQLITE_OMIT_SHARED_CACHE
|
||||||
|
sqlite3VdbeChangeToNoop(v, 2, 1);
|
||||||
|
#else
|
||||||
sqlite3VdbeChangeP1(v, 2, iDb);
|
sqlite3VdbeChangeP1(v, 2, iDb);
|
||||||
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
|
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
|
||||||
sqlite3VdbeChangeP3(v, 2, flags);
|
sqlite3VdbeChangeP3(v, 2, flags);
|
||||||
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
|
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
||||||
** parameter of the other to pTab->tnum. */
|
** parameter of the other to pTab->tnum. */
|
||||||
|
|||||||
228
test/journal2.test
Normal file
228
test/journal2.test
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
# 2010 June 16
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
source $testdir/lock_common.tcl
|
||||||
|
source $testdir/malloc_common.tcl
|
||||||
|
db close
|
||||||
|
|
||||||
|
set a_string_counter 1
|
||||||
|
proc a_string {n} {
|
||||||
|
global a_string_counter
|
||||||
|
incr a_string_counter
|
||||||
|
string range [string repeat "${a_string_counter}." $n] 1 $n
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a [testvfs] and install it as the default VFS. Set the device
|
||||||
|
# characteristics flags to "SAFE_DELETE".
|
||||||
|
#
|
||||||
|
testvfs tvfs -default 1
|
||||||
|
tvfs devchar undeletable_when_open
|
||||||
|
|
||||||
|
# Set up a hook so that each time a journal file is opened, closed or
|
||||||
|
# deleted, the method name ("xOpen", "xClose" or "xDelete") and the final
|
||||||
|
# segment of the journal file-name (i.e. "test.db-journal") are appended to
|
||||||
|
# global list variable $::oplog.
|
||||||
|
#
|
||||||
|
tvfs filter {xOpen xClose xDelete}
|
||||||
|
tvfs script journal_op_catcher
|
||||||
|
proc journal_op_catcher {method filename args} {
|
||||||
|
|
||||||
|
# If global variable ::tvfs_error_on_write is defined, then return an
|
||||||
|
# IO error to every attempt to modify the file-system. Otherwise, return
|
||||||
|
# SQLITE_OK.
|
||||||
|
#
|
||||||
|
if {[info exists ::tvfs_error_on_write]} {
|
||||||
|
if {[lsearch {xDelete xWrite xTruncate} $method]>=0} {
|
||||||
|
return SQLITE_IOERR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# The rest of this command only deals with xOpen(), xClose() and xDelete()
|
||||||
|
# operations on journal files. If this invocation does not represent such
|
||||||
|
# an operation, return with no further ado.
|
||||||
|
#
|
||||||
|
set f [file tail $filename]
|
||||||
|
if {[string match *journal $f]==0} return
|
||||||
|
if {[lsearch {xOpen xDelete xClose} $method]<0} return
|
||||||
|
|
||||||
|
# Append a record of this operation to global list variable $::oplog.
|
||||||
|
#
|
||||||
|
lappend ::oplog $method $f
|
||||||
|
|
||||||
|
# If this is an attempt to delete a journal file for which there exists
|
||||||
|
# one ore more open handles, return an error. The code in test_vfs.c
|
||||||
|
# will not invoke the xDelete method of the "real" VFS in this case.
|
||||||
|
#
|
||||||
|
if {[info exists ::open_journals($f)]==0} { set ::open_journals($f) 0 }
|
||||||
|
switch -- $method {
|
||||||
|
xOpen { incr ::open_journals($f) +1 }
|
||||||
|
xClose { incr ::open_journals($f) -1 }
|
||||||
|
xDelete { if {$::open_journals($f)>0} { return SQLITE_IOERR } }
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_test journal2-1.1 {
|
||||||
|
set ::oplog [list]
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql { CREATE TABLE t1(a, b) }
|
||||||
|
set ::oplog
|
||||||
|
} {xOpen test.db-journal xClose test.db-journal xDelete test.db-journal}
|
||||||
|
do_test journal2-1.2 {
|
||||||
|
set ::oplog [list]
|
||||||
|
execsql {
|
||||||
|
PRAGMA journal_mode = truncate;
|
||||||
|
INSERT INTO t1 VALUES(1, 2);
|
||||||
|
}
|
||||||
|
set ::oplog
|
||||||
|
} {xOpen test.db-journal}
|
||||||
|
do_test journal2-1.3 {
|
||||||
|
set ::oplog [list]
|
||||||
|
execsql { INSERT INTO t1 VALUES(3, 4) }
|
||||||
|
set ::oplog
|
||||||
|
} {}
|
||||||
|
do_test journal2-1.4 { execsql { SELECT * FROM t1 } } {1 2 3 4}
|
||||||
|
|
||||||
|
# Add a second connection. This connection attempts to commit data in
|
||||||
|
# journal_mode=DELETE mode. When it tries to delete the journal file,
|
||||||
|
# the VFS layer returns an IO error.
|
||||||
|
#
|
||||||
|
do_test journal2-1.5 {
|
||||||
|
set ::oplog [list]
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
execsql { PRAGMA journal_mode = delete } db2
|
||||||
|
catchsql { INSERT INTO t1 VALUES(5, 6) } db2
|
||||||
|
} {1 {disk I/O error}}
|
||||||
|
do_test journal2-1.6 { file exists test.db-journal } 1
|
||||||
|
do_test journal2-1.7 { execsql { SELECT * FROM t1 } } {1 2 3 4}
|
||||||
|
do_test journal2-1.8 {
|
||||||
|
execsql { PRAGMA journal_mode = truncate } db2
|
||||||
|
execsql { INSERT INTO t1 VALUES(5, 6) } db2
|
||||||
|
} {}
|
||||||
|
do_test journal2-1.9 { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6}
|
||||||
|
|
||||||
|
# Grow the database until it is reasonably large.
|
||||||
|
#
|
||||||
|
do_test journal2-1.10 {
|
||||||
|
db2 close
|
||||||
|
db func a_string a_string
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t2(a UNIQUE, b UNIQUE);
|
||||||
|
INSERT INTO t2 VALUES(a_string(200), a_string(300));
|
||||||
|
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 2
|
||||||
|
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 4
|
||||||
|
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 8
|
||||||
|
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 16
|
||||||
|
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 32
|
||||||
|
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 64
|
||||||
|
}
|
||||||
|
file size test.db-journal
|
||||||
|
} {0}
|
||||||
|
do_test journal2-1.11 {
|
||||||
|
set sz [expr [file size test.db] / 1024]
|
||||||
|
expr {$sz>120 && $sz<200}
|
||||||
|
} 1
|
||||||
|
|
||||||
|
# Using new connection [db2] (with journal_mode=DELETE), write a lot of
|
||||||
|
# data to the database. So that many pages within the database file are
|
||||||
|
# modified before the transaction is committed.
|
||||||
|
#
|
||||||
|
# Then, enable simulated IO errors in all calls to xDelete, xWrite
|
||||||
|
# and xTruncate before committing the transaction and closing the
|
||||||
|
# database file. From the point of view of other file-system users, it
|
||||||
|
# appears as if the process hosting [db2] unexpectedly exited.
|
||||||
|
#
|
||||||
|
do_test journal2-1.12 {
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
execsql {
|
||||||
|
PRAGMA cache_size = 10;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 SELECT randomblob(200), randomblob(300) FROM t2; -- 128
|
||||||
|
} db2
|
||||||
|
} {}
|
||||||
|
do_test journal2-1.13 {
|
||||||
|
tvfs filter {xOpen xClose xDelete xWrite xTruncate}
|
||||||
|
set ::tvfs_error_on_write 1
|
||||||
|
catchsql { COMMIT } db2
|
||||||
|
} {1 {disk I/O error}}
|
||||||
|
db2 close
|
||||||
|
unset ::tvfs_error_on_write
|
||||||
|
file copy -force test.db testX.db
|
||||||
|
|
||||||
|
do_test journal2-1.14 { file exists test.db-journal } 1
|
||||||
|
do_test journal2-1.15 {
|
||||||
|
execsql {
|
||||||
|
SELECT count(*) FROM t2;
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
}
|
||||||
|
} {64 ok}
|
||||||
|
|
||||||
|
# This block checks that in the test case above, connection [db2] really
|
||||||
|
# did begin writing to the database file before it hit IO errors. If
|
||||||
|
# this is true, then the copy of the database file made before [db]
|
||||||
|
# rolled back the hot journal should fail the integrity-check.
|
||||||
|
#
|
||||||
|
do_test journal2-1.16 {
|
||||||
|
set sz [expr [file size testX.db] / 1024]
|
||||||
|
expr {$sz>240 && $sz<400}
|
||||||
|
} 1
|
||||||
|
do_test journal2-1.17 {
|
||||||
|
expr {[catchsql { PRAGMA integrity_check } db] == "0 ok"}
|
||||||
|
} {1}
|
||||||
|
do_test journal2-1.20 {
|
||||||
|
sqlite3 db2 testX.db
|
||||||
|
expr {[catchsql { PRAGMA integrity_check } db2] == "0 ok"}
|
||||||
|
} {0}
|
||||||
|
do_test journal2-1.21 {
|
||||||
|
db2 close
|
||||||
|
} {}
|
||||||
|
db close
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Test that it is possible to switch from journal_mode=truncate to
|
||||||
|
# journal_mode=WAL on a SAFE_DELETE file-system. SQLite should close and
|
||||||
|
# delete the journal file when committing the transaction that switches
|
||||||
|
# the system to WAL mode.
|
||||||
|
#
|
||||||
|
ifcapable wal {
|
||||||
|
do_test journal2-2.1 {
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
set ::oplog [list]
|
||||||
|
execsql { PRAGMA journal_mode = persist }
|
||||||
|
set ::oplog
|
||||||
|
} {}
|
||||||
|
do_test journal2-2.2 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t1(x);
|
||||||
|
INSERT INTO t1 VALUES(3.14159);
|
||||||
|
}
|
||||||
|
set ::oplog
|
||||||
|
} {xOpen test.db-journal}
|
||||||
|
do_test journal2-2.3 {
|
||||||
|
expr {[file size test.db-journal] > 512}
|
||||||
|
} {1}
|
||||||
|
do_test journal2-2.4 {
|
||||||
|
set ::oplog [list]
|
||||||
|
execsql { PRAGMA journal_mode = WAL }
|
||||||
|
set ::oplog
|
||||||
|
} {xClose test.db-journal xDelete test.db-journal}
|
||||||
|
db close
|
||||||
|
}
|
||||||
|
|
||||||
|
tvfs delete
|
||||||
|
finish_test
|
||||||
|
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
#
|
#
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
#
|
#
|
||||||
# $Id: jrnlmode2.test,v 1.6 2009/06/05 17:09:12 drh Exp $
|
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -20,10 +19,33 @@ ifcapable {!pager_pragmas} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
# Test overview:
|
# The tests in this file check that the following two bugs (both now fixed)
|
||||||
|
# do not reappear.
|
||||||
#
|
#
|
||||||
# jrnlmode2-1.*: Demonstrate bug #3745
|
# jrnlmode2-1.*: Demonstrate bug #3745:
|
||||||
# jrnlmode2-2.*: Demonstrate bug #3751
|
#
|
||||||
|
# In persistent journal mode, if:
|
||||||
|
#
|
||||||
|
# * There is a persistent journal in the file-system, AND
|
||||||
|
# * there exists a connection with a shared lock on the db file,
|
||||||
|
#
|
||||||
|
# then a second connection cannot open a read-transaction on the database.
|
||||||
|
# The reason is because while determining that the persistent-journal is
|
||||||
|
# not a hot-journal, SQLite currently grabs an exclusive lock on the
|
||||||
|
# database file. If this fails because another connection has a shared
|
||||||
|
# lock, then SQLITE_BUSY is returned to the user.
|
||||||
|
#
|
||||||
|
# jrnlmode2-2.*: Demonstrate bug #3751:
|
||||||
|
#
|
||||||
|
# If a connection is opened in SQLITE_OPEN_READONLY mode, the underlying
|
||||||
|
# unix file descriptor on the database file is opened in O_RDONLY mode.
|
||||||
|
#
|
||||||
|
# When SQLite queries the database file for the schema in order to compile
|
||||||
|
# the SELECT statement, it sees the empty journal in the file system, it
|
||||||
|
# attempts to obtain an exclusive lock on the database file (this is a
|
||||||
|
# bug). The attempt to obtain an exclusive (write) lock on a read-only file
|
||||||
|
# fails at the OS level. Under unix, fcntl() reports an EBADF - "Bad file
|
||||||
|
# descriptor" - error.
|
||||||
#
|
#
|
||||||
|
|
||||||
do_test jrnlmode2-1.1 {
|
do_test jrnlmode2-1.1 {
|
||||||
@@ -46,6 +68,8 @@ do_test jrnlmode2-1.3 {
|
|||||||
do_test jrnlmode2-1.4 {
|
do_test jrnlmode2-1.4 {
|
||||||
execsql {
|
execsql {
|
||||||
INSERT INTO t1 VALUES(3, 4);
|
INSERT INTO t1 VALUES(3, 4);
|
||||||
|
}
|
||||||
|
execsql {
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
}
|
}
|
||||||
@@ -87,9 +111,9 @@ do_test jrnlmode2-2.4 {
|
|||||||
} {0 {1 2 3 4 5 6}}
|
} {0 {1 2 3 4 5 6}}
|
||||||
|
|
||||||
do_test jrnlmode2-2.5 {
|
do_test jrnlmode2-2.5 {
|
||||||
|
db close
|
||||||
file delete test.db-journal
|
file delete test.db-journal
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
do_test jrnlmode2-2.6 {
|
do_test jrnlmode2-2.6 {
|
||||||
sqlite3 db2 test.db -readonly 1
|
sqlite3 db2 test.db -readonly 1
|
||||||
catchsql { SELECT * FROM t1 } db2
|
catchsql { SELECT * FROM t1 } db2
|
||||||
|
|||||||
@@ -49,6 +49,16 @@ set FAULTSIM(ioerr-persistent) [list \
|
|||||||
-injecterrlist {{1 {disk I/O error}}} \
|
-injecterrlist {{1 {disk I/O error}}} \
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# SQLITE_FULL errors (always persistent):
|
||||||
|
#
|
||||||
|
set FAULTSIM(full) [list \
|
||||||
|
-injectinstall fullerr_injectinstall \
|
||||||
|
-injectstart fullerr_injectstart \
|
||||||
|
-injectstop fullerr_injectstop \
|
||||||
|
-injecterrlist {{1 {database or disk is full}}} \
|
||||||
|
-injectuninstall fullerr_injectuninstall \
|
||||||
|
]
|
||||||
|
|
||||||
# Transient and persistent SHM errors:
|
# Transient and persistent SHM errors:
|
||||||
#
|
#
|
||||||
set FAULTSIM(shmerr-transient) [list \
|
set FAULTSIM(shmerr-transient) [list \
|
||||||
@@ -126,14 +136,14 @@ proc faultsim_save_and_close {} {
|
|||||||
catch { db close }
|
catch { db close }
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
proc faultsim_restore_and_reopen {} {
|
proc faultsim_restore_and_reopen {{dbfile test.db}} {
|
||||||
catch { db close }
|
catch { db close }
|
||||||
foreach f [glob -nocomplain test.db*] { file delete -force $f }
|
foreach f [glob -nocomplain test.db*] { file delete -force $f }
|
||||||
foreach f2 [glob -nocomplain sv_test.db*] {
|
foreach f2 [glob -nocomplain sv_test.db*] {
|
||||||
set f [string range $f2 3 end]
|
set f [string range $f2 3 end]
|
||||||
file copy -force $f2 $f
|
file copy -force $f2 $f
|
||||||
}
|
}
|
||||||
sqlite3 db test.db
|
sqlite3 db $dbfile
|
||||||
sqlite3_extended_result_codes db 1
|
sqlite3_extended_result_codes db 1
|
||||||
sqlite3_db_config_lookaside db 0 0 0
|
sqlite3_db_config_lookaside db 0 0 0
|
||||||
}
|
}
|
||||||
@@ -146,7 +156,7 @@ proc faultsim_integrity_check {{db db}} {
|
|||||||
proc faultsim_delete_and_reopen {{file test.db}} {
|
proc faultsim_delete_and_reopen {{file test.db}} {
|
||||||
catch { db close }
|
catch { db close }
|
||||||
foreach f [glob -nocomplain test.db*] { file delete -force $f }
|
foreach f [glob -nocomplain test.db*] { file delete -force $f }
|
||||||
sqlite3 db test.db
|
sqlite3 db $file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -177,6 +187,7 @@ proc ioerr_injectstop {} {
|
|||||||
return $sv
|
return $sv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# The following procs are used as [do_one_faultsim_test] callbacks when
|
# The following procs are used as [do_one_faultsim_test] callbacks when
|
||||||
# injecting shared-memory related error faults into test cases.
|
# injecting shared-memory related error faults into test cases.
|
||||||
#
|
#
|
||||||
@@ -195,6 +206,22 @@ proc shmerr_injectstop {} {
|
|||||||
shmfault ioerr 0 0
|
shmfault ioerr 0 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc fullerr_injectinstall {} {
|
||||||
|
testvfs shmfault -default true
|
||||||
|
}
|
||||||
|
proc fullerr_injectuninstall {} {
|
||||||
|
catch {db close}
|
||||||
|
catch {db2 close}
|
||||||
|
shmfault delete
|
||||||
|
}
|
||||||
|
proc fullerr_injectstart {iFail} {
|
||||||
|
shmfault full $iFail
|
||||||
|
}
|
||||||
|
proc fullerr_injectstop {} {
|
||||||
|
shmfault full 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# This command is not called directly. It is used by the
|
# This command is not called directly. It is used by the
|
||||||
# [faultsim_test_result] command created by [do_faultsim_test] and used
|
# [faultsim_test_result] command created by [do_faultsim_test] and used
|
||||||
# by -test scripts.
|
# by -test scripts.
|
||||||
|
|||||||
448
test/pager1.test
448
test/pager1.test
@@ -14,6 +14,7 @@ set testdir [file dirname $argv0]
|
|||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
source $testdir/lock_common.tcl
|
source $testdir/lock_common.tcl
|
||||||
source $testdir/malloc_common.tcl
|
source $testdir/malloc_common.tcl
|
||||||
|
source $testdir/wal_common.tcl
|
||||||
|
|
||||||
#
|
#
|
||||||
# pager1-1.*: Test inter-process locking (clients in multiple processes).
|
# pager1-1.*: Test inter-process locking (clients in multiple processes).
|
||||||
@@ -22,13 +23,14 @@ source $testdir/malloc_common.tcl
|
|||||||
#
|
#
|
||||||
# pager1-3.*: Savepoint related tests.
|
# pager1-3.*: Savepoint related tests.
|
||||||
#
|
#
|
||||||
|
# pager1-4.*: Hot-journal related tests.
|
||||||
proc do_execsql_test {testname sql result} {
|
#
|
||||||
uplevel do_test $testname [list "execsql {$sql}"] [list $result]
|
# pager1-5.*: Cases related to multi-file commits.
|
||||||
}
|
#
|
||||||
proc do_catchsql_test {testname sql result} {
|
# pager1-6.*: Cases related to "PRAGMA max_page_count"
|
||||||
uplevel do_test $testname [list "catchsql {$sql}"] [list $result]
|
#
|
||||||
}
|
# pager1-7.*: Cases specific to "PRAGMA journal_mode=TRUNCATE"
|
||||||
|
#
|
||||||
|
|
||||||
set a_string_counter 1
|
set a_string_counter 1
|
||||||
proc a_string {n} {
|
proc a_string {n} {
|
||||||
@@ -222,6 +224,17 @@ do_execsql_test pager1-3.6 { COMMIT } {}
|
|||||||
# xAccess() call to check for the presence of any master
|
# xAccess() call to check for the presence of any master
|
||||||
# journal file is made).
|
# journal file is made).
|
||||||
#
|
#
|
||||||
|
# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the
|
||||||
|
# page-size or sector-size in the journal header appear to
|
||||||
|
# be invalid (too large, too small or not a power of 2).
|
||||||
|
#
|
||||||
|
# pager1.4.4.*: Test hot-journal rollback of journal file with a master
|
||||||
|
# journal pointer generated in various "PRAGMA synchronous"
|
||||||
|
# modes.
|
||||||
|
#
|
||||||
|
# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a
|
||||||
|
# journal-record for which the checksum fails.
|
||||||
|
#
|
||||||
do_test pager1.4.1.1 {
|
do_test pager1.4.1.1 {
|
||||||
faultsim_delete_and_reopen
|
faultsim_delete_and_reopen
|
||||||
execsql {
|
execsql {
|
||||||
@@ -308,5 +321,426 @@ do_test pager1.4.2.5 {
|
|||||||
}
|
}
|
||||||
} {4 ok}
|
} {4 ok}
|
||||||
|
|
||||||
|
do_test pager1.4.3.1 {
|
||||||
|
testvfs tstvfs -default 1
|
||||||
|
tstvfs filter xSync
|
||||||
|
tstvfs script xSyncCallback
|
||||||
|
proc xSyncCallback {method file args} {
|
||||||
|
set file [file tail $file]
|
||||||
|
if { 0==[string match *journal $file] } { faultsim_save }
|
||||||
|
}
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
execsql {
|
||||||
|
PRAGMA journal_mode = DELETE;
|
||||||
|
CREATE TABLE t1(a, b);
|
||||||
|
INSERT INTO t1 VALUES(1, 2);
|
||||||
|
INSERT INTO t1 VALUES(3, 4);
|
||||||
|
}
|
||||||
|
db close
|
||||||
|
tstvfs delete
|
||||||
|
} {}
|
||||||
|
|
||||||
|
foreach {tn ofst value result} {
|
||||||
|
2 20 31 {1 2 3 4}
|
||||||
|
3 20 32 {1 2 3 4}
|
||||||
|
4 20 33 {1 2 3 4}
|
||||||
|
5 20 65536 {1 2 3 4}
|
||||||
|
6 20 131072 {1 2 3 4}
|
||||||
|
|
||||||
|
7 24 511 {1 2 3 4}
|
||||||
|
8 24 513 {1 2 3 4}
|
||||||
|
9 24 65536 {1 2 3 4}
|
||||||
|
|
||||||
|
10 32 65536 {1 2}
|
||||||
|
} {
|
||||||
|
do_test pager1.4.3.$tn {
|
||||||
|
faultsim_restore_and_reopen
|
||||||
|
hexio_write test.db-journal $ofst [format %.8x $value]
|
||||||
|
execsql { SELECT * FROM t1 }
|
||||||
|
} $result
|
||||||
|
}
|
||||||
|
db close
|
||||||
|
|
||||||
|
# Set up a VFS that snapshots the file-system just before a master journal
|
||||||
|
# file is deleted to commit a multi-file transaction. Specifically, the
|
||||||
|
# file-system is saved just before the xDelete() call to remove the
|
||||||
|
# master journal file from the file-system.
|
||||||
|
#
|
||||||
|
testvfs tv -default 1
|
||||||
|
tv script copy_on_mj_delete
|
||||||
|
set ::mj_filename_length 0
|
||||||
|
proc copy_on_mj_delete {method filename args} {
|
||||||
|
if {[string match *mj* [file tail $filename]]} {
|
||||||
|
set ::mj_filename_length [string length $filename]
|
||||||
|
faultsim_save
|
||||||
|
}
|
||||||
|
return SQLITE_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
set pwd [pwd]
|
||||||
|
foreach {tn1 tcl} {
|
||||||
|
1 { set prefix "test.db" }
|
||||||
|
2 {
|
||||||
|
# This test depends on the underlying VFS being able to open paths
|
||||||
|
# 512 bytes in length. The idea is to create a hot-journal file that
|
||||||
|
# contains a master-journal pointer so large that it could contain
|
||||||
|
# a valid page record (if the file page-size is 512 bytes). So as to
|
||||||
|
# make sure SQLite doesn't get confused by this.
|
||||||
|
#
|
||||||
|
set nPadding [expr 511 - $::mj_filename_length]
|
||||||
|
|
||||||
|
# We cannot just create a really long database file name to open, as
|
||||||
|
# Linux limits a single component of a path to 255 bytes by default
|
||||||
|
# (and presumably other systems have limits too). So create a directory
|
||||||
|
# hierarchy to work in.
|
||||||
|
#
|
||||||
|
set dirname "d123456789012345678901234567890/"
|
||||||
|
set nDir [expr $nPadding / 32]
|
||||||
|
if { $nDir } {
|
||||||
|
set p [string repeat $dirname $nDir]
|
||||||
|
file mkdir $p
|
||||||
|
cd $p
|
||||||
|
}
|
||||||
|
|
||||||
|
set padding [string repeat x [expr $nPadding %32]]
|
||||||
|
set prefix "test.db${padding}"
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
eval $tcl
|
||||||
|
foreach {tn2 sql} {
|
||||||
|
o {
|
||||||
|
PRAGMA main.synchronous=OFF;
|
||||||
|
PRAGMA aux.synchronous=OFF;
|
||||||
|
}
|
||||||
|
o512 {
|
||||||
|
PRAGMA main.synchronous=OFF;
|
||||||
|
PRAGMA aux.synchronous=OFF;
|
||||||
|
PRAGMA main.page_size = 512;
|
||||||
|
PRAGMA aux.page_size = 512;
|
||||||
|
}
|
||||||
|
n {
|
||||||
|
PRAGMA main.synchronous=NORMAL;
|
||||||
|
PRAGMA aux.synchronous=NORMAL;
|
||||||
|
}
|
||||||
|
f {
|
||||||
|
PRAGMA main.synchronous=FULL;
|
||||||
|
PRAGMA aux.synchronous=FULL;
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
|
||||||
|
set tn "${tn1}.${tn2}"
|
||||||
|
|
||||||
|
# Set up a connection to have two databases, test.db (main) and
|
||||||
|
# test.db2 (aux). Then run a multi-file transaction on them. The
|
||||||
|
# VFS will snapshot the file-system just before the master-journal
|
||||||
|
# file is deleted to commit the transaction.
|
||||||
|
#
|
||||||
|
tv filter xDelete
|
||||||
|
do_test pager1-4.4.$tn.1 {
|
||||||
|
faultsim_delete_and_reopen $prefix
|
||||||
|
execsql "
|
||||||
|
ATTACH '${prefix}2' AS aux;
|
||||||
|
$sql
|
||||||
|
CREATE TABLE a(x);
|
||||||
|
CREATE TABLE aux.b(x);
|
||||||
|
INSERT INTO a VALUES('double-you');
|
||||||
|
INSERT INTO a VALUES('why');
|
||||||
|
INSERT INTO a VALUES('zed');
|
||||||
|
INSERT INTO b VALUES('won');
|
||||||
|
INSERT INTO b VALUES('too');
|
||||||
|
INSERT INTO b VALUES('free');
|
||||||
|
"
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO a SELECT * FROM b WHERE rowid<=3;
|
||||||
|
INSERT INTO b SELECT * FROM a WHERE rowid<=3;
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
tv filter {}
|
||||||
|
|
||||||
|
# Check that the transaction was committed successfully.
|
||||||
|
#
|
||||||
|
do_execsql_test pager1-4.4.$tn.2 {
|
||||||
|
SELECT * FROM a
|
||||||
|
} {double-you why zed won too free}
|
||||||
|
do_execsql_test pager1-4.4.$tn.3 {
|
||||||
|
SELECT * FROM b
|
||||||
|
} {won too free double-you why zed}
|
||||||
|
|
||||||
|
# Restore the file-system and reopen the databases. Check that it now
|
||||||
|
# appears that the transaction was not committed (because the file-system
|
||||||
|
# was restored to the state where it had not been).
|
||||||
|
#
|
||||||
|
do_test pager1-4.4.$tn.4 {
|
||||||
|
faultsim_restore_and_reopen $prefix
|
||||||
|
execsql "ATTACH '${prefix}2' AS aux"
|
||||||
|
} {}
|
||||||
|
do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
|
||||||
|
do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
|
||||||
|
|
||||||
|
# Restore the file-system again. This time, before reopening the databases,
|
||||||
|
# delete the master-journal file from the file-system. It now appears that
|
||||||
|
# the transaction was committed (no master-journal file == no rollback).
|
||||||
|
#
|
||||||
|
do_test pager1-4.4.$tn.7 {
|
||||||
|
faultsim_restore_and_reopen $prefix
|
||||||
|
foreach f [glob ${prefix}-mj*] { file delete -force $f }
|
||||||
|
execsql "ATTACH '${prefix}2' AS aux"
|
||||||
|
} {}
|
||||||
|
do_execsql_test pager1-4.4.$tn.8 {
|
||||||
|
SELECT * FROM a
|
||||||
|
} {double-you why zed won too free}
|
||||||
|
do_execsql_test pager1-4.4.$tn.9 {
|
||||||
|
SELECT * FROM b
|
||||||
|
} {won too free double-you why zed}
|
||||||
|
}
|
||||||
|
|
||||||
|
cd $pwd
|
||||||
|
}
|
||||||
|
db close
|
||||||
|
tv delete
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# The following tests deal with multi-file commits.
|
||||||
|
#
|
||||||
|
# pager1-5.1.*: The case where a multi-file cannot be committed because
|
||||||
|
# another connection is holding a SHARED lock on one of the
|
||||||
|
# files. After the SHARED lock is removed, the COMMIT succeeds.
|
||||||
|
#
|
||||||
|
# pager1-5.2.*: Multi-file commits with journal_mode=memory.
|
||||||
|
#
|
||||||
|
# pager1-5.3.*: Multi-file commits with journal_mode=memory.
|
||||||
|
#
|
||||||
|
# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
|
||||||
|
# name is added to a journal file immediately after the last
|
||||||
|
# journal record. But with synchronous=full, extra unused space
|
||||||
|
# is allocated between the last journal record and the
|
||||||
|
# master-journal file name so that the master-journal file
|
||||||
|
# name does not lie on the same sector as the last journal file
|
||||||
|
# record.
|
||||||
|
#
|
||||||
|
# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
|
||||||
|
# truncated to zero bytes when a multi-file transaction is
|
||||||
|
# committed (instead of the first couple of bytes being zeroed).
|
||||||
|
#
|
||||||
|
#
|
||||||
|
do_test pager1-5.1.1 {
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
execsql {
|
||||||
|
ATTACH 'test.db2' AS aux;
|
||||||
|
CREATE TABLE t1(a, b);
|
||||||
|
CREATE TABLE aux.t2(a, b);
|
||||||
|
INSERT INTO t1 VALUES(17, 'Lenin');
|
||||||
|
INSERT INTO t1 VALUES(22, 'Stalin');
|
||||||
|
INSERT INTO t1 VALUES(53, 'Khrushchev');
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test pager1-5.1.2 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 VALUES(64, 'Brezhnev');
|
||||||
|
INSERT INTO t2 SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
sqlite3 db2 test.db2
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
SELECT * FROM t2;
|
||||||
|
} db2
|
||||||
|
} {}
|
||||||
|
do_test pager1-5.1.3 {
|
||||||
|
catchsql COMMIT
|
||||||
|
} {1 {database is locked}}
|
||||||
|
do_test pager1-5.1.4 {
|
||||||
|
execsql COMMIT db2
|
||||||
|
execsql COMMIT
|
||||||
|
execsql { SELECT * FROM t2 } db2
|
||||||
|
} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
|
||||||
|
do_test pager1-5.1.5 {
|
||||||
|
db2 close
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test pager1-5.2.1 {
|
||||||
|
execsql {
|
||||||
|
PRAGMA journal_mode = memory;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 VALUES(84, 'Andropov');
|
||||||
|
INSERT INTO t2 VALUES(84, 'Andropov');
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
} {memory}
|
||||||
|
do_test pager1-5.3.1 {
|
||||||
|
execsql {
|
||||||
|
PRAGMA journal_mode = off;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 VALUES(85, 'Gorbachev');
|
||||||
|
INSERT INTO t2 VALUES(85, 'Gorbachev');
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
} {off}
|
||||||
|
|
||||||
|
do_test pager1-5.4.1 {
|
||||||
|
db close
|
||||||
|
testvfs tv
|
||||||
|
sqlite3 db test.db -vfs tv
|
||||||
|
execsql { ATTACH 'test.db2' AS aux }
|
||||||
|
|
||||||
|
tv filter xDelete
|
||||||
|
tv script max_journal_size
|
||||||
|
tv sectorsize 512
|
||||||
|
set ::max_journal 0
|
||||||
|
proc max_journal_size {method args} {
|
||||||
|
set sz 0
|
||||||
|
catch { set sz [file size test.db-journal] }
|
||||||
|
if {$sz > $::max_journal} {
|
||||||
|
set ::max_journal $sz
|
||||||
|
}
|
||||||
|
return SQLITE_OK
|
||||||
|
}
|
||||||
|
execsql {
|
||||||
|
PRAGMA journal_mode = DELETE;
|
||||||
|
PRAGMA synchronous = NORMAL;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 VALUES(85, 'Gorbachev');
|
||||||
|
INSERT INTO t2 VALUES(85, 'Gorbachev');
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
set ::max_journal
|
||||||
|
} [expr 2615+[string length [pwd]]]
|
||||||
|
do_test pager1-5.4.2 {
|
||||||
|
set ::max_journal 0
|
||||||
|
execsql {
|
||||||
|
PRAGMA synchronous = full;
|
||||||
|
BEGIN;
|
||||||
|
DELETE FROM t1 WHERE b = 'Lenin';
|
||||||
|
DELETE FROM t2 WHERE b = 'Lenin';
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
set ::max_journal
|
||||||
|
} [expr 3111+[string length [pwd]]]
|
||||||
|
db close
|
||||||
|
tv delete
|
||||||
|
|
||||||
|
do_test pager1-5.5.1 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql {
|
||||||
|
ATTACH 'test.db2' AS aux;
|
||||||
|
PRAGMA journal_mode = PERSIST;
|
||||||
|
CREATE TABLE t3(a, b);
|
||||||
|
INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
|
||||||
|
UPDATE t3 SET b = randomblob(1500);
|
||||||
|
}
|
||||||
|
expr [file size test.db-journal] > 15000
|
||||||
|
} {1}
|
||||||
|
do_test pager1-5.5.2 {
|
||||||
|
execsql {
|
||||||
|
PRAGMA synchronous = full;
|
||||||
|
BEGIN;
|
||||||
|
DELETE FROM t1 WHERE b = 'Stalin';
|
||||||
|
DELETE FROM t2 WHERE b = 'Stalin';
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
file size test.db-journal
|
||||||
|
} {0}
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# The following tests work with "PRAGMA max_page_count"
|
||||||
|
#
|
||||||
|
do_test pager1-6.1 {
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
execsql {
|
||||||
|
PRAGMA max_page_count = 10;
|
||||||
|
CREATE TABLE t2(a, b);
|
||||||
|
CREATE TABLE t3(a, b);
|
||||||
|
CREATE TABLE t4(a, b);
|
||||||
|
CREATE TABLE t5(a, b);
|
||||||
|
CREATE TABLE t6(a, b);
|
||||||
|
CREATE TABLE t7(a, b);
|
||||||
|
CREATE TABLE t8(a, b);
|
||||||
|
CREATE TABLE t9(a, b);
|
||||||
|
CREATE TABLE t10(a, b);
|
||||||
|
}
|
||||||
|
} {10}
|
||||||
|
do_test pager1-6.2 {
|
||||||
|
catchsql {
|
||||||
|
CREATE TABLE t11(a, b);
|
||||||
|
}
|
||||||
|
} {1 {database or disk is full}}
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
|
||||||
|
# "PRAGMA locking_mode=EXCLUSIVE".
|
||||||
|
#
|
||||||
|
# Each test is specified with 5 variables. As follows:
|
||||||
|
#
|
||||||
|
# $tn: Test Number. Used as part of the [do_test] test names.
|
||||||
|
# $sql: SQL to execute.
|
||||||
|
# $res: Expected result of executing $sql.
|
||||||
|
# $js: The expected size of the journal file, in bytes, after executing
|
||||||
|
# the SQL script. Or -1 if the journal is not expected to exist.
|
||||||
|
# $ws: The expected size of the WAL file, in bytes, after executing
|
||||||
|
# the SQL script. Or -1 if the WAL is not expected to exist.
|
||||||
|
#
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
foreach {tn sql res js ws} [subst {
|
||||||
|
|
||||||
|
1 {
|
||||||
|
CREATE TABLE t1(a, b);
|
||||||
|
PRAGMA auto_vacuum=OFF;
|
||||||
|
PRAGMA synchronous=NORMAL;
|
||||||
|
PRAGMA page_size=1024;
|
||||||
|
PRAGMA locking_mode=EXCLUSIVE;
|
||||||
|
PRAGMA journal_mode=TRUNCATE;
|
||||||
|
INSERT INTO t1 VALUES(1, 2);
|
||||||
|
} {exclusive truncate} 0 -1
|
||||||
|
|
||||||
|
2 {
|
||||||
|
BEGIN IMMEDIATE;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
COMMIT;
|
||||||
|
} {1 2} 0 -1
|
||||||
|
|
||||||
|
3 {
|
||||||
|
BEGIN;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
COMMIT;
|
||||||
|
} {1 2} 0 -1
|
||||||
|
|
||||||
|
4 { PRAGMA journal_mode = WAL } wal -1 -1
|
||||||
|
5 { INSERT INTO t1 VALUES(3, 4) } {} -1 [wal_file_size 1 1024]
|
||||||
|
6 { PRAGMA locking_mode = NORMAL } normal -1 [wal_file_size 1 1024]
|
||||||
|
7 { INSERT INTO t1 VALUES(5, 6); } {} -1 [wal_file_size 2 1024]
|
||||||
|
|
||||||
|
8 { PRAGMA journal_mode = TRUNCATE } truncate 0 -1
|
||||||
|
9 { INSERT INTO t1 VALUES(7, 8) } {} 0 -1
|
||||||
|
10 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} 0 -1
|
||||||
|
|
||||||
|
}] {
|
||||||
|
do_execsql_test pager1-7.1.$tn.1 $sql $res
|
||||||
|
catch { set J -1 ; set J [file size test.db-journal] }
|
||||||
|
catch { set W -1 ; set W [file size test.db-wal] }
|
||||||
|
do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test pager1-8.1 {
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
db close
|
||||||
|
sqlite3 db :memory:
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE x1(x);
|
||||||
|
INSERT INTO x1 VALUES('Charles');
|
||||||
|
INSERT INTO x1 VALUES('James');
|
||||||
|
INSERT INTO x1 VALUES('Mary');
|
||||||
|
SELECT * FROM x1;
|
||||||
|
}
|
||||||
|
} {Charles James Mary}
|
||||||
|
do_test pager1-8.2 {
|
||||||
|
db close
|
||||||
|
sqlite3 db :memory:
|
||||||
|
catchsql { SELECT * FROM x1 }
|
||||||
|
} {1 {no such table: x1}}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
|
||||||
|
|||||||
117
test/pager2.test
Normal file
117
test/pager2.test
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
# 2010 June 15
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
source $testdir/lock_common.tcl
|
||||||
|
source $testdir/malloc_common.tcl
|
||||||
|
|
||||||
|
set otn 0
|
||||||
|
testvfs tv -default 1
|
||||||
|
foreach code [list {
|
||||||
|
set s 512
|
||||||
|
} {
|
||||||
|
set s 1024
|
||||||
|
set sql { PRAGMA journal_mode = memory }
|
||||||
|
} {
|
||||||
|
set s 1024
|
||||||
|
set sql {
|
||||||
|
PRAGMA journal_mode = memory;
|
||||||
|
PRAGMA locking_mode = exclusive;
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
set s 2048
|
||||||
|
tv devchar safe_append
|
||||||
|
} {
|
||||||
|
set s 4096
|
||||||
|
} {
|
||||||
|
set s 4096
|
||||||
|
set sql { PRAGMA journal_mode = WAL }
|
||||||
|
} {
|
||||||
|
set s 8192
|
||||||
|
set sql { PRAGMA synchronous = off }
|
||||||
|
}] {
|
||||||
|
|
||||||
|
incr otn
|
||||||
|
set sql ""
|
||||||
|
tv devchar {}
|
||||||
|
eval $code
|
||||||
|
tv sectorsize $s
|
||||||
|
|
||||||
|
do_test pager2-1.$otn.0 {
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
execsql $sql
|
||||||
|
execsql {
|
||||||
|
PRAGMA cache_size = 10;
|
||||||
|
CREATE TABLE t1(i INTEGER PRIMARY KEY, j blob);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
set tn 0
|
||||||
|
set lowpoint 0
|
||||||
|
foreach x {
|
||||||
|
100 x 0 100
|
||||||
|
x
|
||||||
|
70 22 96 59 96 50 22 56 21 16 37 64 43 40 0 38 22 38 55 0 6
|
||||||
|
43 62 32 93 54 18 13 29 45 66 29 25 61 31 53 82 75 25 96 86 10 69
|
||||||
|
2 29 6 60 80 95 42 82 85 50 68 96 90 39 78 69 87 97 48 74 65 43
|
||||||
|
x
|
||||||
|
86 34 26 50 41 85 58 44 89 22 6 51 45 46 58 32 97 6 1 12 32 2
|
||||||
|
69 39 48 71 33 31 5 58 90 43 24 54 12 9 18 57 4 38 91 42 27 45
|
||||||
|
50 38 56 29 10 0 26 37 83 1 78 15 47 30 75 62 46 29 68 5 30 4
|
||||||
|
27 96 33 95 79 75 56 10 29 70 32 75 52 88 5 36 50 57 46 63 88 65
|
||||||
|
x
|
||||||
|
44 95 64 20 24 35 69 61 61 2 35 92 42 46 23 98 78 1 38 72 79 35
|
||||||
|
94 37 13 59 5 93 27 58 80 75 58 7 67 13 10 76 84 4 8 70 81 45
|
||||||
|
8 41 98 5 60 26 92 29 91 90 2 62 40 4 5 22 80 15 83 76 52 88
|
||||||
|
29 5 68 73 72 7 54 17 89 32 81 94 51 28 53 71 8 42 54 59 70 79
|
||||||
|
x
|
||||||
|
} {
|
||||||
|
incr tn
|
||||||
|
set now [db one {SELECT count(i) FROM t1}]
|
||||||
|
if {$x == "x"} {
|
||||||
|
execsql { COMMIT ; BEGIN }
|
||||||
|
set lowpoint $now
|
||||||
|
do_test pager2.1.$otn.$tn {
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
execsql {
|
||||||
|
SELECT COALESCE(max(i), 0) FROM t1;
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
}
|
||||||
|
} [list $lowpoint ok]
|
||||||
|
db2 close
|
||||||
|
} else {
|
||||||
|
if {$now > $x } {
|
||||||
|
if { $x>=$lowpoint } {
|
||||||
|
execsql "ROLLBACK TO sp_$x"
|
||||||
|
} else {
|
||||||
|
execsql "DELETE FROM t1 WHERE i>$x"
|
||||||
|
set lowpoint $x
|
||||||
|
}
|
||||||
|
} elseif {$now < $x} {
|
||||||
|
for {set k $now} {$k < $x} {incr k} {
|
||||||
|
execsql "SAVEPOINT sp_$k"
|
||||||
|
execsql { INSERT INTO t1(j) VALUES(randomblob(1500)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_execsql_test pager2.1.$otn.$tn {
|
||||||
|
SELECT COALESCE(max(i), 0) FROM t1;
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
} [list $x ok]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db close
|
||||||
|
tv delete
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
||||||
@@ -54,11 +54,56 @@ do_faultsim_test pagerfault-1 -prep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Test fault-injection while rolling back a hot-journal file with a
|
||||||
|
# page-size different from the current value stored on page 1 of the
|
||||||
|
# database file.
|
||||||
|
#
|
||||||
|
do_test pagerfault-2-pre1 {
|
||||||
|
testvfs tv -default 1
|
||||||
|
tv filter xSync
|
||||||
|
tv script xSyncCb
|
||||||
|
proc xSyncCb {filename args} {
|
||||||
|
if {[string match *journal filename]==0} faultsim_save
|
||||||
|
}
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
execsql {
|
||||||
|
PRAGMA page_size = 4096;
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE abc(a, b, c);
|
||||||
|
INSERT INTO abc VALUES('o', 't', 't');
|
||||||
|
INSERT INTO abc VALUES('f', 'f', 's');
|
||||||
|
INSERT INTO abc SELECT * FROM abc; -- 4
|
||||||
|
INSERT INTO abc SELECT * FROM abc; -- 8
|
||||||
|
INSERT INTO abc SELECT * FROM abc; -- 16
|
||||||
|
INSERT INTO abc SELECT * FROM abc; -- 32
|
||||||
|
INSERT INTO abc SELECT * FROM abc; -- 64
|
||||||
|
INSERT INTO abc SELECT * FROM abc; -- 128
|
||||||
|
INSERT INTO abc SELECT * FROM abc; -- 256
|
||||||
|
COMMIT;
|
||||||
|
PRAGMA page_size = 1024;
|
||||||
|
VACUUM;
|
||||||
|
}
|
||||||
|
db close
|
||||||
|
tv delete
|
||||||
|
} {}
|
||||||
|
do_faultsim_test pagerfault-2 -prep {
|
||||||
|
faultsim_restore_and_reopen
|
||||||
|
} -body {
|
||||||
|
execsql { SELECT * FROM abc }
|
||||||
|
} -test {
|
||||||
|
set answer [split [string repeat "ottffs" 128] ""]
|
||||||
|
faultsim_test_result [list 0 $answer]
|
||||||
|
faultsim_integrity_check
|
||||||
|
set res [db eval { SELECT * FROM abc }]
|
||||||
|
if {$res != $answer} { error "Database content appears incorrect ($res)" }
|
||||||
|
} -faults oom-transient
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
# Test fault-injection while rolling back hot-journals that were created
|
# Test fault-injection while rolling back hot-journals that were created
|
||||||
# as part of a multi-file transaction.
|
# as part of a multi-file transaction.
|
||||||
#
|
#
|
||||||
do_test pagerfault-2-pre1 {
|
do_test pagerfault-3-pre1 {
|
||||||
testvfs tstvfs -default 1
|
testvfs tstvfs -default 1
|
||||||
tstvfs filter xDelete
|
tstvfs filter xDelete
|
||||||
tstvfs script xDeleteCallback
|
tstvfs script xDeleteCallback
|
||||||
@@ -96,7 +141,7 @@ do_test pagerfault-2-pre1 {
|
|||||||
db close
|
db close
|
||||||
tstvfs delete
|
tstvfs delete
|
||||||
} {}
|
} {}
|
||||||
do_faultsim_test pagerfault-2 -faults ioerr-persistent -prep {
|
do_faultsim_test pagerfault-3 -faults ioerr-persistent -prep {
|
||||||
faultsim_restore_and_reopen
|
faultsim_restore_and_reopen
|
||||||
} -body {
|
} -body {
|
||||||
execsql {
|
execsql {
|
||||||
@@ -107,7 +152,6 @@ do_faultsim_test pagerfault-2 -faults ioerr-persistent -prep {
|
|||||||
} -test {
|
} -test {
|
||||||
faultsim_test_result {0 {4 4}} {1 {unable to open database: test.db2}}
|
faultsim_test_result {0 {4 4}} {1 {unable to open database: test.db2}}
|
||||||
faultsim_integrity_check
|
faultsim_integrity_check
|
||||||
|
|
||||||
catchsql { ATTACH 'test.db2' AS aux }
|
catchsql { ATTACH 'test.db2' AS aux }
|
||||||
if {[db one { SELECT count(*) FROM t1 }] != 4
|
if {[db one { SELECT count(*) FROM t1 }] != 4
|
||||||
|| [db one { SELECT count(*) FROM t2 }] != 4
|
|| [db one { SELECT count(*) FROM t2 }] != 4
|
||||||
@@ -116,4 +160,151 @@ do_faultsim_test pagerfault-2 -faults ioerr-persistent -prep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Test fault-injection as part of a vanilla, no-transaction, INSERT
|
||||||
|
# statement.
|
||||||
|
#
|
||||||
|
do_faultsim_test pagerfault-4 -prep {
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
} -body {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE x(y);
|
||||||
|
INSERT INTO x VALUES('z');
|
||||||
|
SELECT * FROM x;
|
||||||
|
}
|
||||||
|
} -test {
|
||||||
|
faultsim_test_result {0 z}
|
||||||
|
faultsim_integrity_check
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Test fault-injection as part of a commit when using journal_mode=PERSIST.
|
||||||
|
# Three different cases:
|
||||||
|
#
|
||||||
|
# pagerfault-5.1: With no journal_size_limit configured.
|
||||||
|
# pagerfault-5.2: With a journal_size_limit configured.
|
||||||
|
# pagerfault-5.4: Multi-file transaction. One connection has a
|
||||||
|
# journal_size_limit of 0, the other has no limit.
|
||||||
|
#
|
||||||
|
do_test pagerfault-5-pre1 {
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
db func a_string a_string
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t1(a UNIQUE, b UNIQUE);
|
||||||
|
INSERT INTO t1 VALUES(a_string(200), a_string(300));
|
||||||
|
INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
|
||||||
|
}
|
||||||
|
faultsim_save_and_close
|
||||||
|
} {}
|
||||||
|
do_faultsim_test pagerfault-5.1 -prep {
|
||||||
|
faultsim_restore_and_reopen
|
||||||
|
db func a_string a_string
|
||||||
|
execsql { PRAGMA journal_mode = PERSIST }
|
||||||
|
} -body {
|
||||||
|
execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
|
||||||
|
} -test {
|
||||||
|
faultsim_test_result {0 {}}
|
||||||
|
faultsim_integrity_check
|
||||||
|
}
|
||||||
|
do_faultsim_test pagerfault-5.2 -prep {
|
||||||
|
faultsim_restore_and_reopen
|
||||||
|
db func a_string a_string
|
||||||
|
execsql {
|
||||||
|
PRAGMA journal_mode = PERSIST;
|
||||||
|
PRAGMA journal_size_limit = 2048;
|
||||||
|
}
|
||||||
|
} -body {
|
||||||
|
execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
|
||||||
|
} -test {
|
||||||
|
faultsim_test_result {0 {}}
|
||||||
|
faultsim_integrity_check
|
||||||
|
}
|
||||||
|
do_faultsim_test pagerfault-5.3 -prep {
|
||||||
|
faultsim_restore_and_reopen
|
||||||
|
db func a_string a_string
|
||||||
|
file delete -force test2.db test2.db-journal test2.db-wal
|
||||||
|
execsql {
|
||||||
|
PRAGMA journal_mode = PERSIST;
|
||||||
|
ATTACH 'test2.db' AS aux;
|
||||||
|
PRAGMA aux.journal_mode = PERSIST;
|
||||||
|
PRAGMA aux.journal_size_limit = 0;
|
||||||
|
}
|
||||||
|
} -body {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
|
||||||
|
CREATE TABLE aux.t2 AS SELECT * FROM t1;
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
} -test {
|
||||||
|
faultsim_test_result {0 {}}
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Test fault-injection as part of a commit when using
|
||||||
|
# journal_mode=TRUNCATE.
|
||||||
|
#
|
||||||
|
do_test pagerfault-6-pre1 {
|
||||||
|
faultsim_delete_and_reopen
|
||||||
|
db func a_string a_string
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t1(a UNIQUE, b UNIQUE);
|
||||||
|
INSERT INTO t1 VALUES(a_string(200), a_string(300));
|
||||||
|
}
|
||||||
|
faultsim_save_and_close
|
||||||
|
} {}
|
||||||
|
do_faultsim_test pagerfault-6.1 -prep {
|
||||||
|
faultsim_restore_and_reopen
|
||||||
|
db func a_string a_string
|
||||||
|
execsql { PRAGMA journal_mode = TRUNCATE }
|
||||||
|
} -body {
|
||||||
|
execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
|
||||||
|
} -test {
|
||||||
|
faultsim_test_result {0 {}}
|
||||||
|
faultsim_integrity_check
|
||||||
|
}
|
||||||
|
|
||||||
|
# The following was an attempt to get a bitvec malloc to fail. Didn't work.
|
||||||
|
#
|
||||||
|
# do_test pagerfault-6-pre1 {
|
||||||
|
# faultsim_delete_and_reopen
|
||||||
|
# execsql {
|
||||||
|
# CREATE TABLE t1(x, y, UNIQUE(x, y));
|
||||||
|
# INSERT INTO t1 VALUES(1, randomblob(1501));
|
||||||
|
# INSERT INTO t1 VALUES(2, randomblob(1502));
|
||||||
|
# INSERT INTO t1 VALUES(3, randomblob(1503));
|
||||||
|
# INSERT INTO t1 VALUES(4, randomblob(1504));
|
||||||
|
# INSERT INTO t1
|
||||||
|
# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
|
||||||
|
# INSERT INTO t1
|
||||||
|
# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
|
||||||
|
# INSERT INTO t1
|
||||||
|
# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
|
||||||
|
# INSERT INTO t1
|
||||||
|
# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
|
||||||
|
# }
|
||||||
|
# faultsim_save_and_close
|
||||||
|
# } {}
|
||||||
|
# do_faultsim_test pagerfault-6 -prep {
|
||||||
|
# faultsim_restore_and_reopen
|
||||||
|
# } -body {
|
||||||
|
# execsql {
|
||||||
|
# BEGIN;
|
||||||
|
# UPDATE t1 SET x=x+4 WHERE x=1;
|
||||||
|
# SAVEPOINT one;
|
||||||
|
# UPDATE t1 SET x=x+4 WHERE x=2;
|
||||||
|
# SAVEPOINT three;
|
||||||
|
# UPDATE t1 SET x=x+4 WHERE x=3;
|
||||||
|
# SAVEPOINT four;
|
||||||
|
# UPDATE t1 SET x=x+4 WHERE x=4;
|
||||||
|
# RELEASE three;
|
||||||
|
# COMMIT;
|
||||||
|
# SELECT DISTINCT x FROM t1;
|
||||||
|
# }
|
||||||
|
# } -test {
|
||||||
|
# faultsim_test_result {0 {5 6 7 8}}
|
||||||
|
# faultsim_integrity_check
|
||||||
|
# }
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
|||||||
@@ -169,7 +169,9 @@ test_suite "coverage-pager" -description {
|
|||||||
Coverage tests for file pager.c.
|
Coverage tests for file pager.c.
|
||||||
} -files {
|
} -files {
|
||||||
pager1.test
|
pager1.test
|
||||||
|
pager2.test
|
||||||
pagerfault.test
|
pagerfault.test
|
||||||
|
journal2.test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,8 @@
|
|||||||
# crashsql ARGS...
|
# crashsql ARGS...
|
||||||
# integrity_check TESTNAME ?DB?
|
# integrity_check TESTNAME ?DB?
|
||||||
# do_test TESTNAME SCRIPT EXPECTED
|
# do_test TESTNAME SCRIPT EXPECTED
|
||||||
|
# do_execsql_test TESTNAME SQL EXPECTED
|
||||||
|
# do_catchsql_test TESTNAME SQL EXPECTED
|
||||||
#
|
#
|
||||||
# Commands providing a lower level interface to the global test counters:
|
# Commands providing a lower level interface to the global test counters:
|
||||||
#
|
#
|
||||||
@@ -317,6 +319,14 @@ proc do_test {name cmd expected} {
|
|||||||
flush stdout
|
flush stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc do_execsql_test {testname sql result} {
|
||||||
|
uplevel do_test $testname [list "execsql {$sql}"] [list $result]
|
||||||
|
}
|
||||||
|
proc do_catchsql_test {testname sql result} {
|
||||||
|
uplevel do_test $testname [list "catchsql {$sql}"] [list $result]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Run an SQL script.
|
# Run an SQL script.
|
||||||
# Return the number of microseconds per statement.
|
# Return the number of microseconds per statement.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -124,46 +124,48 @@ do_test walmode-4.5 {
|
|||||||
# from WAL to rollback mode because a second connection has the database
|
# from WAL to rollback mode because a second connection has the database
|
||||||
# open. Or from rollback to WAL.
|
# open. Or from rollback to WAL.
|
||||||
#
|
#
|
||||||
do_test walmode-4.1 {
|
do_test walmode-4.6 {
|
||||||
sqlite3 db2 test.db
|
sqlite3 db2 test.db
|
||||||
execsql { PRAGMA main.journal_mode } db2
|
execsql { PRAGMA main.journal_mode } db2
|
||||||
} {delete}
|
} {delete}
|
||||||
do_test walmode-4.2 {
|
do_test walmode-4.7 {
|
||||||
execsql { PRAGMA main.journal_mode = wal } db
|
execsql { PRAGMA main.journal_mode = wal } db
|
||||||
} {wal}
|
} {wal}
|
||||||
do_test walmode-4.3 {
|
do_test walmode-4.8 {
|
||||||
execsql { SELECT * FROM t1 } db2
|
execsql { SELECT * FROM t1 } db2
|
||||||
} {1 2}
|
} {1 2}
|
||||||
do_test walmode-4.4 {
|
do_test walmode-4.9 {
|
||||||
catchsql { PRAGMA journal_mode = delete } db
|
catchsql { PRAGMA journal_mode = delete } db
|
||||||
} {1 {database is locked}}
|
} {1 {database is locked}}
|
||||||
do_test walmode-4.5 {
|
do_test walmode-4.10 {
|
||||||
execsql { PRAGMA main.journal_mode } db
|
execsql { PRAGMA main.journal_mode } db
|
||||||
} {wal}
|
} {wal}
|
||||||
do_test walmode-4.6 {
|
|
||||||
|
do_test walmode-4.11 {
|
||||||
db2 close
|
db2 close
|
||||||
execsql { PRAGMA journal_mode = delete } db
|
execsql { PRAGMA journal_mode = delete } db
|
||||||
} {delete}
|
} {delete}
|
||||||
do_test walmode-4.7 {
|
do_test walmode-4.12 {
|
||||||
execsql { PRAGMA main.journal_mode } db
|
execsql { PRAGMA main.journal_mode } db
|
||||||
} {delete}
|
} {delete}
|
||||||
do_test walmode-4.8 {
|
do_test walmode-4.13 {
|
||||||
list [file exists test.db-journal] [file exists test.db-wal]
|
list [file exists test.db-journal] [file exists test.db-wal]
|
||||||
} {0 0}
|
} {0 0}
|
||||||
do_test walmode-4.9 {
|
do_test walmode-4.14 {
|
||||||
sqlite3 db2 test.db
|
sqlite3 db2 test.db
|
||||||
execsql {
|
execsql {
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
} db2
|
} db2
|
||||||
} {1 2}
|
} {1 2}
|
||||||
do_test walmode-4.11 {
|
|
||||||
execsql { PRAGMA main.journal_mode } db
|
do_test walmode-4.16 { execsql { PRAGMA main.journal_mode } db } {delete}
|
||||||
} {delete}
|
do_test walmode-4.17 { execsql { PRAGMA main.journal_mode } db2 } {delete}
|
||||||
do_test walmode-4.10 {
|
|
||||||
|
do_test walmode-4.17 {
|
||||||
catchsql { PRAGMA main.journal_mode = wal } db
|
catchsql { PRAGMA main.journal_mode = wal } db
|
||||||
} {1 {database is locked}}
|
} {1 {database is locked}}
|
||||||
do_test walmode-4.11 {
|
do_test walmode-4.18 {
|
||||||
execsql { PRAGMA main.journal_mode } db
|
execsql { PRAGMA main.journal_mode } db
|
||||||
} {delete}
|
} {delete}
|
||||||
catch { db close }
|
catch { db close }
|
||||||
@@ -180,7 +182,6 @@ do_test walmode-5.1.1 {
|
|||||||
sqlite3 db :memory:
|
sqlite3 db :memory:
|
||||||
execsql { PRAGMA main.journal_mode }
|
execsql { PRAGMA main.journal_mode }
|
||||||
} {memory}
|
} {memory}
|
||||||
breakpoint
|
|
||||||
do_test walmode-5.1.2 {
|
do_test walmode-5.1.2 {
|
||||||
execsql { PRAGMA main.journal_mode = wal }
|
execsql { PRAGMA main.journal_mode = wal }
|
||||||
} {memory}
|
} {memory}
|
||||||
|
|||||||
Reference in New Issue
Block a user