]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Merge latest trunk changes, including support for handling of structured-exceptions...
authordan <Dan Kennedy>
Fri, 11 Aug 2023 19:38:35 +0000 (19:38 +0000)
committerdan <Dan Kennedy>
Fri, 11 Aug 2023 19:38:35 +0000 (19:38 +0000)
FossilOrigin-Name: cb3cf9bab0a75260c683454fb6c677f34b6c4b3555af2494678fd4811f586ac3

1  2 
manifest
manifest.uuid
src/pager.c
src/pager.h
src/sqlite.h.in
src/vdbeaux.c
src/wal.c
src/wal.h

diff --cc manifest
index a8f6418f2c5c8ed6af773c6871e861590a2733b9,151f12d02113e8cedda81969e93f865322d5f364..f9fd583dd7acacf221f13a6dd9b3355721fd4cd8
+++ b/manifest
@@@ -1,11 -1,11 +1,11 @@@
- C Fix\sa\sproblem\swith\shandling\ssavepoints\sin\sBEGIN\sCONCURRENT\stransactions.
- D 2023-08-11T18:25:26.941
 -C If\sSQLITE_USE_SEH\sis\sdefined,\shandle\sstructured-exceptions\sthrown\sby\sMSVC\sbuilds\sif\sthe\s*-shm\sfile\smapping\sis\saccessed\safter\sit\sbecomes\sinvalid\sfor\ssome\sreason.
 -D 2023-08-11T19:31:51.656
++C Merge\slatest\strunk\schanges,\sincluding\ssupport\sfor\shandling\sof\sstructured-exceptions\sin\sMSVC\sbuilds,\swith\sthis\sbranch.
++D 2023-08-11T19:38:35.227
  F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
  F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
  F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
 -F Makefile.in 5ad2d1e198306bc730f06f7545d3a8832225b1bfddbc648d97c0e0b9a35f67e9
 +F Makefile.in 85d32b973dc01fc0763ae2aea661a8b304364d319636071ab3485688e39d8989
  F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
- F Makefile.msc 7248d860f71ab164b4cec3c415e6cc1bd9fee860c370d65bd8bb49e9572521e2
+ F Makefile.msc daad4a19e0b3c3c3b79b64d4ddbf75e3f506405e8d3f3f604d6f48b26043c51f
  F README.md c1c4218efcc4071a6e26db2b517fdbc1035696a29b370edd655faddbef02b224
  F VERSION c6366dc72582d3144ce87b013cc35fe48d62f6d07d5be0c9716ea33c862144aa
  F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@@@ -492,11 -487,11 +492,11 @@@ F ext/session/test_session.c 8957ef4765
  F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
  F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
  F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
 -F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
 +F ext/wasm/EXPORTED_FUNCTIONS.fiddle 7fb73f7150ab79d83bb45a67d257553c905c78cd3d693101699243f36c5ae6c3
- F ext/wasm/GNUmakefile 50a4bd40ee01a90badfc28d0042789740e47e2855d3b9acaa8801b6dc2763aba
+ F ext/wasm/GNUmakefile 8159bc5f9433fe21022c1a8e8c30cb1a523530ba9ef53bdf5d1e0a2186554806
  F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
  F ext/wasm/README.md a8a2962c3aebdf8d2104a9102e336c5554e78fc6072746e5daf9c61514e7d193
 -F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api d6a5078f48a5301ed17b9a30331075d9b2506e1360c1f0dee0c7816c10acd9ab
 +F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api c5eaceabb9e759aaae7d3101a4a3e542f96ab2c99d89a80ce20ec18c23115f33
  F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
  F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
  F ext/wasm/api/README.md 5eb44fa02e9c693a1884a3692428647894b0380b24bca120866b7a24c8786134
@@@ -514,9 -509,9 +514,9 @@@ F ext/wasm/api/sqlite3-license-version-
  F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
  F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
  F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js abb69b5e008961026bf5ff433d7116cb046359af92a5daf73208af2e7ac80ae7
- F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e7a690e0e78ff4d563f2eca468f91db69f001ff4b79c6d2304cbb6f62dca437d
- F ext/wasm/api/sqlite3-wasm.c 8867f1d41c112fb4a2cfe22ff224eccaf309fcdea266cee0ec554f85db72ef0f
+ F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e04fc2fda6a0200ef80efdbb4ddfa0254453558adb17ec3a230f93d2bf1d711c
+ F ext/wasm/api/sqlite3-wasm.c d4d4c2b349b43b7b861e6d2994299630fb79e07573ea6b61e28e8071b7d16b61
 -F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f
 +F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js c5ac33e39f21a3481812d7333ca6e18853640d423a01960ca8dbc6e7c5c3c21c
  F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
  F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
  F ext/wasm/batch-runner.js 0dad6a02ad796f1003d3b7048947d275c4d6277f63767b8e685c27df8fdac93e
@@@ -632,28 -627,28 +632,28 @@@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b
  F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
  F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
  F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
 -F src/os_unix.c 2e8b12107f75d1bd16412f312b4c5d5103191807a37836d3b81beb26436ad81b
 +F src/os_unix.c 587a756c1244e1e2fc1c7ca8d77de891c13c177fbc3c5bfeee58f75445499baa
  F src/os_win.c 7038223a1cda0a47e2ab4db47f63bf1833fe53ba0542f0f283a062ea13894103
  F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
- F src/pager.c e2039b61af0fdb3e5c4a476b064d20a2c7a41eb86e41de1c03a8093fb28cbcaa
- F src/pager.h 7b2ec7bba30b21a97b68d5bdc0dbb82a75f48c4b1457180988f9d409fb789e16
 -F src/pager.c 993445a19b611d473ca007542ab3149840661a4c7e9f2d9e1ec008b7cc2abe78
 -F src/pager.h 6e326bd05970a24dd28d41d3980b6964fbaa37b4da54a2c0d4e0c5bdb06ff187
 -F src/parse.y aeb7760d41cfa86465e3adba506500c021597049fd55f82a30e5b7045862c28c
++F src/pager.c 356c794f7fd5f76318843287497e1711278f2a3174d736ade8397ff4c934d70a
++F src/pager.h b8aa8e36a9698e4833b2610503e290dcbf5aa70fc0a3842b36039f243dfff615
 +F src/parse.y 92a9cc670816e1274a107d02ed8efec6028c23713c767f035479fde411c86f27
  F src/pcache.c 4cd4a0043167da9ba7e19b4d179a0e6354e7fe32c16f781ecf9bf0a5ff63b40b
  F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
  F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
  F src/pragma.c 37b8fb02d090262280c86e1e2654bf59d8dbfbfe8dc6733f2b968a11374c095a
 -F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
 +F src/pragma.h 1f421360eed1a7721e8c521463df8519a7c8d0d5893ebd9dbfe0dba8de996f8c
  F src/prepare.c 80548297dc0e1fb3139cdebffb5a1bcac3dfac66d791012dd74838e70445072d
  F src/printf.c e3ba080e2f409f9bfcc8d34724e6fc160e9c718dc92d0548f6b71b8b6f860ce2
 -F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 +F src/random.c a3e70f8515721ff24d2c0e6afd83923e8faab5ab79ececea4c1bf9fe4049fbb2
  F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
  F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 -F src/select.c 5f545a2c8702d4d3430bbb188cfec47d6c122d899061ef00cbe56af14591c574
 +F src/select.c 996dda45d2a1a0228005849702348c7fd598437afa169c2c110f2c2ee582b382
  F src/shell.c.in 694aaf751f00610381533d4a31c83d142cfc83ef91ef65e2aa6912ace7c39b40
- F src/sqlite.h.in b17354ee013cb7fe7f3dd35a5efe6fa7aac282a5c1076b72c531396719aeb274
 -F src/sqlite.h.in 73a366c1c45d5ac9888cfe81c458826a44498531d106cfb4f328193ab5f6f17d
++F src/sqlite.h.in 866a39afb9215fb8b6a2b5ef7c64fbd90ff590afed863ade038ba79272fa428f
  F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
  F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
 -F src/sqliteInt.h 025ed58a41968ef80d64cdc194caa8dd207b0256b147253d762fdac7a62408f9
 +F src/sqliteInt.h e889cc24d80f126d25a89ae1c4aa4ec7d3ad38500c51bdc00627cd8016e51411
  F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
  F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
  F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@@ -713,16 -708,16 +713,16 @@@ F src/threads.c 4ae07fa022a3dc7c5beb373
  F src/tokenize.c 23d9f4539880b40226254ad9072f4ecf12eb1902e62aea47aac29928afafcfd5
  F src/treeview.c 1d52fbc4e97161e65858d36e3424ea6e3fc045dd8a679c82b4b9593dc30de3bd
  F src/trigger.c ad6ab9452715fa9a8075442e15196022275b414b9141b566af8cdb7a1605f2b0
 -F src/update.c 0bb9171afaa4d0b100ad946873bccda7aef90ffe083ef5c63668fce08c4df9da
 +F src/update.c 6c1c9ad9aba9554157ff01f9e43343478f0cae24b830b76ce659df772f46b9d7
  F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
  F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
- F src/util.c b3532a95ad56db67b3acd3955e688e4cb80ebec6fd1f459a8eb51cceedd6de69
+ F src/util.c a40062117e705eb3339201842717a022092816b92479eead6397cde28af32ff9
 -F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
 -F src/vdbe.c 346d848a0bf8128e3e3722c5406f4bde6c32d7093b93402c6f8e0718d19305c3
 +F src/vacuum.c b1dd6d73869229b6e08bac910ac011dc9da42e3120ec2b7241accc5a752bd419
 +F src/vdbe.c ed1b8487a88aba5d2880dfba514276cbe2107b5986910fc49f616e00b29d9441
  F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
  F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
  F src/vdbeapi.c f37822f215740ede2a8fcae99bc13f2cc3a72dd0e1d22b81b9298c5ca67dbc38
- F src/vdbeaux.c e4ff54897dca508b3c3726973a1cb08f09d81cbe13c0c36012d9c2572402327c
 -F src/vdbeaux.c e3aa5c46827cd95e0fc4d0f302fa3e901ab5f07258fdbb42709eeef40f63018d
++F src/vdbeaux.c 2c87c99975ac23e777e9c270d979eca38f2a021b1f14f061c83faab5b24d5576
  F src/vdbeblob.c 2516697b3ee8154eb8915f29466fb5d4f1ae39ee8b755ea909cefaf57ec5e2ce
  F src/vdbemem.c 317b9f48708139db6239ade40c7980b4bc8233168383690d588dad6d8437f722
  F src/vdbesort.c 0d40dca073c94e158ead752ef4225f4fee22dee84145e8c00ca2309afb489015
@@@ -730,8 -725,8 +730,8 @@@ F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1
  F src/vdbevtab.c 57fa8f56478e5b5cb558cb425e7878515e0a105c54f96f1d1bbf4b9433529254
  F src/vtab.c 1ecf8c3745d29275688d583e12822fa984d421e0286b5ef50c137bc3bf6d7a64
  F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
- F src/wal.c 5a1e2b889af681ff4707c4100dcda7b24ac0939fdb3e793c1109bad995ed6f94
- F src/wal.h 7ffe787437f20a098af347011967a6d3bb8e5c3dc645e6be59eff44d2b2c5297
 -F src/wal.c 02e10f033a6972bc7d50122b400318003199c504cda48f61ad404564505f4e89
 -F src/wal.h 04a9e53121d5076f2a173b0f2facb39d33047093fee71bd3bbe6b1f6f1f5fd4b
++F src/wal.c 403ccb4a7c7ecc7903926468063ec20b2ef4905ff2df64f0b7c6bc78454e21fc
++F src/wal.h bd964b88717cc604081d5496a076e8f0d10a40b3efccd8059a3d01815fc7a8ad
  F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
  F src/where.c b8917792f1e0dbfa28fb29e6cd3d560060d69667be0ba4c491cbc772363264f5
  F src/whereInt.h c7d19902863beadec1d04e66aca39c0bcd60b74f05f0eaa7422c7005dfc5d51a
@@@ -2067,8 -2051,8 +2068,8 @@@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a9
  F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
  F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
  F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P 7cb2b4e35ff901cd597e2bffbb50f25f0445beba0c994de775580876da74ed10
- R 12ceb5187842860667267b0a9c59254f
 -P 0d7aac45b8e7078cc80757e12d6f0b2584f2b0b184dacc2348ad3519978e5bf9 3ed89c344fcb3b7ee8b764d95144643e42e053e1116150d6eda8355fbd6669df
 -R 35781298e1f4461a1a53ad9bec2f5ba2
++P 4a5c0439ae3ce6c98cea26f7e96c5bce543e76b9ad2a3a275601d6e5060899c8 8a6b0c24937e855b710f97b4aea973eff53e6d43e1182842731547aa4b37db2a
++R 99cfcf873e3f4eea5a1d2e7a30e7020a
  U dan
- Z ec08def5a8e5821ae73191f46a5cfffb
 -Z d4c9bf3d3544cd45d448f96b6769914e
++Z 4b488e51ed86e4e34326a2fa271daeb2
  # Remove this line to create a well-formed Fossil manifest.
diff --cc manifest.uuid
index 0139577be5e3c9f9797c3393d1f7786a6d02767a,fc40b98c6e02bf62eeb5436abafdfe1ba80a1dd8..55bfe6f79c438e8eeb2c828719408d50dc3f799d
@@@ -1,1 -1,1 +1,1 @@@
- 4a5c0439ae3ce6c98cea26f7e96c5bce543e76b9ad2a3a275601d6e5060899c8
 -8a6b0c24937e855b710f97b4aea973eff53e6d43e1182842731547aa4b37db2a
++cb3cf9bab0a75260c683454fb6c677f34b6c4b3555af2494678fd4811f586ac3
diff --cc src/pager.c
Simple merge
diff --cc src/pager.h
Simple merge
diff --cc src/sqlite.h.in
Simple merge
diff --cc src/vdbeaux.c
index c97b6be4d182de32766c21ed11b173dca7faec52,225c8d12c93923f8d538eb8572e72e154920a6cf..fa4b6c0d9a4e701ca04a77af779e06ce84e3a305
@@@ -3386,10 -3368,11 +3386,11 @@@ int sqlite3VdbeHalt(Vdbe *p)
            ** is required. */
            rc = vdbeCommit(db, p);
          }
 -        if( rc==SQLITE_BUSY && p->readOnly ){
 +        if( (rc & 0xFF)==SQLITE_BUSY && p->readOnly ){
            sqlite3VdbeLeave(p);
 -          return SQLITE_BUSY;
 +          return rc;
          }else if( rc!=SQLITE_OK ){
+           sqlite3SystemError(db, rc);
            p->rc = rc;
            sqlite3RollbackAll(db, SQLITE_OK);
            p->nChange = 0;
diff --cc src/wal.c
index fbfb0f3253e90d6bcaef462b380c6f3110ba564c,c9d8eaebe53ed9329c8c5ce0aa03d243667bbdae..6e20e732a6bc03f2028beaeee448ca4e4461f684
+++ b/src/wal.c
@@@ -526,11 -526,15 +526,17 @@@ struct Wal 
    WalIndexHdr hdr;           /* Wal-index header for current transaction */
    u32 minFrame;              /* Ignore wal frames before this one */
    u32 iReCksum;              /* On commit, recalculate checksums from here */
 +  u32 nPriorFrame;           /* For sqlite3WalInfo() */
    const char *zWalName;      /* Name of WAL file */
    u32 nCkpt;                 /* Checkpoint sequence counter in the wal-header */
 +  FastPrng sPrng;            /* Random number generator */
+ #ifdef SQLITE_USE_SEH
+   u32 lockMask;              /* Mask of locks held */
+   void *pFree;               /* Pointer to sqlite3_free() if exception thrown */
+   int iSysErrno;             /* System error code following exception */
+ #endif
  #ifdef SQLITE_DEBUG
+   int nSehTry;               /* Number of nested SEH_TRY{} blocks */
    u8 lockError;              /* True if a locking error has occurred */
  #endif
  #ifdef SQLITE_ENABLE_SNAPSHOT
@@@ -3342,208 -3567,39 +3609,213 @@@ int sqlite3WalBeginWriteTransaction(Wa
      return SQLITE_OK;
    }
  #endif
-     if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
 +  
 +  rc = walWriteLock(pWal);
 +  if( rc==SQLITE_OK ){
 +    /* If another connection has written to the database file since the
 +    ** time the read transaction on this connection was started, then
 +    ** the write is disallowed. Release the WRITER lock and return
 +    ** SQLITE_BUSY_SNAPSHOT in this case.  */
-       rc = SQLITE_BUSY_SNAPSHOT;
++    SEH_TRY {
++      if( memcmp(&pWal->hdr, (void*)walIndexHdr(pWal),sizeof(WalIndexHdr))!=0 ){
++        rc = SQLITE_BUSY_SNAPSHOT;
++      }
++    }
++    SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
++    if( rc!=SQLITE_OK ){
 +      walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
 +      pWal->writeLock = 0;
 +    }
 +  }
 +  return rc;
 +}
  
 -  /* Cannot start a write transaction without first holding a read
 -  ** transaction. */
 -  assert( pWal->readLock>=0 );
 -  assert( pWal->writeLock==0 && pWal->iReCksum==0 );
 +/*
 +** This function is called by a writer that has a read-lock on aReadmark[0]
 +** (pWal->readLock==0). This function relinquishes that lock and takes a
 +** lock on a different aReadmark[] slot. 
 +**
 +** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
 +*/
 +static int walUpgradeReadlock(Wal *pWal){
 +  int cnt;
 +  int rc;
 +  assert( pWal->writeLock && pWal->readLock==0 );
 +  walUnlockShared(pWal, WAL_READ_LOCK(0));
 +  pWal->readLock = -1;
 +  cnt = 0;
 +  do{
 +    int notUsed;
 +    rc = walTryBeginRead(pWal, &notUsed, 1, ++cnt);
 +  }while( rc==WAL_RETRY );
 +  assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
 +  testcase( (rc&0xff)==SQLITE_IOERR );
 +  testcase( rc==SQLITE_PROTOCOL );
 +  testcase( rc==SQLITE_OK );
 +  return rc;
 +}
  
 -  if( pWal->readOnly ){
 -    return SQLITE_READONLY;
 -  }
  
 -  /* Only one writer allowed at a time.  Get the write lock.  Return
 -  ** SQLITE_BUSY if unable.
 -  */
 -  rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
 -  if( rc ){
 -    return rc;
 -  }
 -  pWal->writeLock = 1;
 +#ifndef SQLITE_OMIT_CONCURRENT
 +/* 
 +** This function is only ever called when committing a "BEGIN CONCURRENT"
 +** transaction. It may be assumed that no frames have been written to
 +** the wal file. The second parameter is a pointer to the in-memory 
 +** representation of page 1 of the database (which may or may not be
 +** dirty). The third is a bitvec with a bit set for each page in the
 +** database file that was read by the current concurrent transaction.
 +**
 +** This function performs three tasks:
 +**
 +**   1) It obtains the WRITER lock on the wal file,
 +**
 +**   2) It checks that there are no conflicts between the current
 +**      transaction and any transactions committed to the wal file since
 +**      it was opened, and
 +**
 +**   3) It ejects any non-dirty pages from the page-cache that have been
 +**      written by another client since the CONCURRENT transaction was started
 +**      (so as to avoid ending up with an inconsistent cache after the
 +**      current transaction is committed).
 +**
 +** If no error occurs and the caller may proceed with committing the 
 +** transaction, SQLITE_OK is returned. SQLITE_BUSY is returned if the WRITER
 +** lock cannot be obtained. Or, if the WRITER lock can be obtained but there
 +** are conflicts with a committed transaction, SQLITE_BUSY_SNAPSHOT. Finally,
 +** if an error (i.e. an OOM condition or IO error), an SQLite error code
 +** is returned.
 +*/
 +int sqlite3WalLockForCommit(
 +  Wal *pWal, 
 +  PgHdr *pPg1, 
 +  Bitvec *pAllRead, 
 +  Pgno *piConflict
 +){
 +  int rc = walWriteLock(pWal);
  
 -  /* If another connection has written to the database file since the
 -  ** time the read transaction on this connection was started, then
 -  ** the write is disallowed.
 +  /* If the database has been modified since this transaction was started,
 +  ** check if it is still possible to commit. The transaction can be 
 +  ** committed if:
 +  **
 +  **   a) None of the pages in pList have been modified since the 
 +  **      transaction opened, and
 +  **
 +  **   b) The database schema cookie has not been modified since the
 +  **      transaction was started.
    */
 -  SEH_TRY {
 -    if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
 +  if( rc==SQLITE_OK ){
 +    WalIndexHdr head;
 +
 +    if( walIndexLoadHdr(pWal, &head) ){
 +      /* This branch is taken if the wal-index header is corrupted. This 
 +      ** occurs if some other writer has crashed while committing a 
 +      ** transaction to this database since the current concurrent transaction
 +      ** was opened.  */
        rc = SQLITE_BUSY_SNAPSHOT;
 +    }else if( memcmp(&pWal->hdr, (void*)&head, sizeof(WalIndexHdr))!=0 ){
 +      int iHash;
 +      int iLast = walFramePage(head.mxFrame);
 +      u32 iFirst = pWal->hdr.mxFrame+1;     /* First wal frame to check */
 +      if( memcmp(pWal->hdr.aSalt, (u32*)head.aSalt, sizeof(u32)*2) ){
 +        assert( pWal->readLock==0 );
 +        iFirst = 1;
 +      }
 +      if( pPg1==0 ){
 +        /* If pPg1==0, then the current transaction modified the database
 +        ** schema. This means it conflicts with all other transactions. */
 +        *piConflict = 1;
 +        rc = SQLITE_BUSY_SNAPSHOT;
 +      }
 +      for(iHash=walFramePage(iFirst); rc==SQLITE_OK && iHash<=iLast; iHash++){
 +        WalHashLoc sLoc;
 +
 +        rc = walHashGet(pWal, iHash, &sLoc);
 +        if( rc==SQLITE_OK ){
 +          u32 i, iMin, iMax;
 +          assert( head.mxFrame>=sLoc.iZero );
 +          iMin = (sLoc.iZero >= iFirst) ? 1 : (iFirst - sLoc.iZero);
 +          iMax = (iHash==0) ? HASHTABLE_NPAGE_ONE : HASHTABLE_NPAGE;
 +          if( iMax>(head.mxFrame-sLoc.iZero) ) iMax = (head.mxFrame-sLoc.iZero);
 +          for(i=iMin; rc==SQLITE_OK && i<=iMax; i++){
 +            PgHdr *pPg;
 +            if( sLoc.aPgno[i-1]==1 ){
 +              /* Check that the schema cookie has not been modified. If
 +              ** it has not, the commit can proceed. */
 +              u8 aNew[4];
 +              u8 *aOld = &((u8*)pPg1->pData)[40];
 +              int sz;
 +              i64 iOffset;
 +              sz = pWal->hdr.szPage;
 +              sz = (sz&0xfe00) + ((sz&0x0001)<<16);
 +              iOffset = walFrameOffset(i+sLoc.iZero, sz) + WAL_FRAME_HDRSIZE+40;
 +              rc = sqlite3OsRead(pWal->pWalFd, aNew, sizeof(aNew), iOffset);
 +              if( rc==SQLITE_OK && memcmp(aOld, aNew, sizeof(aNew)) ){
 +                rc = SQLITE_BUSY_SNAPSHOT;
 +              }
 +            }else if( sqlite3BitvecTestNotNull(pAllRead, sLoc.aPgno[i-1]) ){
 +              *piConflict = sLoc.aPgno[i-1];
 +              rc = SQLITE_BUSY_SNAPSHOT;
 +            }else
 +            if( (pPg = sqlite3PagerLookup(pPg1->pPager, sLoc.aPgno[i-1])) ){
 +              /* Page aPgno[i-1], which is present in the pager cache, has been
 +              ** modified since the current CONCURRENT transaction was started.
 +              ** However it was not read by the current transaction, so is not
 +              ** a conflict. There are two possibilities: (a) the page was
 +              ** allocated at the of the file by the current transaction or 
 +              ** (b) was present in the cache at the start of the transaction.
 +              **
 +              ** For case (a), do nothing. This page will be moved within the
 +              ** database file by the commit code to avoid the conflict. The
 +              ** call to PagerUnref() is to release the reference grabbed by
 +              ** the sqlite3PagerLookup() above.  
 +              **
 +              ** In case (b), drop the page from the cache - otherwise
 +              ** following the snapshot upgrade the cache would be inconsistent
 +              ** with the database as stored on disk. */
 +              if( sqlite3PagerIswriteable(pPg) ){
 +                sqlite3PagerUnref(pPg);
 +              }else{
 +                sqlite3PcacheDrop(pPg);
 +              }
 +            }
 +          }
 +        }
 +      }
      }
    }
 -  SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
  
 -  if( rc!=SQLITE_OK ){
 -    walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
 -    pWal->writeLock = 0;
 +  pWal->nPriorFrame = pWal->hdr.mxFrame;
 +  return rc;
 +}
 +
 +/* !defined(SQLITE_OMIT_CONCURRENT)
 +**
 +** This function is called as part of committing an CONCURRENT transaction.
 +** It is assumed that sqlite3WalLockForCommit() has already been successfully
 +** called and so (a) the WRITER lock is held and (b) it is known that the
 +** wal-index-header stored in shared memory is not corrupt.
 +**
 +** Before returning, this function upgrades the client so that it is 
 +** operating on the database snapshot currently at the head of the wal file
 +** (even if the CONCURRENT transaction ran against an older snapshot).
 +**
 +** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
 +*/
 +int sqlite3WalUpgradeSnapshot(Wal *pWal){
 +  int rc = SQLITE_OK;
 +  assert( pWal->writeLock );
 +
 +  assert( pWal->szPage==pWal->hdr.szPage );
 +  memcpy(&pWal->hdr, (void*)walIndexHdr(pWal), sizeof(WalIndexHdr));
 +  assert( pWal->szPage==pWal->hdr.szPage || pWal->szPage==0 );
 +  pWal->szPage = pWal->hdr.szPage;
 +
 +  /* If this client has its read-lock on slot aReadmark[0] and the entire
 +  ** wal has not been checkpointed, switch it to a different slot. Otherwise
 +  ** any reads performed between now and committing the transaction will
 +  ** read from the old snapshot - not the one just upgraded to.  */
 +  if( pWal->readLock==0 && pWal->hdr.mxFrame!=walCkptInfo(pWal)->nBackfill ){
 +    rc = walUpgradeReadlock(pWal);
    }
    return rc;
  }
@@@ -3586,37 -3636,33 +3858,39 @@@ int sqlite3WalUndo
      Pgno iMax = pWal->hdr.mxFrame;
      Pgno iFrame;
  
-     memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
 +    /* Restore the clients cache of the wal-index header to the state it
 +    ** was in before the client began writing to the database.
 +    */
 -      /* Restore the clients cache of the wal-index header to the state it
 -      ** was in before the client began writing to the database. 
 -      */
+     SEH_TRY {
-     if( bConcurrent ){
-       pWal->hdr.aCksum[0]++;
-     }
+       memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
 +#ifndef SQLITE_OMIT_CONCURRENT
-     UNUSED_PARAMETER(bConcurrent);
++      if( bConcurrent ){
++        pWal->hdr.aCksum[0]++;
++      }
 +#else
-     for(iFrame=pWal->hdr.mxFrame+1;
-         ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
-         iFrame++
-     ){
-       /* This call cannot fail. Unless the page for which the page number
-       ** is passed as the second argument is (a) in the cache and
-       ** (b) has an outstanding reference, then xUndo is either a no-op
-       ** (if (a) is false) or simply expels the page from the cache (if (b)
-       ** is false).
-       **
-       ** If the upper layer is doing a rollback, it is guaranteed that there
-       ** are no outstanding references to any page other than page 1. And
-       ** page 1 is never written to the log until the transaction is
-       ** committed. As a result, the call to xUndo may not fail.
-       */
-       assert( walFramePgno(pWal, iFrame)!=1 );
-       rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
-     }
-     if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
++      UNUSED_PARAMETER(bConcurrent);
 +#endif
 -      for(iFrame=pWal->hdr.mxFrame+1; 
 -          ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; 
+   
 -    }
 -    SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
++      for(iFrame=pWal->hdr.mxFrame+1;
++          ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
+           iFrame++
+       ){
+         /* This call cannot fail. Unless the page for which the page number
+         ** is passed as the second argument is (a) in the cache and
+         ** (b) has an outstanding reference, then xUndo is either a no-op
+         ** (if (a) is false) or simply expels the page from the cache (if (b)
+         ** is false).
+         **
+         ** If the upper layer is doing a rollback, it is guaranteed that there
+         ** are no outstanding references to any page other than page 1. And
+         ** page 1 is never written to the log until the transaction is
+         ** committed. As a result, the call to xUndo may not fail.
+         */
+         assert( walFramePgno(pWal, iFrame)!=1 );
+         rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+       }
+       if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
++    } SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
    }
    return rc;
  }
@@@ -4149,29 -4222,33 +4449,33 @@@ int sqlite3WalCheckpoint
  
  
    /* Read the wal-index header. */
-   if( rc==SQLITE_OK ){
-     walDisableBlocking(pWal);
-     rc = walIndexReadHdr(pWal, &isChanged);
-     (void)walEnableBlocking(pWal);
-     if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
-       sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
-     }
-   }
-   /* Copy data from the log to the database file. */
-   if( rc==SQLITE_OK ){
-     if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
-       rc = SQLITE_CORRUPT_BKPT;
-     }else{
-       rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
+   SEH_TRY {
+     if( rc==SQLITE_OK ){
+       walDisableBlocking(pWal);
+       rc = walIndexReadHdr(pWal, &isChanged);
+       (void)walEnableBlocking(pWal);
+       if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
+         sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+       }
      }
-     /* If no error occurred, set the output variables. */
-     if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
-       if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
-       if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+   
+     /* Copy data from the log to the database file. */
+     if( rc==SQLITE_OK ){
+       if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
+         rc = SQLITE_CORRUPT_BKPT;
+       }else{
 -        rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf);
++        rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
+       }
 -
++  
+       /* If no error occurred, set the output variables. */
+       if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
+         if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
 -        SEH_INJECT_FAULT;
++        SEH_INJECT_FAULT
+         if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+       }
      }
    }
+   SEH_EXCEPT( rc = walHandleException(pWal); )
  
    if( isChanged ){
      /* If a new wal-index header was loaded before the checkpoint was
diff --cc src/wal.h
index 3f0e2d8d27337ecca62441da3773d70afdfcac58,d39bb50f3decf308eb5b691d64efb97ac53aeb7b..42a71f69c2aab265aed9d42ca32b3ca664f0cb79
+++ b/src/wal.h
@@@ -160,8 -151,9 +160,12 @@@ int sqlite3WalWriteLock(Wal *pWal, int 
  void sqlite3WalDb(Wal *pWal, sqlite3 *db);
  #endif
  
+ #ifdef SQLITE_USE_SEH
+ int sqlite3WalSystemErrno(Wal*);
+ #endif
 +/* sqlite3_wal_info() data */
 +int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame);
 +
  #endif /* ifndef SQLITE_OMIT_WAL */
  #endif /* SQLITE_WAL_H */