]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Merging local changes to apple-osx
authoradam <adam@noemail.net>
Fri, 24 Jun 2011 20:47:06 +0000 (20:47 +0000)
committeradam <adam@noemail.net>
Fri, 24 Jun 2011 20:47:06 +0000 (20:47 +0000)
FossilOrigin-Name: 34f0efa2b12e8eb09331768b1524a076baeb34ea

30 files changed:
manifest
manifest.uuid
src/btree.c
src/main.c
src/os.c
src/os_unix.c
src/pager.c
src/pragma.c
src/select.c
src/sqlite.h.in
src/sqlite3_private.h
src/test1.c
src/test_config.c
src/test_rtree.c
src/test_superlock.c
src/vdbetrace.c
src/wal.c
src/wal.h
test/fallocate.test
test/incrblob3.test
test/multiplex.test
test/pager1.test
test/pragma.test
test/superlock.test
test/tester.tcl
test/wal2.test
test/wal3.test
test/wal6.test
test/walcrash2.test
test/walro.test

index 99539b6a6c58d57009b5411f8e2da259ebf16a42..8b38b14ad9827dc2a82f29dad2091d748013fe40 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Pull\sthe\slast-minute\sfixes\sfor\s3.7.7\sinto\sthe\sapple-osx\sbranch.
-D 2011-06-23T17:42:45.824
+C Merging\slocal\schanges\sto\sapple-osx
+D 2011-06-24T20:47:06.827
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 8410b02448997eb43bdf0ffa482c9bc2d2624e45
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -127,7 +127,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c 986c15232757f2873dff35ee3b35cbf935fc573c
 F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
-F src/btree.c 8c46f0ab69ad9549c75a3a91fed87abdaa743e2f
+F src/btree.c fea8eaab6b7bf0877e35a44827049226e2c397ec
 F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
 F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
 F src/build.c 5a428625d21ad409514afb40ad083bee25dd957a
@@ -149,7 +149,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
 F src/legacy.c 015826a958f690302d27e096a68d50b3657e4201
 F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
 F src/loadext.c 3ae0d52da013a6326310655be6473fd472347b85
-F src/main.c fbe239ee3e61b0e83a8d53028e9efaf8368bc73f
+F src/main.c a5414c66da45e65518e9f84e9cfe4ac1ff30ea06
 F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c 46095d62b241466ef51970e592aa3a7a87e443e1
@@ -164,35 +164,35 @@ F src/mutex_os2.c 882d735098c07c8c6a5472b8dd66e19675fe117f
 F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579
 F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33
 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
-F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
+F src/os.c 1663f3754a3da185369a121a4f417762f77880b6
 F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
 F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
-F src/os_unix.c aeef5f00753ee92478ae1d6c0c92b1aee26691c5
+F src/os_unix.c af3aa6c091f501a590b45c95aa6af269ce728a94
 F src/os_win.c eafcd6b91cf204a7ef29ac1ef2a1b7132e132e58
-F src/pager.c 120550e7ef01dafaa2cbb4a0528c0d87c8f12b41
+F src/pager.c e3688b37e781e8e069ed6375299da82a34a41794
 F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
 F src/pcache.c 49e718c095810c6b3334e3a6d89970aceaddefce
 F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
 F src/pcache1.c 912bd5687d6df344698d8e69560f347b6e21c18a
-F src/pragma.c 2824f4c8f34fd917ba33948ae564ff947c1e6576
+F src/pragma.c a1010255cd602e2d0cd7fa6f63f9de338ce8ac78
 F src/prepare.c 9d7403fe75fefa134351b41400d09ba1b189134b
 F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
 F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
-F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff
+F src/select.c 75b7dd8c6a5ff9b8ec3f7ed51d31af8b30f114bc
 F src/shell.c 0e0173b3e79d956368013e759f084caa7995ecb1
-F src/sqlite.h.in 4b7255c10d39c5faf089dbd29cde7c367ff39f1f
-F src/sqlite3_private.h 2a814d17913732831acf13e7e87860105a3416e4
+F src/sqlite.h.in 6961961e59fdb55d6719f11db79fb167c19bb275
+F src/sqlite3_private.h 1d18557420cb0cc51ff31ec0a3fcce11e5cd6f5a
 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
 F src/sqliteInt.h 7b72f7c6929757c0678d94524dbc7e7e3d6dc398
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
 F src/tclsqlite.c 5db825be61708b1a2b3f8f6e185e9b753829acef
-F src/test1.c 07463c4177b450dd4d9e2425c58ea8cc34502247
+F src/test1.c 4671911a936bc2c9a845bf32f70d770e7a5cd0b8
 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
 F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
 F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
@@ -205,7 +205,7 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
 F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
 F src/test_backup.c 64fd6173ad99daade1227aa17c3ca0d18fa5e5fa
 F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
-F src/test_config.c a7e692af95c211b29bd6a6c4b3dfe0a2a8f808a7
+F src/test_config.c 90707f2dd59c01f11bbbbb168833fdef73f1e5de
 F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
 F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5
@@ -224,11 +224,11 @@ F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
 F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32
 F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
 F src/test_quota.c cc4f67e12558a252ea4a11720be268348f4b1595
-F src/test_rtree.c 30c981837445a4e187ee850a49c4760d9642f7c3
+F src/test_rtree.c af76d5a2ead69280ba33d318263167ad9e674bb0
 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
 F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
-F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
+F src/test_superlock.c 12e2bc484c6c2ba837327d37f2e6a6fd9d1464f8
 F src/test_syscall.c 162c4ec0137a549c009bb9ecab550527743cfc5d
 F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
 F src/test_thread.c fe9a7803fc1d69cccb60f016f28c1cedf2d9fcfa
@@ -249,10 +249,10 @@ F src/vdbeapi.c 7f01db7d26758b2be316116f8325a0b9f0d8edd6
 F src/vdbeaux.c 0b2e2880f13af400a27c92a7673287c3eaec8b21
 F src/vdbeblob.c f024f0bf420f36b070143c32b15cc7287341ffd3
 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
-F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
+F src/vdbetrace.c 4b92fe7355f682368203d29b2be7125cbab85e79
 F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582
-F src/wal.c 0c70ad7b1cac6005fa5e2cbefd23ee05e391c290
-F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
+F src/wal.c 876f9b68df44e65a32c5106010a0a95ee554a284
+F src/wal.h e75d87752bd5df3dc4152ee2cb3b0dcd0b309e5e
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
 F src/where.c 55403ce19c506be6a321c7f129aff693d6103db5
 F test/8_3_names.test b93687beebd17f6ebf812405a6833bae5d1f4199
@@ -399,7 +399,7 @@ F test/exclusive2.test 343d55130c12c67b8bf10407acec043a6c26c86b
 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
 F test/exists.test 5e2d64b4eb5a9d08876599bdae2e1213d2d12e2a
 F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d
-F test/fallocate.test a9927b638567e2e776c112f54d701402a0e74023
+F test/fallocate.test 95a45d7a705ab985a62ceed8ac7b145fcb61154e
 F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
 F test/filefmt.test f178cfc29501a14565954c961b226e61877dd32c
 F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
@@ -504,7 +504,7 @@ F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
 F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
 F test/incrblob.test 76e787ca3301d9bfa6906031c626d26f8dd707de
 F test/incrblob2.test edc3a96e557bd61fb39acc8d2edd43371fbbaa19
-F test/incrblob3.test aedbb35ea1b6450c33b98f2b6ed98e5020be8dc7
+F test/incrblob3.test 086482e7937202be9f8cf327117a042d8628fe7d
 F test/incrblob_err.test c577c91d4ed9e8336cdb188b15d6ee2a6fe9604e
 F test/incrblobfault.test 917c0292224c64a56ef7215fd633a3a82f805be0
 F test/incrvacuum.test 453d1e490d8f5ad2c9b3a54282a0690d6ae56462
@@ -599,7 +599,7 @@ F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd
 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
 F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3
 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
-F test/multiplex.test 555080c87abfc72ba68e2f3df01d4a9a7a4fdf58
+F test/multiplex.test afd41c4fcf132a8940761c7852b427c37705e4bb
 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
 F test/nan.test dc212a22b36109fd1ae37154292444ef249c5ec2
@@ -610,7 +610,7 @@ F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
 F test/null.test a8b09b8ed87852742343b33441a9240022108993
 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
 F test/oserror.test 3fe52e0bd2891a9bf7cdeb639554992453d46301
-F test/pager1.test 228a831060dab96bc91b03ba2a85cedefd1ab38a
+F test/pager1.test 4b7c08cab0717a051e9faf093d23ac202a280050
 F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1
 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
 F test/pagerfault.test b0a275779f0b0233809d2644dec94d689357e00a
@@ -621,7 +621,7 @@ F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
 F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
 F test/permutations.test 1e8892ebf1bd6e9e8036f4841c72a91bf72da74a
-F test/pragma.test 9b08f84e691065281c5e705988a754bf26c2bfaa
+F test/pragma.test 6c4b98a9f5e3fbc23631fcbfa53b095f3955ca72
 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
 F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
@@ -690,7 +690,7 @@ F test/stmt.test 78a6764439cfa5abdcbf98d4d084739e81eeec4f
 F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
 F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
-F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082
+F test/superlock.test 9c567d759fe383abefde0e801e36a3b3aadb082e
 F test/sync.test 2bd73b585089c99e76b3e1796c42059b7d89d872
 F test/syscall.test 707c95e4ab7863e13f1293c6b0c76bead30249b3
 F test/sysfault.test c79441d88d23696fbec7b147dba98d42a04f523f
@@ -700,7 +700,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
 F test/tempdb.test 3263e5c3f0604e54d307481e8587327c54544d18
 F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
 F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
-F test/tester.tcl 801cb7ba763bf5a19475cfb865ad55dddb39ad6a
+F test/tester.tcl be83dc1662e7bce357d53f7ff9cecdc16a7046eb
 F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
 F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
 F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
@@ -881,23 +881,23 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
 F test/wal.test 3ff610479cd005117f54a8c003a8d86432e6f2ac
-F test/wal2.test 24239bb8cd8ca5e47c9ab4ac705f7343d2f9b5a2
-F test/wal3.test 34c65b1cb78e1da5d24c9ab74534c376784f96ea
+F test/wal2.test 6c65a48c23309baec605d8b14dbc41c2d5baceb0
+F test/wal3.test 804be49c55b362c356f2b98cd8bac77145cfa647
 F test/wal4.test 6a68c45bc1ca24a3592ec449ddcb92b29d0e0e87
 F test/wal5.test f06a0427e06db00347e32eb9fa99d6a5c0f2d088
-F test/wal6.test 07aa31ca8892d0527f2c5c5a9a2a87aa421dfaa8
+F test/wal6.test 8df39843b1471dc02993d173937b2c6589e2cb59
 F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
 F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
 F test/walbak.test 767e1c9e0ea0cfb907873b332883e66e187fa4bc
 F test/walbig.test 78ac493db2abdb65b9c6cace5b851cc32df1d449
 F test/walcksum.test cf6787f2ee1a6a3da6f0c2b20b9ede5153e4e03f
 F test/walcrash.test 80c1cc3173a0ef09d8303fa556cb0187a36d82ea
-F test/walcrash2.test 929c99d14ee2e3e3ef82585058968a8b12f72706
+F test/walcrash2.test c032d0040374ae28b41f99fc0cc290b4e2e34f17
 F test/walfault.test 7db81f3dac64ce8897196f199c2909078bcabf8d
 F test/walhook.test c934ac5219fee2b4e7653d291db9107b8dc73bba
 F test/walmode.test feb39956ec6f415fbb9dcb12d91243391c2c4715
 F test/walnoshm.test a074428046408f4eb5c6a00e09df8cc97ff93317
-F test/walro.test 2d5d69e2e99da19ce6faab340330234fc4ca0720
+F test/walro.test 05769ae10ddce1b6ad41bdd5326ab7ef951c8278
 F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
 F test/walslow.test 989854bc5c214700a9f2d545bb158643813b8881
 F test/walthread.test e6e32e93ccebfa401dfc0dd930c79daa3472b0ae
@@ -954,7 +954,7 @@ F tool/symbols.sh bc2a3709940d47c8ac8e0a1fdf17ec801f015a00
 F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings.sh 347d974d143cf132f953b565fbc03026f19fcb4d
-P b5acda0445db39d58229d65a361d539db30f3833 b61a76a53af04f731fe7617f7b6b4fb2aef6587b
-R c25239c8ec2046d490b64494ae9d6208
-U drh
-Z bf5f3fb5150b87e28dd1ca0cfe21c8ad
+P 2d4458af59c697ad453996815d14442230654670
+R 7252e755eb943c8802f791d94d90614b
+U adam
+Z 048c280bdc3796d3c8e3318197ddc394
index f2650fe019fce15ee54c7bf389de20234a75e0f9..cccdb92cdbd58947a204addbcf9c8a22649dd253 100644 (file)
@@ -1 +1 @@
-2d4458af59c697ad453996815d14442230654670
\ No newline at end of file
+34f0efa2b12e8eb09331768b1524a076baeb34ea
\ No newline at end of file
index 3d7162dbb32c54f37c56fc457f1884403ed04e9a..3a58cbdc21f2ce828e32a97a56c3836eafca45f8 100644 (file)
@@ -68,8 +68,14 @@ static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
 ** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
 */
 int sqlite3_enable_shared_cache(int enable){
+#if defined(__APPLE__) && !defined(SQLITE_TEST) && !defined(TH3_COMPATIBILITY)
+  /* Enable global shared cache function for debugging and unit tests, 
+  ** but not for release */
+  return SQLITE_MISUSE;
+#else
   sqlite3GlobalConfig.sharedCacheEnabled = enable;
   return SQLITE_OK;
+#endif
 }
 #endif
 
@@ -2350,6 +2356,18 @@ static int lockBtree(BtShared *pBt){
       if( rc!=SQLITE_OK ){
         goto page1_init_failed;
       }else if( isOpen==0 ){
+#ifdef SQLITE_DEFAULT_WAL_SAFETYLEVEL
+        /* Default to specified safety_level for WAL mode */
+        if( pBt->db!=0 && pBt->db->aDb!=0 ){
+          sqlite3 *db = pBt->db;
+          if( db->aDb[0].safety_level != SQLITE_DEFAULT_WAL_SAFETYLEVEL) {
+            db->aDb[0].safety_level = SQLITE_DEFAULT_WAL_SAFETYLEVEL;
+            sqlite3PagerSetSafetyLevel(pBt->pPager, SQLITE_DEFAULT_WAL_SAFETYLEVEL, 
+                                       (db->flags&SQLITE_FullFSync)!=0,
+                                       (db->flags&SQLITE_CkptFullFSync)!=0);
+          }
+        }
+#endif
         releasePage(pPage1);
         return SQLITE_OK;
       }
index b55fca0a403099d61b76861fd7dd442a4f30195f..e03c9b6e86530a423fd6493a019ab42b86db0471 100644 (file)
@@ -1797,10 +1797,15 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
   return oldLimit;                     /* IMP: R-53341-35419 */
 }
 #if defined(SQLITE_ENABLE_AUTO_PROFILE)
-static void profile_sql(void *aux, const char *sql, u64 ns) {
+void _sqlite_auto_profile(void *aux, const char *sql, u64 ns);
+void _sqlite_auto_trace(void *aux, const char *sql);
+void _sqlite_auto_profile(void *aux, const char *sql, u64 ns) {
 #pragma unused(aux)
        fprintf(stderr, "Query: %s\n Execution Time: %llu ms\n", sql, ns / 1000000);
 }
+void _sqlite_auto_trace(void *aux, const char *sql) {
+       fprintf(stderr, "TraceSQL(%p): %s\n", aux, sql);
+}
 #endif
 
 /*
@@ -2135,6 +2140,9 @@ static int openDatabase(
   db->nextAutovac = -1;
   db->nextPagesize = 0;
   db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger
+#if SQLITE_DEFAULT_CKPTFULLFSYNC
+                 | SQLITE_CkptFullFSync
+#endif
 #if SQLITE_DEFAULT_FILE_FORMAT<4
                  | SQLITE_LegacyFileFmt
 #endif
@@ -2294,9 +2302,13 @@ opendb_out:
 #if defined(SQLITE_ENABLE_AUTO_PROFILE)
   if( db && !rc ){
     char *envprofile = getenv("SQLITE_AUTO_PROFILE");
+    char *envtrace = getenv("SQLITE_AUTO_TRACE");
     
     if( envprofile!=NULL ){
-      sqlite3_profile(db, profile_sql, NULL);
+      sqlite3_profile(db, _sqlite_auto_profile, db);
+    }
+    if( envtrace!=NULL ){
+      sqlite3_trace(db, _sqlite_auto_trace, db);
     }
   }
 #endif
@@ -2966,3 +2978,145 @@ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
   }
   return 0;
 }
+
+#if (SQLITE_ENABLE_APPLE_SPI>0)
+#define SQLITE_FILE_HEADER_LEN 16
+#include <fcntl.h>
+#include "sqlite3_private.h"
+#include "btreeInt.h"
+#include <errno.h>
+#include <sys/param.h>
+
+/* Check for a conflicting lock.  If one is found, print an this
+ ** on standard output using the format string given and return 1.
+ ** If there are no conflicting locks, return 0.
+ */
+static int isLocked(
+  pid_t pid,            /* PID to test for lock owner */
+  int h,                /* File descriptor to check */
+  int type,             /* F_RDLCK or F_WRLCK */
+  unsigned int iOfst,   /* First byte of the lock */
+  unsigned int iCnt,    /* Number of bytes in the lock range */
+  const char *zType     /* Type of lock */
+){
+  struct flock lk;
+  int err;
+  
+  memset(&lk, 0, sizeof(lk));
+  lk.l_type = type;
+  lk.l_whence = SEEK_SET;
+  lk.l_start = iOfst;
+  lk.l_len = iCnt;
+
+  if( pid!=SQLITE_LOCKSTATE_ANYPID ){
+#ifndef F_GETLKPID
+# warning F_GETLKPID undefined, _sqlite3_lockstate falling back to F_GETLK
+    err = fcntl(h, F_GETLK, &lk);
+#else
+    lk.l_pid = pid;
+    err = fcntl(h, F_GETLKPID, &lk);
+#endif
+  }else{
+    err = fcntl(h, F_GETLK, &lk);
+  }
+
+  if( err==(-1) ){
+    fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno);
+    return -1;
+  }
+  
+  if( lk.l_type!=F_UNLCK && (pid==SQLITE_LOCKSTATE_ANYPID || lk.l_pid==pid) ){
+#ifdef SQLITE_DEBUG
+    fprintf(stderr, "%s lock held by %d\n", zType, (int)lk.l_pid);
+#endif
+    return 1;
+  } 
+  return 0;
+}
+
+/*
+ ** Location of locking bytes in the database file
+ */
+#ifndef PENDING_BYTE
+# define PENDING_BYTE      (0x40000000)
+# define RESERVED_BYTE     (PENDING_BYTE+1)
+# define SHARED_FIRST      (PENDING_BYTE+2)
+# define SHARED_SIZE       510
+#endif /* PENDING_BYTE */
+
+/*
+ ** Lock locations for shared-memory locks used by WAL mode.
+ */
+#ifndef SHM_BASE
+# define SHM_BASE          120
+# define SHM_WRITE         SHM_BASE
+# define SHM_CHECKPOINT    (SHM_BASE+1)
+# define SHM_RECOVER       (SHM_BASE+2)
+# define SHM_READ_FIRST    (SHM_BASE+3)
+# define SHM_READ_SIZE     5
+#endif /* SHM_BASE */
+
+/* 
+** Testing a file path for sqlite locks held by a process ID. 
+** Returns SQLITE_LOCKSTATE_ON if locks are present on path
+** that would prevent writing to the database.
+**
+** This test only works for lock testing on unix/posix VFS.
+** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
+*/
+int _sqlite3_lockstate(const char *path, pid_t pid){
+  int hDb;        /* File descriptor for the open database file */
+  int hShm;       /* File descriptor for WAL shared-memory file */
+  ssize_t got;    /* Bytes read from header */
+  int isWal;                 /* True if in WAL mode */
+  int nLock = 0;             /* Number of locks held */
+  unsigned char aHdr[100];   /* Database header */
+  
+  /* Open the file at path and make sure we are dealing with a database file */
+  hDb = open(path, O_RDONLY | O_NOCTTY);
+  if( hDb<0 ){
+    return SQLITE_LOCKSTATE_ERROR;
+  }
+  assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN );
+  got = pread(hDb, aHdr, 100, 0);
+  if( got<0 ){
+    close(hDb);
+    return SQLITE_LOCKSTATE_ERROR;
+  }
+  if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){
+    close(hDb);
+    return SQLITE_LOCKSTATE_NOTADB;
+  }
+  
+  /* First check for an exclusive lock */
+  nLock += isLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE");
+  isWal = aHdr[18]==2;
+  if( nLock==0 && isWal==0 ){
+    /* Rollback mode */
+    nLock += isLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED");
+  }
+  close(hDb);
+  if( nLock==0 && isWal!=0 ){
+    char zShm[MAXPATHLEN];
+    
+    close(hDb);
+    /* WAL mode */
+    strlcpy(zShm, path, MAXPATHLEN);
+    strlcat(zShm, "-shm", MAXPATHLEN);
+    hShm = open(zShm, O_RDONLY, 0);
+    if( hShm<0 ){
+      return SQLITE_LOCKSTATE_OFF;
+    }
+    if( isLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
+       isLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
+      nLock = 1;
+    }
+    close(hShm);
+  }
+  if( nLock>0 ){
+    return SQLITE_LOCKSTATE_ON;
+  }
+  return SQLITE_LOCKSTATE_OFF;
+}
+
+#endif /* SQLITE_ENABLE_APPLE_SPI */
index ba0438adef021ee3e0f5de840e3373390a0da611..49e11b290a982c343d02f6bcaf328cae983bb280 100644 (file)
--- a/src/os.c
+++ b/src/os.c
@@ -131,12 +131,18 @@ int sqlite3OsOpen(
   int *pFlagsOut
 ){
   int rc;
+  int openFlags;
   DO_OS_MALLOC_TEST(0);
   /* 0x87f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
   ** down into the VFS layer.  Some SQLITE_OPEN_ flags (for example,
   ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
   ** reaching the VFS. */
-  rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f3f, pFlagsOut);
+#if SQLITE_ENABLE_DATA_PROTECTION
+  openFlags = flags & (0x87f3f | SQLITE_OPEN_FILEPROTECTION_MASK);
+#else
+  openFlags = flags & 0x87f3f;
+#endif
+  rc = pVfs->xOpen(pVfs, zPath, pFile, openFlags, pFlagsOut);
   assert( rc==SQLITE_OK || pFile->pMethods==0 );
   return rc;
 }
index d641a1f4a93a130a07bd3ed8a6e9d5788c58fe7a..85e17598bbec67190e60ae1de545d946ed30f174 100644 (file)
 
 #if SQLITE_ENABLE_LOCKING_STYLE
 # include <sys/ioctl.h>
+# include <uuid/uuid.h>
+# if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
+                            (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
+#  define HAVE_GETHOSTUUID 1
+# endif
 # if OS_VXWORKS
 #  include <semaphore.h>
 #  include <limits.h>
@@ -220,6 +225,9 @@ struct unixFile {
 #if SQLITE_ENABLE_LOCKING_STYLE
   int openFlags;                      /* The flags specified at open() */
 #endif
+#if SQLITE_ENABLE_DATA_PROTECTION
+  int protFlags;                      /* Data protection flags from unixOpen */
+#endif
 #if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
   unsigned fsFlags;                   /* cached details from statfs() */
 #endif
@@ -285,6 +293,285 @@ struct unixFile {
 #define threadid 0
 #endif
 
+#ifdef __APPLE__
+#define SQLITE_ENABLE_SUPERLOCK 1
+#endif
+
+#if SQLITE_ENABLE_SUPERLOCK
+#include "sqlite3.h"
+#include <string.h>               /* memset(), strlen() */
+#include <assert.h>               /* assert() */
+
+/*
+** A structure to collect a busy-handler callback and argument and a count
+** of the number of times it has been invoked.
+*/
+struct SuperlockBusy {
+  int (*xBusy)(void*,int);        /* Pointer to busy-handler function */
+  void *pBusyArg;                 /* First arg to pass to xBusy */
+  int nBusy;                      /* Number of times xBusy has been invoked */
+};
+typedef struct SuperlockBusy SuperlockBusy;
+
+/*
+** An instance of the following structure is allocated for each active
+** superlock. The opaque handle returned by sqlite3demo_superlock() is
+** actually a pointer to an instance of this structure.
+*/
+struct Superlock {
+  sqlite3 *db;                    /* Database handle used to lock db */
+  int bWal;                       /* True if db is a WAL database */
+};
+typedef struct Superlock Superlock;
+
+/*
+** The pCtx pointer passed to this function is actually a pointer to a
+** SuperlockBusy structure. Invoke the busy-handler function encapsulated
+** by the structure and return the result.
+*/
+static int superlockBusyHandler(void *pCtx, int UNUSED){
+  SuperlockBusy *pBusy = (SuperlockBusy *)pCtx;
+  if( pBusy->xBusy==0 ) return 0;
+  return pBusy->xBusy(pBusy->pBusyArg, pBusy->nBusy++);
+}
+
+/*
+** This function is used to determine if the main database file for 
+** connection db is open in WAL mode or not. If no error occurs and the
+** database file is in WAL mode, set *pbWal to true and return SQLITE_OK.
+** If it is not in WAL mode, set *pbWal to false.
+**
+** If an error occurs, return an SQLite error code. The value of *pbWal
+** is undefined in this case.
+*/
+static int superlockIsWal(Superlock *pLock){
+  int rc;                         /* Return Code */
+  sqlite3_stmt *pStmt;            /* Compiled PRAGMA journal_mode statement */
+
+  rc = sqlite3_prepare(pLock->db, "PRAGMA main.journal_mode", -1, &pStmt, 0);
+  if( rc!=SQLITE_OK ) return rc;
+
+  pLock->bWal = 0;
+  if( SQLITE_ROW==sqlite3_step(pStmt) ){
+    const char *zMode = (const char *)sqlite3_column_text(pStmt, 0);
+    if( zMode && strlen(zMode)==3 && sqlite3_strnicmp("wal", zMode, 3)==0 ){
+      pLock->bWal = 1;
+    }
+  }
+
+  return sqlite3_finalize(pStmt);
+}
+
+/*
+** Obtain an exclusive shm-lock on nByte bytes starting at offset idx
+** of the file fd. If the lock cannot be obtained immediately, invoke
+** the busy-handler until either it is obtained or the busy-handler
+** callback returns 0.
+*/
+static int superlockShmLock(
+  sqlite3_file *fd,               /* Database file handle */
+  int idx,                        /* Offset of shm-lock to obtain */
+  int nByte,                      /* Number of consective bytes to lock */
+  SuperlockBusy *pBusy            /* Busy-handler wrapper object */
+){
+  int rc;
+  int (*xShmLock)(sqlite3_file*, int, int, int) = fd->pMethods->xShmLock;
+  do {
+    rc = xShmLock(fd, idx, nByte, SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE);
+  }while( rc==SQLITE_BUSY && superlockBusyHandler((void *)pBusy, 0) );
+  return rc;
+}
+
+/*
+** Obtain the extra locks on the database file required for WAL databases.
+** Invoke the supplied busy-handler as required.
+*/
+static int superlockWalLock(
+  sqlite3 *db,                    /* Database handle open on WAL database */
+  SuperlockBusy *pBusy            /* Busy handler wrapper object */
+){
+  int rc;                         /* Return code */
+  sqlite3_file *fd = 0;           /* Main database file handle */
+  void volatile *p = 0;           /* Pointer to first page of shared memory */
+
+  /* Obtain a pointer to the sqlite3_file object open on the main db file. */
+  rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
+  if( rc!=SQLITE_OK ) return rc;
+
+  /* Obtain the "recovery" lock. Normally, this lock is only obtained by
+  ** clients running database recovery.  
+  */
+  rc = superlockShmLock(fd, 2, 1, pBusy);
+  if( rc!=SQLITE_OK ) return rc;
+
+  /* Zero the start of the first shared-memory page. This means that any
+  ** clients that open read or write transactions from this point on will
+  ** have to run recovery before proceeding. Since they need the "recovery"
+  ** lock that this process is holding to do that, no new read or write
+  ** transactions may now be opened. Nor can a checkpoint be run, for the
+  ** same reason.
+  */
+  rc = fd->pMethods->xShmMap(fd, 0, 32*1024, 1, &p);
+  if( rc!=SQLITE_OK ) return rc;
+  memset((void *)p, 0, 32);
+
+  /* Obtain exclusive locks on all the "read-lock" slots. Once these locks
+  ** are held, it is guaranteed that there are no active reader, writer or 
+  ** checkpointer clients.
+  */
+  rc = superlockShmLock(fd, 3, SQLITE_SHM_NLOCK-3, pBusy);
+  return rc;
+}
+
+/*
+** Release a superlock held on a database file. The argument passed to 
+** this function must have been obtained from a successful call to
+** sqlite3demo_superlock().
+*/
+static void sqlite3demo_superunlock(void *pLock){
+  Superlock *p = (Superlock *)pLock;
+  if( p->bWal ){
+    int rc;                         /* Return code */
+    int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
+    sqlite3_file *fd = 0;
+    rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
+    if( rc==SQLITE_OK ){
+      fd->pMethods->xShmLock(fd, 2, 1, flags);
+      fd->pMethods->xShmLock(fd, 3, SQLITE_SHM_NLOCK-3, flags);
+    }
+  }
+  sqlite3_close(p->db);
+  sqlite3_free(p);
+}
+
+/*
+** Obtain a superlock on the database file identified by zPath, using the
+** locking primitives provided by VFS zVfs. If successful, SQLITE_OK is
+** returned and output variable *ppLock is populated with an opaque handle
+** that may be used with sqlite3demo_superunlock() to release the lock.
+**
+** If an error occurs, *ppLock is set to 0 and an SQLite error code 
+** (e.g. SQLITE_BUSY) is returned.
+**
+** If a required lock cannot be obtained immediately and the xBusy parameter
+** to this function is not NULL, then xBusy is invoked in the same way
+** as a busy-handler registered with SQLite (using sqlite3_busy_handler())
+** until either the lock can be obtained or the busy-handler function returns
+** 0 (indicating "give up").
+*/
+static int sqlite3demo_superlock(
+  const char *zPath,              /* Path to database file to lock */
+  const char *zVfs,               /* VFS to use to access database file */
+  int flags,                      /* Additional flags to pass to sqlite3_open_v2 */
+  int (*xBusy)(void*,int),        /* Busy handler callback */
+  void *pBusyArg,                 /* Context arg for busy handler */
+  void **ppLock                   /* OUT: Context to pass to superunlock() */
+){
+  SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
+  int rc;                         /* Return code */
+  Superlock *pLock;
+
+  pLock = sqlite3_malloc(sizeof(Superlock));
+  if( !pLock ) return SQLITE_NOMEM;
+  memset(pLock, 0, sizeof(Superlock));
+
+  /* Open a database handle on the file to superlock. */
+  rc = sqlite3_open_v2(
+      zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|flags, zVfs
+  );
+
+  /* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not
+  ** a WAL database, this is all we need to do.  
+  **
+  ** A wrapper function is used to invoke the busy-handler instead of
+  ** registering the busy-handler function supplied by the user directly
+  ** with SQLite. This is because the same busy-handler function may be
+  ** invoked directly later on when attempting to obtain the extra locks
+  ** required in WAL mode. By using the wrapper, we are able to guarantee
+  ** that the "nBusy" integer parameter passed to the users busy-handler
+  ** represents the total number of busy-handler invocations made within
+  ** this call to sqlite3demo_superlock(), including any made during the
+  ** "BEGIN EXCLUSIVE".
+  */
+  if( rc==SQLITE_OK ){
+    busy.xBusy = xBusy;
+    busy.pBusyArg = pBusyArg;
+    sqlite3_busy_handler(pLock->db, superlockBusyHandler, (void *)&busy);
+    rc = sqlite3_exec(pLock->db, "BEGIN EXCLUSIVE", 0, 0, 0);
+  }
+
+  /* If the BEGIN EXCLUSIVE was executed successfully and this is a WAL
+  ** database, call superlockWalLock() to obtain the extra locks required
+  ** to prevent readers, writers and/or checkpointers from accessing the
+  ** db while this process is holding the superlock.
+  **
+  ** Before attempting any WAL locks, commit the transaction started above
+  ** to drop the WAL read and write locks currently held. Otherwise, the
+  ** new WAL locks may conflict with the old.
+  */
+  if( rc==SQLITE_OK ){
+    if( SQLITE_OK==(rc = superlockIsWal(pLock)) && pLock->bWal ){
+      rc = sqlite3_exec(pLock->db, "COMMIT", 0, 0, 0);
+      if( rc==SQLITE_OK ){
+        rc = superlockWalLock(pLock->db, &busy);
+      }
+    }
+  }
+
+  if( rc!=SQLITE_OK ){
+    sqlite3demo_superunlock(pLock);
+    *ppLock = 0;
+  }else{
+    *ppLock = pLock;
+  }
+
+  return rc;
+}
+
+/* A corrupt DB won't work with the sql-based locking attempt, grab an 
+** exclusive lock and return SQLITE_OK or SQLITE_BUSY if the lock fails 
+** returns the current lock level held on sqlite3_file
+*/
+static int sqlite3demo_superlock_corrupt(sqlite3_file *id, int eTargetFileLock, int *pFileLock) {
+  unixFile *pFile = (unixFile*)id;
+  int eFileLock = pFile->eFileLock;
+  int rc = SQLITE_OK;
+  
+  if( eFileLock<eTargetFileLock ){
+    rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);
+  }
+  if( !rc && eFileLock<eTargetFileLock ){
+    rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);
+  }
+  if( rc ){
+    if( pFile->eFileLock > eFileLock ){
+      pFile->pMethod->xUnlock(id, eFileLock);
+    }
+    return rc;
+  }
+  if (pFileLock) {
+    *pFileLock = eFileLock;
+  }
+  return SQLITE_OK;
+}
+
+static int sqlite3demo_superunlock_corrupt(sqlite3_file *id, int eFileLock) {
+  unixFile *pFile = (unixFile*)id;
+  int rc = SQLITE_OK;
+  
+  if( pFile->eFileLock > eFileLock ){
+    rc = pFile->pMethod->xUnlock(id, SQLITE_LOCK_SHARED);
+  }
+  if( pFile->eFileLock > eFileLock ){
+    int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_NONE);
+    if (!rc) rc = unlockRC;
+  }
+  return rc;
+}
+
+#endif /* SQLITE_ENABLE_SUPERLOCK */
+
+
 /*
 ** Different Unix systems declare open() in different ways.  Same use
 ** open(const char*,int,mode_t).  Others use open(const char*,int,...).
@@ -1062,8 +1349,19 @@ static void closePendingFds(unixFile *pFile){
   UnixUnusedFd *pNext;
   for(p=pInode->pUnused; p; p=pNext){
     pNext = p->pNext;
+#if OSCLOSE_CHECK_CLOSE_IOERR
+    if( close(p->fd) ){
+      pFile->lastErrno = errno;
+      rc = SQLITE_IOERR_CLOSE;
+      p->pNext = pError;
+      pError = p;
+    }else{
+      sqlite3_free(p);
+    }
+#else
     robust_close(pFile, p->fd, __LINE__);
     sqlite3_free(p);
+#endif
   }
   pInode->pUnused = 0;
 }
@@ -1220,8 +1518,14 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
     lock.l_len = 1;
     lock.l_type = F_WRLCK;
     if( osFcntl(pFile->h, F_GETLK, &lock) ){
+#if OSLOCKING_CHECK_BUSY_IOERR
+      int tErrno = errno;
+      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
+      pFile->lastErrno = tErrno;
+#else
       rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
       pFile->lastErrno = errno;
+#endif
     } else if( lock.l_type!=F_UNLCK ){
       reserved = 1;
     }
@@ -1420,7 +1724,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
     if( unixFileLock(pFile, &lock) ){
       tErrno = errno;
       rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
-      if( rc!=SQLITE_BUSY ){
+      if( IS_LOCK_ERROR(rc) ){
         pFile->lastErrno = tErrno;
       }
       goto end_lock;
@@ -1451,11 +1755,15 @@ static int unixLock(sqlite3_file *id, int eFileLock){
     if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
       /* This could happen with a network mount */
       tErrno = errno;
+#if OSLOCKING_CHECK_BUSY_IOERR
+      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); 
+#else
       rc = SQLITE_IOERR_UNLOCK; 
+#endif
     }
 
     if( rc ){
-      if( rc!=SQLITE_BUSY ){
+      if( IS_LOCK_ERROR(rc) ){
         pFile->lastErrno = tErrno;
       }
       goto end_lock;
@@ -1622,7 +1930,11 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
         lock.l_len = divSize;
         if( unixFileLock(pFile, &lock)==(-1) ){
           tErrno = errno;
+#if OSLOCKING_CHECK_BUSY_IOERR
+          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+#else
           rc = SQLITE_IOERR_UNLOCK;
+#endif
           if( IS_LOCK_ERROR(rc) ){
             pFile->lastErrno = tErrno;
           }
@@ -1646,7 +1958,11 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
         lock.l_len = SHARED_SIZE-divSize;
         if( unixFileLock(pFile, &lock)==(-1) ){
           tErrno = errno;
+#if OSLOCKING_CHECK_BUSY_IOERR
+          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+#else
           rc = SQLITE_IOERR_UNLOCK;
+#endif
           if( IS_LOCK_ERROR(rc) ){
             pFile->lastErrno = tErrno;
           }
@@ -1660,6 +1976,13 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
         lock.l_start = SHARED_FIRST;
         lock.l_len = SHARED_SIZE;
         if( unixFileLock(pFile, &lock) ){
+#if OSLOCKING_CHECK_BUSY_IOERR
+          tErrno = errno;
+          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
+          if( IS_LOCK_ERROR(rc) ){
+            pFile->lastErrno = tErrno;
+          }
+#else
           /* In theory, the call to unixFileLock() cannot fail because another
           ** process is holding an incompatible lock. If it does, this 
           ** indicates that the other process is not following the locking
@@ -1668,6 +1991,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
           ** an assert to fail). */ 
           rc = SQLITE_IOERR_RDLOCK;
           pFile->lastErrno = errno;
+#endif
           goto end_unlock;
         }
       }
@@ -1679,8 +2003,16 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
     if( unixFileLock(pFile, &lock)==0 ){
       pInode->eFileLock = SHARED_LOCK;
     }else{
+#if OSLOCKING_CHECK_BUSY_IOERR
+      tErrno = errno;
+      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+      if( IS_LOCK_ERROR(rc) ){
+        pFile->lastErrno = tErrno;
+      }
+#else
       rc = SQLITE_IOERR_UNLOCK;
       pFile->lastErrno = errno;
+#endif
       goto end_unlock;
     }
   }
@@ -1700,8 +2032,16 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
       if( unixFileLock(pFile, &lock)==0 ){
         pInode->eFileLock = NO_LOCK;
       }else{
+#if OSLOCKING_CHECK_BUSY_IOERR
+        tErrno = errno;
+        rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+        if( IS_LOCK_ERROR(rc) ){
+          pFile->lastErrno = tErrno;
+        }
+#else
         rc = SQLITE_IOERR_UNLOCK;
-       pFile->lastErrno = errno;
+           pFile->lastErrno = errno;
+#endif
         pInode->eFileLock = NO_LOCK;
         pFile->eFileLock = NO_LOCK;
       }
@@ -1747,6 +2087,26 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){
 */
 static int closeUnixFile(sqlite3_file *id){
   unixFile *pFile = (unixFile*)id;
+#if OSCLOSE_CHECK_CLOSE_IOERR
+  if( pFile->dirfd>=0 ){
+    int err = close(pFile->dirfd);
+    if( err ){
+      pFile->lastErrno = errno;
+      return SQLITE_IOERR_DIR_CLOSE;
+    }else{
+      pFile->dirfd=-1;
+    }
+  }
+  if( pFile->h>=0 ){
+    int err = close(pFile->h);
+    if( err ){
+      pFile->lastErrno = errno;
+      return SQLITE_IOERR_CLOSE;
+    }else{
+      pFile->h=-1;
+    }
+  }
+#else
   if( pFile->dirfd>=0 ){
     robust_close(pFile, pFile->dirfd, __LINE__);
     pFile->dirfd=-1;
@@ -1755,6 +2115,7 @@ static int closeUnixFile(sqlite3_file *id){
     robust_close(pFile, pFile->h, __LINE__);
     pFile->h = -1;
   }
+#endif
 #if OS_VXWORKS
   if( pFile->pId ){
     if( pFile->isDelete ){
@@ -1967,7 +2328,14 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
     }
     return rc;
   } 
+#if OSCLOSE_CHECK_CLOSE_IOERR
+  if( close(fd) ){
+    pFile->lastErrno = errno;
+    rc = SQLITE_IOERR_CLOSE;
+  }
+#else
   robust_close(pFile, fd, __LINE__);
+#endif
   
   /* got it, set the type and return ok */
   pFile->eFileLock = eFileLock;
@@ -2011,7 +2379,11 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
     int rc = 0;
     int tErrno = errno;
     if( ENOENT != tErrno ){
+#if OSLOCKING_CHECK_BUSY_IOERR
+      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+#else
       rc = SQLITE_IOERR_UNLOCK;
+#endif
     }
     if( IS_LOCK_ERROR(rc) ){
       pFile->lastErrno = tErrno;
@@ -2099,7 +2471,11 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
       if ( lrc ) {
         int tErrno = errno;
         /* unlock failed with an error */
+#if OSLOCKING_CHECK_BUSY_IOERR
+        lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+#else 
         lrc = SQLITE_IOERR_UNLOCK; 
+#endif
         if( IS_LOCK_ERROR(lrc) ){
           pFile->lastErrno = tErrno;
           rc = lrc;
@@ -3317,9 +3693,18 @@ static int unixSync(sqlite3_file *id, int flags){
        /* return SQLITE_IOERR; */
     }
 #endif
-    /* Only need to sync once, so close the  directory when we are done */
+  /* Only need to sync once, so close the  directory when we are done */
+#if OSCLOSE_CHECK_CLOSE_IOERR
+    if( close(pFile->dirfd)==0 ){
+      pFile->dirfd = -1;
+    }else{
+      pFile->lastErrno = errno;
+      rc = SQLITE_IOERR_DIR_CLOSE;
+    }
+#else
     robust_close(pFile, pFile->dirfd, __LINE__);
     pFile->dirfd = -1;
+#endif
   }
   return rc;
 }
@@ -3458,6 +3843,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
 #include <copyfile.h>
 static int getDbPathForUnixFile(unixFile *pFile, char *dbPath);
 #endif
+static int isProxyLockingMode(unixFile *);
 
 /*
 ** Information and control of an open file handle.
@@ -3499,212 +3885,258 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
 #if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
     case SQLITE_TRUNCATE_DATABASE: {
       unixFile *pFile = (unixFile*)id;
-      int trc = SQLITE_OK;
-      int eFileLock = pFile->eFileLock;
       int rc = SQLITE_OK;
-      char jPath[MAXPATHLEN+9];
-      size_t jLen;
-      
-      if( eFileLock<SQLITE_LOCK_SHARED ){
-        rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);
-      }
-      if( !rc && eFileLock<SQLITE_LOCK_EXCLUSIVE ){
-        rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);
+      void *pLock = NULL;
+      int flags = 0;
+      int corruptFileLock = 0;
+      int isCorrupt = 0;
+
+#if SQLITE_ENABLE_DATA_PROTECTION
+      flags |= pFile->protFlags;
+#endif
+#if SQLITE_ENABLE_LOCKING_STYLE
+      if( isProxyLockingMode(pFile) ){
+        flags |= SQLITE_OPEN_AUTOPROXY;
       }
+#endif
+      
+      rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
       if( rc ){
-        if( pFile->eFileLock > eFileLock ){
-          pFile->pMethod->xUnlock(id, eFileLock);
+        if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
+          isCorrupt = 1;
+          rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock);
+        }
+        if( rc ){
+          return rc;
         }
-        return rc;
       }
       rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
-      if( !rc && (SQLITE_OK==getDbPathForUnixFile(pFile, jPath)) ){
-        jLen = strlcat(jPath, "-journal", MAXPATHLEN+9);
-        if( jLen < MAXPATHLEN+9 ){
-          int jfd = open(jPath, O_TRUNC);
-          if( (jfd == -1) ){
-            if ( errno!=ENOENT ){
-              perror(jPath);
+
+      if( rc==SQLITE_OK ){
+        char jPath[MAXPATHLEN+9];
+        int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
+        if( zLen<MAXPATHLEN ){
+          size_t jLen;
+          const char extensions[2][9] = { "-wal", "-journal" /*, "-shm" */ };
+          int j = 0;
+          for( j=0; j<2; j++ ){
+            jLen = strlcpy(&jPath[zLen], extensions[j], 9);
+            if( jLen < 9 ){
+              int jfd = open(jPath, O_TRUNC);
+              if( jfd==(-1) ){
+                if ( errno!=ENOENT ){
+                  perror(jPath);
+                }
+              } else {
+                fsync(jfd);
+                close(jfd);
+              }
             }
-          } else {
-            fsync(jfd);
-            close(jfd);
           }
         }
-      }else{
-        trc=rc;
-      }
-      if( !trc ){
-        trc = pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
-      }
-      if( pFile->eFileLock > eFileLock ){
-        int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_SHARED);
-        if (!rc) rc = unlockRC;
+        pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
       }
-      if( pFile->eFileLock > eFileLock ){
-        int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_NONE);
-        if (!rc) rc = unlockRC;
-      }
-      if( trc ){
-        return trc;
+      if( isCorrupt ){
+        sqlite3demo_superunlock_corrupt(id, corruptFileLock);
+      }else{
+        sqlite3demo_superunlock(pLock);
       }
       return rc;
     }
       
     case SQLITE_REPLACE_DATABASE: {
       unixFile *pFile = (unixFile*)id;
-      int trc = SQLITE_OK;
-      int eFileLock = pFile->eFileLock;
-      int rc = SQLITE_OK;
-      char jPath[MAXPATHLEN+9];
-      size_t jLen;
       sqlite3 *srcdb = (sqlite3 *)pArg;
       Btree *pSrcBtree = NULL;
-      int eSrcFileLock = SQLITE_LOCK_NONE;
-      int srcLockRC = -1;
       sqlite3_file *src_file = NULL;
       unixFile *pSrcFile = NULL;
-      
+      char srcWalPath[MAXPATHLEN+5];
+      int srcWalFD = -1;
+      int rc = SQLITE_OK;
+      void *pLock = NULL;
+      int flags = 0;
+      sqlite3 *srcdb2 = NULL;
+      copyfile_state_t s;
+      int corruptSrcFileLock = 0;
+      int corruptDstFileLock = 0;
+      int isSrcCorrupt = 0;
+      int isDstCorrupt = 0;
+
       if( !sqlite3SafetyCheckOk(srcdb) ){
         return SQLITE_MISUSE;
       }
-      if( eFileLock<SQLITE_LOCK_SHARED ){
-        rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);
-      }
-      if( !rc && eFileLock<SQLITE_LOCK_EXCLUSIVE ){
-        rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);
+      
+#if SQLITE_ENABLE_DATA_PROTECTION
+      flags |= pFile->protFlags;
+#endif
+#if SQLITE_ENABLE_LOCKING_STYLE
+      if( isProxyLockingMode(pFile) ){
+        flags |= SQLITE_OPEN_AUTOPROXY;
       }
-      if( !rc ){
-        /* get the src file descriptor adhering to the db struct access rules 
-         ** this code is modeled after sqlite3_file_control() in main.c
-         */ 
-        sqlite3_mutex_enter(srcdb->mutex);
-        if( srcdb->nDb>0 ){
-          pSrcBtree = srcdb->aDb[0].pBt;
+#endif
+      
+      rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
+      if( rc ){
+        if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
+          isDstCorrupt = 1;
+          rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptDstFileLock);
         }
-        if( pSrcBtree ){
-          Pager *pSrcPager;
-          sqlite3BtreeEnter(pSrcBtree);
-          pSrcPager = sqlite3BtreePager(pSrcBtree);
-          assert( pSrcPager!=0 );
-          src_file = sqlite3PagerFile(pSrcPager);
-          assert( src_file!=0 );
-          if( src_file->pMethods ){
-            pSrcFile = (unixFile *)src_file;
-            eSrcFileLock = pSrcFile->eFileLock;
-            if( eSrcFileLock<SQLITE_LOCK_SHARED ){
-              rc = pSrcFile->pMethod->xLock(src_file, SQLITE_LOCK_SHARED);
-              srcLockRC = rc; /* SQLITE_OK means we need to unlock later */
-            } else if( eSrcFileLock==SQLITE_LOCK_EXCLUSIVE ){
-              /* if the src database has an exclusive lock, verify that the
-               ** it doesn't have a journal file with open transactions 
-               */
-              if( getDbPathForUnixFile(pSrcFile, jPath) ){
-                rc = SQLITE_INTERNAL;
-              }else{
-                jLen = strlcat(jPath, "-journal", MAXPATHLEN+9);
-                if( jLen < MAXPATHLEN+9 ){
-                  int jfd = open(jPath, O_RDONLY);
-                  if( jfd==-1 ){
-                    if( errno!=ENOENT ){
-                      pFile->lastErrno = errno;
-                      rc = SQLITE_IOERR;
-                    }
-                  }else{
-                    /* if the journal exists ensure there's no pending 
-                     ** transaction by checking the journal header */
-                    char magic[8];
-                    ssize_t rlen = pread(jfd, magic, 8, 0);
-                    if( rlen<0 ){
-                      pFile->lastErrno = errno;
-                      rc = SQLITE_IOERR;
-                    }else if( rlen==8 ){
-                      char test[8] = {'\0','\0','\0','\0','\0','\0','\0','\0'};
-                      if( memcmp(magic,test,8) ){
-                        rc = SQLITE_LOCKED;
-                      }
-                    }else if( rlen!=0 ){
-                      rc = SQLITE_INTERNAL;
-                    }
-                    close(jfd);
-                  }
-                }
-              }
-            }
-          }else{
-            rc = SQLITE_MISUSE;
+        if( rc ){
+          return rc;
+        }
+      }
+      /* get the src file descriptor adhering to the db struct access rules 
+       ** this code is modeled after sqlite3_file_control() in main.c
+       */ 
+      sqlite3_mutex_enter(srcdb->mutex);
+      if( srcdb->nDb>0 ){
+        pSrcBtree = srcdb->aDb[0].pBt;
+      }
+      if( pSrcBtree ){
+        Pager *pSrcPager;
+        sqlite3BtreeEnter(pSrcBtree);
+        pSrcPager = sqlite3BtreePager(pSrcBtree);
+        assert( pSrcPager!=0 );
+        src_file = sqlite3PagerFile(pSrcPager);
+        assert( src_file!=0 );
+        if( src_file->pMethods ){
+          int srcFlags = 0;
+          pSrcFile = (unixFile *)src_file;
+          /* wal mode db cannot be opened readonly */
+          if ((pSrcFile->openFlags & O_RDWR) == O_RDWR) {
+            srcFlags = SQLITE_OPEN_READWRITE;
+          } else {
+            srcFlags = SQLITE_OPEN_READONLY;
+          }
+#if SQLITE_ENABLE_DATA_PROTECTION
+          srcFlags |= pSrcFile->protFlags;
+#endif
+#if SQLITE_ENABLE_LOCKING_STYLE
+          if( isProxyLockingMode(pSrcFile) ){
+            srcFlags |= SQLITE_OPEN_AUTOPROXY;
           }
-          if( rc ){
-            if( srcLockRC==SQLITE_OK ){
-              pSrcFile->pMethod->xUnlock(src_file, eSrcFileLock);
+#endif
+          rc = sqlite3_open_v2(pSrcFile->zPath, &srcdb2, srcFlags, 0);
+          if( rc==SQLITE_OK ){
+            /* start a deferred transaction and read to establish a read lock */
+            rc = sqlite3_exec(srcdb2, "BEGIN DEFERRED; PRAGMA schema_version", 0, 0, 0);
+            if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
+              isSrcCorrupt = 1;
+              rc = sqlite3demo_superlock_corrupt(src_file, SQLITE_LOCK_SHARED, &corruptSrcFileLock);
             }
-            sqlite3BtreeLeave(pSrcBtree);
           }
         }
-        if( pSrcFile==NULL || (pSrcFile->h<0) ){
-          rc = SQLITE_INTERNAL;
-          sqlite3_mutex_leave(srcdb->mutex);
-        }
       }
-      if( rc ){
-        /* unroll state changes and return error code */
-        if( pFile->eFileLock > eFileLock ){
-          pFile->pMethod->xUnlock(id, eFileLock);
+      if( !srcdb2 || pSrcFile==NULL || pSrcFile->h<0){
+        rc = SQLITE_INTERNAL;
+      }
+      if( rc!=SQLITE_OK ){
+        goto end_replace_database;
+      }
+      /* both databases are locked appropriately, copy the src wal journal if 
+      ** one exists and then the actual database file
+      */
+      strlcpy(srcWalPath, pSrcFile->zPath, MAXPATHLEN+5);
+      strlcat(srcWalPath, "-wal", MAXPATHLEN+5);
+      srcWalFD = open(srcWalPath, O_RDONLY);
+      if( !(srcWalFD<0) ){
+        char dstWalPath[MAXPATHLEN+5];
+        int dstWalFD = -1;
+        strlcpy(dstWalPath, pFile->zPath, MAXPATHLEN+5);
+        strlcat(dstWalPath, "-wal", MAXPATHLEN+5);
+        dstWalFD = open(dstWalPath, O_RDWR|O_CREAT, SQLITE_DEFAULT_FILE_PERMISSIONS);
+        if( !(dstWalFD<0) ){
+          s = copyfile_state_alloc();
+          lseek(srcWalFD, 0, SEEK_SET);
+          lseek(dstWalFD, 0, SEEK_SET);
+          if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_ALL) ){
+            int err=errno;
+            switch(err) {
+              case ENOMEM:
+                rc = SQLITE_NOMEM;
+                break;
+              default:
+                pFile->lastErrno = err;
+                rc = SQLITE_IOERR;
+            }
+          }
+          copyfile_state_free(s);
+          close(dstWalFD);
         }
-        return rc;
-      }else{
-        /* both databases are locked appropriately, copy file data
-         ** and then unroll the locks we added. 
-         */
-        copyfile_state_t s;
+        close(srcWalFD);
+      }
+      if( rc==SQLITE_OK ){
+        /* before we copy, ensure that the file change counter will be modified */
+        uint32_t srcChange = 0;
+        uint32_t dstChange = 0;
+        pread(pSrcFile->h, &srcChange, 4, 24);
+        pread(pFile->h, &dstChange, 4, 24);
         
+        /* copy the actual database */
         s = copyfile_state_alloc();
+        lseek(pSrcFile->h, 0, SEEK_SET);
+        lseek(pFile->h, 0, SEEK_SET);
         if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){
-          switch(errno) {
+          int err=errno;
+          switch(err) {
             case ENOMEM:
               rc = SQLITE_NOMEM;
               break;
             default:
-              rc = SQLITE_INTERNAL;
+              pFile->lastErrno = err;
+              rc = SQLITE_IOERR;
           }
         }
         copyfile_state_free(s);
-        if( srcLockRC==SQLITE_OK ){
-          pSrcFile->pMethod->xUnlock(src_file, eSrcFileLock);
+        
+        if (srcChange == dstChange) {
+          /* modify the change counter to force page zero to be reloaded */
+          dstChange ++;
+          pwrite(pFile->h, &dstChange, 4, 24);
         }
-        sqlite3BtreeLeave(pSrcBtree);
-        sqlite3_mutex_leave(srcdb->mutex);
       }
-      
-      if( !rc && (SQLITE_OK==getDbPathForUnixFile(pFile, jPath)) ){
-        jLen = strlcat(jPath, "-journal", MAXPATHLEN+9);
-        if( jLen < MAXPATHLEN+9 ){
-          int jfd = open(jPath, O_TRUNC);
-          if( (jfd == -1) ){
-            if ( errno!=ENOENT ){
-              perror(jPath);
+      if( isSrcCorrupt ){
+        sqlite3demo_superunlock_corrupt(src_file, corruptSrcFileLock);
+      }else{
+        /* done with the source db so end the transaction */
+        sqlite3_exec(srcdb2, "COMMIT", 0, 0, 0);
+      }
+      /* zero out any old journal clutter */
+      if( rc==SQLITE_OK ){
+        char jPath[MAXPATHLEN+9];
+        int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
+        if( zLen<MAXPATHLEN ){
+          size_t jLen;
+          const char extensions[2][9] = { "-wal", "-journal" /* "-shm" */ };
+          int j = (srcWalFD<0)?0:1; /* skip the wal if we replaced it */
+          for( ; j<2; j++ ){
+            jLen = strlcpy(&jPath[zLen], extensions[j], 9);
+            if( jLen < 9 ){
+              int jfd = open(jPath, O_TRUNC);
+              if( jfd==(-1) ){
+                if ( errno!=ENOENT ){
+                  perror(jPath);
+                }
+              } else {
+                fsync(jfd);
+                close(jfd);
+              }
             }
-          } else {
-            fsync(jfd);
-            close(jfd);
           }
         }
-      }else{
-        trc=rc;
-      }
-      if( !trc ){
-        trc = pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
+        pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
       }
-      if( pFile->eFileLock > eFileLock ){
-        int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_SHARED);
-        if (!rc) rc = unlockRC;
-      }
-      if( pFile->eFileLock > eFileLock ){
-        int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_NONE);
-        if (!rc) rc = unlockRC;
+      
+    end_replace_database:
+      if( pSrcBtree ){
+        sqlite3_close(srcdb2);
+        sqlite3BtreeLeave(pSrcBtree);
       }
-      if( trc ){
-        return trc;
+      sqlite3_mutex_leave(srcdb->mutex);
+      if( isDstCorrupt ){
+        sqlite3demo_superunlock_corrupt(id, corruptDstFileLock);
+      }else{
+        sqlite3demo_superunlock(pLock);
       }
       return rc;
     }
@@ -3924,7 +4356,6 @@ static void unixShmPurge(unixFile *pFd){
   }
 }
 
-static int isProxyLockingMode(unixFile *);
 static const char *proxySharedMemoryBasePath(unixFile *);
 
 /*
@@ -4062,6 +4493,14 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
       if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
         if( robust_ftruncate(pShmNode->h, 0) ){
           rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
+        }else{
+          /* If running as root set the uid/gid of the shm file to match the database */
+          uid_t euid = geteuid();
+          if( euid==0 && (euid!=sStat.st_uid || getegid()!=sStat.st_gid) ){
+            if( fchown(pShmNode->h, sStat.st_uid, sStat.st_gid) ){
+              rc = SQLITE_IOERR_SHMOPEN;
+            }
+          }
         }
       }
       if( rc==SQLITE_OK ){
@@ -5081,7 +5520,9 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
 static int findCreateFileMode(
   const char *zPath,              /* Path of file (possibly) being created */
   int flags,                      /* Flags passed as 4th argument to xOpen() */
-  mode_t *pMode                   /* OUT: Permissions to open file with */
+  mode_t *pMode,                  /* OUT: Permissions to open file with */
+  uid_t *pUid,                    /* OUT: uid to set on the file */
+  gid_t *pGid                     /* OUT: gid to set on the file */
 ){
   int rc = SQLITE_OK;             /* Return Code */
   *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
@@ -5110,6 +5551,8 @@ static int findCreateFileMode(
 
     if( 0==stat(zDb, &sStat) ){
       *pMode = sStat.st_mode & 0777;
+      *pUid = sStat.st_uid;
+      *pGid = sStat.st_gid;
     }else{
       rc = SQLITE_IOERR_FSTAT;
     }
@@ -5152,7 +5595,11 @@ static int unixOpen(
   int fd = -1;                   /* File descriptor returned by open() */
   int dirfd = -1;                /* Directory file descriptor */
   int openFlags = 0;             /* Flags to pass to open() */
+#if SQLITE_ENABLE_DATA_PROTECTION
+  int eType = flags&0xFF0FFF00;  /* Type of file to open */
+#else
   int eType = flags&0xFFFFFF00;  /* Type of file to open */
+#endif
   int noLock;                    /* True to omit locking primitives */
   int rc = SQLITE_OK;            /* Function Return Code */
 
@@ -5241,9 +5688,15 @@ static int unixOpen(
   if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
   openFlags |= (O_LARGEFILE|O_BINARY);
 
+#if SQLITE_ENABLE_DATA_PROTECTION
+  p->protFlags = (flags & SQLITE_OPEN_FILEPROTECTION_MASK);
+#endif
+    
   if( fd<0 ){
     mode_t openMode;              /* Permissions to create file with */
-    rc = findCreateFileMode(zName, flags, &openMode);
+    uid_t uid;
+    gid_t gid;
+    rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
     if( rc!=SQLITE_OK ){
       assert( !p->pUnused );
       assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
@@ -5264,6 +5717,16 @@ static int unixOpen(
       rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
       goto open_finished;
     }
+    /* if we're opening the wal or journal and running as root, set the journal uid/gid */
+    if( !isReadonly && (flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL)) ){
+      uid_t euid = geteuid();
+      if( euid==0 && (euid!=uid || getegid()!=gid) ){
+        if( fchown(fd, uid, gid) ){
+          rc = SQLITE_CANTOPEN_BKPT;
+          goto open_finished;
+        }
+      }
+    }
   }
   assert( fd>=0 );
   if( pOutFlags ){
@@ -5337,23 +5800,6 @@ static int unixOpen(
     if( envforce!=NULL ){
       useProxy = atoi(envforce)>0;
     }else{
-      struct statfs fsInfo;
-      if( statfs(zPath, &fsInfo) == -1 ){
-        /* In theory, the close(fd) call is sub-optimal. If the file opened
-        ** with fd is a database file, and there are other connections open
-        ** on that file that are currently holding advisory locks on it,
-        ** then the call to close() will cancel those locks. In practice,
-        ** we're assuming that statfs() doesn't fail very often. At least
-        ** not while other file descriptors opened by the same process on
-        ** the same file are working.  */
-        p->lastErrno = errno;
-        if( dirfd>=0 ){
-          robust_close(p, dirfd, __LINE__);
-        }
-        robust_close(p, fd, __LINE__);
-        rc = SQLITE_IOERR_ACCESS;
-        goto open_finished;
-      }
       useProxy = !(fsInfo.f_flags&MNT_LOCAL);
     }
     if( useProxy ){
@@ -5419,7 +5865,13 @@ static int unixDelete(
       {
         rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
       }
+#if OSCLOSE_CHECK_CLOSE_IOERR
+      if( close(fd)&&!rc ){
+        rc = SQLITE_IOERR_DIR_CLOSE;
+      }
+#else
       robust_close(0, fd, __LINE__);
+#endif
     }
   }
 #endif
@@ -5885,6 +6337,7 @@ struct proxyLockingContext {
   char *lockProxyPath;         /* Name of the proxy lock file */
   char *dbPath;                /* Name of the open file */
   int conchHeld;               /* 1 if the conch is held, -1 if lockless */
+  int nFails;                  /* Number of conch taking failures */
   void *oldLockingContext;     /* Original lockingcontext to restore on close */
   sqlite3_io_methods const *pOldMethod;     /* Original I/O methods for close */
 };
@@ -6097,10 +6550,10 @@ extern int gethostuuid(uuid_t id, const struct timespec *wait);
 static int proxyGetHostID(unsigned char *pHostID, int *pError){
   assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
   memset(pHostID, 0, PROXY_HOSTIDLEN);
-#if defined(__MAX_OS_X_VERSION_MIN_REQUIRED)\
-               && __MAC_OS_X_VERSION_MIN_REQUIRED<1050
+#if HAVE_GETHOSTUUID
   {
-    static const struct timespec timeout = {1, 0}; /* 1 sec timeout */
+    struct timespec timeout = {1, 0}; /* 1 sec timeout */
+    
     if( gethostuuid(pHostID, &timeout) ){
       int err = errno;
       if( pError ){
@@ -6198,13 +6651,12 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
   proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; 
   unixFile *conchFile = pCtx->conchFile;
   int rc = SQLITE_OK;
-  int nTries = 0;
   struct timespec conchModTime;
   
   do {
     rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
-    nTries ++;
     if( rc==SQLITE_BUSY ){
+      pCtx->nFails ++;
       /* If the lock failed (busy):
        * 1st try: get the mod time of the conch, wait 0.5s and try again. 
        * 2nd try: fail if the mod time changed or host id is different, wait 
@@ -6217,19 +6669,19 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
         return SQLITE_IOERR_LOCK;
       }
       
-      if( nTries==1 ){
+      if( pCtx->nFails==1 ){
         conchModTime = buf.st_mtimespec;
         usleep(500000); /* wait 0.5 sec and try the lock again*/
         continue;  
       }
 
-      assert( nTries>1 );
+      assert( pCtx->nFails>1 );
       if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || 
          conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
         return SQLITE_BUSY;
       }
       
-      if( nTries==2 ){  
+      if( pCtx->nFails==2 ){  
         char tBuf[PROXY_MAXCONCHLEN];
         int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
         if( len<0 ){
@@ -6237,8 +6689,23 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
           return SQLITE_IOERR_LOCK;
         }
         if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
-          /* don't break the lock if the host id doesn't match */
+          /* don't break the lock if the host id doesn't match, but do log
+           * an error to console so users can diagnose stale NFS locks more 
+           * easily 
+           */
           if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){
+            uuid_t conchUUID;
+            uuid_string_t conchUUIDString;
+            uuid_string_t myUUIDString;
+            assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
+            memcpy(conchUUID, &tBuf[PROXY_HEADERLEN], PROXY_HOSTIDLEN);
+            uuid_unparse(conchUUID, conchUUIDString);
+            uuid_unparse(myHostID, myUUIDString);
+            fprintf(stderr, "ERROR: sqlite database is locked because it is in use "
+                    "by another host that holds a host-exclusive lock on %s; "
+                    "this host (UUID %s) cannot override the host-exclusive lock "
+                    "until the other host (UUID %s) releases its locks on %s\n", 
+                    pFile->zPath, myUUIDString, conchUUIDString, conchFile->zPath);
             return SQLITE_BUSY;
           }
         }else{
@@ -6249,8 +6716,8 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
         continue; 
       }
       
-      assert( nTries==3 );
-      if( 0==proxyBreakConchLock(pFile, myHostID) ){
+      assert( pCtx->nFails>=3 );
+      if( (pCtx->nFails==3)&&(0==proxyBreakConchLock(pFile, myHostID)) ){
         rc = SQLITE_OK;
         if( lockType==EXCLUSIVE_LOCK ){
           rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);          
@@ -6260,7 +6727,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
         }
       }
     }
-  } while( rc==SQLITE_BUSY && nTries<3 );
+  } while( rc==SQLITE_BUSY && pCtx->nFails<3 );
   
   return rc;
 }
@@ -6379,7 +6846,7 @@ static int proxyTakeConch(unixFile *pFile){
           rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
         }
       }else{
-        rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK);
+        rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
       }
       if( rc==SQLITE_OK ){
         char writeBuffer[PROXY_MAXCONCHLEN];
@@ -6433,7 +6900,14 @@ static int proxyTakeConch(unixFile *pFile){
       OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
       if( rc==SQLITE_OK && pFile->openFlags ){
         if( pFile->h>=0 ){
+#if defined(STRICT_CLOSE_ERROR) && OSCLOSE_CHECK_CLOSE_IOERR
+          if( close(pFile->h) ){
+            pFile->lastErrno = errno;
+            return SQLITE_IOERR_CLOSE;
+          }
+#else
           robust_close(pFile, pFile->h, __LINE__);
+#endif
         }
         pFile->h = -1;
         int fd = robust_open(pCtx->dbPath, pFile->openFlags,
index 7ff9a9a000aaaa21041910a0d28f4fe572f3068b..22bc145468a3b82f795e3051c7922517a8e971d8 100644 (file)
@@ -2377,7 +2377,11 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
   if( !pMaster ){
     rc = SQLITE_NOMEM;
   }else{
-    const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
+    const int flags = 
+#if SQLITE_ENABLE_DATA_PROTECTION
+      (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
+#endif
+      (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
     rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
   }
   if( rc!=SQLITE_OK ) goto delmaster_out;
@@ -2413,7 +2417,11 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
       ** so, return without deleting the master journal file.
       */
       int c;
-      int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
+      int flags = 
+#if SQLITE_ENABLE_DATA_PROTECTION
+        (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
+#endif
+        (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
       rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
       if( rc!=SQLITE_OK ){
         goto delmaster_out;
@@ -3398,7 +3406,11 @@ static int pagerOpentemp(
   sqlite3_opentemp_count++;  /* Used for testing and analysis only */
 #endif
 
-  vfsFlags |=  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
+  vfsFlags |=  
+#if SQLITE_ENABLE_DATA_PROTECTION
+            (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
+#endif
+            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
             SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
   rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0);
   assert( rc!=SQLITE_OK || isOpen(pFile) );
@@ -4527,7 +4539,11 @@ int sqlite3PagerOpen(
   pPager->noSync = pPager->tempFile;
   pPager->fullSync = pPager->noSync ?0:1;
   pPager->syncFlags = pPager->noSync ? 0 : SQLITE_SYNC_NORMAL;
+#if SQLITE_DEFAULT_CKPTFULLFSYNC
+  pPager->ckptSyncFlags = pPager->noSync ? 0 : SQLITE_SYNC_FULL;
+#else
   pPager->ckptSyncFlags = pPager->syncFlags;
+#endif
   /* pPager->pFirst = 0; */
   /* pPager->pFirstSynced = 0; */
   /* pPager->pLast = 0; */
@@ -4638,7 +4654,11 @@ static int hasHotJournal(Pager *pPager, int *pExists){
           ** it can be ignored.
           */
           if( !jrnlOpen ){
-            int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
+            int f = 
+#if SQLITE_ENABLE_DATA_PROTECTION
+              (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
+#endif
+              SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
             rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
           }
           if( rc==SQLITE_OK ){
@@ -4776,7 +4796,11 @@ int sqlite3PagerSharedLock(Pager *pPager){
             pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists);
         if( rc==SQLITE_OK && bExists ){
           int fout = 0;
-          int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
+          int f = 
+#if SQLITE_ENABLE_DATA_PROTECTION
+            (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
+#endif
+            SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
           assert( !pPager->tempFile );
           rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
           assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
@@ -5152,6 +5176,9 @@ static int pager_open_journal(Pager *pPager){
         sqlite3MemJournalOpen(pPager->jfd);
       }else{
         const int flags =                   /* VFS flags to open journal file */
+#if SQLITE_ENABLE_DATA_PROTECTION
+          (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
+#endif
           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
           (pPager->tempFile ? 
             (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
@@ -6710,10 +6737,14 @@ static int pagerOpenWal(Pager *pPager){
   ** (e.g. due to malloc() failure), return an error code.
   */
   if( rc==SQLITE_OK ){
-    rc = sqlite3WalOpen(pPager->pVfs, 
-        pPager->fd, pPager->zWal, pPager->exclusiveMode,
-        pPager->journalSizeLimit, &pPager->pWal
-    );
+#if SQLITE_ENABLE_DATA_PROTECTION
+    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
+        pPager->journalSizeLimit, (pPager->vfsFlags & SQLITE_OPEN_FILEPROTECTION_MASK), 
+        &pPager->pWal);
+#else
+    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
+        pPager->journalSizeLimit, 0, &pPager->pWal);
+#endif
   }
 
   return rc;
index c36707a2f270256997cabc776236fff0862e9d78..a4eb40449914e775c7765146b55362dd422430d1 100644 (file)
@@ -441,10 +441,10 @@ void sqlite3Pragma(
     if( pId2->n==0 && b>=0 ){
       int ii;
       for(ii=0; ii<db->nDb; ii++){
-        sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b);
+        sqlite3BtreeSecureDelete(db->aDb[ii].pBt, (int)b);
       }
     }
-    b = sqlite3BtreeSecureDelete(pBt, b);
+    b = (int)sqlite3BtreeSecureDelete(pBt, (int)b);
     returnSingleInt(pParse, "secure_delete", &b);
   }else
 
@@ -564,6 +564,14 @@ void sqlite3Pragma(
       iDb = 0;
       pId2->n = 1;
     }
+#ifdef SQLITE_DEFAULT_WAL_SAFETYLEVEL
+    if (eMode == PAGER_JOURNALMODE_WAL) {
+      /* when entering wal mode, immediately switch the safety_level
+       * so that a query to pragma synchronous returns the correct value
+       */
+      pDb->safety_level = SQLITE_DEFAULT_WAL_SAFETYLEVEL;
+    }
+#endif /* SQLITE_DEFAULT_WAL_SAFETYLEVEL */
     for(ii=db->nDb-1; ii>=0; ii--){
       if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
         sqlite3VdbeUsesBtree(v, ii);
index 8dcfb84b8a619a553bd2b0561ff5c3b50af0d90e..983a805c52e312c8566aee7a0a8d634e92c31c88 100644 (file)
@@ -4371,6 +4371,9 @@ select_end:
 }
 
 #if defined(SQLITE_DEBUG)
+void sqlite3PrintExpr(Expr *p);
+void sqlite3PrintExprList(ExprList *pList);
+void sqlite3PrintSelect(Select *p, int indent);
 /*
 *******************************************************************************
 ** The following code is used for testing and debugging only.  The code
index 2e6ca2b74a5307c126a514c38aca09e4baa6ab30..e5d805aa885e486952e65691ba3efcfc8ed31ac1 100644 (file)
@@ -64,6 +64,9 @@ extern "C" {
 */
 #define SQLITE_DEPRECATED
 #define SQLITE_EXPERIMENTAL
+#ifndef __OSX_AVAILABLE_BUT_DEPRECATED
+#define __OSX_AVAILABLE_BUT_DEPRECATED(MacOSAvailable, MacOSDeprecated, iPhoneOSAvailable, iPhoneOSDeprecated)
+#endif
 
 /*
 ** Ensure these symbols were not defined by some previous header file.
@@ -483,6 +486,7 @@ int sqlite3_exec(
 #define SQLITE_OPEN_SHAREDCACHE      0x00020000  /* Ok for sqlite3_open_v2() */
 #define SQLITE_OPEN_PRIVATECACHE     0x00040000  /* Ok for sqlite3_open_v2() */
 #define SQLITE_OPEN_WAL              0x00080000  /* VFS only */
+#define SQLITE_OPEN_FILEPROTECTION_MASK                                 0x00700000
 
 /* Reserved:                         0x00F00000 */
 
@@ -4455,9 +4459,14 @@ void *sqlite3_update_hook(
 ** future releases of SQLite.  Applications that care about shared
 ** cache setting should set it explicitly.
 **
+** ^Note: This method is deprecated on MacOS X 10.7 and iOS version 5.0
+** and will always return SQLITE_MISUSE, instead of calling this function
+** shared cache mode should be enabled per-database connection via 
+** sqlite3_open_v2 with SQLITE_OPEN_SHAREDCACHE instead.
+**
 ** See Also:  [SQLite Shared-Cache Mode]
 */
-int sqlite3_enable_shared_cache(int);
+int sqlite3_enable_shared_cache(int) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_7, __IPHONE_2_0, __IPHONE_5_0);
 
 /*
 ** CAPI3REF: Attempt To Free Heap Memory
index 907da818229783a7cacf5b3d4e9014090ed1dc43..5d39495ee8f4392073a873426dd855bf0c56f234 100644 (file)
@@ -5,6 +5,28 @@
 #ifndef _SQLITE3_PRIVATE_H
 #define _SQLITE3_PRIVATE_H
 
+#define SQLITE_LOCKSTATE_OFF    0
+#define SQLITE_LOCKSTATE_ON     1
+#define SQLITE_LOCKSTATE_NOTADB 2
+#define SQLITE_LOCKSTATE_ERROR  -1
+
+#define SQLITE_LOCKSTATE_ANYPID -1
+
+/* 
+** Test a file path for sqlite locks held by a process ID (-1 = any PID). 
+** Returns one of the following integer codes:
+** 
+**   SQLITE_LOCKSTATE_OFF    no active sqlite file locks match the specified pid
+**   SQLITE_LOCKSTATE_ON     active sqlite file locks match the specified pid
+**   SQLITE_LOCKSTATE_NOTADB path points to a file that is not an sqlite db file
+**   SQLITE_LOCKSTATE_ERROR  path was not vaild or was unreadable
+**
+** There is no support for identifying db files encrypted via SEE encryption
+** currently.  Zero byte files are tested for sqlite locks, but if no sqlite 
+** locks are present then SQLITE_LOCKSTATE_NOTADB is returned.
+*/
+extern int _sqlite3_lockstate(const char *path, pid_t pid);
+
 /*
 ** Pass the SQLITE_TRUNCATE_DATABASE operation code to sqlite3_file_control() 
 ** to truncate a database and its associated journal file to zero length.
index 6171e980bc6579afe996fd261d6b975cbc7f3c0c..dc5f5d2de4dff973904748236caf4959293c3ab3 100644 (file)
@@ -4968,6 +4968,83 @@ static int file_control_lasterrno_test(
   return TCL_OK;  
 }
 
+#ifdef __APPLE__
+/* From sqlite3_priavet.h */
+# ifndef SQLITE_TRUNCATE_DATABASE
+# define SQLITE_TRUNCATE_DATABASE      101
+# endif
+# ifndef SQLITE_REPLACE_DATABASE
+# define SQLITE_REPLACE_DATABASE       102
+# endif
+
+/*
+** tclcmd:   file_control_truncate_test DB
+**
+** This TCL command runs the sqlite3_file_control interface and
+** verifies correct operation of the SQLITE_TRUNCATE_DATABASE verb.
+*/
+static int file_control_truncate_test(
+  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  sqlite3 *db;
+  int rc;
+  
+  if( objc!=2 ){
+    Tcl_AppendResult(interp, "wrong # args: should be \"",
+                     Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
+    return TCL_ERROR;
+  }
+  rc = sqlite3_file_control(db, NULL, SQLITE_TRUNCATE_DATABASE, 0);
+  if( rc ){ 
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 
+    return TCL_ERROR; 
+  }
+  return TCL_OK;  
+}
+
+/*
+** tclcmd:   file_control_replace_test DB
+**
+** This TCL command runs the sqlite3_file_control interface and
+** verifies correct operation of the SQLITE_REPLACE_DATABASE verb.
+*/
+static int file_control_replace_test(
+  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  int iArg = 0;
+  sqlite3 *src_db;
+  sqlite3 *dst_db;
+  int rc;
+  
+  if( objc!=3 ){
+    Tcl_AppendResult(interp, "wrong # args: should be \"",
+                     Tcl_GetStringFromObj(objv[0], 0), " DST_DB SRC_DB", 0);
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &dst_db) ){
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, Tcl_GetString(objv[2]), &src_db) ){
+    return TCL_ERROR;
+  }
+  rc = sqlite3_file_control(dst_db, NULL, SQLITE_REPLACE_DATABASE, src_db);
+  if( rc ){ 
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 
+    return TCL_ERROR; 
+  }
+  return TCL_OK;  
+}
+#endif /* __APPLE__ */
+
 /*
 ** tclcmd:   file_control_chunksize_test DB DBNAME SIZE
 **
@@ -5911,6 +5988,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
      { "file_control_test",          file_control_test,   0   },
      { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
      { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
+#ifdef __APPLE__
+     { "file_control_truncate_test", file_control_truncate_test,  0   },
+     { "file_control_replace_test", file_control_replace_test,  0   },
+#endif 
      { "file_control_chunksize_test", file_control_chunksize_test,  0   },
      { "file_control_sizehint_test", file_control_sizehint_test,  0   },
      { "sqlite3_vfs_list",           vfs_list,     0   },
index 466f84f5dfa3063318a0051d8080dcdc0376e073..51c9215b18a10d5834a1b7ceb27091290db8dd0f 100644 (file)
@@ -435,7 +435,17 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
 #else
   Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","0",TCL_GLOBAL_ONLY);
 #endif
-    
+#if SQLITE_DEFAULT_CKPTFULLFSYNC
+  Tcl_SetVar2(interp,"sqlite_options","default_ckptfullfsync","1",TCL_GLOBAL_ONLY);
+#else
+  Tcl_SetVar2(interp,"sqlite_options","default_ckptfullfsync","0",TCL_GLOBAL_ONLY);
+#endif
+#if SQLITE_DEFAULT_WAL_SAFETYLEVEL
+  Tcl_SetVar2(interp,"sqlite_options","default_wal_safetylevel",
+              STRINGVALUE(SQLITE_DEFAULT_WAL_SAFETYLEVEL),TCL_GLOBAL_ONLY);
+#else
+  Tcl_SetVar2(interp,"sqlite_options","default_wal_safetylevel","0",TCL_GLOBAL_ONLY);
+#endif
     
 #ifdef SQLITE_OMIT_SHARED_CACHE
   Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "0", TCL_GLOBAL_ONLY);
index 5fc994ddf204c9d1771fc95a5589363045aeb720..be1f16bc28fb19301296180b305b7770c63f4e06 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library. 
 */
 
-#include <sqlite3.h>
+#include "sqlite3.h"
 
 /* Solely for the UNUSED_PARAMETER() macro. */
 #include "sqliteInt.h"
index 936fcad0c56f6bc85809742f6ae1c1eeb8b7d2f1..fe08b1b125a6d7a90fe11f0f3b4e20f4588ee7c6 100644 (file)
@@ -18,7 +18,7 @@
 **   sqlite3demo_superunlock()
 */
 
-#include <sqlite3.h>
+#include "sqlite3.h"
 #include <string.h>               /* memset(), strlen() */
 #include <assert.h>               /* assert() */
 
@@ -148,7 +148,7 @@ static int superlockWalLock(
 ** this function must have been obtained from a successful call to
 ** sqlite3demo_superlock().
 */
-void sqlite3demo_superunlock(void *pLock){
+static void sqlite3demo_superunlock(void *pLock){
   Superlock *p = (Superlock *)pLock;
   if( p->bWal ){
     int rc;                         /* Return code */
@@ -179,9 +179,10 @@ void sqlite3demo_superunlock(void *pLock){
 ** until either the lock can be obtained or the busy-handler function returns
 ** 0 (indicating "give up").
 */
-int sqlite3demo_superlock(
+static int sqlite3demo_superlock(
   const char *zPath,              /* Path to database file to lock */
   const char *zVfs,               /* VFS to use to access database file */
+  int flags,                      /* Additional flags to pass to sqlite3_open_v2 */
   int (*xBusy)(void*,int),        /* Busy handler callback */
   void *pBusyArg,                 /* Context arg for busy handler */
   void **ppLock                   /* OUT: Context to pass to superunlock() */
@@ -196,7 +197,7 @@ int sqlite3demo_superlock(
 
   /* Open a database handle on the file to superlock. */
   rc = sqlite3_open_v2(
-      zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs
+    zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|flags, zVfs
   );
 
   /* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not
@@ -331,7 +332,7 @@ static int superlock_cmd(
     xBusy = superlock_busy;
   }
 
-  rc = sqlite3demo_superlock(zPath, zVfs, xBusy, &busy, &pLock);
+  rc = sqlite3demo_superlock(zPath, zVfs, 0, xBusy, &busy, &pLock);
   assert( rc==SQLITE_OK || pLock==0 );
   assert( rc!=SQLITE_OK || pLock!=0 );
 
index de123b550f9902c0afbfb2172e4affc5699ca067..c2a2052537c04feb18c783544bd21efee49034bd 100644 (file)
@@ -83,9 +83,12 @@ char *sqlite3VdbeExpandSql(
   if( db->vdbeExecCnt>1 ){
     while( *zRawSql ){
       const char *zStart = zRawSql;
+      sqlite_int64 iStart = SQLITE_PTR_TO_INT(zRawSql);
+      sqlite_int64 iCurrent;
       while( *(zRawSql++)!='\n' && *zRawSql );
       sqlite3StrAccumAppend(&out, "-- ", 3);
-      sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
+      iCurrent = SQLITE_PTR_TO_INT(zRawSql);
+      sqlite3StrAccumAppend(&out, zStart, (int)(iCurrent-iStart));
     }
   }else{
     while( zRawSql[0] ){
index b9a03dff2380c36bba8a82959ea185b4aa57e69c..74334e9688552c21a022f791f87c566a7f2c3cca 100644 (file)
--- a/src/wal.c
+++ b/src/wal.c
@@ -1247,11 +1247,12 @@ int sqlite3WalOpen(
   const char *zWalName,           /* Name of the WAL file */
   int bNoShm,                     /* True to run in heap-memory mode */
   i64 mxWalSize,                  /* Truncate WAL to this size on reset */
+  int flags,                      /* VFS file protection flags */
   Wal **ppWal                     /* OUT: Allocated Wal handle */
 ){
   int rc;                         /* Return Code */
   Wal *pRet;                      /* Object to allocate and return */
-  int flags;                      /* Flags passed to OsOpen() */
+  int vfsFlags;                   /* Flags passed to OsOpen() */
 
   assert( zWalName && zWalName[0] );
   assert( pDbFd );
@@ -1284,9 +1285,9 @@ int sqlite3WalOpen(
   pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
 
   /* Open file handle on the write-ahead log file. */
-  flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
-  rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
-  if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
+  vfsFlags = flags | (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
+  rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, vfsFlags, &vfsFlags);
+  if( rc==SQLITE_OK && vfsFlags&SQLITE_OPEN_READONLY ){
     pRet->readOnly = WAL_RDONLY;
   }
 
index a62b23bbdc99f2551bcb8f8083541b0968113478..526ea2b117611e9d183744ed16135153c218fcf9 100644 (file)
--- a/src/wal.h
+++ b/src/wal.h
@@ -47,7 +47,7 @@
 typedef struct Wal Wal;
 
 /* Open and close a connection to a write-ahead log. */
-int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
+int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, int, Wal**);
 int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
 
 /* Set the limiting size of a WAL file. */
index f3f2f6ac5003d0100496429a8f7e3062a7a028f0..3fb50fb534837f8728dde948259b155be7060671 100644 (file)
@@ -81,6 +81,7 @@ if {![wal_is_ok]} { set skipwaltests 1 }
 if {!$skipwaltests} {
   db close
   file delete -force test.db
+  if {[forced_proxy_locking]} { file delete -force .test.db-conch }
   sqlite3 db test.db
   file_control_chunksize_test db main [expr 32*1024]
   
index 4c49f1563c18dff4ec0919bdfa86f1732d8ba14d..98ca38878b7c298e6fb7683ca0923fa9aca42704 100644 (file)
@@ -260,12 +260,17 @@ proc access_method {args} {
   return ""
 }
 
-do_test incrblob3-7.2 {
-  sqlite3 db test.db 
-  sqlite3_db_config_lookaside db 0 0 0
-  list [catch {db incrblob blobs v 1} msg] $msg
-} {1 {database schema has changed}}
-db close
+#set sqlite_os_trace 1
+# AFP asserts because the "db incrblob blobs v 1" clears the file locks and the unlock fails (HFS doesn't care about a failed unlock)
+if {[path_is_local "."]} {
+
+  do_test incrblob3-7.2 {
+    sqlite3 db test.db 
+    sqlite3_db_config_lookaside db 0 0 0
+    list [catch {db incrblob blobs v 1} msg] $msg
+  } {1 {database schema has changed}}
+  db close
+}
 tvfs delete
 
 finish_test
index 9278e8427496bb198be62939b93369288c20e3f7..dc3bd66b9e157ee1a027f8040a9f011ac9218892 100644 (file)
@@ -14,6 +14,12 @@ set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 source $testdir/malloc_common.tcl
 
+# AFP doesn't like multiplex db tests
+if { ![path_is_local "."] } {
+  finish_test 
+  return 
+}
+
 set g_chunk_size [ expr ($::SQLITE_MAX_PAGE_SIZE*16384) ]
 set g_max_chunks 32
 
index 136ca05f467ca096bc7b65f2f2e791183ff3e5ee..5c5f8677c7b6ac1575c9e764ab12553f9a13cc41 100644 (file)
@@ -534,6 +534,8 @@ proc copy_on_mj_delete {method filename args} {
 }
 
 set pwd [pwd]
+if {![forced_proxy_locking]} {
+  # proxy locking uses can't deal with auto proxy file paths longer than MAXPATHLEN
 foreach {tn1 tcl} {
   1 { set prefix "test.db" }
   2 { 
@@ -665,6 +667,7 @@ foreach {tn1 tcl} {
 db close
 tv delete
 file delete -force $dirname
+}
 
 
 # Set up a VFS to make a copy of the file-system just before deleting a
@@ -2008,8 +2011,8 @@ do_test pager1-22.2.1 {
   set ::synccount 0
   sqlite3 db test.db
   execsql {
-    PRAGMA synchronous = off;
     PRAGMA journal_mode = WAL;
+    PRAGMA synchronous = off;
     INSERT INTO ko DEFAULT VALUES;
   }
   execsql { PRAGMA wal_checkpoint }
index f2ef3a069d466b32354d32aac0c4b9438d434110..d974d6ea2300ab655f66b754700aa0346c1e0fec 100644 (file)
@@ -1348,7 +1348,7 @@ if !$skip_lock_proxy_tests {
     } db2
   } {1 {database is locked}}
 
-  set lpp3 [exec mktemp -t 'proxy3']
+  set lpp3 [exec mktemp -t "proxy3"]
 
   # lock proxy file can be renamed if no other connections are active
   do_test pragma-16.4 {
@@ -1404,7 +1404,7 @@ if !$skip_lock_proxy_tests {
   } {1 {database is locked}}
 
   db2 close
-  set lpp4 [exec mktemp -t 'proxy4']
+  set lpp4 [exec mktemp -t "proxy4"]
 
   # check that db is unlocked after first host connection closes 
   do_test pragma-16.8.1 {
@@ -1433,9 +1433,9 @@ if !$skip_lock_proxy_tests {
   } {1}
 
   # ensure creating directories for a lock proxy file works
-  set lpp5 [exec mktemp -d -t "proxy5"]/sub/dir/lock
+  set lpp5d [exec mktemp -d -t "proxy5"]
+  set lpp5 $lpp5d/sub/dir/lock
   db close
-  file delete -force proxytest
   do_test pragma-16.10.1 {
     sqlite3 db proxytest.db
     execsql "PRAGMA lock_proxy_file='$lpp5'" 
@@ -1447,7 +1447,7 @@ if !$skip_lock_proxy_tests {
 
   # ensure that after deleting the path, setting ":auto:" works correctly
   db close
-  file delete -force proxytest
+  file delete -force $lpp5d
   do_test pragma-16.10.2 {
     sqlite3 db proxytest.db
     set lockpath3 [execsql {
@@ -1461,8 +1461,8 @@ if !$skip_lock_proxy_tests {
   # ensure that if the path can not be created (file instead of dir)
   # setting :auto: deals with it by creating a new autonamed lock file
   db close
-  file delete -force proxytest
-  close [open "proxytest" a]
+  file delete -force $lpp5d
+  close [open "$lpp5d" a]
   do_test pragma-16.10.3 {
     sqlite3 db proxytest.db
     set lockpath2 [execsql {
@@ -1474,9 +1474,9 @@ if !$skip_lock_proxy_tests {
   } {1}
 
   # make sure we can deal with ugly file paths correctly
-  set lpp6 [exec mktemp -d -t "proxy6"]/./././////./proxytest/../proxytest/sub/dir/lock
   db close
-  file delete -force proxytest
+  file delete -force $lpp5d
+  set lpp6 [exec mktemp -d -t "proxy6"]/./././////./proxytest/../proxytest/sub/dir/lock
   do_test pragma-16.10.4 {
     sqlite3 db proxytest.db
     execsql "PRAGMA lock_proxy_file='$lpp6'" 
@@ -1489,7 +1489,7 @@ if !$skip_lock_proxy_tests {
 
   # ensure that if the path can not be created (perm), setting :auto: deals
   db close
-  file delete -force proxytest
+  file delete -force $lpp5d
   do_test pragma-16.10.5 {
     sqlite3 db proxytest.db
     execsql "PRAGMA lock_proxy_file='$lpp5'" 
@@ -1497,9 +1497,9 @@ if !$skip_lock_proxy_tests {
       create table if not exists bb(bb);
     }
     db close
-    file delete -force proxytest
-    file mkdir proxytest
-    file attributes proxytest -permission 0000
+    file delete -force $lpp5d
+    file mkdir $lpp5d
+    file attributes $lpp5d -permission 0000
     sqlite3 db proxytest.db
     set lockpath5 [execsql {
       PRAGMA lock_proxy_file=":auto:";
@@ -1521,8 +1521,8 @@ if !$skip_lock_proxy_tests {
   } {1 {database is locked}}
   db close
 
-  file attributes proxytest -permission 0777
-  file delete -force proxytest
+  file attributes $lpp5d -permission 0777
+  file delete -force $lpp5d
 
   set env(SQLITE_FORCE_PROXY_LOCKING) $using_proxy
   set sqlite_hostid_num 0
index b12863f7ffd0a8361f4ce357566e79b4b3571383..7fc8cf5fdfd70ed921cddeee212e2ef37c8db9c5 100644 (file)
@@ -52,6 +52,12 @@ do_test 1.2 { sqlite3demo_superlock unlock test.db } {unlock}
 do_catchsql_test 1.3 { SELECT * FROM t1 } {1 {database is locked}}
 do_test 1.4 { unlock } {}
 
+ifcapable !wal {finish_test ; return }
+if { ![wal_is_ok] } {
+  finish_test 
+  return 
+}
+
 do_execsql_test 2.1 { 
   INSERT INTO t1 VALUES(3, 4);
   PRAGMA journal_mode = WAL;
index 391382f4f44a81ff75e6054a1f4af26b573216ad..40eb2e26332f8d8609eb44dedb056c49073014f0 100644 (file)
@@ -242,6 +242,23 @@ if {[info exists cmdlinearg]==0} {
 #
 sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
 
+proc forced_proxy_locking {} {
+  if $::sqlite_options(lock_proxy_pragmas)&&$::sqlite_options(prefer_proxy_locking) {
+    set force_proxy_value 0
+    set force_key "SQLITE_FORCE_PROXY_LOCKING="
+    foreach {env_pair} [exec env] { 
+      if { [string first $force_key $env_pair] == 0} {
+        set force_proxy_value [string range $env_pair [string length $force_key] end]
+      }
+    }
+    if { "$force_proxy_value " == "1 " } {
+      return 1
+    } 
+  }
+  return 0
+}
+
+
 # Create a test database
 #
 proc reset_db {} {
@@ -249,6 +266,14 @@ proc reset_db {} {
   file delete -force test.db
   file delete -force test.db-journal
   file delete -force test.db-wal
+  if {[forced_proxy_locking]} {
+    sqlite3 db ./test.db
+    set lock_proxy_path [db eval "PRAGMA lock_proxy_file;"] 
+    catch {db close}
+    # puts "deleting $lock_proxy_path"
+    file delete -force $lock_proxy_path    
+    file delete -force test.db
+  }
   sqlite3 db ./test.db
   set ::DB [sqlite3_connection_pointer db]
   if {[info exists ::SETUP_SQL]} {
@@ -1334,22 +1359,6 @@ proc presql {} {
   set presql
 }
 
-proc forced_proxy_locking {} {
-  ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
-    set force_proxy_value 0
-    set force_key "SQLITE_FORCE_PROXY_LOCKING="
-    foreach {env_pair} [exec env] { 
-      if { [string first $force_key $env_pair] == 0} {
-        set force_proxy_value [string range $env_pair [string length $force_key] end]
-      }
-    }
-    if { "$force_proxy_value " == "1 " } {
-      return 1
-    } 
-  }
-  return 0
-}
-
 proc wal_is_ok {} {
   if { [forced_proxy_locking] } {
     return 1
index d3657dec9bdedf2effcbbf1d49f28e9ba7084a02..ad69b39380b26844151ba4eaf44060c45f34fb7c 100644 (file)
@@ -1183,6 +1183,11 @@ foreach {tn sql reslist} {
   2 { PRAGMA checkpoint_fullfsync = 1 } {8 4 3 2 5 2}
   3 { PRAGMA checkpoint_fullfsync = 0 } {8 0 3 0 5 0}
 } {
+  if { $::sqlite_options(default_ckptfullfsync) && $tn == 1} {
+    # checkpoint_fullfsync on by default
+    set reslist {8 4 3 2 5 2}
+  }
+
   faultsim_delete_and_reopen
 
   execsql {PRAGMA auto_vacuum = 0}
index 99da0c98aaebd24eb71676e1e806c560ba27f127..13303e2c4dcd11a2c6536546228d721595ae3aba 100644 (file)
@@ -207,6 +207,16 @@ foreach {tn syncmode synccount} {
     {test.db-wal normal test.db-wal normal test.db-wal normal test.db normal}
 } {
 
+  if { $::sqlite_options(default_ckptfullfsync) } {
+    # checkpoint_fullfsync on by default
+    if { $tn == 2} {
+      set synccount {test.db-wal full test.db full}
+    }
+    if { $tn == 3} {
+      set synccount {test.db-wal normal test.db-wal normal test.db-wal full test.db full}
+    }
+  }
+
   proc sync_counter {args} { 
     foreach {method filename id flags} $args break
     lappend ::syncs [file tail $filename] $flags
index 6fae48e9eabab325d2ac38958fea88896980787a..2db4d5d1e43b8c6b7f33629388abd4cefba89fd8 100644 (file)
@@ -20,6 +20,8 @@ source $testdir/wal_common.tcl
 source $testdir/malloc_common.tcl
 ifcapable !wal {finish_test ; return }
 
+if { ![wal_is_ok] } {finish_test ; return }
+
 #-------------------------------------------------------------------------
 # Changing to WAL mode in one connection forces the change in others.
 #
index 60265de485e7413c4ffb798aae4dedbe05d25540..0ad48ec6b53f8a29af2f01ca39907c8321cb8bfd 100644 (file)
@@ -16,10 +16,7 @@ source $testdir/tester.tcl
 source $testdir/lock_common.tcl
 source $testdir/wal_common.tcl
 ifcapable !wal {finish_test ; return }
-if { ![wal_is_ok] } {
-  finish_test 
-  return 
-}
+if { ![wal_is_ok] } { finish_test ; return }
 
 
 #-------------------------------------------------------------------------
index 60bdce9e04611d28bb59a59bb4b171a0fb1b6ae9..4dbfa088400a504ff0313ac2a07d1fdce477fcd3 100644 (file)
@@ -24,6 +24,13 @@ if {$::tcl_platform(platform) != "unix"} {
   return
 }
 
+# these tests can't deal with the location of the -shm file under proxy locking
+#
+if {[forced_proxy_locking]} {
+  finish_test
+  return
+}
+
 do_multiclient_test tn {
   # Do not run tests with the connections in the same process.
   #