diff --git a/Makefile.in b/Makefile.in index 14ceb38cbc..5593b4c6ff 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,7 +31,7 @@ TCC = @CC@ @CPPFLAGS@ @CFLAGS@ -I. -I${TOP}/src -I${TOP}/ext/rtree # Define this for the autoconf-based build, so that the code knows it can # include the generated config.h # -TCC += -D_HAVE_SQLITE_CONFIG_H +TCC += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite # Define -DNDEBUG to compile without debugging (i.e., for production usage) # Omitting the define will cause extra debugging code to be inserted and diff --git a/ext/fts3/fts3_porter.c b/ext/fts3/fts3_porter.c index 148c570088..84aa132229 100644 --- a/ext/fts3/fts3_porter.c +++ b/ext/fts3/fts3_porter.c @@ -40,7 +40,7 @@ typedef struct porter_tokenizer { } porter_tokenizer; /* -** Class derived from sqlit3_tokenizer_cursor +** Class derived from sqlite3_tokenizer_cursor */ typedef struct porter_tokenizer_cursor { sqlite3_tokenizer_cursor base; diff --git a/manifest b/manifest index 68ee2b1ff1..d6154d7b08 100644 --- a/manifest +++ b/manifest @@ -1,7 +1,7 @@ -C Merge\sall\sof\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch. -D 2012-01-05T13:02:36.422 +C Update\ssessions\sbranch\swith\slatest\schanges\sfrom\strunk. +D 2012-01-14T13:50:12.463 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 +F Makefile.in 3f79a373e57c3b92dabf76f40b065e719d31ac34 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.msc dcad80fa69f17d46fe6778ba873fc108ca16298d F Makefile.vxworks 1deb39c8bb047296c30161ffa10c1b5423e632f9 @@ -71,7 +71,7 @@ F ext/fts3/fts3_expr.c f5df26bddf46a5916b2a5f80c4027996e92b7b15 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914 F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec F ext/fts3/fts3_icu.c 6c8f395cdf9e1e3afa7fadb7e523dbbf381c6dfa -F ext/fts3/fts3_porter.c 8d946908f4812c005d3d33fcbe78418b1f4eb70c +F ext/fts3/fts3_porter.c b7e5276f9f0a5fc7018b6fa55ce0f31f269ef881 F ext/fts3/fts3_snippet.c 1f9ee6a8e0e242649645968dcec4deb253d86c2a F ext/fts3/fts3_term.c a5457992723455a58804cb75c8cbd8978db5c2ef F ext/fts3/fts3_test.c 24fa13f330db011500acb95590da9eee24951894 @@ -134,12 +134,12 @@ F src/alter.c ac80a0f31189f8b4a524ebf661e47e84536ee7f5 F src/analyze.c f32ff304da413851eefa562b04e61ff6cb88248b F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 -F src/backup.c 80d713109d295cc3a674f55cfe6446afb9b024ad +F src/backup.c e9538bad2d4a4fcd4308f1aed7cb18a0fbc968f9 F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c 8f683b1fcfd9ac92efa781c9c56c537e080a7117 +F src/btree.c a65816cc000bdd421772986e64c88c9035331332 F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce -F src/btreeInt.h 6e57bacaa4feb7dd56719678133e63a7c289c6e7 +F src/btreeInt.h 6c9960645c431c9456ca56498f43a2b3bf1fa8c2 F src/build.c 8e2a4dedad860fed982270ef43968505f35ec57f F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac @@ -174,19 +174,19 @@ F src/mutex_os2.c 882d735098c07c8c6a5472b8dd66e19675fe117f F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 -F src/os.c 519bdf7c608c4848024e1d87934f9305454145f4 -F src/os.h c7d888830f168a9b681b3aec30789f4ad2445c17 +F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c +F src/os.h a2219c3b05ce31230bb000fdc4f1a542b33ee649 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 -F src/os_unix.c f19ca2ef603e4f6510f3daf206e244476a68413d -F src/os_win.c 88b35c8fe7b32c7398ceace727ea01120cb21989 -F src/pager.c 5b89ab92631a8fc488b87cc663ab064802173fec +F src/os_unix.c 657672fab2580a84116c140b36ee3d6b6fc75b4e +F src/os_win.c 5ac061ae1326a71500cee578ed0fd9113b4f6a37 +F src/pager.c 4d58c983d9f4d34bc2d48e4280361ccaeecd03c5 F src/pager.h 5cd760857707529b403837d813d86b68938d6183 F src/parse.y fabb2e7047417d840e6fdb3ef0988a86849a08ba F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h b1d8775a9bddf44e65edb0d20bfc57a4982f840f -F src/pcache1.c e1aaa3bc9bbfd8b0bc391ca731f5f8185467375d -F src/pragma.c dd66f21fafe7be40e1a48ad4195764cc191cf583 +F src/pcache1.c 281822d22265245b19f908cb3f5df725f7e11b06 +F src/pragma.c fb979b7b5103ad0db1b72bcf349c83f5dec62574 F src/prepare.c ec4989f7f480544bdc4192fe663470d2a2d7d61e F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 @@ -194,16 +194,16 @@ F src/resolve.c 3d3e80a98f203ac6b9329e9621e29eda85ddfd40 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c a1d075db66a0ea42807353501b62997969e5be79 F src/shell.c aa4183d4a5243d8110b1d3d77faa4aea7e9c9c2d -F src/sqlite.h.in e819002c73cc667717aa0eab4f0584e201c4e102 +F src/sqlite.h.in 132b3140f29469dc1222a43fd9451c1785c80a51 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqliteInt.h 701b38210f369a802853894309af5185b44061b4 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e -F src/tclsqlite.c 008daf83b287c600c2495845ac46a9d364c1961a +F src/tclsqlite.c 47d088f383a106b2914ac970586fdab66c1bd169 F src/test1.c 1b1e514e85ffe7152b02cba38bd0a1ce8cd56113 -F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 -F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432 +F src/test2.c 711555927f1f7e8db9aab86b512bc6934a774abe +F src/test3.c 91d3f1a09cfae3533ef17d8b484a160f3d1f1a21 F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7 F src/test5.c e1a19845625144caf038031234a12185e40d315c F src/test6.c cf6ab27a59e1ab64b011bb251ba600131e803e59 @@ -223,16 +223,16 @@ F src/test_hexio.c c4773049603151704a6ab25ac5e936b5109caf5a F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99 F src/test_intarray.h 489edb9068bb926583445cb02589344961054207 -F src/test_journal.c 2c06e4be6584d51b935dc8b353980a9388de62ef +F src/test_journal.c a6a6baf343f79b942331f13378d045e7e270ae64 F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e F src/test_malloc.c 8d416f29ad8573f32601f6056c9d2b17472e9ad5 -F src/test_multiplex.c 2bf2eb36c9eff73c808ba6d19388e2f577438d9e +F src/test_multiplex.c afab2c9d292677ab31e0dd4b3dde2420fb655c5f F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 6abf0a37ce831120c4ef1b913afdd813e7ac1a73 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c 1a5874e3ee9074426f43b37e8d7404948065b585 +F src/test_quota.c b4a6519417d87870e7ef5838dbf3cae164dcc28d F src/test_quota.h 9ffa1d3ad6d0a6a24e8670ea64b909c717ec3358 F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 @@ -250,19 +250,19 @@ F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12 F src/trigger.c ee7e178fb9188f44b532cebd449a7c1df90fb684 F src/update.c 89de085a0bf4da448472029d0420a2b1cf1824ee F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84 -F src/util.c ad06374bc92b98071f221f00d553daea514f2b60 +F src/util.c 9e07bd67dfafe9c75b1da78c87ba030cebbb5388 F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa -F src/vdbe.c 3338717cb2ff8ead889109813149d2182484b835 +F src/vdbe.c 502f3deb63c24fbb3fe6b88a10c984ec897f5b7b F src/vdbe.h 87b8ff40de3f55dbcdc33029416862f517c37a2f -F src/vdbeInt.h 57ca039ec5291566b667932a31ee03e51872caaa +F src/vdbeInt.h 1aa78a0c2d6e4fdc4b9b8ff29192e98182d25afa F src/vdbeapi.c 2fc381f651738feb2495cb001cf2114dea596cc3 F src/vdbeaux.c ca1eada4b21723a67c510c0f456217c03ad15e48 F src/vdbeblob.c 11248c6362389569764682eb0f59ce910f3cc381 -F src/vdbemem.c dadc7465860ad2e980f01c9b0b1ba44903249257 +F src/vdbemem.c 4f7d25d5ea2e2040254095b8f6de07f8dbbadf80 F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790 F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843 F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a -F src/wal.c 932f09509d70fc115a7cc3d494d6fdcb825099ed +F src/wal.c 5f7bcc0610af759953defd769eacebfd98a22bc8 F src/wal.h eaa00b9a403ddda2b56d01b7afc19ef600f9363f F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c af623942514571895818b9b7ae11db95ae3b3d88 @@ -302,7 +302,7 @@ F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 F test/backcompat.test 71eeb75ea567c060774c4e8db4b0e703f21c7677 F test/backup.test 6970614b002b056ae5bab5b76559905e02b6f0b2 -F test/backup2.test b4966934b2dc10a9a6546114566ea69b34a5185e +F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf F test/backup_ioerr.test 40d208bc9224b666ee3ed423f49bc9062a36a9d0 F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f @@ -361,6 +361,7 @@ F test/corruptB.test 20d4a20cbed23958888c3e8995b424a47223d647 F test/corruptC.test 62a767fe64acb1975f58cc6171192839c783edbb F test/corruptD.test 99b1999dbfa7cc04aaeac9d695a2445d4e7c7458 F test/corruptE.test 1b9eb20a8711251ce57b44a257e241085b39b52d +F test/corruptF.test 984b1706c9c0e4248141b056c21124612628d12e F test/count.test 454e1ce985c94d13efeac405ce54439f49336163 F test/crash.test 519dc29f6fea151f015a23236e555239353946eb F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651 @@ -584,7 +585,7 @@ F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9 F test/malloc.test bc745155ff4252d4f35ec8316625b0dfe2abc659 F test/malloc3.test de8eca0c3e748878845fdca3663ec4b642073caf F test/malloc4.test 957337613002b7058a85116493a262f679f3a261 -F test/malloc5.test 30dc30b57fa22552eba0d8c95210d96c3d958a39 +F test/malloc5.test a577cbbcc1594c7763b9b3515b3633555751c7f0 F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151 F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d @@ -619,7 +620,7 @@ F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test eafaa41b9133d7a2ded4641bbe5f340731d35a52 F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054 -F test/multiplex.test 8bc3c71f73fe833bc8a659d454d320044a33b5da +F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test 15903c343f1eaa4b00998b7ceacfc4987e4ccfe9 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 @@ -642,7 +643,7 @@ F test/pageropt.test 9191867ed19a2b3db6c42d1b36b6fbc657cd1ab0 F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 -F test/permutations.test 4ec9fbb2f1389f96be8a7108a86f7f2674ae5d4b +F test/permutations.test ab9fbb673617734869af2fc4cbdb04baa3339d1c F test/pragma.test 7fa35e53085812dac94c2bfcbb02c2a4ad35df5e F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 @@ -697,7 +698,7 @@ F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 -F test/shrink.test 28165922bfea5c003c51a2d02bce69c4141ef013 +F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f F test/softheap1.test c16709a16ad79fa43b32929b2e623d1d117ccf53 @@ -723,7 +724,7 @@ F test/syscall.test 265cda616f56a297406728ee1e74c9b4a93aa6dd F test/sysfault.test c79441d88d23696fbec7b147dba98d42a04f523f F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 -F test/tclsqlite.test d5298750115768bca173da8043ffac2924be21a0 +F test/tclsqlite.test 2f2aa887763af30641f5561bdc26c5d3fbc73a88 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test 51edd31c65ed1560dd600b1796e8325df96318e2 F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d @@ -885,7 +886,7 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2 -F test/unixexcl.test c82934b3fda907573c7dfccc4f4c9506e5537f36 +F test/unixexcl.test a9870e46cc6f8390a494513d4f2bf55b5a8b3e46 F test/unordered.test f53095cee37851bf30130fa1bf299a8845e837bb F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172 F test/uri.test 0d289d32396bdbc491e9dc845f1a52e13f861e0b @@ -926,10 +927,10 @@ F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe F test/walbak.test b9f68e39646375c2b877be906babcc15d38b4877 F test/walbig.test 0ab8a430ef420a3114f7092e0f30fc9585ffa155 F test/walcksum.test f5447800a157c9e2234fbb8e80243f0813941bde -F test/walcrash.test 4fcb661faf71db91214156d52d43ee327f52bde1 +F test/walcrash.test 4457436593be8c136f9148487c7dccd5e9013af2 F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142 F test/walcrash3.test 595e44c6197f0d0aa509fc135be2fd0209d11a2c -F test/walfault.test efb0d5724893133e71b8d9d90abdb781845a6bb0 +F test/walfault.test 97394d8de82a99f7abf1c12ed229640607fd0ad2 F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483 F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496 @@ -954,7 +955,7 @@ F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 -F test/zerodamage.test 7ef0680559163118705975be132933898d349674 +F test/zerodamage.test 0de750389990b1078bab203c712dc3fefd1d8b82 F tool/build-shell.sh 12aa4391073a777fcb6dcc490b219a018ae98bac F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 @@ -962,7 +963,7 @@ F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce -F tool/lemon.c 949328f67cac94969d3112b105b8457edf27f44e +F tool/lemon.c 445f18999b700d83b83a5d9be00c596546c21052 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e @@ -999,7 +1000,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 23580718e1c15ddb89682d0e7566da4d7276bfe9 1378f905d37544701776d38987fe7a312b255983 -R 5ebf66e93e6aec7fb5582a0e00987618 -U drh -Z e88b35dabf798061ce032430eb1150b1 +P a9bcb432f58b96f079a73c456efd4851c582221e 88ad2f23c5036cbb4a69b73ce5792bd5c33a9177 +R 30723a7c24a6752d8bfb2c322e9b8748 +U dan +Z 241182607d7d4efdfae3b5115d25b877 diff --git a/manifest.uuid b/manifest.uuid index 54abe46586..62957ac731 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a9bcb432f58b96f079a73c456efd4851c582221e \ No newline at end of file +01c84fd391a0ca1f5245c7eff0644d0cc6cff86b \ No newline at end of file diff --git a/src/backup.c b/src/backup.c index f3b952bf0d..aa3401897b 100644 --- a/src/backup.c +++ b/src/backup.c @@ -678,9 +678,9 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ pFd = sqlite3PagerFile(sqlite3BtreePager(pTo)); if( pFd->pMethods ){ i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom); - sqlite3BeginBenignMalloc(); - sqlite3OsFileControl(pFd, SQLITE_FCNTL_OVERWRITE, &nByte); - sqlite3EndBenignMalloc(); + rc = sqlite3OsFileControl(pFd, SQLITE_FCNTL_OVERWRITE, &nByte); + if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; + if( rc ) goto copy_finished; } /* Set up an sqlite3_backup object. sqlite3_backup.pDestDb must be set @@ -705,12 +705,13 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ assert( b.rc!=SQLITE_OK ); rc = sqlite3_backup_finish(&b); if( rc==SQLITE_OK ){ - pTo->pBt->pageSizeFixed = 0; + pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; }else{ sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); } assert( sqlite3BtreeIsInTrans(pTo)==0 ); +copy_finished: sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); return rc; diff --git a/src/btree.c b/src/btree.c index 7c043ccf75..2532406651 100644 --- a/src/btree.c +++ b/src/btree.c @@ -243,7 +243,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ /* If some other connection is holding an exclusive lock, the ** requested lock may not be obtained. */ - if( pBt->pWriter!=p && pBt->isExclusive ){ + if( pBt->pWriter!=p && (pBt->btsFlags & BTS_EXCLUSIVE)!=0 ){ sqlite3ConnectionBlocked(p->db, pBt->pWriter->db); return SQLITE_LOCKED_SHAREDCACHE; } @@ -264,7 +264,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ sqlite3ConnectionBlocked(p->db, pIter->pBtree->db); if( eLock==WRITE_LOCK ){ assert( p==pBt->pWriter ); - pBt->isPending = 1; + pBt->btsFlags |= BTS_PENDING; } return SQLITE_LOCKED_SHAREDCACHE; } @@ -352,7 +352,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ ** the setSharedCacheTableLock() procedure) held by Btree object p. ** ** This function assumes that Btree p has an open read or write -** transaction. If it does not, then the BtShared.isPending variable +** transaction. If it does not, then the BTS_PENDING flag ** may be incorrectly cleared. */ static void clearAllSharedCacheTableLocks(Btree *p){ @@ -365,7 +365,7 @@ static void clearAllSharedCacheTableLocks(Btree *p){ while( *ppIter ){ BtLock *pLock = *ppIter; - assert( pBt->isExclusive==0 || pBt->pWriter==pLock->pBtree ); + assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree ); assert( pLock->pBtree->inTrans>=pLock->eLock ); if( pLock->pBtree==p ){ *ppIter = pLock->pNext; @@ -378,22 +378,21 @@ static void clearAllSharedCacheTableLocks(Btree *p){ } } - assert( pBt->isPending==0 || pBt->pWriter ); + assert( (pBt->btsFlags & BTS_PENDING)==0 || pBt->pWriter ); if( pBt->pWriter==p ){ pBt->pWriter = 0; - pBt->isExclusive = 0; - pBt->isPending = 0; + pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); }else if( pBt->nTransaction==2 ){ /* This function is called when Btree p is concluding its ** transaction. If there currently exists a writer, and p is not ** that writer, then the number of locks held by connections other ** than the writer must be about to drop to zero. In this case - ** set the isPending flag to 0. + ** set the BTS_PENDING flag to 0. ** - ** If there is not currently a writer, then BtShared.isPending must + ** If there is not currently a writer, then BTS_PENDING must ** be zero already. So this next line is harmless in that case. */ - pBt->isPending = 0; + pBt->btsFlags &= ~BTS_PENDING; } } @@ -405,8 +404,7 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){ if( pBt->pWriter==p ){ BtLock *pLock; pBt->pWriter = 0; - pBt->isExclusive = 0; - pBt->isPending = 0; + pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){ assert( pLock->eLock==READ_LOCK || pLock->pBtree==p ); pLock->eLock = READ_LOCK; @@ -1264,7 +1262,7 @@ static int freeSpace(MemPage *pPage, int start, int size){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( size>=0 ); /* Minimum cell size is 4 */ - if( pPage->pBt->secureDelete ){ + if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){ /* Overwrite deleted information with zeros when the secure_delete ** option is enabled */ memset(&data[start], 0, size); @@ -1367,6 +1365,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){ }else{ return SQLITE_CORRUPT_BKPT; } + pPage->max1bytePayload = pBt->max1bytePayload; return SQLITE_OK; } @@ -1502,7 +1501,7 @@ static void zeroPage(MemPage *pPage, int flags){ assert( sqlite3PagerGetData(pPage->pDbPage) == data ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pBt->mutex) ); - if( pBt->secureDelete ){ + if( pBt->btsFlags & BTS_SECURE_DELETE ){ memset(&data[hdr], 0, pBt->usableSize - hdr); } data[hdr] = (char)flags; @@ -1855,9 +1854,9 @@ int sqlite3BtreeOpen( pBt->pCursor = 0; pBt->pPage1 = 0; - pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager); + if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY; #ifdef SQLITE_SECURE_DELETE - pBt->secureDelete = 1; + pBt->btsFlags |= BTS_SECURE_DELETE; #endif pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16); if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE @@ -1878,7 +1877,7 @@ int sqlite3BtreeOpen( nReserve = 0; }else{ nReserve = zDbHeader[20]; - pBt->pageSizeFixed = 1; + pBt->btsFlags |= BTS_PAGESIZE_FIXED; #ifndef SQLITE_OMIT_AUTOVACUUM pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0); pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0); @@ -2166,7 +2165,7 @@ int sqlite3BtreeSyncDisabled(Btree *p){ ** If parameter nReserve is less than zero, then the number of reserved ** bytes per page is left unchanged. ** -** If the iFix!=0 then the pageSizeFixed flag is set so that the page size +** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size ** and autovacuum mode can no longer be changed. */ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ @@ -2174,7 +2173,7 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ BtShared *pBt = p->pBt; assert( nReserve>=-1 && nReserve<=255 ); sqlite3BtreeEnter(p); - if( pBt->pageSizeFixed ){ + if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){ sqlite3BtreeLeave(p); return SQLITE_READONLY; } @@ -2191,7 +2190,7 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ } rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve); pBt->usableSize = pBt->pageSize - (u16)nReserve; - if( iFix ) pBt->pageSizeFixed = 1; + if( iFix ) pBt->btsFlags |= BTS_PAGESIZE_FIXED; sqlite3BtreeLeave(p); return rc; } @@ -2231,8 +2230,8 @@ int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ } /* -** Set the secureDelete flag if newFlag is 0 or 1. If newFlag is -1, -** then make no changes. Always return the value of the secureDelete +** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1. If newFlag is -1, +** then make no changes. Always return the value of the BTS_SECURE_DELETE ** setting after the change. */ int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ @@ -2240,9 +2239,10 @@ int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ if( p==0 ) return 0; sqlite3BtreeEnter(p); if( newFlag>=0 ){ - p->pBt->secureDelete = (newFlag!=0) ? 1 : 0; + p->pBt->btsFlags &= ~BTS_SECURE_DELETE; + if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE; } - b = p->pBt->secureDelete; + b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0; sqlite3BtreeLeave(p); return b; } @@ -2263,7 +2263,7 @@ int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ u8 av = (u8)autoVacuum; sqlite3BtreeEnter(p); - if( pBt->pageSizeFixed && (av ?1:0)!=pBt->autoVacuum ){ + if( (pBt->btsFlags & BTS_PAGESIZE_FIXED)!=0 && (av ?1:0)!=pBt->autoVacuum ){ rc = SQLITE_READONLY; }else{ pBt->autoVacuum = av ?1:0; @@ -2337,14 +2337,14 @@ static int lockBtree(BtShared *pBt){ #ifdef SQLITE_OMIT_WAL if( page1[18]>1 ){ - pBt->readOnly = 1; + pBt->btsFlags |= BTS_READ_ONLY; } if( page1[19]>1 ){ goto page1_init_failed; } #else if( page1[18]>2 ){ - pBt->readOnly = 1; + pBt->btsFlags |= BTS_READ_ONLY; } if( page1[19]>2 ){ goto page1_init_failed; @@ -2358,7 +2358,7 @@ static int lockBtree(BtShared *pBt){ ** may not be the latest version - there may be a newer one in the log ** file. */ - if( page1[19]==2 && pBt->doNotUseWAL==0 ){ + if( page1[19]==2 && (pBt->btsFlags & BTS_NO_WAL)==0 ){ int isOpen = 0; rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen); if( rc!=SQLITE_OK ){ @@ -2435,6 +2435,11 @@ static int lockBtree(BtShared *pBt){ pBt->minLocal = (u16)((pBt->usableSize-12)*32/255 - 23); pBt->maxLeaf = (u16)(pBt->usableSize - 35); pBt->minLeaf = (u16)((pBt->usableSize-12)*32/255 - 23); + if( pBt->maxLocal>127 ){ + pBt->max1bytePayload = 127; + }else{ + pBt->max1bytePayload = (u8)pBt->maxLocal; + } assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) ); pBt->pPage1 = pPage1; pBt->nPage = nPage; @@ -2498,7 +2503,7 @@ static int newDatabase(BtShared *pBt){ data[23] = 32; memset(&data[24], 0, 100-24); zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA ); - pBt->pageSizeFixed = 1; + pBt->btsFlags |= BTS_PAGESIZE_FIXED; #ifndef SQLITE_OMIT_AUTOVACUUM assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 ); assert( pBt->incrVacuum==1 || pBt->incrVacuum==0 ); @@ -2562,7 +2567,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } /* Write transactions are not possible on a read-only database */ - if( pBt->readOnly && wrflag ){ + if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ rc = SQLITE_READONLY; goto trans_begun; } @@ -2572,7 +2577,9 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ ** on this shared-btree structure and a second write transaction is ** requested, return SQLITE_LOCKED. */ - if( (wrflag && pBt->inTransaction==TRANS_WRITE) || pBt->isPending ){ + if( (wrflag && pBt->inTransaction==TRANS_WRITE) + || (pBt->btsFlags & BTS_PENDING)!=0 + ){ pBlock = pBt->pWriter->db; }else if( wrflag>1 ){ BtLock *pIter; @@ -2596,7 +2603,8 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK); if( SQLITE_OK!=rc ) goto trans_begun; - pBt->initiallyEmpty = (u8)(pBt->nPage==0); + pBt->btsFlags &= ~BTS_INITIALLY_EMPTY; + if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY; do { /* Call lockBtree() until either pBt->pPage1 is populated or ** lockBtree() returns something other than SQLITE_OK. lockBtree() @@ -2608,7 +2616,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ while( pBt->pPage1==0 && SQLITE_OK==(rc = lockBtree(pBt)) ); if( rc==SQLITE_OK && wrflag ){ - if( pBt->readOnly ){ + if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){ rc = SQLITE_READONLY; }else{ rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db)); @@ -2645,7 +2653,8 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ #ifndef SQLITE_OMIT_SHARED_CACHE assert( !pBt->pWriter ); pBt->pWriter = p; - pBt->isExclusive = (u8)(wrflag>1); + pBt->btsFlags &= ~BTS_EXCLUSIVE; + if( wrflag>1 ) pBt->btsFlags |= BTS_EXCLUSIVE; #endif /* If the db-size header field is incorrect (as it may be if an old @@ -3374,7 +3383,7 @@ int sqlite3BtreeBeginStmt(Btree *p, int iStatement){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans==TRANS_WRITE ); - assert( pBt->readOnly==0 ); + assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( iStatement>0 ); assert( iStatement>p->db->nSavepoint ); assert( pBt->inTransaction==TRANS_WRITE ); @@ -3409,7 +3418,9 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ sqlite3BtreeEnter(p); rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint); if( rc==SQLITE_OK ){ - if( iSavepoint<0 && pBt->initiallyEmpty ) pBt->nPage = 0; + if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){ + pBt->nPage = 0; + } rc = newDatabase(pBt); pBt->nPage = get4byte(28 + pBt->pPage1->aData); @@ -3479,7 +3490,7 @@ static int btreeCursor( assert( wrFlag==0 || p->inTrans==TRANS_WRITE ); assert( pBt->pPage1 && pBt->pPage1->aData ); - if( NEVER(wrFlag && pBt->readOnly) ){ + if( NEVER(wrFlag && (pBt->btsFlags & BTS_READ_ONLY)!=0) ){ return SQLITE_READONLY; } if( iTable==1 && btreePagecount(pBt)==0 ){ @@ -4183,7 +4194,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ return SQLITE_OK; } -#ifndef NDEBUG +#if 0 /* ** Page pParent is an internal (non-leaf) tree page. This function ** asserts that page number iChild is the left-child if the iIdx'th @@ -4216,11 +4227,21 @@ static void moveToParent(BtCursor *pCur){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>0 ); assert( pCur->apPage[pCur->iPage] ); + + /* UPDATE: It is actually possible for the condition tested by the assert + ** below to be untrue if the database file is corrupt. This can occur if + ** one cursor has modified page pParent while a reference to it is held + ** by a second cursor. Which can only happen if a single page is linked + ** into more than one b-tree structure in a corrupt database. */ +#if 0 assertParentIndex( pCur->apPage[pCur->iPage-1], pCur->aiIdx[pCur->iPage-1], pCur->apPage[pCur->iPage]->pgno ); +#endif + testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); + releasePage(pCur->apPage[pCur->iPage]); pCur->iPage--; pCur->info.nSize = 0; @@ -4559,9 +4580,8 @@ int sqlite3BtreeMovetoUnpacked( ** 2 bytes of the cell. */ int nCell = pCell[0]; - if( !(nCell & 0x80) - && nCell<=pPage->maxLocal - && (pCell+nCell+1)<=pPage->aDataEnd + if( nCell<=pPage->max1bytePayload + /* && (pCell+nCell)aDataEnd */ ){ /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main @@ -4570,7 +4590,7 @@ int sqlite3BtreeMovetoUnpacked( c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal - && (pCell+nCell+2)<=pPage->aDataEnd + /* && (pCell+nCell+2)<=pPage->aDataEnd */ ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ @@ -4691,7 +4711,13 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ pPage = pCur->apPage[pCur->iPage]; idx = ++pCur->aiIdx[pCur->iPage]; assert( pPage->isInit ); - assert( idx<=pPage->nCell ); + + /* If the database file is corrupt, it is possible for the value of idx + ** to be invalid here. This can only occur if a second cursor modifies + ** the page while cursor pCur is holding a reference to it. Which can + ** only happen if the database is corrupt in such a way as to link the + ** page into more than one b-tree structure. */ + testcase( idx>pPage->nCell ); pCur->info.nSize = 0; pCur->validNKey = 0; @@ -5116,7 +5142,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ nFree = get4byte(&pPage1->aData[36]); put4byte(&pPage1->aData[36], nFree+1); - if( pBt->secureDelete ){ + if( pBt->btsFlags & BTS_SECURE_DELETE ){ /* If the secure_delete option is enabled, then ** always fully overwrite deleted information with zeros. */ @@ -5177,7 +5203,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ if( rc==SQLITE_OK ){ put4byte(&pTrunk->aData[4], nLeaf+1); put4byte(&pTrunk->aData[8+nLeaf*4], iPage); - if( pPage && !pBt->secureDelete ){ + if( pPage && (pBt->btsFlags & BTS_SECURE_DELETE)==0 ){ sqlite3PagerDontWrite(pPage->pDbPage); } rc = btreeSetHasContent(pBt, iPage); @@ -6018,7 +6044,7 @@ static int balance_nonroot( ** In this case, temporarily copy the cell into the aOvflSpace[] ** buffer. It will be copied out again as soon as the aSpace[] buffer ** is allocated. */ - if( pBt->secureDelete ){ + if( pBt->btsFlags & BTS_SECURE_DELETE ){ int iOff; iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); @@ -6760,7 +6786,8 @@ int sqlite3BtreeInsert( } assert( cursorHoldsMutex(pCur) ); - assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE && !pBt->readOnly ); + assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE + && (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); /* Assert that the caller has been consistent. If this cursor was opened @@ -6889,7 +6916,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); - assert( !pBt->readOnly ); + assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( pCur->wrFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); @@ -7010,7 +7037,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){ assert( sqlite3BtreeHoldsMutex(p) ); assert( pBt->inTransaction==TRANS_WRITE ); - assert( !pBt->readOnly ); + assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); #ifdef SQLITE_OMIT_AUTOVACUUM rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); @@ -7384,7 +7411,9 @@ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ /* If auto-vacuum is disabled in this build and this is an auto-vacuum ** database, mark the database as read-only. */ #ifdef SQLITE_OMIT_AUTOVACUUM - if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ) pBt->readOnly = 1; + if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ){ + pBt->btsFlags |= BTS_READ_ONLY; + } #endif sqlite3BtreeLeave(p); @@ -8184,7 +8213,8 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ if( !pCsr->wrFlag ){ return SQLITE_READONLY; } - assert( !pCsr->pBt->readOnly && pCsr->pBt->inTransaction==TRANS_WRITE ); + assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0 + && pCsr->pBt->inTransaction==TRANS_WRITE ); assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) ); assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) ); assert( pCsr->apPage[pCsr->iPage]->intKey ); @@ -8224,7 +8254,8 @@ int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ /* If setting the version fields to 1, do not automatically open the ** WAL connection, even if the version fields are currently set to 2. */ - pBt->doNotUseWAL = (u8)(iVersion==1); + pBt->btsFlags &= ~BTS_NO_WAL; + if( iVersion==1 ) pBt->btsFlags |= BTS_NO_WAL; rc = sqlite3BtreeBeginTrans(pBtree, 0); if( rc==SQLITE_OK ){ @@ -8241,6 +8272,6 @@ int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ } } - pBt->doNotUseWAL = 0; + pBt->btsFlags &= ~BTS_NO_WAL; return rc; } diff --git a/src/btreeInt.h b/src/btreeInt.h index 1535350a3e..907c02e601 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -277,6 +277,7 @@ struct MemPage { u8 hasData; /* True if this page stores data */ u8 hdrOffset; /* 100 for page 1. 0 otherwise */ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ + u8 max1bytePayload; /* min(maxLocal,127) */ u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ @@ -407,17 +408,14 @@ struct BtShared { sqlite3 *db; /* Database connection currently using this Btree */ BtCursor *pCursor; /* A list of all open cursors */ MemPage *pPage1; /* First page of the database */ - u8 readOnly; /* True if the underlying file is readonly */ - u8 pageSizeFixed; /* True if the page size can no longer be changed */ - u8 secureDelete; /* True if secure_delete is enabled */ - u8 initiallyEmpty; /* Database is empty at start of transaction */ u8 openFlags; /* Flags to sqlite3BtreeOpen() */ #ifndef SQLITE_OMIT_AUTOVACUUM u8 autoVacuum; /* True if auto-vacuum is enabled */ u8 incrVacuum; /* True if incr-vacuum is enabled */ #endif u8 inTransaction; /* Transaction state */ - u8 doNotUseWAL; /* If true, do not open write-ahead-log file */ + u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ + u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */ u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */ @@ -435,12 +433,21 @@ struct BtShared { BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ - u8 isExclusive; /* True if pWriter has an EXCLUSIVE lock on the db */ - u8 isPending; /* If waiting for read-locks to clear */ #endif u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */ }; +/* +** Allowed values for BtShared.btsFlags +*/ +#define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ +#define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ +#define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */ +#define BTS_INITIALLY_EMPTY 0x0008 /* Database was empty at trans start */ +#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */ +#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */ +#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */ + /* ** An instance of the following structure is used to hold information ** about a cell. The parseCellPtr() function fills in this structure diff --git a/src/os.c b/src/os.c index c26429bf9a..b5e918a727 100644 --- a/src/os.c +++ b/src/os.c @@ -97,10 +97,23 @@ int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){ DO_OS_MALLOC_TEST(id); return id->pMethods->xCheckReservedLock(id, pResOut); } + +/* +** Use sqlite3OsFileControl() when we are doing something that might fail +** and we need to know about the failures. Use sqlite3OsFileControlHint() +** when simply tossing information over the wall to the VFS and we do not +** really care if the VFS receives and understands the information since it +** is only a hint and can be safely ignored. The sqlite3OsFileControlHint() +** routine has no return value since the return value would be meaningless. +*/ int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ DO_OS_MALLOC_TEST(id); return id->pMethods->xFileControl(id, op, pArg); } +void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){ + (void)id->pMethods->xFileControl(id, op, pArg); +} + int sqlite3OsSectorSize(sqlite3_file *id){ int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); @@ -151,6 +164,7 @@ int sqlite3OsOpen( } int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ DO_OS_MALLOC_TEST(0); + assert( dirSync==0 || dirSync==1 ); return pVfs->xDelete(pVfs, zPath, dirSync); } int sqlite3OsAccess( diff --git a/src/os.h b/src/os.h index 52ac4b0cbc..08cd178e72 100644 --- a/src/os.h +++ b/src/os.h @@ -252,6 +252,7 @@ int sqlite3OsLock(sqlite3_file*, int); int sqlite3OsUnlock(sqlite3_file*, int); int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut); int sqlite3OsFileControl(sqlite3_file*,int,void*); +void sqlite3OsFileControlHint(sqlite3_file*,int,void*); #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 int sqlite3OsSectorSize(sqlite3_file *id); int sqlite3OsDeviceCharacteristics(sqlite3_file *id); @@ -260,6 +261,7 @@ int sqlite3OsShmLock(sqlite3_file *id, int, int, int); void sqlite3OsShmBarrier(sqlite3_file *id); int sqlite3OsShmUnmap(sqlite3_file *id, int); + /* ** Functions for accessing sqlite3_vfs methods */ diff --git a/src/os_unix.c b/src/os_unix.c index 4f263bcdd0..13faac3a5e 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -225,7 +225,6 @@ struct unixFile { unsigned fsFlags; /* cached details from statfs() */ #endif #if OS_VXWORKS - int isDelete; /* Delete on close if true */ struct vxworksFileId *pId; /* Unique file ID */ #endif #ifndef NDEBUG @@ -260,6 +259,9 @@ struct unixFile { # define UNIXFILE_DIRSYNC 0x00 #endif #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ +#define UNIXFILE_DELETE 0x20 /* Delete on close */ +#define UNIXFILE_URI 0x40 /* Filename might have query parameters */ +#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ /* ** Include code that is common to all os_*.c files @@ -1765,7 +1767,7 @@ static int closeUnixFile(sqlite3_file *id){ } #if OS_VXWORKS if( pFile->pId ){ - if( pFile->isDelete ){ + if( pFile->ctrlFlags & UNIXFILE_DELETE ){ osUnlink(pFile->pId->zCanonicalName); } vxworksReleaseFileId(pFile->pId); @@ -3872,7 +3874,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ rc = SQLITE_NOMEM; goto shm_open_err; } - memset(pShmNode, 0, sizeof(*pShmNode)); + memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename); zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1]; #ifdef SQLITE_SHM_DIRECTORY sqlite3_snprintf(nShmFilename, zShmFilename, @@ -4555,12 +4557,9 @@ typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); static int fillInUnixFile( sqlite3_vfs *pVfs, /* Pointer to vfs object */ int h, /* Open file descriptor of file being opened */ - int syncDir, /* True to sync directory on first sync */ sqlite3_file *pId, /* Write to the unixFile structure here */ const char *zFilename, /* Name of the file being opened */ - int noLock, /* Omit locking if true */ - int isDelete, /* Delete on close if true */ - int isReadOnly /* True if the file is opened read-only */ + int ctrlFlags /* Zero or more UNIXFILE_* values */ ){ const sqlite3_io_methods *pLockingStyle; unixFile *pNew = (unixFile *)pId; @@ -4568,11 +4567,6 @@ static int fillInUnixFile( assert( pNew->pInode==NULL ); - /* Parameter isDelete is only used on vxworks. Express this explicitly - ** here to prevent compiler warnings about unused parameters. - */ - UNUSED_PARAMETER(isDelete); - /* Usually the path zFilename should not be a relative pathname. The ** exception is when opening the proxy "conch" file in builds that ** include the special Apple locking styles. @@ -4585,35 +4579,30 @@ static int fillInUnixFile( #endif /* No locking occurs in temporary files */ - assert( zFilename!=0 || noLock ); + assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); OSTRACE(("OPEN %-3d %s\n", h, zFilename)); pNew->h = h; pNew->pVfs = pVfs; pNew->zPath = zFilename; - pNew->ctrlFlags = 0; - if( sqlite3_uri_boolean(zFilename, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ + pNew->ctrlFlags = (u8)ctrlFlags; + if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), + "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pNew->ctrlFlags |= UNIXFILE_PSOW; } if( memcmp(pVfs->zName,"unix-excl",10)==0 ){ pNew->ctrlFlags |= UNIXFILE_EXCL; } - if( isReadOnly ){ - pNew->ctrlFlags |= UNIXFILE_RDONLY; - } - if( syncDir ){ - pNew->ctrlFlags |= UNIXFILE_DIRSYNC; - } #if OS_VXWORKS pNew->pId = vxworksFindFileId(zFilename); if( pNew->pId==0 ){ - noLock = 1; + ctrlFlags |= UNIXFILE_NOLOCK; rc = SQLITE_NOMEM; } #endif - if( noLock ){ + if( ctrlFlags & UNIXFILE_NOLOCK ){ pLockingStyle = &nolockIoMethods; }else{ pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew); @@ -4734,7 +4723,7 @@ static int fillInUnixFile( osUnlink(zFilename); isDelete = 0; } - pNew->isDelete = isDelete; + if( isDelete ) pNew->ctrlFlags |= UNIXFILE_DELETE; #endif if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); @@ -4799,18 +4788,19 @@ static int unixGetTempname(int nBuf, char *zBuf){ /* Check that the output buffer is large enough for the temporary file ** name. If it is not, return SQLITE_ERROR. */ - if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 17) >= (size_t)nBuf ){ + if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf ){ return SQLITE_ERROR; } do{ - sqlite3_snprintf(nBuf-17, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir); + sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir); j = (int)strlen(zBuf); sqlite3_randomness(15, &zBuf[j]); for(i=0; i<15; i++, j++){ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; } zBuf[j] = 0; + zBuf[j+1] = 0; }while( osAccess(zBuf,0)==0 ); return SQLITE_OK; } @@ -4989,6 +4979,7 @@ static int unixOpen( int eType = flags&0xFFFFFF00; /* Type of file to open */ int noLock; /* True to omit locking primitives */ int rc = SQLITE_OK; /* Function Return Code */ + int ctrlFlags = 0; /* UNIXFILE_* flags */ int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); @@ -5015,7 +5006,7 @@ static int unixOpen( /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ - char zTmpname[MAX_PATHNAME+1]; + char zTmpname[MAX_PATHNAME+2]; const char *zName = zPath; /* Check the following statements are true: @@ -5058,14 +5049,24 @@ static int unixOpen( } } p->pUnused = pUnused; + + /* Database filenames are double-zero terminated if they are not + ** URIs with parameters. Hence, they can always be passed into + ** sqlite3_uri_parameter(). */ + assert( (flags & SQLITE_OPEN_URI) || zName[strlen(zName)+1]==0 ); + }else if( !zName ){ /* If zName is NULL, the upper layer is requesting a temp file. */ assert(isDelete && !syncDir); - rc = unixGetTempname(MAX_PATHNAME+1, zTmpname); + rc = unixGetTempname(MAX_PATHNAME+2, zTmpname); if( rc!=SQLITE_OK ){ return rc; } zName = zTmpname; + + /* Generated temporary filenames are always double-zero terminated + ** for use by sqlite3_uri_parameter(). */ + assert( zName[strlen(zName)+1]==0 ); } /* Determine the value of the flags parameter passed to POSIX function @@ -5142,7 +5143,14 @@ static int unixOpen( ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; } #endif - + + /* Set up appropriate ctrlFlags */ + if( isDelete ) ctrlFlags |= UNIXFILE_DELETE; + if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY; + if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK; + if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC; + if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI; + #if SQLITE_ENABLE_LOCKING_STYLE #if SQLITE_PREFER_PROXY_LOCKING isAutoProxy = 1; @@ -5172,8 +5180,7 @@ static int unixOpen( useProxy = !(fsInfo.f_flags&MNT_LOCAL); } if( useProxy ){ - rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, - isDelete, isReadonly); + rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); if( rc==SQLITE_OK ){ rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); if( rc!=SQLITE_OK ){ @@ -5190,8 +5197,8 @@ static int unixOpen( } #endif - rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, - isDelete, isReadonly); + rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); + open_finished: if( rc!=SQLITE_OK ){ sqlite3_free(p->pUnused); @@ -5216,7 +5223,7 @@ static int unixDelete( return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); } #ifndef SQLITE_DISABLE_DIRSYNC - if( dirSync ){ + if( (dirSync & 1)!=0 ){ int fd; rc = osOpenDirectory(zPath, &fd); if( rc==SQLITE_OK ){ @@ -5862,7 +5869,7 @@ static int proxyCreateUnixFile( pUnused->flags = openFlags; pNew->pUnused = pUnused; - rc = fillInUnixFile(&dummyVfs, fd, 0, (sqlite3_file*)pNew, path, 0, 0, 0); + rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0); if( rc==SQLITE_OK ){ *ppFile = pNew; return SQLITE_OK; diff --git a/src/os_win.c b/src/os_win.c index 7269f436d7..8b86c7ed59 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -2428,7 +2428,9 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ } if( deleteFlag ){ SimulateIOErrorBenign(1); + sqlite3BeginBenignMalloc(); winDelete(pVfs, p->zFilename, 0); + sqlite3EndBenignMalloc(); SimulateIOErrorBenign(0); } *pp = p->pNext; @@ -2463,12 +2465,12 @@ static int winOpenSharedMemory(winFile *pDbFd){ if( p==0 ) return SQLITE_IOERR_NOMEM; memset(p, 0, sizeof(*p)); nName = sqlite3Strlen30(pDbFd->zPath); - pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 16 ); + pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 17 ); if( pNew==0 ){ sqlite3_free(p); return SQLITE_IOERR_NOMEM; } - memset(pNew, 0, sizeof(*pNew)); + memset(pNew, 0, sizeof(*pNew) + nName + 17); pNew->zFilename = (char*)&pNew[1]; sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); @@ -2504,7 +2506,6 @@ static int winOpenSharedMemory(winFile *pDbFd){ SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */ 0); if( SQLITE_OK!=rc ){ - rc = SQLITE_CANTOPEN_BKPT; goto shm_open_err; } @@ -2927,7 +2928,7 @@ static int getTempname(int nBuf, char *zBuf){ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; size_t i, j; - char zTempPath[MAX_PATH+1]; + char zTempPath[MAX_PATH+2]; /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this @@ -2970,14 +2971,14 @@ static int getTempname(int nBuf, char *zBuf){ /* Check that the output buffer is large enough for the temporary file ** name. If it is not, return SQLITE_ERROR. */ - if( (sqlite3Strlen30(zTempPath) + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 17) >= nBuf ){ + if( (sqlite3Strlen30(zTempPath) + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){ return SQLITE_ERROR; } for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} zTempPath[i] = 0; - sqlite3_snprintf(nBuf-17, zBuf, + sqlite3_snprintf(nBuf-18, zBuf, "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); j = sqlite3Strlen30(zBuf); sqlite3_randomness(15, &zBuf[j]); @@ -2985,6 +2986,7 @@ static int getTempname(int nBuf, char *zBuf){ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; } zBuf[j] = 0; + zBuf[j+1] = 0; OSTRACE(("TEMP FILENAME: %s\n", zBuf)); return SQLITE_OK; @@ -3017,7 +3019,7 @@ static int winOpen( /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ - char zTmpname[MAX_PATH+1]; /* Buffer used to create temp filename */ + char zTmpname[MAX_PATH+2]; /* Buffer used to create temp filename */ int rc = SQLITE_OK; /* Function Return Code */ #if !defined(NDEBUG) || SQLITE_OS_WINCE @@ -3076,13 +3078,20 @@ static int winOpen( */ if( !zUtf8Name ){ assert(isDelete && !isOpenJournal); - rc = getTempname(MAX_PATH+1, zTmpname); + rc = getTempname(MAX_PATH+2, zTmpname); if( rc!=SQLITE_OK ){ return rc; } zUtf8Name = zTmpname; } + /* Database filenames are double-zero terminated if they are not + ** URIs with parameters. Hence, they can always be passed into + ** sqlite3_uri_parameter(). + */ + assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || + zUtf8Name[strlen(zUtf8Name)+1]==0 ); + /* Convert the filename to the system encoding. */ zConverted = convertUtf8Filename(zUtf8Name); if( zConverted==0 ){ diff --git a/src/pager.c b/src/pager.c index c57fe18745..6f3b651668 100644 --- a/src/pager.c +++ b/src/pager.c @@ -2486,10 +2486,9 @@ static int pager_truncate(Pager *pPager, Pgno nPage){ if( rc==SQLITE_OK && currentSize!=newSize ){ if( currentSize>newSize ){ rc = sqlite3OsTruncate(pPager->fd, newSize); - }else{ + }else if( (currentSize+szPage)<=newSize ){ char *pTmp = pPager->pTmpSpace; memset(pTmp, 0, szPage); - testcase( (newSize-szPage) < currentSize ); testcase( (newSize-szPage) == currentSize ); testcase( (newSize-szPage) > currentSize ); rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage); @@ -2747,10 +2746,11 @@ end_playback: ** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the ** assertion that the transaction counter was modified. */ - assert( - pPager->fd->pMethods==0 || - sqlite3OsFileControl(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0)>=SQLITE_OK - ); +#ifdef SQLITE_DEBUG + if( pPager->fd->pMethods ){ + sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0); + } +#endif /* If this playback is happening automatically as a result of an IO or ** malloc error that occurred after the change-counter was updated but @@ -3087,10 +3087,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ return rc; } } - nPage = (Pgno)(n / pPager->pageSize); - if( nPage==0 && n>0 ){ - nPage = 1; - } + nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize); } /* If the current number of pages in the file is greater than the @@ -3521,7 +3518,7 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){ if( rc==SQLITE_OK ){ pager_reset(pPager); - pPager->dbSize = (Pgno)(nByte/pageSize); + pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); pPager->pageSize = pageSize; sqlite3PageFree(pPager->pTmpSpace); pPager->pTmpSpace = pNew; @@ -4029,9 +4026,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); if( rc==SQLITE_OK && pPager->dbSize>pPager->dbHintSize ){ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; - sqlite3BeginBenignMalloc(); - sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); - sqlite3EndBenignMalloc(); + sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); pPager->dbHintSize = pPager->dbSize; } @@ -6055,7 +6050,8 @@ int sqlite3PagerRollback(Pager *pPager){ } assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK ); - assert( rc==SQLITE_OK || rc==SQLITE_FULL || (rc&0xFF)==SQLITE_IOERR ); + assert( rc==SQLITE_OK || rc==SQLITE_FULL + || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR ); /* If an error occurs during a ROLLBACK, we can no longer trust the pager ** cache. So call pager_error() on the way out to make any error persistent. diff --git a/src/pcache1.c b/src/pcache1.c index 405ae5aec8..f76d7c8e8e 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -40,7 +40,7 @@ typedef struct PGroup PGroup; ** Mode 1 uses more memory (since PCache instances are not able to rob ** unused pages from other PCaches) but it also operates without a mutex, ** and is therefore often faster. Mode 2 requires a mutex in order to be -** threadsafe, but is able recycle pages more efficient. +** threadsafe, but recycles pages more efficiently. ** ** For mode (1), PGroup.mutex is NULL. For mode (2) there is only a single ** PGroup which is the pcache1.grp global variable and its mutex is @@ -66,7 +66,7 @@ struct PGroup { struct PCache1 { /* Cache configuration parameters. Page size (szPage) and the purgeable ** flag (bPurgeable) are set when the cache is created. nMax may be - ** modified at any time by a call to the pcache1CacheSize() method. + ** modified at any time by a call to the pcache1Cachesize() method. ** The PGroup mutex must be held when accessing nMax. */ PGroup *pGroup; /* PGroup this cache belongs to */ @@ -357,7 +357,7 @@ void sqlite3PageFree(void *p){ ** for all page cache needs and we should not need to spill the ** allocation onto the heap. ** -** Or, the heap is used for all page cache memory put the heap is +** Or, the heap is used for all page cache memory but the heap is ** under memory pressure, then again it is desirable to avoid ** allocating a new page cache entry in order to avoid stressing ** the heap even further. @@ -668,7 +668,7 @@ static int pcache1Pagecount(sqlite3_pcache *p){ ** For a non-purgeable cache (a cache used as the storage for an in-memory ** database) there is really no difference between createFlag 1 and 2. So ** the calling function (pcache.c) will never have a createFlag of 1 on -** a non-purgable cache. +** a non-purgeable cache. ** ** There are three different approaches to obtaining space for a page, ** depending on the value of parameter createFlag (which may be 0, 1 or 2). diff --git a/src/pragma.c b/src/pragma.c index bfdcb2370a..581bcaf0eb 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -795,7 +795,7 @@ void sqlite3Pragma( Pager *pPager = sqlite3BtreePager(pDb->pBt); char *proxy_file_path = NULL; sqlite3_file *pFile = sqlite3PagerFile(pPager); - sqlite3OsFileControl(pFile, SQLITE_GET_LOCKPROXYFILE, + sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE, &proxy_file_path); if( proxy_file_path ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index a91997f9d3..af1abecf48 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2627,8 +2627,10 @@ int sqlite3_open_v2( ** to see if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** -** If F is the filename pointer passed into the xOpen() method of a VFS -** implementation and P is the name of the query parameter, then +** If F is the database filename pointer passed into the xOpen() method of +** a VFS implementation when the flags parameter to xOpen() has one or +** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and +** P is the name of the query parameter, then ** sqlite3_uri_parameter(F,P) returns the value of the P ** parameter if it exists or a NULL pointer if P does not appear as a ** query parameter on F. If P is a query parameter of F @@ -2648,8 +2650,9 @@ int sqlite3_open_v2( ** ** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and ** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and -** is not a pathname pointer that SQLite passed into the xOpen VFS method, -** then the behavior of this routine is undefined and probably undesirable. +** is not a database file pathname pointer that SQLite passed into the xOpen +** VFS method, then the behavior of this routine is undefined and probably +** undesirable. */ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); @@ -6205,7 +6208,7 @@ struct sqlite3_pcache_page { ** [[the xShrink() page cache method]] ** ^SQLite invokes the xShrink() method when it wants the page cache to ** free up as much of heap memory as possible. The page cache implementation -** is not obligated to free any memory, but well-behaved implementions should +** is not obligated to free any memory, but well-behaved implementations should ** do their best. */ typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 4e7f2acbb8..f2a517c8f6 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -3163,7 +3163,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ if( objc<3 || (objc&1)!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" - " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN?" + " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" #ifdef SQLITE_HAS_CODEC " ?-key CODECKEY?" #endif diff --git a/src/test2.c b/src/test2.c index fa7dd76ce4..8343692f6a 100644 --- a/src/test2.c +++ b/src/test2.c @@ -537,6 +537,8 @@ static int fake_big_file( int rc; int n; i64 offset; + char *zFile; + int nFile; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N-MEGABYTES FILE\"", 0); @@ -545,17 +547,24 @@ static int fake_big_file( if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; pVfs = sqlite3_vfs_find(0); - rc = sqlite3OsOpenMalloc(pVfs, argv[2], &fd, + nFile = strlen(argv[2]); + zFile = sqlite3_malloc( nFile+2 ); + if( zFile==0 ) return TCL_ERROR; + memcpy(zFile, argv[2], nFile+1); + zFile[nFile+1] = 0; + rc = sqlite3OsOpenMalloc(pVfs, zFile, &fd, (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0 ); if( rc ){ Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0); + sqlite3_free(zFile); return TCL_ERROR; } offset = n; offset *= 1024*1024; rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset); sqlite3OsCloseFree(fd); + sqlite3_free(zFile); if( rc ){ Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0); return TCL_ERROR; diff --git a/src/test3.c b/src/test3.c index 4eabdccfd6..9bac2cac13 100644 --- a/src/test3.c +++ b/src/test3.c @@ -66,6 +66,8 @@ static int btree_open( Btree *pBt; int rc, nCache; char zBuf[100]; + int n; + char *zFilename; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME NCACHE FLAGS\"", 0); @@ -78,8 +80,14 @@ static int btree_open( sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); sqlite3_mutex_enter(sDb.mutex); } - rc = sqlite3BtreeOpen(sDb.pVfs, argv[1], &sDb, &pBt, 0, + n = strlen(argv[1]); + zFilename = sqlite3_malloc( n+2 ); + if( zFilename==0 ) return TCL_ERROR; + memcpy(zFilename, argv[1], n+1); + zFilename[n+1] = 0; + rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); + sqlite3_free(zFilename); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; diff --git a/src/test_journal.c b/src/test_journal.c index ef82070320..00567db598 100644 --- a/src/test_journal.c +++ b/src/test_journal.c @@ -409,6 +409,7 @@ static int openTransaction(jt_file *pMain, jt_file *pJournal){ if( iOff==PENDING_BYTE ) continue; rc = sqlite3OsRead(pMain->pReal, aData, pMain->nPagesize, iOff); pMain->aCksum[ii] = genCksum(aData, pMain->nPagesize); + if( ii+1==pMain->nPage && rc==SQLITE_IOERR_SHORT_READ ) rc = SQLITE_OK; } } @@ -662,7 +663,7 @@ static int jtCheckReservedLock(sqlite3_file *pFile, int *pResOut){ */ static int jtFileControl(sqlite3_file *pFile, int op, void *pArg){ jt_file *p = (jt_file *)pFile; - return sqlite3OsFileControl(p->pReal, op, pArg); + return p->pReal->pMethods->xFileControl(p->pReal, op, pArg); } /* diff --git a/src/test_multiplex.c b/src/test_multiplex.c index eceb8d74ab..af41c0b61c 100644 --- a/src/test_multiplex.c +++ b/src/test_multiplex.c @@ -220,9 +220,27 @@ static int multiplexStrlen30(const char *z){ /* ** Generate the file-name for chunk iChunk of the group with base name ** zBase. The file-name is written to buffer zOut before returning. Buffer -** zOut must be allocated by the caller so that it is at least (nBase+4) +** zOut must be allocated by the caller so that it is at least (nBase+5) ** bytes in size, where nBase is the length of zBase, not including the ** nul-terminator. +** +** If iChunk is 0 (or 400 - the number for the first journal file chunk), +** the output is a copy of the input string. Otherwise, if +** SQLITE_ENABLE_8_3_NAMES is not defined or the input buffer does not contain +** a "." character, then the output is a copy of the input string with the +** three-digit zero-padded decimal representation if iChunk appended to it. +** For example: +** +** zBase="test.db", iChunk=4 -> zOut="test.db004" +** +** Or, if SQLITE_ENABLE_8_3_NAMES is defined and the input buffer contains +** a "." character, then everything after the "." is replaced by the +** three-digit representation of iChunk. +** +** zBase="test.db", iChunk=4 -> zOut="test.004" +** +** The output buffer string is terminated by 2 0x00 bytes. This makes it safe +** to pass to sqlite3_uri_parameter() and similar. */ static void multiplexFilename( const char *zBase, /* Filename for chunk 0 */ @@ -231,9 +249,9 @@ static void multiplexFilename( int iChunk, /* Chunk to generate filename for */ char *zOut /* Buffer to write generated name to */ ){ - memcpy(zOut, zBase, nBase+1); + int n = nBase; + memcpy(zOut, zBase, n+1); if( iChunk!=0 && iChunk!=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){ - int n = nBase; #ifdef SQLITE_ENABLE_8_3_NAMES int i; for(i=n-1; i>0 && i>=n-4 && zOut[i]!='.'; i--){} @@ -247,7 +265,11 @@ static void multiplexFilename( } #endif sqlite3_snprintf(4,&zOut[n],"%03d",iChunk); + n += 3; } + + assert( zOut[n]=='\0' ); + zOut[n+1] = '\0'; } /* Compute the filename for the iChunk-th chunk @@ -266,7 +288,7 @@ static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){ if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){ char *z; int n = pGroup->nName; - pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+4 ); + pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+5 ); if( z==0 ){ return SQLITE_NOMEM; } @@ -306,7 +328,6 @@ static sqlite3_file *multiplexSubOpen( *rc = multiplexSubFilename(pGroup, iChunk); if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){ int flags, bExists; - createFlag = (pGroup->flags & SQLITE_OPEN_CREATE)!=0; flags = pGroup->flags; if( createFlag ){ flags |= SQLITE_OPEN_CREATE; @@ -350,6 +371,7 @@ static sqlite3_int64 multiplexSubSize( sqlite3_file *pSub; sqlite3_int64 sz = 0; + if( *rc ) return 0; pSub = multiplexSubOpen(pGroup, iChunk, rc, NULL, 0); if( pSub==0 ) return 0; *rc = pSub->pMethods->xFileSize(pSub, &sz); @@ -491,13 +513,14 @@ static int multiplexOpen( } if( rc==SQLITE_OK ){ + const char *zUri = (flags & SQLITE_OPEN_URI) ? zName : 0; /* assign pointers to extra space allocated */ memset(pGroup, 0, sz); pMultiplexOpen->pGroup = pGroup; pGroup->bEnabled = -1; - pGroup->bTruncate = sqlite3_uri_boolean(zName, "truncate", - (flags & SQLITE_OPEN_MAIN_DB)==0); - pGroup->szChunk = sqlite3_uri_int64(zName, "chunksize", + pGroup->bTruncate = sqlite3_uri_boolean(zUri, "truncate", + (flags & SQLITE_OPEN_MAIN_DB)==0); + pGroup->szChunk = sqlite3_uri_int64(zUri, "chunksize", SQLITE_MULTIPLEX_CHUNK_SIZE); pGroup->szChunk = (pGroup->szChunk+0xffff)&~0xffff; if( zName ){ @@ -611,7 +634,7 @@ static int multiplexDelete( */ int nName = strlen(zName); char *z; - z = sqlite3_malloc(nName + 4); + z = sqlite3_malloc(nName + 5); if( z==0 ){ rc = SQLITE_IOERR_NOMEM; }else{ diff --git a/src/test_quota.c b/src/test_quota.c index 4529bd3028..c8ed7389e5 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -937,30 +937,38 @@ int sqlite3_quota_file(const char *zFilename){ int rc; int outFlags = 0; sqlite3_int64 iSize; - fd = (sqlite3_file*)sqlite3_malloc(gQuota.sThisVfs.szOsFile + - gQuota.sThisVfs.mxPathname+1); - if( fd==0 ) return SQLITE_NOMEM; - zFull = gQuota.sThisVfs.szOsFile + (char*)fd; - rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, - gQuota.sThisVfs.mxPathname+1, zFull); + int nAlloc = gQuota.sThisVfs.szOsFile + gQuota.sThisVfs.mxPathname+2; + + /* Allocate space for a file-handle and the full path for file zFilename */ + fd = (sqlite3_file *)sqlite3_malloc(nAlloc); + if( fd==0 ){ + rc = SQLITE_NOMEM; + }else{ + zFull = &((char *)fd)[gQuota.sThisVfs.szOsFile]; + rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, + gQuota.sThisVfs.mxPathname+1, zFull); + } + if( rc==SQLITE_OK ){ + zFull[strlen(zFull)+1] = '\0'; rc = quotaOpen(&gQuota.sThisVfs, zFull, fd, SQLITE_OPEN_READONLY | SQLITE_OPEN_MAIN_DB, &outFlags); - } - if( rc==SQLITE_OK ){ - fd->pMethods->xFileSize(fd, &iSize); - fd->pMethods->xClose(fd); - }else if( rc==SQLITE_CANTOPEN ){ - quotaGroup *pGroup; - quotaFile *pFile; - quotaEnter(); - pGroup = quotaGroupFind(zFull); - if( pGroup ){ - pFile = quotaFindFile(pGroup, zFull, 0); - if( pFile ) quotaRemoveFile(pFile); + if( rc==SQLITE_OK ){ + fd->pMethods->xFileSize(fd, &iSize); + fd->pMethods->xClose(fd); + }else if( rc==SQLITE_CANTOPEN ){ + quotaGroup *pGroup; + quotaFile *pFile; + quotaEnter(); + pGroup = quotaGroupFind(zFull); + if( pGroup ){ + pFile = quotaFindFile(pGroup, zFull, 0); + if( pFile ) quotaRemoveFile(pFile); + } + quotaLeave(); } - quotaLeave(); } + sqlite3_free(fd); return rc; } diff --git a/src/util.c b/src/util.c index 4a332a5e98..fd3c858ab7 100644 --- a/src/util.c +++ b/src/util.c @@ -1164,10 +1164,6 @@ int sqlite3AbsInt32(int x){ ** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always ** do the suffix shortening regardless of URI parameter. ** -** Assume that zBaseFilename contains two \000 terminator bytes (so that -** it can be harmlessly passed into sqlite3_uri_parameter()) and copy both -** zero terminator bytes into the end of the revised name. -** ** Examples: ** ** test.db-journal => test.nal @@ -1176,7 +1172,6 @@ int sqlite3AbsInt32(int x){ ** test.db-mj7f3319fa => test.9fa */ void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ - assert( zBaseFilename[strlen(zBaseFilename)+1]==0 ); #if SQLITE_ENABLE_8_3_NAMES<2 if( sqlite3_uri_boolean(zBaseFilename, "8_3_names", 0) ) #endif @@ -1184,7 +1179,7 @@ void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ int i, sz; sz = sqlite3Strlen30(z); for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} - if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 5); + if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4); } } #endif diff --git a/src/vdbe.c b/src/vdbe.c index c8573f3d6a..8a68602ff7 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -161,12 +161,6 @@ int sqlite3_found_count = 0; if( ((P)->flags&MEM_Ephem)!=0 \ && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} -/* -** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) -** P if required. -*/ -#define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) - /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ #ifdef SQLITE_OMIT_MERGE_SORT # define isSorter(x) 0 diff --git a/src/vdbeInt.h b/src/vdbeInt.h index f38d185592..26077b6845 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -486,8 +486,10 @@ int sqlite3VdbeMemHandleBom(Mem *pMem); #ifndef SQLITE_OMIT_INCRBLOB int sqlite3VdbeMemExpandBlob(Mem *); + #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) #else #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK + #define ExpandBlob(P) SQLITE_OK #endif #endif /* !defined(_VDBEINT_H_) */ diff --git a/src/vdbemem.c b/src/vdbemem.c index 0c78594319..f8777a791d 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -18,12 +18,6 @@ #include "sqliteInt.h" #include "vdbeInt.h" -/* -** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) -** P if required. -*/ -#define expandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) - /* ** If pMem is an object with a valid string representation, this routine ** ensures the internal encoding for the string representation is @@ -123,7 +117,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ int f; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( (pMem->flags&MEM_RowSet)==0 ); - expandBlob(pMem); + ExpandBlob(pMem); f = pMem->flags; if( (f&(MEM_Str|MEM_Blob)) && pMem->z!=pMem->zMalloc ){ if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){ @@ -960,7 +954,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ } assert( (MEM_Blob>>3) == MEM_Str ); pVal->flags |= (pVal->flags & MEM_Blob)>>3; - expandBlob(pVal); + ExpandBlob(pVal); if( pVal->flags&MEM_Str ){ sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&SQLITE_PTR_TO_INT(pVal->z)) ){ diff --git a/src/wal.c b/src/wal.c index b9d3532204..db9ce5186f 100644 --- a/src/wal.c +++ b/src/wal.c @@ -1727,7 +1727,7 @@ static int walCheckpoint( i64 nReq = ((i64)mxPage * szPage); rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); + sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); } } @@ -1843,7 +1843,9 @@ int sqlite3WalClose( ); if( rc==SQLITE_OK ){ int bPersist = -1; - sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist); + sqlite3OsFileControlHint( + pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist + ); if( bPersist!=1 ){ /* Try to delete the WAL file if the checkpoint completed and ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal @@ -1864,7 +1866,9 @@ int sqlite3WalClose( walIndexClose(pWal, isDelete); sqlite3OsClose(pWal->pWalFd); if( isDelete ){ + sqlite3BeginBenignMalloc(); sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0); + sqlite3EndBenignMalloc(); } WALTRACE(("WAL%p: closed\n", pWal)); sqlite3_free((void *)pWal->apWiData); diff --git a/test/backup2.test b/test/backup2.test index 34924b02c8..989319923a 100644 --- a/test/backup2.test +++ b/test/backup2.test @@ -142,21 +142,18 @@ do_test backup2-9 { # Try to restore from an unreadable file. # if {$tcl_platform(platform)=="windows"} { - do_test backup2-10 { - forcedelete bu3.db - file mkdir bu3.db - set rc [catch {db restore temp bu3.db} res] - lappend rc $res - } {1 {cannot open source database: unable to open database file}} -} -if {$tcl_platform(platform)!="windows"} { - do_test backup2-10 { - forcedelete bu3.db - file mkdir bu3.db - set rc [catch {db restore temp bu3.db} res] - lappend rc $res - } {1 {cannot open source database: disk I/O error}} + set msg {cannot open source database: unable to open database file} +} elseif {$tcl_platform(os)=="OpenBSD"} { + set msg {restore failed: file is encrypted or is not a database} +} else { + set msg {cannot open source database: disk I/O error} } +do_test backup2-10 { + forcedelete bu3.db + file mkdir bu3.db + set rc [catch {db restore temp bu3.db} res] + lappend rc $res +} [list 1 $msg] # Try to restore from something that is not a database file. # diff --git a/test/corruptF.test b/test/corruptF.test new file mode 100644 index 0000000000..33eef39bdd --- /dev/null +++ b/test/corruptF.test @@ -0,0 +1,150 @@ +# 2012 January 12 +# +# 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 +set testprefix corruptF + +# Do not use a codec for tests in this file, as the database file is +# manipulated directly using tcl scripts (using the [hexio_write] command). +# +do_not_use_codec + +proc str {i} { format %08d $i } + +# Create a 6 page database containing a single table - t1. Table t1 +# consists of page 2 (the root page) and pages 5 and 6 (leaf pages). +# Database pages 3 and 4 are on the free list. +# +proc create_test_db {} { + catch { db close } + forcedelete test.db + sqlite3 db test.db + db func str str + execsql { + PRAGMA auto_vacuum = 0; + PRAGMA page_size = 1024; + CREATE TABLE t1(x); /* root page = 2 */ + CREATE TABLE t2(x); /* root page = 3 */ + CREATE TABLE t3(x); /* root page = 4 */ + + INSERT INTO t1 VALUES(str(1)); + INSERT INTO t1 SELECT str(rowid+1) FROM t1; + INSERT INTO t1 SELECT str(rowid+2) FROM t1; + INSERT INTO t1 SELECT str(rowid+4) FROM t1; + INSERT INTO t1 SELECT str(rowid+8) FROM t1; + INSERT INTO t1 SELECT str(rowid+16) FROM t1; + INSERT INTO t1 SELECT str(rowid+32) FROM t1; + INSERT INTO t1 SELECT str(rowid+64) FROM t1; + DROP TABLE t2; + DROP TABLE t3; + } + db close +} + +do_test 1.1 { create_test_db } {} + +# Check the db is as we expect. 6 pages in total, with 3 and 4 on the free +# list. Page 3 is the free list trunk and page 4 is a leaf. +# +do_test 1.2 { file size test.db } [expr 6*1024] +do_test 1.3 { hexio_read test.db 32 4 } 00000003 +do_test 1.4 { hexio_read test.db [expr 2*1024] 12 } 000000000000000100000004 + +# Change the free-list entry to page 6 and reopen the db file. +do_test 1.5 { + hexio_write test.db [expr 2*1024 + 8] 00000006 + sqlite3 db test.db +} {} + +# Now create a new table in the database file. The root of the new table +# is page 6, which is also the right-most leaf page in table t1. +# +do_execsql_test 1.6 { + CREATE TABLE t4(x); + SELECT * FROM sqlite_master; +} { + table t1 t1 2 {CREATE TABLE t1(x)} + table t4 t4 6 {CREATE TABLE t4(x)} +} + +# At one point this was causing an assert to fail. +# +# This statement opens a cursor on table t1 and does a full table scan. As +# each row is visited, it is copied into table t4. There is no temporary +# table. +# +# When the t1 cursor reaches page 6 (which is both the right-most leaf of +# t1 and the root of t4), it continues to iterate through the keys within +# it (which at this point are keys that have been inserted into t4). And +# for each row visited, another row is inserted into page 6 - it being the +# root page of t4. Eventually, page 6 becomes full and the height of the +# b-tree for table t4 increased. From the point of view of the t1 cursor, +# this unexpectedly reduces the number of keys on page 6 in the middle of +# its iteration, which causes an assert() to fail. +# +db_save_and_close +if 1 { +for {set i 0} {$i < 128} {incr i} { + db_restore_and_reopen + do_test 1.7.$i { + set res [ + catchsql { INSERT INTO t4 SELECT x FROM t1 WHERE rowid>$i } + ] + if {$res == "0 {}" || $res == "1 {database disk image is malformed}"} { + set res "" + } + set res + } {} +} +} + +do_test 2.1 { create_test_db } {} +do_test 2.2 { file size test.db } [expr 6*1024] +do_test 2.3 { hexio_read test.db 32 4 } 00000003 +do_test 2.4 { hexio_read test.db [expr 2*1024] 12 } 000000000000000100000004 + +# Change the free-list entry to page 5 and reopen the db file. +do_test 2.5 { + hexio_write test.db [expr 2*1024 + 8] 00000005 + sqlite3 db test.db +} {} + +# Now create a new table in the database file. The root of the new table +# is page 5, which is also the right-most leaf page in table t1. +# +do_execsql_test 2.6 { + CREATE TABLE t4(x); + SELECT * FROM sqlite_master; +} { + table t1 t1 2 {CREATE TABLE t1(x)} + table t4 t4 5 {CREATE TABLE t4(x)} +} + +db_save_and_close +for {set i 127} {$i >= 0} {incr i -1} { + db_restore_and_reopen + do_test 2.7.$i { + set res [ + catchsql { + INSERT INTO t4 SELECT x FROM t1 WHERE rowid<$i ORDER BY rowid DESC + } + ] + if {$res == "0 {}" || $res == "1 {database disk image is malformed}"} { + set res "" + } + set res + } {} +} + +finish_test + diff --git a/test/malloc5.test b/test/malloc5.test index 71f56bbbc1..c02f65e344 100644 --- a/test/malloc5.test +++ b/test/malloc5.test @@ -352,7 +352,7 @@ do_test malloc5-6.3.1 { do_test malloc5-6.3.2 { # Try to release 7700 bytes. This should release all the # non-dirty pages held by db2. - sqlite3_release_memory [expr 7*1100] + sqlite3_release_memory [expr 7*1132] list [nPage db] [nPage db2] } {10 3} do_test malloc5-6.3.3 { @@ -366,7 +366,7 @@ do_test malloc5-6.3.4 { # the rest of the db cache. But the db2 cache remains intact, because # SQLite tries to avoid calling sync(). if {$::tcl_platform(wordSize)==8} { - sqlite3_release_memory 10177 + sqlite3_release_memory 10500 } else { sqlite3_release_memory 9900 } diff --git a/test/multiplex.test b/test/multiplex.test index 7168e753ab..32c87d9a52 100644 --- a/test/multiplex.test +++ b/test/multiplex.test @@ -156,6 +156,9 @@ sqlite3_multiplex_initialize "" 1 multiplex_set db main 32768 16 forcedelete test.x +foreach f [glob -nocomplain {test.x*[0-9][0-9][0-9]}] { + forcedelete $f +} do_test multiplex-2.1.2 { sqlite3 db test.x execsql { @@ -192,12 +195,17 @@ do_test multiplex-2.4.2 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168} -do_test multiplex-2.4.99 { +do_test multiplex-2.4.5 { db close + sqlite3 db test.x + db eval vacuum + db close + glob test.x* +} {test.x} +do_test multiplex-2.4.99 { sqlite3_multiplex_shutdown } {SQLITE_OK} - do_test multiplex-2.5.1 { multiplex_delete test.x sqlite3_multiplex_initialize "" 1 diff --git a/test/permutations.test b/test/permutations.test index f48c0e05a7..19388b1844 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -145,7 +145,7 @@ test_suite "valgrind" -prefix "" -description { Run the "veryquick" test suite with a couple of multi-process tests (that fail under valgrind) omitted. } -files [ - test_set $allquicktests -exclude *malloc* *ioerr* *fault* + test_set $allquicktests -exclude *malloc* *ioerr* *fault* wal.test ] -initialize { set ::G(valgrind) 1 } -shutdown { @@ -533,6 +533,8 @@ test_suite "inmemory_journal" -description { # Exclude stmt.test, which expects sub-journals to use temporary files. stmt.test + zerodamage.test + # WAL mode is different. wal* tkt-2d1a5c67d.test backcompat.test }] diff --git a/test/shrink.test b/test/shrink.test index cc055c63b5..e03ebeeb6e 100644 --- a/test/shrink.test +++ b/test/shrink.test @@ -19,6 +19,7 @@ source $testdir/tester.tcl unset -nocomplain baseline do_test shrink-1.1 { db eval { + PRAGMA cache_size = 2000; CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(randomblob(1000000),1); } diff --git a/test/tclsqlite.test b/test/tclsqlite.test index 3b3f750fe3..9245bd7015 100644 --- a/test/tclsqlite.test +++ b/test/tclsqlite.test @@ -25,7 +25,7 @@ source $testdir/tester.tcl if {[sqlite3 -has-codec]} { set r "sqlite_orig HANDLE FILENAME ?-key CODEC-KEY?" } else { - set r "sqlite_orig HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN?" + set r "sqlite_orig HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" } do_test tcl-1.1 { set v [catch {sqlite3 bogus} msg] diff --git a/test/unixexcl.test b/test/unixexcl.test index 8c64488d75..0147e6bbb4 100644 --- a/test/unixexcl.test +++ b/test/unixexcl.test @@ -85,6 +85,7 @@ do_multiclient_test tn { code1 { db close; sqlite3 db file:test.db?psow=0 -vfs unix-excl -uri 1 } code2 { db2 close; sqlite3 db2 file:test.db?psow=0 -vfs unix-excl -uri 1 } sql1 { + PRAGMA auto_vacuum = 0; PRAGMA journal_mode = WAL; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); diff --git a/test/walcrash.test b/test/walcrash.test index cfce5fed6d..adc4841dd1 100644 --- a/test/walcrash.test +++ b/test/walcrash.test @@ -76,7 +76,7 @@ for {set i 1} {$i < $REPEATS} {incr i} { for {set i 1} {$i < $REPEATS} {incr i} { forcedelete test.db test.db-wal do_test walcrash-2.$i.1 { - crashsql -delay 4 -file test.db-wal -seed [incr seed] { + crashsql -delay 5 -file test.db-wal -seed [incr seed] { PRAGMA journal_mode = WAL; CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES(1, 2); @@ -147,7 +147,7 @@ for {set i 1} {$i < $REPEATS} {incr i} { forcedelete test2.db test2.db-wal do_test walcrash-4.$i.1 { - crashsql -delay 3 -file test.db-wal -seed [incr seed] -blocksize 4096 { + crashsql -delay 4 -file test.db-wal -seed [incr seed] -blocksize 4096 { PRAGMA journal_mode = WAL; PRAGMA page_size = 1024; CREATE TABLE t1(a PRIMARY KEY, b); @@ -175,7 +175,7 @@ for {set i 1} {$i < $REPEATS} {incr i} { forcedelete test2.db test2.db-wal do_test walcrash-5.$i.1 { - crashsql -delay 11 -file test.db-wal -seed [incr seed] -blocksize 4096 { + crashsql -delay 13 -file test.db-wal -seed [incr seed] -blocksize 4096 { PRAGMA journal_mode = WAL; PRAGMA page_size = 1024; BEGIN; @@ -216,7 +216,7 @@ for {set i 1} {$i < $REPEATS} {incr i} { forcedelete test2.db test2.db-wal do_test walcrash-6.$i.1 { - crashsql -delay 12 -file test.db-wal -seed [incr seed] -blocksize 512 { + crashsql -delay 14 -file test.db-wal -seed [incr seed] -blocksize 512 { PRAGMA journal_mode = WAL; PRAGMA page_size = 1024; BEGIN; @@ -234,9 +234,9 @@ for {set i 1} {$i < $REPEATS} {incr i} { INSERT INTO t1 SELECT randomblob(900) FROM t1 LIMIT 4; /* 32 */ PRAGMA wal_checkpoint; - INSERT INTO t1 VALUES(randomblob(900)); - INSERT INTO t1 VALUES(randomblob(900)); - INSERT INTO t1 VALUES(randomblob(900)); + INSERT INTO t1 VALUES(randomblob(9000)); + INSERT INTO t1 VALUES(randomblob(9000)); + INSERT INTO t1 VALUES(randomblob(9000)); } } {1 {child process exited abnormally}} diff --git a/test/walfault.test b/test/walfault.test index 1b71d78a4c..6f9aeddea2 100644 --- a/test/walfault.test +++ b/test/walfault.test @@ -123,7 +123,6 @@ do_faultsim_test walfault-3 -prep { faultsim_test_result {0 {}} } - #-------------------------------------------------------------------------- # if {[permutation] != "inmemory_journal"} { @@ -141,7 +140,9 @@ if {[permutation] != "inmemory_journal"} { SELECT * FROM t1; } } -test { - faultsim_test_result {0 {wal 0 7 7 a b}} + # Update: The following changed from {0 {wal 0 7 7 a b}} as a result + # of PSOW being set by default. + faultsim_test_result {0 {wal 0 5 5 a b}} faultsim_integrity_check } } @@ -542,10 +543,11 @@ do_faultsim_test walfault-14 -prep { INSERT INTO abc VALUES(randomblob(1500)); } } -test { - faultsim_test_result {0 {0 10 10}} + faultsim_test_result {0 {0 9 9}} faultsim_integrity_check set nRow [db eval {SELECT count(*) FROM abc}] if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" } } +finish_test finish_test diff --git a/test/zerodamage.test b/test/zerodamage.test index 0e82ce3505..3d18c8dea8 100644 --- a/test/zerodamage.test +++ b/test/zerodamage.test @@ -20,6 +20,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix wal5 +ifcapable !vtab { + finish_test + return +} + # POWERSAFE_OVERWRITE defaults to true # do_test zerodamage-1.0 { @@ -110,3 +115,5 @@ do_test zerodamage-3.1 { } file size test.db-wal } {8416} + +finish_test diff --git a/tool/lemon.c b/tool/lemon.c index 1fb0308bec..c3e612b068 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -117,8 +117,6 @@ void ResortStates(struct lemon *); void SetSize(int); /* All sets will be of size N */ char *SetNew(void); /* A new set for element 0..N */ void SetFree(char*); /* Deallocate a set */ - -char *SetNew(void); /* A new set for element 0..N */ int SetAdd(char*,int); /* Add element to a set */ int SetUnion(char *,char *); /* A <- A U B, thru element N */ #define SetFind(X,Y) (X[Y]) /* True if Y is in set X */ @@ -686,8 +684,9 @@ void FindFirstSets(struct lemon *lemp) for(rp=lemp->rule; rp; rp=rp->next){ if( rp->lhs->lambda ) continue; for(i=0; inrhs; i++){ - struct symbol *sp = rp->rhs[i]; - if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break; + struct symbol *sp = rp->rhs[i]; + assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE ); + if( sp->lambda==LEMON_FALSE ) break; } if( i==rp->nrhs ){ rp->lhs->lambda = LEMON_TRUE; @@ -968,7 +967,7 @@ void FindFollowSets(struct lemon *lemp) }while( progress ); } -static int resolve_conflict(struct action *,struct action *, struct symbol *); +static int resolve_conflict(struct action *,struct action *); /* Compute the reduce actions, and resolve conflicts. */ @@ -1022,7 +1021,7 @@ void FindActions(struct lemon *lemp) for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){ /* The two actions "ap" and "nap" have the same lookahead. ** Figure out which one should be used */ - lemp->nconflict += resolve_conflict(ap,nap,lemp->errsym); + lemp->nconflict += resolve_conflict(ap,nap); } } } @@ -1057,8 +1056,7 @@ void FindActions(struct lemon *lemp) */ static int resolve_conflict( struct action *apx, - struct action *apy, - struct symbol *errsym /* The error symbol (if defined. NULL otherwise) */ + struct action *apy ){ struct symbol *spx, *spy; int errcnt = 0; @@ -1995,7 +1993,7 @@ static void parseonetoken(struct pstate *psp) }else if( x[0]=='{' ){ if( psp->prevrule==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, -"There is no prior rule opon which to attach the code \ +"There is no prior rule upon which to attach the code \ fragment which begins on this line."); psp->errorcnt++; }else if( psp->prevrule->code!=0 ){