-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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
-2d4458af59c697ad453996815d14442230654670
\ No newline at end of file
+34f0efa2b12e8eb09331768b1524a076baeb34ea
\ No newline at end of file
** 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
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;
}
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
/*
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
#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
}
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 */
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;
}
#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>
#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
#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,...).
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;
}
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;
}
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;
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;
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;
}
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;
}
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
** an assert to fail). */
rc = SQLITE_IOERR_RDLOCK;
pFile->lastErrno = errno;
+#endif
goto end_unlock;
}
}
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;
}
}
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;
}
*/
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;
robust_close(pFile, pFile->h, __LINE__);
pFile->h = -1;
}
+#endif
#if OS_VXWORKS
if( pFile->pId ){
if( pFile->isDelete ){
}
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;
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;
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;
/* 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;
}
#include <copyfile.h>
static int getDbPathForUnixFile(unixFile *pFile, char *dbPath);
#endif
+static int isProxyLockingMode(unixFile *);
/*
** Information and control of an open file handle.
#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;
}
}
}
-static int isProxyLockingMode(unixFile *);
static const char *proxySharedMemoryBasePath(unixFile *);
/*
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 ){
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;
if( 0==stat(zDb, &sStat) ){
*pMode = sStat.st_mode & 0777;
+ *pUid = sStat.st_uid;
+ *pGid = sStat.st_gid;
}else{
rc = SQLITE_IOERR_FSTAT;
}
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 */
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 );
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 ){
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 ){
{
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
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 */
};
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 ){
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
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 ){
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{
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);
}
}
}
- } while( rc==SQLITE_BUSY && nTries<3 );
+ } while( rc==SQLITE_BUSY && pCtx->nFails<3 );
return rc;
}
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];
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,
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;
** 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;
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) );
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; */
** 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 ){
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) );
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):
** (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;
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
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);
}
#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
*/
#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.
#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 */
** 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
#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.
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
**
{ "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 },
#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);
** is not included in the SQLite library.
*/
-#include <sqlite3.h>
+#include "sqlite3.h"
/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"
** sqlite3demo_superunlock()
*/
-#include <sqlite3.h>
+#include "sqlite3.h"
#include <string.h> /* memset(), strlen() */
#include <assert.h> /* assert() */
** 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 */
** 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() */
/* 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
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 );
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] ){
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 );
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;
}
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. */
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]
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
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
}
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 {
db close
tv delete
file delete -force $dirname
+}
# Set up a VFS to make a copy of the file-system just before deleting a
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 }
} 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 {
} {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 {
} {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'"
# 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 {
# 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 {
} {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'"
# 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'"
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:";
} {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
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;
#
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 {} {
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]} {
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
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}
{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
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.
#
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 }
#-------------------------------------------------------------------------
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.
#