]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Merge latest trunk changes into this branch.
authordan <Dan Kennedy>
Sat, 13 Jan 2024 19:57:37 +0000 (19:57 +0000)
committerdan <Dan Kennedy>
Sat, 13 Jan 2024 19:57:37 +0000 (19:57 +0000)
FossilOrigin-Name: 95bf4bc2e2cc1e7489d82c68deb68feefbdc34fec1baeb9bb8a92ff1063b806c

1  2 
ext/session/sqlite3session.c
manifest
manifest.uuid
src/build.c
src/os_unix.c
src/wal.c

Simple merge
diff --cc manifest
index 7245d8680da60ea6c58c4e02af48e5c26dcb669c,8c862e2c0c122ad920de679bd5770d394d88bffe..80beb431238b0252a83bcda4d9f82c9f49363ba4
+++ b/manifest
@@@ -1,5 -1,5 +1,5 @@@
- C Merge\sthe\slatest\strunk\senhancements\sinto\sthe\sbegin-concurrent\sbranch.
- D 2024-01-04T15:49:36.249
 -C Have\sthe\sshell\stool\sautomatically\senable\sSQLITE_CONFIG_DQS_DDL\swhen\sexecuting\sa\s".dump"\sscript\sagainst\san\sempty\sdb.
 -D 2024-01-12T11:44:49.861
++C Merge\slatest\strunk\schanges\sinto\sthis\sbranch.
++D 2024-01-13T19:57:37.125
  F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
  F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
  F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@@ -571,11 -568,9 +571,11 @@@ F ext/session/sessionrowid.test 85187c2
  F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
  F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c
  F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
 -F ext/session/sqlite3session.c 829d468f0f3d2710aace56b0116a7ca3f414683ce78e3125ae5e21547a895078
 -F ext/session/sqlite3session.h 4cf19a51975746d7cff2fdd74db8b769c570958e1c3639ac150d824ac1553b3e
 -F ext/session/test_session.c 7b94ad945cd4afe6c73ee935aeb3d44b4446186e1729362af616c7695a5283d9
 +F ext/session/sqlite3changebatch.c d5553b79e012ee2cb06c0a96bdf9dfe19e66354390ea0036cc46c4953142d517
 +F ext/session/sqlite3changebatch.h e72016998c9a22d439ddfd547b69e1ebac810c24
- F ext/session/sqlite3session.c 31324bff026b63daa0c34d0eeb1f0e3ab3aa8d2a5a5efb47d6692c0adb2109cb
++F ext/session/sqlite3session.c 828dbecef4e67034a57c300dc126099eb82249eb27ef66dd6999e2fe1f79c547
 +F ext/session/sqlite3session.h 388d34fea3db95a951b838bf6f16e068d15f5312aa174fe0db6aa03ec0c0c319
 +F ext/session/test_session.c dec29dc72cbf8e4d637bdbc7bd717aa01d2bc173b1874ea73b0ceed06e067627
  F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
  F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
  F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
@@@ -679,12 -674,12 +679,12 @@@ F src/analyze.c 0f15753308c3bca7674f31f
  F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39
  F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4
  F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
 -F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
 +F src/bitvec.c 501daeef838fa82a9fb53540d72f29e3d9172c8867f1e19f94f681e2e20b966e
  F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
 -F src/btree.c dee25e097b749275333b55d64a5ffc079249576f8e88a2ee476468cf67510f4b
 -F src/btree.h 03e3356f5208bcab8eed4e094240fdac4a7f9f5ddf5e91045ce589f67d47c240
 -F src/btreeInt.h 3e2589726c4f105e653461814f65857465da68be1fac688de340c43b873f4062
 -F src/build.c e7d9044592eeeea8e78d8ae53ca8d31fd6e92ca0d4f53e2f2e8ccf7352e0b04b
 +F src/btree.c 6a4a14ab7e1fa00ee08234c749aaef78eeb7baff2806f9f7c0352f83ad10dea2
 +F src/btree.h d906e4d53f483c83d471d99479fa73fcdf20696305d578876f46ee283f3507cb
 +F src/btreeInt.h 57551d7c9830dd7f2d2b3fb73e6ec90aefd98a18b15e565c86ff1a9bb1639273
- F src/build.c 84d8550552b0f1bde347083e63bba3f994bf181e14a8edbf5443c7c0f6676a89
++F src/build.c 9c04ebb789ae19a7d94cd0a1ba8dcea041c2cd0d88157a2cd9cd8ecf40d3bf7f
  F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
  F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
  F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
@@@ -726,28 -721,28 +726,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 d561c469f79f3e30a15cbae7eef0c74d7e6f9c577ab55278d4bbbafe92167f2f
 -F src/os_unix.c 5dc41030cd5dfd99b907976b1725a4ed695566405d33744e4824c3d6aff245a3
++F src/os_unix.c cf1b18d384c4a5bec74d3bcabd261da57a80473f56545a0b6456389c18865b4e
  F src/os_win.c 4a50a154aeebc66a1f8fb79c1ff6dd5fe3d005556533361e0d460d41cb6a45a8
  F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
 -F src/pager.c ff60e98138d2499082ac6230f01ac508aba545315debccfca2fd6042f5f10fcd
 -F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
 -F src/parse.y 020d80386eb216ec9520549106353c517d2bbc89be28752ffdca649a9eaf56ec
 +F src/pager.c 267f4ec1bc93559e7789c43cd3fa9ad0df8de6b609ec90dc74919d573e6bc7bb
 +F src/pager.h af722ebe5d7c34ce7c94237323578385e3822fcf94fde3e7824b73a2efa0081f
 +F src/parse.y e583113148bb13280de7faab4f213fa183d9e6498483d5eee02f9578a07b9cd4
  F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
  F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
  F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
  F src/pragma.c b5b4cff830575e6188cd56a295a57448d2b9dbc53f0dae58e22b97354cda3781
 -F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
 +F src/pragma.h 6ebbdee90ed56a892d2c728e27fd9c1ce48c8a28841888d0c6c147946b38cb25
  F src/prepare.c 371f6115cb69286ebc12c6f2d7511279c2e47d9f54f475d46a554d687a3b312c
  F src/printf.c 18fbdf028345c8fbe6044f5f5bfda5a10d48d6287afef088cc21b0ca57985640
 -F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 +F src/random.c a3e70f8515721ff24d2c0e6afd83923e8faab5ab79ececea4c1bf9fe4049fbb2
  F src/resolve.c e25f51a473a5f30a0d978e4df2aaa98aeec84eac29ecae1ad4708a6c3e669345
  F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 -F src/select.c f1a81ff4f8e9e76c224e2ab3a4baa799add0db22158c7fcede65d8cc4a6fa2da
 +F src/select.c c581265a87628e1abcff72df3e96b56d89e8137ddb780d2522863cce08cf43cd
- F src/shell.c.in 85f8d52fa4f7773823736dd39d0a268fd739207fcae95883c9ec8ce4af59f7df
+ F src/shell.c.in d1ed426aae2d547932971e8019939cacb4dfda8258e45b8924b250e488e2d53d
 -F src/sqlite.h.in 61a60b4ea04db8ead15e1579b20b64cb56e9f55d52c5f9f9694de630110593a3
 +F src/sqlite.h.in 85ea6e5d174322193ac726dd6880bb1e17f58a3100451360b951d362fd776906
  F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
  F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
 -F src/sqliteInt.h 73800d73e21180e6b3df8d0fe7d11758dc24367fd2b0b0075b48fc116de406bb
 +F src/sqliteInt.h 70e19aaaaf1d7f8a2cf46ff0281d30938487dd0c6526c51b5d325a9450ee69e2
  F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
  F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
  F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@@ -824,8 -819,8 +824,8 @@@ F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1
  F src/vdbevtab.c 2143db7db0ceed69b21422581f434baffc507a08d831565193a7a02882a1b6a7
  F src/vtab.c 11948e105f56e84099ca17f1f434b1944539ea84de26d0d767eadfbc670ce1ea
  F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
- F src/wal.c ba4d1d6c70aba0cb3967637b17f70ef997ca56f947f355c308198181937c60d7
 -F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
 -F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
++F src/wal.c 7a63ccb09c364d941bee07c9e6f0d7f081679d6d21331e0b7fef2e7493a3e16e
 +F src/wal.h e9aeb67102d9b9a0b089b80bd6136a16dd6360ac3daa731f2b71c6d4f8341717
  F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
  F src/where.c 217fe82a26c0fb6a3c7fd01865d821e752f9c01fb72f114af3f0b77ce234d1fb
  F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8
@@@ -1346,11 -1330,11 +1346,11 @@@ F test/journal3.test 7c3cf23ffc77db0660
  F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9e1946
  F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
  F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
- F test/json/README.md 63e3e589e1df8fd3cc1588ba1faaff659214003f8b77a15af5c6452b35e30ee2
+ F test/json/README.md de59d5ba0bd2796d797115688630a6405bbf43a2891bad445ac6b9f38b83f236
  F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f
- F test/json/json-q1-b.txt 1e180fe6491efab307e318b22879e3a736ac9a96539bbde7911a13ee5b33abc7
  F test/json/json-q1.txt 65f9d1cdcc4cffa9823fb73ed936aae5658700cd001fde448f68bfb91c807307
- F test/json/json-speed-check.sh b060a9a6c696c0a807d8929400fa11bd7113edc58b0d66b9795f424f8d0db326 x
+ F test/json/json-speed-check.sh 912ee03e700a65c827ee0c7b4752c21ec5ef69cf7679d2f482ca817042bead52 x
 -F test/json/jsonb-q1.txt 1e180fe6491efab307e318b22879e3a736ac9a96539bbde7911a13ee5b33abc7
++F test/json/jsonb-q1.txt 1e180fe6491efab307e318b22879e3a736ac9a96539bbde7911a13ee5b33abc7 w test/json/json-q1-b.txt
  F test/json101.test 70587d7d35ef9e2126364ba70f0c951f70827cfbd28649d779ff3df7e8f87547
  F test/json102.test 557a46e16df1aa9bdbc4076a71a45814ea0e7503d6621d87d42a8c04cbc2b0ef
  F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
@@@ -2173,8 -2157,8 +2174,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 b3a2adfda722b025f43a105300e1c9860e7586eee5a77f548c4581a7be49518b fe952c12903ea2150880c8bb57cda2efc00ce9fa801568a68c619e0745f30567
- R 948ea8d0bec9d59c8057bff565beba24
- U drh
- Z b6a1f627dd96c3c96e08ccf44f295349
 -P b0eb6d3628c1f70399a22d9fd3b79a796bc343adfeba50515440db609565961a
 -R ab5a4296dc153e787688d4ab18626d94
++P c407d3bb9979933d7f5418ac2baa238b1f13c1aa769bf452c5c33088fdb1e959 f47a5f4e0ce078e6cc1183e6cbb3c4013af379b496efae94863a42e5c39928ed
++R fe5d97e053c47e908fb628066364d0e3
+ U dan
 -Z 9795dc3f51dc5999429a02089c48c9c6
++Z 5ed26b44c3c06bbcd8306ad8e3790a13
  # Remove this line to create a well-formed Fossil manifest.
diff --cc manifest.uuid
index b3474941a801d4c12bdcb0049ced94de5c6602f2,eaba41901e075c611fa0570555061f14110b5569..ba5c50250976b812dbc4e2843617e6f479a38541
@@@ -1,1 -1,1 +1,1 @@@
- c407d3bb9979933d7f5418ac2baa238b1f13c1aa769bf452c5c33088fdb1e959
 -f47a5f4e0ce078e6cc1183e6cbb3c4013af379b496efae94863a42e5c39928ed
++95bf4bc2e2cc1e7489d82c68deb68feefbdc34fec1baeb9bb8a92ff1063b806c
diff --cc src/build.c
Simple merge
diff --cc src/os_unix.c
Simple merge
diff --cc src/wal.c
index 2ccb3b0fcacce59c27d18a3fa80b18c92f32c120,fd2eabfd963c6b07ace6d9a6fde8824a26e36d4e..cd7d7d54c3c42c575d56639e97c066cd62c95980
+++ b/src/wal.c
@@@ -3659,200 -3665,40 +3707,200 @@@ int sqlite3WalBeginWriteTransaction(Wa
      return SQLITE_OK;
    }
  #endif
 +  
 +  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.  */
 +    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);
++    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 does the work of sqlite3WalLockForCommit(). The difference
 +** between this function and sqlite3WalLockForCommit() is that the latter
 +** encloses everything in a SEH_TRY {} block.
 +*/
 +static int walLockForCommit(
 +  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;
 +}
 +
 +/* 
 +** 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 = SQLITE_OK;
 +  SEH_TRY {
 +    rc = walLockForCommit(pWal, pPg1, pAllRead, piConflict);
 +  } SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
    return rc;
  }