- C Merge\sin\sall\strunk\schanges\sthrough\sthe\s3.7.8\srelease.
- D 2011-09-19T20:32:36.507
-C Merging\sin\scherry\spicked\sdiffs\sfor\spersist\swal,\salloc\spadding,\swal-safe\svacuum\sand\ssqlite3_file_control\sbased\slockstate\schecking
-D 2011-10-10T22:11:44.216
++C Forward\sport\sthe\sApple-specific\schanges\sfrom\s[db5b7b778c]\sin\sthe\napple-osx-377\sbranch.\s\sFix\sthis\sup\sso\sthat\sit\swill\scompile\sand\srun\son\sLinux.
++D 2011-10-10T23:53:48.384
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
-F Makefile.in 8410b02448997eb43bdf0ffa482c9bc2d2624e45
+F Makefile.in 55bbee3ada084d4aa4dab9e1e0d90a21aab8bbcf
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
-F Makefile.msc 11082f65b452b908d93013292c17850378c39284
-F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151
+F Makefile.msc b5e917439d5ed42364173d1648aae1d418e323ea
+F Makefile.vxworks 1deb39c8bb047296c30161ffa10c1b5423e632f9
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
-F VERSION 3fcdd7fbe3eb282df3978fe77288544543767961
+F VERSION f724de7326e87b7f3b0a55f16ef4b4d993680d54
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
F src/analyze.c a425d62e8fa9ebcb4359ab84ff0c62c6563d2e2a
F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
- F src/backup.c 28a4fe55327ff708bfaf9d4326d02686f7a553c3
-F src/backup.c 1cf56cc81b035e0a9884ddac13442edefcb0cb46
++F src/backup.c 5774963f44ed38c56561033694d3a5ad516c556b
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
-F src/btree.c 1870b70e376c5c9ff31e1235e4e4434212709265
+F src/btree.c 71a65f9bbdc3c93bd0f043aa9148b751474cea5e
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
-F src/build.c 5a428625d21ad409514afb40ad083bee25dd957a
+F src/build.c 851e81f26a75abbb98bd99a7c5f10e8670d867bb
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
-F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4
-F src/date.c d3c11de76392ea62637bfac0f4655889fc2f5a85
-F src/delete.c 4925f9121525fc871f5d8d13c1f7dcc91abb38bb
-F src/expr.c ab46ab0f0c44979a8164ca31728d7d10ae5e8106
+F src/ctime.c e3132ec65240b2e2f3d50831021eac387f27584d
+F src/date.c a3c6842bad7ae632281811de112a8ba63ff08ab3
+F src/delete.c ff68e5ef23aee08c0ff528f699a19397ed8bbed8
+F src/expr.c f4dcaeb8252c4b16fcdc245660f70ed366bc6cdd
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
-F src/fkey.c 9fabba17a4d4778dc660f0cb9d781fc86d7b9d41
+F src/fkey.c 9f00ea98f6b360d477b5a78b5b59a1fbde82431c
F src/func.c 1b9d471b632d8529e0f86b7bd2b918dcc2cb1097
-F src/global.c c70a46f28680f8d7c097dbc0430ccf3b932e90b0
+F src/global.c e230227de13601714b29f9363028514aada5ae2f
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c 015826a958f690302d27e096a68d50b3657e4201
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
-F src/loadext.c 3ae0d52da013a6326310655be6473fd472347b85
-F src/main.c f3d35af74fdccb20f7edb31d842006d99887cf2e
+F src/loadext.c 99a161b27a499fc8ad40745b7b1900a26f0a5f51
- F src/main.c 242eaa584e256364f81f2aef97d3eca283d94073
++F src/main.c 4aabaa8d510c08d59595be5d83c4d630e8200982
F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
- F src/mem1.c 46095d62b241466ef51970e592aa3a7a87e443e1
-F src/mem1.c 1abe5a2c20d981e050504684bfdd3a126356e6d9
++F src/mem1.c c390a8fce10912a770ebe6fa031f5f463649e7ae
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
-F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3
+F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f
F src/memjournal.c 0ebce851677a7ac035ba1512a7e65851b34530c6
F src/mutex.c 6949180803ff05a7d0e2b9334a95b4fb5a00e23f
F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579
F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
-F src/os.c 1663f3754a3da185369a121a4f417762f77880b6
+F src/os.c 0668c16ae226cd58cef8240e5edbd0c93248739e
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
-F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
+F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
- F src/os_unix.c 6fdce4067dc5796b358bd9cf55cf5dd62d580945
- F src/os_win.c 0fc0f46c94b0385a940b0ee32992a833019a5985
- F src/pager.c 984dc40d797d8d822d6ce1d184287600d94a289f
-F src/os_unix.c 8f60f53930d4c9e781c46d803b3534d004282442
-F src/os_win.c daa67fe04bd162fbcc387214e9614a7faa6b90b1
-F src/pager.c 4bee5b51c33855cd8de4094709912b000f2bccff
++F src/os_unix.c ed727d5822235e16519e82ba8bb355426381e1be
++F src/os_win.c 3fc8f4bb69dd71b2dc6b48e8d5fb411748197470
++F src/pager.c 5cafaf3833fceefd21bfa4dd2254b71461663286
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 49e718c095810c6b3334e3a6d89970aceaddefce
F src/prepare.c 9d7403fe75fefa134351b41400d09ba1b189134b
F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
-F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
+F src/resolve.c 36368f44569208fa074e61f4dd0b6c4fb60ca2b4
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
-F src/select.c 75b7dd8c6a5ff9b8ec3f7ed51d31af8b30f114bc
-F src/shell.c 0e0173b3e79d956368013e759f084caa7995ecb1
-F src/sqlite.h.in 05e72174ea58476dc71db4bb6816f5b79a100f76
+F src/select.c f3971442d59d06801ac3c712f2851ece8d1cdead
+F src/shell.c 13fe2aeddc3cc90d6a273831d1f63736d1596f81
- F src/sqlite.h.in 175065018323ca082092f92873e074647d00bec2
- F src/sqlite3_private.h 1d18557420cb0cc51ff31ec0a3fcce11e5cd6f5a
++F src/sqlite.h.in 9b74f2d71c15cc9e3f78c16474e2096a707ceba5
+ F src/sqlite3_private.h e3b586e0aa329075d99be7198df9bc80c5b19e2d
-F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
-F src/sqliteInt.h 2f4919d0105a821f04433a181f877c8a70201f9a
+F src/sqlite3ext.h 1a1a4f784aa9c3b00edd287940197de52487cd93
- F src/sqliteInt.h 751564e4eb28a49d4f53f7bd2a211a48115d01d7
++F src/sqliteInt.h e9a32825290cee916e3e0939c857a13801afc700
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
-F src/tclsqlite.c 5db825be61708b1a2b3f8f6e185e9b753829acef
-F src/test1.c 1ce078b76ff2876c32b6ae4d1bbf754f704c87cb
+F src/tclsqlite.c 3ef1dda2f1dc207c792eaadebf9d8adc44648581
- F src/test1.c 48759e7898dd7af7ae2b01de12045814583e15c6
++F src/test1.c 63a00ab722cc49025a6f675bcda39bed83663a48
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c c819d9f72168a035d545a5bdafe9b085b20df705
-F src/trigger.c c836a6caac16ba96611558922106858f6ca3d6bf
-F src/update.c 80d77311d91ebc06b27149e75701f1b3e9356622
+F src/trigger.c 1cfb80e2290ef66ea89cb4e821caae65a02c0d56
+F src/update.c 74a6cfb34e9732c1e2a86278b229913b4b51eeec
F src/utf.c c53eb7404b3eb5c1cbb5655c6a7a0e0ce6bd50f0
-F src/util.c 0f33bbbdfcc4a2d8cf20c3b2a16ffc3b57c58a70
+F src/util.c 06302ffd2b80408d4f6c7af71f7090e0cf8d8ff7
F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e
-F src/vdbe.c 80d511d7096918f4f6be6a63988a885c54dd1048
-F src/vdbe.h 5cf09e7ee8a3f7d93bc51f196a96550786afe7a1
-F src/vdbeInt.h ad84226cc0adcb1185c22b70696b235a1678bb45
-F src/vdbeapi.c 7f01db7d26758b2be316116f8325a0b9f0d8edd6
-F src/vdbeaux.c cfb5207d13d0bc3d2753bba67900c462b60ecb08
-F src/vdbeblob.c f024f0bf420f36b070143c32b15cc7287341ffd3
-F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
+F src/vdbe.c 26deb38f5bd32ebeb2cb60853a52f2bf33d71641
+F src/vdbe.h f0725ee997db869ecae5bb70a71612aabeca7755
+F src/vdbeInt.h 693d6ac6810298fc6b4c503cfbe3f99a240f40af
+F src/vdbeapi.c 335435e65443f38d3073b5043e80cbbb7090c2d9
- F src/vdbeaux.c 49be7a5ce6a1b7df9ef5791133c3e4e6ab2a1ffe
++F src/vdbeaux.c 669fe607968e058ef49f7ed7846efde4fece5848
+F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
+F src/vdbemem.c 5e6effb96dd53d233361cbfaa3f0a43b9af689e9
+F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
F src/vdbetrace.c 4b92fe7355f682368203d29b2be7125cbab85e79
F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582
- F src/wal.c 92c7c876b026d5e38fab3ce332e49266ffcf8b2b
+ F src/wal.c eea77c324942f7e31ce9c3a5e6e86c4a0424fa09
F src/wal.h e75d87752bd5df3dc4152ee2cb3b0dcd0b309e5e
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
-F src/where.c 55403ce19c506be6a321c7f129aff693d6103db5
-F test/8_3_names.test b93687beebd17f6ebf812405a6833bae5d1f4199
+F src/where.c b641d399cfd8588d0e20d9790d1582b663a732a8
+F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
-F test/all.test 51756962d522e474338e9b2ebb26e7364d4aa125
-F test/alter.test a3f570072b53d7c0fe463bab3f5affa8e113c487
-F test/alter2.test 75f731508f1bf27ba09a6075c66cd02216ba464b
-F test/alter3.test 8677e48d95536f7a6ed86a1a774744dadcc22b07
-F test/alter4.test 1e5dd6b951e9f65ca66422edff02e56df82dd403
+F test/all.test 52fc8dee494092031a556911d404ca30a749a30b
+F test/alter.test 5314fc01ef51ab8af0b8890725b710ed48d4806b
+F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
+F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
+F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
-F test/analyze.test c8cb89e8736336f1f0646c8123e6028a14c7b55e
+F test/analyze.test 68b43c1f9cd6ffc3bbb30d27a23712b38c413eca
F test/analyze2.test 8f2b1534d43f5547ce9a6b736c021d4192c75be3
F test/analyze3.test d61f55d8b472fc6e713160b1e577f7a68e63f38b
F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
-F tool/symbols.sh bc2a3709940d47c8ac8e0a1fdf17ec801f015a00
-F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576
+F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5
+F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-F tool/warnings.sh 347d974d143cf132f953b565fbc03026f19fcb4d
-P aef7945c423a8338374572eeda9444866c64569b
-R d7448c6862ea7b8b001f5bf968511903
-U adam
-Z 39deebc534cda2d5bd1c84327ddbee27
+F tool/warnings.sh b7fdb2cc525f5ef4fa43c80e771636dd3690f9d2
- P ffed86bf969b98d196ac50bb5e5faddecab4fc59 3e0da808d2f5b4d12046e05980ca04578f581177
- R fab0c6c716ebe505f8c308159e4b4eab
++P ade72b1874c7672ae8d62b9ebac8e4d63fee80cc db5b7b778c09c57501cb8266895a0ea4f2de7649
++R 492a1b6738940e27b5c3378a18dde5be
+U drh
- Z 7d1fe25483dc7359b7f468acf5aa09ab
++Z 7f2d52c0164fc6fa32a2a1d8b7959b0c
** the case where the source and destination databases have the
** same schema version.
*/
- if( rc==SQLITE_DONE
- && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
- ){
- int nDestTruncate;
-
- if( p->pDestDb ){
- sqlite3ResetInternalSchema(p->pDestDb, -1);
+ if( rc==SQLITE_DONE ){
+ rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
+ if( rc==SQLITE_OK ){
+ if( p->pDestDb ){
+ sqlite3ResetInternalSchema(p->pDestDb, -1);
+ }
+ if( destMode==PAGER_JOURNALMODE_WAL ){
+ rc = sqlite3BtreeSetVersion(p->pDest, 2);
+ }
+ }
+
+ if( destMode==PAGER_JOURNALMODE_WAL ){
+ /* This call cannot fail. The success of the BtreeUpdateMeta()
- ** method above indicates that a write transaction has been opened
- ** and page 1 is already dirty. Therefore this always succeeds.
- */
++ ** method above indicates that a write transaction has been opened
++ ** and page 1 is already dirty. Therefore this always succeeds.
++ */
+ TESTONLY(int rc2 =) sqlite3BtreeSetVersion(p->pDest, 2);
+ assert( rc2==SQLITE_OK );
}
-
- /* Set nDestTruncate to the final number of pages in the destination
- ** database. The complication here is that the destination page
- ** size may be different to the source page size.
- **
- ** If the source page size is smaller than the destination page size,
- ** round up. In this case the call to sqlite3OsTruncate() below will
- ** fix the size of the file. However it is important to call
- ** sqlite3PagerTruncateImage() here so that any pages in the
- ** destination file that lie beyond the nDestTruncate page mark are
- ** journalled by PagerCommitPhaseOne() before they are destroyed
- ** by the file truncation.
- */
- assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) );
- assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
- if( pgszSrc<pgszDest ){
- int ratio = pgszDest/pgszSrc;
- nDestTruncate = (nSrcPage+ratio-1)/ratio;
- if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
- nDestTruncate--;
- }
- }else{
- nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
- }
- sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
-
- if( pgszSrc<pgszDest ){
- /* If the source page-size is smaller than the destination page-size,
- ** two extra things may need to happen:
- **
- ** * The destination may need to be truncated, and
+ if( rc==SQLITE_OK ){
+ int nDestTruncate;
+ /* Set nDestTruncate to the final number of pages in the destination
+ ** database. The complication here is that the destination page
+ ** size may be different to the source page size.
**
- ** * Data stored on the pages immediately following the
- ** pending-byte page in the source database may need to be
- ** copied into the destination database.
+ ** If the source page size is smaller than the destination page size,
+ ** round up. In this case the call to sqlite3OsTruncate() below will
+ ** fix the size of the file. However it is important to call
+ ** sqlite3PagerTruncateImage() here so that any pages in the
+ ** destination file that lie beyond the nDestTruncate page mark are
+ ** journalled by PagerCommitPhaseOne() before they are destroyed
+ ** by the file truncation.
*/
- const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
- sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
- i64 iOff;
- i64 iEnd;
-
- assert( pFile );
- assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
- nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
- && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
- ));
-
- /* This call ensures that all data required to recreate the original
- ** database has been stored in the journal for pDestPager and the
- ** journal synced to disk. So at this point we may safely modify
- ** the database file in any way, knowing that if a power failure
- ** occurs, the original database will be reconstructed from the
- ** journal file. */
- rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
-
- /* Write the extra pages and truncate the database file as required. */
- iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
- for(
- iOff=PENDING_BYTE+pgszSrc;
- rc==SQLITE_OK && iOff<iEnd;
- iOff+=pgszSrc
- ){
- PgHdr *pSrcPg = 0;
- const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
- rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
- if( rc==SQLITE_OK ){
- u8 *zData = sqlite3PagerGetData(pSrcPg);
- rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
+ assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) );
+ assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
+ if( pgszSrc<pgszDest ){
+ int ratio = pgszDest/pgszSrc;
+ nDestTruncate = (nSrcPage+ratio-1)/ratio;
+ if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
+ nDestTruncate--;
}
- sqlite3PagerUnref(pSrcPg);
- }
- if( rc==SQLITE_OK ){
- rc = backupTruncateFile(pFile, iSize);
+ }else{
+ nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
}
+ sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
+
+ if( pgszSrc<pgszDest ){
+ /* If the source page-size is smaller than the destination page-size,
+ ** two extra things may need to happen:
+ **
+ ** * The destination may need to be truncated, and
+ **
+ ** * Data stored on the pages immediately following the
+ ** pending-byte page in the source database may need to be
+ ** copied into the destination database.
+ */
+ const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
+ sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
+ i64 iOff;
+ i64 iEnd;
+
+ assert( pFile );
+ assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
+ nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
+ && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
+ ));
+
+ /* This call ensures that all data required to recreate the original
+ ** database has been stored in the journal for pDestPager and the
+ ** journal synced to disk. So at this point we may safely modify
+ ** the database file in any way, knowing that if a power failure
+ ** occurs, the original database will be reconstructed from the
+ ** journal file. */
+ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
+
+ /* Write the extra pages and truncate the database file as required */
+ iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
+ for(
+ iOff=PENDING_BYTE+pgszSrc;
+ rc==SQLITE_OK && iOff<iEnd;
+ iOff+=pgszSrc
+ ){
+ PgHdr *pSrcPg = 0;
+ const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
+ rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
+ if( rc==SQLITE_OK ){
+ u8 *zData = sqlite3PagerGetData(pSrcPg);
+ rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
+ }
+ sqlite3PagerUnref(pSrcPg);
+ }
+ if( rc==SQLITE_OK ){
+ rc = backupTruncateFile(pFile, iSize);
+ }
- /* Sync the database file to disk. */
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerSync(pDestPager);
+ /* Sync the database file to disk. */
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSync(pDestPager);
+ }
+ }else{
+ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
+ }
+
+ /* Finish committing the transaction to the destination database. */
+ if( SQLITE_OK==rc
+ && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
+ ){
+ rc = SQLITE_DONE;
}
- }else{
- rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
- }
-
- /* Finish committing the transaction to the destination database. */
- if( SQLITE_OK==rc
- && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
- ){
- rc = SQLITE_DONE;
}
}
** Zero is returned if the call completes successfully, or -1 if a call
** to fcntl() fails. In this case, errno is set appropriately (by fcntl()).
*/
--static int unixFileLock(unixFile *pFile, struct flock *pLock){
- return _unixFileLock(pFile, pLock, 0);
-}
-
-static int unixFileLock2(unixFile *pFile, struct flock *pLock){
- return _unixFileLock(pFile, pLock, 10);
-}
-
-static int _unixFileLock(unixFile *pFile, struct flock *pLock, int retry) {
- int rc = 0;
++static int unixFileLock(unixFile *pFile, struct flock *pLock, int nRetry){
+ int rc;
unixInodeInfo *pInode = pFile->pInode;
assert( unixMutexHeld() );
assert( pInode!=0 );
pInode->bProcessLock = 1;
pInode->nLock++;
}else{
++ int i = 0;
++ do {
++ rc = osFcntl(pFile->h, F_SETLK, pLock);
++ if( rc && nRetry ){
++ usleep(100 * (++i));
++ }
++ }while( !rc && nRetry-- );
rc = 0;
}
}else{
){
lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
lock.l_start = PENDING_BYTE;
-- if( unixFileLock(pFile, &lock) ){
++ if( unixFileLock(pFile, &lock, 0) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
/* Now get the read-lock */
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
-- if( unixFileLock(pFile, &lock) ){
++ if( unixFileLock(pFile, &lock, 0) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
}
lock.l_start = PENDING_BYTE;
lock.l_len = 1L;
lock.l_type = F_UNLCK;
- if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
- if( unixFileLock2(pFile, &lock) && rc==SQLITE_OK ){
++ if( unixFileLock(pFile, &lock, 10) && rc==SQLITE_OK ){
/* This could happen with a network mount */
tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
lock.l_len = SHARED_SIZE;
}
-- if( unixFileLock(pFile, &lock) ){
++ if( unixFileLock(pFile, &lock, 0) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( rc!=SQLITE_BUSY ){
** 4: [RRRR.]
*/
if( eFileLock==SHARED_LOCK ){
++ int tErrno; /* Error code from system call errors */
#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
(void)handleNFSUnlock;
assert( handleNFSUnlock==0 );
#endif
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- int tErrno; /* Error code from system call errors */
if( handleNFSUnlock ){
- int tErrno; /* Error code from system call errors */
off_t divSize = SHARED_SIZE - 1;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = divSize;
- if( unixFileLock(pFile, &lock)==(-1) ){
- if( unixFileLock2(pFile, &lock)==(-1) ){
++ if( unixFileLock(pFile, &lock, 10)==(-1) ){
tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = divSize;
- if( unixFileLock(pFile, &lock)==(-1) ){
- if( unixFileLock2(pFile, &lock)==(-1) ){
++ if( unixFileLock(pFile, &lock, 10)==(-1) ){
tErrno = errno;
-#if OSLOCKING_CHECK_BUSY_IOERR
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
-#else
- rc = SQLITE_IOERR_UNLOCK;
-#endif
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST+divSize;
lock.l_len = SHARED_SIZE-divSize;
- if( unixFileLock(pFile, &lock)==(-1) ){
- if( unixFileLock2(pFile, &lock)==(-1) ){
++ if( unixFileLock(pFile, &lock, 10)==(-1) ){
tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
- if( unixFileLock(pFile, &lock) ){
- #if OSLOCKING_CHECK_BUSY_IOERR
- if( unixFileLock2(pFile, &lock) ){
++ if( unixFileLock(pFile, &lock, 10) ){
tErrno = errno;
+ #if OSLOCKING_CHECK_BUSY_IOERR
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
lock.l_whence = SEEK_SET;
lock.l_start = PENDING_BYTE;
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
- if( unixFileLock(pFile, &lock)==0 ){
- if( unixFileLock2(pFile, &lock)==0 ){
++ if( unixFileLock(pFile, &lock, 10)==0 ){
pInode->eFileLock = SHARED_LOCK;
}else{
#if OSLOCKING_CHECK_BUSY_IOERR
SimulateIOErrorBenign(1);
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
- if( unixFileLock(pFile, &lock)==0 ){
- if( unixFileLock2(pFile, &lock)==0 ){
++ if( unixFileLock(pFile, &lock, 10)==0 ){
pInode->eFileLock = NO_LOCK;
}else{
#if OSLOCKING_CHECK_BUSY_IOERR
#endif
static int isProxyLockingMode(unixFile *);
-static int unixTruncateDatabase(unixFile *, int);
+ #if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
-static int unixInvalidateSupportFiles(unixFile *, int);
++static int unixTruncateDatabase(unixFile *pFile, int bFlags) {
++ sqlite3_file *id = (sqlite3_file *)pFile;
++ int rc = SQLITE_OK;
++ 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( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
++ isCorrupt = 1;
++ rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock);
++ }
++ if( rc ){
++ return rc;
++ }
++ }
++ rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
++ if( rc==SQLITE_OK ){
++ unixInvalidateSupportFiles(pFile, 0);
++ }
++ pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
++
++
++ if( isCorrupt ){
++ sqlite3demo_superunlock_corrupt(id, corruptFileLock);
++ }else{
++ sqlite3demo_superunlock(pLock);
++ }
++ return rc;
++}
+
-
++static int unixInvalidateSupportFiles(unixFile *pFile, int skipWAL) {
++ char jPath[MAXPATHLEN+9];
++ int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
++ if( zLen<MAXPATHLEN ){
++ size_t jLen;
++ const char extensions[3][9] = { "-wal", "-journal", "-shm" };
++ int j = (skipWAL ? 1 : 0);
++ for( ; j<3; j++ ){
++
++ /* Check to see if the shm file is already opened for this pFile */
++ if( j==2 ){
++ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
++ unixShmNode *pShmNode = pFile->pInode->pShmNode;
++ if( pShmNode && !pShmNode->isReadonly ){
++ struct stat sStat;
++ sqlite3_mutex_enter(pShmNode->mutex);
++
++ if( pShmNode->h>=0 && !osFstat(pShmNode->h, &sStat) ){
++ unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4;
++ if( size>0 ){
++ bzero(pShmNode->apRegion[0], size);
++ sqlite3_mutex_leave(pShmNode->mutex);
++ unixLeaveMutex();
++ continue;
++ }
++ }
++ sqlite3_mutex_leave(pShmNode->mutex);
++ }
++ unixLeaveMutex();
++ }
++ jLen = strlcpy(&jPath[zLen], extensions[j], 9);
++ if( jLen < 9 ){
++ int jflags = (j<2) ? O_TRUNC : O_RDWR;
++ int jfd = open(jPath, jflags);
++ if( jfd==(-1) ){
++ if( errno!=ENOENT ){
++ perror(jPath);
++ }
++ } else {
++ if( j==2 ){
++ struct stat sStat;
++ if( !osFstat(jfd, &sStat) ){
++ unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4;
++ if( size>0 ){
++ uint32_t zero = 0;
++ pwrite(jfd, &zero, (size_t)size, 0);
++ }
++ }
++ }
++ fsync(jfd);
++ close(jfd);
++ }
++ }
++ }
++ }
++ return SQLITE_OK;
++}
+
+ static int unixReplaceDatabase(unixFile *pFile, sqlite3 *srcdb) {
+ sqlite3_file *id = (sqlite3_file *)pFile;
+ Btree *pSrcBtree = NULL;
+ 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 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( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
+ isDstCorrupt = 1;
+ rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptDstFileLock);
+ }
+ 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;
+ }
+ #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);
+ }
+ }
+ }
+ }
+ 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);
+ }
+ 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) ){
+ int err=errno;
+ switch(err) {
+ case ENOMEM:
+ rc = SQLITE_NOMEM;
+ break;
+ default:
+ pFile->lastErrno = err;
+ rc = SQLITE_IOERR;
+ }
+ }
+ copyfile_state_free(s);
+
+ if (srcChange == dstChange) {
+ /* modify the change counter to force page zero to be reloaded */
+ dstChange ++;
+ pwrite(pFile->h, &dstChange, 4, 24);
+ }
+ }
+ 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 ){
+ int skipWAL = (srcWalFD<0)?0:1;
+ unixInvalidateSupportFiles(pFile, skipWAL);
+ }
+
+ end_replace_database:
+ if( pSrcBtree ){
+ sqlite3_close(srcdb2);
+ sqlite3BtreeLeave(pSrcBtree);
+ }
+ sqlite3_mutex_leave(srcdb->mutex);
+ if( isDstCorrupt ){
+ sqlite3demo_superunlock_corrupt(id, corruptDstFileLock);
+ }else{
+ sqlite3demo_superunlock(pLock);
+ }
+ return rc;
+ }
-static int unixLockstatePid(unixFile *, pid_t, int *);
-
-#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
-
+ #define SQLITE_FILE_HEADER_LEN 16
+ #include "btreeInt.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 unixIsLocked(
+ 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;
+ }
+
-** Information and control of an open file handle.
+ /*
-static int unixFileControl(sqlite3_file *id, int op, void *pArg){
- unixFile *pFile = (unixFile*)id;
- switch( op ){
- case SQLITE_FCNTL_LOCKSTATE: {
- *(int*)pArg = pFile->eFileLock;
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_LAST_ERRNO: {
- *(int*)pArg = pFile->lastErrno;
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_CHUNK_SIZE: {
- pFile->szChunk = *(int *)pArg;
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_SIZE_HINT: {
- return fcntlSizeHint(pFile, *(i64 *)pArg);
- }
- case SQLITE_FCNTL_PERSIST_WAL: {
- int bPersist = *(int*)pArg;
- if( bPersist<0 ){
- *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
- }else if( bPersist==0 ){
- pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
- }else{
- pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
- }
- return SQLITE_OK;
- }
-#ifndef NDEBUG
- /* The pager calls this method to signal that it has done
- ** a rollback and that the database is therefore unchanged and
- ** it hence it is OK for the transaction change counter to be
- ** unchanged.
- */
- case SQLITE_FCNTL_DB_UNCHANGED: {
- ((unixFile*)id)->dbUpdate = 0;
- return SQLITE_OK;
- }
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- case SQLITE_FCNTL_SET_LOCKPROXYFILE:
- case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
- return proxyFileControl(id,op,pArg);
- }
-#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
-#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
- case SQLITE_FCNTL_TRUNCATE_DATABASE: {
- return unixTruncateDatabase(pFile, (pArg ? (*(int *)pArg) : 0));
- }
- case SQLITE_FCNTL_REPLACE_DATABASE: {
- return unixReplaceDatabase(pFile, (sqlite3 *)pArg);
- }
- case SQLITE_FCNTL_LOCKSTATE_PID: {
- LockstatePID *pLockstate;
- int rc;
-
- if( pArg==NULL ){
- return SQLITE_MISUSE;
- }
- pLockstate = (LockstatePID *)pArg;
- rc = unixLockstatePid(pFile, pLockstate->pid, &(pLockstate->state));
- return rc;
++** This test only works for lock testing on unix/posix VFS.
++** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
+ */
++static int unixLockstatePid(unixFile *pFile, pid_t pid, int *pLockstate){
++ int hDb; /* File descriptor for the open database file */
++ int hShm = -1; /* 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 */
++
++ assert(pLockstate);
++
++ /* make sure we are dealing with a database file */
++ hDb = pFile->h;
++ if( hDb<0 ){
++ *pLockstate = SQLITE_LOCKSTATE_ERROR;
++ return SQLITE_ERROR;
++ }
++ assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN );
++ got = pread(hDb, aHdr, 100, 0);
++ if( got<0 ){
++ *pLockstate = SQLITE_LOCKSTATE_ERROR;
++ return SQLITE_ERROR;
++ }
++ if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){
++ *pLockstate = SQLITE_LOCKSTATE_NOTADB;
++ return SQLITE_NOTADB;
++ }
++
++ /* First check for an exclusive lock */
++ nLock += unixIsLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE");
++ isWal = aHdr[18]==2;
++ if( nLock==0 && isWal==0 ){
++ /* Rollback mode */
++ nLock += unixIsLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED");
++ }
++ if( nLock==0 && isWal!=0 ){
++ /* lookup the file descriptor for the shared memory file if we have it open in this process */
++ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
++ unixShmNode *pShmNode = pFile->pInode->pShmNode;
++ if( pShmNode ){
++ sqlite3_mutex_enter(pShmNode->mutex);
++
++ hShm = pShmNode->h;
++ if( hShm >= 0){
++ if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
++ unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
++ nLock = 1;
++ }
++ }
++
++ sqlite3_mutex_leave(pShmNode->mutex);
++ }
++
++ if( hShm<0 ){
++ /* the shared memory file isn't open in this process space, open our own FD */
++ char zShm[MAXPATHLEN];
++
++ /* WAL mode */
++ strlcpy(zShm, pFile->zPath, MAXPATHLEN);
++ strlcat(zShm, "-shm", MAXPATHLEN);
++ hShm = open(zShm, O_RDONLY, 0);
++ if( hShm<0 ){
++ *pLockstate = SQLITE_LOCKSTATE_OFF;
++ unixLeaveMutex();
++ return SQLITE_OK;
++ }
++ if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
++ unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
++ nLock = 1;
++ }
++ close(hShm);
++ }
++ unixLeaveMutex();
++ }
++ if( nLock>0 ){
++ *pLockstate = SQLITE_LOCKSTATE_ON;
++ } else {
++ *pLockstate = SQLITE_LOCKSTATE_OFF;
++ }
++ return SQLITE_OK;
++}
++
++#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
++
++
+/*
+** Information and control of an open file handle.
+*/
+static int unixFileControl(sqlite3_file *id, int op, void *pArg){
+ unixFile *pFile = (unixFile*)id;
+ switch( op ){
+ case SQLITE_FCNTL_LOCKSTATE: {
+ *(int*)pArg = pFile->eFileLock;
+ return SQLITE_OK;
+ }
+ case SQLITE_LAST_ERRNO: {
+ *(int*)pArg = pFile->lastErrno;
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_CHUNK_SIZE: {
+ pFile->szChunk = *(int *)pArg;
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_SIZE_HINT: {
+ int rc;
+ SimulateIOErrorBenign(1);
+ rc = fcntlSizeHint(pFile, *(i64 *)pArg);
+ SimulateIOErrorBenign(0);
+ return rc;
+ }
+ case SQLITE_FCNTL_PERSIST_WAL: {
+ int bPersist = *(int*)pArg;
+ if( bPersist<0 ){
+ *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
+ }else if( bPersist==0 ){
+ pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
+ }else{
+ pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
+ }
+ return SQLITE_OK;
+ }
+#ifndef NDEBUG
+ /* The pager calls this method to signal that it has done
+ ** a rollback and that the database is therefore unchanged and
+ ** it hence it is OK for the transaction change counter to be
+ ** unchanged.
+ */
+ case SQLITE_FCNTL_DB_UNCHANGED: {
+ ((unixFile*)id)->dbUpdate = 0;
+ return SQLITE_OK;
}
- case SQLITE_SET_LOCKPROXYFILE:
- case SQLITE_GET_LOCKPROXYFILE: {
+#endif
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- case SQLITE_TRUNCATE_DATABASE: {
- unixFile *pFile = (unixFile*)id;
- int rc = SQLITE_OK;
- 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( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
- isCorrupt = 1;
- rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock);
- }
- if( rc ){
- return rc;
- }
- }
- rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
-
- 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);
- }
- }
- }
- }
- pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
- }
- if( isCorrupt ){
- sqlite3demo_superunlock_corrupt(id, corruptFileLock);
- }else{
- sqlite3demo_superunlock(pLock);
- }
- return rc;
++ case SQLITE_FCNTL_SET_LOCKPROXYFILE:
++ case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
+ return proxyFileControl(id,op,pArg);
+ }
+#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
+#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
- case SQLITE_REPLACE_DATABASE: {
- unixFile *pFile = (unixFile*)id;
- sqlite3 *srcdb = (sqlite3 *)pArg;
- Btree *pSrcBtree = NULL;
- 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) ){
++ case SQLITE_FCNTL_TRUNCATE_DATABASE: {
++ return unixTruncateDatabase(pFile, (pArg ? (*(int *)pArg) : 0));
+ }
++ case SQLITE_FCNTL_REPLACE_DATABASE: {
++ return unixReplaceDatabase(pFile, (sqlite3 *)pArg);
++ }
++ case SQLITE_FCNTL_LOCKSTATE_PID: {
++ LockstatePID *pLockstate;
++ int rc;
+
-
- #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( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
- isDstCorrupt = 1;
- rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptDstFileLock);
- }
- 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;
- }
- #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);
- }
- }
- }
- }
- 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);
- }
- 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) ){
- int err=errno;
- switch(err) {
- case ENOMEM:
- rc = SQLITE_NOMEM;
- break;
- default:
- pFile->lastErrno = err;
- rc = SQLITE_IOERR;
- }
- }
- copyfile_state_free(s);
-
- if (srcChange == dstChange) {
- /* modify the change counter to force page zero to be reloaded */
- dstChange ++;
- pwrite(pFile->h, &dstChange, 4, 24);
- }
- }
- 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);
- }
- }
- }
- }
- pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
- }
-
- end_replace_database:
- if( pSrcBtree ){
- sqlite3_close(srcdb2);
- sqlite3BtreeLeave(pSrcBtree);
- }
- sqlite3_mutex_leave(srcdb->mutex);
- if( isDstCorrupt ){
- sqlite3demo_superunlock_corrupt(id, corruptDstFileLock);
- }else{
- sqlite3demo_superunlock(pLock);
- }
++ if( pArg==NULL ){
+ return SQLITE_MISUSE;
+ }
++ pLockstate = (LockstatePID *)pArg;
++ rc = unixLockstatePid(pFile, pLockstate->pid, &(pLockstate->state));
+ return rc;
+ }
++
#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
case SQLITE_FCNTL_SYNC_OMITTED: {
return SQLITE_OK; /* A no-op */