From c94f97fac731c330f510d1cf4d0056aac6755c86 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 10 Feb 2026 18:28:41 +0000 Subject: [PATCH 001/197] Minor tweaks to the star-query optimization in the query planner. FossilOrigin-Name: 5021e114b251467fee6a39749c88ec581ee1f7d50093b02a44dc300db0c0a1c5 --- manifest | 12 +++++----- manifest.uuid | 2 +- src/where.c | 63 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/manifest b/manifest index b4d9ba30cc..c56b3182d1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Immediately\sreset\sall\spending\sprepared\sstatements\son\sany\scall\sto\nsqlite3_set_authorizer(),\seven\sif\sthe\sauthorizer\sis\sbeing\sdisabled. -D 2026-02-09T19:58:04.336 +C Minor\stweaks\sto\sthe\sstar-query\soptimization\sin\sthe\squery\splanner. +D 2026-02-10T18:28:41.694 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -820,7 +820,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab F src/wal.c 505a98fbc599a971d92cb90371cf54546c404cd61e04fd093e7b0c8ff978f9b6 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 -F src/where.c f1237550a01ccbc70141a523661173ddf802f48f7fe94feab9151a66f80c0d9d +F src/where.c 7a7fe745dd8104d0276a3d3f6e6ac7f087af3dd9f34a90bc937e5e7aea817e15 F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da F src/wherecode.c 783ecd30061c875c919a5163e4b55f9a0eccdaf7c9b17ad2908a1668a8766bc4 F src/whereexpr.c bb649ce81bd6dc0eabfa2533ff5656fc7a16411e520a6c59be43e73e51503cce @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 021e48e28931afd781e76db6293e60fd2ffb8377cb1051e8b802f2743a10fa5d -R 8e691803f449515bcdce3d4bea85fe54 +P 5c0468acd1a12f7fd01b9974250fb42c5811939dc2319729a1ef93c073dc0071 +R a8a8cc651a9935d9d998addfdb1931ef U drh -Z d57a142f836bbfe387f4f44113a90926 +Z 9ecd247afb8d5321506fc416f50001e3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cb415b67fd..bab5268fc0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5c0468acd1a12f7fd01b9974250fb42c5811939dc2319729a1ef93c073dc0071 +5021e114b251467fee6a39749c88ec581ee1f7d50093b02a44dc300db0c0a1c5 diff --git a/src/where.c b/src/where.c index 6caa6bfb52..946d9fede5 100644 --- a/src/where.c +++ b/src/where.c @@ -5588,12 +5588,21 @@ static LogEst whereSortingCost( ** 12 otherwise ** ** For the purposes of this heuristic, a star-query is defined as a query -** with a large central table that is joined using an INNER JOIN, -** not CROSS or OUTER JOINs, against four or more smaller tables. -** The central table is called the "fact" table. The smaller tables -** that get joined are "dimension tables". Also, any table that is -** self-joined cannot be a dimension table; we assume that dimension -** tables may only be joined against fact tables. +** with a central "fact" table that is joined against multiple +** "dimension" tables, subject to the following constraints: +** +** (aa) Only a five-way or larger join is considered for this +** optimization. If there are fewer than four terms in the FROM +** clause, this heuristic does not apply. +** +** (bb) The join between the fact table and the dimension tables must +** be an INNER join. CROSS and OUTER JOINs do not qualify. +** +** (cc) A table must have 3 or more dimension tables in order to be +** considered a fact table. (Was 4 prior to 2026-02-10.) +** +** (dd) A table that is a self-join cannot be a dimension table. +** Dimension tables are joined against fact tables. ** ** SIDE EFFECT: (and really the whole point of this subroutine) ** @@ -5646,7 +5655,7 @@ static int computeMxChoice(WhereInfo *pWInfo){ } #endif /* SQLITE_DEBUG */ - if( nLoop>=5 + if( nLoop>=4 /* Constraint (aa) */ && !pWInfo->bStarDone && OptimizationEnabled(pWInfo->pParse->db, SQLITE_StarQuery) ){ @@ -5658,7 +5667,7 @@ static int computeMxChoice(WhereInfo *pWInfo){ pWInfo->bStarDone = 1; /* Only do this computation once */ - /* Look for fact tables with four or more dimensions where the + /* Look for fact tables with three or more dimensions where the ** dimension tables are not separately from the fact tables by an outer ** or cross join. Adjust cost weights if found. */ @@ -5675,18 +5684,17 @@ static int computeMxChoice(WhereInfo *pWInfo){ if( (pFactTab->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ /* If the candidate fact-table is the right table of an outer join ** restrict the search for dimension-tables to be tables to the right - ** of the fact-table. */ - if( iFromIdx+4 > nLoop ) break; /* Impossible to reach nDep>=4 */ + ** of the fact-table. Constraint (bb) */ + if( iFromIdx+3 > nLoop ){ + break; /* ^-- Impossible to reach nDep>=2 - Constraint (cc) */ + } while( pStart && pStart->iTab<=iFromIdx ){ pStart = pStart->pNextLoop; } } for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ if( (aFromTabs[pWLoop->iTab].fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ - /* Fact-tables and dimension-tables cannot be separated by an - ** outer join (at least for the definition of fact- and dimension- - ** used by this heuristic). */ - break; + break; /* Constraint (bb) */ } if( (pWLoop->prereq & m)!=0 /* pWInfo depends on iFromIdx */ && (pWLoop->maskSelf & mSeen)==0 /* pWInfo not already a dependency */ @@ -5700,7 +5708,9 @@ static int computeMxChoice(WhereInfo *pWInfo){ } } } - if( nDep<=3 ) continue; + if( nDep<=2 ){ + continue; /* Constraint (cc) */ + } /* If we reach this point, it means that pFactTab is a fact table ** with four or more dimensions connected by inner joins. Proceed @@ -5713,6 +5723,23 @@ static int computeMxChoice(WhereInfo *pWInfo){ pWLoop->rStarDelta = 0; } } +#endif +#ifdef WHERETRACE_ENABLED /* 0x80000 */ + if( sqlite3WhereTrace & 0x80000 ){ + Bitmask mShow = mSeen; + sqlite3DebugPrintf("Fact table %s(%d), dimensions:", + pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName, + iFromIdx); + for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ + if( mShow & pWLoop->maskSelf ){ + SrcItem *pDim = aFromTabs + pWLoop->iTab; + mShow &= ~pWLoop->maskSelf; + sqlite3DebugPrintf(" %s(%d)", + pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab); + } + } + sqlite3DebugPrintf("\n"); + } #endif pWInfo->bStarUsed = 1; @@ -5736,10 +5763,8 @@ static int computeMxChoice(WhereInfo *pWInfo){ if( sqlite3WhereTrace & 0x80000 ){ SrcItem *pDim = aFromTabs + pWLoop->iTab; sqlite3DebugPrintf( - "Increase SCAN cost of dimension %s(%d) of fact %s(%d) to %d\n", - pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab, - pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName, - iFromIdx, mxRun + "Increase SCAN cost of %s to %d\n", + pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, mxRun ); } pWLoop->rStarDelta = mxRun - pWLoop->rRun; From c652e3431705bffdba1a4ee51473aa09ecc3b543 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 10 Feb 2026 19:33:11 +0000 Subject: [PATCH 002/197] Correction to date/time computations associated with the timestamp-vfs. FossilOrigin-Name: b67889e4f17c3280f839ee7045256cc47d6ce3ed60d880925e3d30f9ebbcf3ff --- ext/misc/tmstmpvfs.c | 4 ++-- manifest | 16 ++++++++-------- manifest.uuid | 2 +- tool/showdb.c | 2 +- tool/showtmlog.c | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index 625ffe4fa5..da67a20772 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -859,7 +859,7 @@ static int tmstmpOpen( TmstmpLog *pLog; sqlite3_uint64 r1; /* Milliseconds since 1970-01-01 */ sqlite3_uint64 days; /* Days since 1970-01-01 */ - sqlite3_uint64 sod; /* Start of date specified by ms */ + sqlite3_uint64 sod; /* Start of date specified by r1 */ sqlite3_uint64 z; /* Days since 0000-03-01 */ sqlite3_uint64 era; /* 400-year era */ int h; /* hour */ @@ -893,7 +893,7 @@ static int tmstmpOpen( m = (sod%3600)/60; s = sod%60; z = days + 719468; - era = z/147097; + era = z/146097; doe = (unsigned)(z - era*146097); yoe = (doe - doe/1460 + doe/36524 - doe/146096)/365; y = (int)yoe + era*400; diff --git a/manifest b/manifest index c56b3182d1..4a4c5a25fd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\stweaks\sto\sthe\sstar-query\soptimization\sin\sthe\squery\splanner. -D 2026-02-10T18:28:41.694 +C Correction\sto\sdate/time\scomputations\sassociated\swith\sthe\stimestamp-vfs. +D 2026-02-10T19:33:11.305 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -403,7 +403,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c 1c335f1df51a60896e84721e262fc23e8a3130ba52b1a34e2b8e4870e5be74e9 +F ext/misc/tmstmpvfs.c 3eb28a9f22f58883f38085daa312467e31ddfd2042c21dcc07173e02a01d68d8 F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2162,12 +2162,12 @@ F tool/pagesig.c f98909b4168d9cac11a2de7f031adea0e2f3131faa7515a72807c03ec58eafe F tool/replace.tcl 511c61acfe563dfb58675efb4628bb158a13d48ff8322123ac447e9d25a82d9a F tool/restore_jrnl.tcl 1079ecba47cc82fa82115b81c1f68097ab1f956f357ee8da5fc4b2589af6bd98 F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/showdb.c db1fba9149d29bc4d9fe2826b881d66da980a5f01e0c0858244e93f18d388321 +F tool/showdb.c 1faa3661d2d634f206c76794cb21d89d3ea9082d07d5e983be0f025e40f21320 F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564 F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809 F tool/showstat4.c b706fcbc4cd1a6e4a73ac32549afc4b460479d650402d64b23e8d813516e8de4 -F tool/showtmlog.c cbdc5f1b21cc8b821a39118b85f2d2616fc7bf3377ddaf02bb1cbcbeb4169f92 +F tool/showtmlog.c 2e9da6c4b4767113a0ad5ddabd4337ea100d38ff9c7fee260f9ccdefb2ffdc23 F tool/showwal.c 11eca547980a066b081f512636151233350ac679f29ecf4ebfce7f4530230b3d F tool/soak1.tcl a3892082ed1079671565c044e93b55c3c7f38829aedf53cc597c65d23ffdaddf F tool/spaceanal.tcl 1f83962090a6b60e1d7bf92495d643e622bef9fe82ea3f2d22350dcbce9a12d0 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 5c0468acd1a12f7fd01b9974250fb42c5811939dc2319729a1ef93c073dc0071 -R a8a8cc651a9935d9d998addfdb1931ef +P 5021e114b251467fee6a39749c88ec581ee1f7d50093b02a44dc300db0c0a1c5 +R 8c009ef3edcff15260e9e11c075a8dac U drh -Z 9ecd247afb8d5321506fc416f50001e3 +Z 82c25fcaf85be039db084b2683a2f369 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bab5268fc0..e953e282ff 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5021e114b251467fee6a39749c88ec581ee1f7d50093b02a44dc300db0c0a1c5 +b67889e4f17c3280f839ee7045256cc47d6ce3ed60d880925e3d30f9ebbcf3ff diff --git a/tool/showdb.c b/tool/showdb.c index 6ee39707c7..84813b8398 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -1051,7 +1051,7 @@ static const char *decodeTimestamp(const unsigned char *a){ m = (sod%3600)/60; s = sod%60; z = days + 719468; - era = z/147097; + era = z/146097; doe = (unsigned)(z - era*146097); yoe = (doe - doe/1460 + doe/36524 - doe/146096)/365; y = (int)yoe + era*400; diff --git a/tool/showtmlog.c b/tool/showtmlog.c index 83ef9a8d45..4c35b777be 100644 --- a/tool/showtmlog.c +++ b/tool/showtmlog.c @@ -49,7 +49,7 @@ static const char *decodeTimestamp(const unsigned char *a){ m = (sod%3600)/60; s = sod%60; z = days + 719468; - era = z/147097; + era = z/146097; doe = (unsigned)(z - era*146097); yoe = (doe - doe/1460 + doe/36524 - doe/146096)/365; y = (int)yoe + era*400; From 643fb6cf4b084ffdf778ff02794920f746a2994d Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 11 Feb 2026 19:42:46 +0000 Subject: [PATCH 003/197] Minor performance enhancement to floating-point rendering. FossilOrigin-Name: 38d8c0d8a0b0e9990ba7bdcce979f2824ffee22a083cb788a75917628b1eb559 --- manifest | 15 +++++++++------ manifest.tags | 4 ++-- manifest.uuid | 2 +- src/util.c | 20 +++++++++++++++++++- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 4a4c5a25fd..9e78194999 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Correction\sto\sdate/time\scomputations\sassociated\swith\sthe\stimestamp-vfs. -D 2026-02-10T19:33:11.305 +C Minor\sperformance\senhancement\sto\sfloating-point\srendering. +D 2026-02-11T19:42:46.005 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 36fb1150062957280777655976f3f9a75db236cb8207a0770ceae8d5ec17fcd3 +F src/util.c 0d191af08ce8bbc31d5ed7d7b5fb0907ac920220147676ca3c7a6288703954dc F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 5021e114b251467fee6a39749c88ec581ee1f7d50093b02a44dc300db0c0a1c5 -R 8c009ef3edcff15260e9e11c075a8dac +P b67889e4f17c3280f839ee7045256cc47d6ce3ed60d880925e3d30f9ebbcf3ff +R cb6350b426b944c91b4d4e6b58ff7a00 +T *branch * fp-perf +T *sym-fp-perf * +T -sym-trunk * U drh -Z 82c25fcaf85be039db084b2683a2f369 +Z 9c515e6aeb36a4ee4cbd4b664e3d6f49 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..7238982b62 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch fp-perf +tag fp-perf diff --git a/manifest.uuid b/manifest.uuid index e953e282ff..998f9549d9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b67889e4f17c3280f839ee7045256cc47d6ce3ed60d880925e3d30f9ebbcf3ff +38d8c0d8a0b0e9990ba7bdcce979f2824ffee22a083cb788a75917628b1eb559 diff --git a/src/util.c b/src/util.c index 8e4fd516ef..20665632d5 100644 --- a/src/util.c +++ b/src/util.c @@ -1092,7 +1092,25 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ /* Extract significant digits. */ i = sizeof(p->zBuf)-1; assert( v>0 ); - while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; } + while( v>=10 ){ + static const char dig[] = + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899"; + int kk = (v%100)*2; + p->zBuf[i] = dig[kk+1]; + p->zBuf[i-1] = dig[kk]; + i -= 2; + v /=100; + } + if( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; } assert( i>=0 && izBuf)-1 ); p->n = sizeof(p->zBuf) - 1 - i; assert( p->n>0 ); From df59c5da78cc2c4d0c1a9993cdbc1bc5cf879900 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 12 Feb 2026 18:15:26 +0000 Subject: [PATCH 004/197] Respect "const" strings in the sqlite3ShadowTableName() function. Patch moved to trunk, where it was intended. FossilOrigin-Name: 51b5afdfac401cbf74af6383d4559439cb6defe2ce23ebcf7ed9a5b526a07b51 --- manifest | 13 +++++++------ manifest.uuid | 2 +- src/build.c | 9 +++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 4a4c5a25fd..ae5dce038f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Correction\sto\sdate/time\scomputations\sassociated\swith\sthe\stimestamp-vfs. -D 2026-02-10T19:33:11.305 +C Respect\s"const"\sstrings\sin\sthe\ssqlite3ShadowTableName()\sfunction.\nPatch\smoved\sto\strunk,\swhere\sit\swas\sintended. +D 2026-02-12T18:15:26.908 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -681,7 +681,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea F src/btree.c b744bf69d520534751c742cababe7ad28c3892f1e3a75242e75a20bca15a834a F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0 F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886 -F src/build.c 4e1afafc56504ed6253e1b115c1502de4243c2287a0c799f4967fcd2d7716ad9 +F src/build.c d2cd51e482e33cc76a8dc94081f922ff327f57532e97ccd7bd31dc058669a36c F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e @@ -2194,8 +2194,9 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 5021e114b251467fee6a39749c88ec581ee1f7d50093b02a44dc300db0c0a1c5 -R 8c009ef3edcff15260e9e11c075a8dac +P b67889e4f17c3280f839ee7045256cc47d6ce3ed60d880925e3d30f9ebbcf3ff +Q +0343ecfaa7e82044807de9fc4cb728a3b5f52cb06e8dd52e39265fd7fbcc68a5 +R bcce8e05e7748a962d1ba7d88458ae7d U drh -Z 82c25fcaf85be039db084b2683a2f369 +Z b0f5cb83b882516729ed30a0b3ccb5f9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e953e282ff..0fd6a51b5c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b67889e4f17c3280f839ee7045256cc47d6ce3ed60d880925e3d30f9ebbcf3ff +51b5afdfac401cbf74af6383d4559439cb6defe2ce23ebcf7ed9a5b526a07b51 diff --git a/src/build.c b/src/build.c index 9af0a1635c..e040f14289 100644 --- a/src/build.c +++ b/src/build.c @@ -2570,13 +2570,14 @@ void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){ ** restored to its original value prior to this routine returning. */ int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ - char *zTail; /* Pointer to the last "_" in zName */ + const char *zTail; /* Pointer to the last "_" in zName */ Table *pTab; /* Table that zName is a shadow of */ + char *zCopy; zTail = strrchr(zName, '_'); if( zTail==0 ) return 0; - *zTail = 0; - pTab = sqlite3FindTable(db, zName, 0); - *zTail = '_'; + zCopy = sqlite3DbStrNDup(db, zName, (int)(zTail-zName)); + pTab = zCopy ? sqlite3FindTable(db, zCopy, 0) : 0; + sqlite3DbFree(db, zCopy); if( pTab==0 ) return 0; if( !IsVirtual(pTab) ) return 0; return sqlite3IsShadowTableOf(db, pTab, zName); From 7d49eb1dff54d65965c190e1b9728282f72cd4a5 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 Feb 2026 11:40:28 +0000 Subject: [PATCH 005/197] Add a "const" to avoid a harmless false-positive compiler warning. FossilOrigin-Name: d44af6cc093ab6b5a196249a84681148bbae3f624abf4bc8cc42c88f3f7320b2 --- manifest | 13 ++++++------- manifest.uuid | 2 +- src/func.c | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index ae5dce038f..d2215837e5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Respect\s"const"\sstrings\sin\sthe\ssqlite3ShadowTableName()\sfunction.\nPatch\smoved\sto\strunk,\swhere\sit\swas\sintended. -D 2026-02-12T18:15:26.908 +C Add\sa\s"const"\sto\savoid\sa\sharmless\sfalse-positive\scompiler\swarning. +D 2026-02-13T11:40:28.552 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -692,7 +692,7 @@ F src/delete.c 901499bed747c3b4b2be45be1abe912ba50a3f6a40ba88cc006ccf279f2d0e97 F src/expr.c c4ff8dcacbc8962fb670fc7c9723c8346398795b16ce2f78439234769baee2e6 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c c065da737307a29e4d240ac727758dbf4102cb3218a1f651eb689b6a6fa12531 -F src/func.c efbcfe7cb7fc92fe5299c9aaa141075eb60d2108253e99bc235384ed6a90d937 +F src/func.c 6b6797b1b8d90c40482795a9a571041ca09bd520c5fa85cb1a49be143eda0bcf F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf @@ -2194,9 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b67889e4f17c3280f839ee7045256cc47d6ce3ed60d880925e3d30f9ebbcf3ff -Q +0343ecfaa7e82044807de9fc4cb728a3b5f52cb06e8dd52e39265fd7fbcc68a5 -R bcce8e05e7748a962d1ba7d88458ae7d +P 51b5afdfac401cbf74af6383d4559439cb6defe2ce23ebcf7ed9a5b526a07b51 +R cb69b3884e549b4404e64346093ca8ca U drh -Z b0f5cb83b882516729ed30a0b3ccb5f9 +Z 70fb0b81d08bfaa7d2ae98d0d6846069 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0fd6a51b5c..a923741bc8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -51b5afdfac401cbf74af6383d4559439cb6defe2ce23ebcf7ed9a5b526a07b51 +d44af6cc093ab6b5a196249a84681148bbae3f624abf4bc8cc42c88f3f7320b2 diff --git a/src/func.c b/src/func.c index 76f2bde77d..d9c148e9c3 100644 --- a/src/func.c +++ b/src/func.c @@ -1201,7 +1201,7 @@ static void unistrFunc( } i = j = 0; while( i Date: Fri, 13 Feb 2026 12:20:57 +0000 Subject: [PATCH 006/197] Use only a single bit, rather than a whole byte, to store infrequently accessed boolean values in the Parse object. FossilOrigin-Name: e1bcd7e1cf6d6b1add49deac65e1b64bcae52fbbad094e561846bb92959db76a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqliteInt.h | 18 +++++++++--------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index d2215837e5..ae396040fa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\s"const"\sto\savoid\sa\sharmless\sfalse-positive\scompiler\swarning. -D 2026-02-13T11:40:28.552 +C Use\sonly\sa\ssingle\sbit,\srather\sthan\sa\swhole\sbyte,\sto\sstore\sinfrequently\naccessed\sboolean\svalues\sin\sthe\sParse\sobject. +D 2026-02-13T12:20:57.401 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -743,7 +743,7 @@ F src/shell.c.in b944a21d98cc4c6107bfd1ec702440579cb4bf86435125b67ff661180e9453b F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h 7f42e42286634092758864472ea445feb45e654c1659b7f5e723ea70939b34dc +F src/sqliteInt.h 9d390349b1e8db865aca6a5bee1d8db9dac8d426ed9e5d944d789d6d57470f00 F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 51b5afdfac401cbf74af6383d4559439cb6defe2ce23ebcf7ed9a5b526a07b51 -R cb69b3884e549b4404e64346093ca8ca +P d44af6cc093ab6b5a196249a84681148bbae3f624abf4bc8cc42c88f3f7320b2 +R cbdb4d0c2bb8d137d8354aa3e44e5e41 U drh -Z 70fb0b81d08bfaa7d2ae98d0d6846069 +Z 28a3e25dd757a4231831a264b2087419 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a923741bc8..a9550d67b9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d44af6cc093ab6b5a196249a84681148bbae3f624abf4bc8cc42c88f3f7320b2 +e1bcd7e1cf6d6b1add49deac65e1b64bcae52fbbad094e561846bb92959db76a diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 664b8afd95..5327976106 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3880,17 +3880,12 @@ struct Parse { u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ - u8 mayAbort; /* True if statement may throw an ABORT exception */ - u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ - u8 bHasExists; /* Has a correlated "EXISTS (SELECT ....)" expression */ u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ - u8 bReturning; /* Coding a RETURNING trigger */ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ - u8 disableTriggers; /* True to disable triggers */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif @@ -3899,10 +3894,15 @@ struct Parse { u8 isCreate; /* CREATE TABLE, INDEX, or VIEW (but not TRIGGER) ** and ALTER TABLE ADD COLUMN. */ #endif - bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */ - bft bHasWith :1; /* True if statement contains WITH */ - bft okConstFactor :1; /* OK to factor out constants */ - bft checkSchema :1; /* Causes schema cookie check after an error */ + bft disableTriggers:1; /* True to disable triggers */ + bft mayAbort :1; /* True if statement may throw an ABORT exception */ + bft hasCompound :1; /* Need to invoke convertCompoundSelectToSubquery() */ + bft bReturning :1; /* Coding a RETURNING trigger */ + bft bHasExists :1; /* Has a correlated "EXISTS (SELECT ....)" expression */ + bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */ + bft bHasWith :1; /* True if statement contains WITH */ + bft okConstFactor:1; /* OK to factor out constants */ + bft checkSchema :1; /* Causes schema cookie check after an error */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ From 990d861038768258588be00b3584d58108d12185 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 Feb 2026 16:02:27 +0000 Subject: [PATCH 007/197] Add new assert() statements to demonstrate that the complaint given in [forum:/forumpost/56ad8b632c|forum post 56ad8b632c] is not a real bug. FossilOrigin-Name: d62999907d5f5987fe0030e1a4a7144c898e55595ac116eec966741a5099322b --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/build.c | 1 + src/fkey.c | 1 + src/trigger.c | 1 + 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index ae396040fa..63341374f8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\sonly\sa\ssingle\sbit,\srather\sthan\sa\swhole\sbyte,\sto\sstore\sinfrequently\naccessed\sboolean\svalues\sin\sthe\sParse\sobject. -D 2026-02-13T12:20:57.401 +C Add\snew\sassert()\sstatements\sto\sdemonstrate\sthat\sthe\scomplaint\sgiven\sin\n[forum:/forumpost/56ad8b632c|forum\spost\s56ad8b632c]\sis\snot\sa\sreal\sbug. +D 2026-02-13T16:02:27.451 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -681,7 +681,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea F src/btree.c b744bf69d520534751c742cababe7ad28c3892f1e3a75242e75a20bca15a834a F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0 F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886 -F src/build.c d2cd51e482e33cc76a8dc94081f922ff327f57532e97ccd7bd31dc058669a36c +F src/build.c cc0afd3ec8417f5f774650f612e755b7ffce392d14ab4441bf5588867893fd3c F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e @@ -691,7 +691,7 @@ F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c F src/delete.c 901499bed747c3b4b2be45be1abe912ba50a3f6a40ba88cc006ccf279f2d0e97 F src/expr.c c4ff8dcacbc8962fb670fc7c9723c8346398795b16ce2f78439234769baee2e6 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 -F src/fkey.c c065da737307a29e4d240ac727758dbf4102cb3218a1f651eb689b6a6fa12531 +F src/fkey.c fb0f74c57d19a2d3f113f3476826919d68feda7ff334abfdb479a9a6353b9fcd F src/func.c 6b6797b1b8d90c40482795a9a571041ca09bd520c5fa85cb1a49be143eda0bcf F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca @@ -799,7 +799,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c f297bbf02037639e7a93b37d9c6e4415b3de1273395ee8fa8183e741e1e7fb72 F src/treeview.c feaa59f14db4f7b5aacca9c5ad5aeb562c1f98262c1ffd74371f4186ade91fc5 -F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c +F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d44af6cc093ab6b5a196249a84681148bbae3f624abf4bc8cc42c88f3f7320b2 -R cbdb4d0c2bb8d137d8354aa3e44e5e41 +P e1bcd7e1cf6d6b1add49deac65e1b64bcae52fbbad094e561846bb92959db76a +R c74731d37412a2c05c1fa7cff1868fd9 U drh -Z 28a3e25dd757a4231831a264b2087419 +Z b29676545410aaf5a0438a51228bcee0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a9550d67b9..78189ac438 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e1bcd7e1cf6d6b1add49deac65e1b64bcae52fbbad094e561846bb92959db76a +d62999907d5f5987fe0030e1a4a7144c898e55595ac116eec966741a5099322b diff --git a/src/build.c b/src/build.c index e040f14289..6b858ccac5 100644 --- a/src/build.c +++ b/src/build.c @@ -4621,6 +4621,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ goto exit_drop_index; } iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); + assert( iDb>=0 && iDbnDb ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; diff --git a/src/fkey.c b/src/fkey.c index 5e0bc89c4e..59edd8810e 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -908,6 +908,7 @@ void sqlite3FkCheck( if( !IsOrdinaryTable(pTab) ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDb>=00 && iDbnDb ); zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the diff --git a/src/trigger.c b/src/trigger.c index 92324f9c23..d26d1dc860 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -336,6 +336,7 @@ void sqlite3FinishTrigger( if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; zName = pTrig->zName; iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); + assert( iDb>=00 && iDbnDb ); pTrig->step_list = pStepList; while( pStepList ){ pStepList->pTrig = pTrig; From db84cdb747ac926d3f272933386fc6196c40cb19 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 Feb 2026 17:58:46 +0000 Subject: [PATCH 008/197] Use a precomputed table of 696 powers of 10 to improve the performance of floating-point to decimal and decimal to floating-point conversions. FossilOrigin-Name: 64d9b7becf2da8927024adda278e837a46837e46af3cff51bd54a183d1716750 --- manifest | 15 +- manifest.uuid | 2 +- src/util.c | 989 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 861 insertions(+), 145 deletions(-) diff --git a/manifest b/manifest index 9e78194999..06fb22038a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sperformance\senhancement\sto\sfloating-point\srendering. -D 2026-02-11T19:42:46.005 +C Use\sa\sprecomputed\stable\sof\s696\spowers\sof\s10\sto\simprove\sthe\sperformance\nof\sfloating-point\sto\sdecimal\sand\sdecimal\sto\sfloating-point\sconversions. +D 2026-02-14T17:58:46.735 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 0d191af08ce8bbc31d5ed7d7b5fb0907ac920220147676ca3c7a6288703954dc +F src/util.c cb0a38becd4eef1084eaf2838bffb3c1423a3bfbebfbeea179d30ac31c0f063b F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,11 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b67889e4f17c3280f839ee7045256cc47d6ce3ed60d880925e3d30f9ebbcf3ff -R cb6350b426b944c91b4d4e6b58ff7a00 -T *branch * fp-perf -T *sym-fp-perf * -T -sym-trunk * +P 38d8c0d8a0b0e9990ba7bdcce979f2824ffee22a083cb788a75917628b1eb559 +R 698349c0b3cdc46d85eb51f40079e9df U drh -Z 9c515e6aeb36a4ee4cbd4b664e3d6f49 +Z 17cef2cc342806b71491096998b8ccfe # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 998f9549d9..a6e1b96c00 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -38d8c0d8a0b0e9990ba7bdcce979f2824ffee22a083cb788a75917628b1eb559 +64d9b7becf2da8927024adda278e837a46837e46af3cff51bd54a183d1716750 diff --git a/src/util.c b/src/util.c index 20665632d5..40a3bf0e2a 100644 --- a/src/util.c +++ b/src/util.c @@ -457,41 +457,850 @@ u8 sqlite3StrIHash(const char *z){ } return h; } +/* +** The following array holds (approximate) powers-of-ten between +** 1.0e-348 and 1.0e+347. Each value is an unsigned 64-bit integer, +** shifted so that its most significant bit is 1. +*/ +static const u64 sqlite3PowerOfTen[] = { + 0xfa8fd5a0081c0288, /* 0: 1.0e-348 << 1220 */ + 0x9c99e58405118195, /* 1: 1.0e-347 << 1216 */ + 0xc3c05ee50655e1fa, /* 2: 1.0e-346 << 1213 */ + 0xf4b0769e47eb5a78, /* 3: 1.0e-345 << 1210 */ + 0x98ee4a22ecf3188b, /* 4: 1.0e-344 << 1206 */ + 0xbf29dcaba82fdeae, /* 5: 1.0e-343 << 1203 */ + 0xeef453d6923bd65a, /* 6: 1.0e-342 << 1200 */ + 0x9558b4661b6565f8, /* 7: 1.0e-341 << 1196 */ + 0xbaaee17fa23ebf76, /* 8: 1.0e-340 << 1193 */ + 0xe95a99df8ace6f53, /* 9: 1.0e-339 << 1190 */ + 0x91d8a02bb6c10594, /* 10: 1.0e-338 << 1186 */ + 0xb64ec836a47146f9, /* 11: 1.0e-337 << 1183 */ + 0xe3e27a444d8d98b7, /* 12: 1.0e-336 << 1180 */ + 0x8e6d8c6ab0787f72, /* 13: 1.0e-335 << 1176 */ + 0xb208ef855c969f4f, /* 14: 1.0e-334 << 1173 */ + 0xde8b2b66b3bc4723, /* 15: 1.0e-333 << 1170 */ + 0x8b16fb203055ac76, /* 16: 1.0e-332 << 1166 */ + 0xaddcb9e83c6b1793, /* 17: 1.0e-331 << 1163 */ + 0xd953e8624b85dd78, /* 18: 1.0e-330 << 1160 */ + 0x87d4713d6f33aa6b, /* 19: 1.0e-329 << 1156 */ + 0xa9c98d8ccb009506, /* 20: 1.0e-328 << 1153 */ + 0xd43bf0effdc0ba48, /* 21: 1.0e-327 << 1150 */ + 0x84a57695fe98746d, /* 22: 1.0e-326 << 1146 */ + 0xa5ced43b7e3e9188, /* 23: 1.0e-325 << 1143 */ + 0xcf42894a5dce35ea, /* 24: 1.0e-324 << 1140 */ + 0x818995ce7aa0e1b2, /* 25: 1.0e-323 << 1136 */ + 0xa1ebfb4219491a1f, /* 26: 1.0e-322 << 1133 */ + 0xca66fa129f9b60a6, /* 27: 1.0e-321 << 1130 */ + 0xfd00b897478238d0, /* 28: 1.0e-320 << 1127 */ + 0x9e20735e8cb16382, /* 29: 1.0e-319 << 1123 */ + 0xc5a890362fddbc62, /* 30: 1.0e-318 << 1120 */ + 0xf712b443bbd52b7b, /* 31: 1.0e-317 << 1117 */ + 0x9a6bb0aa55653b2d, /* 32: 1.0e-316 << 1113 */ + 0xc1069cd4eabe89f8, /* 33: 1.0e-315 << 1110 */ + 0xf148440a256e2c76, /* 34: 1.0e-314 << 1107 */ + 0x96cd2a865764dbca, /* 35: 1.0e-313 << 1103 */ + 0xbc807527ed3e12bc, /* 36: 1.0e-312 << 1100 */ + 0xeba09271e88d976b, /* 37: 1.0e-311 << 1097 */ + 0x93445b8731587ea3, /* 38: 1.0e-310 << 1093 */ + 0xb8157268fdae9e4c, /* 39: 1.0e-309 << 1090 */ + 0xe61acf033d1a45df, /* 40: 1.0e-308 << 1087 */ + 0x8fd0c16206306bab, /* 41: 1.0e-307 << 1083 */ + 0xb3c4f1ba87bc8696, /* 42: 1.0e-306 << 1080 */ + 0xe0b62e2929aba83c, /* 43: 1.0e-305 << 1077 */ + 0x8c71dcd9ba0b4925, /* 44: 1.0e-304 << 1073 */ + 0xaf8e5410288e1b6f, /* 45: 1.0e-303 << 1070 */ + 0xdb71e91432b1a24a, /* 46: 1.0e-302 << 1067 */ + 0x892731ac9faf056e, /* 47: 1.0e-301 << 1063 */ + 0xab70fe17c79ac6ca, /* 48: 1.0e-300 << 1060 */ + 0xd64d3d9db981787d, /* 49: 1.0e-299 << 1057 */ + 0x85f0468293f0eb4e, /* 50: 1.0e-298 << 1053 */ + 0xa76c582338ed2621, /* 51: 1.0e-297 << 1050 */ + 0xd1476e2c07286faa, /* 52: 1.0e-296 << 1047 */ + 0x82cca4db847945ca, /* 53: 1.0e-295 << 1043 */ + 0xa37fce126597973c, /* 54: 1.0e-294 << 1040 */ + 0xcc5fc196fefd7d0c, /* 55: 1.0e-293 << 1037 */ + 0xff77b1fcbebcdc4f, /* 56: 1.0e-292 << 1034 */ + 0x9faacf3df73609b1, /* 57: 1.0e-291 << 1030 */ + 0xc795830d75038c1d, /* 58: 1.0e-290 << 1027 */ + 0xf97ae3d0d2446f25, /* 59: 1.0e-289 << 1024 */ + 0x9becce62836ac577, /* 60: 1.0e-288 << 1020 */ + 0xc2e801fb244576d5, /* 61: 1.0e-287 << 1017 */ + 0xf3a20279ed56d48a, /* 62: 1.0e-286 << 1014 */ + 0x9845418c345644d6, /* 63: 1.0e-285 << 1010 */ + 0xbe5691ef416bd60c, /* 64: 1.0e-284 << 1007 */ + 0xedec366b11c6cb8f, /* 65: 1.0e-283 << 1004 */ + 0x94b3a202eb1c3f39, /* 66: 1.0e-282 << 1000 */ + 0xb9e08a83a5e34f07, /* 67: 1.0e-281 << 997 */ + 0xe858ad248f5c22c9, /* 68: 1.0e-280 << 994 */ + 0x91376c36d99995be, /* 69: 1.0e-279 << 990 */ + 0xb58547448ffffb2d, /* 70: 1.0e-278 << 987 */ + 0xe2e69915b3fff9f9, /* 71: 1.0e-277 << 984 */ + 0x8dd01fad907ffc3b, /* 72: 1.0e-276 << 980 */ + 0xb1442798f49ffb4a, /* 73: 1.0e-275 << 977 */ + 0xdd95317f31c7fa1d, /* 74: 1.0e-274 << 974 */ + 0x8a7d3eef7f1cfc52, /* 75: 1.0e-273 << 970 */ + 0xad1c8eab5ee43b66, /* 76: 1.0e-272 << 967 */ + 0xd863b256369d4a40, /* 77: 1.0e-271 << 964 */ + 0x873e4f75e2224e68, /* 78: 1.0e-270 << 960 */ + 0xa90de3535aaae202, /* 79: 1.0e-269 << 957 */ + 0xd3515c2831559a83, /* 80: 1.0e-268 << 954 */ + 0x8412d9991ed58091, /* 81: 1.0e-267 << 950 */ + 0xa5178fff668ae0b6, /* 82: 1.0e-266 << 947 */ + 0xce5d73ff402d98e3, /* 83: 1.0e-265 << 944 */ + 0x80fa687f881c7f8e, /* 84: 1.0e-264 << 940 */ + 0xa139029f6a239f72, /* 85: 1.0e-263 << 937 */ + 0xc987434744ac874e, /* 86: 1.0e-262 << 934 */ + 0xfbe9141915d7a922, /* 87: 1.0e-261 << 931 */ + 0x9d71ac8fada6c9b5, /* 88: 1.0e-260 << 927 */ + 0xc4ce17b399107c22, /* 89: 1.0e-259 << 924 */ + 0xf6019da07f549b2b, /* 90: 1.0e-258 << 921 */ + 0x99c102844f94e0fb, /* 91: 1.0e-257 << 917 */ + 0xc0314325637a1939, /* 92: 1.0e-256 << 914 */ + 0xf03d93eebc589f88, /* 93: 1.0e-255 << 911 */ + 0x96267c7535b763b5, /* 94: 1.0e-254 << 907 */ + 0xbbb01b9283253ca2, /* 95: 1.0e-253 << 904 */ + 0xea9c227723ee8bcb, /* 96: 1.0e-252 << 901 */ + 0x92a1958a7675175f, /* 97: 1.0e-251 << 897 */ + 0xb749faed14125d36, /* 98: 1.0e-250 << 894 */ + 0xe51c79a85916f484, /* 99: 1.0e-249 << 891 */ + 0x8f31cc0937ae58d2, /* 100: 1.0e-248 << 887 */ + 0xb2fe3f0b8599ef07, /* 101: 1.0e-247 << 884 */ + 0xdfbdcece67006ac9, /* 102: 1.0e-246 << 881 */ + 0x8bd6a141006042bd, /* 103: 1.0e-245 << 877 */ + 0xaecc49914078536d, /* 104: 1.0e-244 << 874 */ + 0xda7f5bf590966848, /* 105: 1.0e-243 << 871 */ + 0x888f99797a5e012d, /* 106: 1.0e-242 << 867 */ + 0xaab37fd7d8f58178, /* 107: 1.0e-241 << 864 */ + 0xd5605fcdcf32e1d6, /* 108: 1.0e-240 << 861 */ + 0x855c3be0a17fcd26, /* 109: 1.0e-239 << 857 */ + 0xa6b34ad8c9dfc06f, /* 110: 1.0e-238 << 854 */ + 0xd0601d8efc57b08b, /* 111: 1.0e-237 << 851 */ + 0x823c12795db6ce57, /* 112: 1.0e-236 << 847 */ + 0xa2cb1717b52481ed, /* 113: 1.0e-235 << 844 */ + 0xcb7ddcdda26da268, /* 114: 1.0e-234 << 841 */ + 0xfe5d54150b090b02, /* 115: 1.0e-233 << 838 */ + 0x9efa548d26e5a6e1, /* 116: 1.0e-232 << 834 */ + 0xc6b8e9b0709f109a, /* 117: 1.0e-231 << 831 */ + 0xf867241c8cc6d4c0, /* 118: 1.0e-230 << 828 */ + 0x9b407691d7fc44f8, /* 119: 1.0e-229 << 824 */ + 0xc21094364dfb5636, /* 120: 1.0e-228 << 821 */ + 0xf294b943e17a2bc4, /* 121: 1.0e-227 << 818 */ + 0x979cf3ca6cec5b5a, /* 122: 1.0e-226 << 814 */ + 0xbd8430bd08277231, /* 123: 1.0e-225 << 811 */ + 0xece53cec4a314ebd, /* 124: 1.0e-224 << 808 */ + 0x940f4613ae5ed136, /* 125: 1.0e-223 << 804 */ + 0xb913179899f68584, /* 126: 1.0e-222 << 801 */ + 0xe757dd7ec07426e5, /* 127: 1.0e-221 << 798 */ + 0x9096ea6f3848984f, /* 128: 1.0e-220 << 794 */ + 0xb4bca50b065abe63, /* 129: 1.0e-219 << 791 */ + 0xe1ebce4dc7f16dfb, /* 130: 1.0e-218 << 788 */ + 0x8d3360f09cf6e4bd, /* 131: 1.0e-217 << 784 */ + 0xb080392cc4349dec, /* 132: 1.0e-216 << 781 */ + 0xdca04777f541c567, /* 133: 1.0e-215 << 778 */ + 0x89e42caaf9491b60, /* 134: 1.0e-214 << 774 */ + 0xac5d37d5b79b6239, /* 135: 1.0e-213 << 771 */ + 0xd77485cb25823ac7, /* 136: 1.0e-212 << 768 */ + 0x86a8d39ef77164bc, /* 137: 1.0e-211 << 764 */ + 0xa8530886b54dbdeb, /* 138: 1.0e-210 << 761 */ + 0xd267caa862a12d66, /* 139: 1.0e-209 << 758 */ + 0x8380dea93da4bc60, /* 140: 1.0e-208 << 754 */ + 0xa46116538d0deb78, /* 141: 1.0e-207 << 751 */ + 0xcd795be870516656, /* 142: 1.0e-206 << 748 */ + 0x806bd9714632dff6, /* 143: 1.0e-205 << 744 */ + 0xa086cfcd97bf97f3, /* 144: 1.0e-204 << 741 */ + 0xc8a883c0fdaf7df0, /* 145: 1.0e-203 << 738 */ + 0xfad2a4b13d1b5d6c, /* 146: 1.0e-202 << 735 */ + 0x9cc3a6eec6311a63, /* 147: 1.0e-201 << 731 */ + 0xc3f490aa77bd60fc, /* 148: 1.0e-200 << 728 */ + 0xf4f1b4d515acb93b, /* 149: 1.0e-199 << 725 */ + 0x991711052d8bf3c5, /* 150: 1.0e-198 << 721 */ + 0xbf5cd54678eef0b6, /* 151: 1.0e-197 << 718 */ + 0xef340a98172aace4, /* 152: 1.0e-196 << 715 */ + 0x9580869f0e7aac0e, /* 153: 1.0e-195 << 711 */ + 0xbae0a846d2195712, /* 154: 1.0e-194 << 708 */ + 0xe998d258869facd7, /* 155: 1.0e-193 << 705 */ + 0x91ff83775423cc06, /* 156: 1.0e-192 << 701 */ + 0xb67f6455292cbf08, /* 157: 1.0e-191 << 698 */ + 0xe41f3d6a7377eeca, /* 158: 1.0e-190 << 695 */ + 0x8e938662882af53e, /* 159: 1.0e-189 << 691 */ + 0xb23867fb2a35b28d, /* 160: 1.0e-188 << 688 */ + 0xdec681f9f4c31f31, /* 161: 1.0e-187 << 685 */ + 0x8b3c113c38f9f37e, /* 162: 1.0e-186 << 681 */ + 0xae0b158b4738705e, /* 163: 1.0e-185 << 678 */ + 0xd98ddaee19068c76, /* 164: 1.0e-184 << 675 */ + 0x87f8a8d4cfa417c9, /* 165: 1.0e-183 << 671 */ + 0xa9f6d30a038d1dbc, /* 166: 1.0e-182 << 668 */ + 0xd47487cc8470652b, /* 167: 1.0e-181 << 665 */ + 0x84c8d4dfd2c63f3b, /* 168: 1.0e-180 << 661 */ + 0xa5fb0a17c777cf09, /* 169: 1.0e-179 << 658 */ + 0xcf79cc9db955c2cc, /* 170: 1.0e-178 << 655 */ + 0x81ac1fe293d599bf, /* 171: 1.0e-177 << 651 */ + 0xa21727db38cb002f, /* 172: 1.0e-176 << 648 */ + 0xca9cf1d206fdc03b, /* 173: 1.0e-175 << 645 */ + 0xfd442e4688bd304a, /* 174: 1.0e-174 << 642 */ + 0x9e4a9cec15763e2e, /* 175: 1.0e-173 << 638 */ + 0xc5dd44271ad3cdba, /* 176: 1.0e-172 << 635 */ + 0xf7549530e188c128, /* 177: 1.0e-171 << 632 */ + 0x9a94dd3e8cf578b9, /* 178: 1.0e-170 << 628 */ + 0xc13a148e3032d6e7, /* 179: 1.0e-169 << 625 */ + 0xf18899b1bc3f8ca1, /* 180: 1.0e-168 << 622 */ + 0x96f5600f15a7b7e5, /* 181: 1.0e-167 << 618 */ + 0xbcb2b812db11a5de, /* 182: 1.0e-166 << 615 */ + 0xebdf661791d60f56, /* 183: 1.0e-165 << 612 */ + 0x936b9fcebb25c995, /* 184: 1.0e-164 << 608 */ + 0xb84687c269ef3bfb, /* 185: 1.0e-163 << 605 */ + 0xe65829b3046b0afa, /* 186: 1.0e-162 << 602 */ + 0x8ff71a0fe2c2e6dc, /* 187: 1.0e-161 << 598 */ + 0xb3f4e093db73a093, /* 188: 1.0e-160 << 595 */ + 0xe0f218b8d25088b8, /* 189: 1.0e-159 << 592 */ + 0x8c974f7383725573, /* 190: 1.0e-158 << 588 */ + 0xafbd2350644eeacf, /* 191: 1.0e-157 << 585 */ + 0xdbac6c247d62a583, /* 192: 1.0e-156 << 582 */ + 0x894bc396ce5da772, /* 193: 1.0e-155 << 578 */ + 0xab9eb47c81f5114f, /* 194: 1.0e-154 << 575 */ + 0xd686619ba27255a2, /* 195: 1.0e-153 << 572 */ + 0x8613fd0145877585, /* 196: 1.0e-152 << 568 */ + 0xa798fc4196e952e7, /* 197: 1.0e-151 << 565 */ + 0xd17f3b51fca3a7a0, /* 198: 1.0e-150 << 562 */ + 0x82ef85133de648c4, /* 199: 1.0e-149 << 558 */ + 0xa3ab66580d5fdaf5, /* 200: 1.0e-148 << 555 */ + 0xcc963fee10b7d1b3, /* 201: 1.0e-147 << 552 */ + 0xffbbcfe994e5c61f, /* 202: 1.0e-146 << 549 */ + 0x9fd561f1fd0f9bd3, /* 203: 1.0e-145 << 545 */ + 0xc7caba6e7c5382c8, /* 204: 1.0e-144 << 542 */ + 0xf9bd690a1b68637b, /* 205: 1.0e-143 << 539 */ + 0x9c1661a651213e2d, /* 206: 1.0e-142 << 535 */ + 0xc31bfa0fe5698db8, /* 207: 1.0e-141 << 532 */ + 0xf3e2f893dec3f126, /* 208: 1.0e-140 << 529 */ + 0x986ddb5c6b3a76b7, /* 209: 1.0e-139 << 525 */ + 0xbe89523386091465, /* 210: 1.0e-138 << 522 */ + 0xee2ba6c0678b597f, /* 211: 1.0e-137 << 519 */ + 0x94db483840b717ef, /* 212: 1.0e-136 << 515 */ + 0xba121a4650e4ddeb, /* 213: 1.0e-135 << 512 */ + 0xe896a0d7e51e1566, /* 214: 1.0e-134 << 509 */ + 0x915e2486ef32cd60, /* 215: 1.0e-133 << 505 */ + 0xb5b5ada8aaff80b8, /* 216: 1.0e-132 << 502 */ + 0xe3231912d5bf60e6, /* 217: 1.0e-131 << 499 */ + 0x8df5efabc5979c8f, /* 218: 1.0e-130 << 495 */ + 0xb1736b96b6fd83b3, /* 219: 1.0e-129 << 492 */ + 0xddd0467c64bce4a0, /* 220: 1.0e-128 << 489 */ + 0x8aa22c0dbef60ee4, /* 221: 1.0e-127 << 485 */ + 0xad4ab7112eb3929d, /* 222: 1.0e-126 << 482 */ + 0xd89d64d57a607744, /* 223: 1.0e-125 << 479 */ + 0x87625f056c7c4a8b, /* 224: 1.0e-124 << 475 */ + 0xa93af6c6c79b5d2d, /* 225: 1.0e-123 << 472 */ + 0xd389b47879823479, /* 226: 1.0e-122 << 469 */ + 0x843610cb4bf160cb, /* 227: 1.0e-121 << 465 */ + 0xa54394fe1eedb8fe, /* 228: 1.0e-120 << 462 */ + 0xce947a3da6a9273e, /* 229: 1.0e-119 << 459 */ + 0x811ccc668829b887, /* 230: 1.0e-118 << 455 */ + 0xa163ff802a3426a8, /* 231: 1.0e-117 << 452 */ + 0xc9bcff6034c13052, /* 232: 1.0e-116 << 449 */ + 0xfc2c3f3841f17c67, /* 233: 1.0e-115 << 446 */ + 0x9d9ba7832936edc0, /* 234: 1.0e-114 << 442 */ + 0xc5029163f384a931, /* 235: 1.0e-113 << 439 */ + 0xf64335bcf065d37d, /* 236: 1.0e-112 << 436 */ + 0x99ea0196163fa42e, /* 237: 1.0e-111 << 432 */ + 0xc06481fb9bcf8d39, /* 238: 1.0e-110 << 429 */ + 0xf07da27a82c37088, /* 239: 1.0e-109 << 426 */ + 0x964e858c91ba2655, /* 240: 1.0e-108 << 422 */ + 0xbbe226efb628afea, /* 241: 1.0e-107 << 419 */ + 0xeadab0aba3b2dbe5, /* 242: 1.0e-106 << 416 */ + 0x92c8ae6b464fc96f, /* 243: 1.0e-105 << 412 */ + 0xb77ada0617e3bbcb, /* 244: 1.0e-104 << 409 */ + 0xe55990879ddcaabd, /* 245: 1.0e-103 << 406 */ + 0x8f57fa54c2a9eab6, /* 246: 1.0e-102 << 402 */ + 0xb32df8e9f3546564, /* 247: 1.0e-101 << 399 */ + 0xdff9772470297ebd, /* 248: 1.0e-100 << 396 */ + 0x8bfbea76c619ef36, /* 249: 1.0e-99 << 392 */ + 0xaefae51477a06b03, /* 250: 1.0e-98 << 389 */ + 0xdab99e59958885c4, /* 251: 1.0e-97 << 386 */ + 0x88b402f7fd75539b, /* 252: 1.0e-96 << 382 */ + 0xaae103b5fcd2a881, /* 253: 1.0e-95 << 379 */ + 0xd59944a37c0752a2, /* 254: 1.0e-94 << 376 */ + 0x857fcae62d8493a5, /* 255: 1.0e-93 << 372 */ + 0xa6dfbd9fb8e5b88e, /* 256: 1.0e-92 << 369 */ + 0xd097ad07a71f26b2, /* 257: 1.0e-91 << 366 */ + 0x825ecc24c873782f, /* 258: 1.0e-90 << 362 */ + 0xa2f67f2dfa90563b, /* 259: 1.0e-89 << 359 */ + 0xcbb41ef979346bca, /* 260: 1.0e-88 << 356 */ + 0xfea126b7d78186bc, /* 261: 1.0e-87 << 353 */ + 0x9f24b832e6b0f436, /* 262: 1.0e-86 << 349 */ + 0xc6ede63fa05d3143, /* 263: 1.0e-85 << 346 */ + 0xf8a95fcf88747d94, /* 264: 1.0e-84 << 343 */ + 0x9b69dbe1b548ce7c, /* 265: 1.0e-83 << 339 */ + 0xc24452da229b021b, /* 266: 1.0e-82 << 336 */ + 0xf2d56790ab41c2a2, /* 267: 1.0e-81 << 333 */ + 0x97c560ba6b0919a5, /* 268: 1.0e-80 << 329 */ + 0xbdb6b8e905cb600f, /* 269: 1.0e-79 << 326 */ + 0xed246723473e3813, /* 270: 1.0e-78 << 323 */ + 0x9436c0760c86e30b, /* 271: 1.0e-77 << 319 */ + 0xb94470938fa89bce, /* 272: 1.0e-76 << 316 */ + 0xe7958cb87392c2c2, /* 273: 1.0e-75 << 313 */ + 0x90bd77f3483bb9b9, /* 274: 1.0e-74 << 309 */ + 0xb4ecd5f01a4aa828, /* 275: 1.0e-73 << 306 */ + 0xe2280b6c20dd5232, /* 276: 1.0e-72 << 303 */ + 0x8d590723948a535f, /* 277: 1.0e-71 << 299 */ + 0xb0af48ec79ace837, /* 278: 1.0e-70 << 296 */ + 0xdcdb1b2798182244, /* 279: 1.0e-69 << 293 */ + 0x8a08f0f8bf0f156b, /* 280: 1.0e-68 << 289 */ + 0xac8b2d36eed2dac5, /* 281: 1.0e-67 << 286 */ + 0xd7adf884aa879177, /* 282: 1.0e-66 << 283 */ + 0x86ccbb52ea94baea, /* 283: 1.0e-65 << 279 */ + 0xa87fea27a539e9a5, /* 284: 1.0e-64 << 276 */ + 0xd29fe4b18e88640e, /* 285: 1.0e-63 << 273 */ + 0x83a3eeeef9153e89, /* 286: 1.0e-62 << 269 */ + 0xa48ceaaab75a8e2b, /* 287: 1.0e-61 << 266 */ + 0xcdb02555653131b6, /* 288: 1.0e-60 << 263 */ + 0x808e17555f3ebf11, /* 289: 1.0e-59 << 259 */ + 0xa0b19d2ab70e6ed6, /* 290: 1.0e-58 << 256 */ + 0xc8de047564d20a8b, /* 291: 1.0e-57 << 253 */ + 0xfb158592be068d2e, /* 292: 1.0e-56 << 250 */ + 0x9ced737bb6c4183d, /* 293: 1.0e-55 << 246 */ + 0xc428d05aa4751e4c, /* 294: 1.0e-54 << 243 */ + 0xf53304714d9265df, /* 295: 1.0e-53 << 240 */ + 0x993fe2c6d07b7fab, /* 296: 1.0e-52 << 236 */ + 0xbf8fdb78849a5f96, /* 297: 1.0e-51 << 233 */ + 0xef73d256a5c0f77c, /* 298: 1.0e-50 << 230 */ + 0x95a8637627989aad, /* 299: 1.0e-49 << 226 */ + 0xbb127c53b17ec159, /* 300: 1.0e-48 << 223 */ + 0xe9d71b689dde71af, /* 301: 1.0e-47 << 220 */ + 0x9226712162ab070d, /* 302: 1.0e-46 << 216 */ + 0xb6b00d69bb55c8d1, /* 303: 1.0e-45 << 213 */ + 0xe45c10c42a2b3b05, /* 304: 1.0e-44 << 210 */ + 0x8eb98a7a9a5b04e3, /* 305: 1.0e-43 << 206 */ + 0xb267ed1940f1c61c, /* 306: 1.0e-42 << 203 */ + 0xdf01e85f912e37a3, /* 307: 1.0e-41 << 200 */ + 0x8b61313bbabce2c6, /* 308: 1.0e-40 << 196 */ + 0xae397d8aa96c1b77, /* 309: 1.0e-39 << 193 */ + 0xd9c7dced53c72255, /* 310: 1.0e-38 << 190 */ + 0x881cea14545c7575, /* 311: 1.0e-37 << 186 */ + 0xaa242499697392d2, /* 312: 1.0e-36 << 183 */ + 0xd4ad2dbfc3d07787, /* 313: 1.0e-35 << 180 */ + 0x84ec3c97da624ab4, /* 314: 1.0e-34 << 176 */ + 0xa6274bbdd0fadd61, /* 315: 1.0e-33 << 173 */ + 0xcfb11ead453994ba, /* 316: 1.0e-32 << 170 */ + 0x81ceb32c4b43fcf4, /* 317: 1.0e-31 << 166 */ + 0xa2425ff75e14fc31, /* 318: 1.0e-30 << 163 */ + 0xcad2f7f5359a3b3e, /* 319: 1.0e-29 << 160 */ + 0xfd87b5f28300ca0d, /* 320: 1.0e-28 << 157 */ + 0x9e74d1b791e07e48, /* 321: 1.0e-27 << 153 */ + 0xc612062576589dda, /* 322: 1.0e-26 << 150 */ + 0xf79687aed3eec551, /* 323: 1.0e-25 << 147 */ + 0x9abe14cd44753b52, /* 324: 1.0e-24 << 143 */ + 0xc16d9a0095928a27, /* 325: 1.0e-23 << 140 */ + 0xf1c90080baf72cb1, /* 326: 1.0e-22 << 137 */ + 0x971da05074da7bee, /* 327: 1.0e-21 << 133 */ + 0xbce5086492111aea, /* 328: 1.0e-20 << 130 */ + 0xec1e4a7db69561a5, /* 329: 1.0e-19 << 127 */ + 0x9392ee8e921d5d07, /* 330: 1.0e-18 << 123 */ + 0xb877aa3236a4b449, /* 331: 1.0e-17 << 120 */ + 0xe69594bec44de15b, /* 332: 1.0e-16 << 117 */ + 0x901d7cf73ab0acd9, /* 333: 1.0e-15 << 113 */ + 0xb424dc35095cd80f, /* 334: 1.0e-14 << 110 */ + 0xe12e13424bb40e13, /* 335: 1.0e-13 << 107 */ + 0x8cbccc096f5088cb, /* 336: 1.0e-12 << 103 */ + 0xafebff0bcb24aafe, /* 337: 1.0e-11 << 100 */ + 0xdbe6fecebdedd5be, /* 338: 1.0e-10 << 97 */ + 0x89705f4136b4a597, /* 339: 1.0e-9 << 93 */ + 0xabcc77118461cefc, /* 340: 1.0e-8 << 90 */ + 0xd6bf94d5e57a42bc, /* 341: 1.0e-7 << 87 */ + 0x8637bd05af6c69b5, /* 342: 1.0e-6 << 83 */ + 0xa7c5ac471b478423, /* 343: 1.0e-5 << 80 */ + 0xd1b71758e219652b, /* 344: 1.0e-4 << 77 */ + 0x83126e978d4fdf3b, /* 345: 1.0e-3 << 73 */ + 0xa3d70a3d70a3d70a, /* 346: 1.0e-2 << 70 */ + 0xcccccccccccccccc, /* 347: 1.0e-1 << 67 */ + 0x8000000000000000, /* 348: 1.0e+0 << 63 */ + 0xa000000000000000, /* 349: 1.0e+1 << 60 */ + 0xc800000000000000, /* 350: 1.0e+2 << 57 */ + 0xfa00000000000000, /* 351: 1.0e+3 << 54 */ + 0x9c40000000000000, /* 352: 1.0e+4 << 50 */ + 0xc350000000000000, /* 353: 1.0e+5 << 47 */ + 0xf424000000000000, /* 354: 1.0e+6 << 44 */ + 0x9896800000000000, /* 355: 1.0e+7 << 40 */ + 0xbebc200000000000, /* 356: 1.0e+8 << 37 */ + 0xee6b280000000000, /* 357: 1.0e+9 << 34 */ + 0x9502f90000000000, /* 358: 1.0e+10 << 30 */ + 0xba43b74000000000, /* 359: 1.0e+11 << 27 */ + 0xe8d4a51000000000, /* 360: 1.0e+12 << 24 */ + 0x9184e72a00000000, /* 361: 1.0e+13 << 20 */ + 0xb5e620f480000000, /* 362: 1.0e+14 << 17 */ + 0xe35fa931a0000000, /* 363: 1.0e+15 << 14 */ + 0x8e1bc9bf04000000, /* 364: 1.0e+16 << 10 */ + 0xb1a2bc2ec5000000, /* 365: 1.0e+17 << 7 */ + 0xde0b6b3a76400000, /* 366: 1.0e+18 << 4 */ + 0x8ac7230489e80000, /* 367: 1.0e+19 >> 0 */ + 0xad78ebc5ac620000, /* 368: 1.0e+20 >> 3 */ + 0xd8d726b7177a8000, /* 369: 1.0e+21 >> 6 */ + 0x878678326eac9000, /* 370: 1.0e+22 >> 10 */ + 0xa968163f0a57b400, /* 371: 1.0e+23 >> 13 */ + 0xd3c21bcecceda100, /* 372: 1.0e+24 >> 16 */ + 0x84595161401484a0, /* 373: 1.0e+25 >> 20 */ + 0xa56fa5b99019a5c8, /* 374: 1.0e+26 >> 23 */ + 0xcecb8f27f4200f3a, /* 375: 1.0e+27 >> 26 */ + 0x813f3978f8940984, /* 376: 1.0e+28 >> 30 */ + 0xa18f07d736b90be5, /* 377: 1.0e+29 >> 33 */ + 0xc9f2c9cd04674ede, /* 378: 1.0e+30 >> 36 */ + 0xfc6f7c4045812296, /* 379: 1.0e+31 >> 39 */ + 0x9dc5ada82b70b59d, /* 380: 1.0e+32 >> 43 */ + 0xc5371912364ce305, /* 381: 1.0e+33 >> 46 */ + 0xf684df56c3e01bc6, /* 382: 1.0e+34 >> 49 */ + 0x9a130b963a6c115c, /* 383: 1.0e+35 >> 53 */ + 0xc097ce7bc90715b3, /* 384: 1.0e+36 >> 56 */ + 0xf0bdc21abb48db20, /* 385: 1.0e+37 >> 59 */ + 0x96769950b50d88f4, /* 386: 1.0e+38 >> 63 */ + 0xbc143fa4e250eb31, /* 387: 1.0e+39 >> 66 */ + 0xeb194f8e1ae525fd, /* 388: 1.0e+40 >> 69 */ + 0x92efd1b8d0cf37be, /* 389: 1.0e+41 >> 73 */ + 0xb7abc627050305ad, /* 390: 1.0e+42 >> 76 */ + 0xe596b7b0c643c719, /* 391: 1.0e+43 >> 79 */ + 0x8f7e32ce7bea5c6f, /* 392: 1.0e+44 >> 83 */ + 0xb35dbf821ae4f38b, /* 393: 1.0e+45 >> 86 */ + 0xe0352f62a19e306e, /* 394: 1.0e+46 >> 89 */ + 0x8c213d9da502de45, /* 395: 1.0e+47 >> 93 */ + 0xaf298d050e4395d6, /* 396: 1.0e+48 >> 96 */ + 0xdaf3f04651d47b4c, /* 397: 1.0e+49 >> 99 */ + 0x88d8762bf324cd0f, /* 398: 1.0e+50 >> 103 */ + 0xab0e93b6efee0053, /* 399: 1.0e+51 >> 106 */ + 0xd5d238a4abe98068, /* 400: 1.0e+52 >> 109 */ + 0x85a36366eb71f041, /* 401: 1.0e+53 >> 113 */ + 0xa70c3c40a64e6c51, /* 402: 1.0e+54 >> 116 */ + 0xd0cf4b50cfe20765, /* 403: 1.0e+55 >> 119 */ + 0x82818f1281ed449f, /* 404: 1.0e+56 >> 123 */ + 0xa321f2d7226895c7, /* 405: 1.0e+57 >> 126 */ + 0xcbea6f8ceb02bb39, /* 406: 1.0e+58 >> 129 */ + 0xfee50b7025c36a08, /* 407: 1.0e+59 >> 132 */ + 0x9f4f2726179a2245, /* 408: 1.0e+60 >> 136 */ + 0xc722f0ef9d80aad6, /* 409: 1.0e+61 >> 139 */ + 0xf8ebad2b84e0d58b, /* 410: 1.0e+62 >> 142 */ + 0x9b934c3b330c8577, /* 411: 1.0e+63 >> 146 */ + 0xc2781f49ffcfa6d5, /* 412: 1.0e+64 >> 149 */ + 0xf316271c7fc3908a, /* 413: 1.0e+65 >> 152 */ + 0x97edd871cfda3a56, /* 414: 1.0e+66 >> 156 */ + 0xbde94e8e43d0c8ec, /* 415: 1.0e+67 >> 159 */ + 0xed63a231d4c4fb27, /* 416: 1.0e+68 >> 162 */ + 0x945e455f24fb1cf8, /* 417: 1.0e+69 >> 166 */ + 0xb975d6b6ee39e436, /* 418: 1.0e+70 >> 169 */ + 0xe7d34c64a9c85d44, /* 419: 1.0e+71 >> 172 */ + 0x90e40fbeea1d3a4a, /* 420: 1.0e+72 >> 176 */ + 0xb51d13aea4a488dd, /* 421: 1.0e+73 >> 179 */ + 0xe264589a4dcdab14, /* 422: 1.0e+74 >> 182 */ + 0x8d7eb76070a08aec, /* 423: 1.0e+75 >> 186 */ + 0xb0de65388cc8ada8, /* 424: 1.0e+76 >> 189 */ + 0xdd15fe86affad912, /* 425: 1.0e+77 >> 192 */ + 0x8a2dbf142dfcc7ab, /* 426: 1.0e+78 >> 196 */ + 0xacb92ed9397bf996, /* 427: 1.0e+79 >> 199 */ + 0xd7e77a8f87daf7fb, /* 428: 1.0e+80 >> 202 */ + 0x86f0ac99b4e8dafd, /* 429: 1.0e+81 >> 206 */ + 0xa8acd7c0222311bc, /* 430: 1.0e+82 >> 209 */ + 0xd2d80db02aabd62b, /* 431: 1.0e+83 >> 212 */ + 0x83c7088e1aab65db, /* 432: 1.0e+84 >> 216 */ + 0xa4b8cab1a1563f52, /* 433: 1.0e+85 >> 219 */ + 0xcde6fd5e09abcf26, /* 434: 1.0e+86 >> 222 */ + 0x80b05e5ac60b6178, /* 435: 1.0e+87 >> 226 */ + 0xa0dc75f1778e39d6, /* 436: 1.0e+88 >> 229 */ + 0xc913936dd571c84c, /* 437: 1.0e+89 >> 232 */ + 0xfb5878494ace3a5f, /* 438: 1.0e+90 >> 235 */ + 0x9d174b2dcec0e47b, /* 439: 1.0e+91 >> 239 */ + 0xc45d1df942711d9a, /* 440: 1.0e+92 >> 242 */ + 0xf5746577930d6500, /* 441: 1.0e+93 >> 245 */ + 0x9968bf6abbe85f20, /* 442: 1.0e+94 >> 249 */ + 0xbfc2ef456ae276e8, /* 443: 1.0e+95 >> 252 */ + 0xefb3ab16c59b14a2, /* 444: 1.0e+96 >> 255 */ + 0x95d04aee3b80ece5, /* 445: 1.0e+97 >> 259 */ + 0xbb445da9ca61281f, /* 446: 1.0e+98 >> 262 */ + 0xea1575143cf97226, /* 447: 1.0e+99 >> 265 */ + 0x924d692ca61be758, /* 448: 1.0e+100 >> 269 */ + 0xb6e0c377cfa2e12e, /* 449: 1.0e+101 >> 272 */ + 0xe498f455c38b997a, /* 450: 1.0e+102 >> 275 */ + 0x8edf98b59a373fec, /* 451: 1.0e+103 >> 279 */ + 0xb2977ee300c50fe7, /* 452: 1.0e+104 >> 282 */ + 0xdf3d5e9bc0f653e1, /* 453: 1.0e+105 >> 285 */ + 0x8b865b215899f46c, /* 454: 1.0e+106 >> 289 */ + 0xae67f1e9aec07187, /* 455: 1.0e+107 >> 292 */ + 0xda01ee641a708de9, /* 456: 1.0e+108 >> 295 */ + 0x884134fe908658b2, /* 457: 1.0e+109 >> 299 */ + 0xaa51823e34a7eede, /* 458: 1.0e+110 >> 302 */ + 0xd4e5e2cdc1d1ea96, /* 459: 1.0e+111 >> 305 */ + 0x850fadc09923329e, /* 460: 1.0e+112 >> 309 */ + 0xa6539930bf6bff45, /* 461: 1.0e+113 >> 312 */ + 0xcfe87f7cef46ff16, /* 462: 1.0e+114 >> 315 */ + 0x81f14fae158c5f6e, /* 463: 1.0e+115 >> 319 */ + 0xa26da3999aef7749, /* 464: 1.0e+116 >> 322 */ + 0xcb090c8001ab551c, /* 465: 1.0e+117 >> 325 */ + 0xfdcb4fa002162a63, /* 466: 1.0e+118 >> 328 */ + 0x9e9f11c4014dda7e, /* 467: 1.0e+119 >> 332 */ + 0xc646d63501a1511d, /* 468: 1.0e+120 >> 335 */ + 0xf7d88bc24209a565, /* 469: 1.0e+121 >> 338 */ + 0x9ae757596946075f, /* 470: 1.0e+122 >> 342 */ + 0xc1a12d2fc3978937, /* 471: 1.0e+123 >> 345 */ + 0xf209787bb47d6b84, /* 472: 1.0e+124 >> 348 */ + 0x9745eb4d50ce6332, /* 473: 1.0e+125 >> 352 */ + 0xbd176620a501fbff, /* 474: 1.0e+126 >> 355 */ + 0xec5d3fa8ce427aff, /* 475: 1.0e+127 >> 358 */ + 0x93ba47c980e98cdf, /* 476: 1.0e+128 >> 362 */ + 0xb8a8d9bbe123f017, /* 477: 1.0e+129 >> 365 */ + 0xe6d3102ad96cec1d, /* 478: 1.0e+130 >> 368 */ + 0x9043ea1ac7e41392, /* 479: 1.0e+131 >> 372 */ + 0xb454e4a179dd1877, /* 480: 1.0e+132 >> 375 */ + 0xe16a1dc9d8545e94, /* 481: 1.0e+133 >> 378 */ + 0x8ce2529e2734bb1d, /* 482: 1.0e+134 >> 382 */ + 0xb01ae745b101e9e4, /* 483: 1.0e+135 >> 385 */ + 0xdc21a1171d42645d, /* 484: 1.0e+136 >> 388 */ + 0x899504ae72497eba, /* 485: 1.0e+137 >> 392 */ + 0xabfa45da0edbde69, /* 486: 1.0e+138 >> 395 */ + 0xd6f8d7509292d603, /* 487: 1.0e+139 >> 398 */ + 0x865b86925b9bc5c2, /* 488: 1.0e+140 >> 402 */ + 0xa7f26836f282b732, /* 489: 1.0e+141 >> 405 */ + 0xd1ef0244af2364ff, /* 490: 1.0e+142 >> 408 */ + 0x8335616aed761f1f, /* 491: 1.0e+143 >> 412 */ + 0xa402b9c5a8d3a6e7, /* 492: 1.0e+144 >> 415 */ + 0xcd036837130890a1, /* 493: 1.0e+145 >> 418 */ + 0x802221226be55a64, /* 494: 1.0e+146 >> 422 */ + 0xa02aa96b06deb0fd, /* 495: 1.0e+147 >> 425 */ + 0xc83553c5c8965d3d, /* 496: 1.0e+148 >> 428 */ + 0xfa42a8b73abbf48c, /* 497: 1.0e+149 >> 431 */ + 0x9c69a97284b578d7, /* 498: 1.0e+150 >> 435 */ + 0xc38413cf25e2d70d, /* 499: 1.0e+151 >> 438 */ + 0xf46518c2ef5b8cd1, /* 500: 1.0e+152 >> 441 */ + 0x98bf2f79d5993802, /* 501: 1.0e+153 >> 445 */ + 0xbeeefb584aff8603, /* 502: 1.0e+154 >> 448 */ + 0xeeaaba2e5dbf6784, /* 503: 1.0e+155 >> 451 */ + 0x952ab45cfa97a0b2, /* 504: 1.0e+156 >> 455 */ + 0xba756174393d88df, /* 505: 1.0e+157 >> 458 */ + 0xe912b9d1478ceb17, /* 506: 1.0e+158 >> 461 */ + 0x91abb422ccb812ee, /* 507: 1.0e+159 >> 465 */ + 0xb616a12b7fe617aa, /* 508: 1.0e+160 >> 468 */ + 0xe39c49765fdf9d94, /* 509: 1.0e+161 >> 471 */ + 0x8e41ade9fbebc27d, /* 510: 1.0e+162 >> 475 */ + 0xb1d219647ae6b31c, /* 511: 1.0e+163 >> 478 */ + 0xde469fbd99a05fe3, /* 512: 1.0e+164 >> 481 */ + 0x8aec23d680043bee, /* 513: 1.0e+165 >> 485 */ + 0xada72ccc20054ae9, /* 514: 1.0e+166 >> 488 */ + 0xd910f7ff28069da4, /* 515: 1.0e+167 >> 491 */ + 0x87aa9aff79042286, /* 516: 1.0e+168 >> 495 */ + 0xa99541bf57452b28, /* 517: 1.0e+169 >> 498 */ + 0xd3fa922f2d1675f2, /* 518: 1.0e+170 >> 501 */ + 0x847c9b5d7c2e09b7, /* 519: 1.0e+171 >> 505 */ + 0xa59bc234db398c25, /* 520: 1.0e+172 >> 508 */ + 0xcf02b2c21207ef2e, /* 521: 1.0e+173 >> 511 */ + 0x8161afb94b44f57d, /* 522: 1.0e+174 >> 515 */ + 0xa1ba1ba79e1632dc, /* 523: 1.0e+175 >> 518 */ + 0xca28a291859bbf93, /* 524: 1.0e+176 >> 521 */ + 0xfcb2cb35e702af78, /* 525: 1.0e+177 >> 524 */ + 0x9defbf01b061adab, /* 526: 1.0e+178 >> 528 */ + 0xc56baec21c7a1916, /* 527: 1.0e+179 >> 531 */ + 0xf6c69a72a3989f5b, /* 528: 1.0e+180 >> 534 */ + 0x9a3c2087a63f6399, /* 529: 1.0e+181 >> 538 */ + 0xc0cb28a98fcf3c7f, /* 530: 1.0e+182 >> 541 */ + 0xf0fdf2d3f3c30b9f, /* 531: 1.0e+183 >> 544 */ + 0x969eb7c47859e743, /* 532: 1.0e+184 >> 548 */ + 0xbc4665b596706114, /* 533: 1.0e+185 >> 551 */ + 0xeb57ff22fc0c7959, /* 534: 1.0e+186 >> 554 */ + 0x9316ff75dd87cbd8, /* 535: 1.0e+187 >> 558 */ + 0xb7dcbf5354e9bece, /* 536: 1.0e+188 >> 561 */ + 0xe5d3ef282a242e81, /* 537: 1.0e+189 >> 564 */ + 0x8fa475791a569d10, /* 538: 1.0e+190 >> 568 */ + 0xb38d92d760ec4455, /* 539: 1.0e+191 >> 571 */ + 0xe070f78d3927556a, /* 540: 1.0e+192 >> 574 */ + 0x8c469ab843b89562, /* 541: 1.0e+193 >> 578 */ + 0xaf58416654a6babb, /* 542: 1.0e+194 >> 581 */ + 0xdb2e51bfe9d0696a, /* 543: 1.0e+195 >> 584 */ + 0x88fcf317f22241e2, /* 544: 1.0e+196 >> 588 */ + 0xab3c2fddeeaad25a, /* 545: 1.0e+197 >> 591 */ + 0xd60b3bd56a5586f1, /* 546: 1.0e+198 >> 594 */ + 0x85c7056562757456, /* 547: 1.0e+199 >> 598 */ + 0xa738c6bebb12d16c, /* 548: 1.0e+200 >> 601 */ + 0xd106f86e69d785c7, /* 549: 1.0e+201 >> 604 */ + 0x82a45b450226b39c, /* 550: 1.0e+202 >> 608 */ + 0xa34d721642b06084, /* 551: 1.0e+203 >> 611 */ + 0xcc20ce9bd35c78a5, /* 552: 1.0e+204 >> 614 */ + 0xff290242c83396ce, /* 553: 1.0e+205 >> 617 */ + 0x9f79a169bd203e41, /* 554: 1.0e+206 >> 621 */ + 0xc75809c42c684dd1, /* 555: 1.0e+207 >> 624 */ + 0xf92e0c3537826145, /* 556: 1.0e+208 >> 627 */ + 0x9bbcc7a142b17ccb, /* 557: 1.0e+209 >> 631 */ + 0xc2abf989935ddbfe, /* 558: 1.0e+210 >> 634 */ + 0xf356f7ebf83552fe, /* 559: 1.0e+211 >> 637 */ + 0x98165af37b2153de, /* 560: 1.0e+212 >> 641 */ + 0xbe1bf1b059e9a8d6, /* 561: 1.0e+213 >> 644 */ + 0xeda2ee1c7064130c, /* 562: 1.0e+214 >> 647 */ + 0x9485d4d1c63e8be7, /* 563: 1.0e+215 >> 651 */ + 0xb9a74a0637ce2ee1, /* 564: 1.0e+216 >> 654 */ + 0xe8111c87c5c1ba99, /* 565: 1.0e+217 >> 657 */ + 0x910ab1d4db9914a0, /* 566: 1.0e+218 >> 661 */ + 0xb54d5e4a127f59c8, /* 567: 1.0e+219 >> 664 */ + 0xe2a0b5dc971f303a, /* 568: 1.0e+220 >> 667 */ + 0x8da471a9de737e24, /* 569: 1.0e+221 >> 671 */ + 0xb10d8e1456105dad, /* 570: 1.0e+222 >> 674 */ + 0xdd50f1996b947518, /* 571: 1.0e+223 >> 677 */ + 0x8a5296ffe33cc92f, /* 572: 1.0e+224 >> 681 */ + 0xace73cbfdc0bfb7b, /* 573: 1.0e+225 >> 684 */ + 0xd8210befd30efa5a, /* 574: 1.0e+226 >> 687 */ + 0x8714a775e3e95c78, /* 575: 1.0e+227 >> 691 */ + 0xa8d9d1535ce3b396, /* 576: 1.0e+228 >> 694 */ + 0xd31045a8341ca07c, /* 577: 1.0e+229 >> 697 */ + 0x83ea2b892091e44d, /* 578: 1.0e+230 >> 701 */ + 0xa4e4b66b68b65d60, /* 579: 1.0e+231 >> 704 */ + 0xce1de40642e3f4b9, /* 580: 1.0e+232 >> 707 */ + 0x80d2ae83e9ce78f3, /* 581: 1.0e+233 >> 711 */ + 0xa1075a24e4421730, /* 582: 1.0e+234 >> 714 */ + 0xc94930ae1d529cfc, /* 583: 1.0e+235 >> 717 */ + 0xfb9b7cd9a4a7443c, /* 584: 1.0e+236 >> 720 */ + 0x9d412e0806e88aa5, /* 585: 1.0e+237 >> 724 */ + 0xc491798a08a2ad4e, /* 586: 1.0e+238 >> 727 */ + 0xf5b5d7ec8acb58a2, /* 587: 1.0e+239 >> 730 */ + 0x9991a6f3d6bf1765, /* 588: 1.0e+240 >> 734 */ + 0xbff610b0cc6edd3f, /* 589: 1.0e+241 >> 737 */ + 0xeff394dcff8a948e, /* 590: 1.0e+242 >> 740 */ + 0x95f83d0a1fb69cd9, /* 591: 1.0e+243 >> 744 */ + 0xbb764c4ca7a4440f, /* 592: 1.0e+244 >> 747 */ + 0xea53df5fd18d5513, /* 593: 1.0e+245 >> 750 */ + 0x92746b9be2f8552c, /* 594: 1.0e+246 >> 754 */ + 0xb7118682dbb66a77, /* 595: 1.0e+247 >> 757 */ + 0xe4d5e82392a40515, /* 596: 1.0e+248 >> 760 */ + 0x8f05b1163ba6832d, /* 597: 1.0e+249 >> 764 */ + 0xb2c71d5bca9023f8, /* 598: 1.0e+250 >> 767 */ + 0xdf78e4b2bd342cf6, /* 599: 1.0e+251 >> 770 */ + 0x8bab8eefb6409c1a, /* 600: 1.0e+252 >> 774 */ + 0xae9672aba3d0c320, /* 601: 1.0e+253 >> 777 */ + 0xda3c0f568cc4f3e8, /* 602: 1.0e+254 >> 780 */ + 0x8865899617fb1871, /* 603: 1.0e+255 >> 784 */ + 0xaa7eebfb9df9de8d, /* 604: 1.0e+256 >> 787 */ + 0xd51ea6fa85785631, /* 605: 1.0e+257 >> 790 */ + 0x8533285c936b35de, /* 606: 1.0e+258 >> 794 */ + 0xa67ff273b8460356, /* 607: 1.0e+259 >> 797 */ + 0xd01fef10a657842c, /* 608: 1.0e+260 >> 800 */ + 0x8213f56a67f6b29b, /* 609: 1.0e+261 >> 804 */ + 0xa298f2c501f45f42, /* 610: 1.0e+262 >> 807 */ + 0xcb3f2f7642717713, /* 611: 1.0e+263 >> 810 */ + 0xfe0efb53d30dd4d7, /* 612: 1.0e+264 >> 813 */ + 0x9ec95d1463e8a506, /* 613: 1.0e+265 >> 817 */ + 0xc67bb4597ce2ce48, /* 614: 1.0e+266 >> 820 */ + 0xf81aa16fdc1b81da, /* 615: 1.0e+267 >> 823 */ + 0x9b10a4e5e9913128, /* 616: 1.0e+268 >> 827 */ + 0xc1d4ce1f63f57d72, /* 617: 1.0e+269 >> 830 */ + 0xf24a01a73cf2dccf, /* 618: 1.0e+270 >> 833 */ + 0x976e41088617ca01, /* 619: 1.0e+271 >> 837 */ + 0xbd49d14aa79dbc82, /* 620: 1.0e+272 >> 840 */ + 0xec9c459d51852ba2, /* 621: 1.0e+273 >> 843 */ + 0x93e1ab8252f33b45, /* 622: 1.0e+274 >> 847 */ + 0xb8da1662e7b00a17, /* 623: 1.0e+275 >> 850 */ + 0xe7109bfba19c0c9d, /* 624: 1.0e+276 >> 853 */ + 0x906a617d450187e2, /* 625: 1.0e+277 >> 857 */ + 0xb484f9dc9641e9da, /* 626: 1.0e+278 >> 860 */ + 0xe1a63853bbd26451, /* 627: 1.0e+279 >> 863 */ + 0x8d07e33455637eb2, /* 628: 1.0e+280 >> 867 */ + 0xb049dc016abc5e5f, /* 629: 1.0e+281 >> 870 */ + 0xdc5c5301c56b75f7, /* 630: 1.0e+282 >> 873 */ + 0x89b9b3e11b6329ba, /* 631: 1.0e+283 >> 877 */ + 0xac2820d9623bf429, /* 632: 1.0e+284 >> 880 */ + 0xd732290fbacaf133, /* 633: 1.0e+285 >> 883 */ + 0x867f59a9d4bed6c0, /* 634: 1.0e+286 >> 887 */ + 0xa81f301449ee8c70, /* 635: 1.0e+287 >> 890 */ + 0xd226fc195c6a2f8c, /* 636: 1.0e+288 >> 893 */ + 0x83585d8fd9c25db7, /* 637: 1.0e+289 >> 897 */ + 0xa42e74f3d032f525, /* 638: 1.0e+290 >> 900 */ + 0xcd3a1230c43fb26f, /* 639: 1.0e+291 >> 903 */ + 0x80444b5e7aa7cf85, /* 640: 1.0e+292 >> 907 */ + 0xa0555e361951c366, /* 641: 1.0e+293 >> 910 */ + 0xc86ab5c39fa63440, /* 642: 1.0e+294 >> 913 */ + 0xfa856334878fc150, /* 643: 1.0e+295 >> 916 */ + 0x9c935e00d4b9d8d2, /* 644: 1.0e+296 >> 920 */ + 0xc3b8358109e84f07, /* 645: 1.0e+297 >> 923 */ + 0xf4a642e14c6262c8, /* 646: 1.0e+298 >> 926 */ + 0x98e7e9cccfbd7dbd, /* 647: 1.0e+299 >> 930 */ + 0xbf21e44003acdd2c, /* 648: 1.0e+300 >> 933 */ + 0xeeea5d5004981478, /* 649: 1.0e+301 >> 936 */ + 0x95527a5202df0ccb, /* 650: 1.0e+302 >> 940 */ + 0xbaa718e68396cffd, /* 651: 1.0e+303 >> 943 */ + 0xe950df20247c83fd, /* 652: 1.0e+304 >> 946 */ + 0x91d28b7416cdd27e, /* 653: 1.0e+305 >> 950 */ + 0xb6472e511c81471d, /* 654: 1.0e+306 >> 953 */ + 0xe3d8f9e563a198e5, /* 655: 1.0e+307 >> 956 */ + 0x8e679c2f5e44ff8f, /* 656: 1.0e+308 >> 960 */ + 0xb201833b35d63f73, /* 657: 1.0e+309 >> 963 */ + 0xde81e40a034bcf4f, /* 658: 1.0e+310 >> 966 */ + 0x8b112e86420f6191, /* 659: 1.0e+311 >> 970 */ + 0xadd57a27d29339f6, /* 660: 1.0e+312 >> 973 */ + 0xd94ad8b1c7380874, /* 661: 1.0e+313 >> 976 */ + 0x87cec76f1c830548, /* 662: 1.0e+314 >> 980 */ + 0xa9c2794ae3a3c69a, /* 663: 1.0e+315 >> 983 */ + 0xd433179d9c8cb841, /* 664: 1.0e+316 >> 986 */ + 0x849feec281d7f328, /* 665: 1.0e+317 >> 990 */ + 0xa5c7ea73224deff3, /* 666: 1.0e+318 >> 993 */ + 0xcf39e50feae16bef, /* 667: 1.0e+319 >> 996 */ + 0x81842f29f2cce375, /* 668: 1.0e+320 >> 1000 */ + 0xa1e53af46f801c53, /* 669: 1.0e+321 >> 1003 */ + 0xca5e89b18b602368, /* 670: 1.0e+322 >> 1006 */ + 0xfcf62c1dee382c42, /* 671: 1.0e+323 >> 1009 */ + 0x9e19db92b4e31ba9, /* 672: 1.0e+324 >> 1013 */ + 0xc5a05277621be293, /* 673: 1.0e+325 >> 1016 */ + 0xf70867153aa2db38, /* 674: 1.0e+326 >> 1019 */ + 0x9a65406d44a5c903, /* 675: 1.0e+327 >> 1023 */ + 0xc0fe908895cf3b44, /* 676: 1.0e+328 >> 1026 */ + 0xf13e34aabb430a15, /* 677: 1.0e+329 >> 1029 */ + 0x96c6e0eab509e64d, /* 678: 1.0e+330 >> 1033 */ + 0xbc789925624c5fe0, /* 679: 1.0e+331 >> 1036 */ + 0xeb96bf6ebadf77d8, /* 680: 1.0e+332 >> 1039 */ + 0x933e37a534cbaae7, /* 681: 1.0e+333 >> 1043 */ + 0xb80dc58e81fe95a1, /* 682: 1.0e+334 >> 1046 */ + 0xe61136f2227e3b09, /* 683: 1.0e+335 >> 1049 */ + 0x8fcac257558ee4e6, /* 684: 1.0e+336 >> 1053 */ + 0xb3bd72ed2af29e1f, /* 685: 1.0e+337 >> 1056 */ + 0xe0accfa875af45a7, /* 686: 1.0e+338 >> 1059 */ + 0x8c6c01c9498d8b88, /* 687: 1.0e+339 >> 1063 */ + 0xaf87023b9bf0ee6a, /* 688: 1.0e+340 >> 1066 */ + 0xdb68c2ca82ed2a05, /* 689: 1.0e+341 >> 1069 */ + 0x892179be91d43a43, /* 690: 1.0e+342 >> 1073 */ + 0xab69d82e364948d4, /* 691: 1.0e+343 >> 1076 */ + 0xd6444e39c3db9b09, /* 692: 1.0e+344 >> 1079 */ + 0x85eab0e41a6940e5, /* 693: 1.0e+345 >> 1083 */ + 0xa7655d1d2103911f, /* 694: 1.0e+346 >> 1086 */ + 0xd13eb46469447567, /* 695: 1.0e+347 >> 1089 */ +}; +#define POWERSOF10_FIRST (-348) +#define POWERSOF10_LAST (+347) +#define POWERSOF10_COUNT (696) + +/* +** Two inputs are multiplied to get a 128-bit result. Return +** the high-order 64 bits of that result. +*/ +static u64 sqlite3Multiply128(u64 a, u64 b){ +#if (defined(__GNUC__) || defined(__clang__)) \ + && (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) + return ((__uint128_t)a * b) >> 64; +#elif defined(_MSC_VER) && defined(_M_X64) + return __umulh(a, b); +#else + u32 a1 = (u32)a; + u32 a2 = a >> 32; + u32 b1 = (u32)b; + u32 b2 = b >> 32; + u32 p0 = a1 * b1; + u32 p1 = a1 * b2; + u32 p2 = a2 * b1; + u32 p3 = a2 * b2; + u32 mid = p1 + (p0 >> 32); + mid += p2; + u32 carry = (mid < p2) ? 1 : 0; + return p3 + (mid >> 32) + carry; +#endif +} -/* Double-Double multiplication. (x[0],x[1]) *= (y,yy) +/* +** pow10to2(x) computes floor(log2(pow(10,x))). +** pow2to10(y) computes floor(log10(pow(2,y))). +** +** Conceptually, pow10to2(p) converts a base-10 exponent p into +** a corresponding base-2 exponent, and pow2to10(e) converts a base-2 +** exponent into a base-10 exponent. +** +** The conversions are based on the observation that: ** -** Reference: -** T. J. Dekker, "A Floating-Point Technique for Extending the -** Available Precision". 1971-07-26. +** ln(10.0)/ln(2.0) == 108853/32768 (approximately) +** ln(2.0)/ln(10.0) == 78913/262144 (approximately) +** +** These ratios are approximate, but they are accurate to 5 digits, +** which is close enough for the usage here. Right-shift is used +** for division so that rounding of negative numbers happens in the +** right direction. */ -static void dekkerMul2(volatile double *x, double y, double yy){ - /* - ** The "volatile" keywords on parameter x[] and on local variables - ** below are needed force intermediate results to be truncated to - ** binary64 rather than be carried around in an extended-precision - ** format. The truncation is necessary for the Dekker algorithm to - ** work. Intel x86 floating point might omit the truncation without - ** the use of volatile. - */ - volatile double tx, ty, p, q, c, cc; - double hx, hy; - u64 m; - memcpy(&m, (void*)&x[0], 8); - m &= 0xfffffffffc000000LL; - memcpy(&hx, &m, 8); - tx = x[0] - hx; - memcpy(&m, &y, 8); - m &= 0xfffffffffc000000LL; - memcpy(&hy, &m, 8); - ty = y - hy; - p = hx*hy; - q = hx*ty + tx*hy; - c = p+q; - cc = p - c + q + tx*ty; - cc = x[0]*yy + x[1]*y + cc; - x[0] = c + cc; - x[1] = c - x[0]; - x[1] += cc; +static int pwr10to2(int p){ return (p*108853) >> 15; } +static int pwr2to10(int p){ return (p*78913) >> 18; } + +/* +** Return a u64 with the N-th bit set. +*/ +#define U64_BIT(N) (((u64)1)<<(N)) + +/* +** Count leading zeros for a 64-bit unsigned integer. +*/ +static int countLeadingZeros(u64 m){ +#if defined(__GNUC__) || defined(__clang__) + return __builtin_clzll(m); +#else + int n = 0; + if( m <= 0x00000000ffffffffULL) { n += 32; m <<= 32; } + if( m <= 0x0000ffffffffffffULL) { n += 16; m <<= 16; } + if( m <= 0x00ffffffffffffffULL) { n += 8; m <<= 8; } + if( m <= 0x0fffffffffffffffULL) { n += 4; m <<= 4; } + if( m <= 0x3fffffffffffffffULL) { n += 2; m <<= 2; } + if( m <= 0x7fffffffffffffffULL) { n += 1; } + return n; +#endif +} + +/* +** Given m and e, which represent a quantity r == m*pow(2,e), +** return values *pD and *pP such that r == (*pD)*pow(10,*pP), +** approximately. *pD should contain at least n significant digits. +** +** The input m is required to have its highest bit set. In other words, +** m should be left-shifted, and e decremented, to maximize the value of m. +*/ +static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){ + int p, idx; + u64 h, out; + p = n - 1 - pwr2to10(e+63); + idx = p - POWERSOF10_FIRST; + h = sqlite3Multiply128(m, sqlite3PowerOfTen[idx]); + assert( -(e + pwr10to2(p) + 3) >=0 ); + assert( -(e + pwr10to2(p) + 3) <64 ); + out = h >> -(e + pwr10to2(p) + 3); + *pD = (out + 2 + ((out>>2)&1)) >> 2; + *pP = -p; +} + +/* +** Return an IEEE754 floating point value that approximates d*pow(10,p). +** +** The "d" value must not have its most significant bit set. +*/ +static double sqlite3Fp10Convert2(u64 d, int p){ + u64 out; + int b; + int e1; + int e2; + int lp; + int idx; + u64 h; + double r; + if( pPOWERSOF10_LAST ){ + return INFINITY; + } + b = 64 - countLeadingZeros(d); + lp = pwr10to2(p); + e1 = 53 - b - lp; + if( e1>1074 ){ + if( -(b + lp) >= 1077 ) return 0.0; + e1 = 1074; + } + e2 = e1 - (64-b); + idx = p - POWERSOF10_FIRST; + h = sqlite3Multiply128(d<<(64-b), sqlite3PowerOfTen[idx]); + assert( -(e2 + lp + 3) >=0 ); + assert( -(e2 + lp + 3) <64 ); + out = (h >> -(e2 + lp + 3)) | 1; + if( out >= U64_BIT(55)-2 ){ + out = (out>>1) | (out&1); + e1--; + } + if( e1<=(-972) ){ + return INFINITY; + } + out = (out + 1 + ((out>>2)&1)) >> 2; + if( (out & U64_BIT(52))!=0 ){ + out = (out & ~U64_BIT(52)) | ((u64)(1075-e1)<<52); + } + memcpy(&r, &out, 8); + return r; } /* @@ -539,8 +1348,6 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ int eValid = 1; /* True exponent is either not used or is well-formed */ int nDigit = 0; /* Number of digits processed */ int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ - u64 s2; /* round-tripped significand */ - double rr[2]; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ @@ -578,7 +1385,7 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ while( z=((LARGEST_UINT64-9)/10) ){ + if( s>=((LARGEST_INT64-9)/10) ){ /* skip non-significant significand digits ** (increase exponent by d to shift decimal left) */ while( z0 && s<((LARGEST_UINT64-0x7ff)/10) ){ - s *= 10; - e--; - } - while( e<0 && (s%10)==0 ){ - s /= 10; - e++; - } - - rr[0] = (double)s; - assert( sizeof(s2)==sizeof(rr[0]) ); -#ifdef SQLITE_DEBUG - rr[1] = 18446744073709549568.0; - memcpy(&s2, &rr[1], sizeof(s2)); - assert( s2==0x43efffffffffffffLL ); -#endif - /* Largest double that can be safely converted to u64 - ** vvvvvvvvvvvvvvvvvvvvvv */ - if( rr[0]<=18446744073709549568.0 ){ - s2 = (u64)rr[0]; - rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); - }else{ - rr[1] = 0.0; - } - assert( rr[1]<=1.0e-10*rr[0] ); /* Equal only when rr[0]==0.0 */ - - if( e>0 ){ - while( e>=100 ){ - e -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( e>=10 ){ - e -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( e>=1 ){ - e -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); - } - }else{ - while( e<=-100 ){ - e += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( e<=-10 ){ - e += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( e<=-1 ){ - e += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); - } - } - *pResult = rr[0]+rr[1]; - if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300; + *pResult = sqlite3Fp10Convert2(s,e); if( sign<0 ) *pResult = -*pResult; assert( !sqlite3IsNaN(*pResult) ); @@ -1018,7 +1770,6 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ int i; u64 v; int e, exp = 0; - double rr[2]; p->isSpecial = 0; p->z = p->zBuf; @@ -1039,55 +1790,23 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ p->sign = '+'; } memcpy(&v,&r,8); - e = v>>52; - if( (e&0x7ff)==0x7ff ){ + e = (v>>52)&0x7ff; + if( e==0x7ff ){ p->isSpecial = 1 + (v!=0x7ff0000000000000LL); p->n = 0; p->iDP = 0; return; } - - /* Multiply r by powers of ten until it lands somewhere in between - ** 1.0e+19 and 1.0e+17. - ** - ** Use Dekker-style double-double computation to increase the - ** precision. - ** - ** The error terms on constants like 1.0e+100 computed using the - ** decimal extension, for example as follows: - ** - ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100))); - */ - rr[0] = r; - rr[1] = 0.0; - if( rr[0]>9.223372036854774784e+18 ){ - while( rr[0]>9.223372036854774784e+118 ){ - exp += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( rr[0]>9.223372036854774784e+28 ){ - exp += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( rr[0]>9.223372036854774784e+18 ){ - exp += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); - } + v &= 0x000fffffffffffffULL; + if( e==0 ){ + int n = countLeadingZeros(v); + v <<= n; + e = -1074 - n; }else{ - while( rr[0]<9.223372036854774784e-83 ){ - exp -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( rr[0]<9.223372036854774784e+07 ){ - exp -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( rr[0]<9.22337203685477478e+17 ){ - exp -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); - } + v = (v<<11) | U64_BIT(63); + e -= 1086; } - v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1]; + sqlite3Fp2Convert10(v, e, 17, &v, &exp); /* Extract significant digits. */ i = sizeof(p->zBuf)-1; From 10fb1e30778e6f7af95539551fd627c4dd2c0ca2 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 Feb 2026 19:36:41 +0000 Subject: [PATCH 009/197] Improved comment. No code changes. FossilOrigin-Name: c5a4da1bf7af8f8ec4b3273f88b09c01ce90986c8a5ce3d03319bd094706c411 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 13 +++++++++++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 06fb22038a..fd7cfaddd3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\sa\sprecomputed\stable\sof\s696\spowers\sof\s10\sto\simprove\sthe\sperformance\nof\sfloating-point\sto\sdecimal\sand\sdecimal\sto\sfloating-point\sconversions. -D 2026-02-14T17:58:46.735 +C Improved\scomment.\s\sNo\scode\schanges. +D 2026-02-14T19:36:41.565 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c cb0a38becd4eef1084eaf2838bffb3c1423a3bfbebfbeea179d30ac31c0f063b +F src/util.c ad807accd351c62850e561f9db5af343bba4428a9fe1dce92fc54646fb474c31 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 38d8c0d8a0b0e9990ba7bdcce979f2824ffee22a083cb788a75917628b1eb559 -R 698349c0b3cdc46d85eb51f40079e9df +P 64d9b7becf2da8927024adda278e837a46837e46af3cff51bd54a183d1716750 +R 32774ee04860dec8c41afee5d6cdd794 U drh -Z 17cef2cc342806b71491096998b8ccfe +Z 9b4ac557cc43dd0479d44740474b642c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a6e1b96c00..77c09872ea 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -64d9b7becf2da8927024adda278e837a46837e46af3cff51bd54a183d1716750 +c5a4da1bf7af8f8ec4b3273f88b09c01ce90986c8a5ce3d03319bd094706c411 diff --git a/src/util.c b/src/util.c index 40a3bf0e2a..04d87b0906 100644 --- a/src/util.c +++ b/src/util.c @@ -461,6 +461,19 @@ u8 sqlite3StrIHash(const char *z){ ** The following array holds (approximate) powers-of-ten between ** 1.0e-348 and 1.0e+347. Each value is an unsigned 64-bit integer, ** shifted so that its most significant bit is 1. +** +** For the power-of-ten whose value is pow(10,p), the value +** is shifted left or right in order to multiply it by +** pow(2,63-pow10to2(p)). Hence, another way to think of the +** entries in this table is: +** +** for p from -348 to +347: +** int( pow(10,p)*pow(2,63-pow10to2(p)) ) +** +** The int(x) function means the integer part of value x. See +** the definition of pow10to2() below for more details about that +** function. There is an assert() in the utility program that +** generates this table that verifies the invariant described above. */ static const u64 sqlite3PowerOfTen[] = { 0xfa8fd5a0081c0288, /* 0: 1.0e-348 << 1220 */ From 4d0611c1ebf930af66e9876e7a59c4f205964db4 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 Feb 2026 19:42:55 +0000 Subject: [PATCH 010/197] Minor corrections. FossilOrigin-Name: 93fdee20021b8cc2a113ea042fedbccd8b53b6aceeeb34c0810e6d3a5f106f07 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index fd7cfaddd3..9850fcd8eb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\scomment.\s\sNo\scode\schanges. -D 2026-02-14T19:36:41.565 +C Minor\scorrections. +D 2026-02-14T19:42:55.437 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c ad807accd351c62850e561f9db5af343bba4428a9fe1dce92fc54646fb474c31 +F src/util.c d61abbf3b7f847dd50ce22acf058a1c655340306404c6c7a3dca82e0163d8f0b F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 64d9b7becf2da8927024adda278e837a46837e46af3cff51bd54a183d1716750 -R 32774ee04860dec8c41afee5d6cdd794 +P c5a4da1bf7af8f8ec4b3273f88b09c01ce90986c8a5ce3d03319bd094706c411 +R 7fcc5141a9c1b98b1ccfeeaa3a1bba48 U drh -Z 9b4ac557cc43dd0479d44740474b642c +Z cf7b408004d4308aa433deccabaff64f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 77c09872ea..928dec8bd2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c5a4da1bf7af8f8ec4b3273f88b09c01ce90986c8a5ce3d03319bd094706c411 +93fdee20021b8cc2a113ea042fedbccd8b53b6aceeeb34c0810e6d3a5f106f07 diff --git a/src/util.c b/src/util.c index 04d87b0906..fc0f5d9021 100644 --- a/src/util.c +++ b/src/util.c @@ -1270,8 +1270,6 @@ static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){ /* ** Return an IEEE754 floating point value that approximates d*pow(10,p). -** -** The "d" value must not have its most significant bit set. */ static double sqlite3Fp10Convert2(u64 d, int p){ u64 out; @@ -1282,7 +1280,9 @@ static double sqlite3Fp10Convert2(u64 d, int p){ int idx; u64 h; double r; - if( pPOWERSOF10_LAST ){ From 4bee65dcb97b772b682e49def78f26d0a3400cbf Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 Feb 2026 20:48:58 +0000 Subject: [PATCH 011/197] Another minor performance refinement. FossilOrigin-Name: 9d3a12d3926d55efffdc84bff342bd1dbccd08426104aeb2d339b064bf6f02f4 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqliteInt.h | 1 + src/util.c | 12 ++++++++---- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 9850fcd8eb..a9a9ebd545 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\scorrections. -D 2026-02-14T19:42:55.437 +C Another\sminor\sperformance\srefinement. +D 2026-02-14T20:48:58.637 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -743,7 +743,7 @@ F src/shell.c.in b944a21d98cc4c6107bfd1ec702440579cb4bf86435125b67ff661180e9453b F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h 7f42e42286634092758864472ea445feb45e654c1659b7f5e723ea70939b34dc +F src/sqliteInt.h b30f6ec44e695d00d83f83bdf3b8dd31a6537c48d909c7abb78643c49784d988 F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -803,7 +803,7 @@ F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c d61abbf3b7f847dd50ce22acf058a1c655340306404c6c7a3dca82e0163d8f0b +F src/util.c dcb787b77edcaf0f89b64e565d54a5edb209542e58a9486011ea4c02b6c6c429 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P c5a4da1bf7af8f8ec4b3273f88b09c01ce90986c8a5ce3d03319bd094706c411 -R 7fcc5141a9c1b98b1ccfeeaa3a1bba48 +P 93fdee20021b8cc2a113ea042fedbccd8b53b6aceeeb34c0810e6d3a5f106f07 +R 18d39bc4715509a368296882a035272e U drh -Z cf7b408004d4308aa433deccabaff64f +Z b2a09b8ec1a49f705731dfc617a2c1b1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 928dec8bd2..c15c2cda97 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -93fdee20021b8cc2a113ea042fedbccd8b53b6aceeeb34c0810e6d3a5f106f07 +9d3a12d3926d55efffdc84bff342bd1dbccd08426104aeb2d339b064bf6f02f4 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 664b8afd95..e10467e8ec 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1070,6 +1070,7 @@ typedef INT16_TYPE LogEst; #else # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) #endif +#define TWO_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&1)==0) /* ** Disable MMAP on platforms where it is known to not work diff --git a/src/util.c b/src/util.c index fc0f5d9021..c87f120b2e 100644 --- a/src/util.c +++ b/src/util.c @@ -1837,12 +1837,16 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ "80818283848586878889" "90919293949596979899"; int kk = (v%100)*2; - p->zBuf[i] = dig[kk+1]; - p->zBuf[i-1] = dig[kk]; + assert( TWO_BYTE_ALIGNMENT(&dig[kk]) ); + assert( TWO_BYTE_ALIGNMENT(&p->zBuf[i-1]) ); + *(u16*)(&p->zBuf[i-1]) = *(u16*)&dig[kk]; i -= 2; - v /=100; + v /= 100; + } + if( v ){ + assert( v<10 ); + p->zBuf[i--] = v + '0'; } - if( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; } assert( i>=0 && izBuf)-1 ); p->n = sizeof(p->zBuf) - 1 - i; assert( p->n>0 ); From 775e4b7073e5c5c9c2fd6247112d7877541c77ca Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 Feb 2026 21:31:31 +0000 Subject: [PATCH 012/197] Fix to the generic version of the 128-bit multiple subroutine. FossilOrigin-Name: 9c3d09ee75beb26447161c0bf5ea252520a6ec051774f1a4e9f18204281d504f --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 22 ++++++++++------------ 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index a9a9ebd545..79d264e866 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Another\sminor\sperformance\srefinement. -D 2026-02-14T20:48:58.637 +C Fix\sto\sthe\sgeneric\sversion\sof\sthe\s128-bit\smultiple\ssubroutine. +D 2026-02-14T21:31:31.986 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c dcb787b77edcaf0f89b64e565d54a5edb209542e58a9486011ea4c02b6c6c429 +F src/util.c 7a7c52c4a5a5df105fd1241d93a775089f912f385eb3487c7b0d596f9ce2c7d2 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 93fdee20021b8cc2a113ea042fedbccd8b53b6aceeeb34c0810e6d3a5f106f07 -R 18d39bc4715509a368296882a035272e +P 9d3a12d3926d55efffdc84bff342bd1dbccd08426104aeb2d339b064bf6f02f4 +R b8f25725ba219a819a702d1e3e67df67 U drh -Z b2a09b8ec1a49f705731dfc617a2c1b1 +Z 27cc9fc5582f41e3830c232fedfd6c40 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c15c2cda97..bdcb0bb63a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9d3a12d3926d55efffdc84bff342bd1dbccd08426104aeb2d339b064bf6f02f4 +9c3d09ee75beb26447161c0bf5ea252520a6ec051774f1a4e9f18204281d504f diff --git a/src/util.c b/src/util.c index c87f120b2e..68d9471e6e 100644 --- a/src/util.c +++ b/src/util.c @@ -1188,18 +1188,16 @@ static u64 sqlite3Multiply128(u64 a, u64 b){ #elif defined(_MSC_VER) && defined(_M_X64) return __umulh(a, b); #else - u32 a1 = (u32)a; - u32 a2 = a >> 32; - u32 b1 = (u32)b; - u32 b2 = b >> 32; - u32 p0 = a1 * b1; - u32 p1 = a1 * b2; - u32 p2 = a2 * b1; - u32 p3 = a2 * b2; - u32 mid = p1 + (p0 >> 32); - mid += p2; - u32 carry = (mid < p2) ? 1 : 0; - return p3 + (mid >> 32) + carry; + u64 a1 = (u32)a; + u64 a2 = a >> 32; + u64 b1 = (u32)b; + u64 b2 = b >> 32; + u64 p0 = a1 * b1; + u64 p1 = a1 * b2; + u64 p2 = a2 * b1; + u64 p3 = a2 * b2; + u64 carry = ((p0 >> 32) + (u32)p1 + (u32)p2) >> 32; + return p3 + (p1 >> 32) + (p2 >> 32) + carry; #endif } From b3b2695d4b2526348d505211173fefe54da482ba Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 Feb 2026 21:47:08 +0000 Subject: [PATCH 013/197] Add the "LLU" suffix to 64-bit integer constants, for portability to older compilers. FossilOrigin-Name: 4bf08110662c4b8db9ee90ce34271890a62a469166ea292f7f782b84236531d4 --- manifest | 12 +- manifest.uuid | 2 +- src/util.c | 1392 ++++++++++++++++++++++++------------------------- 3 files changed, 703 insertions(+), 703 deletions(-) diff --git a/manifest b/manifest index 79d264e866..a4253c97de 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sto\sthe\sgeneric\sversion\sof\sthe\s128-bit\smultiple\ssubroutine. -D 2026-02-14T21:31:31.986 +C Add\sthe\s"LLU"\ssuffix\sto\s64-bit\sinteger\sconstants,\sfor\sportability\sto\solder\ncompilers. +D 2026-02-14T21:47:08.084 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 7a7c52c4a5a5df105fd1241d93a775089f912f385eb3487c7b0d596f9ce2c7d2 +F src/util.c d7cd5a4c9859c260b17d3e2d821306a265f6a4d0962941a1d187b4ccaf74c455 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 9d3a12d3926d55efffdc84bff342bd1dbccd08426104aeb2d339b064bf6f02f4 -R b8f25725ba219a819a702d1e3e67df67 +P 9c3d09ee75beb26447161c0bf5ea252520a6ec051774f1a4e9f18204281d504f +R 81af0af5ea2a6b0d90ff8f5528e1d00d U drh -Z 27cc9fc5582f41e3830c232fedfd6c40 +Z d1c5742bcc364eb12a36c71331cc2f0e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bdcb0bb63a..1f157b26f3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9c3d09ee75beb26447161c0bf5ea252520a6ec051774f1a4e9f18204281d504f +4bf08110662c4b8db9ee90ce34271890a62a469166ea292f7f782b84236531d4 diff --git a/src/util.c b/src/util.c index 68d9471e6e..b0ab7dde3a 100644 --- a/src/util.c +++ b/src/util.c @@ -476,702 +476,702 @@ u8 sqlite3StrIHash(const char *z){ ** generates this table that verifies the invariant described above. */ static const u64 sqlite3PowerOfTen[] = { - 0xfa8fd5a0081c0288, /* 0: 1.0e-348 << 1220 */ - 0x9c99e58405118195, /* 1: 1.0e-347 << 1216 */ - 0xc3c05ee50655e1fa, /* 2: 1.0e-346 << 1213 */ - 0xf4b0769e47eb5a78, /* 3: 1.0e-345 << 1210 */ - 0x98ee4a22ecf3188b, /* 4: 1.0e-344 << 1206 */ - 0xbf29dcaba82fdeae, /* 5: 1.0e-343 << 1203 */ - 0xeef453d6923bd65a, /* 6: 1.0e-342 << 1200 */ - 0x9558b4661b6565f8, /* 7: 1.0e-341 << 1196 */ - 0xbaaee17fa23ebf76, /* 8: 1.0e-340 << 1193 */ - 0xe95a99df8ace6f53, /* 9: 1.0e-339 << 1190 */ - 0x91d8a02bb6c10594, /* 10: 1.0e-338 << 1186 */ - 0xb64ec836a47146f9, /* 11: 1.0e-337 << 1183 */ - 0xe3e27a444d8d98b7, /* 12: 1.0e-336 << 1180 */ - 0x8e6d8c6ab0787f72, /* 13: 1.0e-335 << 1176 */ - 0xb208ef855c969f4f, /* 14: 1.0e-334 << 1173 */ - 0xde8b2b66b3bc4723, /* 15: 1.0e-333 << 1170 */ - 0x8b16fb203055ac76, /* 16: 1.0e-332 << 1166 */ - 0xaddcb9e83c6b1793, /* 17: 1.0e-331 << 1163 */ - 0xd953e8624b85dd78, /* 18: 1.0e-330 << 1160 */ - 0x87d4713d6f33aa6b, /* 19: 1.0e-329 << 1156 */ - 0xa9c98d8ccb009506, /* 20: 1.0e-328 << 1153 */ - 0xd43bf0effdc0ba48, /* 21: 1.0e-327 << 1150 */ - 0x84a57695fe98746d, /* 22: 1.0e-326 << 1146 */ - 0xa5ced43b7e3e9188, /* 23: 1.0e-325 << 1143 */ - 0xcf42894a5dce35ea, /* 24: 1.0e-324 << 1140 */ - 0x818995ce7aa0e1b2, /* 25: 1.0e-323 << 1136 */ - 0xa1ebfb4219491a1f, /* 26: 1.0e-322 << 1133 */ - 0xca66fa129f9b60a6, /* 27: 1.0e-321 << 1130 */ - 0xfd00b897478238d0, /* 28: 1.0e-320 << 1127 */ - 0x9e20735e8cb16382, /* 29: 1.0e-319 << 1123 */ - 0xc5a890362fddbc62, /* 30: 1.0e-318 << 1120 */ - 0xf712b443bbd52b7b, /* 31: 1.0e-317 << 1117 */ - 0x9a6bb0aa55653b2d, /* 32: 1.0e-316 << 1113 */ - 0xc1069cd4eabe89f8, /* 33: 1.0e-315 << 1110 */ - 0xf148440a256e2c76, /* 34: 1.0e-314 << 1107 */ - 0x96cd2a865764dbca, /* 35: 1.0e-313 << 1103 */ - 0xbc807527ed3e12bc, /* 36: 1.0e-312 << 1100 */ - 0xeba09271e88d976b, /* 37: 1.0e-311 << 1097 */ - 0x93445b8731587ea3, /* 38: 1.0e-310 << 1093 */ - 0xb8157268fdae9e4c, /* 39: 1.0e-309 << 1090 */ - 0xe61acf033d1a45df, /* 40: 1.0e-308 << 1087 */ - 0x8fd0c16206306bab, /* 41: 1.0e-307 << 1083 */ - 0xb3c4f1ba87bc8696, /* 42: 1.0e-306 << 1080 */ - 0xe0b62e2929aba83c, /* 43: 1.0e-305 << 1077 */ - 0x8c71dcd9ba0b4925, /* 44: 1.0e-304 << 1073 */ - 0xaf8e5410288e1b6f, /* 45: 1.0e-303 << 1070 */ - 0xdb71e91432b1a24a, /* 46: 1.0e-302 << 1067 */ - 0x892731ac9faf056e, /* 47: 1.0e-301 << 1063 */ - 0xab70fe17c79ac6ca, /* 48: 1.0e-300 << 1060 */ - 0xd64d3d9db981787d, /* 49: 1.0e-299 << 1057 */ - 0x85f0468293f0eb4e, /* 50: 1.0e-298 << 1053 */ - 0xa76c582338ed2621, /* 51: 1.0e-297 << 1050 */ - 0xd1476e2c07286faa, /* 52: 1.0e-296 << 1047 */ - 0x82cca4db847945ca, /* 53: 1.0e-295 << 1043 */ - 0xa37fce126597973c, /* 54: 1.0e-294 << 1040 */ - 0xcc5fc196fefd7d0c, /* 55: 1.0e-293 << 1037 */ - 0xff77b1fcbebcdc4f, /* 56: 1.0e-292 << 1034 */ - 0x9faacf3df73609b1, /* 57: 1.0e-291 << 1030 */ - 0xc795830d75038c1d, /* 58: 1.0e-290 << 1027 */ - 0xf97ae3d0d2446f25, /* 59: 1.0e-289 << 1024 */ - 0x9becce62836ac577, /* 60: 1.0e-288 << 1020 */ - 0xc2e801fb244576d5, /* 61: 1.0e-287 << 1017 */ - 0xf3a20279ed56d48a, /* 62: 1.0e-286 << 1014 */ - 0x9845418c345644d6, /* 63: 1.0e-285 << 1010 */ - 0xbe5691ef416bd60c, /* 64: 1.0e-284 << 1007 */ - 0xedec366b11c6cb8f, /* 65: 1.0e-283 << 1004 */ - 0x94b3a202eb1c3f39, /* 66: 1.0e-282 << 1000 */ - 0xb9e08a83a5e34f07, /* 67: 1.0e-281 << 997 */ - 0xe858ad248f5c22c9, /* 68: 1.0e-280 << 994 */ - 0x91376c36d99995be, /* 69: 1.0e-279 << 990 */ - 0xb58547448ffffb2d, /* 70: 1.0e-278 << 987 */ - 0xe2e69915b3fff9f9, /* 71: 1.0e-277 << 984 */ - 0x8dd01fad907ffc3b, /* 72: 1.0e-276 << 980 */ - 0xb1442798f49ffb4a, /* 73: 1.0e-275 << 977 */ - 0xdd95317f31c7fa1d, /* 74: 1.0e-274 << 974 */ - 0x8a7d3eef7f1cfc52, /* 75: 1.0e-273 << 970 */ - 0xad1c8eab5ee43b66, /* 76: 1.0e-272 << 967 */ - 0xd863b256369d4a40, /* 77: 1.0e-271 << 964 */ - 0x873e4f75e2224e68, /* 78: 1.0e-270 << 960 */ - 0xa90de3535aaae202, /* 79: 1.0e-269 << 957 */ - 0xd3515c2831559a83, /* 80: 1.0e-268 << 954 */ - 0x8412d9991ed58091, /* 81: 1.0e-267 << 950 */ - 0xa5178fff668ae0b6, /* 82: 1.0e-266 << 947 */ - 0xce5d73ff402d98e3, /* 83: 1.0e-265 << 944 */ - 0x80fa687f881c7f8e, /* 84: 1.0e-264 << 940 */ - 0xa139029f6a239f72, /* 85: 1.0e-263 << 937 */ - 0xc987434744ac874e, /* 86: 1.0e-262 << 934 */ - 0xfbe9141915d7a922, /* 87: 1.0e-261 << 931 */ - 0x9d71ac8fada6c9b5, /* 88: 1.0e-260 << 927 */ - 0xc4ce17b399107c22, /* 89: 1.0e-259 << 924 */ - 0xf6019da07f549b2b, /* 90: 1.0e-258 << 921 */ - 0x99c102844f94e0fb, /* 91: 1.0e-257 << 917 */ - 0xc0314325637a1939, /* 92: 1.0e-256 << 914 */ - 0xf03d93eebc589f88, /* 93: 1.0e-255 << 911 */ - 0x96267c7535b763b5, /* 94: 1.0e-254 << 907 */ - 0xbbb01b9283253ca2, /* 95: 1.0e-253 << 904 */ - 0xea9c227723ee8bcb, /* 96: 1.0e-252 << 901 */ - 0x92a1958a7675175f, /* 97: 1.0e-251 << 897 */ - 0xb749faed14125d36, /* 98: 1.0e-250 << 894 */ - 0xe51c79a85916f484, /* 99: 1.0e-249 << 891 */ - 0x8f31cc0937ae58d2, /* 100: 1.0e-248 << 887 */ - 0xb2fe3f0b8599ef07, /* 101: 1.0e-247 << 884 */ - 0xdfbdcece67006ac9, /* 102: 1.0e-246 << 881 */ - 0x8bd6a141006042bd, /* 103: 1.0e-245 << 877 */ - 0xaecc49914078536d, /* 104: 1.0e-244 << 874 */ - 0xda7f5bf590966848, /* 105: 1.0e-243 << 871 */ - 0x888f99797a5e012d, /* 106: 1.0e-242 << 867 */ - 0xaab37fd7d8f58178, /* 107: 1.0e-241 << 864 */ - 0xd5605fcdcf32e1d6, /* 108: 1.0e-240 << 861 */ - 0x855c3be0a17fcd26, /* 109: 1.0e-239 << 857 */ - 0xa6b34ad8c9dfc06f, /* 110: 1.0e-238 << 854 */ - 0xd0601d8efc57b08b, /* 111: 1.0e-237 << 851 */ - 0x823c12795db6ce57, /* 112: 1.0e-236 << 847 */ - 0xa2cb1717b52481ed, /* 113: 1.0e-235 << 844 */ - 0xcb7ddcdda26da268, /* 114: 1.0e-234 << 841 */ - 0xfe5d54150b090b02, /* 115: 1.0e-233 << 838 */ - 0x9efa548d26e5a6e1, /* 116: 1.0e-232 << 834 */ - 0xc6b8e9b0709f109a, /* 117: 1.0e-231 << 831 */ - 0xf867241c8cc6d4c0, /* 118: 1.0e-230 << 828 */ - 0x9b407691d7fc44f8, /* 119: 1.0e-229 << 824 */ - 0xc21094364dfb5636, /* 120: 1.0e-228 << 821 */ - 0xf294b943e17a2bc4, /* 121: 1.0e-227 << 818 */ - 0x979cf3ca6cec5b5a, /* 122: 1.0e-226 << 814 */ - 0xbd8430bd08277231, /* 123: 1.0e-225 << 811 */ - 0xece53cec4a314ebd, /* 124: 1.0e-224 << 808 */ - 0x940f4613ae5ed136, /* 125: 1.0e-223 << 804 */ - 0xb913179899f68584, /* 126: 1.0e-222 << 801 */ - 0xe757dd7ec07426e5, /* 127: 1.0e-221 << 798 */ - 0x9096ea6f3848984f, /* 128: 1.0e-220 << 794 */ - 0xb4bca50b065abe63, /* 129: 1.0e-219 << 791 */ - 0xe1ebce4dc7f16dfb, /* 130: 1.0e-218 << 788 */ - 0x8d3360f09cf6e4bd, /* 131: 1.0e-217 << 784 */ - 0xb080392cc4349dec, /* 132: 1.0e-216 << 781 */ - 0xdca04777f541c567, /* 133: 1.0e-215 << 778 */ - 0x89e42caaf9491b60, /* 134: 1.0e-214 << 774 */ - 0xac5d37d5b79b6239, /* 135: 1.0e-213 << 771 */ - 0xd77485cb25823ac7, /* 136: 1.0e-212 << 768 */ - 0x86a8d39ef77164bc, /* 137: 1.0e-211 << 764 */ - 0xa8530886b54dbdeb, /* 138: 1.0e-210 << 761 */ - 0xd267caa862a12d66, /* 139: 1.0e-209 << 758 */ - 0x8380dea93da4bc60, /* 140: 1.0e-208 << 754 */ - 0xa46116538d0deb78, /* 141: 1.0e-207 << 751 */ - 0xcd795be870516656, /* 142: 1.0e-206 << 748 */ - 0x806bd9714632dff6, /* 143: 1.0e-205 << 744 */ - 0xa086cfcd97bf97f3, /* 144: 1.0e-204 << 741 */ - 0xc8a883c0fdaf7df0, /* 145: 1.0e-203 << 738 */ - 0xfad2a4b13d1b5d6c, /* 146: 1.0e-202 << 735 */ - 0x9cc3a6eec6311a63, /* 147: 1.0e-201 << 731 */ - 0xc3f490aa77bd60fc, /* 148: 1.0e-200 << 728 */ - 0xf4f1b4d515acb93b, /* 149: 1.0e-199 << 725 */ - 0x991711052d8bf3c5, /* 150: 1.0e-198 << 721 */ - 0xbf5cd54678eef0b6, /* 151: 1.0e-197 << 718 */ - 0xef340a98172aace4, /* 152: 1.0e-196 << 715 */ - 0x9580869f0e7aac0e, /* 153: 1.0e-195 << 711 */ - 0xbae0a846d2195712, /* 154: 1.0e-194 << 708 */ - 0xe998d258869facd7, /* 155: 1.0e-193 << 705 */ - 0x91ff83775423cc06, /* 156: 1.0e-192 << 701 */ - 0xb67f6455292cbf08, /* 157: 1.0e-191 << 698 */ - 0xe41f3d6a7377eeca, /* 158: 1.0e-190 << 695 */ - 0x8e938662882af53e, /* 159: 1.0e-189 << 691 */ - 0xb23867fb2a35b28d, /* 160: 1.0e-188 << 688 */ - 0xdec681f9f4c31f31, /* 161: 1.0e-187 << 685 */ - 0x8b3c113c38f9f37e, /* 162: 1.0e-186 << 681 */ - 0xae0b158b4738705e, /* 163: 1.0e-185 << 678 */ - 0xd98ddaee19068c76, /* 164: 1.0e-184 << 675 */ - 0x87f8a8d4cfa417c9, /* 165: 1.0e-183 << 671 */ - 0xa9f6d30a038d1dbc, /* 166: 1.0e-182 << 668 */ - 0xd47487cc8470652b, /* 167: 1.0e-181 << 665 */ - 0x84c8d4dfd2c63f3b, /* 168: 1.0e-180 << 661 */ - 0xa5fb0a17c777cf09, /* 169: 1.0e-179 << 658 */ - 0xcf79cc9db955c2cc, /* 170: 1.0e-178 << 655 */ - 0x81ac1fe293d599bf, /* 171: 1.0e-177 << 651 */ - 0xa21727db38cb002f, /* 172: 1.0e-176 << 648 */ - 0xca9cf1d206fdc03b, /* 173: 1.0e-175 << 645 */ - 0xfd442e4688bd304a, /* 174: 1.0e-174 << 642 */ - 0x9e4a9cec15763e2e, /* 175: 1.0e-173 << 638 */ - 0xc5dd44271ad3cdba, /* 176: 1.0e-172 << 635 */ - 0xf7549530e188c128, /* 177: 1.0e-171 << 632 */ - 0x9a94dd3e8cf578b9, /* 178: 1.0e-170 << 628 */ - 0xc13a148e3032d6e7, /* 179: 1.0e-169 << 625 */ - 0xf18899b1bc3f8ca1, /* 180: 1.0e-168 << 622 */ - 0x96f5600f15a7b7e5, /* 181: 1.0e-167 << 618 */ - 0xbcb2b812db11a5de, /* 182: 1.0e-166 << 615 */ - 0xebdf661791d60f56, /* 183: 1.0e-165 << 612 */ - 0x936b9fcebb25c995, /* 184: 1.0e-164 << 608 */ - 0xb84687c269ef3bfb, /* 185: 1.0e-163 << 605 */ - 0xe65829b3046b0afa, /* 186: 1.0e-162 << 602 */ - 0x8ff71a0fe2c2e6dc, /* 187: 1.0e-161 << 598 */ - 0xb3f4e093db73a093, /* 188: 1.0e-160 << 595 */ - 0xe0f218b8d25088b8, /* 189: 1.0e-159 << 592 */ - 0x8c974f7383725573, /* 190: 1.0e-158 << 588 */ - 0xafbd2350644eeacf, /* 191: 1.0e-157 << 585 */ - 0xdbac6c247d62a583, /* 192: 1.0e-156 << 582 */ - 0x894bc396ce5da772, /* 193: 1.0e-155 << 578 */ - 0xab9eb47c81f5114f, /* 194: 1.0e-154 << 575 */ - 0xd686619ba27255a2, /* 195: 1.0e-153 << 572 */ - 0x8613fd0145877585, /* 196: 1.0e-152 << 568 */ - 0xa798fc4196e952e7, /* 197: 1.0e-151 << 565 */ - 0xd17f3b51fca3a7a0, /* 198: 1.0e-150 << 562 */ - 0x82ef85133de648c4, /* 199: 1.0e-149 << 558 */ - 0xa3ab66580d5fdaf5, /* 200: 1.0e-148 << 555 */ - 0xcc963fee10b7d1b3, /* 201: 1.0e-147 << 552 */ - 0xffbbcfe994e5c61f, /* 202: 1.0e-146 << 549 */ - 0x9fd561f1fd0f9bd3, /* 203: 1.0e-145 << 545 */ - 0xc7caba6e7c5382c8, /* 204: 1.0e-144 << 542 */ - 0xf9bd690a1b68637b, /* 205: 1.0e-143 << 539 */ - 0x9c1661a651213e2d, /* 206: 1.0e-142 << 535 */ - 0xc31bfa0fe5698db8, /* 207: 1.0e-141 << 532 */ - 0xf3e2f893dec3f126, /* 208: 1.0e-140 << 529 */ - 0x986ddb5c6b3a76b7, /* 209: 1.0e-139 << 525 */ - 0xbe89523386091465, /* 210: 1.0e-138 << 522 */ - 0xee2ba6c0678b597f, /* 211: 1.0e-137 << 519 */ - 0x94db483840b717ef, /* 212: 1.0e-136 << 515 */ - 0xba121a4650e4ddeb, /* 213: 1.0e-135 << 512 */ - 0xe896a0d7e51e1566, /* 214: 1.0e-134 << 509 */ - 0x915e2486ef32cd60, /* 215: 1.0e-133 << 505 */ - 0xb5b5ada8aaff80b8, /* 216: 1.0e-132 << 502 */ - 0xe3231912d5bf60e6, /* 217: 1.0e-131 << 499 */ - 0x8df5efabc5979c8f, /* 218: 1.0e-130 << 495 */ - 0xb1736b96b6fd83b3, /* 219: 1.0e-129 << 492 */ - 0xddd0467c64bce4a0, /* 220: 1.0e-128 << 489 */ - 0x8aa22c0dbef60ee4, /* 221: 1.0e-127 << 485 */ - 0xad4ab7112eb3929d, /* 222: 1.0e-126 << 482 */ - 0xd89d64d57a607744, /* 223: 1.0e-125 << 479 */ - 0x87625f056c7c4a8b, /* 224: 1.0e-124 << 475 */ - 0xa93af6c6c79b5d2d, /* 225: 1.0e-123 << 472 */ - 0xd389b47879823479, /* 226: 1.0e-122 << 469 */ - 0x843610cb4bf160cb, /* 227: 1.0e-121 << 465 */ - 0xa54394fe1eedb8fe, /* 228: 1.0e-120 << 462 */ - 0xce947a3da6a9273e, /* 229: 1.0e-119 << 459 */ - 0x811ccc668829b887, /* 230: 1.0e-118 << 455 */ - 0xa163ff802a3426a8, /* 231: 1.0e-117 << 452 */ - 0xc9bcff6034c13052, /* 232: 1.0e-116 << 449 */ - 0xfc2c3f3841f17c67, /* 233: 1.0e-115 << 446 */ - 0x9d9ba7832936edc0, /* 234: 1.0e-114 << 442 */ - 0xc5029163f384a931, /* 235: 1.0e-113 << 439 */ - 0xf64335bcf065d37d, /* 236: 1.0e-112 << 436 */ - 0x99ea0196163fa42e, /* 237: 1.0e-111 << 432 */ - 0xc06481fb9bcf8d39, /* 238: 1.0e-110 << 429 */ - 0xf07da27a82c37088, /* 239: 1.0e-109 << 426 */ - 0x964e858c91ba2655, /* 240: 1.0e-108 << 422 */ - 0xbbe226efb628afea, /* 241: 1.0e-107 << 419 */ - 0xeadab0aba3b2dbe5, /* 242: 1.0e-106 << 416 */ - 0x92c8ae6b464fc96f, /* 243: 1.0e-105 << 412 */ - 0xb77ada0617e3bbcb, /* 244: 1.0e-104 << 409 */ - 0xe55990879ddcaabd, /* 245: 1.0e-103 << 406 */ - 0x8f57fa54c2a9eab6, /* 246: 1.0e-102 << 402 */ - 0xb32df8e9f3546564, /* 247: 1.0e-101 << 399 */ - 0xdff9772470297ebd, /* 248: 1.0e-100 << 396 */ - 0x8bfbea76c619ef36, /* 249: 1.0e-99 << 392 */ - 0xaefae51477a06b03, /* 250: 1.0e-98 << 389 */ - 0xdab99e59958885c4, /* 251: 1.0e-97 << 386 */ - 0x88b402f7fd75539b, /* 252: 1.0e-96 << 382 */ - 0xaae103b5fcd2a881, /* 253: 1.0e-95 << 379 */ - 0xd59944a37c0752a2, /* 254: 1.0e-94 << 376 */ - 0x857fcae62d8493a5, /* 255: 1.0e-93 << 372 */ - 0xa6dfbd9fb8e5b88e, /* 256: 1.0e-92 << 369 */ - 0xd097ad07a71f26b2, /* 257: 1.0e-91 << 366 */ - 0x825ecc24c873782f, /* 258: 1.0e-90 << 362 */ - 0xa2f67f2dfa90563b, /* 259: 1.0e-89 << 359 */ - 0xcbb41ef979346bca, /* 260: 1.0e-88 << 356 */ - 0xfea126b7d78186bc, /* 261: 1.0e-87 << 353 */ - 0x9f24b832e6b0f436, /* 262: 1.0e-86 << 349 */ - 0xc6ede63fa05d3143, /* 263: 1.0e-85 << 346 */ - 0xf8a95fcf88747d94, /* 264: 1.0e-84 << 343 */ - 0x9b69dbe1b548ce7c, /* 265: 1.0e-83 << 339 */ - 0xc24452da229b021b, /* 266: 1.0e-82 << 336 */ - 0xf2d56790ab41c2a2, /* 267: 1.0e-81 << 333 */ - 0x97c560ba6b0919a5, /* 268: 1.0e-80 << 329 */ - 0xbdb6b8e905cb600f, /* 269: 1.0e-79 << 326 */ - 0xed246723473e3813, /* 270: 1.0e-78 << 323 */ - 0x9436c0760c86e30b, /* 271: 1.0e-77 << 319 */ - 0xb94470938fa89bce, /* 272: 1.0e-76 << 316 */ - 0xe7958cb87392c2c2, /* 273: 1.0e-75 << 313 */ - 0x90bd77f3483bb9b9, /* 274: 1.0e-74 << 309 */ - 0xb4ecd5f01a4aa828, /* 275: 1.0e-73 << 306 */ - 0xe2280b6c20dd5232, /* 276: 1.0e-72 << 303 */ - 0x8d590723948a535f, /* 277: 1.0e-71 << 299 */ - 0xb0af48ec79ace837, /* 278: 1.0e-70 << 296 */ - 0xdcdb1b2798182244, /* 279: 1.0e-69 << 293 */ - 0x8a08f0f8bf0f156b, /* 280: 1.0e-68 << 289 */ - 0xac8b2d36eed2dac5, /* 281: 1.0e-67 << 286 */ - 0xd7adf884aa879177, /* 282: 1.0e-66 << 283 */ - 0x86ccbb52ea94baea, /* 283: 1.0e-65 << 279 */ - 0xa87fea27a539e9a5, /* 284: 1.0e-64 << 276 */ - 0xd29fe4b18e88640e, /* 285: 1.0e-63 << 273 */ - 0x83a3eeeef9153e89, /* 286: 1.0e-62 << 269 */ - 0xa48ceaaab75a8e2b, /* 287: 1.0e-61 << 266 */ - 0xcdb02555653131b6, /* 288: 1.0e-60 << 263 */ - 0x808e17555f3ebf11, /* 289: 1.0e-59 << 259 */ - 0xa0b19d2ab70e6ed6, /* 290: 1.0e-58 << 256 */ - 0xc8de047564d20a8b, /* 291: 1.0e-57 << 253 */ - 0xfb158592be068d2e, /* 292: 1.0e-56 << 250 */ - 0x9ced737bb6c4183d, /* 293: 1.0e-55 << 246 */ - 0xc428d05aa4751e4c, /* 294: 1.0e-54 << 243 */ - 0xf53304714d9265df, /* 295: 1.0e-53 << 240 */ - 0x993fe2c6d07b7fab, /* 296: 1.0e-52 << 236 */ - 0xbf8fdb78849a5f96, /* 297: 1.0e-51 << 233 */ - 0xef73d256a5c0f77c, /* 298: 1.0e-50 << 230 */ - 0x95a8637627989aad, /* 299: 1.0e-49 << 226 */ - 0xbb127c53b17ec159, /* 300: 1.0e-48 << 223 */ - 0xe9d71b689dde71af, /* 301: 1.0e-47 << 220 */ - 0x9226712162ab070d, /* 302: 1.0e-46 << 216 */ - 0xb6b00d69bb55c8d1, /* 303: 1.0e-45 << 213 */ - 0xe45c10c42a2b3b05, /* 304: 1.0e-44 << 210 */ - 0x8eb98a7a9a5b04e3, /* 305: 1.0e-43 << 206 */ - 0xb267ed1940f1c61c, /* 306: 1.0e-42 << 203 */ - 0xdf01e85f912e37a3, /* 307: 1.0e-41 << 200 */ - 0x8b61313bbabce2c6, /* 308: 1.0e-40 << 196 */ - 0xae397d8aa96c1b77, /* 309: 1.0e-39 << 193 */ - 0xd9c7dced53c72255, /* 310: 1.0e-38 << 190 */ - 0x881cea14545c7575, /* 311: 1.0e-37 << 186 */ - 0xaa242499697392d2, /* 312: 1.0e-36 << 183 */ - 0xd4ad2dbfc3d07787, /* 313: 1.0e-35 << 180 */ - 0x84ec3c97da624ab4, /* 314: 1.0e-34 << 176 */ - 0xa6274bbdd0fadd61, /* 315: 1.0e-33 << 173 */ - 0xcfb11ead453994ba, /* 316: 1.0e-32 << 170 */ - 0x81ceb32c4b43fcf4, /* 317: 1.0e-31 << 166 */ - 0xa2425ff75e14fc31, /* 318: 1.0e-30 << 163 */ - 0xcad2f7f5359a3b3e, /* 319: 1.0e-29 << 160 */ - 0xfd87b5f28300ca0d, /* 320: 1.0e-28 << 157 */ - 0x9e74d1b791e07e48, /* 321: 1.0e-27 << 153 */ - 0xc612062576589dda, /* 322: 1.0e-26 << 150 */ - 0xf79687aed3eec551, /* 323: 1.0e-25 << 147 */ - 0x9abe14cd44753b52, /* 324: 1.0e-24 << 143 */ - 0xc16d9a0095928a27, /* 325: 1.0e-23 << 140 */ - 0xf1c90080baf72cb1, /* 326: 1.0e-22 << 137 */ - 0x971da05074da7bee, /* 327: 1.0e-21 << 133 */ - 0xbce5086492111aea, /* 328: 1.0e-20 << 130 */ - 0xec1e4a7db69561a5, /* 329: 1.0e-19 << 127 */ - 0x9392ee8e921d5d07, /* 330: 1.0e-18 << 123 */ - 0xb877aa3236a4b449, /* 331: 1.0e-17 << 120 */ - 0xe69594bec44de15b, /* 332: 1.0e-16 << 117 */ - 0x901d7cf73ab0acd9, /* 333: 1.0e-15 << 113 */ - 0xb424dc35095cd80f, /* 334: 1.0e-14 << 110 */ - 0xe12e13424bb40e13, /* 335: 1.0e-13 << 107 */ - 0x8cbccc096f5088cb, /* 336: 1.0e-12 << 103 */ - 0xafebff0bcb24aafe, /* 337: 1.0e-11 << 100 */ - 0xdbe6fecebdedd5be, /* 338: 1.0e-10 << 97 */ - 0x89705f4136b4a597, /* 339: 1.0e-9 << 93 */ - 0xabcc77118461cefc, /* 340: 1.0e-8 << 90 */ - 0xd6bf94d5e57a42bc, /* 341: 1.0e-7 << 87 */ - 0x8637bd05af6c69b5, /* 342: 1.0e-6 << 83 */ - 0xa7c5ac471b478423, /* 343: 1.0e-5 << 80 */ - 0xd1b71758e219652b, /* 344: 1.0e-4 << 77 */ - 0x83126e978d4fdf3b, /* 345: 1.0e-3 << 73 */ - 0xa3d70a3d70a3d70a, /* 346: 1.0e-2 << 70 */ - 0xcccccccccccccccc, /* 347: 1.0e-1 << 67 */ - 0x8000000000000000, /* 348: 1.0e+0 << 63 */ - 0xa000000000000000, /* 349: 1.0e+1 << 60 */ - 0xc800000000000000, /* 350: 1.0e+2 << 57 */ - 0xfa00000000000000, /* 351: 1.0e+3 << 54 */ - 0x9c40000000000000, /* 352: 1.0e+4 << 50 */ - 0xc350000000000000, /* 353: 1.0e+5 << 47 */ - 0xf424000000000000, /* 354: 1.0e+6 << 44 */ - 0x9896800000000000, /* 355: 1.0e+7 << 40 */ - 0xbebc200000000000, /* 356: 1.0e+8 << 37 */ - 0xee6b280000000000, /* 357: 1.0e+9 << 34 */ - 0x9502f90000000000, /* 358: 1.0e+10 << 30 */ - 0xba43b74000000000, /* 359: 1.0e+11 << 27 */ - 0xe8d4a51000000000, /* 360: 1.0e+12 << 24 */ - 0x9184e72a00000000, /* 361: 1.0e+13 << 20 */ - 0xb5e620f480000000, /* 362: 1.0e+14 << 17 */ - 0xe35fa931a0000000, /* 363: 1.0e+15 << 14 */ - 0x8e1bc9bf04000000, /* 364: 1.0e+16 << 10 */ - 0xb1a2bc2ec5000000, /* 365: 1.0e+17 << 7 */ - 0xde0b6b3a76400000, /* 366: 1.0e+18 << 4 */ - 0x8ac7230489e80000, /* 367: 1.0e+19 >> 0 */ - 0xad78ebc5ac620000, /* 368: 1.0e+20 >> 3 */ - 0xd8d726b7177a8000, /* 369: 1.0e+21 >> 6 */ - 0x878678326eac9000, /* 370: 1.0e+22 >> 10 */ - 0xa968163f0a57b400, /* 371: 1.0e+23 >> 13 */ - 0xd3c21bcecceda100, /* 372: 1.0e+24 >> 16 */ - 0x84595161401484a0, /* 373: 1.0e+25 >> 20 */ - 0xa56fa5b99019a5c8, /* 374: 1.0e+26 >> 23 */ - 0xcecb8f27f4200f3a, /* 375: 1.0e+27 >> 26 */ - 0x813f3978f8940984, /* 376: 1.0e+28 >> 30 */ - 0xa18f07d736b90be5, /* 377: 1.0e+29 >> 33 */ - 0xc9f2c9cd04674ede, /* 378: 1.0e+30 >> 36 */ - 0xfc6f7c4045812296, /* 379: 1.0e+31 >> 39 */ - 0x9dc5ada82b70b59d, /* 380: 1.0e+32 >> 43 */ - 0xc5371912364ce305, /* 381: 1.0e+33 >> 46 */ - 0xf684df56c3e01bc6, /* 382: 1.0e+34 >> 49 */ - 0x9a130b963a6c115c, /* 383: 1.0e+35 >> 53 */ - 0xc097ce7bc90715b3, /* 384: 1.0e+36 >> 56 */ - 0xf0bdc21abb48db20, /* 385: 1.0e+37 >> 59 */ - 0x96769950b50d88f4, /* 386: 1.0e+38 >> 63 */ - 0xbc143fa4e250eb31, /* 387: 1.0e+39 >> 66 */ - 0xeb194f8e1ae525fd, /* 388: 1.0e+40 >> 69 */ - 0x92efd1b8d0cf37be, /* 389: 1.0e+41 >> 73 */ - 0xb7abc627050305ad, /* 390: 1.0e+42 >> 76 */ - 0xe596b7b0c643c719, /* 391: 1.0e+43 >> 79 */ - 0x8f7e32ce7bea5c6f, /* 392: 1.0e+44 >> 83 */ - 0xb35dbf821ae4f38b, /* 393: 1.0e+45 >> 86 */ - 0xe0352f62a19e306e, /* 394: 1.0e+46 >> 89 */ - 0x8c213d9da502de45, /* 395: 1.0e+47 >> 93 */ - 0xaf298d050e4395d6, /* 396: 1.0e+48 >> 96 */ - 0xdaf3f04651d47b4c, /* 397: 1.0e+49 >> 99 */ - 0x88d8762bf324cd0f, /* 398: 1.0e+50 >> 103 */ - 0xab0e93b6efee0053, /* 399: 1.0e+51 >> 106 */ - 0xd5d238a4abe98068, /* 400: 1.0e+52 >> 109 */ - 0x85a36366eb71f041, /* 401: 1.0e+53 >> 113 */ - 0xa70c3c40a64e6c51, /* 402: 1.0e+54 >> 116 */ - 0xd0cf4b50cfe20765, /* 403: 1.0e+55 >> 119 */ - 0x82818f1281ed449f, /* 404: 1.0e+56 >> 123 */ - 0xa321f2d7226895c7, /* 405: 1.0e+57 >> 126 */ - 0xcbea6f8ceb02bb39, /* 406: 1.0e+58 >> 129 */ - 0xfee50b7025c36a08, /* 407: 1.0e+59 >> 132 */ - 0x9f4f2726179a2245, /* 408: 1.0e+60 >> 136 */ - 0xc722f0ef9d80aad6, /* 409: 1.0e+61 >> 139 */ - 0xf8ebad2b84e0d58b, /* 410: 1.0e+62 >> 142 */ - 0x9b934c3b330c8577, /* 411: 1.0e+63 >> 146 */ - 0xc2781f49ffcfa6d5, /* 412: 1.0e+64 >> 149 */ - 0xf316271c7fc3908a, /* 413: 1.0e+65 >> 152 */ - 0x97edd871cfda3a56, /* 414: 1.0e+66 >> 156 */ - 0xbde94e8e43d0c8ec, /* 415: 1.0e+67 >> 159 */ - 0xed63a231d4c4fb27, /* 416: 1.0e+68 >> 162 */ - 0x945e455f24fb1cf8, /* 417: 1.0e+69 >> 166 */ - 0xb975d6b6ee39e436, /* 418: 1.0e+70 >> 169 */ - 0xe7d34c64a9c85d44, /* 419: 1.0e+71 >> 172 */ - 0x90e40fbeea1d3a4a, /* 420: 1.0e+72 >> 176 */ - 0xb51d13aea4a488dd, /* 421: 1.0e+73 >> 179 */ - 0xe264589a4dcdab14, /* 422: 1.0e+74 >> 182 */ - 0x8d7eb76070a08aec, /* 423: 1.0e+75 >> 186 */ - 0xb0de65388cc8ada8, /* 424: 1.0e+76 >> 189 */ - 0xdd15fe86affad912, /* 425: 1.0e+77 >> 192 */ - 0x8a2dbf142dfcc7ab, /* 426: 1.0e+78 >> 196 */ - 0xacb92ed9397bf996, /* 427: 1.0e+79 >> 199 */ - 0xd7e77a8f87daf7fb, /* 428: 1.0e+80 >> 202 */ - 0x86f0ac99b4e8dafd, /* 429: 1.0e+81 >> 206 */ - 0xa8acd7c0222311bc, /* 430: 1.0e+82 >> 209 */ - 0xd2d80db02aabd62b, /* 431: 1.0e+83 >> 212 */ - 0x83c7088e1aab65db, /* 432: 1.0e+84 >> 216 */ - 0xa4b8cab1a1563f52, /* 433: 1.0e+85 >> 219 */ - 0xcde6fd5e09abcf26, /* 434: 1.0e+86 >> 222 */ - 0x80b05e5ac60b6178, /* 435: 1.0e+87 >> 226 */ - 0xa0dc75f1778e39d6, /* 436: 1.0e+88 >> 229 */ - 0xc913936dd571c84c, /* 437: 1.0e+89 >> 232 */ - 0xfb5878494ace3a5f, /* 438: 1.0e+90 >> 235 */ - 0x9d174b2dcec0e47b, /* 439: 1.0e+91 >> 239 */ - 0xc45d1df942711d9a, /* 440: 1.0e+92 >> 242 */ - 0xf5746577930d6500, /* 441: 1.0e+93 >> 245 */ - 0x9968bf6abbe85f20, /* 442: 1.0e+94 >> 249 */ - 0xbfc2ef456ae276e8, /* 443: 1.0e+95 >> 252 */ - 0xefb3ab16c59b14a2, /* 444: 1.0e+96 >> 255 */ - 0x95d04aee3b80ece5, /* 445: 1.0e+97 >> 259 */ - 0xbb445da9ca61281f, /* 446: 1.0e+98 >> 262 */ - 0xea1575143cf97226, /* 447: 1.0e+99 >> 265 */ - 0x924d692ca61be758, /* 448: 1.0e+100 >> 269 */ - 0xb6e0c377cfa2e12e, /* 449: 1.0e+101 >> 272 */ - 0xe498f455c38b997a, /* 450: 1.0e+102 >> 275 */ - 0x8edf98b59a373fec, /* 451: 1.0e+103 >> 279 */ - 0xb2977ee300c50fe7, /* 452: 1.0e+104 >> 282 */ - 0xdf3d5e9bc0f653e1, /* 453: 1.0e+105 >> 285 */ - 0x8b865b215899f46c, /* 454: 1.0e+106 >> 289 */ - 0xae67f1e9aec07187, /* 455: 1.0e+107 >> 292 */ - 0xda01ee641a708de9, /* 456: 1.0e+108 >> 295 */ - 0x884134fe908658b2, /* 457: 1.0e+109 >> 299 */ - 0xaa51823e34a7eede, /* 458: 1.0e+110 >> 302 */ - 0xd4e5e2cdc1d1ea96, /* 459: 1.0e+111 >> 305 */ - 0x850fadc09923329e, /* 460: 1.0e+112 >> 309 */ - 0xa6539930bf6bff45, /* 461: 1.0e+113 >> 312 */ - 0xcfe87f7cef46ff16, /* 462: 1.0e+114 >> 315 */ - 0x81f14fae158c5f6e, /* 463: 1.0e+115 >> 319 */ - 0xa26da3999aef7749, /* 464: 1.0e+116 >> 322 */ - 0xcb090c8001ab551c, /* 465: 1.0e+117 >> 325 */ - 0xfdcb4fa002162a63, /* 466: 1.0e+118 >> 328 */ - 0x9e9f11c4014dda7e, /* 467: 1.0e+119 >> 332 */ - 0xc646d63501a1511d, /* 468: 1.0e+120 >> 335 */ - 0xf7d88bc24209a565, /* 469: 1.0e+121 >> 338 */ - 0x9ae757596946075f, /* 470: 1.0e+122 >> 342 */ - 0xc1a12d2fc3978937, /* 471: 1.0e+123 >> 345 */ - 0xf209787bb47d6b84, /* 472: 1.0e+124 >> 348 */ - 0x9745eb4d50ce6332, /* 473: 1.0e+125 >> 352 */ - 0xbd176620a501fbff, /* 474: 1.0e+126 >> 355 */ - 0xec5d3fa8ce427aff, /* 475: 1.0e+127 >> 358 */ - 0x93ba47c980e98cdf, /* 476: 1.0e+128 >> 362 */ - 0xb8a8d9bbe123f017, /* 477: 1.0e+129 >> 365 */ - 0xe6d3102ad96cec1d, /* 478: 1.0e+130 >> 368 */ - 0x9043ea1ac7e41392, /* 479: 1.0e+131 >> 372 */ - 0xb454e4a179dd1877, /* 480: 1.0e+132 >> 375 */ - 0xe16a1dc9d8545e94, /* 481: 1.0e+133 >> 378 */ - 0x8ce2529e2734bb1d, /* 482: 1.0e+134 >> 382 */ - 0xb01ae745b101e9e4, /* 483: 1.0e+135 >> 385 */ - 0xdc21a1171d42645d, /* 484: 1.0e+136 >> 388 */ - 0x899504ae72497eba, /* 485: 1.0e+137 >> 392 */ - 0xabfa45da0edbde69, /* 486: 1.0e+138 >> 395 */ - 0xd6f8d7509292d603, /* 487: 1.0e+139 >> 398 */ - 0x865b86925b9bc5c2, /* 488: 1.0e+140 >> 402 */ - 0xa7f26836f282b732, /* 489: 1.0e+141 >> 405 */ - 0xd1ef0244af2364ff, /* 490: 1.0e+142 >> 408 */ - 0x8335616aed761f1f, /* 491: 1.0e+143 >> 412 */ - 0xa402b9c5a8d3a6e7, /* 492: 1.0e+144 >> 415 */ - 0xcd036837130890a1, /* 493: 1.0e+145 >> 418 */ - 0x802221226be55a64, /* 494: 1.0e+146 >> 422 */ - 0xa02aa96b06deb0fd, /* 495: 1.0e+147 >> 425 */ - 0xc83553c5c8965d3d, /* 496: 1.0e+148 >> 428 */ - 0xfa42a8b73abbf48c, /* 497: 1.0e+149 >> 431 */ - 0x9c69a97284b578d7, /* 498: 1.0e+150 >> 435 */ - 0xc38413cf25e2d70d, /* 499: 1.0e+151 >> 438 */ - 0xf46518c2ef5b8cd1, /* 500: 1.0e+152 >> 441 */ - 0x98bf2f79d5993802, /* 501: 1.0e+153 >> 445 */ - 0xbeeefb584aff8603, /* 502: 1.0e+154 >> 448 */ - 0xeeaaba2e5dbf6784, /* 503: 1.0e+155 >> 451 */ - 0x952ab45cfa97a0b2, /* 504: 1.0e+156 >> 455 */ - 0xba756174393d88df, /* 505: 1.0e+157 >> 458 */ - 0xe912b9d1478ceb17, /* 506: 1.0e+158 >> 461 */ - 0x91abb422ccb812ee, /* 507: 1.0e+159 >> 465 */ - 0xb616a12b7fe617aa, /* 508: 1.0e+160 >> 468 */ - 0xe39c49765fdf9d94, /* 509: 1.0e+161 >> 471 */ - 0x8e41ade9fbebc27d, /* 510: 1.0e+162 >> 475 */ - 0xb1d219647ae6b31c, /* 511: 1.0e+163 >> 478 */ - 0xde469fbd99a05fe3, /* 512: 1.0e+164 >> 481 */ - 0x8aec23d680043bee, /* 513: 1.0e+165 >> 485 */ - 0xada72ccc20054ae9, /* 514: 1.0e+166 >> 488 */ - 0xd910f7ff28069da4, /* 515: 1.0e+167 >> 491 */ - 0x87aa9aff79042286, /* 516: 1.0e+168 >> 495 */ - 0xa99541bf57452b28, /* 517: 1.0e+169 >> 498 */ - 0xd3fa922f2d1675f2, /* 518: 1.0e+170 >> 501 */ - 0x847c9b5d7c2e09b7, /* 519: 1.0e+171 >> 505 */ - 0xa59bc234db398c25, /* 520: 1.0e+172 >> 508 */ - 0xcf02b2c21207ef2e, /* 521: 1.0e+173 >> 511 */ - 0x8161afb94b44f57d, /* 522: 1.0e+174 >> 515 */ - 0xa1ba1ba79e1632dc, /* 523: 1.0e+175 >> 518 */ - 0xca28a291859bbf93, /* 524: 1.0e+176 >> 521 */ - 0xfcb2cb35e702af78, /* 525: 1.0e+177 >> 524 */ - 0x9defbf01b061adab, /* 526: 1.0e+178 >> 528 */ - 0xc56baec21c7a1916, /* 527: 1.0e+179 >> 531 */ - 0xf6c69a72a3989f5b, /* 528: 1.0e+180 >> 534 */ - 0x9a3c2087a63f6399, /* 529: 1.0e+181 >> 538 */ - 0xc0cb28a98fcf3c7f, /* 530: 1.0e+182 >> 541 */ - 0xf0fdf2d3f3c30b9f, /* 531: 1.0e+183 >> 544 */ - 0x969eb7c47859e743, /* 532: 1.0e+184 >> 548 */ - 0xbc4665b596706114, /* 533: 1.0e+185 >> 551 */ - 0xeb57ff22fc0c7959, /* 534: 1.0e+186 >> 554 */ - 0x9316ff75dd87cbd8, /* 535: 1.0e+187 >> 558 */ - 0xb7dcbf5354e9bece, /* 536: 1.0e+188 >> 561 */ - 0xe5d3ef282a242e81, /* 537: 1.0e+189 >> 564 */ - 0x8fa475791a569d10, /* 538: 1.0e+190 >> 568 */ - 0xb38d92d760ec4455, /* 539: 1.0e+191 >> 571 */ - 0xe070f78d3927556a, /* 540: 1.0e+192 >> 574 */ - 0x8c469ab843b89562, /* 541: 1.0e+193 >> 578 */ - 0xaf58416654a6babb, /* 542: 1.0e+194 >> 581 */ - 0xdb2e51bfe9d0696a, /* 543: 1.0e+195 >> 584 */ - 0x88fcf317f22241e2, /* 544: 1.0e+196 >> 588 */ - 0xab3c2fddeeaad25a, /* 545: 1.0e+197 >> 591 */ - 0xd60b3bd56a5586f1, /* 546: 1.0e+198 >> 594 */ - 0x85c7056562757456, /* 547: 1.0e+199 >> 598 */ - 0xa738c6bebb12d16c, /* 548: 1.0e+200 >> 601 */ - 0xd106f86e69d785c7, /* 549: 1.0e+201 >> 604 */ - 0x82a45b450226b39c, /* 550: 1.0e+202 >> 608 */ - 0xa34d721642b06084, /* 551: 1.0e+203 >> 611 */ - 0xcc20ce9bd35c78a5, /* 552: 1.0e+204 >> 614 */ - 0xff290242c83396ce, /* 553: 1.0e+205 >> 617 */ - 0x9f79a169bd203e41, /* 554: 1.0e+206 >> 621 */ - 0xc75809c42c684dd1, /* 555: 1.0e+207 >> 624 */ - 0xf92e0c3537826145, /* 556: 1.0e+208 >> 627 */ - 0x9bbcc7a142b17ccb, /* 557: 1.0e+209 >> 631 */ - 0xc2abf989935ddbfe, /* 558: 1.0e+210 >> 634 */ - 0xf356f7ebf83552fe, /* 559: 1.0e+211 >> 637 */ - 0x98165af37b2153de, /* 560: 1.0e+212 >> 641 */ - 0xbe1bf1b059e9a8d6, /* 561: 1.0e+213 >> 644 */ - 0xeda2ee1c7064130c, /* 562: 1.0e+214 >> 647 */ - 0x9485d4d1c63e8be7, /* 563: 1.0e+215 >> 651 */ - 0xb9a74a0637ce2ee1, /* 564: 1.0e+216 >> 654 */ - 0xe8111c87c5c1ba99, /* 565: 1.0e+217 >> 657 */ - 0x910ab1d4db9914a0, /* 566: 1.0e+218 >> 661 */ - 0xb54d5e4a127f59c8, /* 567: 1.0e+219 >> 664 */ - 0xe2a0b5dc971f303a, /* 568: 1.0e+220 >> 667 */ - 0x8da471a9de737e24, /* 569: 1.0e+221 >> 671 */ - 0xb10d8e1456105dad, /* 570: 1.0e+222 >> 674 */ - 0xdd50f1996b947518, /* 571: 1.0e+223 >> 677 */ - 0x8a5296ffe33cc92f, /* 572: 1.0e+224 >> 681 */ - 0xace73cbfdc0bfb7b, /* 573: 1.0e+225 >> 684 */ - 0xd8210befd30efa5a, /* 574: 1.0e+226 >> 687 */ - 0x8714a775e3e95c78, /* 575: 1.0e+227 >> 691 */ - 0xa8d9d1535ce3b396, /* 576: 1.0e+228 >> 694 */ - 0xd31045a8341ca07c, /* 577: 1.0e+229 >> 697 */ - 0x83ea2b892091e44d, /* 578: 1.0e+230 >> 701 */ - 0xa4e4b66b68b65d60, /* 579: 1.0e+231 >> 704 */ - 0xce1de40642e3f4b9, /* 580: 1.0e+232 >> 707 */ - 0x80d2ae83e9ce78f3, /* 581: 1.0e+233 >> 711 */ - 0xa1075a24e4421730, /* 582: 1.0e+234 >> 714 */ - 0xc94930ae1d529cfc, /* 583: 1.0e+235 >> 717 */ - 0xfb9b7cd9a4a7443c, /* 584: 1.0e+236 >> 720 */ - 0x9d412e0806e88aa5, /* 585: 1.0e+237 >> 724 */ - 0xc491798a08a2ad4e, /* 586: 1.0e+238 >> 727 */ - 0xf5b5d7ec8acb58a2, /* 587: 1.0e+239 >> 730 */ - 0x9991a6f3d6bf1765, /* 588: 1.0e+240 >> 734 */ - 0xbff610b0cc6edd3f, /* 589: 1.0e+241 >> 737 */ - 0xeff394dcff8a948e, /* 590: 1.0e+242 >> 740 */ - 0x95f83d0a1fb69cd9, /* 591: 1.0e+243 >> 744 */ - 0xbb764c4ca7a4440f, /* 592: 1.0e+244 >> 747 */ - 0xea53df5fd18d5513, /* 593: 1.0e+245 >> 750 */ - 0x92746b9be2f8552c, /* 594: 1.0e+246 >> 754 */ - 0xb7118682dbb66a77, /* 595: 1.0e+247 >> 757 */ - 0xe4d5e82392a40515, /* 596: 1.0e+248 >> 760 */ - 0x8f05b1163ba6832d, /* 597: 1.0e+249 >> 764 */ - 0xb2c71d5bca9023f8, /* 598: 1.0e+250 >> 767 */ - 0xdf78e4b2bd342cf6, /* 599: 1.0e+251 >> 770 */ - 0x8bab8eefb6409c1a, /* 600: 1.0e+252 >> 774 */ - 0xae9672aba3d0c320, /* 601: 1.0e+253 >> 777 */ - 0xda3c0f568cc4f3e8, /* 602: 1.0e+254 >> 780 */ - 0x8865899617fb1871, /* 603: 1.0e+255 >> 784 */ - 0xaa7eebfb9df9de8d, /* 604: 1.0e+256 >> 787 */ - 0xd51ea6fa85785631, /* 605: 1.0e+257 >> 790 */ - 0x8533285c936b35de, /* 606: 1.0e+258 >> 794 */ - 0xa67ff273b8460356, /* 607: 1.0e+259 >> 797 */ - 0xd01fef10a657842c, /* 608: 1.0e+260 >> 800 */ - 0x8213f56a67f6b29b, /* 609: 1.0e+261 >> 804 */ - 0xa298f2c501f45f42, /* 610: 1.0e+262 >> 807 */ - 0xcb3f2f7642717713, /* 611: 1.0e+263 >> 810 */ - 0xfe0efb53d30dd4d7, /* 612: 1.0e+264 >> 813 */ - 0x9ec95d1463e8a506, /* 613: 1.0e+265 >> 817 */ - 0xc67bb4597ce2ce48, /* 614: 1.0e+266 >> 820 */ - 0xf81aa16fdc1b81da, /* 615: 1.0e+267 >> 823 */ - 0x9b10a4e5e9913128, /* 616: 1.0e+268 >> 827 */ - 0xc1d4ce1f63f57d72, /* 617: 1.0e+269 >> 830 */ - 0xf24a01a73cf2dccf, /* 618: 1.0e+270 >> 833 */ - 0x976e41088617ca01, /* 619: 1.0e+271 >> 837 */ - 0xbd49d14aa79dbc82, /* 620: 1.0e+272 >> 840 */ - 0xec9c459d51852ba2, /* 621: 1.0e+273 >> 843 */ - 0x93e1ab8252f33b45, /* 622: 1.0e+274 >> 847 */ - 0xb8da1662e7b00a17, /* 623: 1.0e+275 >> 850 */ - 0xe7109bfba19c0c9d, /* 624: 1.0e+276 >> 853 */ - 0x906a617d450187e2, /* 625: 1.0e+277 >> 857 */ - 0xb484f9dc9641e9da, /* 626: 1.0e+278 >> 860 */ - 0xe1a63853bbd26451, /* 627: 1.0e+279 >> 863 */ - 0x8d07e33455637eb2, /* 628: 1.0e+280 >> 867 */ - 0xb049dc016abc5e5f, /* 629: 1.0e+281 >> 870 */ - 0xdc5c5301c56b75f7, /* 630: 1.0e+282 >> 873 */ - 0x89b9b3e11b6329ba, /* 631: 1.0e+283 >> 877 */ - 0xac2820d9623bf429, /* 632: 1.0e+284 >> 880 */ - 0xd732290fbacaf133, /* 633: 1.0e+285 >> 883 */ - 0x867f59a9d4bed6c0, /* 634: 1.0e+286 >> 887 */ - 0xa81f301449ee8c70, /* 635: 1.0e+287 >> 890 */ - 0xd226fc195c6a2f8c, /* 636: 1.0e+288 >> 893 */ - 0x83585d8fd9c25db7, /* 637: 1.0e+289 >> 897 */ - 0xa42e74f3d032f525, /* 638: 1.0e+290 >> 900 */ - 0xcd3a1230c43fb26f, /* 639: 1.0e+291 >> 903 */ - 0x80444b5e7aa7cf85, /* 640: 1.0e+292 >> 907 */ - 0xa0555e361951c366, /* 641: 1.0e+293 >> 910 */ - 0xc86ab5c39fa63440, /* 642: 1.0e+294 >> 913 */ - 0xfa856334878fc150, /* 643: 1.0e+295 >> 916 */ - 0x9c935e00d4b9d8d2, /* 644: 1.0e+296 >> 920 */ - 0xc3b8358109e84f07, /* 645: 1.0e+297 >> 923 */ - 0xf4a642e14c6262c8, /* 646: 1.0e+298 >> 926 */ - 0x98e7e9cccfbd7dbd, /* 647: 1.0e+299 >> 930 */ - 0xbf21e44003acdd2c, /* 648: 1.0e+300 >> 933 */ - 0xeeea5d5004981478, /* 649: 1.0e+301 >> 936 */ - 0x95527a5202df0ccb, /* 650: 1.0e+302 >> 940 */ - 0xbaa718e68396cffd, /* 651: 1.0e+303 >> 943 */ - 0xe950df20247c83fd, /* 652: 1.0e+304 >> 946 */ - 0x91d28b7416cdd27e, /* 653: 1.0e+305 >> 950 */ - 0xb6472e511c81471d, /* 654: 1.0e+306 >> 953 */ - 0xe3d8f9e563a198e5, /* 655: 1.0e+307 >> 956 */ - 0x8e679c2f5e44ff8f, /* 656: 1.0e+308 >> 960 */ - 0xb201833b35d63f73, /* 657: 1.0e+309 >> 963 */ - 0xde81e40a034bcf4f, /* 658: 1.0e+310 >> 966 */ - 0x8b112e86420f6191, /* 659: 1.0e+311 >> 970 */ - 0xadd57a27d29339f6, /* 660: 1.0e+312 >> 973 */ - 0xd94ad8b1c7380874, /* 661: 1.0e+313 >> 976 */ - 0x87cec76f1c830548, /* 662: 1.0e+314 >> 980 */ - 0xa9c2794ae3a3c69a, /* 663: 1.0e+315 >> 983 */ - 0xd433179d9c8cb841, /* 664: 1.0e+316 >> 986 */ - 0x849feec281d7f328, /* 665: 1.0e+317 >> 990 */ - 0xa5c7ea73224deff3, /* 666: 1.0e+318 >> 993 */ - 0xcf39e50feae16bef, /* 667: 1.0e+319 >> 996 */ - 0x81842f29f2cce375, /* 668: 1.0e+320 >> 1000 */ - 0xa1e53af46f801c53, /* 669: 1.0e+321 >> 1003 */ - 0xca5e89b18b602368, /* 670: 1.0e+322 >> 1006 */ - 0xfcf62c1dee382c42, /* 671: 1.0e+323 >> 1009 */ - 0x9e19db92b4e31ba9, /* 672: 1.0e+324 >> 1013 */ - 0xc5a05277621be293, /* 673: 1.0e+325 >> 1016 */ - 0xf70867153aa2db38, /* 674: 1.0e+326 >> 1019 */ - 0x9a65406d44a5c903, /* 675: 1.0e+327 >> 1023 */ - 0xc0fe908895cf3b44, /* 676: 1.0e+328 >> 1026 */ - 0xf13e34aabb430a15, /* 677: 1.0e+329 >> 1029 */ - 0x96c6e0eab509e64d, /* 678: 1.0e+330 >> 1033 */ - 0xbc789925624c5fe0, /* 679: 1.0e+331 >> 1036 */ - 0xeb96bf6ebadf77d8, /* 680: 1.0e+332 >> 1039 */ - 0x933e37a534cbaae7, /* 681: 1.0e+333 >> 1043 */ - 0xb80dc58e81fe95a1, /* 682: 1.0e+334 >> 1046 */ - 0xe61136f2227e3b09, /* 683: 1.0e+335 >> 1049 */ - 0x8fcac257558ee4e6, /* 684: 1.0e+336 >> 1053 */ - 0xb3bd72ed2af29e1f, /* 685: 1.0e+337 >> 1056 */ - 0xe0accfa875af45a7, /* 686: 1.0e+338 >> 1059 */ - 0x8c6c01c9498d8b88, /* 687: 1.0e+339 >> 1063 */ - 0xaf87023b9bf0ee6a, /* 688: 1.0e+340 >> 1066 */ - 0xdb68c2ca82ed2a05, /* 689: 1.0e+341 >> 1069 */ - 0x892179be91d43a43, /* 690: 1.0e+342 >> 1073 */ - 0xab69d82e364948d4, /* 691: 1.0e+343 >> 1076 */ - 0xd6444e39c3db9b09, /* 692: 1.0e+344 >> 1079 */ - 0x85eab0e41a6940e5, /* 693: 1.0e+345 >> 1083 */ - 0xa7655d1d2103911f, /* 694: 1.0e+346 >> 1086 */ - 0xd13eb46469447567, /* 695: 1.0e+347 >> 1089 */ + 0xfa8fd5a0081c0288LLU, /* 0: 1.0e-348 << 1220 */ + 0x9c99e58405118195LLU, /* 1: 1.0e-347 << 1216 */ + 0xc3c05ee50655e1faLLU, /* 2: 1.0e-346 << 1213 */ + 0xf4b0769e47eb5a78LLU, /* 3: 1.0e-345 << 1210 */ + 0x98ee4a22ecf3188bLLU, /* 4: 1.0e-344 << 1206 */ + 0xbf29dcaba82fdeaeLLU, /* 5: 1.0e-343 << 1203 */ + 0xeef453d6923bd65aLLU, /* 6: 1.0e-342 << 1200 */ + 0x9558b4661b6565f8LLU, /* 7: 1.0e-341 << 1196 */ + 0xbaaee17fa23ebf76LLU, /* 8: 1.0e-340 << 1193 */ + 0xe95a99df8ace6f53LLU, /* 9: 1.0e-339 << 1190 */ + 0x91d8a02bb6c10594LLU, /* 10: 1.0e-338 << 1186 */ + 0xb64ec836a47146f9LLU, /* 11: 1.0e-337 << 1183 */ + 0xe3e27a444d8d98b7LLU, /* 12: 1.0e-336 << 1180 */ + 0x8e6d8c6ab0787f72LLU, /* 13: 1.0e-335 << 1176 */ + 0xb208ef855c969f4fLLU, /* 14: 1.0e-334 << 1173 */ + 0xde8b2b66b3bc4723LLU, /* 15: 1.0e-333 << 1170 */ + 0x8b16fb203055ac76LLU, /* 16: 1.0e-332 << 1166 */ + 0xaddcb9e83c6b1793LLU, /* 17: 1.0e-331 << 1163 */ + 0xd953e8624b85dd78LLU, /* 18: 1.0e-330 << 1160 */ + 0x87d4713d6f33aa6bLLU, /* 19: 1.0e-329 << 1156 */ + 0xa9c98d8ccb009506LLU, /* 20: 1.0e-328 << 1153 */ + 0xd43bf0effdc0ba48LLU, /* 21: 1.0e-327 << 1150 */ + 0x84a57695fe98746dLLU, /* 22: 1.0e-326 << 1146 */ + 0xa5ced43b7e3e9188LLU, /* 23: 1.0e-325 << 1143 */ + 0xcf42894a5dce35eaLLU, /* 24: 1.0e-324 << 1140 */ + 0x818995ce7aa0e1b2LLU, /* 25: 1.0e-323 << 1136 */ + 0xa1ebfb4219491a1fLLU, /* 26: 1.0e-322 << 1133 */ + 0xca66fa129f9b60a6LLU, /* 27: 1.0e-321 << 1130 */ + 0xfd00b897478238d0LLU, /* 28: 1.0e-320 << 1127 */ + 0x9e20735e8cb16382LLU, /* 29: 1.0e-319 << 1123 */ + 0xc5a890362fddbc62LLU, /* 30: 1.0e-318 << 1120 */ + 0xf712b443bbd52b7bLLU, /* 31: 1.0e-317 << 1117 */ + 0x9a6bb0aa55653b2dLLU, /* 32: 1.0e-316 << 1113 */ + 0xc1069cd4eabe89f8LLU, /* 33: 1.0e-315 << 1110 */ + 0xf148440a256e2c76LLU, /* 34: 1.0e-314 << 1107 */ + 0x96cd2a865764dbcaLLU, /* 35: 1.0e-313 << 1103 */ + 0xbc807527ed3e12bcLLU, /* 36: 1.0e-312 << 1100 */ + 0xeba09271e88d976bLLU, /* 37: 1.0e-311 << 1097 */ + 0x93445b8731587ea3LLU, /* 38: 1.0e-310 << 1093 */ + 0xb8157268fdae9e4cLLU, /* 39: 1.0e-309 << 1090 */ + 0xe61acf033d1a45dfLLU, /* 40: 1.0e-308 << 1087 */ + 0x8fd0c16206306babLLU, /* 41: 1.0e-307 << 1083 */ + 0xb3c4f1ba87bc8696LLU, /* 42: 1.0e-306 << 1080 */ + 0xe0b62e2929aba83cLLU, /* 43: 1.0e-305 << 1077 */ + 0x8c71dcd9ba0b4925LLU, /* 44: 1.0e-304 << 1073 */ + 0xaf8e5410288e1b6fLLU, /* 45: 1.0e-303 << 1070 */ + 0xdb71e91432b1a24aLLU, /* 46: 1.0e-302 << 1067 */ + 0x892731ac9faf056eLLU, /* 47: 1.0e-301 << 1063 */ + 0xab70fe17c79ac6caLLU, /* 48: 1.0e-300 << 1060 */ + 0xd64d3d9db981787dLLU, /* 49: 1.0e-299 << 1057 */ + 0x85f0468293f0eb4eLLU, /* 50: 1.0e-298 << 1053 */ + 0xa76c582338ed2621LLU, /* 51: 1.0e-297 << 1050 */ + 0xd1476e2c07286faaLLU, /* 52: 1.0e-296 << 1047 */ + 0x82cca4db847945caLLU, /* 53: 1.0e-295 << 1043 */ + 0xa37fce126597973cLLU, /* 54: 1.0e-294 << 1040 */ + 0xcc5fc196fefd7d0cLLU, /* 55: 1.0e-293 << 1037 */ + 0xff77b1fcbebcdc4fLLU, /* 56: 1.0e-292 << 1034 */ + 0x9faacf3df73609b1LLU, /* 57: 1.0e-291 << 1030 */ + 0xc795830d75038c1dLLU, /* 58: 1.0e-290 << 1027 */ + 0xf97ae3d0d2446f25LLU, /* 59: 1.0e-289 << 1024 */ + 0x9becce62836ac577LLU, /* 60: 1.0e-288 << 1020 */ + 0xc2e801fb244576d5LLU, /* 61: 1.0e-287 << 1017 */ + 0xf3a20279ed56d48aLLU, /* 62: 1.0e-286 << 1014 */ + 0x9845418c345644d6LLU, /* 63: 1.0e-285 << 1010 */ + 0xbe5691ef416bd60cLLU, /* 64: 1.0e-284 << 1007 */ + 0xedec366b11c6cb8fLLU, /* 65: 1.0e-283 << 1004 */ + 0x94b3a202eb1c3f39LLU, /* 66: 1.0e-282 << 1000 */ + 0xb9e08a83a5e34f07LLU, /* 67: 1.0e-281 << 997 */ + 0xe858ad248f5c22c9LLU, /* 68: 1.0e-280 << 994 */ + 0x91376c36d99995beLLU, /* 69: 1.0e-279 << 990 */ + 0xb58547448ffffb2dLLU, /* 70: 1.0e-278 << 987 */ + 0xe2e69915b3fff9f9LLU, /* 71: 1.0e-277 << 984 */ + 0x8dd01fad907ffc3bLLU, /* 72: 1.0e-276 << 980 */ + 0xb1442798f49ffb4aLLU, /* 73: 1.0e-275 << 977 */ + 0xdd95317f31c7fa1dLLU, /* 74: 1.0e-274 << 974 */ + 0x8a7d3eef7f1cfc52LLU, /* 75: 1.0e-273 << 970 */ + 0xad1c8eab5ee43b66LLU, /* 76: 1.0e-272 << 967 */ + 0xd863b256369d4a40LLU, /* 77: 1.0e-271 << 964 */ + 0x873e4f75e2224e68LLU, /* 78: 1.0e-270 << 960 */ + 0xa90de3535aaae202LLU, /* 79: 1.0e-269 << 957 */ + 0xd3515c2831559a83LLU, /* 80: 1.0e-268 << 954 */ + 0x8412d9991ed58091LLU, /* 81: 1.0e-267 << 950 */ + 0xa5178fff668ae0b6LLU, /* 82: 1.0e-266 << 947 */ + 0xce5d73ff402d98e3LLU, /* 83: 1.0e-265 << 944 */ + 0x80fa687f881c7f8eLLU, /* 84: 1.0e-264 << 940 */ + 0xa139029f6a239f72LLU, /* 85: 1.0e-263 << 937 */ + 0xc987434744ac874eLLU, /* 86: 1.0e-262 << 934 */ + 0xfbe9141915d7a922LLU, /* 87: 1.0e-261 << 931 */ + 0x9d71ac8fada6c9b5LLU, /* 88: 1.0e-260 << 927 */ + 0xc4ce17b399107c22LLU, /* 89: 1.0e-259 << 924 */ + 0xf6019da07f549b2bLLU, /* 90: 1.0e-258 << 921 */ + 0x99c102844f94e0fbLLU, /* 91: 1.0e-257 << 917 */ + 0xc0314325637a1939LLU, /* 92: 1.0e-256 << 914 */ + 0xf03d93eebc589f88LLU, /* 93: 1.0e-255 << 911 */ + 0x96267c7535b763b5LLU, /* 94: 1.0e-254 << 907 */ + 0xbbb01b9283253ca2LLU, /* 95: 1.0e-253 << 904 */ + 0xea9c227723ee8bcbLLU, /* 96: 1.0e-252 << 901 */ + 0x92a1958a7675175fLLU, /* 97: 1.0e-251 << 897 */ + 0xb749faed14125d36LLU, /* 98: 1.0e-250 << 894 */ + 0xe51c79a85916f484LLU, /* 99: 1.0e-249 << 891 */ + 0x8f31cc0937ae58d2LLU, /* 100: 1.0e-248 << 887 */ + 0xb2fe3f0b8599ef07LLU, /* 101: 1.0e-247 << 884 */ + 0xdfbdcece67006ac9LLU, /* 102: 1.0e-246 << 881 */ + 0x8bd6a141006042bdLLU, /* 103: 1.0e-245 << 877 */ + 0xaecc49914078536dLLU, /* 104: 1.0e-244 << 874 */ + 0xda7f5bf590966848LLU, /* 105: 1.0e-243 << 871 */ + 0x888f99797a5e012dLLU, /* 106: 1.0e-242 << 867 */ + 0xaab37fd7d8f58178LLU, /* 107: 1.0e-241 << 864 */ + 0xd5605fcdcf32e1d6LLU, /* 108: 1.0e-240 << 861 */ + 0x855c3be0a17fcd26LLU, /* 109: 1.0e-239 << 857 */ + 0xa6b34ad8c9dfc06fLLU, /* 110: 1.0e-238 << 854 */ + 0xd0601d8efc57b08bLLU, /* 111: 1.0e-237 << 851 */ + 0x823c12795db6ce57LLU, /* 112: 1.0e-236 << 847 */ + 0xa2cb1717b52481edLLU, /* 113: 1.0e-235 << 844 */ + 0xcb7ddcdda26da268LLU, /* 114: 1.0e-234 << 841 */ + 0xfe5d54150b090b02LLU, /* 115: 1.0e-233 << 838 */ + 0x9efa548d26e5a6e1LLU, /* 116: 1.0e-232 << 834 */ + 0xc6b8e9b0709f109aLLU, /* 117: 1.0e-231 << 831 */ + 0xf867241c8cc6d4c0LLU, /* 118: 1.0e-230 << 828 */ + 0x9b407691d7fc44f8LLU, /* 119: 1.0e-229 << 824 */ + 0xc21094364dfb5636LLU, /* 120: 1.0e-228 << 821 */ + 0xf294b943e17a2bc4LLU, /* 121: 1.0e-227 << 818 */ + 0x979cf3ca6cec5b5aLLU, /* 122: 1.0e-226 << 814 */ + 0xbd8430bd08277231LLU, /* 123: 1.0e-225 << 811 */ + 0xece53cec4a314ebdLLU, /* 124: 1.0e-224 << 808 */ + 0x940f4613ae5ed136LLU, /* 125: 1.0e-223 << 804 */ + 0xb913179899f68584LLU, /* 126: 1.0e-222 << 801 */ + 0xe757dd7ec07426e5LLU, /* 127: 1.0e-221 << 798 */ + 0x9096ea6f3848984fLLU, /* 128: 1.0e-220 << 794 */ + 0xb4bca50b065abe63LLU, /* 129: 1.0e-219 << 791 */ + 0xe1ebce4dc7f16dfbLLU, /* 130: 1.0e-218 << 788 */ + 0x8d3360f09cf6e4bdLLU, /* 131: 1.0e-217 << 784 */ + 0xb080392cc4349decLLU, /* 132: 1.0e-216 << 781 */ + 0xdca04777f541c567LLU, /* 133: 1.0e-215 << 778 */ + 0x89e42caaf9491b60LLU, /* 134: 1.0e-214 << 774 */ + 0xac5d37d5b79b6239LLU, /* 135: 1.0e-213 << 771 */ + 0xd77485cb25823ac7LLU, /* 136: 1.0e-212 << 768 */ + 0x86a8d39ef77164bcLLU, /* 137: 1.0e-211 << 764 */ + 0xa8530886b54dbdebLLU, /* 138: 1.0e-210 << 761 */ + 0xd267caa862a12d66LLU, /* 139: 1.0e-209 << 758 */ + 0x8380dea93da4bc60LLU, /* 140: 1.0e-208 << 754 */ + 0xa46116538d0deb78LLU, /* 141: 1.0e-207 << 751 */ + 0xcd795be870516656LLU, /* 142: 1.0e-206 << 748 */ + 0x806bd9714632dff6LLU, /* 143: 1.0e-205 << 744 */ + 0xa086cfcd97bf97f3LLU, /* 144: 1.0e-204 << 741 */ + 0xc8a883c0fdaf7df0LLU, /* 145: 1.0e-203 << 738 */ + 0xfad2a4b13d1b5d6cLLU, /* 146: 1.0e-202 << 735 */ + 0x9cc3a6eec6311a63LLU, /* 147: 1.0e-201 << 731 */ + 0xc3f490aa77bd60fcLLU, /* 148: 1.0e-200 << 728 */ + 0xf4f1b4d515acb93bLLU, /* 149: 1.0e-199 << 725 */ + 0x991711052d8bf3c5LLU, /* 150: 1.0e-198 << 721 */ + 0xbf5cd54678eef0b6LLU, /* 151: 1.0e-197 << 718 */ + 0xef340a98172aace4LLU, /* 152: 1.0e-196 << 715 */ + 0x9580869f0e7aac0eLLU, /* 153: 1.0e-195 << 711 */ + 0xbae0a846d2195712LLU, /* 154: 1.0e-194 << 708 */ + 0xe998d258869facd7LLU, /* 155: 1.0e-193 << 705 */ + 0x91ff83775423cc06LLU, /* 156: 1.0e-192 << 701 */ + 0xb67f6455292cbf08LLU, /* 157: 1.0e-191 << 698 */ + 0xe41f3d6a7377eecaLLU, /* 158: 1.0e-190 << 695 */ + 0x8e938662882af53eLLU, /* 159: 1.0e-189 << 691 */ + 0xb23867fb2a35b28dLLU, /* 160: 1.0e-188 << 688 */ + 0xdec681f9f4c31f31LLU, /* 161: 1.0e-187 << 685 */ + 0x8b3c113c38f9f37eLLU, /* 162: 1.0e-186 << 681 */ + 0xae0b158b4738705eLLU, /* 163: 1.0e-185 << 678 */ + 0xd98ddaee19068c76LLU, /* 164: 1.0e-184 << 675 */ + 0x87f8a8d4cfa417c9LLU, /* 165: 1.0e-183 << 671 */ + 0xa9f6d30a038d1dbcLLU, /* 166: 1.0e-182 << 668 */ + 0xd47487cc8470652bLLU, /* 167: 1.0e-181 << 665 */ + 0x84c8d4dfd2c63f3bLLU, /* 168: 1.0e-180 << 661 */ + 0xa5fb0a17c777cf09LLU, /* 169: 1.0e-179 << 658 */ + 0xcf79cc9db955c2ccLLU, /* 170: 1.0e-178 << 655 */ + 0x81ac1fe293d599bfLLU, /* 171: 1.0e-177 << 651 */ + 0xa21727db38cb002fLLU, /* 172: 1.0e-176 << 648 */ + 0xca9cf1d206fdc03bLLU, /* 173: 1.0e-175 << 645 */ + 0xfd442e4688bd304aLLU, /* 174: 1.0e-174 << 642 */ + 0x9e4a9cec15763e2eLLU, /* 175: 1.0e-173 << 638 */ + 0xc5dd44271ad3cdbaLLU, /* 176: 1.0e-172 << 635 */ + 0xf7549530e188c128LLU, /* 177: 1.0e-171 << 632 */ + 0x9a94dd3e8cf578b9LLU, /* 178: 1.0e-170 << 628 */ + 0xc13a148e3032d6e7LLU, /* 179: 1.0e-169 << 625 */ + 0xf18899b1bc3f8ca1LLU, /* 180: 1.0e-168 << 622 */ + 0x96f5600f15a7b7e5LLU, /* 181: 1.0e-167 << 618 */ + 0xbcb2b812db11a5deLLU, /* 182: 1.0e-166 << 615 */ + 0xebdf661791d60f56LLU, /* 183: 1.0e-165 << 612 */ + 0x936b9fcebb25c995LLU, /* 184: 1.0e-164 << 608 */ + 0xb84687c269ef3bfbLLU, /* 185: 1.0e-163 << 605 */ + 0xe65829b3046b0afaLLU, /* 186: 1.0e-162 << 602 */ + 0x8ff71a0fe2c2e6dcLLU, /* 187: 1.0e-161 << 598 */ + 0xb3f4e093db73a093LLU, /* 188: 1.0e-160 << 595 */ + 0xe0f218b8d25088b8LLU, /* 189: 1.0e-159 << 592 */ + 0x8c974f7383725573LLU, /* 190: 1.0e-158 << 588 */ + 0xafbd2350644eeacfLLU, /* 191: 1.0e-157 << 585 */ + 0xdbac6c247d62a583LLU, /* 192: 1.0e-156 << 582 */ + 0x894bc396ce5da772LLU, /* 193: 1.0e-155 << 578 */ + 0xab9eb47c81f5114fLLU, /* 194: 1.0e-154 << 575 */ + 0xd686619ba27255a2LLU, /* 195: 1.0e-153 << 572 */ + 0x8613fd0145877585LLU, /* 196: 1.0e-152 << 568 */ + 0xa798fc4196e952e7LLU, /* 197: 1.0e-151 << 565 */ + 0xd17f3b51fca3a7a0LLU, /* 198: 1.0e-150 << 562 */ + 0x82ef85133de648c4LLU, /* 199: 1.0e-149 << 558 */ + 0xa3ab66580d5fdaf5LLU, /* 200: 1.0e-148 << 555 */ + 0xcc963fee10b7d1b3LLU, /* 201: 1.0e-147 << 552 */ + 0xffbbcfe994e5c61fLLU, /* 202: 1.0e-146 << 549 */ + 0x9fd561f1fd0f9bd3LLU, /* 203: 1.0e-145 << 545 */ + 0xc7caba6e7c5382c8LLU, /* 204: 1.0e-144 << 542 */ + 0xf9bd690a1b68637bLLU, /* 205: 1.0e-143 << 539 */ + 0x9c1661a651213e2dLLU, /* 206: 1.0e-142 << 535 */ + 0xc31bfa0fe5698db8LLU, /* 207: 1.0e-141 << 532 */ + 0xf3e2f893dec3f126LLU, /* 208: 1.0e-140 << 529 */ + 0x986ddb5c6b3a76b7LLU, /* 209: 1.0e-139 << 525 */ + 0xbe89523386091465LLU, /* 210: 1.0e-138 << 522 */ + 0xee2ba6c0678b597fLLU, /* 211: 1.0e-137 << 519 */ + 0x94db483840b717efLLU, /* 212: 1.0e-136 << 515 */ + 0xba121a4650e4ddebLLU, /* 213: 1.0e-135 << 512 */ + 0xe896a0d7e51e1566LLU, /* 214: 1.0e-134 << 509 */ + 0x915e2486ef32cd60LLU, /* 215: 1.0e-133 << 505 */ + 0xb5b5ada8aaff80b8LLU, /* 216: 1.0e-132 << 502 */ + 0xe3231912d5bf60e6LLU, /* 217: 1.0e-131 << 499 */ + 0x8df5efabc5979c8fLLU, /* 218: 1.0e-130 << 495 */ + 0xb1736b96b6fd83b3LLU, /* 219: 1.0e-129 << 492 */ + 0xddd0467c64bce4a0LLU, /* 220: 1.0e-128 << 489 */ + 0x8aa22c0dbef60ee4LLU, /* 221: 1.0e-127 << 485 */ + 0xad4ab7112eb3929dLLU, /* 222: 1.0e-126 << 482 */ + 0xd89d64d57a607744LLU, /* 223: 1.0e-125 << 479 */ + 0x87625f056c7c4a8bLLU, /* 224: 1.0e-124 << 475 */ + 0xa93af6c6c79b5d2dLLU, /* 225: 1.0e-123 << 472 */ + 0xd389b47879823479LLU, /* 226: 1.0e-122 << 469 */ + 0x843610cb4bf160cbLLU, /* 227: 1.0e-121 << 465 */ + 0xa54394fe1eedb8feLLU, /* 228: 1.0e-120 << 462 */ + 0xce947a3da6a9273eLLU, /* 229: 1.0e-119 << 459 */ + 0x811ccc668829b887LLU, /* 230: 1.0e-118 << 455 */ + 0xa163ff802a3426a8LLU, /* 231: 1.0e-117 << 452 */ + 0xc9bcff6034c13052LLU, /* 232: 1.0e-116 << 449 */ + 0xfc2c3f3841f17c67LLU, /* 233: 1.0e-115 << 446 */ + 0x9d9ba7832936edc0LLU, /* 234: 1.0e-114 << 442 */ + 0xc5029163f384a931LLU, /* 235: 1.0e-113 << 439 */ + 0xf64335bcf065d37dLLU, /* 236: 1.0e-112 << 436 */ + 0x99ea0196163fa42eLLU, /* 237: 1.0e-111 << 432 */ + 0xc06481fb9bcf8d39LLU, /* 238: 1.0e-110 << 429 */ + 0xf07da27a82c37088LLU, /* 239: 1.0e-109 << 426 */ + 0x964e858c91ba2655LLU, /* 240: 1.0e-108 << 422 */ + 0xbbe226efb628afeaLLU, /* 241: 1.0e-107 << 419 */ + 0xeadab0aba3b2dbe5LLU, /* 242: 1.0e-106 << 416 */ + 0x92c8ae6b464fc96fLLU, /* 243: 1.0e-105 << 412 */ + 0xb77ada0617e3bbcbLLU, /* 244: 1.0e-104 << 409 */ + 0xe55990879ddcaabdLLU, /* 245: 1.0e-103 << 406 */ + 0x8f57fa54c2a9eab6LLU, /* 246: 1.0e-102 << 402 */ + 0xb32df8e9f3546564LLU, /* 247: 1.0e-101 << 399 */ + 0xdff9772470297ebdLLU, /* 248: 1.0e-100 << 396 */ + 0x8bfbea76c619ef36LLU, /* 249: 1.0e-99 << 392 */ + 0xaefae51477a06b03LLU, /* 250: 1.0e-98 << 389 */ + 0xdab99e59958885c4LLU, /* 251: 1.0e-97 << 386 */ + 0x88b402f7fd75539bLLU, /* 252: 1.0e-96 << 382 */ + 0xaae103b5fcd2a881LLU, /* 253: 1.0e-95 << 379 */ + 0xd59944a37c0752a2LLU, /* 254: 1.0e-94 << 376 */ + 0x857fcae62d8493a5LLU, /* 255: 1.0e-93 << 372 */ + 0xa6dfbd9fb8e5b88eLLU, /* 256: 1.0e-92 << 369 */ + 0xd097ad07a71f26b2LLU, /* 257: 1.0e-91 << 366 */ + 0x825ecc24c873782fLLU, /* 258: 1.0e-90 << 362 */ + 0xa2f67f2dfa90563bLLU, /* 259: 1.0e-89 << 359 */ + 0xcbb41ef979346bcaLLU, /* 260: 1.0e-88 << 356 */ + 0xfea126b7d78186bcLLU, /* 261: 1.0e-87 << 353 */ + 0x9f24b832e6b0f436LLU, /* 262: 1.0e-86 << 349 */ + 0xc6ede63fa05d3143LLU, /* 263: 1.0e-85 << 346 */ + 0xf8a95fcf88747d94LLU, /* 264: 1.0e-84 << 343 */ + 0x9b69dbe1b548ce7cLLU, /* 265: 1.0e-83 << 339 */ + 0xc24452da229b021bLLU, /* 266: 1.0e-82 << 336 */ + 0xf2d56790ab41c2a2LLU, /* 267: 1.0e-81 << 333 */ + 0x97c560ba6b0919a5LLU, /* 268: 1.0e-80 << 329 */ + 0xbdb6b8e905cb600fLLU, /* 269: 1.0e-79 << 326 */ + 0xed246723473e3813LLU, /* 270: 1.0e-78 << 323 */ + 0x9436c0760c86e30bLLU, /* 271: 1.0e-77 << 319 */ + 0xb94470938fa89bceLLU, /* 272: 1.0e-76 << 316 */ + 0xe7958cb87392c2c2LLU, /* 273: 1.0e-75 << 313 */ + 0x90bd77f3483bb9b9LLU, /* 274: 1.0e-74 << 309 */ + 0xb4ecd5f01a4aa828LLU, /* 275: 1.0e-73 << 306 */ + 0xe2280b6c20dd5232LLU, /* 276: 1.0e-72 << 303 */ + 0x8d590723948a535fLLU, /* 277: 1.0e-71 << 299 */ + 0xb0af48ec79ace837LLU, /* 278: 1.0e-70 << 296 */ + 0xdcdb1b2798182244LLU, /* 279: 1.0e-69 << 293 */ + 0x8a08f0f8bf0f156bLLU, /* 280: 1.0e-68 << 289 */ + 0xac8b2d36eed2dac5LLU, /* 281: 1.0e-67 << 286 */ + 0xd7adf884aa879177LLU, /* 282: 1.0e-66 << 283 */ + 0x86ccbb52ea94baeaLLU, /* 283: 1.0e-65 << 279 */ + 0xa87fea27a539e9a5LLU, /* 284: 1.0e-64 << 276 */ + 0xd29fe4b18e88640eLLU, /* 285: 1.0e-63 << 273 */ + 0x83a3eeeef9153e89LLU, /* 286: 1.0e-62 << 269 */ + 0xa48ceaaab75a8e2bLLU, /* 287: 1.0e-61 << 266 */ + 0xcdb02555653131b6LLU, /* 288: 1.0e-60 << 263 */ + 0x808e17555f3ebf11LLU, /* 289: 1.0e-59 << 259 */ + 0xa0b19d2ab70e6ed6LLU, /* 290: 1.0e-58 << 256 */ + 0xc8de047564d20a8bLLU, /* 291: 1.0e-57 << 253 */ + 0xfb158592be068d2eLLU, /* 292: 1.0e-56 << 250 */ + 0x9ced737bb6c4183dLLU, /* 293: 1.0e-55 << 246 */ + 0xc428d05aa4751e4cLLU, /* 294: 1.0e-54 << 243 */ + 0xf53304714d9265dfLLU, /* 295: 1.0e-53 << 240 */ + 0x993fe2c6d07b7fabLLU, /* 296: 1.0e-52 << 236 */ + 0xbf8fdb78849a5f96LLU, /* 297: 1.0e-51 << 233 */ + 0xef73d256a5c0f77cLLU, /* 298: 1.0e-50 << 230 */ + 0x95a8637627989aadLLU, /* 299: 1.0e-49 << 226 */ + 0xbb127c53b17ec159LLU, /* 300: 1.0e-48 << 223 */ + 0xe9d71b689dde71afLLU, /* 301: 1.0e-47 << 220 */ + 0x9226712162ab070dLLU, /* 302: 1.0e-46 << 216 */ + 0xb6b00d69bb55c8d1LLU, /* 303: 1.0e-45 << 213 */ + 0xe45c10c42a2b3b05LLU, /* 304: 1.0e-44 << 210 */ + 0x8eb98a7a9a5b04e3LLU, /* 305: 1.0e-43 << 206 */ + 0xb267ed1940f1c61cLLU, /* 306: 1.0e-42 << 203 */ + 0xdf01e85f912e37a3LLU, /* 307: 1.0e-41 << 200 */ + 0x8b61313bbabce2c6LLU, /* 308: 1.0e-40 << 196 */ + 0xae397d8aa96c1b77LLU, /* 309: 1.0e-39 << 193 */ + 0xd9c7dced53c72255LLU, /* 310: 1.0e-38 << 190 */ + 0x881cea14545c7575LLU, /* 311: 1.0e-37 << 186 */ + 0xaa242499697392d2LLU, /* 312: 1.0e-36 << 183 */ + 0xd4ad2dbfc3d07787LLU, /* 313: 1.0e-35 << 180 */ + 0x84ec3c97da624ab4LLU, /* 314: 1.0e-34 << 176 */ + 0xa6274bbdd0fadd61LLU, /* 315: 1.0e-33 << 173 */ + 0xcfb11ead453994baLLU, /* 316: 1.0e-32 << 170 */ + 0x81ceb32c4b43fcf4LLU, /* 317: 1.0e-31 << 166 */ + 0xa2425ff75e14fc31LLU, /* 318: 1.0e-30 << 163 */ + 0xcad2f7f5359a3b3eLLU, /* 319: 1.0e-29 << 160 */ + 0xfd87b5f28300ca0dLLU, /* 320: 1.0e-28 << 157 */ + 0x9e74d1b791e07e48LLU, /* 321: 1.0e-27 << 153 */ + 0xc612062576589ddaLLU, /* 322: 1.0e-26 << 150 */ + 0xf79687aed3eec551LLU, /* 323: 1.0e-25 << 147 */ + 0x9abe14cd44753b52LLU, /* 324: 1.0e-24 << 143 */ + 0xc16d9a0095928a27LLU, /* 325: 1.0e-23 << 140 */ + 0xf1c90080baf72cb1LLU, /* 326: 1.0e-22 << 137 */ + 0x971da05074da7beeLLU, /* 327: 1.0e-21 << 133 */ + 0xbce5086492111aeaLLU, /* 328: 1.0e-20 << 130 */ + 0xec1e4a7db69561a5LLU, /* 329: 1.0e-19 << 127 */ + 0x9392ee8e921d5d07LLU, /* 330: 1.0e-18 << 123 */ + 0xb877aa3236a4b449LLU, /* 331: 1.0e-17 << 120 */ + 0xe69594bec44de15bLLU, /* 332: 1.0e-16 << 117 */ + 0x901d7cf73ab0acd9LLU, /* 333: 1.0e-15 << 113 */ + 0xb424dc35095cd80fLLU, /* 334: 1.0e-14 << 110 */ + 0xe12e13424bb40e13LLU, /* 335: 1.0e-13 << 107 */ + 0x8cbccc096f5088cbLLU, /* 336: 1.0e-12 << 103 */ + 0xafebff0bcb24aafeLLU, /* 337: 1.0e-11 << 100 */ + 0xdbe6fecebdedd5beLLU, /* 338: 1.0e-10 << 97 */ + 0x89705f4136b4a597LLU, /* 339: 1.0e-9 << 93 */ + 0xabcc77118461cefcLLU, /* 340: 1.0e-8 << 90 */ + 0xd6bf94d5e57a42bcLLU, /* 341: 1.0e-7 << 87 */ + 0x8637bd05af6c69b5LLU, /* 342: 1.0e-6 << 83 */ + 0xa7c5ac471b478423LLU, /* 343: 1.0e-5 << 80 */ + 0xd1b71758e219652bLLU, /* 344: 1.0e-4 << 77 */ + 0x83126e978d4fdf3bLLU, /* 345: 1.0e-3 << 73 */ + 0xa3d70a3d70a3d70aLLU, /* 346: 1.0e-2 << 70 */ + 0xccccccccccccccccLLU, /* 347: 1.0e-1 << 67 */ + 0x8000000000000000LLU, /* 348: 1.0e+0 << 63 */ + 0xa000000000000000LLU, /* 349: 1.0e+1 << 60 */ + 0xc800000000000000LLU, /* 350: 1.0e+2 << 57 */ + 0xfa00000000000000LLU, /* 351: 1.0e+3 << 54 */ + 0x9c40000000000000LLU, /* 352: 1.0e+4 << 50 */ + 0xc350000000000000LLU, /* 353: 1.0e+5 << 47 */ + 0xf424000000000000LLU, /* 354: 1.0e+6 << 44 */ + 0x9896800000000000LLU, /* 355: 1.0e+7 << 40 */ + 0xbebc200000000000LLU, /* 356: 1.0e+8 << 37 */ + 0xee6b280000000000LLU, /* 357: 1.0e+9 << 34 */ + 0x9502f90000000000LLU, /* 358: 1.0e+10 << 30 */ + 0xba43b74000000000LLU, /* 359: 1.0e+11 << 27 */ + 0xe8d4a51000000000LLU, /* 360: 1.0e+12 << 24 */ + 0x9184e72a00000000LLU, /* 361: 1.0e+13 << 20 */ + 0xb5e620f480000000LLU, /* 362: 1.0e+14 << 17 */ + 0xe35fa931a0000000LLU, /* 363: 1.0e+15 << 14 */ + 0x8e1bc9bf04000000LLU, /* 364: 1.0e+16 << 10 */ + 0xb1a2bc2ec5000000LLU, /* 365: 1.0e+17 << 7 */ + 0xde0b6b3a76400000LLU, /* 366: 1.0e+18 << 4 */ + 0x8ac7230489e80000LLU, /* 367: 1.0e+19 >> 0 */ + 0xad78ebc5ac620000LLU, /* 368: 1.0e+20 >> 3 */ + 0xd8d726b7177a8000LLU, /* 369: 1.0e+21 >> 6 */ + 0x878678326eac9000LLU, /* 370: 1.0e+22 >> 10 */ + 0xa968163f0a57b400LLU, /* 371: 1.0e+23 >> 13 */ + 0xd3c21bcecceda100LLU, /* 372: 1.0e+24 >> 16 */ + 0x84595161401484a0LLU, /* 373: 1.0e+25 >> 20 */ + 0xa56fa5b99019a5c8LLU, /* 374: 1.0e+26 >> 23 */ + 0xcecb8f27f4200f3aLLU, /* 375: 1.0e+27 >> 26 */ + 0x813f3978f8940984LLU, /* 376: 1.0e+28 >> 30 */ + 0xa18f07d736b90be5LLU, /* 377: 1.0e+29 >> 33 */ + 0xc9f2c9cd04674edeLLU, /* 378: 1.0e+30 >> 36 */ + 0xfc6f7c4045812296LLU, /* 379: 1.0e+31 >> 39 */ + 0x9dc5ada82b70b59dLLU, /* 380: 1.0e+32 >> 43 */ + 0xc5371912364ce305LLU, /* 381: 1.0e+33 >> 46 */ + 0xf684df56c3e01bc6LLU, /* 382: 1.0e+34 >> 49 */ + 0x9a130b963a6c115cLLU, /* 383: 1.0e+35 >> 53 */ + 0xc097ce7bc90715b3LLU, /* 384: 1.0e+36 >> 56 */ + 0xf0bdc21abb48db20LLU, /* 385: 1.0e+37 >> 59 */ + 0x96769950b50d88f4LLU, /* 386: 1.0e+38 >> 63 */ + 0xbc143fa4e250eb31LLU, /* 387: 1.0e+39 >> 66 */ + 0xeb194f8e1ae525fdLLU, /* 388: 1.0e+40 >> 69 */ + 0x92efd1b8d0cf37beLLU, /* 389: 1.0e+41 >> 73 */ + 0xb7abc627050305adLLU, /* 390: 1.0e+42 >> 76 */ + 0xe596b7b0c643c719LLU, /* 391: 1.0e+43 >> 79 */ + 0x8f7e32ce7bea5c6fLLU, /* 392: 1.0e+44 >> 83 */ + 0xb35dbf821ae4f38bLLU, /* 393: 1.0e+45 >> 86 */ + 0xe0352f62a19e306eLLU, /* 394: 1.0e+46 >> 89 */ + 0x8c213d9da502de45LLU, /* 395: 1.0e+47 >> 93 */ + 0xaf298d050e4395d6LLU, /* 396: 1.0e+48 >> 96 */ + 0xdaf3f04651d47b4cLLU, /* 397: 1.0e+49 >> 99 */ + 0x88d8762bf324cd0fLLU, /* 398: 1.0e+50 >> 103 */ + 0xab0e93b6efee0053LLU, /* 399: 1.0e+51 >> 106 */ + 0xd5d238a4abe98068LLU, /* 400: 1.0e+52 >> 109 */ + 0x85a36366eb71f041LLU, /* 401: 1.0e+53 >> 113 */ + 0xa70c3c40a64e6c51LLU, /* 402: 1.0e+54 >> 116 */ + 0xd0cf4b50cfe20765LLU, /* 403: 1.0e+55 >> 119 */ + 0x82818f1281ed449fLLU, /* 404: 1.0e+56 >> 123 */ + 0xa321f2d7226895c7LLU, /* 405: 1.0e+57 >> 126 */ + 0xcbea6f8ceb02bb39LLU, /* 406: 1.0e+58 >> 129 */ + 0xfee50b7025c36a08LLU, /* 407: 1.0e+59 >> 132 */ + 0x9f4f2726179a2245LLU, /* 408: 1.0e+60 >> 136 */ + 0xc722f0ef9d80aad6LLU, /* 409: 1.0e+61 >> 139 */ + 0xf8ebad2b84e0d58bLLU, /* 410: 1.0e+62 >> 142 */ + 0x9b934c3b330c8577LLU, /* 411: 1.0e+63 >> 146 */ + 0xc2781f49ffcfa6d5LLU, /* 412: 1.0e+64 >> 149 */ + 0xf316271c7fc3908aLLU, /* 413: 1.0e+65 >> 152 */ + 0x97edd871cfda3a56LLU, /* 414: 1.0e+66 >> 156 */ + 0xbde94e8e43d0c8ecLLU, /* 415: 1.0e+67 >> 159 */ + 0xed63a231d4c4fb27LLU, /* 416: 1.0e+68 >> 162 */ + 0x945e455f24fb1cf8LLU, /* 417: 1.0e+69 >> 166 */ + 0xb975d6b6ee39e436LLU, /* 418: 1.0e+70 >> 169 */ + 0xe7d34c64a9c85d44LLU, /* 419: 1.0e+71 >> 172 */ + 0x90e40fbeea1d3a4aLLU, /* 420: 1.0e+72 >> 176 */ + 0xb51d13aea4a488ddLLU, /* 421: 1.0e+73 >> 179 */ + 0xe264589a4dcdab14LLU, /* 422: 1.0e+74 >> 182 */ + 0x8d7eb76070a08aecLLU, /* 423: 1.0e+75 >> 186 */ + 0xb0de65388cc8ada8LLU, /* 424: 1.0e+76 >> 189 */ + 0xdd15fe86affad912LLU, /* 425: 1.0e+77 >> 192 */ + 0x8a2dbf142dfcc7abLLU, /* 426: 1.0e+78 >> 196 */ + 0xacb92ed9397bf996LLU, /* 427: 1.0e+79 >> 199 */ + 0xd7e77a8f87daf7fbLLU, /* 428: 1.0e+80 >> 202 */ + 0x86f0ac99b4e8dafdLLU, /* 429: 1.0e+81 >> 206 */ + 0xa8acd7c0222311bcLLU, /* 430: 1.0e+82 >> 209 */ + 0xd2d80db02aabd62bLLU, /* 431: 1.0e+83 >> 212 */ + 0x83c7088e1aab65dbLLU, /* 432: 1.0e+84 >> 216 */ + 0xa4b8cab1a1563f52LLU, /* 433: 1.0e+85 >> 219 */ + 0xcde6fd5e09abcf26LLU, /* 434: 1.0e+86 >> 222 */ + 0x80b05e5ac60b6178LLU, /* 435: 1.0e+87 >> 226 */ + 0xa0dc75f1778e39d6LLU, /* 436: 1.0e+88 >> 229 */ + 0xc913936dd571c84cLLU, /* 437: 1.0e+89 >> 232 */ + 0xfb5878494ace3a5fLLU, /* 438: 1.0e+90 >> 235 */ + 0x9d174b2dcec0e47bLLU, /* 439: 1.0e+91 >> 239 */ + 0xc45d1df942711d9aLLU, /* 440: 1.0e+92 >> 242 */ + 0xf5746577930d6500LLU, /* 441: 1.0e+93 >> 245 */ + 0x9968bf6abbe85f20LLU, /* 442: 1.0e+94 >> 249 */ + 0xbfc2ef456ae276e8LLU, /* 443: 1.0e+95 >> 252 */ + 0xefb3ab16c59b14a2LLU, /* 444: 1.0e+96 >> 255 */ + 0x95d04aee3b80ece5LLU, /* 445: 1.0e+97 >> 259 */ + 0xbb445da9ca61281fLLU, /* 446: 1.0e+98 >> 262 */ + 0xea1575143cf97226LLU, /* 447: 1.0e+99 >> 265 */ + 0x924d692ca61be758LLU, /* 448: 1.0e+100 >> 269 */ + 0xb6e0c377cfa2e12eLLU, /* 449: 1.0e+101 >> 272 */ + 0xe498f455c38b997aLLU, /* 450: 1.0e+102 >> 275 */ + 0x8edf98b59a373fecLLU, /* 451: 1.0e+103 >> 279 */ + 0xb2977ee300c50fe7LLU, /* 452: 1.0e+104 >> 282 */ + 0xdf3d5e9bc0f653e1LLU, /* 453: 1.0e+105 >> 285 */ + 0x8b865b215899f46cLLU, /* 454: 1.0e+106 >> 289 */ + 0xae67f1e9aec07187LLU, /* 455: 1.0e+107 >> 292 */ + 0xda01ee641a708de9LLU, /* 456: 1.0e+108 >> 295 */ + 0x884134fe908658b2LLU, /* 457: 1.0e+109 >> 299 */ + 0xaa51823e34a7eedeLLU, /* 458: 1.0e+110 >> 302 */ + 0xd4e5e2cdc1d1ea96LLU, /* 459: 1.0e+111 >> 305 */ + 0x850fadc09923329eLLU, /* 460: 1.0e+112 >> 309 */ + 0xa6539930bf6bff45LLU, /* 461: 1.0e+113 >> 312 */ + 0xcfe87f7cef46ff16LLU, /* 462: 1.0e+114 >> 315 */ + 0x81f14fae158c5f6eLLU, /* 463: 1.0e+115 >> 319 */ + 0xa26da3999aef7749LLU, /* 464: 1.0e+116 >> 322 */ + 0xcb090c8001ab551cLLU, /* 465: 1.0e+117 >> 325 */ + 0xfdcb4fa002162a63LLU, /* 466: 1.0e+118 >> 328 */ + 0x9e9f11c4014dda7eLLU, /* 467: 1.0e+119 >> 332 */ + 0xc646d63501a1511dLLU, /* 468: 1.0e+120 >> 335 */ + 0xf7d88bc24209a565LLU, /* 469: 1.0e+121 >> 338 */ + 0x9ae757596946075fLLU, /* 470: 1.0e+122 >> 342 */ + 0xc1a12d2fc3978937LLU, /* 471: 1.0e+123 >> 345 */ + 0xf209787bb47d6b84LLU, /* 472: 1.0e+124 >> 348 */ + 0x9745eb4d50ce6332LLU, /* 473: 1.0e+125 >> 352 */ + 0xbd176620a501fbffLLU, /* 474: 1.0e+126 >> 355 */ + 0xec5d3fa8ce427affLLU, /* 475: 1.0e+127 >> 358 */ + 0x93ba47c980e98cdfLLU, /* 476: 1.0e+128 >> 362 */ + 0xb8a8d9bbe123f017LLU, /* 477: 1.0e+129 >> 365 */ + 0xe6d3102ad96cec1dLLU, /* 478: 1.0e+130 >> 368 */ + 0x9043ea1ac7e41392LLU, /* 479: 1.0e+131 >> 372 */ + 0xb454e4a179dd1877LLU, /* 480: 1.0e+132 >> 375 */ + 0xe16a1dc9d8545e94LLU, /* 481: 1.0e+133 >> 378 */ + 0x8ce2529e2734bb1dLLU, /* 482: 1.0e+134 >> 382 */ + 0xb01ae745b101e9e4LLU, /* 483: 1.0e+135 >> 385 */ + 0xdc21a1171d42645dLLU, /* 484: 1.0e+136 >> 388 */ + 0x899504ae72497ebaLLU, /* 485: 1.0e+137 >> 392 */ + 0xabfa45da0edbde69LLU, /* 486: 1.0e+138 >> 395 */ + 0xd6f8d7509292d603LLU, /* 487: 1.0e+139 >> 398 */ + 0x865b86925b9bc5c2LLU, /* 488: 1.0e+140 >> 402 */ + 0xa7f26836f282b732LLU, /* 489: 1.0e+141 >> 405 */ + 0xd1ef0244af2364ffLLU, /* 490: 1.0e+142 >> 408 */ + 0x8335616aed761f1fLLU, /* 491: 1.0e+143 >> 412 */ + 0xa402b9c5a8d3a6e7LLU, /* 492: 1.0e+144 >> 415 */ + 0xcd036837130890a1LLU, /* 493: 1.0e+145 >> 418 */ + 0x802221226be55a64LLU, /* 494: 1.0e+146 >> 422 */ + 0xa02aa96b06deb0fdLLU, /* 495: 1.0e+147 >> 425 */ + 0xc83553c5c8965d3dLLU, /* 496: 1.0e+148 >> 428 */ + 0xfa42a8b73abbf48cLLU, /* 497: 1.0e+149 >> 431 */ + 0x9c69a97284b578d7LLU, /* 498: 1.0e+150 >> 435 */ + 0xc38413cf25e2d70dLLU, /* 499: 1.0e+151 >> 438 */ + 0xf46518c2ef5b8cd1LLU, /* 500: 1.0e+152 >> 441 */ + 0x98bf2f79d5993802LLU, /* 501: 1.0e+153 >> 445 */ + 0xbeeefb584aff8603LLU, /* 502: 1.0e+154 >> 448 */ + 0xeeaaba2e5dbf6784LLU, /* 503: 1.0e+155 >> 451 */ + 0x952ab45cfa97a0b2LLU, /* 504: 1.0e+156 >> 455 */ + 0xba756174393d88dfLLU, /* 505: 1.0e+157 >> 458 */ + 0xe912b9d1478ceb17LLU, /* 506: 1.0e+158 >> 461 */ + 0x91abb422ccb812eeLLU, /* 507: 1.0e+159 >> 465 */ + 0xb616a12b7fe617aaLLU, /* 508: 1.0e+160 >> 468 */ + 0xe39c49765fdf9d94LLU, /* 509: 1.0e+161 >> 471 */ + 0x8e41ade9fbebc27dLLU, /* 510: 1.0e+162 >> 475 */ + 0xb1d219647ae6b31cLLU, /* 511: 1.0e+163 >> 478 */ + 0xde469fbd99a05fe3LLU, /* 512: 1.0e+164 >> 481 */ + 0x8aec23d680043beeLLU, /* 513: 1.0e+165 >> 485 */ + 0xada72ccc20054ae9LLU, /* 514: 1.0e+166 >> 488 */ + 0xd910f7ff28069da4LLU, /* 515: 1.0e+167 >> 491 */ + 0x87aa9aff79042286LLU, /* 516: 1.0e+168 >> 495 */ + 0xa99541bf57452b28LLU, /* 517: 1.0e+169 >> 498 */ + 0xd3fa922f2d1675f2LLU, /* 518: 1.0e+170 >> 501 */ + 0x847c9b5d7c2e09b7LLU, /* 519: 1.0e+171 >> 505 */ + 0xa59bc234db398c25LLU, /* 520: 1.0e+172 >> 508 */ + 0xcf02b2c21207ef2eLLU, /* 521: 1.0e+173 >> 511 */ + 0x8161afb94b44f57dLLU, /* 522: 1.0e+174 >> 515 */ + 0xa1ba1ba79e1632dcLLU, /* 523: 1.0e+175 >> 518 */ + 0xca28a291859bbf93LLU, /* 524: 1.0e+176 >> 521 */ + 0xfcb2cb35e702af78LLU, /* 525: 1.0e+177 >> 524 */ + 0x9defbf01b061adabLLU, /* 526: 1.0e+178 >> 528 */ + 0xc56baec21c7a1916LLU, /* 527: 1.0e+179 >> 531 */ + 0xf6c69a72a3989f5bLLU, /* 528: 1.0e+180 >> 534 */ + 0x9a3c2087a63f6399LLU, /* 529: 1.0e+181 >> 538 */ + 0xc0cb28a98fcf3c7fLLU, /* 530: 1.0e+182 >> 541 */ + 0xf0fdf2d3f3c30b9fLLU, /* 531: 1.0e+183 >> 544 */ + 0x969eb7c47859e743LLU, /* 532: 1.0e+184 >> 548 */ + 0xbc4665b596706114LLU, /* 533: 1.0e+185 >> 551 */ + 0xeb57ff22fc0c7959LLU, /* 534: 1.0e+186 >> 554 */ + 0x9316ff75dd87cbd8LLU, /* 535: 1.0e+187 >> 558 */ + 0xb7dcbf5354e9beceLLU, /* 536: 1.0e+188 >> 561 */ + 0xe5d3ef282a242e81LLU, /* 537: 1.0e+189 >> 564 */ + 0x8fa475791a569d10LLU, /* 538: 1.0e+190 >> 568 */ + 0xb38d92d760ec4455LLU, /* 539: 1.0e+191 >> 571 */ + 0xe070f78d3927556aLLU, /* 540: 1.0e+192 >> 574 */ + 0x8c469ab843b89562LLU, /* 541: 1.0e+193 >> 578 */ + 0xaf58416654a6babbLLU, /* 542: 1.0e+194 >> 581 */ + 0xdb2e51bfe9d0696aLLU, /* 543: 1.0e+195 >> 584 */ + 0x88fcf317f22241e2LLU, /* 544: 1.0e+196 >> 588 */ + 0xab3c2fddeeaad25aLLU, /* 545: 1.0e+197 >> 591 */ + 0xd60b3bd56a5586f1LLU, /* 546: 1.0e+198 >> 594 */ + 0x85c7056562757456LLU, /* 547: 1.0e+199 >> 598 */ + 0xa738c6bebb12d16cLLU, /* 548: 1.0e+200 >> 601 */ + 0xd106f86e69d785c7LLU, /* 549: 1.0e+201 >> 604 */ + 0x82a45b450226b39cLLU, /* 550: 1.0e+202 >> 608 */ + 0xa34d721642b06084LLU, /* 551: 1.0e+203 >> 611 */ + 0xcc20ce9bd35c78a5LLU, /* 552: 1.0e+204 >> 614 */ + 0xff290242c83396ceLLU, /* 553: 1.0e+205 >> 617 */ + 0x9f79a169bd203e41LLU, /* 554: 1.0e+206 >> 621 */ + 0xc75809c42c684dd1LLU, /* 555: 1.0e+207 >> 624 */ + 0xf92e0c3537826145LLU, /* 556: 1.0e+208 >> 627 */ + 0x9bbcc7a142b17ccbLLU, /* 557: 1.0e+209 >> 631 */ + 0xc2abf989935ddbfeLLU, /* 558: 1.0e+210 >> 634 */ + 0xf356f7ebf83552feLLU, /* 559: 1.0e+211 >> 637 */ + 0x98165af37b2153deLLU, /* 560: 1.0e+212 >> 641 */ + 0xbe1bf1b059e9a8d6LLU, /* 561: 1.0e+213 >> 644 */ + 0xeda2ee1c7064130cLLU, /* 562: 1.0e+214 >> 647 */ + 0x9485d4d1c63e8be7LLU, /* 563: 1.0e+215 >> 651 */ + 0xb9a74a0637ce2ee1LLU, /* 564: 1.0e+216 >> 654 */ + 0xe8111c87c5c1ba99LLU, /* 565: 1.0e+217 >> 657 */ + 0x910ab1d4db9914a0LLU, /* 566: 1.0e+218 >> 661 */ + 0xb54d5e4a127f59c8LLU, /* 567: 1.0e+219 >> 664 */ + 0xe2a0b5dc971f303aLLU, /* 568: 1.0e+220 >> 667 */ + 0x8da471a9de737e24LLU, /* 569: 1.0e+221 >> 671 */ + 0xb10d8e1456105dadLLU, /* 570: 1.0e+222 >> 674 */ + 0xdd50f1996b947518LLU, /* 571: 1.0e+223 >> 677 */ + 0x8a5296ffe33cc92fLLU, /* 572: 1.0e+224 >> 681 */ + 0xace73cbfdc0bfb7bLLU, /* 573: 1.0e+225 >> 684 */ + 0xd8210befd30efa5aLLU, /* 574: 1.0e+226 >> 687 */ + 0x8714a775e3e95c78LLU, /* 575: 1.0e+227 >> 691 */ + 0xa8d9d1535ce3b396LLU, /* 576: 1.0e+228 >> 694 */ + 0xd31045a8341ca07cLLU, /* 577: 1.0e+229 >> 697 */ + 0x83ea2b892091e44dLLU, /* 578: 1.0e+230 >> 701 */ + 0xa4e4b66b68b65d60LLU, /* 579: 1.0e+231 >> 704 */ + 0xce1de40642e3f4b9LLU, /* 580: 1.0e+232 >> 707 */ + 0x80d2ae83e9ce78f3LLU, /* 581: 1.0e+233 >> 711 */ + 0xa1075a24e4421730LLU, /* 582: 1.0e+234 >> 714 */ + 0xc94930ae1d529cfcLLU, /* 583: 1.0e+235 >> 717 */ + 0xfb9b7cd9a4a7443cLLU, /* 584: 1.0e+236 >> 720 */ + 0x9d412e0806e88aa5LLU, /* 585: 1.0e+237 >> 724 */ + 0xc491798a08a2ad4eLLU, /* 586: 1.0e+238 >> 727 */ + 0xf5b5d7ec8acb58a2LLU, /* 587: 1.0e+239 >> 730 */ + 0x9991a6f3d6bf1765LLU, /* 588: 1.0e+240 >> 734 */ + 0xbff610b0cc6edd3fLLU, /* 589: 1.0e+241 >> 737 */ + 0xeff394dcff8a948eLLU, /* 590: 1.0e+242 >> 740 */ + 0x95f83d0a1fb69cd9LLU, /* 591: 1.0e+243 >> 744 */ + 0xbb764c4ca7a4440fLLU, /* 592: 1.0e+244 >> 747 */ + 0xea53df5fd18d5513LLU, /* 593: 1.0e+245 >> 750 */ + 0x92746b9be2f8552cLLU, /* 594: 1.0e+246 >> 754 */ + 0xb7118682dbb66a77LLU, /* 595: 1.0e+247 >> 757 */ + 0xe4d5e82392a40515LLU, /* 596: 1.0e+248 >> 760 */ + 0x8f05b1163ba6832dLLU, /* 597: 1.0e+249 >> 764 */ + 0xb2c71d5bca9023f8LLU, /* 598: 1.0e+250 >> 767 */ + 0xdf78e4b2bd342cf6LLU, /* 599: 1.0e+251 >> 770 */ + 0x8bab8eefb6409c1aLLU, /* 600: 1.0e+252 >> 774 */ + 0xae9672aba3d0c320LLU, /* 601: 1.0e+253 >> 777 */ + 0xda3c0f568cc4f3e8LLU, /* 602: 1.0e+254 >> 780 */ + 0x8865899617fb1871LLU, /* 603: 1.0e+255 >> 784 */ + 0xaa7eebfb9df9de8dLLU, /* 604: 1.0e+256 >> 787 */ + 0xd51ea6fa85785631LLU, /* 605: 1.0e+257 >> 790 */ + 0x8533285c936b35deLLU, /* 606: 1.0e+258 >> 794 */ + 0xa67ff273b8460356LLU, /* 607: 1.0e+259 >> 797 */ + 0xd01fef10a657842cLLU, /* 608: 1.0e+260 >> 800 */ + 0x8213f56a67f6b29bLLU, /* 609: 1.0e+261 >> 804 */ + 0xa298f2c501f45f42LLU, /* 610: 1.0e+262 >> 807 */ + 0xcb3f2f7642717713LLU, /* 611: 1.0e+263 >> 810 */ + 0xfe0efb53d30dd4d7LLU, /* 612: 1.0e+264 >> 813 */ + 0x9ec95d1463e8a506LLU, /* 613: 1.0e+265 >> 817 */ + 0xc67bb4597ce2ce48LLU, /* 614: 1.0e+266 >> 820 */ + 0xf81aa16fdc1b81daLLU, /* 615: 1.0e+267 >> 823 */ + 0x9b10a4e5e9913128LLU, /* 616: 1.0e+268 >> 827 */ + 0xc1d4ce1f63f57d72LLU, /* 617: 1.0e+269 >> 830 */ + 0xf24a01a73cf2dccfLLU, /* 618: 1.0e+270 >> 833 */ + 0x976e41088617ca01LLU, /* 619: 1.0e+271 >> 837 */ + 0xbd49d14aa79dbc82LLU, /* 620: 1.0e+272 >> 840 */ + 0xec9c459d51852ba2LLU, /* 621: 1.0e+273 >> 843 */ + 0x93e1ab8252f33b45LLU, /* 622: 1.0e+274 >> 847 */ + 0xb8da1662e7b00a17LLU, /* 623: 1.0e+275 >> 850 */ + 0xe7109bfba19c0c9dLLU, /* 624: 1.0e+276 >> 853 */ + 0x906a617d450187e2LLU, /* 625: 1.0e+277 >> 857 */ + 0xb484f9dc9641e9daLLU, /* 626: 1.0e+278 >> 860 */ + 0xe1a63853bbd26451LLU, /* 627: 1.0e+279 >> 863 */ + 0x8d07e33455637eb2LLU, /* 628: 1.0e+280 >> 867 */ + 0xb049dc016abc5e5fLLU, /* 629: 1.0e+281 >> 870 */ + 0xdc5c5301c56b75f7LLU, /* 630: 1.0e+282 >> 873 */ + 0x89b9b3e11b6329baLLU, /* 631: 1.0e+283 >> 877 */ + 0xac2820d9623bf429LLU, /* 632: 1.0e+284 >> 880 */ + 0xd732290fbacaf133LLU, /* 633: 1.0e+285 >> 883 */ + 0x867f59a9d4bed6c0LLU, /* 634: 1.0e+286 >> 887 */ + 0xa81f301449ee8c70LLU, /* 635: 1.0e+287 >> 890 */ + 0xd226fc195c6a2f8cLLU, /* 636: 1.0e+288 >> 893 */ + 0x83585d8fd9c25db7LLU, /* 637: 1.0e+289 >> 897 */ + 0xa42e74f3d032f525LLU, /* 638: 1.0e+290 >> 900 */ + 0xcd3a1230c43fb26fLLU, /* 639: 1.0e+291 >> 903 */ + 0x80444b5e7aa7cf85LLU, /* 640: 1.0e+292 >> 907 */ + 0xa0555e361951c366LLU, /* 641: 1.0e+293 >> 910 */ + 0xc86ab5c39fa63440LLU, /* 642: 1.0e+294 >> 913 */ + 0xfa856334878fc150LLU, /* 643: 1.0e+295 >> 916 */ + 0x9c935e00d4b9d8d2LLU, /* 644: 1.0e+296 >> 920 */ + 0xc3b8358109e84f07LLU, /* 645: 1.0e+297 >> 923 */ + 0xf4a642e14c6262c8LLU, /* 646: 1.0e+298 >> 926 */ + 0x98e7e9cccfbd7dbdLLU, /* 647: 1.0e+299 >> 930 */ + 0xbf21e44003acdd2cLLU, /* 648: 1.0e+300 >> 933 */ + 0xeeea5d5004981478LLU, /* 649: 1.0e+301 >> 936 */ + 0x95527a5202df0ccbLLU, /* 650: 1.0e+302 >> 940 */ + 0xbaa718e68396cffdLLU, /* 651: 1.0e+303 >> 943 */ + 0xe950df20247c83fdLLU, /* 652: 1.0e+304 >> 946 */ + 0x91d28b7416cdd27eLLU, /* 653: 1.0e+305 >> 950 */ + 0xb6472e511c81471dLLU, /* 654: 1.0e+306 >> 953 */ + 0xe3d8f9e563a198e5LLU, /* 655: 1.0e+307 >> 956 */ + 0x8e679c2f5e44ff8fLLU, /* 656: 1.0e+308 >> 960 */ + 0xb201833b35d63f73LLU, /* 657: 1.0e+309 >> 963 */ + 0xde81e40a034bcf4fLLU, /* 658: 1.0e+310 >> 966 */ + 0x8b112e86420f6191LLU, /* 659: 1.0e+311 >> 970 */ + 0xadd57a27d29339f6LLU, /* 660: 1.0e+312 >> 973 */ + 0xd94ad8b1c7380874LLU, /* 661: 1.0e+313 >> 976 */ + 0x87cec76f1c830548LLU, /* 662: 1.0e+314 >> 980 */ + 0xa9c2794ae3a3c69aLLU, /* 663: 1.0e+315 >> 983 */ + 0xd433179d9c8cb841LLU, /* 664: 1.0e+316 >> 986 */ + 0x849feec281d7f328LLU, /* 665: 1.0e+317 >> 990 */ + 0xa5c7ea73224deff3LLU, /* 666: 1.0e+318 >> 993 */ + 0xcf39e50feae16befLLU, /* 667: 1.0e+319 >> 996 */ + 0x81842f29f2cce375LLU, /* 668: 1.0e+320 >> 1000 */ + 0xa1e53af46f801c53LLU, /* 669: 1.0e+321 >> 1003 */ + 0xca5e89b18b602368LLU, /* 670: 1.0e+322 >> 1006 */ + 0xfcf62c1dee382c42LLU, /* 671: 1.0e+323 >> 1009 */ + 0x9e19db92b4e31ba9LLU, /* 672: 1.0e+324 >> 1013 */ + 0xc5a05277621be293LLU, /* 673: 1.0e+325 >> 1016 */ + 0xf70867153aa2db38LLU, /* 674: 1.0e+326 >> 1019 */ + 0x9a65406d44a5c903LLU, /* 675: 1.0e+327 >> 1023 */ + 0xc0fe908895cf3b44LLU, /* 676: 1.0e+328 >> 1026 */ + 0xf13e34aabb430a15LLU, /* 677: 1.0e+329 >> 1029 */ + 0x96c6e0eab509e64dLLU, /* 678: 1.0e+330 >> 1033 */ + 0xbc789925624c5fe0LLU, /* 679: 1.0e+331 >> 1036 */ + 0xeb96bf6ebadf77d8LLU, /* 680: 1.0e+332 >> 1039 */ + 0x933e37a534cbaae7LLU, /* 681: 1.0e+333 >> 1043 */ + 0xb80dc58e81fe95a1LLU, /* 682: 1.0e+334 >> 1046 */ + 0xe61136f2227e3b09LLU, /* 683: 1.0e+335 >> 1049 */ + 0x8fcac257558ee4e6LLU, /* 684: 1.0e+336 >> 1053 */ + 0xb3bd72ed2af29e1fLLU, /* 685: 1.0e+337 >> 1056 */ + 0xe0accfa875af45a7LLU, /* 686: 1.0e+338 >> 1059 */ + 0x8c6c01c9498d8b88LLU, /* 687: 1.0e+339 >> 1063 */ + 0xaf87023b9bf0ee6aLLU, /* 688: 1.0e+340 >> 1066 */ + 0xdb68c2ca82ed2a05LLU, /* 689: 1.0e+341 >> 1069 */ + 0x892179be91d43a43LLU, /* 690: 1.0e+342 >> 1073 */ + 0xab69d82e364948d4LLU, /* 691: 1.0e+343 >> 1076 */ + 0xd6444e39c3db9b09LLU, /* 692: 1.0e+344 >> 1079 */ + 0x85eab0e41a6940e5LLU, /* 693: 1.0e+345 >> 1083 */ + 0xa7655d1d2103911fLLU, /* 694: 1.0e+346 >> 1086 */ + 0xd13eb46469447567LLU, /* 695: 1.0e+347 >> 1089 */ }; #define POWERSOF10_FIRST (-348) #define POWERSOF10_LAST (+347) From 658908a32ff372429db18a10113df67f37637713 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 Feb 2026 22:04:53 +0000 Subject: [PATCH 014/197] Fix to [9d3a12d3926d55ef] to force the static const string literal to have two-byte alignment. Necessary to get that patch to work in Mac-ARM. FossilOrigin-Name: a80c847169f307a4d2e524b6732ea557bf7f312f1a319d6c6c2e81adb0907596 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 12 ++++++++---- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index a4253c97de..b6b573f2ec 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\s"LLU"\ssuffix\sto\s64-bit\sinteger\sconstants,\sfor\sportability\sto\solder\ncompilers. -D 2026-02-14T21:47:08.084 +C Fix\sto\s[9d3a12d3926d55ef]\sto\sforce\sthe\sstatic\sconst\sstring\sliteral\sto\nhave\stwo-byte\salignment.\s\sNecessary\sto\sget\sthat\spatch\sto\swork\sin\sMac-ARM. +D 2026-02-14T22:04:53.811 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c d7cd5a4c9859c260b17d3e2d821306a265f6a4d0962941a1d187b4ccaf74c455 +F src/util.c 2b95816e47e3e789c3a803a8591678c082c24e78146175e9c1b9039c61869ec0 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 9c3d09ee75beb26447161c0bf5ea252520a6ec051774f1a4e9f18204281d504f -R 81af0af5ea2a6b0d90ff8f5528e1d00d +P 4bf08110662c4b8db9ee90ce34271890a62a469166ea292f7f782b84236531d4 +R e9a61f8d803b1efd3bc1e0ac0477000a U drh -Z d1c5742bcc364eb12a36c71331cc2f0e +Z 60f49f9dc3f68ee820a036cf7efdaecb # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1f157b26f3..ad4d726634 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4bf08110662c4b8db9ee90ce34271890a62a469166ea292f7f782b84236531d4 +a80c847169f307a4d2e524b6732ea557bf7f312f1a319d6c6c2e81adb0907596 diff --git a/src/util.c b/src/util.c index b0ab7dde3a..8ae247a328 100644 --- a/src/util.c +++ b/src/util.c @@ -1823,7 +1823,10 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ i = sizeof(p->zBuf)-1; assert( v>0 ); while( v>=10 ){ - static const char dig[] = + static const union { + char a[200]; + short int forAlignment; + } dig = { "00010203040506070809" "10111213141516171819" "20212223242526272829" @@ -1833,11 +1836,12 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ "60616263646566676869" "70717273747576777879" "80818283848586878889" - "90919293949596979899"; + "90919293949596979899" + }; int kk = (v%100)*2; - assert( TWO_BYTE_ALIGNMENT(&dig[kk]) ); + assert( TWO_BYTE_ALIGNMENT(&dig.a[kk]) ); assert( TWO_BYTE_ALIGNMENT(&p->zBuf[i-1]) ); - *(u16*)(&p->zBuf[i-1]) = *(u16*)&dig[kk]; + *(u16*)(&p->zBuf[i-1]) = *(u16*)&dig.a[kk]; i -= 2; v /= 100; } From adbb756155417c9cac1c0ea3205578db29d7b8cb Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 15 Feb 2026 18:41:29 +0000 Subject: [PATCH 015/197] Avoid the big power-of-ten lookup table. FossilOrigin-Name: 245ac7d9ec61e14fcef13a731e290fc5e8979efef6f4345f875eab9b882b0713 --- manifest | 12 +- manifest.uuid | 2 +- src/util.c | 850 +++++++------------------------------------------- 3 files changed, 127 insertions(+), 737 deletions(-) diff --git a/manifest b/manifest index b6b573f2ec..62d504e47c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sto\s[9d3a12d3926d55ef]\sto\sforce\sthe\sstatic\sconst\sstring\sliteral\sto\nhave\stwo-byte\salignment.\s\sNecessary\sto\sget\sthat\spatch\sto\swork\sin\sMac-ARM. -D 2026-02-14T22:04:53.811 +C Avoid\sthe\sbig\spower-of-ten\slookup\stable. +D 2026-02-15T18:41:29.104 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c cb894db98083c68c4a17c72566ed39434aa91286db20d2891279ee49e6bfec0c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 2b95816e47e3e789c3a803a8591678c082c24e78146175e9c1b9039c61869ec0 +F src/util.c 0cc410d538fe13a2cda90a8d0087c82cf4c1ab0d5055b8e3a595f28266f190c7 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 4bf08110662c4b8db9ee90ce34271890a62a469166ea292f7f782b84236531d4 -R e9a61f8d803b1efd3bc1e0ac0477000a +P a80c847169f307a4d2e524b6732ea557bf7f312f1a319d6c6c2e81adb0907596 +R 3eb7e8d20bd192b2f6690ce98ebbba28 U drh -Z 60f49f9dc3f68ee820a036cf7efdaecb +Z 4720cdecbf1fe28948310be768602949 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ad4d726634..fc8d52e1ce 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a80c847169f307a4d2e524b6732ea557bf7f312f1a319d6c6c2e81adb0907596 +245ac7d9ec61e14fcef13a731e290fc5e8979efef6f4345f875eab9b882b0713 diff --git a/src/util.c b/src/util.c index 8ae247a328..9522c14c0c 100644 --- a/src/util.c +++ b/src/util.c @@ -457,725 +457,6 @@ u8 sqlite3StrIHash(const char *z){ } return h; } -/* -** The following array holds (approximate) powers-of-ten between -** 1.0e-348 and 1.0e+347. Each value is an unsigned 64-bit integer, -** shifted so that its most significant bit is 1. -** -** For the power-of-ten whose value is pow(10,p), the value -** is shifted left or right in order to multiply it by -** pow(2,63-pow10to2(p)). Hence, another way to think of the -** entries in this table is: -** -** for p from -348 to +347: -** int( pow(10,p)*pow(2,63-pow10to2(p)) ) -** -** The int(x) function means the integer part of value x. See -** the definition of pow10to2() below for more details about that -** function. There is an assert() in the utility program that -** generates this table that verifies the invariant described above. -*/ -static const u64 sqlite3PowerOfTen[] = { - 0xfa8fd5a0081c0288LLU, /* 0: 1.0e-348 << 1220 */ - 0x9c99e58405118195LLU, /* 1: 1.0e-347 << 1216 */ - 0xc3c05ee50655e1faLLU, /* 2: 1.0e-346 << 1213 */ - 0xf4b0769e47eb5a78LLU, /* 3: 1.0e-345 << 1210 */ - 0x98ee4a22ecf3188bLLU, /* 4: 1.0e-344 << 1206 */ - 0xbf29dcaba82fdeaeLLU, /* 5: 1.0e-343 << 1203 */ - 0xeef453d6923bd65aLLU, /* 6: 1.0e-342 << 1200 */ - 0x9558b4661b6565f8LLU, /* 7: 1.0e-341 << 1196 */ - 0xbaaee17fa23ebf76LLU, /* 8: 1.0e-340 << 1193 */ - 0xe95a99df8ace6f53LLU, /* 9: 1.0e-339 << 1190 */ - 0x91d8a02bb6c10594LLU, /* 10: 1.0e-338 << 1186 */ - 0xb64ec836a47146f9LLU, /* 11: 1.0e-337 << 1183 */ - 0xe3e27a444d8d98b7LLU, /* 12: 1.0e-336 << 1180 */ - 0x8e6d8c6ab0787f72LLU, /* 13: 1.0e-335 << 1176 */ - 0xb208ef855c969f4fLLU, /* 14: 1.0e-334 << 1173 */ - 0xde8b2b66b3bc4723LLU, /* 15: 1.0e-333 << 1170 */ - 0x8b16fb203055ac76LLU, /* 16: 1.0e-332 << 1166 */ - 0xaddcb9e83c6b1793LLU, /* 17: 1.0e-331 << 1163 */ - 0xd953e8624b85dd78LLU, /* 18: 1.0e-330 << 1160 */ - 0x87d4713d6f33aa6bLLU, /* 19: 1.0e-329 << 1156 */ - 0xa9c98d8ccb009506LLU, /* 20: 1.0e-328 << 1153 */ - 0xd43bf0effdc0ba48LLU, /* 21: 1.0e-327 << 1150 */ - 0x84a57695fe98746dLLU, /* 22: 1.0e-326 << 1146 */ - 0xa5ced43b7e3e9188LLU, /* 23: 1.0e-325 << 1143 */ - 0xcf42894a5dce35eaLLU, /* 24: 1.0e-324 << 1140 */ - 0x818995ce7aa0e1b2LLU, /* 25: 1.0e-323 << 1136 */ - 0xa1ebfb4219491a1fLLU, /* 26: 1.0e-322 << 1133 */ - 0xca66fa129f9b60a6LLU, /* 27: 1.0e-321 << 1130 */ - 0xfd00b897478238d0LLU, /* 28: 1.0e-320 << 1127 */ - 0x9e20735e8cb16382LLU, /* 29: 1.0e-319 << 1123 */ - 0xc5a890362fddbc62LLU, /* 30: 1.0e-318 << 1120 */ - 0xf712b443bbd52b7bLLU, /* 31: 1.0e-317 << 1117 */ - 0x9a6bb0aa55653b2dLLU, /* 32: 1.0e-316 << 1113 */ - 0xc1069cd4eabe89f8LLU, /* 33: 1.0e-315 << 1110 */ - 0xf148440a256e2c76LLU, /* 34: 1.0e-314 << 1107 */ - 0x96cd2a865764dbcaLLU, /* 35: 1.0e-313 << 1103 */ - 0xbc807527ed3e12bcLLU, /* 36: 1.0e-312 << 1100 */ - 0xeba09271e88d976bLLU, /* 37: 1.0e-311 << 1097 */ - 0x93445b8731587ea3LLU, /* 38: 1.0e-310 << 1093 */ - 0xb8157268fdae9e4cLLU, /* 39: 1.0e-309 << 1090 */ - 0xe61acf033d1a45dfLLU, /* 40: 1.0e-308 << 1087 */ - 0x8fd0c16206306babLLU, /* 41: 1.0e-307 << 1083 */ - 0xb3c4f1ba87bc8696LLU, /* 42: 1.0e-306 << 1080 */ - 0xe0b62e2929aba83cLLU, /* 43: 1.0e-305 << 1077 */ - 0x8c71dcd9ba0b4925LLU, /* 44: 1.0e-304 << 1073 */ - 0xaf8e5410288e1b6fLLU, /* 45: 1.0e-303 << 1070 */ - 0xdb71e91432b1a24aLLU, /* 46: 1.0e-302 << 1067 */ - 0x892731ac9faf056eLLU, /* 47: 1.0e-301 << 1063 */ - 0xab70fe17c79ac6caLLU, /* 48: 1.0e-300 << 1060 */ - 0xd64d3d9db981787dLLU, /* 49: 1.0e-299 << 1057 */ - 0x85f0468293f0eb4eLLU, /* 50: 1.0e-298 << 1053 */ - 0xa76c582338ed2621LLU, /* 51: 1.0e-297 << 1050 */ - 0xd1476e2c07286faaLLU, /* 52: 1.0e-296 << 1047 */ - 0x82cca4db847945caLLU, /* 53: 1.0e-295 << 1043 */ - 0xa37fce126597973cLLU, /* 54: 1.0e-294 << 1040 */ - 0xcc5fc196fefd7d0cLLU, /* 55: 1.0e-293 << 1037 */ - 0xff77b1fcbebcdc4fLLU, /* 56: 1.0e-292 << 1034 */ - 0x9faacf3df73609b1LLU, /* 57: 1.0e-291 << 1030 */ - 0xc795830d75038c1dLLU, /* 58: 1.0e-290 << 1027 */ - 0xf97ae3d0d2446f25LLU, /* 59: 1.0e-289 << 1024 */ - 0x9becce62836ac577LLU, /* 60: 1.0e-288 << 1020 */ - 0xc2e801fb244576d5LLU, /* 61: 1.0e-287 << 1017 */ - 0xf3a20279ed56d48aLLU, /* 62: 1.0e-286 << 1014 */ - 0x9845418c345644d6LLU, /* 63: 1.0e-285 << 1010 */ - 0xbe5691ef416bd60cLLU, /* 64: 1.0e-284 << 1007 */ - 0xedec366b11c6cb8fLLU, /* 65: 1.0e-283 << 1004 */ - 0x94b3a202eb1c3f39LLU, /* 66: 1.0e-282 << 1000 */ - 0xb9e08a83a5e34f07LLU, /* 67: 1.0e-281 << 997 */ - 0xe858ad248f5c22c9LLU, /* 68: 1.0e-280 << 994 */ - 0x91376c36d99995beLLU, /* 69: 1.0e-279 << 990 */ - 0xb58547448ffffb2dLLU, /* 70: 1.0e-278 << 987 */ - 0xe2e69915b3fff9f9LLU, /* 71: 1.0e-277 << 984 */ - 0x8dd01fad907ffc3bLLU, /* 72: 1.0e-276 << 980 */ - 0xb1442798f49ffb4aLLU, /* 73: 1.0e-275 << 977 */ - 0xdd95317f31c7fa1dLLU, /* 74: 1.0e-274 << 974 */ - 0x8a7d3eef7f1cfc52LLU, /* 75: 1.0e-273 << 970 */ - 0xad1c8eab5ee43b66LLU, /* 76: 1.0e-272 << 967 */ - 0xd863b256369d4a40LLU, /* 77: 1.0e-271 << 964 */ - 0x873e4f75e2224e68LLU, /* 78: 1.0e-270 << 960 */ - 0xa90de3535aaae202LLU, /* 79: 1.0e-269 << 957 */ - 0xd3515c2831559a83LLU, /* 80: 1.0e-268 << 954 */ - 0x8412d9991ed58091LLU, /* 81: 1.0e-267 << 950 */ - 0xa5178fff668ae0b6LLU, /* 82: 1.0e-266 << 947 */ - 0xce5d73ff402d98e3LLU, /* 83: 1.0e-265 << 944 */ - 0x80fa687f881c7f8eLLU, /* 84: 1.0e-264 << 940 */ - 0xa139029f6a239f72LLU, /* 85: 1.0e-263 << 937 */ - 0xc987434744ac874eLLU, /* 86: 1.0e-262 << 934 */ - 0xfbe9141915d7a922LLU, /* 87: 1.0e-261 << 931 */ - 0x9d71ac8fada6c9b5LLU, /* 88: 1.0e-260 << 927 */ - 0xc4ce17b399107c22LLU, /* 89: 1.0e-259 << 924 */ - 0xf6019da07f549b2bLLU, /* 90: 1.0e-258 << 921 */ - 0x99c102844f94e0fbLLU, /* 91: 1.0e-257 << 917 */ - 0xc0314325637a1939LLU, /* 92: 1.0e-256 << 914 */ - 0xf03d93eebc589f88LLU, /* 93: 1.0e-255 << 911 */ - 0x96267c7535b763b5LLU, /* 94: 1.0e-254 << 907 */ - 0xbbb01b9283253ca2LLU, /* 95: 1.0e-253 << 904 */ - 0xea9c227723ee8bcbLLU, /* 96: 1.0e-252 << 901 */ - 0x92a1958a7675175fLLU, /* 97: 1.0e-251 << 897 */ - 0xb749faed14125d36LLU, /* 98: 1.0e-250 << 894 */ - 0xe51c79a85916f484LLU, /* 99: 1.0e-249 << 891 */ - 0x8f31cc0937ae58d2LLU, /* 100: 1.0e-248 << 887 */ - 0xb2fe3f0b8599ef07LLU, /* 101: 1.0e-247 << 884 */ - 0xdfbdcece67006ac9LLU, /* 102: 1.0e-246 << 881 */ - 0x8bd6a141006042bdLLU, /* 103: 1.0e-245 << 877 */ - 0xaecc49914078536dLLU, /* 104: 1.0e-244 << 874 */ - 0xda7f5bf590966848LLU, /* 105: 1.0e-243 << 871 */ - 0x888f99797a5e012dLLU, /* 106: 1.0e-242 << 867 */ - 0xaab37fd7d8f58178LLU, /* 107: 1.0e-241 << 864 */ - 0xd5605fcdcf32e1d6LLU, /* 108: 1.0e-240 << 861 */ - 0x855c3be0a17fcd26LLU, /* 109: 1.0e-239 << 857 */ - 0xa6b34ad8c9dfc06fLLU, /* 110: 1.0e-238 << 854 */ - 0xd0601d8efc57b08bLLU, /* 111: 1.0e-237 << 851 */ - 0x823c12795db6ce57LLU, /* 112: 1.0e-236 << 847 */ - 0xa2cb1717b52481edLLU, /* 113: 1.0e-235 << 844 */ - 0xcb7ddcdda26da268LLU, /* 114: 1.0e-234 << 841 */ - 0xfe5d54150b090b02LLU, /* 115: 1.0e-233 << 838 */ - 0x9efa548d26e5a6e1LLU, /* 116: 1.0e-232 << 834 */ - 0xc6b8e9b0709f109aLLU, /* 117: 1.0e-231 << 831 */ - 0xf867241c8cc6d4c0LLU, /* 118: 1.0e-230 << 828 */ - 0x9b407691d7fc44f8LLU, /* 119: 1.0e-229 << 824 */ - 0xc21094364dfb5636LLU, /* 120: 1.0e-228 << 821 */ - 0xf294b943e17a2bc4LLU, /* 121: 1.0e-227 << 818 */ - 0x979cf3ca6cec5b5aLLU, /* 122: 1.0e-226 << 814 */ - 0xbd8430bd08277231LLU, /* 123: 1.0e-225 << 811 */ - 0xece53cec4a314ebdLLU, /* 124: 1.0e-224 << 808 */ - 0x940f4613ae5ed136LLU, /* 125: 1.0e-223 << 804 */ - 0xb913179899f68584LLU, /* 126: 1.0e-222 << 801 */ - 0xe757dd7ec07426e5LLU, /* 127: 1.0e-221 << 798 */ - 0x9096ea6f3848984fLLU, /* 128: 1.0e-220 << 794 */ - 0xb4bca50b065abe63LLU, /* 129: 1.0e-219 << 791 */ - 0xe1ebce4dc7f16dfbLLU, /* 130: 1.0e-218 << 788 */ - 0x8d3360f09cf6e4bdLLU, /* 131: 1.0e-217 << 784 */ - 0xb080392cc4349decLLU, /* 132: 1.0e-216 << 781 */ - 0xdca04777f541c567LLU, /* 133: 1.0e-215 << 778 */ - 0x89e42caaf9491b60LLU, /* 134: 1.0e-214 << 774 */ - 0xac5d37d5b79b6239LLU, /* 135: 1.0e-213 << 771 */ - 0xd77485cb25823ac7LLU, /* 136: 1.0e-212 << 768 */ - 0x86a8d39ef77164bcLLU, /* 137: 1.0e-211 << 764 */ - 0xa8530886b54dbdebLLU, /* 138: 1.0e-210 << 761 */ - 0xd267caa862a12d66LLU, /* 139: 1.0e-209 << 758 */ - 0x8380dea93da4bc60LLU, /* 140: 1.0e-208 << 754 */ - 0xa46116538d0deb78LLU, /* 141: 1.0e-207 << 751 */ - 0xcd795be870516656LLU, /* 142: 1.0e-206 << 748 */ - 0x806bd9714632dff6LLU, /* 143: 1.0e-205 << 744 */ - 0xa086cfcd97bf97f3LLU, /* 144: 1.0e-204 << 741 */ - 0xc8a883c0fdaf7df0LLU, /* 145: 1.0e-203 << 738 */ - 0xfad2a4b13d1b5d6cLLU, /* 146: 1.0e-202 << 735 */ - 0x9cc3a6eec6311a63LLU, /* 147: 1.0e-201 << 731 */ - 0xc3f490aa77bd60fcLLU, /* 148: 1.0e-200 << 728 */ - 0xf4f1b4d515acb93bLLU, /* 149: 1.0e-199 << 725 */ - 0x991711052d8bf3c5LLU, /* 150: 1.0e-198 << 721 */ - 0xbf5cd54678eef0b6LLU, /* 151: 1.0e-197 << 718 */ - 0xef340a98172aace4LLU, /* 152: 1.0e-196 << 715 */ - 0x9580869f0e7aac0eLLU, /* 153: 1.0e-195 << 711 */ - 0xbae0a846d2195712LLU, /* 154: 1.0e-194 << 708 */ - 0xe998d258869facd7LLU, /* 155: 1.0e-193 << 705 */ - 0x91ff83775423cc06LLU, /* 156: 1.0e-192 << 701 */ - 0xb67f6455292cbf08LLU, /* 157: 1.0e-191 << 698 */ - 0xe41f3d6a7377eecaLLU, /* 158: 1.0e-190 << 695 */ - 0x8e938662882af53eLLU, /* 159: 1.0e-189 << 691 */ - 0xb23867fb2a35b28dLLU, /* 160: 1.0e-188 << 688 */ - 0xdec681f9f4c31f31LLU, /* 161: 1.0e-187 << 685 */ - 0x8b3c113c38f9f37eLLU, /* 162: 1.0e-186 << 681 */ - 0xae0b158b4738705eLLU, /* 163: 1.0e-185 << 678 */ - 0xd98ddaee19068c76LLU, /* 164: 1.0e-184 << 675 */ - 0x87f8a8d4cfa417c9LLU, /* 165: 1.0e-183 << 671 */ - 0xa9f6d30a038d1dbcLLU, /* 166: 1.0e-182 << 668 */ - 0xd47487cc8470652bLLU, /* 167: 1.0e-181 << 665 */ - 0x84c8d4dfd2c63f3bLLU, /* 168: 1.0e-180 << 661 */ - 0xa5fb0a17c777cf09LLU, /* 169: 1.0e-179 << 658 */ - 0xcf79cc9db955c2ccLLU, /* 170: 1.0e-178 << 655 */ - 0x81ac1fe293d599bfLLU, /* 171: 1.0e-177 << 651 */ - 0xa21727db38cb002fLLU, /* 172: 1.0e-176 << 648 */ - 0xca9cf1d206fdc03bLLU, /* 173: 1.0e-175 << 645 */ - 0xfd442e4688bd304aLLU, /* 174: 1.0e-174 << 642 */ - 0x9e4a9cec15763e2eLLU, /* 175: 1.0e-173 << 638 */ - 0xc5dd44271ad3cdbaLLU, /* 176: 1.0e-172 << 635 */ - 0xf7549530e188c128LLU, /* 177: 1.0e-171 << 632 */ - 0x9a94dd3e8cf578b9LLU, /* 178: 1.0e-170 << 628 */ - 0xc13a148e3032d6e7LLU, /* 179: 1.0e-169 << 625 */ - 0xf18899b1bc3f8ca1LLU, /* 180: 1.0e-168 << 622 */ - 0x96f5600f15a7b7e5LLU, /* 181: 1.0e-167 << 618 */ - 0xbcb2b812db11a5deLLU, /* 182: 1.0e-166 << 615 */ - 0xebdf661791d60f56LLU, /* 183: 1.0e-165 << 612 */ - 0x936b9fcebb25c995LLU, /* 184: 1.0e-164 << 608 */ - 0xb84687c269ef3bfbLLU, /* 185: 1.0e-163 << 605 */ - 0xe65829b3046b0afaLLU, /* 186: 1.0e-162 << 602 */ - 0x8ff71a0fe2c2e6dcLLU, /* 187: 1.0e-161 << 598 */ - 0xb3f4e093db73a093LLU, /* 188: 1.0e-160 << 595 */ - 0xe0f218b8d25088b8LLU, /* 189: 1.0e-159 << 592 */ - 0x8c974f7383725573LLU, /* 190: 1.0e-158 << 588 */ - 0xafbd2350644eeacfLLU, /* 191: 1.0e-157 << 585 */ - 0xdbac6c247d62a583LLU, /* 192: 1.0e-156 << 582 */ - 0x894bc396ce5da772LLU, /* 193: 1.0e-155 << 578 */ - 0xab9eb47c81f5114fLLU, /* 194: 1.0e-154 << 575 */ - 0xd686619ba27255a2LLU, /* 195: 1.0e-153 << 572 */ - 0x8613fd0145877585LLU, /* 196: 1.0e-152 << 568 */ - 0xa798fc4196e952e7LLU, /* 197: 1.0e-151 << 565 */ - 0xd17f3b51fca3a7a0LLU, /* 198: 1.0e-150 << 562 */ - 0x82ef85133de648c4LLU, /* 199: 1.0e-149 << 558 */ - 0xa3ab66580d5fdaf5LLU, /* 200: 1.0e-148 << 555 */ - 0xcc963fee10b7d1b3LLU, /* 201: 1.0e-147 << 552 */ - 0xffbbcfe994e5c61fLLU, /* 202: 1.0e-146 << 549 */ - 0x9fd561f1fd0f9bd3LLU, /* 203: 1.0e-145 << 545 */ - 0xc7caba6e7c5382c8LLU, /* 204: 1.0e-144 << 542 */ - 0xf9bd690a1b68637bLLU, /* 205: 1.0e-143 << 539 */ - 0x9c1661a651213e2dLLU, /* 206: 1.0e-142 << 535 */ - 0xc31bfa0fe5698db8LLU, /* 207: 1.0e-141 << 532 */ - 0xf3e2f893dec3f126LLU, /* 208: 1.0e-140 << 529 */ - 0x986ddb5c6b3a76b7LLU, /* 209: 1.0e-139 << 525 */ - 0xbe89523386091465LLU, /* 210: 1.0e-138 << 522 */ - 0xee2ba6c0678b597fLLU, /* 211: 1.0e-137 << 519 */ - 0x94db483840b717efLLU, /* 212: 1.0e-136 << 515 */ - 0xba121a4650e4ddebLLU, /* 213: 1.0e-135 << 512 */ - 0xe896a0d7e51e1566LLU, /* 214: 1.0e-134 << 509 */ - 0x915e2486ef32cd60LLU, /* 215: 1.0e-133 << 505 */ - 0xb5b5ada8aaff80b8LLU, /* 216: 1.0e-132 << 502 */ - 0xe3231912d5bf60e6LLU, /* 217: 1.0e-131 << 499 */ - 0x8df5efabc5979c8fLLU, /* 218: 1.0e-130 << 495 */ - 0xb1736b96b6fd83b3LLU, /* 219: 1.0e-129 << 492 */ - 0xddd0467c64bce4a0LLU, /* 220: 1.0e-128 << 489 */ - 0x8aa22c0dbef60ee4LLU, /* 221: 1.0e-127 << 485 */ - 0xad4ab7112eb3929dLLU, /* 222: 1.0e-126 << 482 */ - 0xd89d64d57a607744LLU, /* 223: 1.0e-125 << 479 */ - 0x87625f056c7c4a8bLLU, /* 224: 1.0e-124 << 475 */ - 0xa93af6c6c79b5d2dLLU, /* 225: 1.0e-123 << 472 */ - 0xd389b47879823479LLU, /* 226: 1.0e-122 << 469 */ - 0x843610cb4bf160cbLLU, /* 227: 1.0e-121 << 465 */ - 0xa54394fe1eedb8feLLU, /* 228: 1.0e-120 << 462 */ - 0xce947a3da6a9273eLLU, /* 229: 1.0e-119 << 459 */ - 0x811ccc668829b887LLU, /* 230: 1.0e-118 << 455 */ - 0xa163ff802a3426a8LLU, /* 231: 1.0e-117 << 452 */ - 0xc9bcff6034c13052LLU, /* 232: 1.0e-116 << 449 */ - 0xfc2c3f3841f17c67LLU, /* 233: 1.0e-115 << 446 */ - 0x9d9ba7832936edc0LLU, /* 234: 1.0e-114 << 442 */ - 0xc5029163f384a931LLU, /* 235: 1.0e-113 << 439 */ - 0xf64335bcf065d37dLLU, /* 236: 1.0e-112 << 436 */ - 0x99ea0196163fa42eLLU, /* 237: 1.0e-111 << 432 */ - 0xc06481fb9bcf8d39LLU, /* 238: 1.0e-110 << 429 */ - 0xf07da27a82c37088LLU, /* 239: 1.0e-109 << 426 */ - 0x964e858c91ba2655LLU, /* 240: 1.0e-108 << 422 */ - 0xbbe226efb628afeaLLU, /* 241: 1.0e-107 << 419 */ - 0xeadab0aba3b2dbe5LLU, /* 242: 1.0e-106 << 416 */ - 0x92c8ae6b464fc96fLLU, /* 243: 1.0e-105 << 412 */ - 0xb77ada0617e3bbcbLLU, /* 244: 1.0e-104 << 409 */ - 0xe55990879ddcaabdLLU, /* 245: 1.0e-103 << 406 */ - 0x8f57fa54c2a9eab6LLU, /* 246: 1.0e-102 << 402 */ - 0xb32df8e9f3546564LLU, /* 247: 1.0e-101 << 399 */ - 0xdff9772470297ebdLLU, /* 248: 1.0e-100 << 396 */ - 0x8bfbea76c619ef36LLU, /* 249: 1.0e-99 << 392 */ - 0xaefae51477a06b03LLU, /* 250: 1.0e-98 << 389 */ - 0xdab99e59958885c4LLU, /* 251: 1.0e-97 << 386 */ - 0x88b402f7fd75539bLLU, /* 252: 1.0e-96 << 382 */ - 0xaae103b5fcd2a881LLU, /* 253: 1.0e-95 << 379 */ - 0xd59944a37c0752a2LLU, /* 254: 1.0e-94 << 376 */ - 0x857fcae62d8493a5LLU, /* 255: 1.0e-93 << 372 */ - 0xa6dfbd9fb8e5b88eLLU, /* 256: 1.0e-92 << 369 */ - 0xd097ad07a71f26b2LLU, /* 257: 1.0e-91 << 366 */ - 0x825ecc24c873782fLLU, /* 258: 1.0e-90 << 362 */ - 0xa2f67f2dfa90563bLLU, /* 259: 1.0e-89 << 359 */ - 0xcbb41ef979346bcaLLU, /* 260: 1.0e-88 << 356 */ - 0xfea126b7d78186bcLLU, /* 261: 1.0e-87 << 353 */ - 0x9f24b832e6b0f436LLU, /* 262: 1.0e-86 << 349 */ - 0xc6ede63fa05d3143LLU, /* 263: 1.0e-85 << 346 */ - 0xf8a95fcf88747d94LLU, /* 264: 1.0e-84 << 343 */ - 0x9b69dbe1b548ce7cLLU, /* 265: 1.0e-83 << 339 */ - 0xc24452da229b021bLLU, /* 266: 1.0e-82 << 336 */ - 0xf2d56790ab41c2a2LLU, /* 267: 1.0e-81 << 333 */ - 0x97c560ba6b0919a5LLU, /* 268: 1.0e-80 << 329 */ - 0xbdb6b8e905cb600fLLU, /* 269: 1.0e-79 << 326 */ - 0xed246723473e3813LLU, /* 270: 1.0e-78 << 323 */ - 0x9436c0760c86e30bLLU, /* 271: 1.0e-77 << 319 */ - 0xb94470938fa89bceLLU, /* 272: 1.0e-76 << 316 */ - 0xe7958cb87392c2c2LLU, /* 273: 1.0e-75 << 313 */ - 0x90bd77f3483bb9b9LLU, /* 274: 1.0e-74 << 309 */ - 0xb4ecd5f01a4aa828LLU, /* 275: 1.0e-73 << 306 */ - 0xe2280b6c20dd5232LLU, /* 276: 1.0e-72 << 303 */ - 0x8d590723948a535fLLU, /* 277: 1.0e-71 << 299 */ - 0xb0af48ec79ace837LLU, /* 278: 1.0e-70 << 296 */ - 0xdcdb1b2798182244LLU, /* 279: 1.0e-69 << 293 */ - 0x8a08f0f8bf0f156bLLU, /* 280: 1.0e-68 << 289 */ - 0xac8b2d36eed2dac5LLU, /* 281: 1.0e-67 << 286 */ - 0xd7adf884aa879177LLU, /* 282: 1.0e-66 << 283 */ - 0x86ccbb52ea94baeaLLU, /* 283: 1.0e-65 << 279 */ - 0xa87fea27a539e9a5LLU, /* 284: 1.0e-64 << 276 */ - 0xd29fe4b18e88640eLLU, /* 285: 1.0e-63 << 273 */ - 0x83a3eeeef9153e89LLU, /* 286: 1.0e-62 << 269 */ - 0xa48ceaaab75a8e2bLLU, /* 287: 1.0e-61 << 266 */ - 0xcdb02555653131b6LLU, /* 288: 1.0e-60 << 263 */ - 0x808e17555f3ebf11LLU, /* 289: 1.0e-59 << 259 */ - 0xa0b19d2ab70e6ed6LLU, /* 290: 1.0e-58 << 256 */ - 0xc8de047564d20a8bLLU, /* 291: 1.0e-57 << 253 */ - 0xfb158592be068d2eLLU, /* 292: 1.0e-56 << 250 */ - 0x9ced737bb6c4183dLLU, /* 293: 1.0e-55 << 246 */ - 0xc428d05aa4751e4cLLU, /* 294: 1.0e-54 << 243 */ - 0xf53304714d9265dfLLU, /* 295: 1.0e-53 << 240 */ - 0x993fe2c6d07b7fabLLU, /* 296: 1.0e-52 << 236 */ - 0xbf8fdb78849a5f96LLU, /* 297: 1.0e-51 << 233 */ - 0xef73d256a5c0f77cLLU, /* 298: 1.0e-50 << 230 */ - 0x95a8637627989aadLLU, /* 299: 1.0e-49 << 226 */ - 0xbb127c53b17ec159LLU, /* 300: 1.0e-48 << 223 */ - 0xe9d71b689dde71afLLU, /* 301: 1.0e-47 << 220 */ - 0x9226712162ab070dLLU, /* 302: 1.0e-46 << 216 */ - 0xb6b00d69bb55c8d1LLU, /* 303: 1.0e-45 << 213 */ - 0xe45c10c42a2b3b05LLU, /* 304: 1.0e-44 << 210 */ - 0x8eb98a7a9a5b04e3LLU, /* 305: 1.0e-43 << 206 */ - 0xb267ed1940f1c61cLLU, /* 306: 1.0e-42 << 203 */ - 0xdf01e85f912e37a3LLU, /* 307: 1.0e-41 << 200 */ - 0x8b61313bbabce2c6LLU, /* 308: 1.0e-40 << 196 */ - 0xae397d8aa96c1b77LLU, /* 309: 1.0e-39 << 193 */ - 0xd9c7dced53c72255LLU, /* 310: 1.0e-38 << 190 */ - 0x881cea14545c7575LLU, /* 311: 1.0e-37 << 186 */ - 0xaa242499697392d2LLU, /* 312: 1.0e-36 << 183 */ - 0xd4ad2dbfc3d07787LLU, /* 313: 1.0e-35 << 180 */ - 0x84ec3c97da624ab4LLU, /* 314: 1.0e-34 << 176 */ - 0xa6274bbdd0fadd61LLU, /* 315: 1.0e-33 << 173 */ - 0xcfb11ead453994baLLU, /* 316: 1.0e-32 << 170 */ - 0x81ceb32c4b43fcf4LLU, /* 317: 1.0e-31 << 166 */ - 0xa2425ff75e14fc31LLU, /* 318: 1.0e-30 << 163 */ - 0xcad2f7f5359a3b3eLLU, /* 319: 1.0e-29 << 160 */ - 0xfd87b5f28300ca0dLLU, /* 320: 1.0e-28 << 157 */ - 0x9e74d1b791e07e48LLU, /* 321: 1.0e-27 << 153 */ - 0xc612062576589ddaLLU, /* 322: 1.0e-26 << 150 */ - 0xf79687aed3eec551LLU, /* 323: 1.0e-25 << 147 */ - 0x9abe14cd44753b52LLU, /* 324: 1.0e-24 << 143 */ - 0xc16d9a0095928a27LLU, /* 325: 1.0e-23 << 140 */ - 0xf1c90080baf72cb1LLU, /* 326: 1.0e-22 << 137 */ - 0x971da05074da7beeLLU, /* 327: 1.0e-21 << 133 */ - 0xbce5086492111aeaLLU, /* 328: 1.0e-20 << 130 */ - 0xec1e4a7db69561a5LLU, /* 329: 1.0e-19 << 127 */ - 0x9392ee8e921d5d07LLU, /* 330: 1.0e-18 << 123 */ - 0xb877aa3236a4b449LLU, /* 331: 1.0e-17 << 120 */ - 0xe69594bec44de15bLLU, /* 332: 1.0e-16 << 117 */ - 0x901d7cf73ab0acd9LLU, /* 333: 1.0e-15 << 113 */ - 0xb424dc35095cd80fLLU, /* 334: 1.0e-14 << 110 */ - 0xe12e13424bb40e13LLU, /* 335: 1.0e-13 << 107 */ - 0x8cbccc096f5088cbLLU, /* 336: 1.0e-12 << 103 */ - 0xafebff0bcb24aafeLLU, /* 337: 1.0e-11 << 100 */ - 0xdbe6fecebdedd5beLLU, /* 338: 1.0e-10 << 97 */ - 0x89705f4136b4a597LLU, /* 339: 1.0e-9 << 93 */ - 0xabcc77118461cefcLLU, /* 340: 1.0e-8 << 90 */ - 0xd6bf94d5e57a42bcLLU, /* 341: 1.0e-7 << 87 */ - 0x8637bd05af6c69b5LLU, /* 342: 1.0e-6 << 83 */ - 0xa7c5ac471b478423LLU, /* 343: 1.0e-5 << 80 */ - 0xd1b71758e219652bLLU, /* 344: 1.0e-4 << 77 */ - 0x83126e978d4fdf3bLLU, /* 345: 1.0e-3 << 73 */ - 0xa3d70a3d70a3d70aLLU, /* 346: 1.0e-2 << 70 */ - 0xccccccccccccccccLLU, /* 347: 1.0e-1 << 67 */ - 0x8000000000000000LLU, /* 348: 1.0e+0 << 63 */ - 0xa000000000000000LLU, /* 349: 1.0e+1 << 60 */ - 0xc800000000000000LLU, /* 350: 1.0e+2 << 57 */ - 0xfa00000000000000LLU, /* 351: 1.0e+3 << 54 */ - 0x9c40000000000000LLU, /* 352: 1.0e+4 << 50 */ - 0xc350000000000000LLU, /* 353: 1.0e+5 << 47 */ - 0xf424000000000000LLU, /* 354: 1.0e+6 << 44 */ - 0x9896800000000000LLU, /* 355: 1.0e+7 << 40 */ - 0xbebc200000000000LLU, /* 356: 1.0e+8 << 37 */ - 0xee6b280000000000LLU, /* 357: 1.0e+9 << 34 */ - 0x9502f90000000000LLU, /* 358: 1.0e+10 << 30 */ - 0xba43b74000000000LLU, /* 359: 1.0e+11 << 27 */ - 0xe8d4a51000000000LLU, /* 360: 1.0e+12 << 24 */ - 0x9184e72a00000000LLU, /* 361: 1.0e+13 << 20 */ - 0xb5e620f480000000LLU, /* 362: 1.0e+14 << 17 */ - 0xe35fa931a0000000LLU, /* 363: 1.0e+15 << 14 */ - 0x8e1bc9bf04000000LLU, /* 364: 1.0e+16 << 10 */ - 0xb1a2bc2ec5000000LLU, /* 365: 1.0e+17 << 7 */ - 0xde0b6b3a76400000LLU, /* 366: 1.0e+18 << 4 */ - 0x8ac7230489e80000LLU, /* 367: 1.0e+19 >> 0 */ - 0xad78ebc5ac620000LLU, /* 368: 1.0e+20 >> 3 */ - 0xd8d726b7177a8000LLU, /* 369: 1.0e+21 >> 6 */ - 0x878678326eac9000LLU, /* 370: 1.0e+22 >> 10 */ - 0xa968163f0a57b400LLU, /* 371: 1.0e+23 >> 13 */ - 0xd3c21bcecceda100LLU, /* 372: 1.0e+24 >> 16 */ - 0x84595161401484a0LLU, /* 373: 1.0e+25 >> 20 */ - 0xa56fa5b99019a5c8LLU, /* 374: 1.0e+26 >> 23 */ - 0xcecb8f27f4200f3aLLU, /* 375: 1.0e+27 >> 26 */ - 0x813f3978f8940984LLU, /* 376: 1.0e+28 >> 30 */ - 0xa18f07d736b90be5LLU, /* 377: 1.0e+29 >> 33 */ - 0xc9f2c9cd04674edeLLU, /* 378: 1.0e+30 >> 36 */ - 0xfc6f7c4045812296LLU, /* 379: 1.0e+31 >> 39 */ - 0x9dc5ada82b70b59dLLU, /* 380: 1.0e+32 >> 43 */ - 0xc5371912364ce305LLU, /* 381: 1.0e+33 >> 46 */ - 0xf684df56c3e01bc6LLU, /* 382: 1.0e+34 >> 49 */ - 0x9a130b963a6c115cLLU, /* 383: 1.0e+35 >> 53 */ - 0xc097ce7bc90715b3LLU, /* 384: 1.0e+36 >> 56 */ - 0xf0bdc21abb48db20LLU, /* 385: 1.0e+37 >> 59 */ - 0x96769950b50d88f4LLU, /* 386: 1.0e+38 >> 63 */ - 0xbc143fa4e250eb31LLU, /* 387: 1.0e+39 >> 66 */ - 0xeb194f8e1ae525fdLLU, /* 388: 1.0e+40 >> 69 */ - 0x92efd1b8d0cf37beLLU, /* 389: 1.0e+41 >> 73 */ - 0xb7abc627050305adLLU, /* 390: 1.0e+42 >> 76 */ - 0xe596b7b0c643c719LLU, /* 391: 1.0e+43 >> 79 */ - 0x8f7e32ce7bea5c6fLLU, /* 392: 1.0e+44 >> 83 */ - 0xb35dbf821ae4f38bLLU, /* 393: 1.0e+45 >> 86 */ - 0xe0352f62a19e306eLLU, /* 394: 1.0e+46 >> 89 */ - 0x8c213d9da502de45LLU, /* 395: 1.0e+47 >> 93 */ - 0xaf298d050e4395d6LLU, /* 396: 1.0e+48 >> 96 */ - 0xdaf3f04651d47b4cLLU, /* 397: 1.0e+49 >> 99 */ - 0x88d8762bf324cd0fLLU, /* 398: 1.0e+50 >> 103 */ - 0xab0e93b6efee0053LLU, /* 399: 1.0e+51 >> 106 */ - 0xd5d238a4abe98068LLU, /* 400: 1.0e+52 >> 109 */ - 0x85a36366eb71f041LLU, /* 401: 1.0e+53 >> 113 */ - 0xa70c3c40a64e6c51LLU, /* 402: 1.0e+54 >> 116 */ - 0xd0cf4b50cfe20765LLU, /* 403: 1.0e+55 >> 119 */ - 0x82818f1281ed449fLLU, /* 404: 1.0e+56 >> 123 */ - 0xa321f2d7226895c7LLU, /* 405: 1.0e+57 >> 126 */ - 0xcbea6f8ceb02bb39LLU, /* 406: 1.0e+58 >> 129 */ - 0xfee50b7025c36a08LLU, /* 407: 1.0e+59 >> 132 */ - 0x9f4f2726179a2245LLU, /* 408: 1.0e+60 >> 136 */ - 0xc722f0ef9d80aad6LLU, /* 409: 1.0e+61 >> 139 */ - 0xf8ebad2b84e0d58bLLU, /* 410: 1.0e+62 >> 142 */ - 0x9b934c3b330c8577LLU, /* 411: 1.0e+63 >> 146 */ - 0xc2781f49ffcfa6d5LLU, /* 412: 1.0e+64 >> 149 */ - 0xf316271c7fc3908aLLU, /* 413: 1.0e+65 >> 152 */ - 0x97edd871cfda3a56LLU, /* 414: 1.0e+66 >> 156 */ - 0xbde94e8e43d0c8ecLLU, /* 415: 1.0e+67 >> 159 */ - 0xed63a231d4c4fb27LLU, /* 416: 1.0e+68 >> 162 */ - 0x945e455f24fb1cf8LLU, /* 417: 1.0e+69 >> 166 */ - 0xb975d6b6ee39e436LLU, /* 418: 1.0e+70 >> 169 */ - 0xe7d34c64a9c85d44LLU, /* 419: 1.0e+71 >> 172 */ - 0x90e40fbeea1d3a4aLLU, /* 420: 1.0e+72 >> 176 */ - 0xb51d13aea4a488ddLLU, /* 421: 1.0e+73 >> 179 */ - 0xe264589a4dcdab14LLU, /* 422: 1.0e+74 >> 182 */ - 0x8d7eb76070a08aecLLU, /* 423: 1.0e+75 >> 186 */ - 0xb0de65388cc8ada8LLU, /* 424: 1.0e+76 >> 189 */ - 0xdd15fe86affad912LLU, /* 425: 1.0e+77 >> 192 */ - 0x8a2dbf142dfcc7abLLU, /* 426: 1.0e+78 >> 196 */ - 0xacb92ed9397bf996LLU, /* 427: 1.0e+79 >> 199 */ - 0xd7e77a8f87daf7fbLLU, /* 428: 1.0e+80 >> 202 */ - 0x86f0ac99b4e8dafdLLU, /* 429: 1.0e+81 >> 206 */ - 0xa8acd7c0222311bcLLU, /* 430: 1.0e+82 >> 209 */ - 0xd2d80db02aabd62bLLU, /* 431: 1.0e+83 >> 212 */ - 0x83c7088e1aab65dbLLU, /* 432: 1.0e+84 >> 216 */ - 0xa4b8cab1a1563f52LLU, /* 433: 1.0e+85 >> 219 */ - 0xcde6fd5e09abcf26LLU, /* 434: 1.0e+86 >> 222 */ - 0x80b05e5ac60b6178LLU, /* 435: 1.0e+87 >> 226 */ - 0xa0dc75f1778e39d6LLU, /* 436: 1.0e+88 >> 229 */ - 0xc913936dd571c84cLLU, /* 437: 1.0e+89 >> 232 */ - 0xfb5878494ace3a5fLLU, /* 438: 1.0e+90 >> 235 */ - 0x9d174b2dcec0e47bLLU, /* 439: 1.0e+91 >> 239 */ - 0xc45d1df942711d9aLLU, /* 440: 1.0e+92 >> 242 */ - 0xf5746577930d6500LLU, /* 441: 1.0e+93 >> 245 */ - 0x9968bf6abbe85f20LLU, /* 442: 1.0e+94 >> 249 */ - 0xbfc2ef456ae276e8LLU, /* 443: 1.0e+95 >> 252 */ - 0xefb3ab16c59b14a2LLU, /* 444: 1.0e+96 >> 255 */ - 0x95d04aee3b80ece5LLU, /* 445: 1.0e+97 >> 259 */ - 0xbb445da9ca61281fLLU, /* 446: 1.0e+98 >> 262 */ - 0xea1575143cf97226LLU, /* 447: 1.0e+99 >> 265 */ - 0x924d692ca61be758LLU, /* 448: 1.0e+100 >> 269 */ - 0xb6e0c377cfa2e12eLLU, /* 449: 1.0e+101 >> 272 */ - 0xe498f455c38b997aLLU, /* 450: 1.0e+102 >> 275 */ - 0x8edf98b59a373fecLLU, /* 451: 1.0e+103 >> 279 */ - 0xb2977ee300c50fe7LLU, /* 452: 1.0e+104 >> 282 */ - 0xdf3d5e9bc0f653e1LLU, /* 453: 1.0e+105 >> 285 */ - 0x8b865b215899f46cLLU, /* 454: 1.0e+106 >> 289 */ - 0xae67f1e9aec07187LLU, /* 455: 1.0e+107 >> 292 */ - 0xda01ee641a708de9LLU, /* 456: 1.0e+108 >> 295 */ - 0x884134fe908658b2LLU, /* 457: 1.0e+109 >> 299 */ - 0xaa51823e34a7eedeLLU, /* 458: 1.0e+110 >> 302 */ - 0xd4e5e2cdc1d1ea96LLU, /* 459: 1.0e+111 >> 305 */ - 0x850fadc09923329eLLU, /* 460: 1.0e+112 >> 309 */ - 0xa6539930bf6bff45LLU, /* 461: 1.0e+113 >> 312 */ - 0xcfe87f7cef46ff16LLU, /* 462: 1.0e+114 >> 315 */ - 0x81f14fae158c5f6eLLU, /* 463: 1.0e+115 >> 319 */ - 0xa26da3999aef7749LLU, /* 464: 1.0e+116 >> 322 */ - 0xcb090c8001ab551cLLU, /* 465: 1.0e+117 >> 325 */ - 0xfdcb4fa002162a63LLU, /* 466: 1.0e+118 >> 328 */ - 0x9e9f11c4014dda7eLLU, /* 467: 1.0e+119 >> 332 */ - 0xc646d63501a1511dLLU, /* 468: 1.0e+120 >> 335 */ - 0xf7d88bc24209a565LLU, /* 469: 1.0e+121 >> 338 */ - 0x9ae757596946075fLLU, /* 470: 1.0e+122 >> 342 */ - 0xc1a12d2fc3978937LLU, /* 471: 1.0e+123 >> 345 */ - 0xf209787bb47d6b84LLU, /* 472: 1.0e+124 >> 348 */ - 0x9745eb4d50ce6332LLU, /* 473: 1.0e+125 >> 352 */ - 0xbd176620a501fbffLLU, /* 474: 1.0e+126 >> 355 */ - 0xec5d3fa8ce427affLLU, /* 475: 1.0e+127 >> 358 */ - 0x93ba47c980e98cdfLLU, /* 476: 1.0e+128 >> 362 */ - 0xb8a8d9bbe123f017LLU, /* 477: 1.0e+129 >> 365 */ - 0xe6d3102ad96cec1dLLU, /* 478: 1.0e+130 >> 368 */ - 0x9043ea1ac7e41392LLU, /* 479: 1.0e+131 >> 372 */ - 0xb454e4a179dd1877LLU, /* 480: 1.0e+132 >> 375 */ - 0xe16a1dc9d8545e94LLU, /* 481: 1.0e+133 >> 378 */ - 0x8ce2529e2734bb1dLLU, /* 482: 1.0e+134 >> 382 */ - 0xb01ae745b101e9e4LLU, /* 483: 1.0e+135 >> 385 */ - 0xdc21a1171d42645dLLU, /* 484: 1.0e+136 >> 388 */ - 0x899504ae72497ebaLLU, /* 485: 1.0e+137 >> 392 */ - 0xabfa45da0edbde69LLU, /* 486: 1.0e+138 >> 395 */ - 0xd6f8d7509292d603LLU, /* 487: 1.0e+139 >> 398 */ - 0x865b86925b9bc5c2LLU, /* 488: 1.0e+140 >> 402 */ - 0xa7f26836f282b732LLU, /* 489: 1.0e+141 >> 405 */ - 0xd1ef0244af2364ffLLU, /* 490: 1.0e+142 >> 408 */ - 0x8335616aed761f1fLLU, /* 491: 1.0e+143 >> 412 */ - 0xa402b9c5a8d3a6e7LLU, /* 492: 1.0e+144 >> 415 */ - 0xcd036837130890a1LLU, /* 493: 1.0e+145 >> 418 */ - 0x802221226be55a64LLU, /* 494: 1.0e+146 >> 422 */ - 0xa02aa96b06deb0fdLLU, /* 495: 1.0e+147 >> 425 */ - 0xc83553c5c8965d3dLLU, /* 496: 1.0e+148 >> 428 */ - 0xfa42a8b73abbf48cLLU, /* 497: 1.0e+149 >> 431 */ - 0x9c69a97284b578d7LLU, /* 498: 1.0e+150 >> 435 */ - 0xc38413cf25e2d70dLLU, /* 499: 1.0e+151 >> 438 */ - 0xf46518c2ef5b8cd1LLU, /* 500: 1.0e+152 >> 441 */ - 0x98bf2f79d5993802LLU, /* 501: 1.0e+153 >> 445 */ - 0xbeeefb584aff8603LLU, /* 502: 1.0e+154 >> 448 */ - 0xeeaaba2e5dbf6784LLU, /* 503: 1.0e+155 >> 451 */ - 0x952ab45cfa97a0b2LLU, /* 504: 1.0e+156 >> 455 */ - 0xba756174393d88dfLLU, /* 505: 1.0e+157 >> 458 */ - 0xe912b9d1478ceb17LLU, /* 506: 1.0e+158 >> 461 */ - 0x91abb422ccb812eeLLU, /* 507: 1.0e+159 >> 465 */ - 0xb616a12b7fe617aaLLU, /* 508: 1.0e+160 >> 468 */ - 0xe39c49765fdf9d94LLU, /* 509: 1.0e+161 >> 471 */ - 0x8e41ade9fbebc27dLLU, /* 510: 1.0e+162 >> 475 */ - 0xb1d219647ae6b31cLLU, /* 511: 1.0e+163 >> 478 */ - 0xde469fbd99a05fe3LLU, /* 512: 1.0e+164 >> 481 */ - 0x8aec23d680043beeLLU, /* 513: 1.0e+165 >> 485 */ - 0xada72ccc20054ae9LLU, /* 514: 1.0e+166 >> 488 */ - 0xd910f7ff28069da4LLU, /* 515: 1.0e+167 >> 491 */ - 0x87aa9aff79042286LLU, /* 516: 1.0e+168 >> 495 */ - 0xa99541bf57452b28LLU, /* 517: 1.0e+169 >> 498 */ - 0xd3fa922f2d1675f2LLU, /* 518: 1.0e+170 >> 501 */ - 0x847c9b5d7c2e09b7LLU, /* 519: 1.0e+171 >> 505 */ - 0xa59bc234db398c25LLU, /* 520: 1.0e+172 >> 508 */ - 0xcf02b2c21207ef2eLLU, /* 521: 1.0e+173 >> 511 */ - 0x8161afb94b44f57dLLU, /* 522: 1.0e+174 >> 515 */ - 0xa1ba1ba79e1632dcLLU, /* 523: 1.0e+175 >> 518 */ - 0xca28a291859bbf93LLU, /* 524: 1.0e+176 >> 521 */ - 0xfcb2cb35e702af78LLU, /* 525: 1.0e+177 >> 524 */ - 0x9defbf01b061adabLLU, /* 526: 1.0e+178 >> 528 */ - 0xc56baec21c7a1916LLU, /* 527: 1.0e+179 >> 531 */ - 0xf6c69a72a3989f5bLLU, /* 528: 1.0e+180 >> 534 */ - 0x9a3c2087a63f6399LLU, /* 529: 1.0e+181 >> 538 */ - 0xc0cb28a98fcf3c7fLLU, /* 530: 1.0e+182 >> 541 */ - 0xf0fdf2d3f3c30b9fLLU, /* 531: 1.0e+183 >> 544 */ - 0x969eb7c47859e743LLU, /* 532: 1.0e+184 >> 548 */ - 0xbc4665b596706114LLU, /* 533: 1.0e+185 >> 551 */ - 0xeb57ff22fc0c7959LLU, /* 534: 1.0e+186 >> 554 */ - 0x9316ff75dd87cbd8LLU, /* 535: 1.0e+187 >> 558 */ - 0xb7dcbf5354e9beceLLU, /* 536: 1.0e+188 >> 561 */ - 0xe5d3ef282a242e81LLU, /* 537: 1.0e+189 >> 564 */ - 0x8fa475791a569d10LLU, /* 538: 1.0e+190 >> 568 */ - 0xb38d92d760ec4455LLU, /* 539: 1.0e+191 >> 571 */ - 0xe070f78d3927556aLLU, /* 540: 1.0e+192 >> 574 */ - 0x8c469ab843b89562LLU, /* 541: 1.0e+193 >> 578 */ - 0xaf58416654a6babbLLU, /* 542: 1.0e+194 >> 581 */ - 0xdb2e51bfe9d0696aLLU, /* 543: 1.0e+195 >> 584 */ - 0x88fcf317f22241e2LLU, /* 544: 1.0e+196 >> 588 */ - 0xab3c2fddeeaad25aLLU, /* 545: 1.0e+197 >> 591 */ - 0xd60b3bd56a5586f1LLU, /* 546: 1.0e+198 >> 594 */ - 0x85c7056562757456LLU, /* 547: 1.0e+199 >> 598 */ - 0xa738c6bebb12d16cLLU, /* 548: 1.0e+200 >> 601 */ - 0xd106f86e69d785c7LLU, /* 549: 1.0e+201 >> 604 */ - 0x82a45b450226b39cLLU, /* 550: 1.0e+202 >> 608 */ - 0xa34d721642b06084LLU, /* 551: 1.0e+203 >> 611 */ - 0xcc20ce9bd35c78a5LLU, /* 552: 1.0e+204 >> 614 */ - 0xff290242c83396ceLLU, /* 553: 1.0e+205 >> 617 */ - 0x9f79a169bd203e41LLU, /* 554: 1.0e+206 >> 621 */ - 0xc75809c42c684dd1LLU, /* 555: 1.0e+207 >> 624 */ - 0xf92e0c3537826145LLU, /* 556: 1.0e+208 >> 627 */ - 0x9bbcc7a142b17ccbLLU, /* 557: 1.0e+209 >> 631 */ - 0xc2abf989935ddbfeLLU, /* 558: 1.0e+210 >> 634 */ - 0xf356f7ebf83552feLLU, /* 559: 1.0e+211 >> 637 */ - 0x98165af37b2153deLLU, /* 560: 1.0e+212 >> 641 */ - 0xbe1bf1b059e9a8d6LLU, /* 561: 1.0e+213 >> 644 */ - 0xeda2ee1c7064130cLLU, /* 562: 1.0e+214 >> 647 */ - 0x9485d4d1c63e8be7LLU, /* 563: 1.0e+215 >> 651 */ - 0xb9a74a0637ce2ee1LLU, /* 564: 1.0e+216 >> 654 */ - 0xe8111c87c5c1ba99LLU, /* 565: 1.0e+217 >> 657 */ - 0x910ab1d4db9914a0LLU, /* 566: 1.0e+218 >> 661 */ - 0xb54d5e4a127f59c8LLU, /* 567: 1.0e+219 >> 664 */ - 0xe2a0b5dc971f303aLLU, /* 568: 1.0e+220 >> 667 */ - 0x8da471a9de737e24LLU, /* 569: 1.0e+221 >> 671 */ - 0xb10d8e1456105dadLLU, /* 570: 1.0e+222 >> 674 */ - 0xdd50f1996b947518LLU, /* 571: 1.0e+223 >> 677 */ - 0x8a5296ffe33cc92fLLU, /* 572: 1.0e+224 >> 681 */ - 0xace73cbfdc0bfb7bLLU, /* 573: 1.0e+225 >> 684 */ - 0xd8210befd30efa5aLLU, /* 574: 1.0e+226 >> 687 */ - 0x8714a775e3e95c78LLU, /* 575: 1.0e+227 >> 691 */ - 0xa8d9d1535ce3b396LLU, /* 576: 1.0e+228 >> 694 */ - 0xd31045a8341ca07cLLU, /* 577: 1.0e+229 >> 697 */ - 0x83ea2b892091e44dLLU, /* 578: 1.0e+230 >> 701 */ - 0xa4e4b66b68b65d60LLU, /* 579: 1.0e+231 >> 704 */ - 0xce1de40642e3f4b9LLU, /* 580: 1.0e+232 >> 707 */ - 0x80d2ae83e9ce78f3LLU, /* 581: 1.0e+233 >> 711 */ - 0xa1075a24e4421730LLU, /* 582: 1.0e+234 >> 714 */ - 0xc94930ae1d529cfcLLU, /* 583: 1.0e+235 >> 717 */ - 0xfb9b7cd9a4a7443cLLU, /* 584: 1.0e+236 >> 720 */ - 0x9d412e0806e88aa5LLU, /* 585: 1.0e+237 >> 724 */ - 0xc491798a08a2ad4eLLU, /* 586: 1.0e+238 >> 727 */ - 0xf5b5d7ec8acb58a2LLU, /* 587: 1.0e+239 >> 730 */ - 0x9991a6f3d6bf1765LLU, /* 588: 1.0e+240 >> 734 */ - 0xbff610b0cc6edd3fLLU, /* 589: 1.0e+241 >> 737 */ - 0xeff394dcff8a948eLLU, /* 590: 1.0e+242 >> 740 */ - 0x95f83d0a1fb69cd9LLU, /* 591: 1.0e+243 >> 744 */ - 0xbb764c4ca7a4440fLLU, /* 592: 1.0e+244 >> 747 */ - 0xea53df5fd18d5513LLU, /* 593: 1.0e+245 >> 750 */ - 0x92746b9be2f8552cLLU, /* 594: 1.0e+246 >> 754 */ - 0xb7118682dbb66a77LLU, /* 595: 1.0e+247 >> 757 */ - 0xe4d5e82392a40515LLU, /* 596: 1.0e+248 >> 760 */ - 0x8f05b1163ba6832dLLU, /* 597: 1.0e+249 >> 764 */ - 0xb2c71d5bca9023f8LLU, /* 598: 1.0e+250 >> 767 */ - 0xdf78e4b2bd342cf6LLU, /* 599: 1.0e+251 >> 770 */ - 0x8bab8eefb6409c1aLLU, /* 600: 1.0e+252 >> 774 */ - 0xae9672aba3d0c320LLU, /* 601: 1.0e+253 >> 777 */ - 0xda3c0f568cc4f3e8LLU, /* 602: 1.0e+254 >> 780 */ - 0x8865899617fb1871LLU, /* 603: 1.0e+255 >> 784 */ - 0xaa7eebfb9df9de8dLLU, /* 604: 1.0e+256 >> 787 */ - 0xd51ea6fa85785631LLU, /* 605: 1.0e+257 >> 790 */ - 0x8533285c936b35deLLU, /* 606: 1.0e+258 >> 794 */ - 0xa67ff273b8460356LLU, /* 607: 1.0e+259 >> 797 */ - 0xd01fef10a657842cLLU, /* 608: 1.0e+260 >> 800 */ - 0x8213f56a67f6b29bLLU, /* 609: 1.0e+261 >> 804 */ - 0xa298f2c501f45f42LLU, /* 610: 1.0e+262 >> 807 */ - 0xcb3f2f7642717713LLU, /* 611: 1.0e+263 >> 810 */ - 0xfe0efb53d30dd4d7LLU, /* 612: 1.0e+264 >> 813 */ - 0x9ec95d1463e8a506LLU, /* 613: 1.0e+265 >> 817 */ - 0xc67bb4597ce2ce48LLU, /* 614: 1.0e+266 >> 820 */ - 0xf81aa16fdc1b81daLLU, /* 615: 1.0e+267 >> 823 */ - 0x9b10a4e5e9913128LLU, /* 616: 1.0e+268 >> 827 */ - 0xc1d4ce1f63f57d72LLU, /* 617: 1.0e+269 >> 830 */ - 0xf24a01a73cf2dccfLLU, /* 618: 1.0e+270 >> 833 */ - 0x976e41088617ca01LLU, /* 619: 1.0e+271 >> 837 */ - 0xbd49d14aa79dbc82LLU, /* 620: 1.0e+272 >> 840 */ - 0xec9c459d51852ba2LLU, /* 621: 1.0e+273 >> 843 */ - 0x93e1ab8252f33b45LLU, /* 622: 1.0e+274 >> 847 */ - 0xb8da1662e7b00a17LLU, /* 623: 1.0e+275 >> 850 */ - 0xe7109bfba19c0c9dLLU, /* 624: 1.0e+276 >> 853 */ - 0x906a617d450187e2LLU, /* 625: 1.0e+277 >> 857 */ - 0xb484f9dc9641e9daLLU, /* 626: 1.0e+278 >> 860 */ - 0xe1a63853bbd26451LLU, /* 627: 1.0e+279 >> 863 */ - 0x8d07e33455637eb2LLU, /* 628: 1.0e+280 >> 867 */ - 0xb049dc016abc5e5fLLU, /* 629: 1.0e+281 >> 870 */ - 0xdc5c5301c56b75f7LLU, /* 630: 1.0e+282 >> 873 */ - 0x89b9b3e11b6329baLLU, /* 631: 1.0e+283 >> 877 */ - 0xac2820d9623bf429LLU, /* 632: 1.0e+284 >> 880 */ - 0xd732290fbacaf133LLU, /* 633: 1.0e+285 >> 883 */ - 0x867f59a9d4bed6c0LLU, /* 634: 1.0e+286 >> 887 */ - 0xa81f301449ee8c70LLU, /* 635: 1.0e+287 >> 890 */ - 0xd226fc195c6a2f8cLLU, /* 636: 1.0e+288 >> 893 */ - 0x83585d8fd9c25db7LLU, /* 637: 1.0e+289 >> 897 */ - 0xa42e74f3d032f525LLU, /* 638: 1.0e+290 >> 900 */ - 0xcd3a1230c43fb26fLLU, /* 639: 1.0e+291 >> 903 */ - 0x80444b5e7aa7cf85LLU, /* 640: 1.0e+292 >> 907 */ - 0xa0555e361951c366LLU, /* 641: 1.0e+293 >> 910 */ - 0xc86ab5c39fa63440LLU, /* 642: 1.0e+294 >> 913 */ - 0xfa856334878fc150LLU, /* 643: 1.0e+295 >> 916 */ - 0x9c935e00d4b9d8d2LLU, /* 644: 1.0e+296 >> 920 */ - 0xc3b8358109e84f07LLU, /* 645: 1.0e+297 >> 923 */ - 0xf4a642e14c6262c8LLU, /* 646: 1.0e+298 >> 926 */ - 0x98e7e9cccfbd7dbdLLU, /* 647: 1.0e+299 >> 930 */ - 0xbf21e44003acdd2cLLU, /* 648: 1.0e+300 >> 933 */ - 0xeeea5d5004981478LLU, /* 649: 1.0e+301 >> 936 */ - 0x95527a5202df0ccbLLU, /* 650: 1.0e+302 >> 940 */ - 0xbaa718e68396cffdLLU, /* 651: 1.0e+303 >> 943 */ - 0xe950df20247c83fdLLU, /* 652: 1.0e+304 >> 946 */ - 0x91d28b7416cdd27eLLU, /* 653: 1.0e+305 >> 950 */ - 0xb6472e511c81471dLLU, /* 654: 1.0e+306 >> 953 */ - 0xe3d8f9e563a198e5LLU, /* 655: 1.0e+307 >> 956 */ - 0x8e679c2f5e44ff8fLLU, /* 656: 1.0e+308 >> 960 */ - 0xb201833b35d63f73LLU, /* 657: 1.0e+309 >> 963 */ - 0xde81e40a034bcf4fLLU, /* 658: 1.0e+310 >> 966 */ - 0x8b112e86420f6191LLU, /* 659: 1.0e+311 >> 970 */ - 0xadd57a27d29339f6LLU, /* 660: 1.0e+312 >> 973 */ - 0xd94ad8b1c7380874LLU, /* 661: 1.0e+313 >> 976 */ - 0x87cec76f1c830548LLU, /* 662: 1.0e+314 >> 980 */ - 0xa9c2794ae3a3c69aLLU, /* 663: 1.0e+315 >> 983 */ - 0xd433179d9c8cb841LLU, /* 664: 1.0e+316 >> 986 */ - 0x849feec281d7f328LLU, /* 665: 1.0e+317 >> 990 */ - 0xa5c7ea73224deff3LLU, /* 666: 1.0e+318 >> 993 */ - 0xcf39e50feae16befLLU, /* 667: 1.0e+319 >> 996 */ - 0x81842f29f2cce375LLU, /* 668: 1.0e+320 >> 1000 */ - 0xa1e53af46f801c53LLU, /* 669: 1.0e+321 >> 1003 */ - 0xca5e89b18b602368LLU, /* 670: 1.0e+322 >> 1006 */ - 0xfcf62c1dee382c42LLU, /* 671: 1.0e+323 >> 1009 */ - 0x9e19db92b4e31ba9LLU, /* 672: 1.0e+324 >> 1013 */ - 0xc5a05277621be293LLU, /* 673: 1.0e+325 >> 1016 */ - 0xf70867153aa2db38LLU, /* 674: 1.0e+326 >> 1019 */ - 0x9a65406d44a5c903LLU, /* 675: 1.0e+327 >> 1023 */ - 0xc0fe908895cf3b44LLU, /* 676: 1.0e+328 >> 1026 */ - 0xf13e34aabb430a15LLU, /* 677: 1.0e+329 >> 1029 */ - 0x96c6e0eab509e64dLLU, /* 678: 1.0e+330 >> 1033 */ - 0xbc789925624c5fe0LLU, /* 679: 1.0e+331 >> 1036 */ - 0xeb96bf6ebadf77d8LLU, /* 680: 1.0e+332 >> 1039 */ - 0x933e37a534cbaae7LLU, /* 681: 1.0e+333 >> 1043 */ - 0xb80dc58e81fe95a1LLU, /* 682: 1.0e+334 >> 1046 */ - 0xe61136f2227e3b09LLU, /* 683: 1.0e+335 >> 1049 */ - 0x8fcac257558ee4e6LLU, /* 684: 1.0e+336 >> 1053 */ - 0xb3bd72ed2af29e1fLLU, /* 685: 1.0e+337 >> 1056 */ - 0xe0accfa875af45a7LLU, /* 686: 1.0e+338 >> 1059 */ - 0x8c6c01c9498d8b88LLU, /* 687: 1.0e+339 >> 1063 */ - 0xaf87023b9bf0ee6aLLU, /* 688: 1.0e+340 >> 1066 */ - 0xdb68c2ca82ed2a05LLU, /* 689: 1.0e+341 >> 1069 */ - 0x892179be91d43a43LLU, /* 690: 1.0e+342 >> 1073 */ - 0xab69d82e364948d4LLU, /* 691: 1.0e+343 >> 1076 */ - 0xd6444e39c3db9b09LLU, /* 692: 1.0e+344 >> 1079 */ - 0x85eab0e41a6940e5LLU, /* 693: 1.0e+345 >> 1083 */ - 0xa7655d1d2103911fLLU, /* 694: 1.0e+346 >> 1086 */ - 0xd13eb46469447567LLU, /* 695: 1.0e+347 >> 1089 */ -}; -#define POWERSOF10_FIRST (-348) -#define POWERSOF10_LAST (+347) -#define POWERSOF10_COUNT (696) /* ** Two inputs are multiplied to get a 128-bit result. Return @@ -1201,6 +482,123 @@ static u64 sqlite3Multiply128(u64 a, u64 b){ #endif } +/* +** Return a u64 with the N-th bit set. +*/ +#define U64_BIT(N) (((u64)1)<<(N)) + +/* +** Range of powers of 10 that we need to deal with when converting +** IEEE754 doubles to and from decimal. +*/ +#define POWERSOF10_FIRST (-348) +#define POWERSOF10_LAST (+347) + +/* +** For any p between -348 and +347, return the integer part of +** +** pow(10,p) * pow(2,63-pow10to2(p)) +** +** Or, in other words, for any p in range, return the most significant +** 64 bits of pow(10,p). The pow(10,p) value is shifted left or right, +** as appropriate so the most significant 64 bits fit exactly into a +** 64-bit unsigned integer. +** +** Algorithm: +** +** (1) For p between 0 and 26, return the value directly from the aBase[] +** lookup table. +** +** (2) For p outside the range 0 to 26, use aScale[] for the initial value +** then refine that result (if necessary) by a single multiplication +** against aBase[]. +*/ +static u64 powerOfTen(int p){ + static const u64 aBase[] = { + 0x8000000000000000LLU, /* 0: 1.0e+0 << 63 */ + 0xa000000000000000LLU, /* 1: 1.0e+1 << 60 */ + 0xc800000000000000LLU, /* 2: 1.0e+2 << 57 */ + 0xfa00000000000000LLU, /* 3: 1.0e+3 << 54 */ + 0x9c40000000000000LLU, /* 4: 1.0e+4 << 50 */ + 0xc350000000000000LLU, /* 5: 1.0e+5 << 47 */ + 0xf424000000000000LLU, /* 6: 1.0e+6 << 44 */ + 0x9896800000000000LLU, /* 7: 1.0e+7 << 40 */ + 0xbebc200000000000LLU, /* 8: 1.0e+8 << 37 */ + 0xee6b280000000000LLU, /* 9: 1.0e+9 << 34 */ + 0x9502f90000000000LLU, /* 10: 1.0e+10 << 30 */ + 0xba43b74000000000LLU, /* 11: 1.0e+11 << 27 */ + 0xe8d4a51000000000LLU, /* 12: 1.0e+12 << 24 */ + 0x9184e72a00000000LLU, /* 13: 1.0e+13 << 20 */ + 0xb5e620f480000000LLU, /* 14: 1.0e+14 << 17 */ + 0xe35fa931a0000000LLU, /* 15: 1.0e+15 << 14 */ + 0x8e1bc9bf04000000LLU, /* 16: 1.0e+16 << 10 */ + 0xb1a2bc2ec5000000LLU, /* 17: 1.0e+17 << 7 */ + 0xde0b6b3a76400000LLU, /* 18: 1.0e+18 << 4 */ + 0x8ac7230489e80000LLU, /* 19: 1.0e+19 >> 0 */ + 0xad78ebc5ac620000LLU, /* 20: 1.0e+20 >> 3 */ + 0xd8d726b7177a8000LLU, /* 21: 1.0e+21 >> 6 */ + 0x878678326eac9000LLU, /* 22: 1.0e+22 >> 10 */ + 0xa968163f0a57b400LLU, /* 23: 1.0e+23 >> 13 */ + 0xd3c21bcecceda100LLU, /* 24: 1.0e+24 >> 16 */ + 0x84595161401484a0LLU, /* 25: 1.0e+25 >> 20 */ + 0xa56fa5b99019a5c8LLU, /* 26: 1.0e+26 >> 23 */ + }; + static const u64 aScale[] = { + 0x8049a4ac0c5811aeLLU, /* 0: 1.0e-351 << 1229 */ + 0xcf42894a5dce35eaLLU, /* 1: 1.0e-324 << 1140 */ + 0xa76c582338ed2621LLU, /* 2: 1.0e-297 << 1050 */ + 0x873e4f75e2224e68LLU, /* 3: 1.0e-270 << 960 */ + 0xda7f5bf590966848LLU, /* 4: 1.0e-243 << 871 */ + 0xb080392cc4349decLLU, /* 5: 1.0e-216 << 781 */ + 0x8e938662882af53eLLU, /* 6: 1.0e-189 << 691 */ + 0xe65829b3046b0afaLLU, /* 7: 1.0e-162 << 602 */ + 0xba121a4650e4ddebLLU, /* 8: 1.0e-135 << 512 */ + 0x964e858c91ba2655LLU, /* 9: 1.0e-108 << 422 */ + 0xf2d56790ab41c2a2LLU, /* 10: 1.0e-81 << 333 */ + 0xc428d05aa4751e4cLLU, /* 11: 1.0e-54 << 243 */ + 0x9e74d1b791e07e48LLU, /* 12: 1.0e-27 << 153 */ + 0x8000000000000000LLU, /* 13: 1.0e+0 << 63 */ + 0xcecb8f27f4200f3aLLU, /* 14: 1.0e+27 >> 26 */ + 0xa70c3c40a64e6c51LLU, /* 15: 1.0e+54 >> 116 */ + 0x86f0ac99b4e8dafdLLU, /* 16: 1.0e+81 >> 206 */ + 0xda01ee641a708de9LLU, /* 17: 1.0e+108 >> 295 */ + 0xb01ae745b101e9e4LLU, /* 18: 1.0e+135 >> 385 */ + 0x8e41ade9fbebc27dLLU, /* 19: 1.0e+162 >> 475 */ + 0xe5d3ef282a242e81LLU, /* 20: 1.0e+189 >> 564 */ + 0xb9a74a0637ce2ee1LLU, /* 21: 1.0e+216 >> 654 */ + 0x95f83d0a1fb69cd9LLU, /* 22: 1.0e+243 >> 744 */ + 0xf24a01a73cf2dccfLLU, /* 23: 1.0e+270 >> 833 */ + 0xc3b8358109e84f07LLU, /* 24: 1.0e+297 >> 923 */ + 0x9e19db92b4e31ba9LLU, /* 25: 1.0e+324 >> 1013 */ + }; + int g, n; + u64 x, y; + + assert( p>=POWERSOF10_FIRST && p<=POWERSOF10_LAST ); + if( p<0 ){ + g = p/27; + n = p%27; + if( n ){ + g--; + n += 27; + } + }else if( p<27 ){ + return aBase[p]; + }else{ + g = p/27; + n = p%27; + } + y = aScale[g+13]; + if( n==0 ){ + return y; + } + x = sqlite3Multiply128(aBase[n],y); + if( (U64_BIT(63) & x)==0 ){ + x <<= 1; + } + return x; +} + /* ** pow10to2(x) computes floor(log2(pow(10,x))). ** pow2to10(y) computes floor(log10(pow(2,y))). @@ -1222,11 +620,6 @@ static u64 sqlite3Multiply128(u64 a, u64 b){ static int pwr10to2(int p){ return (p*108853) >> 15; } static int pwr2to10(int p){ return (p*78913) >> 18; } -/* -** Return a u64 with the N-th bit set. -*/ -#define U64_BIT(N) (((u64)1)<<(N)) - /* ** Count leading zeros for a 64-bit unsigned integer. */ @@ -1254,11 +647,10 @@ static int countLeadingZeros(u64 m){ ** m should be left-shifted, and e decremented, to maximize the value of m. */ static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){ - int p, idx; + int p; u64 h, out; p = n - 1 - pwr2to10(e+63); - idx = p - POWERSOF10_FIRST; - h = sqlite3Multiply128(m, sqlite3PowerOfTen[idx]); + h = sqlite3Multiply128(m, powerOfTen(p)); assert( -(e + pwr10to2(p) + 3) >=0 ); assert( -(e + pwr10to2(p) + 3) <64 ); out = h >> -(e + pwr10to2(p) + 3); @@ -1275,7 +667,6 @@ static double sqlite3Fp10Convert2(u64 d, int p){ int e1; int e2; int lp; - int idx; u64 h; double r; assert( (d & U64_BIT(63))==0 ); @@ -1294,8 +685,7 @@ static double sqlite3Fp10Convert2(u64 d, int p){ e1 = 1074; } e2 = e1 - (64-b); - idx = p - POWERSOF10_FIRST; - h = sqlite3Multiply128(d<<(64-b), sqlite3PowerOfTen[idx]); + h = sqlite3Multiply128(d<<(64-b), powerOfTen(p)); assert( -(e2 + lp + 3) >=0 ); assert( -(e2 + lp + 3) <64 ); out = (h >> -(e2 + lp + 3)) | 1; From 7b93f1a38710d4d116f9db82ff370d8525c00df1 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 16 Feb 2026 11:59:14 +0000 Subject: [PATCH 016/197] Fix a problem with identifying ON clauses attached to RIGHT or FULL JOINs (which is an error) if the join appeared in a flattened sub-query. FossilOrigin-Name: cf2dc6dfad275dad8fef763a57baaaf6301b0d3bf1916be90f22200cbe0115d0 --- manifest | 21 ++++++++++----------- manifest.uuid | 2 +- src/resolve.c | 8 ++++++++ src/select.c | 14 +------------- src/sqliteInt.h | 1 + test/joinI.test | 25 +++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 9f7d1acde9..a3134bc2e0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Performance\simprovement\sin\sfloating-point\sconversions. -D 2026-02-16T11:14:59.370 +C Fix\sa\sproblem\swith\sidentifying\sON\sclauses\sattached\sto\sRIGHT\sor\sFULL\sJOINs\s(which\sis\san\serror)\sif\sthe\sjoin\sappeared\sin\sa\sflattened\ssub-query. +D 2026-02-16T11:59:14.701 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -736,14 +736,14 @@ F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c -F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b +F src/resolve.c c1dcb80bea2c37e6d01fea793e4f5f6f6254569f3a3aecf18d88b6fc3702a84b F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c 3bbcb0dbdac61a856b1ba3e2ed64d609935eca884b20208e5df5eeb183e2413f +F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c F src/shell.c.in b944a21d98cc4c6107bfd1ec702440579cb4bf86435125b67ff661180e9453b5 F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h 8ee3bc74b485825d30292c1dd253cd476fba76cbe112e0b074616c2811fd245e +F src/sqliteInt.h 908d5522b3b362c2b968b6a6ee2f495a32e2d4da971209ac43810a0b081f1d90 F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -1342,7 +1342,7 @@ F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127 F test/joinH.test 1d2fc3190be68525fd9ce749b9468c40ba2930181e52fb5ee6f836051b38effb -F test/joinI.test fc7d24a2b1e444979b83bd92c30ebb975cebb5b9eae4442ce94969bd8d083053 +F test/joinI.test f48cfbec4fd68a0d7a4498593164a4d76d622774afe896b46c223cbe15e02f55 F test/journal1.test bc61a4228db11bffca118bd358ba4b868524bf080f3532749de6c539656e20fa F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test e5aeff93a7776cf644dbc48dec277655cff80a1cd24689036abc87869b120ea6 @@ -2194,9 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d62999907d5f5987fe0030e1a4a7144c898e55595ac116eec966741a5099322b 245ac7d9ec61e14fcef13a731e290fc5e8979efef6f4345f875eab9b882b0713 -R b366df680debb06b15e36654b276676e -T +closed 245ac7d9ec61e14fcef13a731e290fc5e8979efef6f4345f875eab9b882b0713 -U drh -Z 31a78bbdbba7544afc87d10fe769a17b +P b5ebbd004183f81902fa79a143222204b33dbe1cacb918194556b8dac67bd567 +R 962f4ef1dbd316a124811ac609d56f62 +U dan +Z 5af30b1d418ec7aa73d461b781393237 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 144927d253..6b98f673bf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b5ebbd004183f81902fa79a143222204b33dbe1cacb918194556b8dac67bd567 +cf2dc6dfad275dad8fef763a57baaaf6301b0d3bf1916be90f22200cbe0115d0 diff --git a/src/resolve.c b/src/resolve.c index 6aa8d6653b..d806092359 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -2250,6 +2250,14 @@ void sqlite3ResolveSelectNames( w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); + + /* If the SELECT statement contains ON clauses that were moved into + ** the WHERE clause, go through and verify that none of the terms + ** in the ON clauses reference tables to the right of the ON clause. + ** Do this now, immediately after name resolution. */ + if( pParse->nErr==0 && (p->selFlags & SF_OnToWhere) ){ + sqlite3SelectCheckOnClauses(pParse, p); + } } /* diff --git a/src/select.c b/src/select.c index 600ef021fc..e75de96d5c 100644 --- a/src/select.c +++ b/src/select.c @@ -7491,7 +7491,7 @@ static int selectCheckOnClausesSelect(Walker *pWalker, Select *pSelect){ ** Check all ON clauses in pSelect to verify that they do not reference ** columns to the right. */ -static void selectCheckOnClauses(Parse *pParse, Select *pSelect){ +void sqlite3SelectCheckOnClauses(Parse *pParse, Select *pSelect){ Walker w; CheckOnCtx sCtx; int ii; @@ -7671,18 +7671,6 @@ int sqlite3Select( } #endif - /* If the SELECT statement contains ON clauses that were moved into - ** the WHERE clause, go through and verify that none of the terms - ** in the ON clauses reference tables to the right of the ON clause. - ** Do this now, after name resolution, but before query flattening - */ - if( p->selFlags & SF_OnToWhere ){ - selectCheckOnClauses(pParse, p); - if( pParse->nErr ){ - goto select_end; - } - } - /* If the SF_UFSrcCheck flag is set, then this function is being called ** as part of populating the temp table for an UPDATE...FROM statement. ** In this case, it is an error if the target object (pSrc->a[0]) name diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 0f11c22e7f..833572f417 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -5068,6 +5068,7 @@ Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); void sqlite3SelectDeleteGeneric(sqlite3*,void*); +void sqlite3SelectCheckOnClauses(Parse *pParse, Select *pSelect); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, Trigger*); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); diff --git a/test/joinI.test b/test/joinI.test index 577ca4c2c3..c9cd316f74 100644 --- a/test/joinI.test +++ b/test/joinI.test @@ -121,5 +121,30 @@ do_execsql_test 5.1 { INNER JOIN child2 ON child2.child2key = parent1.child2key; } +#------------------------------------------------------------------------- +reset_db +do_execsql_test 6.0 { + CREATE TABLE t5(a, d); + CREATE TABLE t6(a, e); + INSERT INTO t5 VALUES(1, 'red'); + INSERT INTO t6 VALUES(0, 1000); + + CREATE TABLE t7(x); + CREATE TABLE t8(y); +} + +do_catchsql_test 6.1 { + SELECT * FROM t6 CROSS JOIN (t7 RIGHT JOIN t8 ON (t6.a)); +} {1 {no such column: t6.a}} + +do_catchsql_test 6.4 { + SELECT * FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6; +} {1 {ON clause references tables to its right}} + +do_catchsql_test 6.5 { + SELECT * FROM + (SELECT * FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6); +} {1 {ON clause references tables to its right}} + finish_test From 1105c33900f93c0a74f233b7d62e94146df506eb Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 16 Feb 2026 16:56:25 +0000 Subject: [PATCH 017/197] Fix another case where SQLite might fail to identify an ON clause on a RIGHT or FULL join that refers to FROM-clause elements to its right. FossilOrigin-Name: e956b36063e77b5ad0d8b8afb5dc942665f570d762929ff277e320c06ded8ce6 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/resolve.c | 16 ++++++++-------- test/joinI.test | 22 ++++++++++++++++++++++ 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index a3134bc2e0..01047c2b72 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swith\sidentifying\sON\sclauses\sattached\sto\sRIGHT\sor\sFULL\sJOINs\s(which\sis\san\serror)\sif\sthe\sjoin\sappeared\sin\sa\sflattened\ssub-query. -D 2026-02-16T11:59:14.701 +C Fix\sanother\scase\swhere\sSQLite\smight\sfail\sto\sidentify\san\sON\sclause\son\sa\sRIGHT\sor\sFULL\sjoin\sthat\srefers\sto\sFROM-clause\selements\sto\sits\sright. +D 2026-02-16T16:56:25.515 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -736,7 +736,7 @@ F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c -F src/resolve.c c1dcb80bea2c37e6d01fea793e4f5f6f6254569f3a3aecf18d88b6fc3702a84b +F src/resolve.c f7af61e80e1ae1e0fc5aae9e430f6195a4063d670deae504905d1ef13324cd76 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c F src/shell.c.in b944a21d98cc4c6107bfd1ec702440579cb4bf86435125b67ff661180e9453b5 @@ -1342,7 +1342,7 @@ F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127 F test/joinH.test 1d2fc3190be68525fd9ce749b9468c40ba2930181e52fb5ee6f836051b38effb -F test/joinI.test f48cfbec4fd68a0d7a4498593164a4d76d622774afe896b46c223cbe15e02f55 +F test/joinI.test 249802b168ce96d8d57943ef9abafc1e36e28d91829f68bc2b6e87f2b4d33241 F test/journal1.test bc61a4228db11bffca118bd358ba4b868524bf080f3532749de6c539656e20fa F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test e5aeff93a7776cf644dbc48dec277655cff80a1cd24689036abc87869b120ea6 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b5ebbd004183f81902fa79a143222204b33dbe1cacb918194556b8dac67bd567 -R 962f4ef1dbd316a124811ac609d56f62 +P cf2dc6dfad275dad8fef763a57baaaf6301b0d3bf1916be90f22200cbe0115d0 +R 2e7ff14b5ef634dc725bfd72473b0ff4 U dan -Z 5af30b1d418ec7aa73d461b781393237 +Z d0c166fbac26f66972b26fd6effe2f97 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 6b98f673bf..0a85212cf4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cf2dc6dfad275dad8fef763a57baaaf6301b0d3bf1916be90f22200cbe0115d0 +e956b36063e77b5ad0d8b8afb5dc942665f570d762929ff277e320c06ded8ce6 diff --git a/src/resolve.c b/src/resolve.c index d806092359..0f4572f3a5 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -2073,6 +2073,14 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ return WRC_Abort; } + /* If the SELECT statement contains ON clauses that were moved into + ** the WHERE clause, go through and verify that none of the terms + ** in the ON clauses reference tables to the right of the ON clause. */ + if( (p->selFlags & SF_OnToWhere) ){ + sqlite3SelectCheckOnClauses(pParse, p); + if( pParse->nErr ) return WRC_Abort; + } + /* Advance to the next term of the compound */ p = p->pPrior; @@ -2250,14 +2258,6 @@ void sqlite3ResolveSelectNames( w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); - - /* If the SELECT statement contains ON clauses that were moved into - ** the WHERE clause, go through and verify that none of the terms - ** in the ON clauses reference tables to the right of the ON clause. - ** Do this now, immediately after name resolution. */ - if( pParse->nErr==0 && (p->selFlags & SF_OnToWhere) ){ - sqlite3SelectCheckOnClauses(pParse, p); - } } /* diff --git a/test/joinI.test b/test/joinI.test index c9cd316f74..3390afc6e4 100644 --- a/test/joinI.test +++ b/test/joinI.test @@ -146,5 +146,27 @@ do_catchsql_test 6.5 { (SELECT * FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6); } {1 {ON clause references tables to its right}} +do_catchsql_test 6.6 { + SELECT *, NOT EXISTS ( + SELECT * FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6 + ) FROM t5; +} {1 {ON clause references tables to its right}} + +do_catchsql_test 6.7 { + SELECT *, NOT EXISTS ( + SELECT 1 + EXCEPT + SELECT 11 FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6 + ) FROM t5; +} {1 {ON clause references tables to its right}} + +do_catchsql_test 6.8 { + SELECT *, NOT EXISTS ( + SELECT 11 FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6 + EXCEPT + SELECT 1 + ) FROM t5; +} {1 {ON clause references tables to its right}} + finish_test From 5c977eaa0aa812ca54625adf98f15a42dd61cf07 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 16 Feb 2026 16:56:59 +0000 Subject: [PATCH 018/197] Refactor the sqlite3AtoF() routine so that it requires a zero-terminated UTF-8 input. When the need arises to convert UTF16 or non-terminated strings, wrapper functions are used. Together, this makes the code slightly smaller and faster. FossilOrigin-Name: 67c7c72e9bdf04c920d77006538a202c923fa74b47c81dc3014c2929dac7277d --- ext/rtree/geopoly.c | 3 +- manifest | 39 ++++++++++---------- manifest.tags | 4 +-- manifest.uuid | 2 +- src/date.c | 14 +++++--- src/expr.c | 2 +- src/func.c | 4 +-- src/json.c | 2 +- src/resolve.c | 2 +- src/sqliteInt.h | 2 +- src/util.c | 77 +++++++++++++--------------------------- src/vdbe.c | 8 +++-- src/vdbeInt.h | 3 +- src/vdbemem.c | 86 +++++++++++++++++++++++++++++++++++++-------- src/whereexpr.c | 5 +-- 15 files changed, 148 insertions(+), 105 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 0ae42e7b72..50c48891ae 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -200,7 +200,8 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ /* The sqlite3AtoF() routine is much much faster than atof(), if it ** is available */ double r; - (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8); + assert( p->z[j]==0 ); + (void)sqlite3AtoF((const char*)p->z, &r); *pVal = r; #else *pVal = (GeoCoord)atof((const char*)p->z); diff --git a/manifest b/manifest index a3134bc2e0..d8088ec23f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swith\sidentifying\sON\sclauses\sattached\sto\sRIGHT\sor\sFULL\sJOINs\s(which\sis\san\serror)\sif\sthe\sjoin\sappeared\sin\sa\sflattened\ssub-query. -D 2026-02-16T11:59:14.701 +C Refactor\sthe\ssqlite3AtoF()\sroutine\sso\sthat\sit\srequires\sa\szero-terminated\nUTF-8\sinput.\s\sWhen\sthe\sneed\sarises\sto\sconvert\sUTF16\sor\snon-terminated\nstrings,\swrapper\sfunctions\sare\sused.\s\sTogether,\sthis\smakes\sthe\scode\sslightly\nsmaller\sand\sfaster. +D 2026-02-16T16:56:59.150 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -498,7 +498,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782 F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c335096108c12c01bddbadcec F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c F ext/rtree/README 734aa36238bcd2dee91db5dba107d5fcbdb02396612811377a8ad50f1272b1c1 -F ext/rtree/geopoly.c f0573d5109fdc658a180db0db6eec86ab2a1cf5ce58ec66cbf3356167ea757eb +F ext/rtree/geopoly.c 8317e860e8b2b61c7772956e6da5351268428d1530f5bc5345f50c82e90fa5c0 F ext/rtree/rtree.c 9331997a76b88a9bc04e156bdfd6e2fe35c0aa93bc338ebc6aa0ae470fe4a852 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test e0608db762b2aadca0ecb6f97396cf66244490adc3ba88f2a292b27be3e1da3e @@ -685,21 +685,21 @@ F src/build.c cc0afd3ec8417f5f774650f612e755b7ffce392d14ab4441bf5588867893fd3c F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e -F src/date.c e19e0cfff9a41bfdd884c655755f6f00bca4c1a22272b56e0dd6667b7ea893a2 +F src/date.c e1a6c5ac4753016198d664d633b8541fa4ad4ccde2beb12548fa99e746f38cec F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c F src/delete.c 901499bed747c3b4b2be45be1abe912ba50a3f6a40ba88cc006ccf279f2d0e97 -F src/expr.c c4ff8dcacbc8962fb670fc7c9723c8346398795b16ce2f78439234769baee2e6 +F src/expr.c 8c3b23cb35f43c2d0570c1058b9a269e561e769e09c81ba192992c95022c1939 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c fb0f74c57d19a2d3f113f3476826919d68feda7ff334abfdb479a9a6353b9fcd -F src/func.c 6b6797b1b8d90c40482795a9a571041ca09bd520c5fa85cb1a49be143eda0bcf +F src/func.c 785f62a6e00636c9b185ccee0cde17be711458227340137d57492ed3226d4253 F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf F src/hwtime.h 21c2cf1f736e7b97502c3674d0c386db3f06870d6f10d0cf8174e2a4b8cb726e F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd -F src/json.c af766b62caee01c735cfe7795cc91ffea5a5e1c555a5d8a9aa5a301f00a1b0ad +F src/json.c 8b6341a419150b28530cc21e3951b2238c35cdc312f11b2ca29017fe4b1dedc0 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9 F src/main.c e95aa130478fc98a49181ddf094baab45f319286411129253618efe0008f0dc4 @@ -736,14 +736,14 @@ F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c -F src/resolve.c c1dcb80bea2c37e6d01fea793e4f5f6f6254569f3a3aecf18d88b6fc3702a84b +F src/resolve.c 57020e1b499b7189953c59ce8a4db9fe7fdc849b47d583b1e1eb50c9dd1d1733 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c F src/shell.c.in b944a21d98cc4c6107bfd1ec702440579cb4bf86435125b67ff661180e9453b5 F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h 908d5522b3b362c2b968b6a6ee2f495a32e2d4da971209ac43810a0b081f1d90 +F src/sqliteInt.h cd77fd03f7bf9d7b012a28c96cacdd20f09054bfe4edcebd92f789f0bc37c9fb F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -803,15 +803,15 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 0cc410d538fe13a2cda90a8d0087c82cf4c1ab0d5055b8e3a595f28266f190c7 +F src/util.c 16c7fcce87e43c612dd579c87d11a085ce5243565b7c324806f4a506c5e696a4 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 -F src/vdbe.c fa28a8f740f3d94c4e6b6d42ba90c220472683486268e753017512a70ef715f5 +F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 -F src/vdbeInt.h c45d0195dad0a9099132109e3b63697f4f119baddeb391c36ca226cee530a485 +F src/vdbeInt.h 42488247a80cd9d300627833c6c85ace067ae5011a99e7614e2358130d62feea F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1 F src/vdbeaux.c 396d38a62a357b807eabae0cae441fc89d2767a57ab08026b7072bf7aa2dd00c F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692 -F src/vdbemem.c 699d2fb0a59a00cf9b77898653167673de60fa5577e07bd6bee6adaef5fdc374 +F src/vdbemem.c bdfda8e65933cfee34aa29c2bfa31fc07609f3d56d147aa8a367a297533d33d1 F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70 F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 @@ -823,7 +823,7 @@ F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 F src/where.c 7a7fe745dd8104d0276a3d3f6e6ac7f087af3dd9f34a90bc937e5e7aea817e15 F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da F src/wherecode.c 783ecd30061c875c919a5163e4b55f9a0eccdaf7c9b17ad2908a1668a8766bc4 -F src/whereexpr.c bb649ce81bd6dc0eabfa2533ff5656fc7a16411e520a6c59be43e73e51503cce +F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6 F src/window.c c0a38cd32473e8e8e7bc435039f914a36ca42465506dc491c65870c01ddac9fb F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test 4d7a34d328e58ca2a2d78fd76c27614a41ca7ddf4312ded9c68c04f430b3b47d @@ -2194,8 +2194,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b5ebbd004183f81902fa79a143222204b33dbe1cacb918194556b8dac67bd567 -R 962f4ef1dbd316a124811ac609d56f62 -U dan -Z 5af30b1d418ec7aa73d461b781393237 +P cf2dc6dfad275dad8fef763a57baaaf6301b0d3bf1916be90f22200cbe0115d0 +R 437155dd45848e71532967f5113d7bd1 +T *branch * numeric-conversion-perf +T *sym-numeric-conversion-perf * +T -sym-trunk * +U drh +Z 37bb3fa124d03f3d009e27255e0475da # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..db708de054 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch numeric-conversion-perf +tag numeric-conversion-perf diff --git a/manifest.uuid b/manifest.uuid index 6b98f673bf..896529709f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cf2dc6dfad275dad8fef763a57baaaf6301b0d3bf1916be90f22200cbe0115d0 +67c7c72e9bdf04c920d77006538a202c923fa74b47c81dc3014c2929dac7277d diff --git a/src/date.c b/src/date.c index 5e7ae6f1fc..17c8e8a543 100644 --- a/src/date.c +++ b/src/date.c @@ -429,7 +429,7 @@ static int parseDateOrTime( return 0; }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); - }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){ + }else if( sqlite3AtoF(zDate, &r)>0 ){ setRawDateNumber(p, r); return 0; }else if( (sqlite3StrICmp(zDate,"subsec")==0 @@ -875,7 +875,7 @@ static int parseModifier( ** date is already on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 - && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 + && sqlite3AtoF(&z[8], &r)>0 && r>=0.0 && r<7.0 && (n=(int)r)==r ){ sqlite3_int64 Z; computeYMD_HMS(p); @@ -946,9 +946,11 @@ static int parseModifier( case '8': case '9': { double rRounder; - int i; + int i, rx; int Y,M,D,h,m,x; const char *z2 = z; + char *zCopy; + sqlite3 *db = sqlite3_context_db_handle(pCtx); char z0 = z[0]; for(n=1; z[n]; n++){ if( z[n]==':' ) break; @@ -958,7 +960,11 @@ static int parseModifier( if( n==6 && getDigits(&z[1], "50f", &Y)==1 ) break; } } - if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){ + zCopy = sqlite3DbStrNDup(db, z, n); + if( zCopy==0 ) break; + rx = sqlite3AtoF(zCopy, &r)<=0; + sqlite3DbFree(db, zCopy); + if( rx ){ assert( rc==1 ); break; } diff --git a/src/expr.c b/src/expr.c index b635b98910..d486e48e37 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4303,7 +4303,7 @@ static void sqlite3ExprCodeIN( static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ if( ALWAYS(z!=0) ){ double value; - sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); + sqlite3AtoF(z, &value); assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ if( negateFlag ) value = -value; sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL); diff --git a/src/func.c b/src/func.c index d9c148e9c3..029f7ae8ef 100644 --- a/src/func.c +++ b/src/func.c @@ -466,7 +466,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_result_error_nomem(context); return; } - sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8); + sqlite3AtoF(zBuf, &r); sqlite3_free(zBuf); } sqlite3_result_double(context, r); @@ -1104,7 +1104,7 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){ sqlite3_str_appendf(pStr, "%!0.15g", r1); zVal = sqlite3_str_value(pStr); if( zVal ){ - sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8); + sqlite3AtoF(zVal, &r2); if( r1!=r2 ){ sqlite3_str_reset(pStr); sqlite3_str_appendf(pStr, "%!0.20e", r1); diff --git a/src/json.c b/src/json.c index 794b5406cf..795d3ed731 100644 --- a/src/json.c +++ b/src/json.c @@ -3266,7 +3266,7 @@ static void jsonReturnFromBlob( to_double: z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); if( z==0 ) goto returnfromblob_oom; - rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); + rc = sqlite3AtoF(z, &r); sqlite3DbFree(db, z); if( rc<=0 ) goto returnfromblob_malformed; sqlite3_result_double(pCtx, r); diff --git a/src/resolve.c b/src/resolve.c index d806092359..868c889f3d 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -936,7 +936,7 @@ static int exprProbability(Expr *p){ double r = -1.0; if( p->op!=TK_FLOAT ) return -1; assert( !ExprHasProperty(p, EP_IntValue) ); - sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); + sqlite3AtoF(p->u.zToken, &r); assert( r>=0.0 ); if( r>1.0 ) return -1; return (int)(r*134217728.0); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 833572f417..27d436c4ba 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -5290,7 +5290,7 @@ int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); int sqlite3RealSameAsInt(double,sqlite3_int64); i64 sqlite3RealToI64(double); int sqlite3Int64ToText(i64,char*); -int sqlite3AtoF(const char *z, double*, int, u8); +int sqlite3AtoF(const char *z, double*); int sqlite3GetInt32(const char *, int*); int sqlite3GetUInt32(const char*, u32*); int sqlite3Atoi(const char*); diff --git a/src/util.c b/src/util.c index 9522c14c0c..bd60ec92e9 100644 --- a/src/util.c +++ b/src/util.c @@ -708,8 +708,7 @@ static double sqlite3Fp10Convert2(u64 d, int p){ ** The string z[] is an text representation of a real number. ** Convert this string to a double and write it into *pResult. ** -** The string z[] is length bytes in length (bytes, not characters) and -** uses the encoding enc. The string is not necessarily zero-terminated. +** z[] must be UTF-8 and zero-terminated. ** ** Return TRUE if the result is a valid real number (or integer) and FALSE ** if the string is empty or contains extraneous text. More specifically @@ -736,10 +735,8 @@ static double sqlite3Fp10Convert2(u64 d, int p){ #if defined(_MSC_VER) #pragma warning(disable : 4756) #endif -int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ +int sqlite3AtoF(const char *z, double *pResult){ #ifndef SQLITE_OMIT_FLOATING_POINT - int incr; - const char *zEnd; /* sign * significand * (10 ^ (esign * exponent)) */ int sign = 1; /* sign of significand */ u64 s = 0; /* significand */ @@ -748,103 +745,76 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ int e = 0; /* exponent */ int eValid = 1; /* True exponent is either not used or is well-formed */ int nDigit = 0; /* Number of digits processed */ - int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ + int eType = 1; /* 1: pure integer, 2+: fractional */ - assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ - if( length==0 ) return 0; - - if( enc==SQLITE_UTF8 ){ - incr = 1; - zEnd = z + length; - }else{ - int i; - incr = 2; - length &= ~1; - assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); - testcase( enc==SQLITE_UTF16LE ); - testcase( enc==SQLITE_UTF16BE ); - for(i=3-enc; i=zEnd ) return 0; + while( sqlite3Isspace(*z) ) z++; /* get sign of significand */ if( *z=='-' ){ sign = -1; - z+=incr; + z++; }else if( *z=='+' ){ - z+=incr; + z++; } /* copy max significant digits to significand */ - while( z=((LARGEST_INT64-9)/10) ){ /* skip non-significant significand digits ** (increase exponent by d to shift decimal left) */ - while( z=zEnd ) goto do_atof_calc; /* if decimal point is present */ if( *z=='.' ){ - z+=incr; + z++; eType++; /* copy digits from after decimal to significand ** (decrease exponent by d to shift decimal right) */ - while( z=zEnd ) goto do_atof_calc; /* if exponent is present */ if( *z=='e' || *z=='E' ){ - z+=incr; + z++; eValid = 0; eType++; - /* This branch is needed to avoid a (harmless) buffer overread. The - ** special comment alerts the mutation tester that the correct answer - ** is obtained even if the branch is omitted */ - if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/ - /* get sign of exponent */ if( *z=='-' ){ esign = -1; - z+=incr; + z++; }else if( *z=='+' ){ - z+=incr; + z++; } /* copy digits to exponent */ - while( z0 && eValid && eType>0 ){ + if( z[0]==0 && nDigit>0 && eValid ){ return eType; }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ return -1; @@ -864,13 +834,16 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ return 0; } #else - return !sqlite3Atoi64(z, pResult, length, enc); + return !sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8); #endif /* SQLITE_OMIT_FLOATING_POINT */ } #if defined(_MSC_VER) #pragma warning(default : 4756) #endif + + + /* ** Render an signed 64-bit integer as text. Store the result in zOut[] and ** return the length of the string that was stored, in bytes. The value diff --git a/src/vdbe.c b/src/vdbe.c index e7d5a4c27d..e2e98eb5ff 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -353,10 +353,9 @@ static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){ */ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; - u8 enc = pRec->enc; int rc; assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str ); - rc = sqlite3AtoF(pRec->z, &rValue, pRec->n, enc); + rValue = sqlite3MemRealValueRC(pRec, &rc); if( rc<=0 ) return; if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ pRec->flags |= MEM_Int; @@ -438,7 +437,10 @@ int sqlite3_value_numeric_type(sqlite3_value *pVal){ int eType = sqlite3_value_type(pVal); if( eType==SQLITE_TEXT ){ Mem *pMem = (Mem*)pVal; + assert( pMem->db!=0 ); + sqlite3_mutex_enter(pMem->db->mutex); applyNumericAffinity(pMem, 0); + sqlite3_mutex_leave(pMem->db->mutex); eType = sqlite3_value_type(pVal); } return eType; @@ -471,7 +473,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ pMem->u.i = 0; return MEM_Int; } - rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + pMem->u.r = sqlite3MemRealValueRC(pMem, &rc); if( rc<=0 ){ if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ pMem->u.i = ix; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index fdca8ecb95..320721d065 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -649,13 +649,14 @@ int sqlite3VdbeMemSetZeroBlob(Mem*,int); int sqlite3VdbeMemIsRowSet(const Mem*); #endif int sqlite3VdbeMemSetRowSet(Mem*); -void sqlite3VdbeMemZeroTerminateIfAble(Mem*); +int sqlite3VdbeMemZeroTerminateIfAble(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemStringify(Mem*, u8, u8); int sqlite3IntFloatCompare(i64,double); i64 sqlite3VdbeIntValue(const Mem*); int sqlite3VdbeMemIntegerify(Mem*); double sqlite3VdbeRealValue(Mem*); +SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem*, int*); int sqlite3VdbeBooleanValue(Mem*, int ifNull); void sqlite3VdbeIntegerAffinity(Mem*); int sqlite3VdbeMemRealify(Mem*); diff --git a/src/vdbemem.c b/src/vdbemem.c index db0561aee1..91c45ee08b 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -320,13 +320,16 @@ int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ ** ** This is an optimization. Correct operation continues even if ** this routine is a no-op. +** +** Return true if the strig is zero-terminated after this routine is +** called and false if it is not. */ -void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ +int sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ if( (pMem->flags & (MEM_Str|MEM_Term|MEM_Ephem|MEM_Static))!=MEM_Str ){ /* pMem must be a string, and it cannot be an ephemeral or static string */ - return; + return 0; } - if( pMem->enc!=SQLITE_UTF8 ) return; + if( pMem->enc!=SQLITE_UTF8 ) return 0; assert( pMem->z!=0 ); if( pMem->flags & MEM_Dyn ){ if( pMem->xDel==sqlite3_free @@ -334,18 +337,19 @@ void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ ){ pMem->z[pMem->n] = 0; pMem->flags |= MEM_Term; - return; + return 1; } if( pMem->xDel==sqlite3RCStrUnref ){ /* Blindly assume that all RCStr objects are zero-terminated */ pMem->flags |= MEM_Term; - return; + return 1; } }else if( pMem->szMalloc >= pMem->n+1 ){ pMem->z[pMem->n] = 0; pMem->flags |= MEM_Term; - return; + return 1; } + return 0; } /* @@ -643,18 +647,70 @@ i64 sqlite3VdbeIntValue(const Mem *pMem){ } } +/* +** Invoke sqlite3AtoF() on the text value of pMem and return the +** double result. If sqlite3AtoF() returns an error code, write +** that code into *pRC if (*pRC)!=NULL. +** +** The caller must ensure that pMem->db!=0 and that pMem is in +** mode MEM_Str or MEM_Blob. +*/ +SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem *pMem, int *pRC){ + double val = (double)0; + int rc = 0; + assert( pMem->db!=0 ); + assert( pMem->flags & (MEM_Str|MEM_Blob) ); + if( pMem->z==0 ){ + /* no-op */ + }else if( pMem->enc==SQLITE_UTF8 + && ((pMem->flags & MEM_Term)!=0 || sqlite3VdbeMemZeroTerminateIfAble(pMem)) + ){ + rc = sqlite3AtoF(pMem->z, &val); + }else if( pMem->n==0 ){ + /* no-op */ + }else if( pMem->enc==SQLITE_UTF8 ){ + char *zCopy = sqlite3DbStrNDup(pMem->db, pMem->z, pMem->n); + if( zCopy ){ + rc = sqlite3AtoF(zCopy, &val); + sqlite3DbFree(pMem->db, zCopy); + } + }else{ + int n, i, j; + char *zCopy; + const char *z; + + n = pMem->n & ~1; + zCopy = sqlite3DbMallocRaw(pMem->db, n/2 + 2); + if( zCopy ){ + z = pMem->z; + if( pMem->enc==SQLITE_UTF16LE ){ + for(i=j=0; idb, zCopy); + } + } + if( pRC ) *pRC = rc; + return val; +} + /* ** Return the best representation of pMem that we can get into a ** double. If pMem is already a double or an integer, return its ** value. If it is a string or blob, try to convert it to a double. ** If it is a NULL, return 0.0. */ -static SQLITE_NOINLINE double memRealValue(Mem *pMem){ - /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ - double val = (double)0; - sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); - return val; -} double sqlite3VdbeRealValue(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -665,7 +721,7 @@ double sqlite3VdbeRealValue(Mem *pMem){ testcase( pMem->flags & MEM_IntReal ); return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ - return memRealValue(pMem); + return sqlite3MemRealValueRC(pMem, 0); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; @@ -789,7 +845,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){ sqlite3_int64 ix; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + pMem->u.r = sqlite3MemRealValueRC(pMem, &rc); if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1) || sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r))) ){ @@ -1760,7 +1816,7 @@ static int valueFromExpr( if( affinity==SQLITE_AFF_BLOB ){ if( op==TK_FLOAT ){ assert( pVal && pVal->z && pVal->flags==(MEM_Str|MEM_Term) ); - sqlite3AtoF(pVal->z, &pVal->u.r, pVal->n, SQLITE_UTF8); + sqlite3AtoF(pVal->z, &pVal->u.r); pVal->flags = MEM_Real; }else if( op==TK_INTEGER ){ /* This case is required by -9223372036854775808 and other strings diff --git a/src/whereexpr.c b/src/whereexpr.c index 443bf6c55d..74bf624c8d 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -293,13 +293,14 @@ static int isLikeOrGlob( ){ int isNum; double rDummy; - isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + assert( zNew[iTo]==0 ); + isNum = sqlite3AtoF(zNew, &rDummy); if( isNum<=0 ){ if( iTo==1 && zNew[0]=='-' ){ isNum = +1; }else{ zNew[iTo-1]++; - isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + isNum = sqlite3AtoF(zNew, &rDummy); zNew[iTo-1]--; } } From 6315919ba8e5342f6fcbc061e8ddd42639cff308 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 16 Feb 2026 17:22:17 +0000 Subject: [PATCH 019/197] Fix a bad assert() in the previous check-in. FossilOrigin-Name: a4540582b5b704af13b570b3dc609dbacada719302372a038cf74eee3688d5e7 --- ext/rtree/geopoly.c | 1 - manifest | 15 ++++++--------- manifest.uuid | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 50c48891ae..22166a6f9e 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -200,7 +200,6 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ /* The sqlite3AtoF() routine is much much faster than atof(), if it ** is available */ double r; - assert( p->z[j]==0 ); (void)sqlite3AtoF((const char*)p->z, &r); *pVal = r; #else diff --git a/manifest b/manifest index d8088ec23f..25e473f434 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refactor\sthe\ssqlite3AtoF()\sroutine\sso\sthat\sit\srequires\sa\szero-terminated\nUTF-8\sinput.\s\sWhen\sthe\sneed\sarises\sto\sconvert\sUTF16\sor\snon-terminated\nstrings,\swrapper\sfunctions\sare\sused.\s\sTogether,\sthis\smakes\sthe\scode\sslightly\nsmaller\sand\sfaster. -D 2026-02-16T16:56:59.150 +C Fix\sa\sbad\sassert()\sin\sthe\sprevious\scheck-in. +D 2026-02-16T17:22:17.815 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -498,7 +498,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782 F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c335096108c12c01bddbadcec F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c F ext/rtree/README 734aa36238bcd2dee91db5dba107d5fcbdb02396612811377a8ad50f1272b1c1 -F ext/rtree/geopoly.c 8317e860e8b2b61c7772956e6da5351268428d1530f5bc5345f50c82e90fa5c0 +F ext/rtree/geopoly.c bd1971479184d559499ff3087c37f2823977d7b0ec80916141ae66f70345c88d F ext/rtree/rtree.c 9331997a76b88a9bc04e156bdfd6e2fe35c0aa93bc338ebc6aa0ae470fe4a852 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test e0608db762b2aadca0ecb6f97396cf66244490adc3ba88f2a292b27be3e1da3e @@ -2194,11 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P cf2dc6dfad275dad8fef763a57baaaf6301b0d3bf1916be90f22200cbe0115d0 -R 437155dd45848e71532967f5113d7bd1 -T *branch * numeric-conversion-perf -T *sym-numeric-conversion-perf * -T -sym-trunk * +P 67c7c72e9bdf04c920d77006538a202c923fa74b47c81dc3014c2929dac7277d +R 94ab950169198f260c23800402fd70a5 U drh -Z 37bb3fa124d03f3d009e27255e0475da +Z c0318b1fd81a3ec64d379bf447b9b4ea # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 896529709f..fe029aa3b9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -67c7c72e9bdf04c920d77006538a202c923fa74b47c81dc3014c2929dac7277d +a4540582b5b704af13b570b3dc609dbacada719302372a038cf74eee3688d5e7 From 63338e3ba8ce973135269088cc2497db171a2a8c Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 16 Feb 2026 23:52:51 +0000 Subject: [PATCH 020/197] Simplifications to sqlite3AtoF(), resulting in slightly faster performance and slightly smaller size. FossilOrigin-Name: 6b9ab641763bc1620a01beec71589506b3b0827bff1c6cd98a5d17c6070050b3 --- manifest | 12 ++++++------ manifest.tags | 4 ++-- manifest.uuid | 2 +- src/util.c | 44 +++++++++++++++++++++----------------------- 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/manifest b/manifest index 25e473f434..d472bbb667 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbad\sassert()\sin\sthe\sprevious\scheck-in. -D 2026-02-16T17:22:17.815 +C Simplifications\sto\ssqlite3AtoF(),\sresulting\sin\sslightly\sfaster\sperformance\nand\sslightly\ssmaller\ssize. +D 2026-02-16T23:52:51.130 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 16c7fcce87e43c612dd579c87d11a085ce5243565b7c324806f4a506c5e696a4 +F src/util.c 06313141ca1d9cf6a80961a6a2084e1f682dfecc741b5c2f527f257f47d61b0a F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 67c7c72e9bdf04c920d77006538a202c923fa74b47c81dc3014c2929dac7277d -R 94ab950169198f260c23800402fd70a5 +P a4540582b5b704af13b570b3dc609dbacada719302372a038cf74eee3688d5e7 +R b9f18dca12593a3b130cb73988b798a1 U drh -Z c0318b1fd81a3ec64d379bf447b9b4ea +Z c47bffdb8f799c234ea9ad61d838f43a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index db708de054..0839adf594 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch numeric-conversion-perf -tag numeric-conversion-perf +branch numeric-conversion +tag numeric-conversion diff --git a/manifest.uuid b/manifest.uuid index fe029aa3b9..5b11965ef0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a4540582b5b704af13b570b3dc609dbacada719302372a038cf74eee3688d5e7 +6b9ab641763bc1620a01beec71589506b3b0827bff1c6cd98a5d17c6070050b3 diff --git a/src/util.c b/src/util.c index bd60ec92e9..47d6dbee91 100644 --- a/src/util.c +++ b/src/util.c @@ -738,12 +738,9 @@ static double sqlite3Fp10Convert2(u64 d, int p){ int sqlite3AtoF(const char *z, double *pResult){ #ifndef SQLITE_OMIT_FLOATING_POINT /* sign * significand * (10 ^ (esign * exponent)) */ - int sign = 1; /* sign of significand */ - u64 s = 0; /* significand */ - int d = 0; /* adjust exponent for shifting decimal point */ - int esign = 1; /* sign of exponent */ - int e = 0; /* exponent */ - int eValid = 1; /* True exponent is either not used or is well-formed */ + int neg = 0; /* True for a negative value */ + u64 s = 0; /* mantissa */ + int d = 0; /* Value is s * pow(10,d) */ int nDigit = 0; /* Number of digits processed */ int eType = 1; /* 1: pure integer, 2+: fractional */ @@ -754,7 +751,7 @@ int sqlite3AtoF(const char *z, double *pResult){ /* get sign of significand */ if( *z=='-' ){ - sign = -1; + neg = 1; z++; }else if( *z=='+' ){ z++; @@ -789,8 +786,8 @@ int sqlite3AtoF(const char *z, double *pResult){ /* if exponent is present */ if( *z=='e' || *z=='E' ){ + int esign = 1; /* sign of exponent */ z++; - eValid = 0; eType++; /* get sign of exponent */ @@ -801,10 +798,16 @@ int sqlite3AtoF(const char *z, double *pResult){ z++; } /* copy digits to exponent */ - while( sqlite3Isdigit(*z) ){ - e = e<10000 ? (e*10 + (*z - '0')) : 10000; + if( sqlite3Isdigit(*z) ){ + int exp = *z - '0'; z++; - eValid = 1; + while( sqlite3Isdigit(*z) ){ + exp = exp<10000 ? (exp*10 + (*z - '0')) : 10000; + z++; + } + d += esign*exp; + }else{ + eType = -1; } } @@ -813,22 +816,17 @@ int sqlite3AtoF(const char *z, double *pResult){ /* Zero is a special case */ if( s==0 ){ - *pResult = sign<0 ? -0.0 : +0.0; - goto atofz_return; + *pResult = neg ? -0.0 : +0.0; + }else{ + *pResult = sqlite3Fp10Convert2(s,d); + if( neg ) *pResult = -*pResult; + assert( !sqlite3IsNaN(*pResult) ); } - /* adjust exponent by d, and update sign */ - e = (e*esign) + d; - - *pResult = sqlite3Fp10Convert2(s,e); - if( sign<0 ) *pResult = -*pResult; - assert( !sqlite3IsNaN(*pResult) ); - -atofz_return: /* return true if number and no extra non-whitespace characters after */ - if( z[0]==0 && nDigit>0 && eValid ){ + if( z[0]==0 && nDigit>0 ){ return eType; - }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ + }else if( eType>=2 && nDigit>0 ){ return -1; }else{ return 0; From 0b5e944480c7054582f4ebc7526c0bf2ab3f3a01 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 17 Feb 2026 00:37:12 +0000 Subject: [PATCH 021/197] Faster conversion of integers to text, by converting two digits at a time. FossilOrigin-Name: 90300e02f0de45b57d53976cae72928b3e56532d90b8b8cdc988e14762777930 --- manifest | 12 ++++---- manifest.uuid | 2 +- src/util.c | 81 ++++++++++++++++++++++++++++++--------------------- 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/manifest b/manifest index d472bbb667..204e1e699f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplifications\sto\ssqlite3AtoF(),\sresulting\sin\sslightly\sfaster\sperformance\nand\sslightly\ssmaller\ssize. -D 2026-02-16T23:52:51.130 +C Faster\sconversion\sof\sintegers\sto\stext,\sby\sconverting\stwo\sdigits\sat\sa\stime. +D 2026-02-17T00:37:12.629 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 06313141ca1d9cf6a80961a6a2084e1f682dfecc741b5c2f527f257f47d61b0a +F src/util.c a5d1c01e9ac773b2a783db45169fc7674ed2f6e05dadc88052702273ec94928c F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P a4540582b5b704af13b570b3dc609dbacada719302372a038cf74eee3688d5e7 -R b9f18dca12593a3b130cb73988b798a1 +P 6b9ab641763bc1620a01beec71589506b3b0827bff1c6cd98a5d17c6070050b3 +R 576ef9ddbda75f09f3eafbf37da65a3c U drh -Z c47bffdb8f799c234ea9ad61d838f43a +Z 308ac5fa17afdaa5c0816c0d53c230b6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5b11965ef0..586fb1f5fc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6b9ab641763bc1620a01beec71589506b3b0827bff1c6cd98a5d17c6070050b3 +90300e02f0de45b57d53976cae72928b3e56532d90b8b8cdc988e14762777930 diff --git a/src/util.c b/src/util.c index 47d6dbee91..4bed8dda8f 100644 --- a/src/util.c +++ b/src/util.c @@ -839,7 +839,25 @@ int sqlite3AtoF(const char *z, double *pResult){ #pragma warning(default : 4756) #endif - +/* +** Digit pairs used to convert a U64 or I64 into text, two digits +** at a time. +*/ +static const union { + char a[200]; + short int forceAlignment; +} sqlite3DigitPairs = { + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899" +}; /* @@ -853,23 +871,35 @@ int sqlite3AtoF(const char *z, double *pResult){ int sqlite3Int64ToText(i64 v, char *zOut){ int i; u64 x; - char zTemp[22]; - if( v<0 ){ - x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; - }else{ + union { + char a[23]; + u16 forceAlignment; + } u; + if( v>0 ){ x = v; + }else if( v==0 ){ + zOut[0] = '0'; + zOut[1] = 0; + return 1; + }else{ + x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; } - i = sizeof(zTemp)-2; - zTemp[sizeof(zTemp)-1] = 0; - while( 1 /*exit-by-break*/ ){ - zTemp[i] = (x%10) + '0'; - x = x/10; - if( x==0 ) break; - i--; - }; - if( v<0 ) zTemp[--i] = '-'; - memcpy(zOut, &zTemp[i], sizeof(zTemp)-i); - return sizeof(zTemp)-1-i; + i = sizeof(u.a)-1; + u.a[i] = 0; + while( x>=10 ){ + int kk = (x%100)*2; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) ); + assert( TWO_BYTE_ALIGNMENT(&u.a[i-2]) ); + *(u16*)(&u.a[i-2]) = *(u16*)&sqlite3DigitPairs.a[kk]; + i -= 2; + x /= 100; + } + if( x ){ + u.a[--i] = x + '0'; + } + if( v<0 ) u.a[--i] = '-'; + memcpy(zOut, &u.a[i], sizeof(u.a)-i); + return sizeof(u.a)-1-i; } /* @@ -1184,25 +1214,10 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ i = sizeof(p->zBuf)-1; assert( v>0 ); while( v>=10 ){ - static const union { - char a[200]; - short int forAlignment; - } dig = { - "00010203040506070809" - "10111213141516171819" - "20212223242526272829" - "30313233343536373839" - "40414243444546474849" - "50515253545556575859" - "60616263646566676869" - "70717273747576777879" - "80818283848586878889" - "90919293949596979899" - }; int kk = (v%100)*2; - assert( TWO_BYTE_ALIGNMENT(&dig.a[kk]) ); + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) ); assert( TWO_BYTE_ALIGNMENT(&p->zBuf[i-1]) ); - *(u16*)(&p->zBuf[i-1]) = *(u16*)&dig.a[kk]; + *(u16*)(&p->zBuf[i-1]) = *(u16*)&sqlite3DigitPairs.a[kk]; i -= 2; v /= 100; } From 530f536ce77d5eafe8e3d2ce4884b56450ee91ca Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 17 Feb 2026 11:28:48 +0000 Subject: [PATCH 022/197] New assert()s for the return value from sqlite3SchemaToIndex(). FossilOrigin-Name: 2610105a439e25c050b2deb32953861187c81b1d97407f41dc188e6627e0ac4d --- manifest | 13 ++++++------- manifest.uuid | 2 +- src/build.c | 3 +++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 0e327cf018..f9d8484609 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\ssimplifications,\sperformance\simprovements,\sand\ssize\sreductions\nto\sthe\snumeric\sto\stext\sconversion\slogic. -D 2026-02-17T01:04:23.976 +C New\sassert()s\sfor\sthe\sreturn\svalue\sfrom\ssqlite3SchemaToIndex(). +D 2026-02-17T11:28:48.505 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -681,7 +681,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea F src/btree.c b744bf69d520534751c742cababe7ad28c3892f1e3a75242e75a20bca15a834a F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0 F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886 -F src/build.c cc0afd3ec8417f5f774650f612e755b7ffce392d14ab4441bf5588867893fd3c +F src/build.c b993e4adef4c4cdfd7abf62e2676c467bb1923f25f40c3c7ab2a7bfbace3de7f F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e @@ -2194,9 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P e956b36063e77b5ad0d8b8afb5dc942665f570d762929ff277e320c06ded8ce6 90300e02f0de45b57d53976cae72928b3e56532d90b8b8cdc988e14762777930 -R b1ffbc813bb58c2693a15c98e01b4b2a -T +closed 90300e02f0de45b57d53976cae72928b3e56532d90b8b8cdc988e14762777930 +P dd5af703e1082951a4295a3453611db12b23cfbcfee4258ec3985abe96ab54ba +R 752a788ebe8252b2a0286d1bd66fa125 U drh -Z d14f3cc379cb89f415ec0148cadbccca +Z a9505c2d735590a5b6c9434f3d545798 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 23349f3fe2..1b5e4bffab 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dd5af703e1082951a4295a3453611db12b23cfbcfee4258ec3985abe96ab54ba +2610105a439e25c050b2deb32953861187c81b1d97407f41dc188e6627e0ac4d diff --git a/src/build.c b/src/build.c index 6b858ccac5..c451941451 100644 --- a/src/build.c +++ b/src/build.c @@ -486,6 +486,7 @@ Table *sqlite3LocateTableItem( const char *zDb; if( p->fg.fixedSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema); + assert( iDb>=0 && iDbdb->nDb ); zDb = pParse->db->aDb[iDb].zDbSName; }else{ assert( !p->fg.isSubquery ); @@ -2730,6 +2731,7 @@ void sqlite3EndTable( convertToWithoutRowidTable(pParse, p); } iDb = sqlite3SchemaToIndex(db, p->pSchema); + assert( iDb>=0 && iDb<=db->nDb ); #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. @@ -3025,6 +3027,7 @@ void sqlite3CreateView( sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); + assert( iDb>=0 && iDbnDb ); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; From 31d4e56b297266828938dffda1eff6575a5614e3 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 17 Feb 2026 12:23:12 +0000 Subject: [PATCH 023/197] Fix a harmless compiler warning from MSVC. FossilOrigin-Name: 12f3a6d0aaff8818c427d79e2b9394328625b3a60ccaa7b628d064084c65cfaf --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index f9d8484609..993d6a84c6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\sassert()s\sfor\sthe\sreturn\svalue\sfrom\ssqlite3SchemaToIndex(). -D 2026-02-17T11:28:48.505 +C Fix\sa\sharmless\scompiler\swarning\sfrom\sMSVC. +D 2026-02-17T12:23:12.724 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c a5d1c01e9ac773b2a783db45169fc7674ed2f6e05dadc88052702273ec94928c +F src/util.c 10572efe1bcf43fc2f6015cfba6126a4a5e32e7d6478a946a2b27d5ce189328b F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P dd5af703e1082951a4295a3453611db12b23cfbcfee4258ec3985abe96ab54ba -R 752a788ebe8252b2a0286d1bd66fa125 +P 2610105a439e25c050b2deb32953861187c81b1d97407f41dc188e6627e0ac4d +R 5886af748abe9a72a68682d3ad979bc9 U drh -Z a9505c2d735590a5b6c9434f3d545798 +Z 7efc95a8fc6e07536942a6656313d09e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1b5e4bffab..adb55eb16f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2610105a439e25c050b2deb32953861187c81b1d97407f41dc188e6627e0ac4d +12f3a6d0aaff8818c427d79e2b9394328625b3a60ccaa7b628d064084c65cfaf diff --git a/src/util.c b/src/util.c index 4bed8dda8f..ebd38705c2 100644 --- a/src/util.c +++ b/src/util.c @@ -844,7 +844,7 @@ int sqlite3AtoF(const char *z, double *pResult){ ** at a time. */ static const union { - char a[200]; + char a[201]; short int forceAlignment; } sqlite3DigitPairs = { "00010203040506070809" From 8c3e8dce41f1e14e41afd162f67c0ef8dcacb308 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 17 Feb 2026 14:02:27 +0000 Subject: [PATCH 024/197] Increase the number of floating-point precision test cases by 9x, and increase the require precision to 16 digits. FossilOrigin-Name: 62c2cf74db5e47f975d1f47818f82f060ddecad4b68c4d4dbc6190cc9a8fc397 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/fpconv1.test | 11 ++++++----- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 993d6a84c6..2d0d4dae16 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sharmless\scompiler\swarning\sfrom\sMSVC. -D 2026-02-17T12:23:12.724 +C Increase\sthe\snumber\sof\sfloating-point\sprecision\stest\scases\sby\s9x,\sand\nincrease\sthe\srequire\sprecision\sto\s16\sdigits. +D 2026-02-17T14:02:27.515 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -1130,7 +1130,7 @@ F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958 F test/fork-test.c 9ac2e6423a1d38df3d6be0e8ac15608b545de21e2b19d9d876254c5931b63edb F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4 F test/fp-speed-1.c b37de94eba034e1703668816225f54510ec60fb0685406608cc707afe6b8234d -F test/fpconv1.test d5d8aa0c427533006c112fb1957cdd1ea68c1d0709470dabb9ca02c2e4c06ad8 +F test/fpconv1.test ac9616f36ac8b8bc16b78f389978d8fb1420f53c1fc93d2793a9553ca2755f72 F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654 F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 2610105a439e25c050b2deb32953861187c81b1d97407f41dc188e6627e0ac4d -R 5886af748abe9a72a68682d3ad979bc9 +P 12f3a6d0aaff8818c427d79e2b9394328625b3a60ccaa7b628d064084c65cfaf +R bcf6cb540190f93195962d583ed6f2e0 U drh -Z 7efc95a8fc6e07536942a6656313d09e +Z 9f6a9fb600611e6d6cb6106d77d50061 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index adb55eb16f..df4ea7b5bf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -12f3a6d0aaff8818c427d79e2b9394328625b3a60ccaa7b628d064084c65cfaf +62c2cf74db5e47f975d1f47818f82f060ddecad4b68c4d4dbc6190cc9a8fc397 diff --git a/test/fpconv1.test b/test/fpconv1.test index 195fdf9904..7b052d78b2 100644 --- a/test/fpconv1.test +++ b/test/fpconv1.test @@ -26,19 +26,20 @@ sqlite3_create_function db do_execsql_test fpconv1-1.0 { WITH RECURSIVE /* Number of random floating-point values to try. - ** On a circa 2016 x64 linux box, this test runs at - ** about 80000 cases per second -------------------vvvvvv */ - c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100000), + ** On a circa 2021 Ryzen 5950X running Mint Linux, and + ** compiled with -O0 -DSQLITE_DEBUG, this test runs at + ** about 150000 cases per second ------------------vvvvvv */ + c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<900000), fp(y) AS MATERIALIZED ( SELECT CAST( format('%+d.%019d0e%+03d', random()%10,abs(random()),random()%200) AS real) FROM c ) SELECT y FROM fp - WHERE -log10(abs(decimal_sub(dtostr(y,24),format('%!.24e',y))/y))<15.0; + WHERE -log10(abs(decimal_sub(dtostr(y,24),format('%!.24e',y))/y))<16.0; /* Number of digits of accuracy required -------^^^^ */ } {} # ^---- Expect a empty set as the result. The output is all tested numbers -# that fail to preserve at least 15 significant digits of accuracy. +# that fail to preserve at least 16 significant digits of accuracy. finish_test From 7549e784a8d6831dfff0c3b944a653cf8c92584f Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 17 Feb 2026 14:28:18 +0000 Subject: [PATCH 025/197] Minor fixes to tmstmpvfs.c. FossilOrigin-Name: 091bd90ed5a6a326fd532e93bd17903e052476da14dc6aee2599a9acf75a3276 --- ext/misc/tmstmpvfs.c | 12 ++++++++---- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index da67a20772..6f1af36f74 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -484,6 +484,7 @@ static void tmstmpPutU32(u32 v, unsigned char *a){ /* Free a TmstmpLog object */ static void tmstmpLogFree(TmstmpLog *pLog){ if( pLog==0 ) return; + if( pLog->log ) fclose(pLog->log); sqlite3_free(pLog->zLogname); sqlite3_free(pLog); } @@ -502,6 +503,7 @@ static int tmstmpLogFlush(TmstmpFile *p){ } } (void)fwrite(pLog->a, pLog->n, 1, pLog->log); + fflush(pLog->log); pLog->n = 0; return 0; } @@ -619,7 +621,7 @@ static int tmstmpWrite( u32 x = 0; p->iFrame = (iOfst - 32)/(p->pgsz+24)+1; p->pgno = tmstmpGetU32((const u8*)zBuf); - p->salt1 = tmstmpGetU32(((const u8*)zBuf)+16); + p->salt1 = tmstmpGetU32(((const u8*)zBuf)+8); memcpy(&x, ((const u8*)zBuf)+4, 4); p->isCommit = (x!=0); p->iOfst = iOfst; @@ -637,7 +639,7 @@ static int tmstmpWrite( memset(s, 0, TMSTMP_RESERVE); tmstmpPutTS(p, s+2); tmstmpPutU32(p->iFrame, s+8); - tmstmpPutU32(p->pPartner->salt1, s+12); + tmstmpPutU32(p->pPartner->salt1 & 0xffffff, s+12); assert( p->pgsz>0 ); tmstmpEvent(p, ELOG_CKPT_PAGE, 0, (iOfst/p->pgsz)+1, p->iFrame, 0); }else if( p->pPartner==0 ){ @@ -647,7 +649,7 @@ static int tmstmpWrite( tmstmpPutTS(p, s+2); s[12] = 2; assert( p->pgsz>0 ); - tmstmpEvent(p, ELOG_DB_PAGE, 0, (u32)(iOfst/p->pgsz), 0, s+2); + tmstmpEvent(p, ELOG_DB_PAGE, 0, (u32)(iOfst/p->pgsz)+1, 0, s+2); } return pSub->pMethods->xWrite(pSub,zBuf,iAmt,iOfst); } @@ -879,7 +881,9 @@ static int tmstmpOpen( r1 = 0; pLog = sqlite3_malloc64( sizeof(TmstmpLog) ); if( pLog==0 ){ - return SQLITE_NOMEM; + pSubFile->pMethods->xClose(pSubFile); + rc = SQLITE_NOMEM; + goto tmstmp_open_done; } memset(pLog, 0, sizeof(pLog[0])); p->pLog = pLog; diff --git a/manifest b/manifest index 2d0d4dae16..2c0f15fe61 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Increase\sthe\snumber\sof\sfloating-point\sprecision\stest\scases\sby\s9x,\sand\nincrease\sthe\srequire\sprecision\sto\s16\sdigits. -D 2026-02-17T14:02:27.515 +C Minor\sfixes\sto\stmstmpvfs.c. +D 2026-02-17T14:28:18.685 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -403,7 +403,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c 3eb28a9f22f58883f38085daa312467e31ddfd2042c21dcc07173e02a01d68d8 +F ext/misc/tmstmpvfs.c 240caad4441328dc52bd2871f48811db46dff858d5598030e389176837a2f4df F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 12f3a6d0aaff8818c427d79e2b9394328625b3a60ccaa7b628d064084c65cfaf -R bcf6cb540190f93195962d583ed6f2e0 +P 62c2cf74db5e47f975d1f47818f82f060ddecad4b68c4d4dbc6190cc9a8fc397 +R bae7bcc1d98d32b5cc1ad4c718984cec U drh -Z 9f6a9fb600611e6d6cb6106d77d50061 +Z b56da0878ac4e43a938e2a3c2eed45b5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index df4ea7b5bf..10cc6fb188 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -62c2cf74db5e47f975d1f47818f82f060ddecad4b68c4d4dbc6190cc9a8fc397 +091bd90ed5a6a326fd532e93bd17903e052476da14dc6aee2599a9acf75a3276 From 37ee141d25f43c9d7f7f20e3ae44d9265edc4419 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 17 Feb 2026 20:28:25 +0000 Subject: [PATCH 026/197] Restore the CLI function dtostr() back to its original purpose of converting floating point values to decimal using the host computer's C-library. FossilOrigin-Name: f3cc05ba7fa9cb77573de5cd28ab90f10844567692ed57a706c5dc35b1348009 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 2c0f15fe61..dd756e1ee4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sfixes\sto\stmstmpvfs.c. -D 2026-02-17T14:28:18.685 +C Restore\sthe\sCLI\sfunction\sdtostr()\sback\sto\sits\soriginal\spurpose\sof\sconverting\nfloating\spoint\svalues\sto\sdecimal\susing\sthe\shost\scomputer's\sC-library. +D 2026-02-17T20:28:25.509 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -739,7 +739,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c -F src/shell.c.in b944a21d98cc4c6107bfd1ec702440579cb4bf86435125b67ff661180e9453b5 +F src/shell.c.in d7fbdf03b3592af0b5480d8e3e274add46cb50b8263d2a3156e04157ebdb7694 F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 62c2cf74db5e47f975d1f47818f82f060ddecad4b68c4d4dbc6190cc9a8fc397 -R bae7bcc1d98d32b5cc1ad4c718984cec +P 091bd90ed5a6a326fd532e93bd17903e052476da14dc6aee2599a9acf75a3276 +R cd671e340350caab6a75edc7dcce7710 U drh -Z b56da0878ac4e43a938e2a3c2eed45b5 +Z af08287ac982b3bc21237452366bd06d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 10cc6fb188..339f48cea9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -091bd90ed5a6a326fd532e93bd17903e052476da14dc6aee2599a9acf75a3276 +f3cc05ba7fa9cb77573de5cd28ab90f10844567692ed57a706c5dc35b1348009 diff --git a/src/shell.c.in b/src/shell.c.in index a9c88e7688..52b08647de 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -931,7 +931,7 @@ static void shellDtostr( char z[400]; if( n<1 ) n = 1; if( n>350 ) n = 350; - sqlite3_snprintf(sizeof(z), z, "%#+.*e", n, r); + sprintf(z, "%#+.*e", n, r); sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); } From cac09127e16bb61b13cb547806b96507707e4cf4 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 19 Feb 2026 12:59:42 +0000 Subject: [PATCH 027/197] Improvements to rounding behavior in the new floating-point conversion logic. FossilOrigin-Name: e540f6c370675ae043af8cdbb80f7eb17c08e50f7634e0b78f0b1dccf7bd4b18 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 13 ++++++------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index dd756e1ee4..80396f18d7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Restore\sthe\sCLI\sfunction\sdtostr()\sback\sto\sits\soriginal\spurpose\sof\sconverting\nfloating\spoint\svalues\sto\sdecimal\susing\sthe\shost\scomputer's\sC-library. -D 2026-02-17T20:28:25.509 +C Improvements\sto\srounding\sbehavior\sin\sthe\snew\sfloating-point\sconversion\slogic. +D 2026-02-19T12:59:42.005 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 10572efe1bcf43fc2f6015cfba6126a4a5e32e7d6478a946a2b27d5ce189328b +F src/util.c 72874125f70f61082bfb82b4580c1a320ab22b8cded2fb98e42ab98b39dc7bf1 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 091bd90ed5a6a326fd532e93bd17903e052476da14dc6aee2599a9acf75a3276 -R cd671e340350caab6a75edc7dcce7710 +P f3cc05ba7fa9cb77573de5cd28ab90f10844567692ed57a706c5dc35b1348009 +R c76121d106ccfa4ba10f05ce6b9cda5e U drh -Z af08287ac982b3bc21237452366bd06d +Z d2d61bfcd3046306c59cf37d2f198b36 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 339f48cea9..c26f9fb5b4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f3cc05ba7fa9cb77573de5cd28ab90f10844567692ed57a706c5dc35b1348009 +e540f6c370675ae043af8cdbb80f7eb17c08e50f7634e0b78f0b1dccf7bd4b18 diff --git a/src/util.c b/src/util.c index ebd38705c2..048db497c2 100644 --- a/src/util.c +++ b/src/util.c @@ -648,13 +648,12 @@ static int countLeadingZeros(u64 m){ */ static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){ int p; - u64 h, out; + u64 h; p = n - 1 - pwr2to10(e+63); h = sqlite3Multiply128(m, powerOfTen(p)); - assert( -(e + pwr10to2(p) + 3) >=0 ); - assert( -(e + pwr10to2(p) + 3) <64 ); - out = h >> -(e + pwr10to2(p) + 3); - *pD = (out + 2 + ((out>>2)&1)) >> 2; + assert( -(e + pwr10to2(p) + 1) >=0 ); + assert( -(e + pwr10to2(p) + 1) <64 ); + *pD = h >> -(e + pwr10to2(p) + 1); *pP = -p; } @@ -1156,7 +1155,7 @@ int sqlite3Atoi(const char *z){ ** representation. ** ** If iRound<=0 then round to -iRound significant digits to the -** the left of the decimal point, or to a maximum of mxRound total +** the right of the decimal point, or to a maximum of mxRound total ** significant digits. ** ** If iRound>0 round to min(iRound,mxRound) significant digits total. @@ -1208,7 +1207,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ v = (v<<11) | U64_BIT(63); e -= 1086; } - sqlite3Fp2Convert10(v, e, 17, &v, &exp); + sqlite3Fp2Convert10(v, e, (iRound<=0||iRound>=18)?18:iRound+1, &v, &exp); /* Extract significant digits. */ i = sizeof(p->zBuf)-1; From e8750019c25c3032d466f92808ea96ba7d9e4c22 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 19 Feb 2026 17:20:40 +0000 Subject: [PATCH 028/197] In the CLI, the ".quit" command in a --cmd argument causes an immediate exit. [forum:/forumpost/f057122b68|Forum post f057122b68]. FossilOrigin-Name: 4731cc8856aa4dcfad5db501648bfd0afef43d8c5f339e7b11a1e3ee64348b87 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 80396f18d7..82b1ef8977 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\srounding\sbehavior\sin\sthe\snew\sfloating-point\sconversion\slogic. -D 2026-02-19T12:59:42.005 +C In\sthe\sCLI,\sthe\s".quit"\scommand\sin\sa\s--cmd\sargument\scauses\san\simmediate\nexit.\s\s[forum:/forumpost/f057122b68|Forum\spost\sf057122b68]. +D 2026-02-19T17:20:40.116 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -739,7 +739,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c -F src/shell.c.in d7fbdf03b3592af0b5480d8e3e274add46cb50b8263d2a3156e04157ebdb7694 +F src/shell.c.in 15285c21cc3f1da9289b0b6c5fd0b2ca8ab2e664b4b300c404afe7634ce9876f F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f3cc05ba7fa9cb77573de5cd28ab90f10844567692ed57a706c5dc35b1348009 -R c76121d106ccfa4ba10f05ce6b9cda5e +P e540f6c370675ae043af8cdbb80f7eb17c08e50f7634e0b78f0b1dccf7bd4b18 +R e8a52a3904398a00cac725666cd6d19d U drh -Z d2d61bfcd3046306c59cf37d2f198b36 +Z ee96430e99114f754ef74526e72d7a91 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c26f9fb5b4..fd6ff32707 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e540f6c370675ae043af8cdbb80f7eb17c08e50f7634e0b78f0b1dccf7bd4b18 +4731cc8856aa4dcfad5db501648bfd0afef43d8c5f339e7b11a1e3ee64348b87 diff --git a/src/shell.c.in b/src/shell.c.in index 52b08647de..05d5831201 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -13346,7 +13346,7 @@ int SQLITE_CDECL main(int argc, char **argv){ z = cmdline_option_value(argc,argv,++i); if( z[0]=='.' ){ rc = do_meta_command(z, &data); - if( rc && bail_on_error ){ + if( rc && (bail_on_error || rc==2) ){ if( rc==2 ) rc = 0; goto shell_main_exit; } From 20c65785cdb9476469bf51cdede0f420249c017b Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 20 Feb 2026 12:27:52 +0000 Subject: [PATCH 029/197] Improved rounding of floating-point conversions in some corner cases. FossilOrigin-Name: 436dccd42650a6ab0a74459ae42fdb3e36d853f934324acc2bc961f87c001852 --- manifest | 13 +++++++------ manifest.uuid | 2 +- src/util.c | 12 +++++++++--- test/atof2.test | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 test/atof2.test diff --git a/manifest b/manifest index 82b1ef8977..b48850df5e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sCLI,\sthe\s".quit"\scommand\sin\sa\s--cmd\sargument\scauses\san\simmediate\nexit.\s\s[forum:/forumpost/f057122b68|Forum\spost\sf057122b68]. -D 2026-02-19T17:20:40.116 +C Improved\srounding\sof\sfloating-point\sconversions\sin\ssome\scorner\scases. +D 2026-02-20T12:27:52.339 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 72874125f70f61082bfb82b4580c1a320ab22b8cded2fb98e42ab98b39dc7bf1 +F src/util.c 43dce657e603820a31f196c703eb2213e10ef0c35b7960ac82312784294b6e4a F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -872,6 +872,7 @@ F test/analyzeF.test 40b5cc3ad7b10e81020d7ca86f1417647ecfae7477cfd88acc5aa7ae106 F test/analyzeG.test 623be33038c49648872746c8dd8b23b5792c08fef173c55e82f1b12fca259852 F test/analyzer1.test b6a624ec0af92eec209e1328465b66937c8fdf2fb442a3fa45321ddb3700f4aa F test/atof1.test bd21c4a0e718ab1470de07a2a79f2544d7903be34feebcc80de04beee4807b00 +F test/atof2.test 12912add57230495450e2fc94cb8ad1c9f3277f8843a3bc27079cae45c9782a1 F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061 F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da F test/atrc.c c388fac43dbba05c804432a7135ae688b32e8f25818e9994ffba4b64cf60c27c @@ -2194,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P e540f6c370675ae043af8cdbb80f7eb17c08e50f7634e0b78f0b1dccf7bd4b18 -R e8a52a3904398a00cac725666cd6d19d +P 4731cc8856aa4dcfad5db501648bfd0afef43d8c5f339e7b11a1e3ee64348b87 +R f79214badaf5b7fbc5067c602383d74f U drh -Z ee96430e99114f754ef74526e72d7a91 +Z d75fc23742e879c6b1e0a5a3257032f9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fd6ff32707..d8385da970 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4731cc8856aa4dcfad5db501648bfd0afef43d8c5f339e7b11a1e3ee64348b87 +436dccd42650a6ab0a74459ae42fdb3e36d853f934324acc2bc961f87c001852 diff --git a/src/util.c b/src/util.c index 048db497c2..e2c54a35db 100644 --- a/src/util.c +++ b/src/util.c @@ -649,11 +649,17 @@ static int countLeadingZeros(u64 m){ static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){ int p; u64 h; + assert( n>=1 && n<=18 ); p = n - 1 - pwr2to10(e+63); h = sqlite3Multiply128(m, powerOfTen(p)); - assert( -(e + pwr10to2(p) + 1) >=0 ); - assert( -(e + pwr10to2(p) + 1) <64 ); - *pD = h >> -(e + pwr10to2(p) + 1); + assert( -(e + pwr10to2(p) + 2) >= 0 ); + assert( -(e + pwr10to2(p) + 1) <= 63 ); + if( n==18 ){ + h >>= -(e + pwr10to2(p) + 2); + *pD = (h + ((h<<1)&2))>>1; + }else{ + *pD = h >> -(e + pwr10to2(p) + 1); + } *pP = -p; } diff --git a/test/atof2.test b/test/atof2.test new file mode 100644 index 0000000000..5a68d1352b --- /dev/null +++ b/test/atof2.test @@ -0,0 +1,35 @@ +# 2026-02-20 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Tests of the sqlite3AtoF() function. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Rounding cases: +# +do_execsql_test atof2-1.0 { + SELECT format('%g',192.496475); +} 192.496 +do_execsql_test atof2-1.1 { + SELECT format('%g',192.496501); +} 192.497 + +load_static_extension db ieee754 +do_execsql_test atof2-2.1 { + SELECT format('%!.30f',ieee754_inc(100.0,-1)); +} 99.9999999999999858 +do_execsql_test atof2-2.2 { + SELECT format('%!.30f',ieee754_inc(100.0,-2)); +} 99.9999999999999716 + +finish_test From d447df420582b289ae32ec5880e0e5e5e3ee3b06 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 20 Feb 2026 14:20:33 +0000 Subject: [PATCH 030/197] Add new functions ieee754_to_int() and ieee754_from_int() to the ieee754 extension. No changes to the core SQLite. FossilOrigin-Name: 8660d3e94cbe892693554df282bce0fa8c7aedbc5e020cab647cbbff3d7e55b7 --- ext/misc/ieee754.c | 34 ++++++++++++++++++++++++++++++++++ manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/ext/misc/ieee754.c b/ext/misc/ieee754.c index 932b1c278c..f551b2265a 100644 --- a/ext/misc/ieee754.c +++ b/ext/misc/ieee754.c @@ -259,6 +259,38 @@ static void ieee754func_to_blob( } } +/* +** Functions to convert between 64-bit integers and floats. +** +** The bit patterns are copied. The numeric values are different. +*/ +static void ieee754func_from_int( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + UNUSED_PARAMETER(argc); + if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){ + double r; + sqlite3_int64 v = sqlite3_value_int64(argv[0]); + memcpy(&r, &v, sizeof(r)); + sqlite3_result_double(context, r); + } +} +static void ieee754func_to_int( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + UNUSED_PARAMETER(argc); + if( sqlite3_value_type(argv[0])==SQLITE_FLOAT ){ + double r = sqlite3_value_double(argv[0]); + sqlite3_uint64 v; + memcpy(&v, &r, sizeof(v)); + sqlite3_result_int64(context, v); + } +} + /* ** SQL Function: ieee754_inc(r,N) ** @@ -311,6 +343,8 @@ int sqlite3_ieee_init( { "ieee754_exponent", 1, 2, ieee754func }, { "ieee754_to_blob", 1, 0, ieee754func_to_blob }, { "ieee754_from_blob", 1, 0, ieee754func_from_blob }, + { "ieee754_to_int", 1, 0, ieee754func_to_int }, + { "ieee754_from_int", 1, 0, ieee754func_from_int }, { "ieee754_inc", 2, 0, ieee754inc }, }; unsigned int i; diff --git a/manifest b/manifest index b48850df5e..e0e6f9e434 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\srounding\sof\sfloating-point\sconversions\sin\ssome\scorner\scases. -D 2026-02-20T12:27:52.339 +C Add\snew\sfunctions\sieee754_to_int()\sand\sieee754_from_int()\sto\sthe\nieee754\sextension.\s\sNo\schanges\sto\sthe\score\sSQLite. +D 2026-02-20T14:20:33.971 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -376,7 +376,7 @@ F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a562918 F ext/misc/fileio.c 452300ca34fadafd2bb9eb09557de5a518da1fd2349f9f9cedd22b1566a7164f F ext/misc/fossildelta.c 86dfa83f85f7ccd640591d8a5c6865346d0c2ee6a949d78591eceb892f1cbfec F ext/misc/fuzzer.c 6b231352815304ba60d8e9ec2ee73d4918e74d9b76bda8940ba2b64e8777515e -F ext/misc/ieee754.c 7d7ecdd9490f6746ad88e0aa4f073ea66422341dce062d24d1b4d47d2e9050d6 +F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b F ext/misc/memstat.c 43705d795090efb78c85c736b89251e743c291e23daaa8382fe7a0df2c6a283d F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b F ext/misc/mmapwarm.c a81af4aaec00f24f308e2f4c19bf1d88f3ac3ce848c36daa7a4cd38145c4080d @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 4731cc8856aa4dcfad5db501648bfd0afef43d8c5f339e7b11a1e3ee64348b87 -R f79214badaf5b7fbc5067c602383d74f +P 436dccd42650a6ab0a74459ae42fdb3e36d853f934324acc2bc961f87c001852 +R 2afe772fbea1438e3a27c2459d477b85 U drh -Z d75fc23742e879c6b1e0a5a3257032f9 +Z 182dac5ab39ffff0cbe6eba3144bb514 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d8385da970..c194933323 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -436dccd42650a6ab0a74459ae42fdb3e36d853f934324acc2bc961f87c001852 +8660d3e94cbe892693554df282bce0fa8c7aedbc5e020cab647cbbff3d7e55b7 From 9e395efec686281ca453ba2be80507bdef47e36e Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 20 Feb 2026 14:22:09 +0000 Subject: [PATCH 031/197] Fix a cse in the fiddle.debug build where it could not overwrite its read-only/generated index.html. FossilOrigin-Name: 7adb2c0f438a97d377760436b1ac81fffab36e541a2b5ee733bfc7108e0180e5 --- ext/wasm/GNUmakefile | 2 +- ext/wasm/mkwasmbuilds.c | 11 +++++++++-- manifest | 16 ++++++++-------- manifest.uuid | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index 4302647609..dc3c2d2555 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -206,7 +206,7 @@ b.mkdir@ = if [ ! -d $(dir $@) ]; then \ # $1 = logtag, $2 = src file(s). $3 = dest dir b.cp = $(call b.mkdir@); \ echo '$(logtag.$(1)) $(emo.disk) $(2) ==> $3'; \ - cp -p $(2) $(3) || exit + cp -f -p $(2) $(3) || exit # # $(call b.c-pp.shcmd,LOGTAG,src,dest,-Dx=y...) diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c index 1b8b3d02ba..37f2967d88 100644 --- a/ext/wasm/mkwasmbuilds.c +++ b/ext/wasm/mkwasmbuilds.c @@ -994,10 +994,17 @@ static void mk_fiddle(void){ pf("$(out.%s.js): $(MAKEFILE_LIST) " "$(EXPORTED_FUNCTIONS.fiddle) " "$(fiddle.c.in) " - "$(pre-post.%s.deps)\n", + "$(pre-post.%s.deps)", zBuildName, zBuildName); + if( isDebug ){ + pf(" $(dir.fiddle)/fiddle-worker.js" + " $(dir.fiddle)/fiddle.js" + " $(dir.fiddle)/index.html"); + } + ps(""); emit_compile_start(zBuildName); - pf("\t$(b.cmd@)$(bin.emcc) -o $@" + pf("\t@$(call b.mkdir@)\n" + "\t$(b.cmd@)$(bin.emcc) -o $@" " $(emcc.flags.%s)" /* set in GNUmakefile */ " $(pre-post.%s.flags)" " $(fiddle.c.in)" diff --git a/manifest b/manifest index e0e6f9e434..d1d740ff1c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\snew\sfunctions\sieee754_to_int()\sand\sieee754_from_int()\sto\sthe\nieee754\sextension.\s\sNo\schanges\sto\sthe\score\sSQLite. -D 2026-02-20T14:20:33.971 +C Fix\sa\scse\sin\sthe\sfiddle.debug\sbuild\swhere\sit\scould\snot\soverwrite\sits\sread-only/generated\sindex.html. +D 2026-02-20T14:22:09.912 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -581,7 +581,7 @@ F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009e F ext/session/sqlite3session.c 6ebd02be470f36d41c4bd78927f39d507b62051ba025eacaed9936c769902a07 F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a F ext/session/test_session.c 190110e3bd9463717248dec1272b44fe9943e57b7646d0b4200dcf11e4dccee6 -F ext/wasm/GNUmakefile a2698072853b67c39e92ca19835c65fbaa8b8884078a99c4e54b72b9ede8306e +F ext/wasm/GNUmakefile 79236447d750609aa6beda30feec1314180c5462a493ad94214122887232bfd4 F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259 F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff @@ -634,7 +634,7 @@ F ext/wasm/index.html 475bc283338749db4e3fbf24cf3f5aa020cc85a1fffb780d400a915fcb F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b F ext/wasm/jaccwabyt/jaccwabyt.md 6aa90fa1a973d0ad10d077088bea163b241d8470c75eafdef87620a1de1dea41 F ext/wasm/mkdist.sh f8883b077a2ca47cf92e6f0ce305fbf72ca648c3501810125056c4b09c2d5554 x -F ext/wasm/mkwasmbuilds.c 5d7baa9258299fd492351578a93dff960317822a08ee3ad6dd91ef5d21209812 +F ext/wasm/mkwasmbuilds.c 0e9198eb90acae4bcf57cf62d7186f6af5aaac02efdb075a1aded33614b3805a F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2 F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96 F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 436dccd42650a6ab0a74459ae42fdb3e36d853f934324acc2bc961f87c001852 -R 2afe772fbea1438e3a27c2459d477b85 -U drh -Z 182dac5ab39ffff0cbe6eba3144bb514 +P 8660d3e94cbe892693554df282bce0fa8c7aedbc5e020cab647cbbff3d7e55b7 +R 389af95283f5ab275172b5b1245f2df2 +U stephan +Z 85bcd6f2a42107fa459e33d70b89b165 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c194933323..b83452454a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8660d3e94cbe892693554df282bce0fa8c7aedbc5e020cab647cbbff3d7e55b7 +7adb2c0f438a97d377760436b1ac81fffab36e541a2b5ee733bfc7108e0180e5 From 62546d4b1ff9211ccff922f622ee73871b1ed2b0 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 20 Feb 2026 16:21:58 +0000 Subject: [PATCH 032/197] In the decimal extension, an optional second argument to the decimal() and decimal_exp() functions rounds the value to the number of significant digits specified by that argument. FossilOrigin-Name: cb24edf1afc3f9083a4963c5fe232933eccc7c0cb8872aa5fcd336d226b885ef --- ext/misc/decimal.c | 44 +++++++++++++++++++++++++++++++++++++++----- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c index f87699f96b..ac9c7c7e5e 100644 --- a/ext/misc/decimal.c +++ b/ext/misc/decimal.c @@ -291,12 +291,36 @@ static void decimal_result(sqlite3_context *pCtx, Decimal *p){ sqlite3_result_text(pCtx, z, i, sqlite3_free); } +/* +** Round a decimal value to N significant digits. N must be positive. +*/ +static void decimal_round(Decimal *p, int N){ + int i; + int nZero; + if( N<1 ) return; + for(nZero=0; nZeronDigit && p->a[nZero]==0; nZero++){} + N += nZero; + if( p->nDigit<=N ) return; + if( p->a[N]>4 ){ + p->a[N-1]++; + for(i=N-1; i>0 && p->a[i]>9; i--){ + p->a[i] = 0; + p->a[i-1]++; + } + if( p->a[0]>9 ){ + p->a[0] = 1; + p->nFrac--; + } + } + memset(&p->a[N], 0, p->nDigit - N); +} + /* ** Make the given Decimal the result in an format similar to '%+#e'. ** In other words, show exponential notation with leading and trailing ** zeros omitted. */ -static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p){ +static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){ char *z; /* The output buffer */ int i; /* Loop counter */ int nZero; /* Number of leading zeros */ @@ -314,8 +338,10 @@ static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p){ sqlite3_result_null(pCtx); return; } - for(nDigit=p->nDigit; nDigit>0 && p->a[nDigit-1]==0; nDigit--){} + if( N<1 ) N = 0; + for(nDigit=p->nDigit; nDigit>N && p->a[nDigit-1]==0; nDigit--){} for(nZero=0; nZeroa[nZero]==0; nZero++){} + N += nZero; nFrac = p->nFrac + (nDigit - p->nDigit); nDigit -= nZero; z = sqlite3_malloc64( (sqlite3_int64)nDigit+20 ); @@ -677,10 +703,16 @@ static void decimalFunc( sqlite3_value **argv ){ Decimal *p = decimal_new(context, argv[0], 0); - UNUSED_PARAMETER(argc); + int N; + if( argc==2 ){ + N = sqlite3_value_int(argv[1]); + if( N>0 ) decimal_round(p, N); + }else{ + N = 0; + } if( p ){ if( sqlite3_user_data(context)!=0 ){ - decimal_result_sci(context, p); + decimal_result_sci(context, p, N); }else{ decimal_result(context, p); } @@ -850,7 +882,7 @@ static void decimalPow2Func( UNUSED_PARAMETER(argc); if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){ Decimal *pA = decimalPow2(sqlite3_value_int(argv[0])); - decimal_result_sci(context, pA); + decimal_result_sci(context, pA, 0); decimal_free(pA); } } @@ -871,7 +903,9 @@ int sqlite3_decimal_init( void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } aFunc[] = { { "decimal", 1, 0, decimalFunc }, + { "decimal", 2, 0, decimalFunc }, { "decimal_exp", 1, 1, decimalFunc }, + { "decimal_exp", 2, 1, decimalFunc }, { "decimal_cmp", 2, 0, decimalCmpFunc }, { "decimal_add", 2, 0, decimalAddFunc }, { "decimal_sub", 2, 0, decimalSubFunc }, diff --git a/manifest b/manifest index d1d740ff1c..257c23a120 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\scse\sin\sthe\sfiddle.debug\sbuild\swhere\sit\scould\snot\soverwrite\sits\sread-only/generated\sindex.html. -D 2026-02-20T14:22:09.912 +C In\sthe\sdecimal\sextension,\san\soptional\ssecond\sargument\sto\sthe\ndecimal()\sand\sdecimal_exp()\sfunctions\srounds\sthe\svalue\sto\sthe\nnumber\sof\ssignificant\sdigits\sspecified\sby\sthat\sargument. +D 2026-02-20T16:21:58.730 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -370,7 +370,7 @@ F ext/misc/completion.c c27b64fdd0943c1b7f152376599814cee2641f7d67a7bb9bd2b957c2 F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565 F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680 -F ext/misc/decimal.c d4883de142f6dcd36eda23da40b55e2b51374e7b01eb54a7173940191389fc5e +F ext/misc/decimal.c 38aa18b29e96c745c78725ef3740a53f4b2b8cdfa226dfab13aaf2168a071db7 F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b F ext/misc/fileio.c 452300ca34fadafd2bb9eb09557de5a518da1fd2349f9f9cedd22b1566a7164f @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 8660d3e94cbe892693554df282bce0fa8c7aedbc5e020cab647cbbff3d7e55b7 -R 389af95283f5ab275172b5b1245f2df2 -U stephan -Z 85bcd6f2a42107fa459e33d70b89b165 +P 7adb2c0f438a97d377760436b1ac81fffab36e541a2b5ee733bfc7108e0180e5 +R d3925fd721dfabc8744fb8ec5748bbad +U drh +Z a53353c83d76fce8dcafd070d72a5289 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b83452454a..02ddfbd494 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7adb2c0f438a97d377760436b1ac81fffab36e541a2b5ee733bfc7108e0180e5 +cb24edf1afc3f9083a4963c5fe232933eccc7c0cb8872aa5fcd336d226b885ef From ac5ee556eb5b211c4acdfc7f71385d0dc678df31 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 20 Feb 2026 20:43:25 +0000 Subject: [PATCH 033/197] Inconsequential changes to floating-point conversion, amounting to mere code cleanup to aid comprehension. FossilOrigin-Name: 6d9c29123b6b143b0f7c8f5d018f170c72edfc5b1a4d67edd45e5552def2af6c --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/printf.c | 2 +- src/sqliteInt.h | 6 +++--- src/util.c | 1 + 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 257c23a120..30469cdd11 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sdecimal\sextension,\san\soptional\ssecond\sargument\sto\sthe\ndecimal()\sand\sdecimal_exp()\sfunctions\srounds\sthe\svalue\sto\sthe\nnumber\sof\ssignificant\sdigits\sspecified\sby\sthat\sargument. -D 2026-02-20T16:21:58.730 +C Inconsequential\schanges\sto\sfloating-point\sconversion,\samounting\sto\smere\ncode\scleanup\sto\said\scomprehension. +D 2026-02-20T20:43:25.912 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -734,7 +734,7 @@ F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d -F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded +F src/printf.c 9cff219dba73b1aa9a8113e83e962f03f7bea8b6eb51cefb25bc468d5a69fb2d F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 @@ -743,7 +743,7 @@ F src/shell.c.in 15285c21cc3f1da9289b0b6c5fd0b2ca8ab2e664b4b300c404afe7634ce9876 F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h cd77fd03f7bf9d7b012a28c96cacdd20f09054bfe4edcebd92f789f0bc37c9fb +F src/sqliteInt.h 347722b895995dc3015147150c1f9fed5224748c26b36d69ef405656d1603100 F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 43dce657e603820a31f196c703eb2213e10ef0c35b7960ac82312784294b6e4a +F src/util.c 64c047521e35adc402e6f2a8dcd20732392c02641418becfc4387a1c02f5e042 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 7adb2c0f438a97d377760436b1ac81fffab36e541a2b5ee733bfc7108e0180e5 -R d3925fd721dfabc8744fb8ec5748bbad +P cb24edf1afc3f9083a4963c5fe232933eccc7c0cb8872aa5fcd336d226b885ef +R 5dc7d1cf9df5b4fd3583425b84bcab00 U drh -Z a53353c83d76fce8dcafd070d72a5289 +Z a28f337e825428b6e4dfea35f10cb54e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 02ddfbd494..f7d89da182 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cb24edf1afc3f9083a4963c5fe232933eccc7c0cb8872aa5fcd336d226b885ef +6d9c29123b6b143b0f7c8f5d018f170c72edfc5b1a4d67edd45e5552def2af6c diff --git a/src/printf.c b/src/printf.c index 29b0ce37d6..d9f3c229dd 100644 --- a/src/printf.c +++ b/src/printf.c @@ -549,7 +549,7 @@ void sqlite3_str_vappendf( }else{ iRound = precision+1; } - sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16); + sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 20 : 16); if( s.isSpecial ){ if( s.isSpecial==2 ){ bufpt = flag_zeropad ? "null" : "NaN"; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 27d436c4ba..8ccb079096 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4820,12 +4820,12 @@ struct PrintfArguments { ** value into an approximate decimal representation. */ struct FpDecode { - char sign; /* '+' or '-' */ - char isSpecial; /* 1: Infinity 2: NaN */ int n; /* Significant digits in the decode */ int iDP; /* Location of the decimal point */ char *z; /* Start of significant digits */ - char zBuf[24]; /* Storage for significant digits */ + char zBuf[20]; /* Storage for significant digits */ + char sign; /* '+' or '-' */ + char isSpecial; /* 1: Infinity 2: NaN */ }; void sqlite3FpDecode(FpDecode*,double,int,int); diff --git a/src/util.c b/src/util.c index e2c54a35db..c39a1da16b 100644 --- a/src/util.c +++ b/src/util.c @@ -1234,6 +1234,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ p->n = sizeof(p->zBuf) - 1 - i; assert( p->n>0 ); assert( p->nzBuf) ); + testcase( p->n==sizeof(p->zBuf)-1 ); p->iDP = p->n + exp; if( iRound<=0 ){ iRound = p->iDP - iRound; From aec283385ef9969198df61136e5171c63ffd3b4d Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 21 Feb 2026 00:20:29 +0000 Subject: [PATCH 034/197] Small performance increase and size reduction in sqlite3FpDecode() by using local variables instead of structure elements. FossilOrigin-Name: b4c378bba582205aa676e45b21ffa17ad6199e2a017ec73cf41a0243f693b589 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 54 +++++++++++++++++++++++++++------------------------ 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/manifest b/manifest index 30469cdd11..d449f79dbe 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Inconsequential\schanges\sto\sfloating-point\sconversion,\samounting\sto\smere\ncode\scleanup\sto\said\scomprehension. -D 2026-02-20T20:43:25.912 +C Small\sperformance\sincrease\sand\ssize\sreduction\sin\ssqlite3FpDecode()\sby\susing\nlocal\svariables\sinstead\sof\sstructure\selements. +D 2026-02-21T00:20:29.013 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 64c047521e35adc402e6f2a8dcd20732392c02641418becfc4387a1c02f5e042 +F src/util.c 2578230d8c15e11cb86b7e6c4c069e5ea880a058d1d9aa25887fb607ac6942cd F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P cb24edf1afc3f9083a4963c5fe232933eccc7c0cb8872aa5fcd336d226b885ef -R 5dc7d1cf9df5b4fd3583425b84bcab00 +P 6d9c29123b6b143b0f7c8f5d018f170c72edfc5b1a4d67edd45e5552def2af6c +R ab113b7f537cba0046252b74a0cfbdbd U drh -Z a28f337e825428b6e4dfea35f10cb54e +Z eb44db8829fa7401363a7a2fe662819e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f7d89da182..fa0737e469 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6d9c29123b6b143b0f7c8f5d018f170c72edfc5b1a4d67edd45e5552def2af6c +b4c378bba582205aa676e45b21ffa17ad6199e2a017ec73cf41a0243f693b589 diff --git a/src/util.c b/src/util.c index c39a1da16b..e0de0abf07 100644 --- a/src/util.c +++ b/src/util.c @@ -1174,9 +1174,10 @@ int sqlite3Atoi(const char *z){ ** The p->z[] array is *not* zero-terminated. */ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ - int i; + int i, n; u64 v; int e, exp = 0; + char *zBuf; p->isSpecial = 0; p->z = p->zBuf; @@ -1206,9 +1207,9 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ } v &= 0x000fffffffffffffULL; if( e==0 ){ - int n = countLeadingZeros(v); - v <<= n; - e = -1074 - n; + int nn = countLeadingZeros(v); + v <<= nn; + e = -1074 - nn; }else{ v = (v<<11) | U64_BIT(63); e -= 1086; @@ -1217,38 +1218,39 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ /* Extract significant digits. */ i = sizeof(p->zBuf)-1; + zBuf = p->zBuf; assert( v>0 ); while( v>=10 ){ int kk = (v%100)*2; assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) ); - assert( TWO_BYTE_ALIGNMENT(&p->zBuf[i-1]) ); - *(u16*)(&p->zBuf[i-1]) = *(u16*)&sqlite3DigitPairs.a[kk]; + assert( TWO_BYTE_ALIGNMENT(&zBuf[i-1]) ); + *(u16*)(&zBuf[i-1]) = *(u16*)&sqlite3DigitPairs.a[kk]; i -= 2; v /= 100; } if( v ){ assert( v<10 ); - p->zBuf[i--] = v + '0'; + zBuf[i--] = v + '0'; } assert( i>=0 && izBuf)-1 ); - p->n = sizeof(p->zBuf) - 1 - i; - assert( p->n>0 ); - assert( p->nzBuf) ); - testcase( p->n==sizeof(p->zBuf)-1 ); - p->iDP = p->n + exp; + n = sizeof(p->zBuf) - 1 - i; + assert( n>0 ); + assert( nzBuf) ); + testcase( n==sizeof(p->zBuf)-1 ); + p->iDP = n + exp; if( iRound<=0 ){ iRound = p->iDP - iRound; - if( iRound==0 && p->zBuf[i+1]>='5' ){ + if( iRound==0 && zBuf[i+1]>='5' ){ iRound = 1; - p->zBuf[i--] = '0'; - p->n++; + zBuf[i--] = '0'; + n++; p->iDP++; } } - if( iRound>0 && (iRoundn || p->n>mxRound) ){ - char *z = &p->zBuf[i+1]; + if( iRound>0 && (iRoundmxRound) ){ + char *z = &zBuf[i+1]; if( iRound>mxRound ) iRound = mxRound; - p->n = iRound; + n = iRound; if( z[iRound]>='5' ){ int j = iRound-1; while( 1 /*exit-by-break*/ ){ @@ -1257,7 +1259,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ z[j] = '0'; if( j==0 ){ p->z[i--] = '1'; - p->n++; + n++; p->iDP++; break; }else{ @@ -1266,13 +1268,15 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ } } } - p->z = &p->zBuf[i+1]; - assert( i+p->n < sizeof(p->zBuf) ); - assert( p->n>0 ); - while( p->z[p->n-1]=='0' ){ - p->n--; - assert( p->n>0 ); + p->z = &zBuf[i+1]; + assert( i+n < sizeof(p->zBuf) ); + assert( n>0 ); + zBuf = p->z; + while( zBuf[n-1]=='0' ){ + n--; + assert( n>0 ); } + p->n = n; } /* From 24ef9fbb1972831dfd1a74da0fe2b2782ac04e42 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 21 Feb 2026 00:56:11 +0000 Subject: [PATCH 035/197] Further simplification, performance gain, and size reduction in sqlite3FpDecode(). FossilOrigin-Name: 5954f22ceb6b43ed160ec085cd86b66299d8aab3e349a41941a4f1c2eade7457 --- manifest | 12 ++++++------ manifest.tags | 4 ++-- manifest.uuid | 2 +- src/util.c | 29 ++++++++++++++++------------- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index d449f79dbe..d6092d9986 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Small\sperformance\sincrease\sand\ssize\sreduction\sin\ssqlite3FpDecode()\sby\susing\nlocal\svariables\sinstead\sof\sstructure\selements. -D 2026-02-21T00:20:29.013 +C Further\ssimplification,\sperformance\sgain,\sand\ssize\sreduction\sin\nsqlite3FpDecode(). +D 2026-02-21T00:56:11.032 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 2578230d8c15e11cb86b7e6c4c069e5ea880a058d1d9aa25887fb607ac6942cd +F src/util.c 1aa25fd0e8a9e7e7038dc35576ca084ab1ce305808683ed9fc34c0a911cd7cfe F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 6d9c29123b6b143b0f7c8f5d018f170c72edfc5b1a4d67edd45e5552def2af6c -R ab113b7f537cba0046252b74a0cfbdbd +P b4c378bba582205aa676e45b21ffa17ad6199e2a017ec73cf41a0243f693b589 +R 2ba85f29f79912c10542f94e5fe0f51a U drh -Z eb44db8829fa7401363a7a2fe662819e +Z 6f74841077f4058908580abdb7a6af5c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..a43a9fc376 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch fp-performance-v2 +tag fp-performance-v2 diff --git a/manifest.uuid b/manifest.uuid index fa0737e469..26c7dc2690 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b4c378bba582205aa676e45b21ffa17ad6199e2a017ec73cf41a0243f693b589 +5954f22ceb6b43ed160ec085cd86b66299d8aab3e349a41941a4f1c2eade7457 diff --git a/src/util.c b/src/util.c index e0de0abf07..ed98fcc59f 100644 --- a/src/util.c +++ b/src/util.c @@ -1174,13 +1174,14 @@ int sqlite3Atoi(const char *z){ ** The p->z[] array is *not* zero-terminated. */ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ - int i, n; - u64 v; - int e, exp = 0; - char *zBuf; + int i; /* Index into zBuf[] where to put next character */ + int n; /* Number of digits */ + u64 v; /* mantissa */ + int e, exp = 0; /* Base-2 and base-10 exponent */ + char *zBuf; /* Local alias for p->zBuf */ + char *z; /* Local alias for p->z */ p->isSpecial = 0; - p->z = p->zBuf; assert( mxRound>0 ); /* Convert negative numbers to positive. Deal with Infinity, 0.0, and @@ -1203,6 +1204,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ p->isSpecial = 1 + (v!=0x7ff0000000000000LL); p->n = 0; p->iDP = 0; + p->z = p->zBuf; return; } v &= 0x000fffffffffffffULL; @@ -1216,7 +1218,9 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ } sqlite3Fp2Convert10(v, e, (iRound<=0||iRound>=18)?18:iRound+1, &v, &exp); - /* Extract significant digits. */ + /* Extract significant digits, start at the right-most slot in p->zBuf + ** and working back to the right. "i" keeps track of the next slot in + ** which to store a digit. */ i = sizeof(p->zBuf)-1; zBuf = p->zBuf; assert( v>0 ); @@ -1233,7 +1237,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ zBuf[i--] = v + '0'; } assert( i>=0 && izBuf)-1 ); - n = sizeof(p->zBuf) - 1 - i; + n = sizeof(p->zBuf) - 1 - i; /* Total number of digits extracted */ assert( n>0 ); assert( nzBuf) ); testcase( n==sizeof(p->zBuf)-1 ); @@ -1247,8 +1251,8 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ p->iDP++; } } + z = &zBuf[i+1]; /* z points to the first digit */ if( iRound>0 && (iRoundmxRound) ){ - char *z = &zBuf[i+1]; if( iRound>mxRound ) iRound = mxRound; n = iRound; if( z[iRound]>='5' ){ @@ -1258,7 +1262,8 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ if( z[j]<='9' ) break; z[j] = '0'; if( j==0 ){ - p->z[i--] = '1'; + z--; + z[0] = '1'; n++; p->iDP++; break; @@ -1268,15 +1273,13 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ } } } - p->z = &zBuf[i+1]; - assert( i+n < sizeof(p->zBuf) ); assert( n>0 ); - zBuf = p->z; - while( zBuf[n-1]=='0' ){ + while( z[n-1]=='0' ){ n--; assert( n>0 ); } p->n = n; + p->z = z; } /* From 4428aa842ccb865ff61e0badcdc1e4437638c33a Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 21 Feb 2026 10:57:02 +0000 Subject: [PATCH 036/197] Increase the precision of double → text conversions that happen in sqlite3_column_text(), or sqlite3_value_text(), or in the CAST() operator, or similar, so that round-tripping the value back to double results in exactly the same value. FossilOrigin-Name: ef0049e3ade304f64e1ab97e52e1e21379e4db461f3fa80dac8e544fb90d622f --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/util.c | 31 +++++++++++++++++++++++++++++++ src/vdbemem.c | 2 +- test/e_expr.test | 8 ++++---- 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index d6092d9986..0bfab54814 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\ssimplification,\sperformance\sgain,\sand\ssize\sreduction\sin\nsqlite3FpDecode(). -D 2026-02-21T00:56:11.032 +C Increase\sthe\sprecision\sof\sdouble\s→\stext\sconversions\sthat\shappen\sin\nsqlite3_column_text(),\sor\ssqlite3_value_text(),\sor\sin\sthe\sCAST()\soperator,\nor\ssimilar,\sso\sthat\sround-tripping\sthe\svalue\sback\sto\sdouble\sresults\sin\nexactly\sthe\ssame\svalue. +D 2026-02-21T10:57:02.002 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 1aa25fd0e8a9e7e7038dc35576ca084ab1ce305808683ed9fc34c0a911cd7cfe +F src/util.c 2bff4df366c4af1b50176f7a6b9517782d80bd7a9fd755f132ee6c989001fb24 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -811,7 +811,7 @@ F src/vdbeInt.h 42488247a80cd9d300627833c6c85ace067ae5011a99e7614e2358130d62feea F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1 F src/vdbeaux.c 396d38a62a357b807eabae0cae441fc89d2767a57ab08026b7072bf7aa2dd00c F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692 -F src/vdbemem.c bdfda8e65933cfee34aa29c2bfa31fc07609f3d56d147aa8a367a297533d33d1 +F src/vdbemem.c 61b014628c6db12dd10b094b84f3e83ea0f85a1c485891bf0b5f370f3625d4ca F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70 F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 @@ -1071,7 +1071,7 @@ F test/e_createtable.test 31b9bcb6ac8876bc7ec342d86d9c231a84c62b442093a6651dfd0f F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e F test/e_droptrigger.test 235c610f8bf8ec44513e222b9085c7e49fad65ad0c1975ac2577109dd06fd8fa F test/e_dropview.test 74e405df7fa0f762e0c9445b166fe03955856532e2bb234c372f7c51228d75e7 -F test/e_expr.test 0a1e175caddc78b27306647cb4ce2362c55790190f8cdd178b75fd6262eb8f76 +F test/e_expr.test 9bdb347b78b9f4eff9153ea97797facc179a821898588471a70808b4471a69b0 F test/e_fkey.test feeba6238aeff9d809fb6236b351da8df4ae9bda89e088e54526b31a0cbfeec5 F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07 F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b4c378bba582205aa676e45b21ffa17ad6199e2a017ec73cf41a0243f693b589 -R 2ba85f29f79912c10542f94e5fe0f51a +P 5954f22ceb6b43ed160ec085cd86b66299d8aab3e349a41941a4f1c2eade7457 +R 273816acc4ad445067b918c67e26e2bb U drh -Z 6f74841077f4058908580abdb7a6af5c +Z 8c81f31c7c681f8cd4928433e40b84e9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 26c7dc2690..6a27d619b0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5954f22ceb6b43ed160ec085cd86b66299d8aab3e349a41941a4f1c2eade7457 +ef0049e3ade304f64e1ab97e52e1e21379e4db461f3fa80dac8e544fb90d622f diff --git a/src/util.c b/src/util.c index ed98fcc59f..3c78c759c2 100644 --- a/src/util.c +++ b/src/util.c @@ -1254,6 +1254,37 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ z = &zBuf[i+1]; /* z points to the first digit */ if( iRound>0 && (iRoundmxRound) ){ if( iRound>mxRound ) iRound = mxRound; + if( iRound==17 ){ + /* If the precision is exactly 17, which only happens with the "!" + ** flag (ex: "%!.17g") then try to reduce the precision if that + ** yields text that will round-trip to the original floating-point. + ** value. Thus, for exaple, 49.47 will render as 49.47, rather than + ** as 49.469999999999999. */ + if( z[15]=='9' && z[14]=='9' ){ + int jj, kk; + u64 v2; + for(jj=14; jj>0 && z[jj-1]=='9'; jj--){} + if( jj==0 ){ + v2 = 1; + }else{ + v2 = z[0] - '0'; + for(kk=1; kkiDP>=n || (z[15]=='0' && z[14]=='0' && z[13]=='0') ){ + int jj, kk; + u64 v2; + for(jj=14; jj>0 && z[jj-1]=='0'; jj--){} + v2 = z[0] - '0'; + for(kk=1; kk='5' ){ int j = iRound-1; diff --git a/src/vdbemem.c b/src/vdbemem.c index 91c45ee08b..48e1014663 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -120,7 +120,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ #endif }else{ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); - sqlite3_str_appendf(&acc, "%!.15g", + sqlite3_str_appendf(&acc, "%!.17g", (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r); assert( acc.zText==zBuf && acc.mxAlloc<=0 ); zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */ diff --git a/test/e_expr.test b/test/e_expr.test index 81d2fd172c..5c0bfb0c1f 100644 --- a/test/e_expr.test +++ b/test/e_expr.test @@ -1744,10 +1744,10 @@ do_execsql_test e_expr-32.2.8 { integer 9223372036854775807 \ integer 9223372036854775807 \ integer 9223372036854775807 \ - real 9.22337203685478e+18 \ - real 9.22337203685478e+18 \ - real 9.22337203685478e+18 \ - real 9.22337203685478e+18 \ + real 9.2233720368547758e+18 \ + real 9.2233720368547758e+18 \ + real 9.2233720368547758e+18 \ + real 9.2233720368547758e+18 \ integer -5 \ integer -5 \ ] From 7aba858597f55a7d46818ee5dfc0183e458dc06a Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 21 Feb 2026 13:40:07 +0000 Subject: [PATCH 037/197] Remove an unreachable branch. FossilOrigin-Name: 93f90eacc0c5b2ae0042ec525359298883f8473e24967208feef4029d9fa2d08 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 0bfab54814..8108e80e84 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Increase\sthe\sprecision\sof\sdouble\s→\stext\sconversions\sthat\shappen\sin\nsqlite3_column_text(),\sor\ssqlite3_value_text(),\sor\sin\sthe\sCAST()\soperator,\nor\ssimilar,\sso\sthat\sround-tripping\sthe\svalue\sback\sto\sdouble\sresults\sin\nexactly\sthe\ssame\svalue. -D 2026-02-21T10:57:02.002 +C Remove\san\sunreachable\sbranch. +D 2026-02-21T13:40:07.301 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 2bff4df366c4af1b50176f7a6b9517782d80bd7a9fd755f132ee6c989001fb24 +F src/util.c 95f8f7574c8f65039e341f0c905267121569ebf4d0de026c44ee1809fe00d5bf F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 5954f22ceb6b43ed160ec085cd86b66299d8aab3e349a41941a4f1c2eade7457 -R 273816acc4ad445067b918c67e26e2bb +P ef0049e3ade304f64e1ab97e52e1e21379e4db461f3fa80dac8e544fb90d622f +R 4284bb3336406325134043995228dfd1 U drh -Z 8c81f31c7c681f8cd4928433e40b84e9 +Z 6f1ea06f09642b6d8ff481a030d40fdb # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 6a27d619b0..f50a9520fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ef0049e3ade304f64e1ab97e52e1e21379e4db461f3fa80dac8e544fb90d622f +93f90eacc0c5b2ae0042ec525359298883f8473e24967208feef4029d9fa2d08 diff --git a/src/util.c b/src/util.c index 3c78c759c2..b287263d42 100644 --- a/src/util.c +++ b/src/util.c @@ -1277,7 +1277,8 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ }else if( p->iDP>=n || (z[15]=='0' && z[14]=='0' && z[13]=='0') ){ int jj, kk; u64 v2; - for(jj=14; jj>0 && z[jj-1]=='0'; jj--){} + assert( z[0]!='0' ); + for(jj=14; z[jj-1]=='0'; jj--){} v2 = z[0] - '0'; for(kk=1; kk Date: Sat, 21 Feb 2026 13:57:40 +0000 Subject: [PATCH 038/197] New test cases for floating-point conversions. FossilOrigin-Name: 3033fe97b14ba0531278d4aa444bc5340e044b87a72b3a4341032ddee442000f --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/fpconv1.test | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 8108e80e84..c3151a0aaa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sunreachable\sbranch. -D 2026-02-21T13:40:07.301 +C New\stest\scases\sfor\sfloating-point\sconversions. +D 2026-02-21T13:57:40.503 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -1131,7 +1131,7 @@ F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958 F test/fork-test.c 9ac2e6423a1d38df3d6be0e8ac15608b545de21e2b19d9d876254c5931b63edb F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4 F test/fp-speed-1.c b37de94eba034e1703668816225f54510ec60fb0685406608cc707afe6b8234d -F test/fpconv1.test ac9616f36ac8b8bc16b78f389978d8fb1420f53c1fc93d2793a9553ca2755f72 +F test/fpconv1.test d9e1e1bdeaf22b2e800aa6847466468a930f6aea6b59eea348711f9445a043b1 F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654 F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P ef0049e3ade304f64e1ab97e52e1e21379e4db461f3fa80dac8e544fb90d622f -R 4284bb3336406325134043995228dfd1 +P 93f90eacc0c5b2ae0042ec525359298883f8473e24967208feef4029d9fa2d08 +R e68f89bae9b5fbd05cf0e0e735a13171 U drh -Z 6f1ea06f09642b6d8ff481a030d40fdb +Z 5a9c96d60317e775f664966a4b06b2ad # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f50a9520fa..f51a8bda13 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -93f90eacc0c5b2ae0042ec525359298883f8473e24967208feef4029d9fa2d08 +3033fe97b14ba0531278d4aa444bc5340e044b87a72b3a4341032ddee442000f diff --git a/test/fpconv1.test b/test/fpconv1.test index 7b052d78b2..597e065e8b 100644 --- a/test/fpconv1.test +++ b/test/fpconv1.test @@ -28,18 +28,59 @@ do_execsql_test fpconv1-1.0 { /* Number of random floating-point values to try. ** On a circa 2021 Ryzen 5950X running Mint Linux, and ** compiled with -O0 -DSQLITE_DEBUG, this test runs at - ** about 150000 cases per second ------------------vvvvvv */ - c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<900000), + ** about 150000 cases per second ------------------vvvvvvv */ + c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<500_000), fp(y) AS MATERIALIZED ( SELECT CAST( format('%+d.%019d0e%+03d', random()%10,abs(random()),random()%200) AS real) FROM c ) SELECT y FROM fp - WHERE -log10(abs(decimal_sub(dtostr(y,24),format('%!.24e',y))/y))<16.0; + WHERE -log10(abs(decimal_sub(dtostr(y,24),format('%!.24e',y))/y))<17.0; /* Number of digits of accuracy required -------^^^^ */ } {} # ^---- Expect a empty set as the result. The output is all tested numbers # that fail to preserve at least 16 significant digits of accuracy. +######################################################################## +# Random test to ensure that double -> text -> double conversions +# round-trip exactly. +# + +load_static_extension db ieee754 + +do_execsql_test fpconv1-2.0 { + WITH RECURSIVE + c(x,s) AS MATERIALIZED (VALUES(1,random()&0xffefffffffffffff) + UNION ALL + SELECT x+1,random()&0xffefffffffffffff + FROM c WHERE x<1_000_000), + fp(y,s) AS ( + SELECT ieee754_from_int(s),s FROM c + ), + fp2(yt,y,s) AS ( + SELECT y||'', y, s FROM fp + ) + SELECT format('%#016x',s) aS 'orig-hex', + format('%#016x',ieee754_to_int(CAST(yt AS real))) AS 'full-roundtrip', + yt AS 'rendered-as', + decimal_exp(yt,30) AS 'text-decimal', + decimal_exp(ieee754_from_int(s),30) AS 'float-decimal' + FROM fp2 + WHERE ieee754_to_int(CAST(yt AS real))<>s; +} {} +# ^---- Values that fail to round-trip will be reported + +# Unusual rendering cases: +# +do_execsql_test fpconv1-3.0 { + SELECT 1.23 - 2.34; +} {-1.1099999999999999} +# ^--- Not -1.11 as you would expect. -1.11 has a different bit pattern + +do_execsql_test fpconv1-3.1 { + SELECT 1.23 * 2.34; +} {2.8781999999999996} +# ^--- Not 2.8782 as you would expect. 2.8782 has a different bit pattern + finish_test From 8642ca202539414b482d0b806c77c721e38c3ef6 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 21 Feb 2026 19:26:58 +0000 Subject: [PATCH 039/197] New sqlite3_db_config(SQLITE_DBCONFIG_FP_DIGITS) that let's the application specify the number of significant digits that double→text conversions will attempt to preserve. FossilOrigin-Name: 3f16985dcc47a366b54164c5024f920a79dddd76faeac5e36b4770732ed72c0a --- manifest | 24 ++++++++++++------------ manifest.uuid | 2 +- src/main.c | 9 +++++++++ src/shell.c.in | 15 ++++++++++++--- src/sqlite.h.in | 18 +++++++++++++++++- src/sqliteInt.h | 1 + src/test1.c | 1 + src/vdbemem.c | 15 ++++++++++----- test/fpconv1.test | 40 ++++++++++++++++++++++++++-------------- 9 files changed, 89 insertions(+), 36 deletions(-) diff --git a/manifest b/manifest index c3151a0aaa..2bddd7d3ad 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stest\scases\sfor\sfloating-point\sconversions. -D 2026-02-21T13:57:40.503 +C New\ssqlite3_db_config(SQLITE_DBCONFIG_FP_DIGITS)\sthat\slet's\sthe\sapplication\nspecify\sthe\snumber\sof\ssignificant\sdigits\sthat\sdouble→text\sconversions\nwill\sattempt\sto\spreserve. +D 2026-02-21T19:26:58.856 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -702,7 +702,7 @@ F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd F src/json.c 8b6341a419150b28530cc21e3951b2238c35cdc312f11b2ca29017fe4b1dedc0 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9 -F src/main.c e95aa130478fc98a49181ddf094baab45f319286411129253618efe0008f0dc4 +F src/main.c 211f7721b191523b815dee6c6a1e9a5f3ebc052a0ddaaed24a75cf20bf9d4b06 F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2 @@ -739,17 +739,17 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c -F src/shell.c.in 15285c21cc3f1da9289b0b6c5fd0b2ca8ab2e664b4b300c404afe7634ce9876f -F src/sqlite.h.in 8bcbaecfe2cbecf8c5c1381354fcdd7d307443e88b4953fccb222456c1267b61 +F src/shell.c.in 3e87584890a4e9797865e4771689d8d1aca3b0f824f973192784716ecfa320a2 +F src/sqlite.h.in b8a0b4dd92b1e52caa9676e39971bdaaf44eef30c4b148c9c2fa99e88ed6cf3a F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h 347722b895995dc3015147150c1f9fed5224748c26b36d69ef405656d1603100 +F src/sqliteInt.h ffa3071dc3b9172acfe1a4edd8bc699928b0d5e02f0b8b9067676aa8e5f8f787 F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/tclsqlite.c 85b5a20df96016e5d1d8fdc68c8a4c279c5b93e2049b77cd806c2cc50b9d8c56 F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a -F src/test1.c 302cc00a5f0bbfa36d73b299d600c073b02ffa7f2b59fd2c81091983ccd574a8 +F src/test1.c 3e3b013f59ffcb57dce00c90d55907072d71d4e970cb0a590cb261efe11bae9c F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff F src/test3.c 432646f581d8af1bb495e58fc98234380250954f5d5535e507fc785eccc3987a F src/test4.c 0ac87fc13cdb334ab3a71823f99b6c32a6bebe5d603cd6a71d84c823d43a25a0 @@ -811,7 +811,7 @@ F src/vdbeInt.h 42488247a80cd9d300627833c6c85ace067ae5011a99e7614e2358130d62feea F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1 F src/vdbeaux.c 396d38a62a357b807eabae0cae441fc89d2767a57ab08026b7072bf7aa2dd00c F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692 -F src/vdbemem.c 61b014628c6db12dd10b094b84f3e83ea0f85a1c485891bf0b5f370f3625d4ca +F src/vdbemem.c 565c214150dbab0678bfb04db5488f1788df87aad4ec3ec71cc61e0eb3f18f38 F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70 F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 @@ -1131,7 +1131,7 @@ F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958 F test/fork-test.c 9ac2e6423a1d38df3d6be0e8ac15608b545de21e2b19d9d876254c5931b63edb F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4 F test/fp-speed-1.c b37de94eba034e1703668816225f54510ec60fb0685406608cc707afe6b8234d -F test/fpconv1.test d9e1e1bdeaf22b2e800aa6847466468a930f6aea6b59eea348711f9445a043b1 +F test/fpconv1.test 63f352682fa65601a326563ad633086df6ab194e6ed5e7366786f38a525a7fd7 F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654 F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 93f90eacc0c5b2ae0042ec525359298883f8473e24967208feef4029d9fa2d08 -R e68f89bae9b5fbd05cf0e0e735a13171 +P 3033fe97b14ba0531278d4aa444bc5340e044b87a72b3a4341032ddee442000f +R 4d154d27dd2b7e6c72267982eae3c18d U drh -Z 5a9c96d60317e775f664966a4b06b2ad +Z 47c16a6580f94070b6e59ea57711afd7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f51a8bda13..fffbbc32ca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3033fe97b14ba0531278d4aa444bc5340e044b87a72b3a4341032ddee442000f +3f16985dcc47a366b54164c5024f920a79dddd76faeac5e36b4770732ed72c0a diff --git a/src/main.c b/src/main.c index 37e6f23744..a3bfe6d137 100644 --- a/src/main.c +++ b/src/main.c @@ -971,6 +971,14 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){ rc = setupLookaside(db, pBuf, sz, cnt); break; } + case SQLITE_DBCONFIG_FP_DIGITS: { + int nIn = va_arg(ap, int); + int *pOut = va_arg(ap, int*); + if( nIn>3 && nIn<24 ) db->nFpDigit = (u8)nIn; + if( pOut ) *pOut = db->nFpDigit; + rc = SQLITE_OK; + break; + } default: { static const struct { int op; /* The opcode */ @@ -3399,6 +3407,7 @@ static int openDatabase( db->aDb = db->aDbStatic; db->lookaside.bDisable = 1; db->lookaside.sz = 0; + db->nFpDigit = 17; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); diff --git a/src/shell.c.in b/src/shell.c.in index 05d5831201..8eaa060812 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -9267,6 +9267,7 @@ static int do_meta_command(const char *zLine, ShellState *p){ { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER }, { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW }, { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, + { "fp_digits", SQLITE_DBCONFIG_FP_DIGITS }, { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE }, { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT }, { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, @@ -9283,11 +9284,19 @@ static int do_meta_command(const char *zLine, ShellState *p){ for(ii=0; ii1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue; if( nArg>=3 ){ - sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0); + if( aDbConfig[ii].op==SQLITE_DBCONFIG_FP_DIGITS ){ + sqlite3_db_config(p->db, aDbConfig[ii].op, atoi(azArg[2]), 0); + }else{ + sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0); + } } sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v); - cli_printf(p->out, "%19s %s\n", - aDbConfig[ii].zName, v ? "on" : "off"); + if( aDbConfig[ii].op==SQLITE_DBCONFIG_FP_DIGITS ){ + cli_printf(p->out, "%19s %d\n", aDbConfig[ii].zName, v); + }else{ + cli_printf(p->out, "%19s %s\n", + aDbConfig[ii].zName, v ? "on" : "off"); + } if( nArg>1 ) break; } if( nArg>1 && ii==ArraySize(aDbConfig) ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index e1f478a0a9..182f6871c8 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2648,6 +2648,21 @@ struct sqlite3_mem_methods { ** comments are allowed in SQL text after processing the first argument. ** ** +** [[SQLITE_DBCONFIG_FP_DIGITS]] +**
SQLITE_DBCONFIG_FP_DIGITS
+**
The SQLITE_DBCONFIG_FP_DIGITS option is a small integer is the number +** of significant digits that SQLite attempts to preserve when converting +** floating point numbers (IEEE 754 "doubles") into text. The default value +** (as of SQLite version 3.52.0) is 17.

+** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is a small integer, between 3 and 20, or +** zero. The FP_DIGITS setting is changed to the small integer, or left +** altered if the first argument is out of range. The second argument is a +** pointer to an integer. If the pointer is not NULL, then the value of +** the FP_DIGITS setting, after possibly being modified by the first +** arguments, is written into the integer to which the second argument points. +**

+** ** ** ** [[DBCONFIG arguments]]

Arguments To SQLITE_DBCONFIG Options

@@ -2692,7 +2707,8 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1022 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_FP_DIGITS 1023 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1023 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8ccb079096..051cb4e874 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1692,6 +1692,7 @@ struct sqlite3 { u8 noSharedCache; /* True if no shared-cache backends */ u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ u8 eOpenState; /* Current condition of the connection */ + u8 nFpDigit; /* Significant digits to keep on double->text */ int nextPagesize; /* Pagesize after VACUUM if >0 */ i64 nChange; /* Value returned by sqlite3_changes() */ i64 nTotalChange; /* Value returned by sqlite3_total_changes() */ diff --git a/src/test1.c b/src/test1.c index 230034fa01..3ca5c837a7 100644 --- a/src/test1.c +++ b/src/test1.c @@ -8644,6 +8644,7 @@ static int SQLITE_TCLAPI test_sqlite3_db_config( { "ATTACH_CREATE", SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE }, { "ATTACH_WRITE", SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE }, { "COMMENTS", SQLITE_DBCONFIG_ENABLE_COMMENTS }, + { "FP_DIGITS", SQLITE_DBCONFIG_FP_DIGITS }, }; int i; int v = 0; diff --git a/src/vdbemem.c b/src/vdbemem.c index 48e1014663..9e654858d3 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -107,10 +107,11 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ StrAccum acc; assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); assert( sz>22 ); - if( p->flags & MEM_Int ){ -#if GCC_VERSION>=7000000 + if( p->flags & (MEM_Int|MEM_IntReal) ){ +#if 0 /* Work-around for GCC bug - ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */ + ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270. + ** Bug fixed circa 2020, so this work-around removed in 2026. */ i64 x; assert( (p->flags&MEM_Int)*2==sizeof(x) ); memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2); @@ -118,10 +119,14 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ #else p->n = sqlite3Int64ToText(p->u.i, zBuf); #endif + if( p->flags & MEM_IntReal ){ + memcpy(zBuf+p->n,".0", 3); + p->n += 2; + } }else{ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); - sqlite3_str_appendf(&acc, "%!.17g", - (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r); + sqlite3_str_appendf(&acc, "%!.*g", + (p->db ? p->db->nFpDigit : 17), p->u.r); assert( acc.zText==zBuf && acc.mxAlloc<=0 ); zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */ p->n = acc.nChar; diff --git a/test/fpconv1.test b/test/fpconv1.test index 597e065e8b..a93489907e 100644 --- a/test/fpconv1.test +++ b/test/fpconv1.test @@ -17,13 +17,37 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl + +# Unusual rendering cases: +# +do_execsql_test fpconv1-1.0 { + SELECT 1.23 - 2.34; +} {-1.1099999999999999} +# ^--- Not -1.11 as you would expect. -1.11 has a different bit pattern + +do_execsql_test fpconv1-1.1 { + SELECT 1.23 * 2.34; +} {2.8781999999999996} +# ^--- Not 2.8782 as you would expect. 2.8782 has a different bit pattern + +# Change significant digits to 15 and get a different result. +sqlite3_db_config db FP_DIGITS 15 +do_execsql_test fpconv1-1.2 { + SELECT 1.23 - 2.34; +} {-1.11} +do_execsql_test fpconv1-1.3 { + SELECT 1.23 * 2.34; +} {2.8782} +sqlite3_db_config db FP_DIGITS 17 + + if {[catch {load_static_extension db decimal} error]} { puts "Skipping decimal tests, hit load error: $error" finish_test; return } sqlite3_create_function db -do_execsql_test fpconv1-1.0 { +do_execsql_test fpconv1-2.0 { WITH RECURSIVE /* Number of random floating-point values to try. ** On a circa 2021 Ryzen 5950X running Mint Linux, and @@ -49,7 +73,7 @@ do_execsql_test fpconv1-1.0 { load_static_extension db ieee754 -do_execsql_test fpconv1-2.0 { +do_execsql_test fpconv1-3.0 { WITH RECURSIVE c(x,s) AS MATERIALIZED (VALUES(1,random()&0xffefffffffffffff) UNION ALL @@ -71,16 +95,4 @@ do_execsql_test fpconv1-2.0 { } {} # ^---- Values that fail to round-trip will be reported -# Unusual rendering cases: -# -do_execsql_test fpconv1-3.0 { - SELECT 1.23 - 2.34; -} {-1.1099999999999999} -# ^--- Not -1.11 as you would expect. -1.11 has a different bit pattern - -do_execsql_test fpconv1-3.1 { - SELECT 1.23 * 2.34; -} {2.8781999999999996} -# ^--- Not 2.8782 as you would expect. 2.8782 has a different bit pattern - finish_test From f8681fb63810dbbc741f22f49f2366141587024b Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 21 Feb 2026 20:20:06 +0000 Subject: [PATCH 040/197] Fix a harmless warning in the decimal extension. FossilOrigin-Name: f16c7c4000f2b992f7245dcaf669f13ed464579f8894f3c16842eebf41285c70 --- ext/misc/decimal.c | 1 - manifest | 13 ++++++------- manifest.uuid | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c index ac9c7c7e5e..be4321ca8c 100644 --- a/ext/misc/decimal.c +++ b/ext/misc/decimal.c @@ -341,7 +341,6 @@ static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){ if( N<1 ) N = 0; for(nDigit=p->nDigit; nDigit>N && p->a[nDigit-1]==0; nDigit--){} for(nZero=0; nZeroa[nZero]==0; nZero++){} - N += nZero; nFrac = p->nFrac + (nDigit - p->nDigit); nDigit -= nZero; z = sqlite3_malloc64( (sqlite3_int64)nDigit+20 ); diff --git a/manifest b/manifest index 3aa96e6b9d..f05a8ddd52 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\srounding\sof\sdouble→text\sconversions\sfor\srounding\sdigits\nof\s17.\s\sAdd\sthe\snew\ssqlite3_db_config(),\sSQLITE_DBCONFIG_FP_DIGITS,\nto\sspecify\sthe\snumber\sof\ssignificant\sdigits\sto\spreserve\son\sconversions. -D 2026-02-21T20:03:47.616 +C Fix\sa\sharmless\swarning\sin\sthe\sdecimal\sextension. +D 2026-02-21T20:20:06.720 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -370,7 +370,7 @@ F ext/misc/completion.c c27b64fdd0943c1b7f152376599814cee2641f7d67a7bb9bd2b957c2 F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565 F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680 -F ext/misc/decimal.c 38aa18b29e96c745c78725ef3740a53f4b2b8cdfa226dfab13aaf2168a071db7 +F ext/misc/decimal.c e1da22eee70d7e3eaa99a6b761bc03c4d01d7ffa554bf3178b1f1f184932806c F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b F ext/misc/fileio.c 452300ca34fadafd2bb9eb09557de5a518da1fd2349f9f9cedd22b1566a7164f @@ -2195,9 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 6d9c29123b6b143b0f7c8f5d018f170c72edfc5b1a4d67edd45e5552def2af6c 3f16985dcc47a366b54164c5024f920a79dddd76faeac5e36b4770732ed72c0a -R 4d154d27dd2b7e6c72267982eae3c18d -T +closed 3f16985dcc47a366b54164c5024f920a79dddd76faeac5e36b4770732ed72c0a +P 78c12b4f6ae869c3ea5e368c97b45991442bdd2d3a60935f1e6fc02a8e01cd41 +R 49ff7c0b58fdceea8cbf4269b84e9dc8 U drh -Z ff618f76f13f938e13046abb7fac9de3 +Z 066b8dfa63132b7df4fb39636455127f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 37492bc7db..89cbec7e9a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -78c12b4f6ae869c3ea5e368c97b45991442bdd2d3a60935f1e6fc02a8e01cd41 +f16c7c4000f2b992f7245dcaf669f13ed464579f8894f3c16842eebf41285c70 From 60f132bf1288549ef1e7043f4a88fe6e199f0cf4 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 21 Feb 2026 21:19:41 +0000 Subject: [PATCH 041/197] Fix typos and include wording in the documentation for SQLITE_DBCONFIG_FP_DIGITS. FossilOrigin-Name: c30cee1224904eb2092daa0ad9494aec7c7a8c6c1661f5b91b62c3ef0c5ea95b --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqlite.h.in | 24 +++++++++++++----------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index f05a8ddd52..20186b546e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sharmless\swarning\sin\sthe\sdecimal\sextension. -D 2026-02-21T20:20:06.720 +C Fix\stypos\sand\sinclude\swording\sin\sthe\sdocumentation\sfor\nSQLITE_DBCONFIG_FP_DIGITS. +D 2026-02-21T21:19:41.549 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -740,7 +740,7 @@ F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c F src/shell.c.in 3e87584890a4e9797865e4771689d8d1aca3b0f824f973192784716ecfa320a2 -F src/sqlite.h.in b8a0b4dd92b1e52caa9676e39971bdaaf44eef30c4b148c9c2fa99e88ed6cf3a +F src/sqlite.h.in c7582608c8270428b288a529f4a4170298a19548266b55edaa2e70ce8d607f0e F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca F src/sqliteInt.h ffa3071dc3b9172acfe1a4edd8bc699928b0d5e02f0b8b9067676aa8e5f8f787 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 78c12b4f6ae869c3ea5e368c97b45991442bdd2d3a60935f1e6fc02a8e01cd41 -R 49ff7c0b58fdceea8cbf4269b84e9dc8 +P f16c7c4000f2b992f7245dcaf669f13ed464579f8894f3c16842eebf41285c70 +R 944ea7c224f9333bdc2c56f7b2ed487a U drh -Z 066b8dfa63132b7df4fb39636455127f +Z ef2f611c8a724472ddbfbfc7d613ba7b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 89cbec7e9a..7193b3ed74 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f16c7c4000f2b992f7245dcaf669f13ed464579f8894f3c16842eebf41285c70 +c30cee1224904eb2092daa0ad9494aec7c7a8c6c1661f5b91b62c3ef0c5ea95b diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 182f6871c8..930c3a1814 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2650,15 +2650,16 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_FP_DIGITS]] **
SQLITE_DBCONFIG_FP_DIGITS
-**
The SQLITE_DBCONFIG_FP_DIGITS option is a small integer is the number -** of significant digits that SQLite attempts to preserve when converting -** floating point numbers (IEEE 754 "doubles") into text. The default value -** (as of SQLite version 3.52.0) is 17.

+**

The SQLITE_DBCONFIG_FP_DIGITS setting is a small integer that determines +** the number of significant digits that SQLite will attempt to preserve when +** converting floating point numbers (IEEE 754 "doubles") into text. The +** default value 17, as of SQLite version 3.52.0. The value was 15 in all +** prior versions.

** This option takes two arguments which are an integer and a pointer -** to an integer. The first argument is a small integer, between 3 and 20, or -** zero. The FP_DIGITS setting is changed to the small integer, or left -** altered if the first argument is out of range. The second argument is a -** pointer to an integer. If the pointer is not NULL, then the value of +** to an integer. The first argument is a small integer, between 3 and 23, or +** zero. The FP_DIGITS setting is changed to that small integer, or left +** altered if the first argument is zero or out of range. The second argument +** is a pointer to an integer. If the pointer is not NULL, then the value of ** the FP_DIGITS setting, after possibly being modified by the first ** arguments, is written into the integer to which the second argument points. **

@@ -2680,9 +2681,10 @@ struct sqlite3_mem_methods { ** the first argument. ** **

While most SQLITE_DBCONFIG options use the argument format -** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME] -** and [SQLITE_DBCONFIG_LOOKASIDE] options are different. See the -** documentation of those exceptional options for details. +** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME], +** [SQLITE_DBCONFIG_LOOKASIDE], and [SQLITE_DBCONFIG_FP_DIGITS] options +** are different. See the documentation of those exceptional options for +** details. */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ From 9bc017423c5f841eb55a3d9e711356c19ac86dd5 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 22 Feb 2026 20:44:52 +0000 Subject: [PATCH 042/197] Add the realpath() SQL function to the fileio.c extension. And clean up the UTF8 handling on the Windows side of that extension while we are at it. FossilOrigin-Name: 8bb8941930378b436f1353603be194644568b55fe347475be0caddddad40efa3 --- ext/misc/fileio.c | 149 ++++++++++++++++++++++++++++------------------ manifest | 12 ++-- manifest.uuid | 2 +- 3 files changed, 99 insertions(+), 64 deletions(-) diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c index db3fd6c3fd..876b397c70 100644 --- a/ext/misc/fileio.c +++ b/ext/misc/fileio.c @@ -100,6 +100,8 @@ SQLITE_EXTENSION_INIT1 # define STRUCT_STAT struct _stat # define chmod(path,mode) fileio_chmod(path,mode) # define mkdir(path,mode) fileio_mkdir(path) + extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); + extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); #endif #include #include @@ -131,12 +133,9 @@ SQLITE_EXTENSION_INIT1 */ #if defined(_WIN32) || defined(WIN32) static int fileio_chmod(const char *zPath, int pmode){ - sqlite3_int64 sz = strlen(zPath); - wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); int rc; + wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath); if( b1==0 ) return -1; - sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); - b1[sz] = 0; rc = _wchmod(b1, pmode); sqlite3_free(b1); return rc; @@ -148,12 +147,9 @@ static int fileio_chmod(const char *zPath, int pmode){ */ #if defined(_WIN32) || defined(WIN32) static int fileio_mkdir(const char *zPath){ - sqlite3_int64 sz = strlen(zPath); - wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); int rc; + wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath); if( b1==0 ) return -1; - sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); - b1[sz] = 0; rc = _wmkdir(b1); sqlite3_free(b1); return rc; @@ -266,50 +262,7 @@ static sqlite3_uint64 fileTimeToUnixTime( return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; } - - -#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32)) -# /* To allow a standalone DLL, use this next replacement function: */ -# undef sqlite3_win32_utf8_to_unicode -# define sqlite3_win32_utf8_to_unicode utf8_to_utf16 -# -LPWSTR utf8_to_utf16(const char *z){ - int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0); - LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR)); - if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) ) - return rv; - sqlite3_free(rv); - return 0; -} -#endif - -/* -** This function attempts to normalize the time values found in the stat() -** buffer to UTC. This is necessary on Win32, where the runtime library -** appears to return these values as local times. -*/ -static void statTimesToUtc( - const char *zPath, - STRUCT_STAT *pStatBuf -){ - HANDLE hFindFile; - WIN32_FIND_DATAW fd; - LPWSTR zUnicodeName; - extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); - zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath); - if( zUnicodeName ){ - memset(&fd, 0, sizeof(WIN32_FIND_DATAW)); - hFindFile = FindFirstFileW(zUnicodeName, &fd); - if( hFindFile!=NULL ){ - pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime); - pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime); - pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime); - FindClose(hFindFile); - } - sqlite3_free(zUnicodeName); - } -} -#endif +#endif /* _WIN32 */ /* ** This function is used in place of stat(). On Windows, special handling @@ -321,14 +274,22 @@ static int fileStat( STRUCT_STAT *pStatBuf ){ #if defined(_WIN32) - sqlite3_int64 sz = strlen(zPath); - wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); int rc; + wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath); if( b1==0 ) return 1; - sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); - b1[sz] = 0; rc = _wstat(b1, pStatBuf); - if( rc==0 ) statTimesToUtc(zPath, pStatBuf); + if( rc==0 ){ + HANDLE hFindFile; + WIN32_FIND_DATAW fd; + memset(&fd, 0, sizeof(WIN32_FIND_DATAW)); + hFindFile = FindFirstFileW(b1, &fd); + if( hFindFile!=NULL ){ + pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime); + pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime); + pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime); + FindClose(hFindFile); + } + } sqlite3_free(b1); return rc; #else @@ -1093,6 +1054,74 @@ static int fsdirRegister(sqlite3 *db){ # define fsdirRegister(x) SQLITE_OK #endif +/* +** The realpath() C-language function, implemented as an SQL function. +*/ +static void realpathFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ +#if !defined(_WIN32) /* BEGIN unix */ + + const char *zPath; /* Input */ + char *zOut = 0; /* Result */ + char *z = 0; /* Temporary buffer */ +#if defined(PATH_MAX) + char zBuf[PATH_MAX+1]; /* Space for the temporary buffer */ +#endif + + (void)argc; + zPath = (const char*)sqlite3_value_text(argv[0]); + if( zPath==0 ) return; + +#if defined(PATH_MAX) + z = realpath(zPath, zBuf); + if( z ){ + zOut = sqlite3_mprintf("%s", zBuf); + } +#endif /* defined(PATH_MAX) */ + if( zOut==0 ){ + /* Try POSIX.1-2008 malloc behavior */ + z = realpath(zPath, NULL); + if( z ){ + zOut = sqlite3_mprintf("%s", z); + free(z); + } + } + +#else /* End UNIX, Begin WINDOWS */ + + const char *zPath; /* Input */ + wchar_t *zPath16; /* UTF16 translation of zPath */ + char *zOut = 0; /* Result */ + wchar_t *z = 0; /* Temporary buffer */ + + (void)argc; + zPath = (const char*)sqlite3_value_text(argv[0]); + if( zPath==0 ) return; + + zPath16 = sqlite3_win32_utf8_to_unicode(zPath); + if( zPath16==0 ) return; + z = _wfullpath(NULL, zPath16, 0); + sqlite3_free(zPath16); + if( z==0 ){ + sqlite3_result_error(context, "unable to resolve path", -1); + return; + } + zOut = sqlite3_win32_unicode_to_utf8(z); + free(z); + +#endif /* End WINDOWS, Begin common code */ + + if( zOut==0 ){ + sqlite3_result_error(context, "unable to resolve path", -1); + return; + } + sqlite3_result_text(context, zOut, -1, sqlite3_free); +} + + #ifdef _WIN32 __declspec(dllexport) #endif @@ -1119,5 +1148,11 @@ int sqlite3_fileio_init( if( rc==SQLITE_OK ){ rc = fsdirRegister(db); } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "realpath", 1, + SQLITE_UTF8, 0, + realpathFunc, 0, 0); + } + return rc; } diff --git a/manifest b/manifest index 20186b546e..93d063c618 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypos\sand\sinclude\swording\sin\sthe\sdocumentation\sfor\nSQLITE_DBCONFIG_FP_DIGITS. -D 2026-02-21T21:19:41.549 +C Add\sthe\srealpath()\sSQL\sfunction\sto\sthe\sfileio.c\sextension.\s\sAnd\sclean\sup\nthe\sUTF8\shandling\son\sthe\sWindows\sside\sof\sthat\sextension\swhile\swe\sare\sat\sit. +D 2026-02-22T20:44:52.610 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -373,7 +373,7 @@ F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a0 F ext/misc/decimal.c e1da22eee70d7e3eaa99a6b761bc03c4d01d7ffa554bf3178b1f1f184932806c F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b -F ext/misc/fileio.c 452300ca34fadafd2bb9eb09557de5a518da1fd2349f9f9cedd22b1566a7164f +F ext/misc/fileio.c 6bbde149252e989fce657bfba66754dd7c545311546292cf33976e6b455a658c F ext/misc/fossildelta.c 86dfa83f85f7ccd640591d8a5c6865346d0c2ee6a949d78591eceb892f1cbfec F ext/misc/fuzzer.c 6b231352815304ba60d8e9ec2ee73d4918e74d9b76bda8940ba2b64e8777515e F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f16c7c4000f2b992f7245dcaf669f13ed464579f8894f3c16842eebf41285c70 -R 944ea7c224f9333bdc2c56f7b2ed487a +P c30cee1224904eb2092daa0ad9494aec7c7a8c6c1661f5b91b62c3ef0c5ea95b +R a026dfab96aebae2bd7cee1e81138b75 U drh -Z ef2f611c8a724472ddbfbfc7d613ba7b +Z 7731fd8c09c5128d6fba3a643ba9f80c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7193b3ed74..4077fe2836 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c30cee1224904eb2092daa0ad9494aec7c7a8c6c1661f5b91b62c3ef0c5ea95b +8bb8941930378b436f1353603be194644568b55fe347475be0caddddad40efa3 From 95fe5b9c38ca5700c21b8c3e6eee9dcaad4a0fa1 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 23 Feb 2026 00:57:00 +0000 Subject: [PATCH 043/197] Improved implementation of realpath() in the fileio.c extension that does not require the last element of the path to actually exist. FossilOrigin-Name: 4df4999484d9008d8af3c9c340810e0cf5f57161ba053ed5501276b450577039 --- ext/misc/fileio.c | 94 +++++++++++++++++++++++++++++++++-------------- manifest | 12 +++--- manifest.uuid | 2 +- 3 files changed, 74 insertions(+), 34 deletions(-) diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c index 876b397c70..e103d42332 100644 --- a/ext/misc/fileio.c +++ b/ext/misc/fileio.c @@ -94,6 +94,8 @@ SQLITE_EXTENSION_INIT1 # include # include # define STRUCT_STAT struct stat +# include +# include #else # include "windirent.h" # include @@ -1055,26 +1057,20 @@ static int fsdirRegister(sqlite3 *db){ #endif /* -** The realpath() C-language function, implemented as an SQL function. +** This version of realpath() works on any system. The string +** returned is held in memory allocated using sqlite3_malloc64(). +** The caller is responsible for calling sqlite3_free(). */ -static void realpathFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ +static char *portable_realpath(const char *zPath){ #if !defined(_WIN32) /* BEGIN unix */ - const char *zPath; /* Input */ char *zOut = 0; /* Result */ - char *z = 0; /* Temporary buffer */ + char *z; /* Temporary buffer */ #if defined(PATH_MAX) char zBuf[PATH_MAX+1]; /* Space for the temporary buffer */ #endif - (void)argc; - zPath = (const char*)sqlite3_value_text(argv[0]); - if( zPath==0 ) return; - + if( zPath==0 ) return 0; #if defined(PATH_MAX) z = realpath(zPath, zBuf); if( z ){ @@ -1089,36 +1085,81 @@ static void realpathFunc( free(z); } } + return zOut; #else /* End UNIX, Begin WINDOWS */ - const char *zPath; /* Input */ wchar_t *zPath16; /* UTF16 translation of zPath */ char *zOut = 0; /* Result */ wchar_t *z = 0; /* Temporary buffer */ - (void)argc; - zPath = (const char*)sqlite3_value_text(argv[0]); - if( zPath==0 ) return; + if( zPath==0 ) return 0; zPath16 = sqlite3_win32_utf8_to_unicode(zPath); - if( zPath16==0 ) return; + if( zPath16==0 ) return 0; z = _wfullpath(NULL, zPath16, 0); sqlite3_free(zPath16); - if( z==0 ){ - sqlite3_result_error(context, "unable to resolve path", -1); - return; + if( z ){ + zOut = sqlite3_win32_unicode_to_utf8(z); + free(z); } - zOut = sqlite3_win32_unicode_to_utf8(z); - free(z); + return zOut; #endif /* End WINDOWS, Begin common code */ +} - if( zOut==0 ){ - sqlite3_result_error(context, "unable to resolve path", -1); - return; +/* +** SQL function: realpath(X) +** +** Try to convert file or pathname X into its real, absolute pathname. +** Return NULL if unable. +** +** The file X is not required to exist. However, if any directory +** in the path to X does not exist, then the function returns NULL. +*/ +static void realpathFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zPath; + char *zOut; +#ifdef _WIN32 + const int isWin = 1; +#else + const int isWin = 0; +#endif + + (void)argc; + zPath = (const char*)sqlite3_value_text(argv[0]); + if( zPath==0 ) return; + if( zPath[0]==0 ) zPath = "."; + zOut = portable_realpath(zPath); + if( zOut==0 + && (strchr(zPath,'/') || (isWin && strchr(zPath,'\\'))) + ){ + char *zCopy = sqlite3_mprintf("%s", zPath); + size_t i; + char cSep = 0; + if( zCopy==0 ) return; + for(i = strlen(zCopy) - 1; i>0; i--){ + if( zCopy[i]=='/' || (isWin && zCopy[i]=='\\') ){ + cSep = zCopy[i]; + zCopy[i] = 0; + break; + } + } + if( cSep ){ + zOut = portable_realpath(zCopy); + if( zOut ){ + zOut = sqlite3_mprintf("%z%c%s",zOut,cSep,&zCopy[i+1]); + } + } + sqlite3_free(zCopy); + } + if( zOut ){ + sqlite3_result_text(context, zOut, -1, sqlite3_free); } - sqlite3_result_text(context, zOut, -1, sqlite3_free); } @@ -1153,6 +1194,5 @@ int sqlite3_fileio_init( SQLITE_UTF8, 0, realpathFunc, 0, 0); } - return rc; } diff --git a/manifest b/manifest index 93d063c618..f368ebcd13 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\srealpath()\sSQL\sfunction\sto\sthe\sfileio.c\sextension.\s\sAnd\sclean\sup\nthe\sUTF8\shandling\son\sthe\sWindows\sside\sof\sthat\sextension\swhile\swe\sare\sat\sit. -D 2026-02-22T20:44:52.610 +C Improved\simplementation\sof\srealpath()\sin\sthe\sfileio.c\sextension\sthat\sdoes\snot\srequire\nthe\slast\selement\sof\sthe\spath\sto\sactually\sexist. +D 2026-02-23T00:57:00.749 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -373,7 +373,7 @@ F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a0 F ext/misc/decimal.c e1da22eee70d7e3eaa99a6b761bc03c4d01d7ffa554bf3178b1f1f184932806c F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b -F ext/misc/fileio.c 6bbde149252e989fce657bfba66754dd7c545311546292cf33976e6b455a658c +F ext/misc/fileio.c 43f44347a4b70d22a7c1a68f799dc4ec4c58e39d84f04cebc6f669c6eadcb09b F ext/misc/fossildelta.c 86dfa83f85f7ccd640591d8a5c6865346d0c2ee6a949d78591eceb892f1cbfec F ext/misc/fuzzer.c 6b231352815304ba60d8e9ec2ee73d4918e74d9b76bda8940ba2b64e8777515e F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P c30cee1224904eb2092daa0ad9494aec7c7a8c6c1661f5b91b62c3ef0c5ea95b -R a026dfab96aebae2bd7cee1e81138b75 +P 8bb8941930378b436f1353603be194644568b55fe347475be0caddddad40efa3 +R 655393f8c2d5cab161b45421e875ddda U drh -Z 7731fd8c09c5128d6fba3a643ba9f80c +Z 730476000580ff31324acec73800a8e3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4077fe2836..dbb7963f69 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8bb8941930378b436f1353603be194644568b55fe347475be0caddddad40efa3 +4df4999484d9008d8af3c9c340810e0cf5f57161ba053ed5501276b450577039 From 9dac613f0437952476d977409318c456d1d2dd3e Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 23 Feb 2026 01:34:14 +0000 Subject: [PATCH 044/197] When doing an SQLAR archive extraction in the CLI, postpone creating symlinks until after all files and directories have been created. This prevents a hostile archive from creating a symlink through which it can subsequently write content outside of the target directory. [forum:forumpost/9e176adfef91c207|Forum post 9e176adfef91c207]. FossilOrigin-Name: 9719034d4d3becda127dc294f7f58ded9c982509c690dd55b56310912957eb51 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 32 ++++++++++++++++++++------------ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index f368ebcd13..0ad630f8bd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\simplementation\sof\srealpath()\sin\sthe\sfileio.c\sextension\sthat\sdoes\snot\srequire\nthe\slast\selement\sof\sthe\spath\sto\sactually\sexist. -D 2026-02-23T00:57:00.749 +C When\sdoing\san\sSQLAR\sarchive\sextraction\sin\sthe\sCLI,\spostpone\screating\ssymlinks\suntil\safter\nall\sfiles\sand\sdirectories\shave\sbeen\screated.\s\sThis\sprevents\sa\shostile\sarchive\sfrom\ncreating\sa\ssymlink\sthrough\swhich\sit\scan\ssubsequently\swrite\scontent\soutside\sof\sthe\starget\ndirectory.\s\s[forum:forumpost/9e176adfef91c207|Forum\spost\s9e176adfef91c207]. +D 2026-02-23T01:34:14.113 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -739,7 +739,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c -F src/shell.c.in 3e87584890a4e9797865e4771689d8d1aca3b0f824f973192784716ecfa320a2 +F src/shell.c.in 096db72b94687e46d7805e96c2a28fd1525fc6735d8967b9ce37b0b9dbbb9c90 F src/sqlite.h.in c7582608c8270428b288a529f4a4170298a19548266b55edaa2e70ce8d607f0e F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 8bb8941930378b436f1353603be194644568b55fe347475be0caddddad40efa3 -R 655393f8c2d5cab161b45421e875ddda +P 4df4999484d9008d8af3c9c340810e0cf5f57161ba053ed5501276b450577039 +R 536f614f7f299837eaceb0448191c5cb U drh -Z 730476000580ff31324acec73800a8e3 +Z 1a29d5706c125cd77c3ea8fb58018127 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index dbb7963f69..75b99ad74c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4df4999484d9008d8af3c9c340810e0cf5f57161ba053ed5501276b450577039 +9719034d4d3becda127dc294f7f58ded9c982509c690dd55b56310912957eb51 diff --git a/src/shell.c.in b/src/shell.c.in index 8eaa060812..f071e09bbf 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -6665,11 +6665,14 @@ static int arRemoveCommand(ArCommand *pAr){ */ static int arExtractCommand(ArCommand *pAr){ const char *zSql1 = - "SELECT " - " ($dir || name)," - " writefile(($dir || name), %s, mode, mtime) " - "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)" - " AND name NOT GLOB '*..[/\\]*'"; + "SELECT ($dir || name),\n" + " writefile(($dir || name), %s, mode, mtime)\n" + " FROM %s\n" + " WHERE (%s)\n" + " AND NOT ((mode&0xf000)==0x8000 AND $pass>0)\n" /* Files on pass 0 */ + " AND NOT (data IS NULL AND $pass==1)\n" /* Dirs on passes 0,2 */ + " AND NOT ((mode&0xf000)==0xa000 AND $pass<>1)\n" /* Symlink on pass 1 */ + " AND name NOT GLOB '*..[/\\]*'\n"; const char *azExtraArg[] = { "sqlar_uncompress(data, sz)", @@ -6705,16 +6708,21 @@ static int arExtractCommand(ArCommand *pAr){ j = sqlite3_bind_parameter_index(pSql, "$dir"); sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); - /* Run the SELECT statement twice. The first time, writefile() is called - ** for all archive members that should be extracted. The second time, - ** only for the directories. This is because the timestamps for - ** extracted directories must be reset after they are populated (as - ** populating them changes the timestamp). */ - for(i=0; i<2; i++){ - j = sqlite3_bind_parameter_index(pSql, "$dirOnly"); + /* Run the SELECT statement thrice: + ** (1) writefile() all files and directories, but not symlinks + ** (2) writefile() for symlinks + ** (3) writefile() for directory again + ** Symlinks are created after everything else to prevent writing content + ** through a symlink that was created by the extraction. + ** The third pass is so that the timestamps for extracted directories + ** will be reset to the value in the archive, since populating them + ** in the previous passes will have changed the timestamp. */ + for(i=0; i<3; i++){ + j = sqlite3_bind_parameter_index(pSql, "$pass"); sqlite3_bind_int(pSql, j, i); if( pAr->bDryRun ){ cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql)); + break; }else{ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ if( i==0 && pAr->bVerbose ){ From 9235f9b049c8795ad108cbffa495a141e9156405 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 23 Feb 2026 11:44:30 +0000 Subject: [PATCH 045/197] Enhance the realpath() SQL function in the fileio.c extension so that it works ever for pathnames that do not exist. FossilOrigin-Name: 27a5735fb1e194d763ab9fdb933fad4f694fb2f8ad19205d17ac81caebd82548 --- ext/misc/fileio.c | 87 ++++++++++++++++++++++++++++++++++------------- manifest | 12 +++---- manifest.uuid | 2 +- 3 files changed, 71 insertions(+), 30 deletions(-) diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c index e103d42332..51b748291a 100644 --- a/ext/misc/fileio.c +++ b/ext/misc/fileio.c @@ -1114,16 +1114,20 @@ static char *portable_realpath(const char *zPath){ ** Try to convert file or pathname X into its real, absolute pathname. ** Return NULL if unable. ** -** The file X is not required to exist. However, if any directory -** in the path to X does not exist, then the function returns NULL. +** The file or directory X is not required to exist. The answer is formed +** by calling system realpath() on the prefix of X that does exist and +** appending the tail of X that does not (yet) exist. */ static void realpathFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ - const char *zPath; - char *zOut; + const char *zPath; /* Original input path */ + char *zCopy; /* An editable copy of zPath */ + char *zOut; /* The result */ + char cSep = 0; /* Separator turned into \000 */ + size_t len; /* Prefix length before cSep */ #ifdef _WIN32 const int isWin = 1; #else @@ -1134,30 +1138,67 @@ static void realpathFunc( zPath = (const char*)sqlite3_value_text(argv[0]); if( zPath==0 ) return; if( zPath[0]==0 ) zPath = "."; - zOut = portable_realpath(zPath); - if( zOut==0 - && (strchr(zPath,'/') || (isWin && strchr(zPath,'\\'))) - ){ - char *zCopy = sqlite3_mprintf("%s", zPath); - size_t i; - char cSep = 0; - if( zCopy==0 ) return; - for(i = strlen(zCopy) - 1; i>0; i--){ - if( zCopy[i]=='/' || (isWin && zCopy[i]=='\\') ){ - cSep = zCopy[i]; - zCopy[i] = 0; - break; + zCopy = sqlite3_mprintf("%s",zPath); + len = strlen(zCopy); + while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){ + len--; + } + zCopy[len] = 0; + while( 1 /*exit-by-break*/ ){ + zOut = portable_realpath(zCopy); + zCopy[len] = cSep; + if( zOut ){ + if( cSep ){ + zOut = sqlite3_mprintf("%z%s",zOut,&zCopy[len]); } - } - if( cSep ){ - zOut = portable_realpath(zCopy); - if( zOut ){ - zOut = sqlite3_mprintf("%z%c%s",zOut,cSep,&zCopy[i+1]); + break; + }else{ + size_t i = len-1; + while( i>0 ){ + if( zCopy[i]=='/' || (isWin && zCopy[i]=='\\') ) break; + i--; + } + if( i<=0 ){ + if( zCopy[0]=='/' ){ + zOut = zCopy; + zCopy = 0; + }else if( (zOut = portable_realpath("."))!=0 ){ + zOut = sqlite3_mprintf("%z/%s", zOut, zCopy); + } + break; } + cSep = zCopy[i]; + zCopy[i] = 0; + len = i; } - sqlite3_free(zCopy); } + sqlite3_free(zCopy); if( zOut ){ + /* Simplify any "/./" or "/../" that might have snuck into the + ** pathname due to appending of zCopy. We only have to consider + ** unix "/" separators, because the _wfilepath() system call on + ** Windows will have already done this simplification for us. */ + size_t i, j, n; + n = strlen(zOut); + for(i=j=0; i0 && zOut[j-1]!='/' ){ j--; } + if( j>0 ){ j--; } + i += 2; + continue; + } + } + zOut[j++] = zOut[i]; + } + zOut[j] = 0; + + /* Return the result */ sqlite3_result_text(context, zOut, -1, sqlite3_free); } } diff --git a/manifest b/manifest index 0ad630f8bd..0d6b98c841 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\sdoing\san\sSQLAR\sarchive\sextraction\sin\sthe\sCLI,\spostpone\screating\ssymlinks\suntil\safter\nall\sfiles\sand\sdirectories\shave\sbeen\screated.\s\sThis\sprevents\sa\shostile\sarchive\sfrom\ncreating\sa\ssymlink\sthrough\swhich\sit\scan\ssubsequently\swrite\scontent\soutside\sof\sthe\starget\ndirectory.\s\s[forum:forumpost/9e176adfef91c207|Forum\spost\s9e176adfef91c207]. -D 2026-02-23T01:34:14.113 +C Enhance\sthe\srealpath()\sSQL\sfunction\sin\sthe\sfileio.c\sextension\nso\sthat\sit\sworks\sever\sfor\spathnames\sthat\sdo\snot\sexist. +D 2026-02-23T11:44:30.800 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -373,7 +373,7 @@ F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a0 F ext/misc/decimal.c e1da22eee70d7e3eaa99a6b761bc03c4d01d7ffa554bf3178b1f1f184932806c F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b -F ext/misc/fileio.c 43f44347a4b70d22a7c1a68f799dc4ec4c58e39d84f04cebc6f669c6eadcb09b +F ext/misc/fileio.c 33165b3cd99f83dcd333a338eb51491f6b01c8d96cb6ae81f96a6a096834e030 F ext/misc/fossildelta.c 86dfa83f85f7ccd640591d8a5c6865346d0c2ee6a949d78591eceb892f1cbfec F ext/misc/fuzzer.c 6b231352815304ba60d8e9ec2ee73d4918e74d9b76bda8940ba2b64e8777515e F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 4df4999484d9008d8af3c9c340810e0cf5f57161ba053ed5501276b450577039 -R 536f614f7f299837eaceb0448191c5cb +P 9719034d4d3becda127dc294f7f58ded9c982509c690dd55b56310912957eb51 +R bf2d4ba90ab9cecc4df495425f391fd6 U drh -Z 1a29d5706c125cd77c3ea8fb58018127 +Z 7b2a1df61967b73bec8a68ebbc48bbf5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 75b99ad74c..b84b3aaf79 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9719034d4d3becda127dc294f7f58ded9c982509c690dd55b56310912957eb51 +27a5735fb1e194d763ab9fdb933fad4f694fb2f8ad19205d17ac81caebd82548 From ffd9892a023ea3b66a0dc8de39cc8829e39bb1ec Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 23 Feb 2026 12:19:05 +0000 Subject: [PATCH 046/197] Change the SQLAR archive extraction algorithm in the CLI so that it uses the newly enhanced realpath() SQL function to guard against attacks that use symlinks to try to write files outside of the destination directory. [forum:/forumpost/641b09daa17d9086|Forum post 641b09daa17d9086]. FossilOrigin-Name: 7cced53e8c508fbf1816162c5358c77a712f76a38fd18f07171efc3c028a3c57 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 42 +++++++++++++++++++++--------------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/manifest b/manifest index 0d6b98c841..d8e909b52f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\srealpath()\sSQL\sfunction\sin\sthe\sfileio.c\sextension\nso\sthat\sit\sworks\sever\sfor\spathnames\sthat\sdo\snot\sexist. -D 2026-02-23T11:44:30.800 +C Change\sthe\sSQLAR\sarchive\sextraction\salgorithm\sin\sthe\sCLI\sso\sthat\sit\nuses\sthe\snewly\senhanced\srealpath()\sSQL\sfunction\sto\sguard\sagainst\nattacks\sthat\suse\ssymlinks\sto\stry\sto\swrite\sfiles\soutside\sof\sthe\ndestination\sdirectory.\n[forum:/forumpost/641b09daa17d9086|Forum\spost\s641b09daa17d9086]. +D 2026-02-23T12:19:05.604 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -739,7 +739,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c -F src/shell.c.in 096db72b94687e46d7805e96c2a28fd1525fc6735d8967b9ce37b0b9dbbb9c90 +F src/shell.c.in 2acdfca982deb70cdfefb8b422822d4e0234fe4dde6ff2bd9020b26445853917 F src/sqlite.h.in c7582608c8270428b288a529f4a4170298a19548266b55edaa2e70ce8d607f0e F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 9719034d4d3becda127dc294f7f58ded9c982509c690dd55b56310912957eb51 -R bf2d4ba90ab9cecc4df495425f391fd6 +P 27a5735fb1e194d763ab9fdb933fad4f694fb2f8ad19205d17ac81caebd82548 +R 5f3ef586ef29ee2dd47a3c1f07f1d05a U drh -Z 7b2a1df61967b73bec8a68ebbc48bbf5 +Z 1ae541096a3f2b3c5c84a58179012397 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b84b3aaf79..2c985e691c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -27a5735fb1e194d763ab9fdb933fad4f694fb2f8ad19205d17ac81caebd82548 +7cced53e8c508fbf1816162c5358c77a712f76a38fd18f07171efc3c028a3c57 diff --git a/src/shell.c.in b/src/shell.c.in index f071e09bbf..fb1dc2c2cd 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -6665,14 +6665,15 @@ static int arRemoveCommand(ArCommand *pAr){ */ static int arExtractCommand(ArCommand *pAr){ const char *zSql1 = + "WITH dest(dpath,dlen) AS (SELECT realpath($dir),length(realpath($dir)))\n" "SELECT ($dir || name),\n" - " writefile(($dir || name), %s, mode, mtime)\n" - " FROM %s\n" + " CASE WHEN $dryrun THEN 0\n" + " ELSE writefile($dir||name, %s, mode, mtime) END\n" + " FROM dest CROSS JOIN %s\n" " WHERE (%s)\n" - " AND NOT ((mode&0xf000)==0x8000 AND $pass>0)\n" /* Files on pass 0 */ - " AND NOT (data IS NULL AND $pass==1)\n" /* Dirs on passes 0,2 */ - " AND NOT ((mode&0xf000)==0xa000 AND $pass<>1)\n" /* Symlink on pass 1 */ - " AND name NOT GLOB '*..[/\\]*'\n"; + " AND (data IS NULL OR $pass==0)\n" /* Dirs both passes */ + " AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */ + " AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */ const char *azExtraArg[] = { "sqlar_uncompress(data, sz)", @@ -6707,29 +6708,28 @@ static int arExtractCommand(ArCommand *pAr){ if( rc==SQLITE_OK ){ j = sqlite3_bind_parameter_index(pSql, "$dir"); sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); + j = sqlite3_bind_parameter_index(pSql, "$dryrun"); + sqlite3_bind_int(pSql, j, pAr->bDryRun); - /* Run the SELECT statement thrice: - ** (1) writefile() all files and directories, but not symlinks - ** (2) writefile() for symlinks - ** (3) writefile() for directory again - ** Symlinks are created after everything else to prevent writing content - ** through a symlink that was created by the extraction. - ** The third pass is so that the timestamps for extracted directories + /* Run the SELECT statement twice + ** (0) writefile() all files and directories + ** (1) writefile() for directory again + ** The second pass is so that the timestamps for extracted directories ** will be reset to the value in the archive, since populating them - ** in the previous passes will have changed the timestamp. */ - for(i=0; i<3; i++){ + ** in the first pass will have changed the timestamp. */ + for(i=0; i<2; i++){ j = sqlite3_bind_parameter_index(pSql, "$pass"); sqlite3_bind_int(pSql, j, i); if( pAr->bDryRun ){ cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql)); - break; - }else{ - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ - if( i==0 && pAr->bVerbose ){ - cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); - } + if( pAr->bVerbose==0 ) break; + } + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ + if( i==0 && pAr->bVerbose ){ + cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); } } + if( pAr->bDryRun ) break; shellReset(&rc, pSql); } shellFinalize(&rc, pSql); From d2e27e5d54db8a0350e4e687988d4e7d54fe0882 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 23 Feb 2026 13:29:29 +0000 Subject: [PATCH 047/197] Add test cases for the symlink defenses of the previous check-in. FossilOrigin-Name: 5da9bf09cc00faf98cc515fb5a10a0af325b8f7608893808d031dfef62380be2 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/shell8.test | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index d8e909b52f..62bd48113b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sSQLAR\sarchive\sextraction\salgorithm\sin\sthe\sCLI\sso\sthat\sit\nuses\sthe\snewly\senhanced\srealpath()\sSQL\sfunction\sto\sguard\sagainst\nattacks\sthat\suse\ssymlinks\sto\stry\sto\swrite\sfiles\soutside\sof\sthe\ndestination\sdirectory.\n[forum:/forumpost/641b09daa17d9086|Forum\spost\s641b09daa17d9086]. -D 2026-02-23T12:19:05.604 +C Add\stest\scases\sfor\sthe\ssymlink\sdefenses\sof\sthe\sprevious\scheck-in. +D 2026-02-23T13:29:29.514 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -1626,7 +1626,7 @@ F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db28 F test/shell5.test a9cd2c8b62e125049ef500937674f47dd6787f0157ac0515aa554044a4dc3ea9 F test/shell6.test e3b883b61d4916b6906678a35f9d19054861123ad91b856461e0a456273bdbb8 F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d5c3 -F test/shell8.test 641cf21a99c59404c24e3062923734951c4099a6b6b6520de00cf7a1249ee871 +F test/shell8.test fc3b6ca51ffba9b4b658d4c65a07b50338a2b592a276a66b8464be448d0f5e30 F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209 F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480 F test/shellB.test b2afd5c28aba750c066996a082210d6a4fcab8fd042cad076d9c1023164af9b1 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 27a5735fb1e194d763ab9fdb933fad4f694fb2f8ad19205d17ac81caebd82548 -R 5f3ef586ef29ee2dd47a3c1f07f1d05a +P 7cced53e8c508fbf1816162c5358c77a712f76a38fd18f07171efc3c028a3c57 +R 759eaf7b561ab385ab020df9b6f9eba9 U drh -Z 1ae541096a3f2b3c5c84a58179012397 +Z 1cdbe80a45cdf36eafc051b6689caa6d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2c985e691c..b5fdeb09b2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7cced53e8c508fbf1816162c5358c77a712f76a38fd18f07171efc3c028a3c57 +5da9bf09cc00faf98cc515fb5a10a0af325b8f7608893808d031dfef62380be2 diff --git a/test/shell8.test b/test/shell8.test index e555396365..2e0581bafb 100644 --- a/test/shell8.test +++ b/test/shell8.test @@ -217,6 +217,46 @@ if {$tcl_platform(platform)=="unix"} { do_test 3.3 { catchcmd shell8.db {.ar -x} } {0 {}} + + # Test defenses against using symlinks to write outside + # of the destination directory. See forum thread at + # sqlite.org/forum/forumpost/2026-02-21T11:04:36z + # + forcedelete shell8.db + forcedelete ar1 + forcedelete ar2 + forcedelete ar3 + file mkdir ar2 + file mkdir ar3 + set pwd [pwd] + sqlite3 db shell8.db + db eval { + CREATE TABLE sqlar( + name TEXT PRIMARY KEY, -- name of the file + mode INT, -- access permissions + mtime INT, -- last modification time + sz INT, -- original file size + data BLOB -- compressed content + ); + INSERT INTO sqlar VALUES + ('abc',33188,0,-1,'content for abc'), + ('escape',40960,0,-1,$pwd||'/ar3'), + ('escape/def',33188,0,-1,'content for escape/def'), + ('ghi',33188,0,-1,'content for ghi'); + } + do_test 3.4.1 { + catchcmd shell8.db {.ar -x --directory ar2} + lsort [glob -tails -directory ar2 *] + } {abc escape ghi} + do_test 3.4.2 { + lsort [glob -tails -directory ar3 *] + } {} + # ^^--- An extraction into ar2 should not leak any files into ar3 + + forcedelete shell8.db + forcedelete ar2 + forcedelete ar3 + } finish_test From da67225f04ad0470b54433fee31baf266e6630ef Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 23 Feb 2026 19:51:54 +0000 Subject: [PATCH 048/197] Fix an assert() that is incorrect when the SQLITE_DBCONFIG_FP_DIGITS setting is on a non-default value. FossilOrigin-Name: 3ca1ed81c4fa41f5f9fdbebf0929dd8421a4e29f95764fe1027d4d8706a41480 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbemem.c | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 62bd48113b..e9a0b51ce1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stest\scases\sfor\sthe\ssymlink\sdefenses\sof\sthe\sprevious\scheck-in. -D 2026-02-23T13:29:29.514 +C Fix\san\sassert()\sthat\sis\sincorrect\swhen\sthe\sSQLITE_DBCONFIG_FP_DIGITS\ssetting\nis\son\sa\snon-default\svalue. +D 2026-02-23T19:51:54.706 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -811,7 +811,7 @@ F src/vdbeInt.h 42488247a80cd9d300627833c6c85ace067ae5011a99e7614e2358130d62feea F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1 F src/vdbeaux.c 396d38a62a357b807eabae0cae441fc89d2767a57ab08026b7072bf7aa2dd00c F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692 -F src/vdbemem.c 565c214150dbab0678bfb04db5488f1788df87aad4ec3ec71cc61e0eb3f18f38 +F src/vdbemem.c 2eddebf6403f2811c7049ddbb1dd96d5f63617b39fcbaa2384009a45b2269006 F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70 F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 7cced53e8c508fbf1816162c5358c77a712f76a38fd18f07171efc3c028a3c57 -R 759eaf7b561ab385ab020df9b6f9eba9 +P 5da9bf09cc00faf98cc515fb5a10a0af325b8f7608893808d031dfef62380be2 +R 281306f1efa2da650e12d075418cdbc9 U drh -Z 1cdbe80a45cdf36eafc051b6689caa6d +Z a61e6702dddced0a140b817d52fd7496 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b5fdeb09b2..2eeedc28e6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5da9bf09cc00faf98cc515fb5a10a0af325b8f7608893808d031dfef62380be2 +3ca1ed81c4fa41f5f9fdbebf0929dd8421a4e29f95764fe1027d4d8706a41480 diff --git a/src/vdbemem.c b/src/vdbemem.c index 9e654858d3..e58b6629c4 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -175,6 +175,9 @@ int sqlite3VdbeMemValidStrRep(Mem *p){ assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 ); } if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1; + if( p->db==0 ){ + return 1; /* db->nFpDigit required to validate p->z[] */ + } memcpy(&tmp, p, sizeof(tmp)); vdbeMemRenderNum(sizeof(zBuf), zBuf, &tmp); z = p->z; From 9d6529020723bc4f2341931ddfd9d126ae36a575 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 24 Feb 2026 19:37:16 +0000 Subject: [PATCH 049/197] Rename SQLITE_ENABLE_MULTITHREADED_CHECKS to SQLITE_THREAD_MISUSE_WARNINGS. Run test cases with that option. Also add the SQLITE_THREAD_MISUSE_ABORT option. FossilOrigin-Name: be8c8b9cb7b618a1571a988bc1cfdc15d99a8bf144d699385c0076e940b9f7f5 --- manifest | 24 ++++++++++++------------ manifest.uuid | 2 +- src/main.c | 2 +- src/mutex.c | 24 ++++++++++++++++-------- src/sqliteInt.h | 15 ++++++++++++++- src/test_config.c | 8 ++++++++ test/mutex1.test | 26 ++++++++++++++++---------- test/testrunner_data.tcl | 1 + tool/omittest.tcl | 2 +- 9 files changed, 70 insertions(+), 34 deletions(-) diff --git a/manifest b/manifest index e9a0b51ce1..c29bae770c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sassert()\sthat\sis\sincorrect\swhen\sthe\sSQLITE_DBCONFIG_FP_DIGITS\ssetting\nis\son\sa\snon-default\svalue. -D 2026-02-23T19:51:54.706 +C Rename\sSQLITE_ENABLE_MULTITHREADED_CHECKS\sto\sSQLITE_THREAD_MISUSE_WARNINGS.\nRun\stest\scases\swith\sthat\soption.\sAlso\sadd\sthe\nSQLITE_THREAD_MISUSE_ABORT\soption. +D 2026-02-24T19:37:16.964 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -702,7 +702,7 @@ F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd F src/json.c 8b6341a419150b28530cc21e3951b2238c35cdc312f11b2ca29017fe4b1dedc0 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9 -F src/main.c 211f7721b191523b815dee6c6a1e9a5f3ebc052a0ddaaed24a75cf20bf9d4b06 +F src/main.c 31a13302193fbd51279c7e69cdfa0320d0de7629f9151e0964c1d320e8bdd7a4 F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2 @@ -712,7 +712,7 @@ F src/mem5.c b7da5c10a726aacacc9ad7cdcb0667deec643e117591cc69cf9b4b9e7f3e96ff F src/memdb.c a3feb427cdd4036ea2db0ba56d152f14c8212ca760ccb05fb7aa49ff6b897df3 F src/memjournal.c c283c6c95d940eb9dc70f1863eef3ee40382dbd35e5a1108026e7817c206e8a0 F src/msvc.h 80b35f95d93bf996ccb3e498535255f2ef1118c78764719a7cd15ab4106ccac9 -F src/mutex.c 06bcd9c3dbf2d9b21fcd182606c00fafb9bfe0287983c8e17acd13d2c81a2fa9 +F src/mutex.c 5dc0dd69c4216dd976bd463f4ee62a0fa0c24860c0815238ff205f62e194431f F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4 F src/mutex_unix.c f7ee5a2061a4c11815a2bf4fc0e2bfa6fb8d9dc89390eb613ca0cec32fc9a3d1 @@ -743,7 +743,7 @@ F src/shell.c.in 2acdfca982deb70cdfefb8b422822d4e0234fe4dde6ff2bd9020b2644585391 F src/sqlite.h.in c7582608c8270428b288a529f4a4170298a19548266b55edaa2e70ce8d607f0e F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h ffa3071dc3b9172acfe1a4edd8bc699928b0d5e02f0b8b9067676aa8e5f8f787 +F src/sqliteInt.h 185abb373dc2a311e3292540ef177ea301d8140b976ecd8ba381a5a0162cd6e9 F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -762,7 +762,7 @@ F src/test_backup.c a2bfd90d2ff2511b8635507bdb30fa9b605ade19c16b533066cae3077f5b F src/test_bestindex.c d75fad21369d80910238032bcf8d9ca1f2bffda13c1ceec63bfbb7f704448b15 F src/test_blob.c 77b994e17f2c87055f44fd96c9a206c5a7155bae2cda2769af60c2f3582f962c F src/test_btree.c 28283787d32b8fa953eb77412ad0de2c9895260e4e5bd5a94b3c7411664f90d5 -F src/test_config.c 9b6dac5bc4ab56c9c6289ca9a6a73a156e178e58bcfdac19a69f6e17e28ad5ac +F src/test_config.c e02566c2c4ee2916324ce17123a798b47663cead2de546cfbd71d8cddb46bb26 F src/test_delete.c d0e8f6dc55cfc98a7c27c057fb88d512260564bf0b611482656c68b8f7f401ed F src/test_demovfs.c 3efa2adf4f21e10d95521721687d5ca047aea91fa62dd8cc22ac9e5a9c942383 F src/test_devsym.c 649434ed34d0b03fbd5a6b42df80f0f9a7e53f94dd1710aad5dd8831e91c4e86 @@ -1454,7 +1454,7 @@ F test/multiplex.test d74c034e52805f6de8cc5432cef8c9eb774bb64ec29b83a22effc8ca4d F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test fac575e0b1b852025575a6a8357701d80933e98b5d2fe6d35ddaa68f92f6a1f7 F test/multiplex4.test e8ae4c4bd70606a5727743241f13b5701990abe4 -F test/mutex1.test 42cb5e244c3a77bb0ef2b967e06fa5e7ba7d32d90a9b20bed98f6f5ede185a25 +F test/mutex1.test 2cdc320a3320521d73b8090a04a2245c1e625e5f90672882517bf5fedcec8f13 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660 F test/nan.test 73ea63ab43668313e2f8cc9ef9e9a966672c7934f3ce76926fbe991235d07d91 F test/nockpt.test 3db354270fc63b6871eebd40285d4c55324fb27be629c958adbff6d7fcaa8e14 @@ -1715,7 +1715,7 @@ F test/temptrigger.test a00f258ed8d21a0e8fd4f322f15e8cfb5cef2e43655670e07a753e3f F test/tester.tcl 2d943f60200e0a36bcd3f1f0baf181a751cd3604ef6b6bd4c8dc39b4e8a53116 F test/testloadext.c 862b848783eaed9985fbce46c65cd214664376b549fae252b364d5d1ef350a27 F test/testrunner.tcl 78d67079fc39caf2af3fd9d4c30bdac78dae7ec50b9fc802835e7a5189581e07 x -F test/testrunner_data.tcl 87b8afd37c8e517fa87b7936540b2fc1ede8291f0567fb88744b9bff272a2e8b +F test/testrunner_data.tcl 078e251983c8fc573567125147655f68132210f226c92922daf21fb913779717 F test/testrunner_estwork.tcl 81e2ae10238f50540f42fbf2d94913052a99bfb494b69e546506323f195dcff9 F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899 F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502 @@ -2157,7 +2157,7 @@ F tool/mkvsix.tcl 67b40996a50f985a573278eea32fc5a5eb6110bdf14d33f1d8086e48c69e54 F tool/mkwinarm64ec.tcl 171f79234fa53552a129b360356df5599fdab15239caffb3d29c571292728033 F tool/offsets.c 8ed2b344d33f06e71366a9b93ccedaa38c096cc1dbd4c3c26ad08c6115285845 F tool/omittest-msvc.tcl d6b8f501ac1d7798c4126065030f89812379012cad98a1735d6d7221492abc08 -F tool/omittest.tcl bec70ef0e16255c8d9eb06ecd7edf823c07a60a836186cdbce3528fb34b67995 +F tool/omittest.tcl 436b7072e00e25e9b77145a9f67aa8e0eeabd186168827435fd03f8f981aac32 F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a F tool/pagesig.c f98909b4168d9cac11a2de7f031adea0e2f3131faa7515a72807c03ec58eafeb F tool/replace.tcl 511c61acfe563dfb58675efb4628bb158a13d48ff8322123ac447e9d25a82d9a @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 5da9bf09cc00faf98cc515fb5a10a0af325b8f7608893808d031dfef62380be2 -R 281306f1efa2da650e12d075418cdbc9 +P 3ca1ed81c4fa41f5f9fdbebf0929dd8421a4e29f95764fe1027d4d8706a41480 +R 5c6421821f79cf8e5629e0b605fa5e03 U drh -Z a61e6702dddced0a140b817d52fd7496 +Z f5b0ef52b5c43aa0e22df96a7972ea83 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2eeedc28e6..57095c535f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3ca1ed81c4fa41f5f9fdbebf0929dd8421a4e29f95764fe1027d4d8706a41480 +be8c8b9cb7b618a1571a988bc1cfdc15d99a8bf144d699385c0076e940b9f7f5 diff --git a/src/main.c b/src/main.c index a3bfe6d137..b44ac8dca8 100644 --- a/src/main.c +++ b/src/main.c @@ -3386,7 +3386,7 @@ static int openDatabase( db = sqlite3MallocZero( sizeof(sqlite3) ); if( db==0 ) goto opendb_out; if( isThreadsafe -#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +#if defined(SQLITE_THREAD_MISUSE_WARNINGS) || sqlite3GlobalConfig.bCoreMutex #endif ){ diff --git a/src/mutex.c b/src/mutex.c index 62e09cb4fa..f0936af91d 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -27,23 +27,28 @@ static SQLITE_WSD int mutexIsInit = 0; #ifndef SQLITE_MUTEX_OMIT -#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +#ifdef SQLITE_THREAD_MISUSE_WARNINGS /* -** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains +** This block (enclosed by SQLITE_THREAD_MISUSE_WARNINGS) contains ** the implementation of a wrapper around the system default mutex ** implementation (sqlite3DefaultMutex()). ** ** Most calls are passed directly through to the underlying default ** mutex implementation. Except, if a mutex is configured by calling ** sqlite3MutexWarnOnContention() on it, then if contention is ever -** encountered within xMutexEnter() a warning is emitted via sqlite3_log(). +** encountered within xMutexEnter() then a warning is emitted via +** sqlite3_log(). Furthermore, if SQLITE_THREAD_MISUSE_ABORT is +** defined then abort() is called after the sqlite3_log() warning. ** -** This type of mutex is used as the database handle mutex when testing -** apps that usually use SQLITE_CONFIG_MULTITHREAD mode. +** This type of mutex is used on the database handle mutex when testing +** apps that usually use SQLITE_CONFIG_MULTITHREAD mode. A failure +** indicates that the app ought to be using SQLITE_OPEN_FULLMUTEX or +** similar because it is trying to use the same database handle from +** two different connections at the same time. */ /* -** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS +** Type for all mutexes used when SQLITE_THREAD_MISUSE_WARNINGS ** is defined. Variable CheckMutex.mutex is a pointer to the real mutex ** allocated by the system mutex implementation. Variable iType is usually set ** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST @@ -160,6 +165,9 @@ static void checkMutexEnter(sqlite3_mutex *p){ sqlite3_log(SQLITE_MISUSE, "illegal multi-threaded access to database connection" ); +#if SQLITE_THREAD_MISUSE_ABORT + abort(); +#endif } pGlobalMutexMethods->xMutexEnter(pCheck->mutex); } @@ -211,7 +219,7 @@ void sqlite3MutexWarnOnContention(sqlite3_mutex *p){ pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION; } } -#endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */ +#endif /* ifdef SQLITE_THREAD_MISUSE_WARNINGS */ /* ** Initialize the mutex system. @@ -228,7 +236,7 @@ int sqlite3MutexInit(void){ sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex; if( sqlite3GlobalConfig.bCoreMutex ){ -#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +#ifdef SQLITE_THREAD_MISUSE_WARNINGS pFrom = multiThreadedCheckMutex(); #else pFrom = sqlite3DefaultMutex(); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 051cb4e874..795f874b61 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4787,7 +4787,20 @@ int sqlite3LookasideUsed(sqlite3*,int*); sqlite3_mutex *sqlite3Pcache1Mutex(void); sqlite3_mutex *sqlite3MallocMutex(void); -#if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT) + +/* The SQLITE_THREAD_MISUSE_WARNINGS compile-time option used to be called +** SQLITE_ENABLE_MULTITHREADED_CHECKS. Keep that older macro for backwards +** compatibility, at least for a while... */ +#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +# define SQLITE_THREAD_MISUSE_WARNINGS 1 +#endif + +/* SQLITE_THREAD_MISUSE_ABORT implies SQLITE_THREAD_MISUSE_WARNINGS */ +#ifdef SQLITE_THREAD_MISUSE_ABORT +# define SQLITE_THREAD_MISUSE_WARNINGS 1 +#endif + +#if defined(SQLITE_THREAD_MISUSE_WARNINGS) && !defined(SQLITE_MUTEX_OMIT) void sqlite3MutexWarnOnContention(sqlite3_mutex*); #else # define sqlite3MutexWarnOnContention(x) diff --git a/src/test_config.c b/src/test_config.c index 5d0f419ec3..bebf8625ae 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -679,6 +679,14 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "trace", "1", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_THREAD_MISUSE_WARNINGS + Tcl_SetVar2(interp, "sqlite_options", "thread_misuse_warnings", + "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "thread_misuse_warnings", + "0", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_OMIT_TRIGGER Tcl_SetVar2(interp, "sqlite_options", "trigger", "0", TCL_GLOBAL_ONLY); #else diff --git a/test/mutex1.test b/test/mutex1.test index cb189a7a8a..de291f4c91 100644 --- a/test/mutex1.test +++ b/test/mutex1.test @@ -115,6 +115,10 @@ ifcapable threadsafe1&&shared_cache { } } { + ifcapable thread_misuse_warnings { + if {$mode ne "serialized"} continue + } + # For journal_mode=memory, the static_prng mutex is not required. This # is because the header of an in-memory journal does not contain # any random bytes, and so no call to sqlite3_randomness() is made. @@ -177,16 +181,18 @@ ifcapable threadsafe1&&shared_cache { # Open and use a connection in "nomutex" mode. Test that no recursive # mutexes are obtained. - do_test mutex1.3.1 { - catch {db close} - clear_mutex_counters - sqlite3 db test.db -nomutex 1 - execsql { SELECT * FROM abc } - } {1 2 3 1 2 3 1 2 3} - do_test mutex1.3.2 { - mutex_counters counters - set counters(recursive) - } {0} + ifcapable !thread_misuse_warnings { + do_test mutex1.3.1 { + catch {db close} + clear_mutex_counters + sqlite3 db test.db -nomutex 1 + execsql { SELECT * FROM abc } + } {1 2 3 1 2 3 1 2 3} + do_test mutex1.3.2 { + mutex_counters counters + set counters(recursive) + } {0} + } } # Test the sqlite3_db_mutex() function. diff --git a/test/testrunner_data.tcl b/test/testrunner_data.tcl index 845f2245c3..4daee02745 100644 --- a/test/testrunner_data.tcl +++ b/test/testrunner_data.tcl @@ -192,6 +192,7 @@ namespace eval trd { -DSQLITE_ENABLE_HIDDEN_COLUMNS -DSQLITE_MAX_ATTACHED=125 -DSQLITE_MUTATION_TEST + -DSQLITE_THREAD_MISUSE_ABORT --enable-fts5 } set build(Debug-Two) { diff --git a/tool/omittest.tcl b/tool/omittest.tcl index 0452a4c6f6..03c9220cda 100644 --- a/tool/omittest.tcl +++ b/tool/omittest.tcl @@ -123,7 +123,6 @@ set CompileOptionsToTest { SQLITE_ENABLE_MEMSYS SQLITE_ENABLE_MODULE_COMMENTS SQLITE_ENABLE_MULTIPLEX - SQLITE_ENABLE_MULTITHREADED_CHECKS SQLITE_ENABLE_NORMALIZE SQLITE_ENABLE_NULL_TRIM SQLITE_ENABLE_OFFSET_SQL_FUNC @@ -152,6 +151,7 @@ set CompileOptionsToTest { SQLITE_ENABLE_VFSTRACE SQLITE_ENABLE_WHERETRACE SQLITE_ENABLE_ZIPVFS + SQLITE_THREAD_MISUSE_WARNINGS } # Parse command-line options. From b1a73ba34d05b32007315e4065c6468cc638e3af Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 24 Feb 2026 19:50:27 +0000 Subject: [PATCH 050/197] Adjust the changes to shell8.test from [5da9bf09cc00faf9] so that they work with older versions of TCL. FossilOrigin-Name: c3b9e2cee3565da50bcc92766f700c31142391a697cbab7465774cf20a307dd8 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/shell8.test | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index c29bae770c..04cf958c30 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rename\sSQLITE_ENABLE_MULTITHREADED_CHECKS\sto\sSQLITE_THREAD_MISUSE_WARNINGS.\nRun\stest\scases\swith\sthat\soption.\sAlso\sadd\sthe\nSQLITE_THREAD_MISUSE_ABORT\soption. -D 2026-02-24T19:37:16.964 +C Adjust\sthe\schanges\sto\sshell8.test\sfrom\s[5da9bf09cc00faf9]\sso\sthat\sthey\nwork\swith\solder\sversions\sof\sTCL. +D 2026-02-24T19:50:27.370 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -1626,7 +1626,7 @@ F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db28 F test/shell5.test a9cd2c8b62e125049ef500937674f47dd6787f0157ac0515aa554044a4dc3ea9 F test/shell6.test e3b883b61d4916b6906678a35f9d19054861123ad91b856461e0a456273bdbb8 F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d5c3 -F test/shell8.test fc3b6ca51ffba9b4b658d4c65a07b50338a2b592a276a66b8464be448d0f5e30 +F test/shell8.test 38c9e4d7e85d2a3ecfacaa9f6cda4f7a81bf4fffb5f3f37f9cd76827c6883192 F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209 F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480 F test/shellB.test b2afd5c28aba750c066996a082210d6a4fcab8fd042cad076d9c1023164af9b1 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 3ca1ed81c4fa41f5f9fdbebf0929dd8421a4e29f95764fe1027d4d8706a41480 -R 5c6421821f79cf8e5629e0b605fa5e03 +P be8c8b9cb7b618a1571a988bc1cfdc15d99a8bf144d699385c0076e940b9f7f5 +R 09366efa0ae6da108ede7866c4a5981c U drh -Z f5b0ef52b5c43aa0e22df96a7972ea83 +Z 5db1abeb187d1d013a8be468216382aa # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 57095c535f..bd84eacf03 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -be8c8b9cb7b618a1571a988bc1cfdc15d99a8bf144d699385c0076e940b9f7f5 +c3b9e2cee3565da50bcc92766f700c31142391a697cbab7465774cf20a307dd8 diff --git a/test/shell8.test b/test/shell8.test index 2e0581bafb..40579a599d 100644 --- a/test/shell8.test +++ b/test/shell8.test @@ -246,10 +246,10 @@ if {$tcl_platform(platform)=="unix"} { } do_test 3.4.1 { catchcmd shell8.db {.ar -x --directory ar2} - lsort [glob -tails -directory ar2 *] + lsort [glob -tails -directory ar2 -nocomplain *] } {abc escape ghi} do_test 3.4.2 { - lsort [glob -tails -directory ar3 *] + lsort [glob -tails -directory ar3 -nocomplain *] } {} # ^^--- An extraction into ar2 should not leak any files into ar3 From 46bf39e3962babd1d722ea6ecaa16b24b852a8ba Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 25 Feb 2026 01:04:22 +0000 Subject: [PATCH 051/197] Use a 64-bit hash for the testing option SQLITE_CHECK_PAGES to maintain page alignment. FossilOrigin-Name: 75a35cd8f97f8a6cd2311c829685bd3b1cfb394de15174aef347f15cfb1913a1 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/pager.c | 8 ++++---- src/pcache.h | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 04cf958c30..e1887b1708 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Adjust\sthe\schanges\sto\sshell8.test\sfrom\s[5da9bf09cc00faf9]\sso\sthat\sthey\nwork\swith\solder\sversions\sof\sTCL. -D 2026-02-24T19:50:27.370 +C Use\sa\s64-bit\shash\sfor\sthe\stesting\soption\sSQLITE_CHECK_PAGES\sto\smaintain\npage\salignment. +D 2026-02-25T01:04:22.306 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -726,11 +726,11 @@ F src/os_setup.h 8efc64eda6a6c2f221387eefc2e7e45fd5a3d5c8337a7a83519ba4fbd2957ae F src/os_unix.c dcf7988ddbdd68619b821c9a722f9377abb46f1d26c9279eb5a50402fd43d749 F src/os_win.c 0d553b6e8b92c8eb85e7f1b4a8036fe8638c8b32c9ad8d9d72a861c10f81b4c5 F src/os_win.h 5e168adf482484327195d10f9c3bce3520f598e04e07ffe62c9c5a8067c1037b -F src/pager.c a81461de271ac4886ad75b7ca2cca8157a48635820c4646cd2714acdc2c17e5f +F src/pager.c fe34fd22ec251436985d7b6ebdd05bf238a17901c2cb23d3d28974dd2361a912 F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8 F src/parse.y 7c2184b5665c671258c4e96a10bbc9dbf7e1ede462ebc4e614249de0d54c8a26 F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484 -F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 +F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P be8c8b9cb7b618a1571a988bc1cfdc15d99a8bf144d699385c0076e940b9f7f5 -R 09366efa0ae6da108ede7866c4a5981c +P c3b9e2cee3565da50bcc92766f700c31142391a697cbab7465774cf20a307dd8 +R f3287272bab54c42208ca20f46460827 U drh -Z 5db1abeb187d1d013a8be468216382aa +Z 3c6ddaa5a6b8277e3edc3f70592591fc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bd84eacf03..c40677af38 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c3b9e2cee3565da50bcc92766f700c31142391a697cbab7465774cf20a307dd8 +75a35cd8f97f8a6cd2311c829685bd3b1cfb394de15174aef347f15cfb1913a1 diff --git a/src/pager.c b/src/pager.c index 1e03b87ec0..61b391d6b4 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1235,17 +1235,17 @@ static int jrnlBufferSize(Pager *pPager){ */ #ifdef SQLITE_CHECK_PAGES /* -** Return a 32-bit hash of the page data for pPage. +** Return a 64-bit hash of the page data for pPage. */ -static u32 pager_datahash(int nByte, unsigned char *pData){ - u32 hash = 0; +static u64 pager_datahash(int nByte, unsigned char *pData){ + u64 hash = 0; int i; for(i=0; ipPager->pageSize, (unsigned char *)pPage->pData); } static void pager_set_pagehash(PgHdr *pPage){ diff --git a/src/pcache.h b/src/pcache.h index f945dab1a4..dafb593904 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -29,10 +29,10 @@ struct PgHdr { PCache *pCache; /* PRIVATE: Cache that owns this page */ PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ Pager *pPager; /* The pager this page is part of */ - Pgno pgno; /* Page number for this page */ #ifdef SQLITE_CHECK_PAGES - u32 pageHash; /* Hash of page content */ + u64 pageHash; /* Hash of page content */ #endif + Pgno pgno; /* Page number for this page */ u16 flags; /* PGHDR flags defined below */ /********************************************************************** From f45c695471a0001d471840a228c7d24d15799ff1 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 25 Feb 2026 12:44:19 +0000 Subject: [PATCH 052/197] Reinstant the work-around for [https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270|GCC compiler bug 96270] which is apparently still an issue as of gcc 13.3.0 with -m32 on Mint Linux. The test case in the bug report is fixed, but the vdbeMemRenderNum() routine in SQLite still shows the problem. FossilOrigin-Name: 7fae321095ebec775de1b39b974fb1f295d5efbd5723e9cb29a981c97a4262c8 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbemem.c | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index e1887b1708..f13241de98 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\sa\s64-bit\shash\sfor\sthe\stesting\soption\sSQLITE_CHECK_PAGES\sto\smaintain\npage\salignment. -D 2026-02-25T01:04:22.306 +C Reinstant\sthe\swork-around\sfor\s[https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270|GCC\scompiler\sbug\s96270]\nwhich\sis\sapparently\sstill\san\sissue\sas\sof\sgcc\s13.3.0\swith\s-m32\son\sMint\sLinux.\nThe\stest\scase\sin\sthe\sbug\sreport\sis\sfixed,\sbut\sthe\svdbeMemRenderNum()\sroutine\nin\sSQLite\sstill\sshows\sthe\sproblem. +D 2026-02-25T12:44:19.970 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -811,7 +811,7 @@ F src/vdbeInt.h 42488247a80cd9d300627833c6c85ace067ae5011a99e7614e2358130d62feea F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1 F src/vdbeaux.c 396d38a62a357b807eabae0cae441fc89d2767a57ab08026b7072bf7aa2dd00c F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692 -F src/vdbemem.c 2eddebf6403f2811c7049ddbb1dd96d5f63617b39fcbaa2384009a45b2269006 +F src/vdbemem.c 401a320db404ce7e51f94a69cca30b2737d74d3b8e9ab272287cbfccdc9ffd10 F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70 F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P c3b9e2cee3565da50bcc92766f700c31142391a697cbab7465774cf20a307dd8 -R f3287272bab54c42208ca20f46460827 +P 75a35cd8f97f8a6cd2311c829685bd3b1cfb394de15174aef347f15cfb1913a1 +R a056b439b6d5d9d4c93ec16898c6d538 U drh -Z 3c6ddaa5a6b8277e3edc3f70592591fc +Z e627ce35647ad04f6d121e351748c96b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c40677af38..4bef84000b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -75a35cd8f97f8a6cd2311c829685bd3b1cfb394de15174aef347f15cfb1913a1 +7fae321095ebec775de1b39b974fb1f295d5efbd5723e9cb29a981c97a4262c8 diff --git a/src/vdbemem.c b/src/vdbemem.c index e58b6629c4..09f94cb585 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -108,13 +108,13 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); assert( sz>22 ); if( p->flags & (MEM_Int|MEM_IntReal) ){ -#if 0 +#if GCC_VERSION>=7000000 && defined(__i386__) /* Work-around for GCC bug - ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270. - ** Bug fixed circa 2020, so this work-around removed in 2026. */ + ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 + ** This is still an issue as of 2026-02-25, GCC 13.3.0 with -m32 */ i64 x; - assert( (p->flags&MEM_Int)*2==sizeof(x) ); - memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2); + assert( (MEM_Str&~p->flags)*4==sizeof(x) ); + memcpy(&x, (char*)&p->u, (MEM_Str&~p->flags)*4); p->n = sqlite3Int64ToText(x, zBuf); #else p->n = sqlite3Int64ToText(p->u.i, zBuf); From 1a152ea92a0b95ca7b7ee232fbc0fdde9c1a7c90 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 25 Feb 2026 21:19:20 +0000 Subject: [PATCH 053/197] The GCC bug is fixed in GCC-15. FossilOrigin-Name: 21f9abe6c9d1e2ce99ed75c2984103dcd2356b5d53bca3f3732176bb856bf3f7 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbemem.c | 9 +++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index f13241de98..736c135472 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Reinstant\sthe\swork-around\sfor\s[https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270|GCC\scompiler\sbug\s96270]\nwhich\sis\sapparently\sstill\san\sissue\sas\sof\sgcc\s13.3.0\swith\s-m32\son\sMint\sLinux.\nThe\stest\scase\sin\sthe\sbug\sreport\sis\sfixed,\sbut\sthe\svdbeMemRenderNum()\sroutine\nin\sSQLite\sstill\sshows\sthe\sproblem. -D 2026-02-25T12:44:19.970 +C The\sGCC\sbug\sis\sfixed\sin\sGCC-15. +D 2026-02-25T21:19:20.849 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -811,7 +811,7 @@ F src/vdbeInt.h 42488247a80cd9d300627833c6c85ace067ae5011a99e7614e2358130d62feea F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1 F src/vdbeaux.c 396d38a62a357b807eabae0cae441fc89d2767a57ab08026b7072bf7aa2dd00c F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692 -F src/vdbemem.c 401a320db404ce7e51f94a69cca30b2737d74d3b8e9ab272287cbfccdc9ffd10 +F src/vdbemem.c 317ec5e870ddb16951b606c9fe8be22baef22ecbe46f58fdefc259662238afb7 F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70 F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 75a35cd8f97f8a6cd2311c829685bd3b1cfb394de15174aef347f15cfb1913a1 -R a056b439b6d5d9d4c93ec16898c6d538 +P 7fae321095ebec775de1b39b974fb1f295d5efbd5723e9cb29a981c97a4262c8 +R 2bce2d64dedeeeba07cce6ad1de3a76b U drh -Z e627ce35647ad04f6d121e351748c96b +Z 54d73eb42d56bcceef1669c00ba9a6e1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4bef84000b..c681a81bc1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7fae321095ebec775de1b39b974fb1f295d5efbd5723e9cb29a981c97a4262c8 +21f9abe6c9d1e2ce99ed75c2984103dcd2356b5d53bca3f3732176bb856bf3f7 diff --git a/src/vdbemem.c b/src/vdbemem.c index 09f94cb585..5689cb7551 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -107,11 +107,12 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ StrAccum acc; assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); assert( sz>22 ); - if( p->flags & (MEM_Int|MEM_IntReal) ){ -#if GCC_VERSION>=7000000 && defined(__i386__) - /* Work-around for GCC bug + if( p->flags & (MEM_Int|MEM_IntReal) ){ +#if GCC_VERSION>=7000000 && GCC_VERSION<15000000 && defined(__i386__) + /* Work-around for GCC bug or bugs: ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 - ** This is still an issue as of 2026-02-25, GCC 13.3.0 with -m32 */ + ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114659 + ** The problem appears to be fixed in GCC 15 */ i64 x; assert( (MEM_Str&~p->flags)*4==sizeof(x) ); memcpy(&x, (char*)&p->u, (MEM_Str&~p->flags)*4); From a86c6017e7be0d7f0b1aa01e14dc4eea23b72012 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 26 Feb 2026 11:03:22 +0000 Subject: [PATCH 054/197] Fix a problem where the wrong collation could be used as part of a row-value comparison between columns with different collation sequences. [forum:/forumpost/6ceca07fc3 | Forum post 6ceca07fc3]. FossilOrigin-Name: 212c68249cc0e8904fc36d8e90646d04604f2b3b9d4c32eaeac7d920fa0fba99 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/where.c | 2 +- test/rowvalueA.test | 25 +++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 736c135472..431bb7dbf7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sGCC\sbug\sis\sfixed\sin\sGCC-15. -D 2026-02-25T21:19:20.849 +C Fix\sa\sproblem\swhere\sthe\swrong\scollation\scould\sbe\sused\sas\spart\sof\sa\srow-value\scomparison\sbetween\scolumns\swith\sdifferent\scollation\ssequences.\s[forum:/forumpost/6ceca07fc3\s|\sForum\spost\s6ceca07fc3]. +D 2026-02-26T11:03:22.388 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -820,7 +820,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab F src/wal.c 505a98fbc599a971d92cb90371cf54546c404cd61e04fd093e7b0c8ff978f9b6 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 -F src/where.c 7a7fe745dd8104d0276a3d3f6e6ac7f087af3dd9f34a90bc937e5e7aea817e15 +F src/where.c 9f09ee7b260010138d5f9fb5f195b98051119eae3096a99d72ff16c83230f4af F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da F src/wherecode.c 783ecd30061c875c919a5163e4b55f9a0eccdaf7c9b17ad2908a1668a8766bc4 F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6 @@ -1563,7 +1563,7 @@ F test/rowvalue6.test d19b54feb604d5601f8614b15e214e0774c01087 F test/rowvalue7.test 06ec0aca725bf683313d03793aa2943bc7f45a901848c7056a9665b769c8fc38 F test/rowvalue8.test 5900eddad9e2c3c2e26f1a95f74aafc1232ee5e0 F test/rowvalue9.test 7499a8fd7ca3a3f0e19d94e135355439aa2b596f86b775ca8de79672da2ca378 -F test/rowvalueA.test be8d6ad8b476eb24c151bb20bfd487e0d50c5e99618b7b0e656035069d2fc2cf +F test/rowvalueA.test 1c5ed13f3b0641452ae35e6488d6ecc16cefce99f2adf7c07c513530e2aac6b7 F test/rowvaluefault.test 963ae9cdaed30a85a29668dd514e639f3556cae903ee9f172ea972d511c54fff F test/rowvaluevtab.test cd9747bb3f308086944c07968f547ad6b05022e698d80b9ffbdfe09ce0b8da6f F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 7fae321095ebec775de1b39b974fb1f295d5efbd5723e9cb29a981c97a4262c8 -R 2bce2d64dedeeeba07cce6ad1de3a76b -U drh -Z 54d73eb42d56bcceef1669c00ba9a6e1 +P 21f9abe6c9d1e2ce99ed75c2984103dcd2356b5d53bca3f3732176bb856bf3f7 +R e23cf8b848c14a991d9b2e23b9e1852d +U dan +Z 99729fa9f5784c4cfcf5503d4e9925ba # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c681a81bc1..3f9fd09aae 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -21f9abe6c9d1e2ce99ed75c2984103dcd2356b5d53bca3f3732176bb856bf3f7 +212c68249cc0e8904fc36d8e90646d04604f2b3b9d4c32eaeac7d920fa0fba99 diff --git a/src/where.c b/src/where.c index 946d9fede5..2ef2ce0bee 100644 --- a/src/where.c +++ b/src/where.c @@ -3182,7 +3182,7 @@ static int whereRangeVectorLen( idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn); if( aff!=idxaff ) break; - pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); + pColl = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr); if( pColl==0 ) break; if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break; } diff --git a/test/rowvalueA.test b/test/rowvalueA.test index 8760c2c396..16429f985a 100644 --- a/test/rowvalueA.test +++ b/test/rowvalueA.test @@ -73,4 +73,29 @@ do_catchsql_test 2.3 { SELECT 2 IN ( (1, 2), (3, 4), (5, 6) ) } {1 {row value misused}} +#------------------------------------------------------------------------- +# Test the fix for forum post https://sqlite.org/forum/forumpost/6ceca07fc3 +# +do_execsql_test 3.0 { + CREATE TABLE x2 (x, y); + INSERT INTO x2 VALUES (1234, 'abc'); + + CREATE TABLE x1 (a, b PRIMARY KEY COLLATE NOCASE) WITHOUT ROWID; + INSERT INTO x1 VALUES (1234, 'ABCD'); +} + +do_execsql_test 3.1 { + SELECT * FROM x2 CROSS JOIN x1 WHERE (1234, x2.y) > (x1.a, x1.b); +} {1234 abc 1234 ABCD} + +do_execsql_test 3.2 { + CREATE INDEX x1a ON x1(a); +} + +do_execsql_test 3.3 { + SELECT * FROM x2 CROSS JOIN x1 WHERE (1234, x2.y) > (x1.a, x1.b); +} {1234 abc 1234 ABCD} + + + finish_test From 8bc78bebfb0c2835b4482d95ffc92903dc827afb Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 26 Feb 2026 12:17:19 +0000 Subject: [PATCH 055/197] Fix an inconsequential typo in the output of the datedebug() SQL function. FossilOrigin-Name: 3a92a53d8cf77822c22618dbf35851a20d27c4a659d23db2d24e7ccb3f61c7fc --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/date.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 431bb7dbf7..067c2fad31 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swhere\sthe\swrong\scollation\scould\sbe\sused\sas\spart\sof\sa\srow-value\scomparison\sbetween\scolumns\swith\sdifferent\scollation\ssequences.\s[forum:/forumpost/6ceca07fc3\s|\sForum\spost\s6ceca07fc3]. -D 2026-02-26T11:03:22.388 +C Fix\san\sinconsequential\stypo\sin\sthe\soutput\sof\sthe\sdatedebug()\sSQL\sfunction. +D 2026-02-26T12:17:19.803 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -685,7 +685,7 @@ F src/build.c b993e4adef4c4cdfd7abf62e2676c467bb1923f25f40c3c7ab2a7bfbace3de7f F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e -F src/date.c e1a6c5ac4753016198d664d633b8541fa4ad4ccde2beb12548fa99e746f38cec +F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8 F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c F src/delete.c 901499bed747c3b4b2be45be1abe912ba50a3f6a40ba88cc006ccf279f2d0e97 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 21f9abe6c9d1e2ce99ed75c2984103dcd2356b5d53bca3f3732176bb856bf3f7 -R e23cf8b848c14a991d9b2e23b9e1852d -U dan -Z 99729fa9f5784c4cfcf5503d4e9925ba +P 212c68249cc0e8904fc36d8e90646d04604f2b3b9d4c32eaeac7d920fa0fba99 +R 3f8504e826a6815f483ecb886c1e98ae +U drh +Z 6f0fc114d1ec32a0f9ff43ae3bda77ba # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3f9fd09aae..64dd3404e9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -212c68249cc0e8904fc36d8e90646d04604f2b3b9d4c32eaeac7d920fa0fba99 +3a92a53d8cf77822c22618dbf35851a20d27c4a659d23db2d24e7ccb3f61c7fc diff --git a/src/date.c b/src/date.c index 17c8e8a543..58a7ce5443 100644 --- a/src/date.c +++ b/src/date.c @@ -1784,7 +1784,7 @@ static void datedebugFunc( char *zJson; zJson = sqlite3_mprintf( "{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d," - "s:%.3f,validJD:%d,validYMS:%d,validHMS:%d," + "s:%.3f,validJD:%d,validYMD:%d,validHMS:%d," "nFloor:%d,rawS:%d,isError:%d,useSubsec:%d," "isUtc:%d,isLocal:%d}", x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz, From 5a6eef2fb21cd883a9ff6138bf8be42ccefdecd5 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 26 Feb 2026 13:35:38 +0000 Subject: [PATCH 056/197] Improvements to the SQLITE_PREPARE_FROM_DDL documentation. FossilOrigin-Name: c3288f16848866a2c846221c33631785f7b39938078bb95c61895f789395aa1d --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqlite.h.in | 27 ++++++++++++++------------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 067c2fad31..dda3e45248 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sinconsequential\stypo\sin\sthe\soutput\sof\sthe\sdatedebug()\sSQL\sfunction. -D 2026-02-26T12:17:19.803 +C Improvements\sto\sthe\sSQLITE_PREPARE_FROM_DDL\sdocumentation. +D 2026-02-26T13:35:38.171 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -740,7 +740,7 @@ F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c F src/shell.c.in 2acdfca982deb70cdfefb8b422822d4e0234fe4dde6ff2bd9020b26445853917 -F src/sqlite.h.in c7582608c8270428b288a529f4a4170298a19548266b55edaa2e70ce8d607f0e +F src/sqlite.h.in 5d01afb77c8254d856330b2338326a334de21dd62466edd85269d1b743383fd9 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca F src/sqliteInt.h 185abb373dc2a311e3292540ef177ea301d8140b976ecd8ba381a5a0162cd6e9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 212c68249cc0e8904fc36d8e90646d04604f2b3b9d4c32eaeac7d920fa0fba99 -R 3f8504e826a6815f483ecb886c1e98ae +P 3a92a53d8cf77822c22618dbf35851a20d27c4a659d23db2d24e7ccb3f61c7fc +R d1b84334b6d4b2518d0ef54646f93142 U drh -Z 6f0fc114d1ec32a0f9ff43ae3bda77ba +Z d883aa6ff4bade42b94571426eca9fb7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 64dd3404e9..dfb59e711d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3a92a53d8cf77822c22618dbf35851a20d27c4a659d23db2d24e7ccb3f61c7fc +c3288f16848866a2c846221c33631785f7b39938078bb95c61895f789395aa1d diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 930c3a1814..04dd1137b1 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4453,19 +4453,20 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** logs the error. ** ** [[SQLITE_PREPARE_FROM_DDL]]

SQLITE_PREPARE_FROM_DDL
-**
The SQLITE_PREPARE_FROM_DDL flag causes the SQL compiler to behave as if -** the SQL statement is part of a database schema. This makes a difference -** when the [SQLITE_DBCONFIG_TRUSTED_SCHEMA] option is set to off. -** When this option is used and SQLITE_DBCONFIG_TRUSTED_SCHEMA is off, -** SQL functions may not be called unless they are tagged with -** [SQLITE_INNOCUOUS] and virtual tables may not be used unless tagged -** with [SQLITE_VTAB_INNOCUOUS]. Use the SQLITE_PREPARE_FROM_DDL option -** when preparing SQL that is derived from parts of the database -** schema. In particular, virtual table implementations that -** run SQL statements based on the arguments to their CREATE VIRTUAL -** TABLE statement should use [sqlite3_prepare_v3()] and set the -** SQLITE_PREPARE_FROM_DLL flag to prevent bypass of the -** [SQLITE_DBCONFIG_TRUSTED_SCHEMA] security checks. +**
The SQLITE_PREPARE_FROM_DDL flag causes the SQL compiler to enforce +** security constraints that would otherwise only be enforced when parsing +** the database schema. In other words, the SQLITE_PREPARE_FROM_DDL flag +** causes the SQL compiler to treat the SQL statement being prepared as if +** it had come from an attacker. When SQLITE_PREPARE_FROM_DLL is used and +** [SQLITE_DBCONFIG_TRUSTED_SCHEMA] is off, SQL functions may only be called +** if they are tagged with [SQLITE_INNOCUOUS] and virtual tables may only +** be used if they are tagged with [SQLITE_VTAB_INNOCUOUS]. Best practice +** is to use the SQLITE_PREPARE_FROM_DDL option when preparing any SQL that +** is derived from parts of the database schema. In particular, virtual +** table implementations that run SQL statements that are derived from +** arguments to their CREATE VIRTUAL TABLE statement should always use +** [sqlite3_prepare_v3()] and set the SQLITE_PREPARE_FROM_DLL flag to +** prevent bypass of the [SQLITE_DBCONFIG_TRUSTED_SCHEMA] security checks. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 From 5dfccfb0bbcf930473d6d4c1abdca39b8184b94b Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 26 Feb 2026 16:19:21 +0000 Subject: [PATCH 057/197] Fix typos in the SQLITE_PREPARE_FROM_DDL documentation. FossilOrigin-Name: 9174e7dacf867c1f80e73ccf5e0ee7b9e84fbe9f2e53559d06b72206b1cde3c6 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqlite.h.in | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index dda3e45248..387c312553 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\sthe\sSQLITE_PREPARE_FROM_DDL\sdocumentation. -D 2026-02-26T13:35:38.171 +C Fix\stypos\sin\sthe\sSQLITE_PREPARE_FROM_DDL\sdocumentation. +D 2026-02-26T16:19:21.240 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -740,7 +740,7 @@ F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c F src/shell.c.in 2acdfca982deb70cdfefb8b422822d4e0234fe4dde6ff2bd9020b26445853917 -F src/sqlite.h.in 5d01afb77c8254d856330b2338326a334de21dd62466edd85269d1b743383fd9 +F src/sqlite.h.in 1f853f1d836af3e5a0b451521041d05658988a45f6978aaae08286e483fee5ac F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca F src/sqliteInt.h 185abb373dc2a311e3292540ef177ea301d8140b976ecd8ba381a5a0162cd6e9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 3a92a53d8cf77822c22618dbf35851a20d27c4a659d23db2d24e7ccb3f61c7fc -R d1b84334b6d4b2518d0ef54646f93142 +P c3288f16848866a2c846221c33631785f7b39938078bb95c61895f789395aa1d +R dcd62261fc7d31c8a65dd3cc5d14fd76 U drh -Z d883aa6ff4bade42b94571426eca9fb7 +Z de1179cfcfccba649912303467a12236 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index dfb59e711d..1a18fe1258 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c3288f16848866a2c846221c33631785f7b39938078bb95c61895f789395aa1d +9174e7dacf867c1f80e73ccf5e0ee7b9e84fbe9f2e53559d06b72206b1cde3c6 diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 04dd1137b1..b6773e1d9b 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4457,7 +4457,7 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** security constraints that would otherwise only be enforced when parsing ** the database schema. In other words, the SQLITE_PREPARE_FROM_DDL flag ** causes the SQL compiler to treat the SQL statement being prepared as if -** it had come from an attacker. When SQLITE_PREPARE_FROM_DLL is used and +** it had come from an attacker. When SQLITE_PREPARE_FROM_DDL is used and ** [SQLITE_DBCONFIG_TRUSTED_SCHEMA] is off, SQL functions may only be called ** if they are tagged with [SQLITE_INNOCUOUS] and virtual tables may only ** be used if they are tagged with [SQLITE_VTAB_INNOCUOUS]. Best practice @@ -4465,7 +4465,7 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** is derived from parts of the database schema. In particular, virtual ** table implementations that run SQL statements that are derived from ** arguments to their CREATE VIRTUAL TABLE statement should always use -** [sqlite3_prepare_v3()] and set the SQLITE_PREPARE_FROM_DLL flag to +** [sqlite3_prepare_v3()] and set the SQLITE_PREPARE_FROM_DDL flag to ** prevent bypass of the [SQLITE_DBCONFIG_TRUSTED_SCHEMA] security checks. ** */ From 8c6bf948b79e04fbc17daba8697138df6a8e81ed Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 27 Feb 2026 03:11:40 +0000 Subject: [PATCH 058/197] An initial copy/paste stub for experimenting with using WebLocks for a new copy of the OPFS vfs. This is not yet functional, or even loading, but needs stashing to avoid potential loss. FossilOrigin-Name: 372f18ae909bafd7167b70051935832e3107ede72aaeccbf5c042db7ba791912 --- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 1471 ++++++++++++++++++++++ manifest | 16 +- manifest.tags | 4 +- manifest.uuid | 2 +- 4 files changed, 1484 insertions(+), 9 deletions(-) create mode 100644 ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js new file mode 100644 index 0000000000..9fe09269cf --- /dev/null +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -0,0 +1,1471 @@ +//#if not target:node +/* + 2026-02-20 + + The author disclaims copyright to this source code. In place of a + legal notice, here is a blessing: + + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. + + *********************************************************************** + + This file is a placeholder for a reimplementation of the "opfs" VFS + (as distinct from "opfs-sahpool") which uses WebLocks instead + locking based on a bespoke custom Atomics.wait()/notify() + protocol. This file holds the "synchronous half" of the VFS, whereas + it shares the "asynchronous half" of the "opfs" VFS. + + This file is intended to be appended to the main sqlite3 JS + deliverable somewhere after sqlite3-api-oo1.js. +*/ +'use strict'; +globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ +/** + installOpfsVfs() returns a Promise which, on success, installs an + sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs + which accept a VFS. It is intended to be called via + sqlite3ApiBootstrap.initializers or an equivalent mechanism. + + The installed VFS uses the Origin-Private FileSystem API for + all file storage. On error it is rejected with an exception + explaining the problem. Reasons for rejection include, but are + not limited to: + + - The counterpart Worker (see below) could not be loaded. + + - The environment does not support OPFS. That includes when + this function is called from the main window thread. + + Significant notes and limitations: + + - The OPFS features used here are only available in dedicated Worker + threads. This file tries to detect that case, resulting in a + rejected Promise if those features do not seem to be available. + + - It requires the SharedArrayBuffer and Atomics classes, and the + former is only available if the HTTP server emits the so-called + COOP and COEP response headers. These features are required for + proxying OPFS's synchronous API via the synchronous interface + required by the sqlite3_vfs API. + + - This function may only be called a single time. When called, this + function removes itself from the sqlite3 object. + + All arguments to this function are for internal/development purposes + only. They do not constitute a public API and may change at any + time. + + The argument may optionally be a plain object with the following + configuration options: + + - proxyUri: name of the async proxy JS file. + + - verbose (=2): an integer 0-3. 0 disables all logging, 1 enables + logging of errors. 2 enables logging of warnings and errors. 3 + additionally enables debugging info. Logging is performed + via the sqlite3.config.{log|warn|error}() functions. + + - sanityChecks (=false): if true, some basic sanity tests are run on + the OPFS VFS API after it's initialized, before the returned + Promise resolves. This is only intended for testing and + development of the VFS, not client-side use. + + On success, the Promise resolves to the top-most sqlite3 namespace + object and that object gets a new object installed in its + `opfs` property, containing several OPFS-specific utilities. +*/ +const installOpfsVfs = function callee(options){ + if(!globalThis.SharedArrayBuffer + || !globalThis.Atomics){ + return Promise.reject( + new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. "+ + "The server must emit the COOP/COEP response headers to enable those. "+ + "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep") + ); + }else if('undefined'===typeof WorkerGlobalScope){ + return Promise.reject( + new Error("The OPFS sqlite3_vfs cannot run in the main thread "+ + "because it requires Atomics.wait().") + ); + }else if(!globalThis.FileSystemHandle || + !globalThis.FileSystemDirectoryHandle || + !globalThis.FileSystemFileHandle || + !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || + !navigator?.storage?.getDirectory){ + return Promise.reject( + new Error("Missing required OPFS APIs.") + ); + } + const nu = (...obj)=>Object.assign(Object.create(null),...obj); + options = nu(options); + const urlParams = new URL(globalThis.location.href).searchParams; + if(urlParams.has('opfs-disable')){ + //sqlite3.config.warn('Explicitly not installing 'opfs-wl' VFS due to opfs-disable flag.'); + return Promise.resolve(sqlite3); + } + if(undefined===options.verbose){ + options.verbose = urlParams.has('opfs-verbose') + ? (+urlParams.get('opfs-verbose') || 2) : 1; + } + if(undefined===options.sanityChecks){ + options.sanityChecks = urlParams.has('opfs-sanity-check'); + } + if(undefined===options.proxyUri){ + options.proxyUri = callee.defaultProxyUri; + } + + //sqlite3.config.warn("OPFS options =",options,globalThis.location); + + if('function' === typeof options.proxyUri){ + options.proxyUri = options.proxyUri(); + } + const thePromise = new Promise(function(promiseResolve_, promiseReject_){ + const loggers = [ + sqlite3.config.error, + sqlite3.config.warn, + sqlite3.config.log + ]; + const logImpl = (level,...args)=>{ + if(options.verbose>level) loggers[level]("OPFS syncer:",...args); + }; + const log = (...args)=>logImpl(2, ...args); + const warn = (...args)=>logImpl(1, ...args); + const error = (...args)=>logImpl(0, ...args); + const toss = sqlite3.util.toss; + const capi = sqlite3.capi; + const util = sqlite3.util; + const wasm = sqlite3.wasm; + const sqlite3_vfs = capi.sqlite3_vfs; + const sqlite3_file = capi.sqlite3_file; + const sqlite3_io_methods = capi.sqlite3_io_methods; + /** + Generic utilities for working with OPFS. This will get filled out + by the Promise setup and, on success, installed as sqlite3.opfs. + + ACHTUNG: do not rely on these APIs in client code. They are + experimental and subject to change or removal as the + OPFS-specific sqlite3_vfs evolves. + */ + const opfsUtil = Object.create(null); + + /** + Returns true if _this_ thread has access to the OPFS APIs. + */ + const thisThreadHasOPFS = ()=>{ + return globalThis.FileSystemHandle && + globalThis.FileSystemDirectoryHandle && + globalThis.FileSystemFileHandle && + globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle && + navigator?.storage?.getDirectory; + }; + + /** + Not part of the public API. Solely for internal/development + use. + */ + opfsUtil.metrics = { + dump: function(){ + let k, n = 0, t = 0, w = 0; + for(k in state.opIds){ + const m = metrics[k]; + n += m.count; + t += m.time; + w += m.wait; + m.avgTime = (m.count && m.time) ? (m.time / m.count) : 0; + m.avgWait = (m.count && m.wait) ? (m.wait / m.count) : 0; + } + sqlite3.config.log(globalThis.location.href, + "metrics for",globalThis.location.href,":",metrics, + "\nTotal of",n,"op(s) for",t, + "ms (incl. "+w+" ms of waiting on the async side)"); + sqlite3.config.log("Serialization metrics:",metrics.s11n); + W.postMessage({type:'opfs-async-metrics'}); + }, + reset: function(){ + let k; + const r = (m)=>(m.count = m.time = m.wait = 0); + for(k in state.opIds){ + r(metrics[k] = Object.create(null)); + } + let s = metrics.s11n = Object.create(null); + s = s.serialize = Object.create(null); + s.count = s.time = 0; + s = metrics.s11n.deserialize = Object.create(null); + s.count = s.time = 0; + } + }/*metrics*/; + const opfsIoMethods = new sqlite3_io_methods(); + const opfsVfs = new sqlite3_vfs() + .addOnDispose( ()=>opfsIoMethods.dispose()); + let promiseWasRejected = undefined; + const promiseReject = (err)=>{ + promiseWasRejected = true; + opfsVfs.dispose(); + return promiseReject_(err); + }; + const promiseResolve = ()=>{ + promiseWasRejected = false; + return promiseResolve_(sqlite3); + }; + const W = +//#if target:es6-bundler-friendly + new Worker(new URL("sqlite3-opfs-async-proxy.js", import.meta.url)); +//#elif target:es6-module + new Worker(new URL(options.proxyUri, import.meta.url)); +//#else + new Worker(options.proxyUri); +//#endif + setTimeout(()=>{ + /* At attempt to work around a browser-specific quirk in which + the Worker load is failing in such a way that we neither + resolve nor reject it. This workaround gives that resolve/reject + a time limit and rejects if that timer expires. Discussion: + https://sqlite.org/forum/forumpost/a708c98dcb3ef */ + if(undefined===promiseWasRejected){ + promiseReject( + new Error("Timeout while waiting for OPFS async proxy worker.") + ); + } + }, 4000); + W._originalOnError = W.onerror /* will be restored later */; + W.onerror = function(err){ + // The error object doesn't contain any useful info when the + // failure is, e.g., that the remote script is 404. + error("Error initializing OPFS asyncer:",err); + promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons.")); + }; + const pDVfs = capi.sqlite3_vfs_find(null)/*pointer to default VFS*/; + const dVfs = pDVfs + ? new sqlite3_vfs(pDVfs) + : null /* dVfs will be null when sqlite3 is built with + SQLITE_OS_OTHER. */; + opfsIoMethods.$iVersion = 1; + opfsVfs.$iVersion = 2/*yes, two*/; + opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; + opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit + is undocumented/unspecified. */; + opfsVfs.$zName = wasm.allocCString('opfs-wl'); + // All C-side memory of opfsVfs is zeroed out, but just to be explicit: + opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null; + opfsVfs.addOnDispose( + '$zName', opfsVfs.$zName, + 'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null) + ); + /** + Pedantic sidebar about opfsVfs.ondispose: the entries in that array + are items to clean up when opfsVfs.dispose() is called, but in this + environment it will never be called. The VFS instance simply + hangs around until the WASM module instance is cleaned up. We + "could" _hypothetically_ clean it up by "importing" an + sqlite3_os_end() impl into the wasm build, but the shutdown order + of the wasm engine and the JS one are undefined so there is no + guaranty that the opfsVfs instance would be available in one + environment or the other when sqlite3_os_end() is called (_if_ it + gets called at all in a wasm build, which is undefined). + */ + /** + State which we send to the async-api Worker or share with it. + This object must initially contain only cloneable or sharable + objects. After the worker's "inited" message arrives, other types + of data may be added to it. + + For purposes of Atomics.wait() and Atomics.notify(), we use a + SharedArrayBuffer with one slot reserved for each of the API + proxy's methods. The sync side of the API uses Atomics.wait() + on the corresponding slot and the async side uses + Atomics.notify() on that slot. + + The approach of using a single SAB to serialize comms for all + instances might(?) lead to deadlock situations in multi-db + cases. We should probably have one SAB here with a single slot + for locking a per-file initialization step and then allocate a + separate SAB like the above one for each file. That will + require a bit of acrobatics but should be feasible. The most + problematic part is that xOpen() would have to use + postMessage() to communicate its SharedArrayBuffer, and mixing + that approach with Atomics.wait/notify() gets a bit messy. + */ + const state = Object.create(null); + state.verbose = options.verbose; + state.littleEndian = (()=>{ + const buffer = new ArrayBuffer(2); + new DataView(buffer).setInt16(0, 256, true /* ==>littleEndian */); + // Int16Array uses the platform's endianness. + return new Int16Array(buffer)[0] === 256; + })(); + /** + asyncIdleWaitTime is how long (ms) to wait, in the async proxy, + for each Atomics.wait() when waiting on inbound VFS API calls. + We need to wake up periodically to give the thread a chance to + do other things. If this is too high (e.g. 500ms) then even two + workers/tabs can easily run into locking errors. Some multiple + of this value is also used for determining how long to wait on + lock contention to free up. + */ + state.asyncIdleWaitTime = 150; + + /** + Whether the async counterpart should log exceptions to + the serialization channel. That produces a great deal of + noise for seemingly innocuous things like xAccess() checks + for missing files, so this option may have one of 3 values: + + 0 = no exception logging. + + 1 = only log exceptions for "significant" ops like xOpen(), + xRead(), and xWrite(). + + 2 = log all exceptions. + */ + state.asyncS11nExceptions = 1; + /* Size of file I/O buffer block. 64k = max sqlite3 page size, and + xRead/xWrite() will never deal in blocks larger than that. */ + state.fileBufferSize = 1024 * 64; + state.sabS11nOffset = state.fileBufferSize; + /** + The size of the block in our SAB for serializing arguments and + result values. Needs to be large enough to hold serialized + values of any of the proxied APIs. Filenames are the largest + part but are limited to opfsVfs.$mxPathname bytes. We also + store exceptions there, so it needs to be long enough to hold + a reasonably long exception string. + */ + state.sabS11nSize = opfsVfs.$mxPathname * 2; + /** + The SAB used for all data I/O between the synchronous and + async halves (file i/o and arg/result s11n). + */ + state.sabIO = new SharedArrayBuffer( + state.fileBufferSize/* file i/o block */ + + state.sabS11nSize/* argument/result serialization block */ + ); + state.opIds = Object.create(null); + const metrics = Object.create(null); + { + /* Indexes for use in our SharedArrayBuffer... */ + let i = 0; + /* SAB slot used to communicate which operation is desired + between both workers. This worker writes to it and the other + listens for changes. */ + state.opIds.whichOp = i++; + /* Slot for storing return values. This worker listens to that + slot and the other worker writes to it. */ + state.opIds.rc = i++; + /* Each function gets an ID which this worker writes to + the whichOp slot. The async-api worker uses Atomic.wait() + on the whichOp slot to figure out which operation to run + next. */ + state.opIds.xAccess = i++; + state.opIds.xClose = i++; + state.opIds.xDelete = i++; + state.opIds.xDeleteNoWait = i++; + state.opIds.xFileSize = i++; + state.opIds.xLock = i++; + state.opIds.xOpen = i++; + state.opIds.xRead = i++; + state.opIds.xSleep = i++; + state.opIds.xSync = i++; + state.opIds.xTruncate = i++; + state.opIds.xUnlock = i++; + state.opIds.xWrite = i++; + state.opIds.mkdir = i++; + state.opIds.lockControl = i++ /* we signal the intent to lock here */; + state.opIds.lockType + /** Internal signals which are used only during development and + testing via the dev console. */ + state.opIds['opfs-async-metrics'] = i++; + state.opIds['opfs-async-shutdown'] = i++; + /* The retry slot is used by the async part for wait-and-retry + semantics. Though we could hypothetically use the xSleep slot + for that, doing so might lead to undesired side effects. */ + state.opIds.retry = i++; + + /* Slots for submitting the lock type and receiving its acknowledgement. */ + state.lock = nu({ + type: i++, + atomicsHandshake: i++ + }); + state.sabOP = new SharedArrayBuffer( + i * 4/* ==sizeof int32, noting that Atomics.wait() and friends + can only function on Int32Array views of an SAB. */); + opfsUtil.metrics.reset(); + } + /** + SQLITE_xxx constants to export to the async worker + counterpart... + */ + state.sq3Codes = Object.create(null); + [ + 'SQLITE_ACCESS_EXISTS', + 'SQLITE_ACCESS_READWRITE', + 'SQLITE_BUSY', + 'SQLITE_CANTOPEN', + 'SQLITE_ERROR', + 'SQLITE_IOERR', + 'SQLITE_IOERR_ACCESS', + 'SQLITE_IOERR_CLOSE', + 'SQLITE_IOERR_DELETE', + 'SQLITE_IOERR_FSYNC', + 'SQLITE_IOERR_LOCK', + 'SQLITE_IOERR_READ', + 'SQLITE_IOERR_SHORT_READ', + 'SQLITE_IOERR_TRUNCATE', + 'SQLITE_IOERR_UNLOCK', + 'SQLITE_IOERR_WRITE', + 'SQLITE_LOCK_EXCLUSIVE', + 'SQLITE_LOCK_NONE', + 'SQLITE_LOCK_PENDING', + 'SQLITE_LOCK_RESERVED', + 'SQLITE_LOCK_SHARED', + 'SQLITE_LOCKED', + 'SQLITE_MISUSE', + 'SQLITE_NOTFOUND', + 'SQLITE_OPEN_CREATE', + 'SQLITE_OPEN_DELETEONCLOSE', + 'SQLITE_OPEN_MAIN_DB', + 'SQLITE_OPEN_READONLY' + ].forEach((k)=>{ + if(undefined === (state.sq3Codes[k] = capi[k])){ + toss("Maintenance required: not found:",k); + } + }); + state.opfsFlags = Object.assign(Object.create(null),{ + /** + Flag for use with xOpen(). URI flag "opfs-unlock-asap=1" + enables this. See defaultUnlockAsap, below. + */ + OPFS_UNLOCK_ASAP: 0x01, + /** + Flag for use with xOpen(). URI flag "delete-before-open=1" + tells the VFS to delete the db file before attempting to open + it. This can be used, e.g., to replace a db which has been + corrupted (without forcing us to expose a delete/unlink() + function in the public API). + + Failure to unlink the file is ignored but may lead to + downstream errors. An unlink can fail if, e.g., another tab + has the handle open. + + It goes without saying that deleting a file out from under another + instance results in Undefined Behavior. + */ + OPFS_UNLINK_BEFORE_OPEN: 0x02, + /** + If true, any async routine which implicitly acquires a sync + access handle (i.e. an OPFS lock) will release that lock at + the end of the call which acquires it. If false, such + "autolocks" are not released until the VFS is idle for some + brief amount of time. + + The benefit of enabling this is much higher concurrency. The + down-side is much-reduced performance (as much as a 4x decrease + in speedtest1). + */ + defaultUnlockAsap: false + }); + + /** + Runs the given operation (by name) in the async worker + counterpart, waits for its response, and returns the result + which the async worker writes to SAB[state.opIds.rc]. The + 2nd and subsequent arguments must be the arguments for the + async op. + */ + const opRun = (op,...args)=>{ + const opNdx = state.opIds[op] || toss("Invalid op ID:",op); + state.s11n.serialize(...args); + Atomics.store(state.sabOPView, state.opIds.rc, -1); + Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); + Atomics.notify(state.sabOPView, state.opIds.whichOp) + /* async thread will take over here */; + const t = performance.now(); + while('not-equal'!==Atomics.wait(state.sabOPView, state.opIds.rc, -1)){ + /* + The reason for this loop is buried in the details of a long + discussion at: + + https://github.com/sqlite/sqlite-wasm/issues/12 + + Summary: in at least one browser flavor, under high loads, + the wait()/notify() pairings can get out of sync. Calling + wait() here until it returns 'not-equal' gets them back in + sync. + */ + } + /* When the above wait() call returns 'not-equal', the async + half will have completed the operation and reported its results + in the state.opIds.rc slot of the SAB. */ + const rc = Atomics.load(state.sabOPView, state.opIds.rc); + metrics[op].wait += performance.now() - t; + if(rc && state.asyncS11nExceptions){ + const err = state.s11n.deserialize(); + if(err) error(op+"() async error:",...err); + } + return rc; + }; + + /** + Not part of the public API. Only for test/development use. + */ + opfsUtil.debug = { + asyncShutdown: ()=>{ + warn("Shutting down OPFS async listener. The OPFS VFS will no longer work."); + opRun('opfs-async-shutdown'); + }, + asyncRestart: ()=>{ + warn("Attempting to restart OPFS VFS async listener. Might work, might not."); + W.postMessage({type: 'opfs-async-restart'}); + } + }; + + const initS11n = ()=>{ + /** + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ACHTUNG: this code is 100% duplicated in the other half of + this proxy! The documentation is maintained in the + "synchronous half". + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + This proxy de/serializes cross-thread function arguments and + output-pointer values via the state.sabIO SharedArrayBuffer, + using the region defined by (state.sabS11nOffset, + state.sabS11nOffset + state.sabS11nSize]. Only one dataset is + recorded at a time. + + This is not a general-purpose format. It only supports the + range of operations, and data sizes, needed by the + sqlite3_vfs and sqlite3_io_methods operations. Serialized + data are transient and this serialization algorithm may + change at any time. + + The data format can be succinctly summarized as: + + Nt...Td...D + + Where: + + - N = number of entries (1 byte) + + - t = type ID of first argument (1 byte) + + - ...T = type IDs of the 2nd and subsequent arguments (1 byte + each). + + - d = raw bytes of first argument (per-type size). + + - ...D = raw bytes of the 2nd and subsequent arguments (per-type + size). + + All types except strings have fixed sizes. Strings are stored + using their TextEncoder/TextDecoder representations. It would + arguably make more sense to store them as Int16Arrays of + their JS character values, but how best/fastest to get that + in and out of string form is an open point. Initial + experimentation with that approach did not gain us any speed. + + Historical note: this impl was initially about 1% this size by + using using JSON.stringify/parse(), but using fit-to-purpose + serialization saves considerable runtime. + */ + if(state.s11n) return state.s11n; + const textDecoder = new TextDecoder(), + textEncoder = new TextEncoder('utf-8'), + viewU8 = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize), + viewDV = new DataView(state.sabIO, state.sabS11nOffset, state.sabS11nSize); + state.s11n = Object.create(null); + /* Only arguments and return values of these types may be + serialized. This covers the whole range of types needed by the + sqlite3_vfs API. */ + const TypeIds = Object.create(null); + TypeIds.number = { id: 1, size: 8, getter: 'getFloat64', setter: 'setFloat64' }; + TypeIds.bigint = { id: 2, size: 8, getter: 'getBigInt64', setter: 'setBigInt64' }; + TypeIds.boolean = { id: 3, size: 4, getter: 'getInt32', setter: 'setInt32' }; + TypeIds.string = { id: 4 }; + + const getTypeId = (v)=>( + TypeIds[typeof v] + || toss("Maintenance required: this value type cannot be serialized.",v) + ); + const getTypeIdById = (tid)=>{ + switch(tid){ + case TypeIds.number.id: return TypeIds.number; + case TypeIds.bigint.id: return TypeIds.bigint; + case TypeIds.boolean.id: return TypeIds.boolean; + case TypeIds.string.id: return TypeIds.string; + default: toss("Invalid type ID:",tid); + } + }; + + /** + Returns an array of the deserialized state stored by the most + recent serialize() operation (from this thread or the + counterpart thread), or null if the serialization buffer is + empty. If passed a truthy argument, the serialization buffer + is cleared after deserialization. + */ + state.s11n.deserialize = function(clear=false){ + ++metrics.s11n.deserialize.count; + const t = performance.now(); + const argc = viewU8[0]; + const rc = argc ? [] : null; + if(argc){ + const typeIds = []; + let offset = 1, i, n, v; + for(i = 0; i < argc; ++i, ++offset){ + typeIds.push(getTypeIdById(viewU8[offset])); + } + for(i = 0; i < argc; ++i){ + const t = typeIds[i]; + if(t.getter){ + v = viewDV[t.getter](offset, state.littleEndian); + offset += t.size; + }else{/*String*/ + n = viewDV.getInt32(offset, state.littleEndian); + offset += 4; + v = textDecoder.decode(viewU8.slice(offset, offset+n)); + offset += n; + } + rc.push(v); + } + } + if(clear) viewU8[0] = 0; + //log("deserialize:",argc, rc); + metrics.s11n.deserialize.time += performance.now() - t; + return rc; + }; + + /** + Serializes all arguments to the shared buffer for consumption + by the counterpart thread. + + This routine is only intended for serializing OPFS VFS + arguments and (in at least one special case) result values, + and the buffer is sized to be able to comfortably handle + those. + + If passed no arguments then it zeroes out the serialization + state. + */ + state.s11n.serialize = function(...args){ + const t = performance.now(); + ++metrics.s11n.serialize.count; + if(args.length){ + //log("serialize():",args); + const typeIds = []; + let i = 0, offset = 1; + viewU8[0] = args.length & 0xff /* header = # of args */; + for(; i < args.length; ++i, ++offset){ + /* Write the TypeIds.id value into the next args.length + bytes. */ + typeIds.push(getTypeId(args[i])); + viewU8[offset] = typeIds[i].id; + } + for(i = 0; i < args.length; ++i) { + /* Deserialize the following bytes based on their + corresponding TypeIds.id from the header. */ + const t = typeIds[i]; + if(t.setter){ + viewDV[t.setter](offset, args[i], state.littleEndian); + offset += t.size; + }else{/*String*/ + const s = textEncoder.encode(args[i]); + viewDV.setInt32(offset, s.byteLength, state.littleEndian); + offset += 4; + viewU8.set(s, offset); + offset += s.byteLength; + } + } + //log("serialize() result:",viewU8.slice(0,offset)); + }else{ + viewU8[0] = 0; + } + metrics.s11n.serialize.time += performance.now() - t; + }; + return state.s11n; + }/*initS11n()*/; + + /** + Generates a random ASCII string len characters long, intended for + use as a temporary file name. + */ + const randomFilename = function f(len=16){ + if(!f._chars){ + f._chars = "abcdefghijklmnopqrstuvwxyz"+ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+ + "012346789"; + f._n = f._chars.length; + } + const a = []; + let i = 0; + for( ; i < len; ++i){ + const ndx = Math.random() * (f._n * 64) % f._n | 0; + a[i] = f._chars[ndx]; + } + return a.join(""); + /* + An alternative impl. with an unpredictable length + but much simpler: + + Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36) + */ + }; + + /** + Map of sqlite3_file pointers to objects constructed by xOpen(). + */ + const __openFiles = Object.create(null); + + const opTimer = Object.create(null); + opTimer.op = undefined; + opTimer.start = undefined; + const mTimeStart = (op)=>{ + opTimer.start = performance.now(); + opTimer.op = op; + ++metrics[op].count; + }; + const mTimeEnd = ()=>( + metrics[opTimer.op].time += performance.now() - opTimer.start + ); + + /** + Impls for the sqlite3_io_methods methods. Maintenance reminder: + members are in alphabetical order to simplify finding them. + */ + const ioSyncWrappers = { + xCheckReservedLock: function(pFile,pOut){ + /** + As of late 2022, only a single lock can be held on an OPFS + file. We have no way of checking whether any _other_ db + connection has a lock except by trying to obtain and (on + success) release a sync-handle for it, but doing so would + involve an inherent race condition. For the time being, + pending a better solution, we simply report whether the + given pFile is open. + + Update 2024-06-12: based on forum discussions, this + function now always sets pOut to 0 (false): + + https://sqlite.org/forum/forumpost/a2f573b00cda1372 + */ + wasm.poke(pOut, 0, 'i32'); + return 0; + }, + xClose: function(pFile){ + mTimeStart('xClose'); + let rc = 0; + const f = __openFiles[pFile]; + if(f){ + delete __openFiles[pFile]; + rc = opRun('xClose', pFile); + if(f.sq3File) f.sq3File.dispose(); + } + mTimeEnd(); + return rc; + }, + xDeviceCharacteristics: function(pFile){ + return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; + }, + xFileControl: function(pFile, opId, pArg){ + /*mTimeStart('xFileControl'); + mTimeEnd();*/ + return capi.SQLITE_NOTFOUND; + }, + xFileSize: function(pFile,pSz64){ + mTimeStart('xFileSize'); + let rc = opRun('xFileSize', pFile); + if(0==rc){ + try { + const sz = state.s11n.deserialize()[0]; + wasm.poke(pSz64, sz, 'i64'); + }catch(e){ + error("Unexpected error reading xFileSize() result:",e); + rc = state.sq3Codes.SQLITE_IOERR; + } + } + mTimeEnd(); + return rc; + }, + xLock: function(pFile,lockType){ + mTimeStart('xLock'); + const f = __openFiles[pFile]; + let rc = 0; + /* All OPFS locks are exclusive locks. If xLock() has + previously succeeded, do nothing except record the lock + type. If no lock is active, have the async counterpart + lock the file. */ + if( !f.lockType ) { + rc = opRun('xLock', pFile, lockType); + if( 0===rc ) f.lockType = lockType; + }else{ + f.lockType = lockType; + } + mTimeEnd(); + return rc; + }, + xRead: function(pFile,pDest,n,offset64){ + mTimeStart('xRead'); + const f = __openFiles[pFile]; + let rc; + try { + rc = opRun('xRead',pFile, n, Number(offset64)); + if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){ + /** + Results get written to the SharedArrayBuffer f.sabView. + Because the heap is _not_ a SharedArrayBuffer, we have + to copy the results. TypedArray.set() seems to be the + fastest way to copy this. */ + wasm.heap8u().set(f.sabView.subarray(0, n), Number(pDest)); + } + }catch(e){ + error("xRead(",arguments,") failed:",e,f); + rc = capi.SQLITE_IOERR_READ; + } + mTimeEnd(); + return rc; + }, + xSync: function(pFile,flags){ + mTimeStart('xSync'); + ++metrics.xSync.count; + const rc = opRun('xSync', pFile, flags); + mTimeEnd(); + return rc; + }, + xTruncate: function(pFile,sz64){ + mTimeStart('xTruncate'); + const rc = opRun('xTruncate', pFile, Number(sz64)); + mTimeEnd(); + return rc; + }, + xUnlock: function(pFile,lockType){ + mTimeStart('xUnlock'); + const f = __openFiles[pFile]; + let rc = 0; + if( capi.SQLITE_LOCK_NONE === lockType + && f.lockType ){ + rc = opRun('xUnlock', pFile, lockType); + } + if( 0===rc ) f.lockType = lockType; + mTimeEnd(); + return rc; + }, + xWrite: function(pFile,pSrc,n,offset64){ + mTimeStart('xWrite'); + const f = __openFiles[pFile]; + let rc; + try { + f.sabView.set(wasm.heap8u().subarray( + Number(pSrc), Number(pSrc) + n + )); + rc = opRun('xWrite', pFile, n, Number(offset64)); + }catch(e){ + error("xWrite(",arguments,") failed:",e,f); + rc = capi.SQLITE_IOERR_WRITE; + } + mTimeEnd(); + return rc; + } + }/*ioSyncWrappers*/; + + /** + Impls for the sqlite3_vfs methods. Maintenance reminder: members + are in alphabetical order to simplify finding them. + */ + const vfsSyncWrappers = { + xAccess: function(pVfs,zName,flags,pOut){ + mTimeStart('xAccess'); + const rc = opRun('xAccess', wasm.cstrToJs(zName)); + wasm.poke( pOut, (rc ? 0 : 1), 'i32' ); + mTimeEnd(); + return 0; + }, + xCurrentTime: function(pVfs,pOut){ + /* If it turns out that we need to adjust for timezone, see: + https://stackoverflow.com/a/11760121/1458521 */ + wasm.poke(pOut, 2440587.5 + (new Date().getTime()/86400000), + 'double'); + return 0; + }, + xCurrentTimeInt64: function(pVfs,pOut){ + wasm.poke(pOut, (2440587.5 * 86400000) + new Date().getTime(), + 'i64'); + return 0; + }, + xDelete: function(pVfs, zName, doSyncDir){ + mTimeStart('xDelete'); + const rc = opRun('xDelete', wasm.cstrToJs(zName), doSyncDir, false); + mTimeEnd(); + return rc; + }, + xFullPathname: function(pVfs,zName,nOut,pOut){ + /* Until/unless we have some notion of "current dir" + in OPFS, simply copy zName to pOut... */ + const i = wasm.cstrncpy(pOut, zName, nOut); + return i!!v) : p; + }; + + /** + Takes the absolute path to a filesystem element. Returns an + array of [handleOfContainingDir, filename]. If the 2nd argument + is truthy then each directory element leading to the file is + created along the way. Throws if any creation or resolution + fails. + */ + opfsUtil.getDirForFilename = async function f(absFilename, createDirs = false){ + const path = opfsUtil.getResolvedPath(absFilename, true); + const filename = path.pop(); + let dh = opfsUtil.rootDirectory; + for(const dirName of path){ + if(dirName){ + dh = await dh.getDirectoryHandle(dirName, {create: !!createDirs}); + } + } + return [dh, filename]; + }; + + /** + Creates the given directory name, recursively, in + the OPFS filesystem. Returns true if it succeeds or the + directory already exists, else false. + */ + opfsUtil.mkdir = async function(absDirName){ + try { + await opfsUtil.getDirForFilename(absDirName+"/filepart", true); + return true; + }catch(e){ + //sqlite3.config.warn("mkdir(",absDirName,") failed:",e); + return false; + } + }; + /** + Checks whether the given OPFS filesystem entry exists, + returning true if it does, false if it doesn't or if an + exception is intercepted while trying to make the + determination. + */ + opfsUtil.entryExists = async function(fsEntryName){ + try { + const [dh, fn] = await opfsUtil.getDirForFilename(fsEntryName); + await dh.getFileHandle(fn); + return true; + }catch(e){ + return false; + } + }; + + /** + Generates a random ASCII string, intended for use as a + temporary file name. Its argument is the length of the string, + defaulting to 16. + */ + opfsUtil.randomFilename = randomFilename; + + /** + Returns a promise which resolves to an object which represents + all files and directories in the OPFS tree. The top-most object + has two properties: `dirs` is an array of directory entries + (described below) and `files` is a list of file names for all + files in that directory. + + Traversal starts at sqlite3.opfs.rootDirectory. + + Each `dirs` entry is an object in this form: + + ``` + { name: directoryName, + dirs: [...subdirs], + files: [...file names] + } + ``` + + The `files` and `subdirs` entries are always set but may be + empty arrays. + + The returned object has the same structure but its `name` is + an empty string. All returned objects are created with + Object.create(null), so have no prototype. + + Design note: the entries do not contain more information, + e.g. file sizes, because getting such info is not only + expensive but is subject to locking-related errors. + */ + opfsUtil.treeList = async function(){ + const doDir = async function callee(dirHandle,tgt){ + tgt.name = dirHandle.name; + tgt.dirs = []; + tgt.files = []; + for await (const handle of dirHandle.values()){ + if('directory' === handle.kind){ + const subDir = Object.create(null); + tgt.dirs.push(subDir); + await callee(handle, subDir); + }else{ + tgt.files.push(handle.name); + } + } + }; + const root = Object.create(null); + await doDir(opfsUtil.rootDirectory, root); + return root; + }; + + /** + Irrevocably deletes _all_ files in the current origin's OPFS. + Obviously, this must be used with great caution. It may throw + an exception if removal of anything fails (e.g. a file is + locked), but the precise conditions under which the underlying + APIs will throw are not documented (so we cannot tell you what + they are). + */ + opfsUtil.rmfr = async function(){ + const dir = opfsUtil.rootDirectory, opt = {recurse: true}; + for await (const handle of dir.values()){ + dir.removeEntry(handle.name, opt); + } + }; + + /** + Deletes the given OPFS filesystem entry. As this environment + has no notion of "current directory", the given name must be an + absolute path. If the 2nd argument is truthy, deletion is + recursive (use with caution!). + + The returned Promise resolves to true if the deletion was + successful, else false (but...). The OPFS API reports the + reason for the failure only in human-readable form, not + exceptions which can be type-checked to determine the + failure. Because of that... + + If the final argument is truthy then this function will + propagate any exception on error, rather than returning false. + */ + opfsUtil.unlink = async function(fsEntryName, recursive = false, + throwOnError = false){ + try { + const [hDir, filenamePart] = + await opfsUtil.getDirForFilename(fsEntryName, false); + await hDir.removeEntry(filenamePart, {recursive}); + return true; + }catch(e){ + if(throwOnError){ + throw new Error("unlink(",arguments[0],") failed: "+e.message,{ + cause: e + }); + } + return false; + } + }; + + /** + Traverses the OPFS filesystem, calling a callback for each + entry. The argument may be either a callback function or an + options object with any of the following properties: + + - `callback`: function which gets called for each filesystem + entry. It gets passed 3 arguments: 1) the + FileSystemFileHandle or FileSystemDirectoryHandle of each + entry (noting that both are instanceof FileSystemHandle). 2) + the FileSystemDirectoryHandle of the parent directory. 3) the + current depth level, with 0 being at the top of the tree + relative to the starting directory. If the callback returns a + literal false, as opposed to any other falsy value, traversal + stops without an error. Any exceptions it throws are + propagated. Results are undefined if the callback manipulate + the filesystem (e.g. removing or adding entries) because the + how OPFS iterators behave in the face of such changes is + undocumented. + + - `recursive` [bool=true]: specifies whether to recurse into + subdirectories or not. Whether recursion is depth-first or + breadth-first is unspecified! + + - `directory` [FileSystemDirectoryEntry=sqlite3.opfs.rootDirectory] + specifies the starting directory. + + If this function is passed a function, it is assumed to be the + callback. + + Returns a promise because it has to (by virtue of being async) + but that promise has no specific meaning: the traversal it + performs is synchronous. The promise must be used to catch any + exceptions propagated by the callback, however. + */ + opfsUtil.traverse = async function(opt){ + const defaultOpt = { + recursive: true, + directory: opfsUtil.rootDirectory + }; + if('function'===typeof opt){ + opt = {callback:opt}; + } + opt = Object.assign(defaultOpt, opt||{}); + const doDir = async function callee(dirHandle, depth){ + for await (const handle of dirHandle.values()){ + if(false === opt.callback(handle, dirHandle, depth)) return false; + else if(opt.recursive && 'directory' === handle.kind){ + if(false === await callee(handle, depth + 1)) break; + } + } + }; + doDir(opt.directory, 0); + }; + + /** + impl of importDb() when it's given a function as its second + argument. + */ + const importDbChunked = async function(filename, callback){ + const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true); + const hFile = await hDir.getFileHandle(fnamePart, {create:true}); + let sah = await hFile.createSyncAccessHandle(); + let nWrote = 0, chunk, checkedHeader = false, err = false; + try{ + sah.truncate(0); + while( undefined !== (chunk = await callback()) ){ + if(chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk); + if( !checkedHeader && 0===nWrote && chunk.byteLength>=15 ){ + util.affirmDbHeader(chunk); + checkedHeader = true; + } + sah.write(chunk, {at: nWrote}); + nWrote += chunk.byteLength; + } + if( nWrote < 512 || 0!==nWrote % 512 ){ + toss("Input size",nWrote,"is not correct for an SQLite database."); + } + if( !checkedHeader ){ + const header = new Uint8Array(20); + sah.read( header, {at: 0} ); + util.affirmDbHeader( header ); + } + sah.write(new Uint8Array([1,1]), {at: 18}/*force db out of WAL mode*/); + return nWrote; + }catch(e){ + await sah.close(); + sah = undefined; + await hDir.removeEntry( fnamePart ).catch(()=>{}); + throw e; + }finally { + if( sah ) await sah.close(); + } + }; + + /** + Asynchronously imports the given bytes (a byte array or + ArrayBuffer) into the given database file. + + Results are undefined if the given db name refers to an opened + db. + + If passed a function for its second argument, its behaviour + changes: imports its data in chunks fed to it by the given + callback function. It calls the callback (which may be async) + repeatedly, expecting either a Uint8Array or ArrayBuffer (to + denote new input) or undefined (to denote EOF). For so long as + the callback continues to return non-undefined, it will append + incoming data to the given VFS-hosted database file. When + called this way, the resolved value of the returned Promise is + the number of bytes written to the target file. + + It very specifically requires the input to be an SQLite3 + database and throws if that's not the case. It does so in + order to prevent this function from taking on a larger scope + than it is specifically intended to. i.e. we do not want it to + become a convenience for importing arbitrary files into OPFS. + + This routine rewrites the database header bytes in the output + file (not the input array) to force disabling of WAL mode. + + On error this throws and the state of the input file is + undefined (it depends on where the exception was triggered). + + On success, resolves to the number of bytes written. + */ + opfsUtil.importDb = async function(filename, bytes){ + if( bytes instanceof Function ){ + return importDbChunked(filename, bytes); + } + if(bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); + util.affirmIsDb(bytes); + const n = bytes.byteLength; + const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true); + let sah, err, nWrote = 0; + try { + const hFile = await hDir.getFileHandle(fnamePart, {create:true}); + sah = await hFile.createSyncAccessHandle(); + sah.truncate(0); + nWrote = sah.write(bytes, {at: 0}); + if(nWrote != n){ + toss("Expected to write "+n+" bytes but wrote "+nWrote+"."); + } + sah.write(new Uint8Array([1,1]), {at: 18}) /* force db out of WAL mode */; + return nWrote; + }catch(e){ + if( sah ){ await sah.close(); sah = undefined; } + await hDir.removeEntry( fnamePart ).catch(()=>{}); + throw e; + }finally{ + if( sah ) await sah.close(); + } + }; + + if(sqlite3.oo1){ + const OpfsDb = function(...args){ + const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); + opt.vfs = opfsVfs.$zName; + sqlite3.oo1.DB.dbCtorHelper.call(this, opt); + }; + OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype); + sqlite3.oo1.OpfsDb = OpfsDb; + OpfsDb.importDb = opfsUtil.importDb; + sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback( + opfsVfs.pointer, + function(oo1Db, sqlite3){ + /* Set a relatively high default busy-timeout handler to + help OPFS dbs deal with multi-tab/multi-worker + contention. */ + sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000); + } + ); + }/*extend sqlite3.oo1*/ + + const sanityCheck = function(){ + const scope = wasm.scopedAllocPush(); + const sq3File = new sqlite3_file(); + try{ + const fid = sq3File.pointer; + const openFlags = capi.SQLITE_OPEN_CREATE + | capi.SQLITE_OPEN_READWRITE + //| capi.SQLITE_OPEN_DELETEONCLOSE + | capi.SQLITE_OPEN_MAIN_DB; + const pOut = wasm.scopedAlloc(8); + const dbFile = "/sanity/check/file"+randomFilename(8); + const zDbFile = wasm.scopedAllocCString(dbFile); + let rc; + state.s11n.serialize("This is ä string."); + rc = state.s11n.deserialize(); + log("deserialize() says:",rc); + if("This is ä string."!==rc[0]) toss("String d13n error."); + vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); + rc = wasm.peek(pOut,'i32'); + log("xAccess(",dbFile,") exists ?=",rc); + rc = vfsSyncWrappers.xOpen(opfsVfs.pointer, zDbFile, + fid, openFlags, pOut); + log("open rc =",rc,"state.sabOPView[xOpen] =", + state.sabOPView[state.opIds.xOpen]); + if(0!==rc){ + error("open failed with code",rc); + return; + } + vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); + rc = wasm.peek(pOut,'i32'); + if(!rc) toss("xAccess() failed to detect file."); + rc = ioSyncWrappers.xSync(sq3File.pointer, 0); + if(rc) toss('sync failed w/ rc',rc); + rc = ioSyncWrappers.xTruncate(sq3File.pointer, 1024); + if(rc) toss('truncate failed w/ rc',rc); + wasm.poke(pOut,0,'i64'); + rc = ioSyncWrappers.xFileSize(sq3File.pointer, pOut); + if(rc) toss('xFileSize failed w/ rc',rc); + log("xFileSize says:",wasm.peek(pOut, 'i64')); + rc = ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1); + if(rc) toss("xWrite() failed!"); + const readBuf = wasm.scopedAlloc(16); + rc = ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2); + wasm.poke(readBuf+6,0); + let jRead = wasm.cstrToJs(readBuf); + log("xRead() got:",jRead); + if("sanity"!==jRead) toss("Unexpected xRead() value."); + if(vfsSyncWrappers.xSleep){ + log("xSleep()ing before close()ing..."); + vfsSyncWrappers.xSleep(opfsVfs.pointer,2000); + log("waking up from xSleep()"); + } + rc = ioSyncWrappers.xClose(fid); + log("xClose rc =",rc,"sabOPView =",state.sabOPView); + log("Deleting file:",dbFile); + vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 0x1234); + vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); + rc = wasm.peek(pOut,'i32'); + if(rc) toss("Expecting 0 from xAccess(",dbFile,") after xDelete()."); + warn("End of OPFS sanity checks."); + }finally{ + sq3File.dispose(); + wasm.scopedAllocPop(scope); + } + }/*sanityCheck()*/; + + W.onmessage = function({data}){ + //log("Worker.onmessage:",data); + switch(data.type){ + case 'opfs-unavailable': + /* Async proxy has determined that OPFS is unavailable. There's + nothing more for us to do here. */ + promiseReject(new Error(data.payload.join(' '))); + break; + case 'opfs-async-loaded': + /* Arrives as soon as the asyc proxy finishes loading. + Pass our config and shared state on to the async + worker. */ + W.postMessage({type: 'opfs-async-init',args: state}); + break; + case 'opfs-async-inited': { + /* Indicates that the async partner has received the 'init' + and has finished initializing, so the real work can + begin... */ + if(true===promiseWasRejected){ + break /* promise was already rejected via timer */; + } + try { + sqlite3.vfs.installVfs({ + io: {struct: opfsIoMethods, methods: ioSyncWrappers}, + vfs: {struct: opfsVfs, methods: vfsSyncWrappers} + }); + state.sabOPView = new Int32Array(state.sabOP); + state.sabFileBufView = new Uint8Array(state.sabIO, 0, state.fileBufferSize); + state.sabS11nView = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize); + initS11n(); + if(options.sanityChecks){ + warn("Running sanity checks because of opfs-sanity-check URL arg..."); + sanityCheck(); + } + if(thisThreadHasOPFS()){ + navigator.storage.getDirectory().then((d)=>{ + W.onerror = W._originalOnError; + delete W._originalOnError; + sqlite3.opfs = opfsUtil; + opfsUtil.rootDirectory = d; + log("End of OPFS sqlite3_vfs setup.", opfsVfs); + promiseResolve(); + }).catch(promiseReject); + }else{ + promiseResolve(); + } + }catch(e){ + error(e); + promiseReject(e); + } + break; + } + default: { + const errMsg = ( + "Unexpected message from the OPFS async worker: " + + JSON.stringify(data) + ); + error(errMsg); + promiseReject(new Error(errMsg)); + break; + } + }/*switch(data.type)*/ + }/*W.onmessage()*/; + })/*thePromise*/; + return thePromise; +}/*installOpfsVfs()*/; +installOpfsVfs.defaultProxyUri = + "sqlite3-opfs-async-proxy.js"; +globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ + try{ + let proxyJs = installOpfsVfs.defaultProxyUri; + if( sqlite3?.scriptInfo?.sqlite3Dir ){ + installOpfsVfs.defaultProxyUri = + sqlite3.scriptInfo.sqlite3Dir + proxyJs; + //sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri); + } + return installOpfsVfs().catch((e)=>{ + sqlite3.config.warn("Ignoring inability to install OPFS sqlite3_vfs:",e.message); + }); + }catch(e){ + sqlite3.config.error("installOpfsVfs() exception:",e); + return Promise.reject(e); + } +}); +}/*sqlite3ApiBootstrap.initializers.push()*/); +//#else +/* The OPFS VFS parts are elided from builds targeting node.js. */ +//#endif target:node diff --git a/manifest b/manifest index 387c312553..52ed36f06c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypos\sin\sthe\sSQLITE_PREPARE_FROM_DDL\sdocumentation. -D 2026-02-26T16:19:21.240 +C An\sinitial\scopy/paste\sstub\sfor\sexperimenting\swith\susing\sWebLocks\sfor\sa\snew\scopy\sof\sthe\sOPFS\svfs.\sThis\sis\snot\syet\sfunctional,\sor\seven\sloading,\sbut\sneeds\sstashing\sto\savoid\spotential\sloss. +D 2026-02-27T03:11:40.358 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -605,6 +605,7 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.js 92d6d327a862f1627ff3e88e60fdfea9def06 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 17b16db29e2e0c75d00f675c17710539269e30f853da6bac9044879e298c270f F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 38484644c21b21b97f60979dddd620e47bdba628bde4ae62b6ce8859870e4f85 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 @@ -2195,8 +2196,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P c3288f16848866a2c846221c33631785f7b39938078bb95c61895f789395aa1d -R dcd62261fc7d31c8a65dd3cc5d14fd76 -U drh -Z de1179cfcfccba649912303467a12236 +P 9174e7dacf867c1f80e73ccf5e0ee7b9e84fbe9f2e53559d06b72206b1cde3c6 +R b825f5f5f6b51df161046dc5b5c20e5a +T *branch * opfs-wl +T *sym-opfs-wl * +T -sym-trunk * Cancelled\sby\sbranch. +U stephan +Z 7cdbae53834e92d0f15d611fc35ab500 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..e8a777ecb7 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch opfs-wl +tag opfs-wl diff --git a/manifest.uuid b/manifest.uuid index 1a18fe1258..f746549ef5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9174e7dacf867c1f80e73ccf5e0ee7b9e84fbe9f2e53559d06b72206b1cde3c6 +372f18ae909bafd7167b70051935832e3107ede72aaeccbf5c042db7ba791912 From d22d0edc482bd0b6ed063cd5adab8a8cb3cd917e Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 27 Feb 2026 03:21:47 +0000 Subject: [PATCH 059/197] JS: slight performance improvements in KVVfsStorage. FossilOrigin-Name: 56edf2addb155dbb60269fe563ecb5f6132672c6c61f6f9d18ebdff72111298d --- ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js | 22 +++++++++++++++------- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js index a78c0548b7..f04ae379a0 100644 --- a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js @@ -209,17 +209,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ and recreating it whenever a property index might be invalidated. */ class KVVfsStorage { - #map; - #keys; - #getKeys(){return this.#keys ??= Object.keys(this.#map);} + #map = Object.create(null); + #keys = null; + #size = 0; constructor(){ this.clear(); } + #getKeys(){ + return this.#keys ??= Object.keys(this.#map); + } + key(n){ const k = this.#getKeys(); - return n=0 && n Date: Fri, 27 Feb 2026 06:33:28 +0000 Subject: [PATCH 060/197] Another nano-optimization in kvvfs v2. FossilOrigin-Name: a9d60190d693504742a894918f145111908d7d6cb9e853ba7a2356529046372a --- ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js | 4 ++-- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js index f04ae379a0..e3fb722877 100644 --- a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js @@ -222,8 +222,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } key(n){ - const k = this.#getKeys(); - return (n>=0 && n= this.#size) return null; + return this.#getKeys()[n]; } getItem(k){ diff --git a/manifest b/manifest index dc7a3fcadc..f852498453 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C JS:\sslight\sperformance\simprovements\sin\sKVVfsStorage. -D 2026-02-27T03:21:47.234 +C Another\snano-optimization\sin\skvvfs\sv2. +D 2026-02-27T06:33:28.814 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -603,7 +603,7 @@ F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc F ext/wasm/api/sqlite3-opfs-async-proxy.js 92d6d327a862f1627ff3e88e60fdfea9def06ad539d98929ba46490e64372736 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d -F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 7f55954f5965d84d8de9e3edbe3a9010198e7964da10f6a6f740f06d4c67ed40 +F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 9174e7dacf867c1f80e73ccf5e0ee7b9e84fbe9f2e53559d06b72206b1cde3c6 -R 73e280751e913525512dae1e58b75d8d +P 56edf2addb155dbb60269fe563ecb5f6132672c6c61f6f9d18ebdff72111298d +R 5b3bfeee546454189a63527edef767f3 U stephan -Z 6b9092990679409a5bbdeb3b4b80a0ab +Z 4baa500c382a22f693cae8a172359fdd # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e8a6088f02..13f1ca1d1f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -56edf2addb155dbb60269fe563ecb5f6132672c6c61f6f9d18ebdff72111298d +a9d60190d693504742a894918f145111908d7d6cb9e853ba7a2356529046372a From c67a538168d047b1c4ad540c6efa60368c305d7f Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 27 Feb 2026 11:36:43 +0000 Subject: [PATCH 061/197] Add an assert() to sqlite3RegisterLikeFunctions() to hopefully prevent future false-positive bug reports coming out of CodeQL. FossilOrigin-Name: 7c5f4dcd748baa60097bbf68d7aca99cc959bb1f7da92bd9ad86a4425a37d391 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/func.c | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index f852498453..4b64ee0584 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Another\snano-optimization\sin\skvvfs\sv2. -D 2026-02-27T06:33:28.814 +C Add\san\sassert()\sto\ssqlite3RegisterLikeFunctions()\sto\shopefully\sprevent\nfuture\sfalse-positive\sbug\sreports\scoming\sout\sof\sCodeQL. +D 2026-02-27T11:36:43.172 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -692,7 +692,7 @@ F src/delete.c 901499bed747c3b4b2be45be1abe912ba50a3f6a40ba88cc006ccf279f2d0e97 F src/expr.c 8c3b23cb35f43c2d0570c1058b9a269e561e769e09c81ba192992c95022c1939 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c fb0f74c57d19a2d3f113f3476826919d68feda7ff334abfdb479a9a6353b9fcd -F src/func.c 785f62a6e00636c9b185ccee0cde17be711458227340137d57492ed3226d4253 +F src/func.c 6e7de3551ae0f8205006e5109f025223246edd20186d54d90746dee7c1c5c093 F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 56edf2addb155dbb60269fe563ecb5f6132672c6c61f6f9d18ebdff72111298d -R 5b3bfeee546454189a63527edef767f3 -U stephan -Z 4baa500c382a22f693cae8a172359fdd +P a9d60190d693504742a894918f145111908d7d6cb9e853ba7a2356529046372a +R 373fdc5fd31bcf352858ec23ef321693 +U drh +Z b04ae17c992b424e316fba8939b5712f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 13f1ca1d1f..0b3496514f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a9d60190d693504742a894918f145111908d7d6cb9e853ba7a2356529046372a +7c5f4dcd748baa60097bbf68d7aca99cc959bb1f7da92bd9ad86a4425a37d391 diff --git a/src/func.c b/src/func.c index 029f7ae8ef..d9d8f59ad6 100644 --- a/src/func.c +++ b/src/func.c @@ -2364,6 +2364,8 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ sqlite3CreateFunc(db, "like", nArg, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); pDef = sqlite3FindFunction(db, "like", nArg, SQLITE_UTF8, 0); + assert( pDef!=0 ); /* The sqlite3CreateFunc() call above cannot fail + ** because the "like" SQL-function already exists */ pDef->funcFlags |= flags; pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE; } From 7d9fbe64766bfe243d0cd625d2e461d24838809a Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 27 Feb 2026 13:25:42 +0000 Subject: [PATCH 062/197] Fix an off-by-one error in the indentation of multi-line outputs in QRF_STYLE_Line mode. FossilOrigin-Name: d47499b21c893cc8749a1cafe1cf712dacfeaa6cfe2cdb75d1fc450f3cb6879f --- ext/qrf/qrf.c | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- test/qrf01.test | 16 ++++++++-------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ext/qrf/qrf.c b/ext/qrf/qrf.c index ab6b898097..b78b52e6ac 100644 --- a/ext/qrf/qrf.c +++ b/ext/qrf/qrf.c @@ -2630,7 +2630,7 @@ static void qrfOneSimpleRow(Qrf *p){ do{ int nThis, nWide, iNext; qrfWrapLine(zVal, mxW, bWW, &nThis, &nWide, &iNext); - if( cnt ) sqlite3_str_appendchar(p->pOut,p->u.sLine.mxColWth+3,' '); + if( cnt ) sqlite3_str_appendchar(p->pOut,p->u.sLine.mxColWth+2,' '); cnt++; if( cnt>p->mxHeight ){ zVal = "..."; diff --git a/manifest b/manifest index 4b64ee0584..f0bf9354b2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\san\sassert()\sto\ssqlite3RegisterLikeFunctions()\sto\shopefully\sprevent\nfuture\sfalse-positive\sbug\sreports\scoming\sout\sof\sCodeQL. -D 2026-02-27T11:36:43.172 +C Fix\san\soff-by-one\serror\sin\sthe\sindentation\sof\smulti-line\soutputs\sin\nQRF_STYLE_Line\smode. +D 2026-02-27T13:25:42.245 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -420,7 +420,7 @@ F ext/misc/zipfile.c 837591f0505d21f7f7937ea046c9b0fc594f7fa3ca00c2bd54ffa1c94bf F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee F ext/qrf/README.md e6e0ce2700acf6fd06312b42726a8f08ca240f30e1b122bff87c71c602046352 F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430 -F ext/qrf/qrf.c 9216879683752773fa612849b8bc6a26b74f2a7cb9253bcbdd168092d8bfbbe2 +F ext/qrf/qrf.c 78b93d1d773bdcc667ab41716dab2fa9ad26957aa239cc1244eaff61d2cffbc9 F ext/qrf/qrf.h 2ac14b0aaacf44636d8c81051bfeab4afae50a98fbb2e10ff5aed0c28a87b2b2 F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8 F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255 @@ -1519,7 +1519,7 @@ F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224c F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/pushdown.test 46a626ef1c0ca79b85296ff2e078b9da20a50e9b804b38f441590c3987580ddd -F test/qrf01.test 1d69175c966a95c7b2897a1831ca49ba84afc1107b32f7c455e05125ac7c8d11 +F test/qrf01.test abc3e558a75ae2678a3172051b39960dc6fd4b298b6d594afa50939759f4037f F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92 F test/qrf03.test e7efe46d204671726b4707585126cd78d107368de4a7d0c7b8d5157cdd8624ed F test/qrf04.test 0894692c998d2401dcc33449c02051b503ecce0c94217be54fb007c82d2d1379 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P a9d60190d693504742a894918f145111908d7d6cb9e853ba7a2356529046372a -R 373fdc5fd31bcf352858ec23ef321693 +P 7c5f4dcd748baa60097bbf68d7aca99cc959bb1f7da92bd9ad86a4425a37d391 +R c0695f0bf4f7677e2bfd61f6b8ddb9bf U drh -Z b04ae17c992b424e316fba8939b5712f +Z 7207a3f768dad62f163ba0943026bc9d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0b3496514f..fb9082614a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7c5f4dcd748baa60097bbf68d7aca99cc959bb1f7da92bd9ad86a4425a37d391 +d47499b21c893cc8749a1cafe1cf712dacfeaa6cfe2cdb75d1fc450f3cb6879f diff --git a/test/qrf01.test b/test/qrf01.test index 2eb189b0bf..3ae0279577 100644 --- a/test/qrf01.test +++ b/test/qrf01.test @@ -697,13 +697,13 @@ do_test 5.2b { mtime: 1333101221 datetime(...: 2012-03-30 09:53:41 value: x'cc7c57616c706861b535332e31313638383732334762 - 657461c73071726657696474685072696e7428702c2070 - 2d3e704f75742c202d702d3e752e734c696e652e6d7843 - ... + 657461c73071726657696474685072696e7428702c2070 + 2d3e704f75742c202d702d3e752e734c696e652e6d7843 + ... name: one - two - three + two + three mtime: 1333206973 datetime(...: 2012-03-31 15:16:13 value: @@ -712,9 +712,9 @@ datetime(...: 2012-03-31 15:16:13 mtime: 1708791504 datetime(...: 2024-02-24 16:18:24 value: x'00000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000 - ... + 0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000 + ... } set sql "SELECT name, mtime, datetime(mtime,'unixepoch') AS time,\ value FROM t1 ORDER BY mtime" From f707e2ec5d4144bd41922ff35594762496756a72 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 27 Feb 2026 18:32:12 +0000 Subject: [PATCH 063/197] Two code comment typo fixes reported in the forum. No code changes. FossilOrigin-Name: 3fbd28fabc5509a0bf2026cb60891d6d3efe251910baa3a3934225d0a7187bfa --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/parse.y | 2 +- src/select.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index f0bf9354b2..b9a72a1ea6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\soff-by-one\serror\sin\sthe\sindentation\sof\smulti-line\soutputs\sin\nQRF_STYLE_Line\smode. -D 2026-02-27T13:25:42.245 +C Two\scode\scomment\stypo\sfixes\sreported\sin\sthe\sforum.\sNo\scode\schanges. +D 2026-02-27T18:32:12.368 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -728,7 +728,7 @@ F src/os_win.c 0d553b6e8b92c8eb85e7f1b4a8036fe8638c8b32c9ad8d9d72a861c10f81b4c5 F src/os_win.h 5e168adf482484327195d10f9c3bce3520f598e04e07ffe62c9c5a8067c1037b F src/pager.c fe34fd22ec251436985d7b6ebdd05bf238a17901c2cb23d3d28974dd2361a912 F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8 -F src/parse.y 7c2184b5665c671258c4e96a10bbc9dbf7e1ede462ebc4e614249de0d54c8a26 +F src/parse.y 3b784d6083380a950e3b1b32ce5ddd303e8c7c209d8ab788df2c62aaf9ee8eb3 F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484 F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd @@ -738,7 +738,7 @@ F src/printf.c 9cff219dba73b1aa9a8113e83e962f03f7bea8b6eb51cefb25bc468d5a69fb2d F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c +F src/select.c 8fe87c39a45037dac2e3dc02e1dc13ca09c1155cc14df9daaa65e5318179beaf F src/shell.c.in 2acdfca982deb70cdfefb8b422822d4e0234fe4dde6ff2bd9020b26445853917 F src/sqlite.h.in 1f853f1d836af3e5a0b451521041d05658988a45f6978aaae08286e483fee5ac F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 7c5f4dcd748baa60097bbf68d7aca99cc959bb1f7da92bd9ad86a4425a37d391 -R c0695f0bf4f7677e2bfd61f6b8ddb9bf -U drh -Z 7207a3f768dad62f163ba0943026bc9d +P d47499b21c893cc8749a1cafe1cf712dacfeaa6cfe2cdb75d1fc450f3cb6879f +R 612a2e5dd9ca10ceec362c816e047b27 +U stephan +Z 37981c0c0433582c0b5d3fcf8366b6e3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fb9082614a..c29fad6e5b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d47499b21c893cc8749a1cafe1cf712dacfeaa6cfe2cdb75d1fc450f3cb6879f +3fbd28fabc5509a0bf2026cb60891d6d3efe251910baa3a3934225d0a7187bfa diff --git a/src/parse.y b/src/parse.y index cbcc9b43ae..f5a6bed14b 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1427,7 +1427,7 @@ expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] { expr(A) ::= expr(A) ISNULL|NOTNULL(E). {A = sqlite3PExprIsNull(pParse,@E,A);} expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExprIsNull(pParse,TK_NOTNULL,A);} -// expr1 IS expr2 same as expr1 IS NOT DISTICT FROM expr2 +// expr1 IS expr2 same as expr1 IS NOT DISTINCT FROM expr2 // expr1 IS NOT expr2 same as expr1 IS DISTINCT FROM expr2 // expr(A) ::= expr(A) IS expr(Y). { diff --git a/src/select.c b/src/select.c index e75de96d5c..62e73a699c 100644 --- a/src/select.c +++ b/src/select.c @@ -21,7 +21,7 @@ */ typedef struct DistinctCtx DistinctCtx; struct DistinctCtx { - u8 isTnct; /* 0: Not distinct. 1: DISTICT 2: DISTINCT and ORDER BY */ + u8 isTnct; /* 0: Not distinct. 1: DISTINCT 2: DISTINCT and ORDER BY */ u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ int tabTnct; /* Ephemeral table used for DISTINCT processing */ int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ From afaf7ea2e4f5d585e71dce8fb8c058158e710603 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 27 Feb 2026 20:37:03 +0000 Subject: [PATCH 064/197] Minor simplification to the text→binary64 conversion algorithm. FossilOrigin-Name: 6632d51f1673e9a6b6e26baebc7aaa1ae27024ad5db1baff6ee5fcf865099f43 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/util.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index b9a72a1ea6..59031e860c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Two\scode\scomment\stypo\sfixes\sreported\sin\sthe\sforum.\sNo\scode\schanges. -D 2026-02-27T18:32:12.368 +C Minor\ssimplification\sto\sthe\stext→binary64\sconversion\salgorithm. +D 2026-02-27T20:37:03.759 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 95f8f7574c8f65039e341f0c905267121569ebf4d0de026c44ee1809fe00d5bf +F src/util.c aaa5fbad1bcecdb8a873950aeabfddf47814cbdb258b9c774041a33d7aee739f F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d47499b21c893cc8749a1cafe1cf712dacfeaa6cfe2cdb75d1fc450f3cb6879f -R 612a2e5dd9ca10ceec362c816e047b27 -U stephan -Z 37981c0c0433582c0b5d3fcf8366b6e3 +P 3fbd28fabc5509a0bf2026cb60891d6d3efe251910baa3a3934225d0a7187bfa +R 5d85555e5b7026b5225f749aa45ba7e8 +U drh +Z 872a2fa601913fc9cb45b1534ed4798c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c29fad6e5b..91c2fbb502 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3fbd28fabc5509a0bf2026cb60891d6d3efe251910baa3a3934225d0a7187bfa +6632d51f1673e9a6b6e26baebc7aaa1ae27024ad5db1baff6ee5fcf865099f43 diff --git a/src/util.c b/src/util.c index b287263d42..c56a2795fa 100644 --- a/src/util.c +++ b/src/util.c @@ -701,7 +701,7 @@ static double sqlite3Fp10Convert2(u64 d, int p){ if( e1<=(-972) ){ return INFINITY; } - out = (out + 1 + ((out>>2)&1)) >> 2; + out = (out + 1) >> 2; if( (out & U64_BIT(52))!=0 ){ out = (out & ~U64_BIT(52)) | ((u64)(1075-e1)<<52); } From 7ac310d0c69737bba0098f9b4486c44b45fc7ef6 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 27 Feb 2026 22:59:46 +0000 Subject: [PATCH 065/197] Improvements to power-of-ten computations used for text ↔ binary64 conversions. FossilOrigin-Name: 0780bce854b962fb2d4a1a19c55c9b5790a9669f26e1ff8b5f1f1733cfc647e0 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 22 +++++++++++----------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index 59031e860c..338b165797 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\ssimplification\sto\sthe\stext→binary64\sconversion\salgorithm. -D 2026-02-27T20:37:03.759 +C Improvements\sto\spower-of-ten\scomputations\sused\sfor\stext\s↔\sbinary64\nconversions. +D 2026-02-27T22:59:46.633 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c aaa5fbad1bcecdb8a873950aeabfddf47814cbdb258b9c774041a33d7aee739f +F src/util.c 4769c290c2325d058a65f38a0056da39cbed1ad372c5a7184732ffa779261db6 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 3fbd28fabc5509a0bf2026cb60891d6d3efe251910baa3a3934225d0a7187bfa -R 5d85555e5b7026b5225f749aa45ba7e8 +P 6632d51f1673e9a6b6e26baebc7aaa1ae27024ad5db1baff6ee5fcf865099f43 +R 780d0868274477455c94d9f95a020fbe U drh -Z 872a2fa601913fc9cb45b1534ed4798c +Z e4a510a255d84f66bd7f025adf1138d4 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 91c2fbb502..59d81d1399 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6632d51f1673e9a6b6e26baebc7aaa1ae27024ad5db1baff6ee5fcf865099f43 +0780bce854b962fb2d4a1a19c55c9b5790a9669f26e1ff8b5f1f1733cfc647e0 diff --git a/src/util.c b/src/util.c index c56a2795fa..3ba31da98b 100644 --- a/src/util.c +++ b/src/util.c @@ -546,28 +546,28 @@ static u64 powerOfTen(int p){ static const u64 aScale[] = { 0x8049a4ac0c5811aeLLU, /* 0: 1.0e-351 << 1229 */ 0xcf42894a5dce35eaLLU, /* 1: 1.0e-324 << 1140 */ - 0xa76c582338ed2621LLU, /* 2: 1.0e-297 << 1050 */ + 0xa76c582338ed2622LLU, /* 2: 1.0e-297 << 1050 */ 0x873e4f75e2224e68LLU, /* 3: 1.0e-270 << 960 */ - 0xda7f5bf590966848LLU, /* 4: 1.0e-243 << 871 */ - 0xb080392cc4349decLLU, /* 5: 1.0e-216 << 781 */ + 0xda7f5bf590966849LLU, /* 4: 1.0e-243 << 871 */ + 0xb080392cc4349dedLLU, /* 5: 1.0e-216 << 781 */ 0x8e938662882af53eLLU, /* 6: 1.0e-189 << 691 */ 0xe65829b3046b0afaLLU, /* 7: 1.0e-162 << 602 */ - 0xba121a4650e4ddebLLU, /* 8: 1.0e-135 << 512 */ + 0xba121a4650e4ddecLLU, /* 8: 1.0e-135 << 512 */ 0x964e858c91ba2655LLU, /* 9: 1.0e-108 << 422 */ - 0xf2d56790ab41c2a2LLU, /* 10: 1.0e-81 << 333 */ - 0xc428d05aa4751e4cLLU, /* 11: 1.0e-54 << 243 */ + 0xf2d56790ab41c2a3LLU, /* 10: 1.0e-81 << 333 */ + 0xc428d05aa4751e4dLLU, /* 11: 1.0e-54 << 243 */ 0x9e74d1b791e07e48LLU, /* 12: 1.0e-27 << 153 */ 0x8000000000000000LLU, /* 13: 1.0e+0 << 63 */ 0xcecb8f27f4200f3aLLU, /* 14: 1.0e+27 >> 26 */ - 0xa70c3c40a64e6c51LLU, /* 15: 1.0e+54 >> 116 */ + 0xa70c3c40a64e6c52LLU, /* 15: 1.0e+54 >> 116 */ 0x86f0ac99b4e8dafdLLU, /* 16: 1.0e+81 >> 206 */ - 0xda01ee641a708de9LLU, /* 17: 1.0e+108 >> 295 */ + 0xda01ee641a708deaLLU, /* 17: 1.0e+108 >> 295 */ 0xb01ae745b101e9e4LLU, /* 18: 1.0e+135 >> 385 */ 0x8e41ade9fbebc27dLLU, /* 19: 1.0e+162 >> 475 */ - 0xe5d3ef282a242e81LLU, /* 20: 1.0e+189 >> 564 */ + 0xe5d3ef282a242e82LLU, /* 20: 1.0e+189 >> 564 */ 0xb9a74a0637ce2ee1LLU, /* 21: 1.0e+216 >> 654 */ 0x95f83d0a1fb69cd9LLU, /* 22: 1.0e+243 >> 744 */ - 0xf24a01a73cf2dccfLLU, /* 23: 1.0e+270 >> 833 */ + 0xf24a01a73cf2dcd0LLU, /* 23: 1.0e+270 >> 833 */ 0xc3b8358109e84f07LLU, /* 24: 1.0e+297 >> 923 */ 0x9e19db92b4e31ba9LLU, /* 25: 1.0e+324 >> 1013 */ }; @@ -594,7 +594,7 @@ static u64 powerOfTen(int p){ } x = sqlite3Multiply128(aBase[n],y); if( (U64_BIT(63) & x)==0 ){ - x <<= 1; + x = (x<<1)|1; } return x; } From a000db975424962e28186641ad93d47f3c3e72c2 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 28 Feb 2026 20:22:10 +0000 Subject: [PATCH 066/197] Code changes in sqlite3Fp10Convert2() for easier maintenance. Does not affect the generated machine code. FossilOrigin-Name: 21c8fc7100e23b632b77934cbbafb98dfd3e6e73bab702446ef6345b378c9d36 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 10 ++++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 338b165797..fea4c94d67 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\spower-of-ten\scomputations\sused\sfor\stext\s↔\sbinary64\nconversions. -D 2026-02-27T22:59:46.633 +C Code\schanges\sin\ssqlite3Fp10Convert2()\sfor\seasier\smaintenance.\s\sDoes\snot\naffect\sthe\sgenerated\smachine\scode. +D 2026-02-28T20:22:10.499 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 4769c290c2325d058a65f38a0056da39cbed1ad372c5a7184732ffa779261db6 +F src/util.c 367d14ee23de8f5dd77a5a57ba0eba7f27108feb32750fff191e04317c36a19b F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 6632d51f1673e9a6b6e26baebc7aaa1ae27024ad5db1baff6ee5fcf865099f43 -R 780d0868274477455c94d9f95a020fbe +P 0780bce854b962fb2d4a1a19c55c9b5790a9669f26e1ff8b5f1f1733cfc647e0 +R 31f541b8320013c073025618707ba1b2 U drh -Z e4a510a255d84f66bd7f025adf1138d4 +Z 27e14806d84c6d235e25b0158b899e3c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 59d81d1399..485e417c4b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0780bce854b962fb2d4a1a19c55c9b5790a9669f26e1ff8b5f1f1733cfc647e0 +21c8fc7100e23b632b77934cbbafb98dfd3e6e73bab702446ef6345b378c9d36 diff --git a/src/util.c b/src/util.c index 3ba31da98b..1ac2553025 100644 --- a/src/util.c +++ b/src/util.c @@ -672,6 +672,7 @@ static double sqlite3Fp10Convert2(u64 d, int p){ int e1; int e2; int lp; + int x; u64 h; double r; assert( (d & U64_BIT(63))==0 ); @@ -691,11 +692,12 @@ static double sqlite3Fp10Convert2(u64 d, int p){ } e2 = e1 - (64-b); h = sqlite3Multiply128(d<<(64-b), powerOfTen(p)); - assert( -(e2 + lp + 3) >=0 ); - assert( -(e2 + lp + 3) <64 ); - out = (h >> -(e2 + lp + 3)) | 1; + x = -(e2 + lp + 3); + assert( x >= 0 ); + assert( x <= 63 ); + out = (h >> x) | 1; if( out >= U64_BIT(55)-2 ){ - out = (out>>1) | (out&1); + out = (out>>1) | 1; e1--; } if( e1<=(-972) ){ From 83de60bd7ba2e101e1c33ae34d1339125e2b453d Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 1 Mar 2026 20:22:08 +0000 Subject: [PATCH 067/197] Simplified rounding logic in sqlite3Fp10Convert2(). FossilOrigin-Name: 8ac63ebc5c04ba555bbf0d878a70e25deba5fcc75ff44c464600b92c27e5dcb0 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/util.c | 20 +++++++++----------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index fea4c94d67..51a63a8cf2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Code\schanges\sin\ssqlite3Fp10Convert2()\sfor\seasier\smaintenance.\s\sDoes\snot\naffect\sthe\sgenerated\smachine\scode. -D 2026-02-28T20:22:10.499 +C Simplified\srounding\slogic\sin\ssqlite3Fp10Convert2(). +D 2026-03-01T20:22:08.292 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -803,7 +803,7 @@ F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 367d14ee23de8f5dd77a5a57ba0eba7f27108feb32750fff191e04317c36a19b +F src/util.c eccfa8b3b414bb64c6543421c9fd10e5f07e103baae36427a273a9131527694c F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 0780bce854b962fb2d4a1a19c55c9b5790a9669f26e1ff8b5f1f1733cfc647e0 -R 31f541b8320013c073025618707ba1b2 +P 21c8fc7100e23b632b77934cbbafb98dfd3e6e73bab702446ef6345b378c9d36 +R af3efb8f8f323da927b8fb2503c5d89e U drh -Z 27e14806d84c6d235e25b0158b899e3c +Z 73d1b37c301d10277342aa84d5761b61 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 485e417c4b..df2b0bf426 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -21c8fc7100e23b632b77934cbbafb98dfd3e6e73bab702446ef6345b378c9d36 +8ac63ebc5c04ba555bbf0d878a70e25deba5fcc75ff44c464600b92c27e5dcb0 diff --git a/src/util.c b/src/util.c index 1ac2553025..071029173d 100644 --- a/src/util.c +++ b/src/util.c @@ -668,9 +668,8 @@ static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){ */ static double sqlite3Fp10Convert2(u64 d, int p){ u64 out; - int b; int e1; - int e2; + int lz; int lp; int x; u64 h; @@ -683,27 +682,26 @@ static double sqlite3Fp10Convert2(u64 d, int p){ if( p>POWERSOF10_LAST ){ return INFINITY; } - b = 64 - countLeadingZeros(d); + lz = countLeadingZeros(d); lp = pwr10to2(p); - e1 = 53 - b - lp; + e1 = lz - (lp + 11); if( e1>1074 ){ - if( -(b + lp) >= 1077 ) return 0.0; + if( e1>=1130 ) return 0.0; e1 = 1074; } - e2 = e1 - (64-b); - h = sqlite3Multiply128(d<<(64-b), powerOfTen(p)); - x = -(e2 + lp + 3); + h = sqlite3Multiply128(d<= 0 ); assert( x <= 63 ); - out = (h >> x) | 1; + out = h >> x; if( out >= U64_BIT(55)-2 ){ - out = (out>>1) | 1; + out >>= 1; e1--; } if( e1<=(-972) ){ return INFINITY; } - out = (out + 1) >> 2; + out = (out + 2) >> 2; if( (out & U64_BIT(52))!=0 ){ out = (out & ~U64_BIT(52)) | ((u64)(1075-e1)<<52); } From e293b2d835c0de26d2326377539b294c682a5235 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 1 Mar 2026 22:36:02 +0000 Subject: [PATCH 068/197] Fix an OOB read in the incremental integrity-check extension. FossilOrigin-Name: abecc8e388e294311aa0b572e0a984b8ddad2afbf829c1246e1682fa549c8fac --- ext/intck/sqlite3intck.c | 2 +- manifest | 15 ++++++++------- manifest.uuid | 2 +- test/intck01.sql | 23 +++++++++++++++++++++++ test/shellB.test | 1 + 5 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 test/intck01.sql diff --git a/ext/intck/sqlite3intck.c b/ext/intck/sqlite3intck.c index 5f645fae6e..e3fef77637 100644 --- a/ext/intck/sqlite3intck.c +++ b/ext/intck/sqlite3intck.c @@ -319,7 +319,7 @@ static int intckGetToken(const char *z){ char c = z[0]; int iRet = 1; if( c=='\'' || c=='"' || c=='`' ){ - while( 1 ){ + while( z[iRet] ){ if( z[iRet]==c ){ iRet++; if( z[iRet]!=c ) break; diff --git a/manifest b/manifest index 51a63a8cf2..7fbf9ca49a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplified\srounding\slogic\sin\ssqlite3Fp10Convert2(). -D 2026-03-01T20:22:08.292 +C Fix\san\sOOB\sread\sin\sthe\sincremental\sintegrity-check\sextension. +D 2026-03-01T22:36:02.371 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -285,7 +285,7 @@ F ext/intck/intck_common.tcl a61fd2697ae55b0a3d89847ca0b590c6e0d8ff64bebb70920d9 F ext/intck/intckbusy.test d5ed4ef85a4b1dc1dee2484bd14a4bb68529659cca743327df0c775f005fa387 F ext/intck/intckcorrupt.test f6c302792326fb3db9dcfc70b554c55369bc4b52882eaaf039cfe0b74c821029 F ext/intck/intckfault.test cff3f75dff74abb3edfcb13f6aa53f6436746ab64b09fe5e2028f051e985efab -F ext/intck/sqlite3intck.c b1c8a86f90fc00741d13314db9c58f7e2f92d1d19c5ad1c6904ec83a6bbd5c96 +F ext/intck/sqlite3intck.c 3c4a166645a1624731f63acd342e24e81e4ffd497116d94a427d72e6cc6caa69 F ext/intck/sqlite3intck.h 2b40c38e7063ab822c974c0bd4aed97dabb579ccfe2e180a4639bb3bbef0f1c9 F ext/intck/test_intck.c 4f9eaadaedccb9df1d26ba41116a0a8e5b0c5556dc3098c8ff68633adcccdea8 F ext/jni/GNUmakefile 8a94e3a1953b88cf117fb2a5380480feada8b4f5316f02572cab425030a720b4 @@ -1315,6 +1315,7 @@ F test/insertfault.test ac63d14ea3b49c573673a572f4014b9117383a03e497c58f308b5c77 F test/instr.test 67ba309e9697c24a304e98a7c8f372456177dd4e32237d2a305e1e05f7bb79c2 F test/instrfault.test 95e28efade652e6d51ae11b377088fe523a581a07ec428009e152a4dd0e0f44c F test/intarray.test bb976b0b3df0ebb6a2eddfb61768280440e672beba5460ed49679ea984ccf440 +F test/intck01.sql f2d88bf41cdd64f2ed8c3d4f357cf520f017aa2986999ab9a62eb6506ef18106 F test/interrupt.test ac1ef50ec9ab8e4f0e17c47629f82539d4b22558904e321ed5abea2e6187da7a F test/interrupt2.test e4408ca770a6feafbadb0801e54a0dcd1a8d108d F test/intpkey.test 7d54711acf553cdd641a40e9c6cfc2bf1a76070074940c1b126442517054320f @@ -1629,7 +1630,7 @@ F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d F test/shell8.test 38c9e4d7e85d2a3ecfacaa9f6cda4f7a81bf4fffb5f3f37f9cd76827c6883192 F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209 F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480 -F test/shellB.test b2afd5c28aba750c066996a082210d6a4fcab8fd042cad076d9c1023164af9b1 +F test/shellB.test 1f0a95bf8c7047a385f54b69b272887e1efeb3d8f34e6f09ed2f865083bbfc3e F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 @@ -2195,8 +2196,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 21c8fc7100e23b632b77934cbbafb98dfd3e6e73bab702446ef6345b378c9d36 -R af3efb8f8f323da927b8fb2503c5d89e +P 8ac63ebc5c04ba555bbf0d878a70e25deba5fcc75ff44c464600b92c27e5dcb0 +R 3fa7dbd1f9c7e7bf7f235a0b6a9eb234 U drh -Z 73d1b37c301d10277342aa84d5761b61 +Z 3bb8f45dd6d08d23bece1f3ddd3cf2c3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index df2b0bf426..84929cd5ee 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8ac63ebc5c04ba555bbf0d878a70e25deba5fcc75ff44c464600b92c27e5dcb0 +abecc8e388e294311aa0b572e0a984b8ddad2afbf829c1246e1682fa549c8fac diff --git a/test/intck01.sql b/test/intck01.sql new file mode 100644 index 0000000000..b1996aeeb9 --- /dev/null +++ b/test/intck01.sql @@ -0,0 +1,23 @@ +#!sqlite3 +# +# 2026-03-01 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Bug report sqlite.org/forum/forumpost/efc9bc9cb3 +# +.testcase 100 +.mode quote +.intck 1 +SELECT parse_create_index('CREATE IDEX i ON t("x',0); +.check < Date: Sun, 1 Mar 2026 23:01:17 +0000 Subject: [PATCH 069/197] New floating-point test case. FossilOrigin-Name: f353399932e9797198e635405a594c2987850070e3f9aee87a05c5a65d4c1e00 --- manifest | 13 +++++++------ manifest.uuid | 2 +- test/fptest01.sql | 33 +++++++++++++++++++++++++++++++++ test/shellB.test | 1 + 4 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 test/fptest01.sql diff --git a/manifest b/manifest index 7fbf9ca49a..d7f1070582 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sOOB\sread\sin\sthe\sincremental\sintegrity-check\sextension. -D 2026-03-01T22:36:02.371 +C New\sfloating-point\stest\scase. +D 2026-03-01T23:01:17.452 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -1132,6 +1132,7 @@ F test/fork-test.c 9ac2e6423a1d38df3d6be0e8ac15608b545de21e2b19d9d876254c5931b63 F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4 F test/fp-speed-1.c b37de94eba034e1703668816225f54510ec60fb0685406608cc707afe6b8234d F test/fpconv1.test 63f352682fa65601a326563ad633086df6ab194e6ed5e7366786f38a525a7fd7 +F test/fptest01.sql 73caa1c71ff0d74d5e76d9ad98d9c4a26f3d928f3cd7f737196cf209dffe7cae F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654 F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a @@ -1630,7 +1631,7 @@ F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d F test/shell8.test 38c9e4d7e85d2a3ecfacaa9f6cda4f7a81bf4fffb5f3f37f9cd76827c6883192 F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209 F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480 -F test/shellB.test 1f0a95bf8c7047a385f54b69b272887e1efeb3d8f34e6f09ed2f865083bbfc3e +F test/shellB.test 73fd5aa8c126f6941493e22598bc9864be4af670bc989b426443a2baebc104dd F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 @@ -2196,8 +2197,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 8ac63ebc5c04ba555bbf0d878a70e25deba5fcc75ff44c464600b92c27e5dcb0 -R 3fa7dbd1f9c7e7bf7f235a0b6a9eb234 +P abecc8e388e294311aa0b572e0a984b8ddad2afbf829c1246e1682fa549c8fac +R 3a662ca0649735fc41e920572fb64776 U drh -Z 3bb8f45dd6d08d23bece1f3ddd3cf2c3 +Z 42f0fd55beedce180599a4c54b875ae0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 84929cd5ee..92ecd4ac90 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -abecc8e388e294311aa0b572e0a984b8ddad2afbf829c1246e1682fa549c8fac +f353399932e9797198e635405a594c2987850070e3f9aee87a05c5a65d4c1e00 diff --git a/test/fptest01.sql b/test/fptest01.sql new file mode 100644 index 0000000000..af9307b7a8 --- /dev/null +++ b/test/fptest01.sql @@ -0,0 +1,33 @@ +#!sqlite3 +# +# 2026-03-01 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Floating-point to text conversions +# + +# Verify that binary64 -> text -> binary64 conversions round-trip +# successfully for 98,256 different edge-case binary64 values. The +# query result is all cases that do not round-trip without change, +# and so the query result should be an empty set. +# +.testcase 100 +.mode list +WITH + i1(i) AS (VALUES(0) UNION ALL SELECT i+1 FROM i1 WHERE i<15), + i2(j) AS (VALUES(0) UNION ALL SELECT j+1 FROM i2 WHERE j<0x7fe), + i3(k) AS (VALUES(0x0000000000000000), + (0x000fffffffffff00), + (0x0008080808080800)), + fpint(n) AS (SELECT (j<<52)+i+k FROM i2, i1, i3), + fp(n,r) AS (SELECT n, ieee754_from_int(n) FROM fpint) +SELECT n, r FROM fp WHERE r<>(0.0 + (r||'')); +.check '' diff --git a/test/shellB.test b/test/shellB.test index 7260875950..183465ac6a 100644 --- a/test/shellB.test +++ b/test/shellB.test @@ -48,5 +48,6 @@ ifcapable vtab { do_clitest import01.sql } do_clitest intck01.sql +do_clitest fptest01.sql finish_test From ffaf9110f64e9c156ac077a6276fe720e0924009 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 1 Mar 2026 23:23:52 +0000 Subject: [PATCH 070/197] More floating point conversion test cases. FossilOrigin-Name: 44a736a700ab12b398873400dc06cd334817842b4fa08bf8070a9ad6dbff0b51 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/fptest01.sql | 45 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d7f1070582..84db63d7c0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\sfloating-point\stest\scase. -D 2026-03-01T23:01:17.452 +C More\sfloating\spoint\sconversion\stest\scases. +D 2026-03-01T23:23:52.724 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -1132,7 +1132,7 @@ F test/fork-test.c 9ac2e6423a1d38df3d6be0e8ac15608b545de21e2b19d9d876254c5931b63 F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4 F test/fp-speed-1.c b37de94eba034e1703668816225f54510ec60fb0685406608cc707afe6b8234d F test/fpconv1.test 63f352682fa65601a326563ad633086df6ab194e6ed5e7366786f38a525a7fd7 -F test/fptest01.sql 73caa1c71ff0d74d5e76d9ad98d9c4a26f3d928f3cd7f737196cf209dffe7cae +F test/fptest01.sql 210562ad8d5a7895f26273dd3be56561a41bcb51d78a28a337af0f1ceaa3bb8d F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654 F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a @@ -2197,8 +2197,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P abecc8e388e294311aa0b572e0a984b8ddad2afbf829c1246e1682fa549c8fac -R 3a662ca0649735fc41e920572fb64776 +P f353399932e9797198e635405a594c2987850070e3f9aee87a05c5a65d4c1e00 +R 6cbc7c2f243f2aec8662e3be08e46909 U drh -Z 42f0fd55beedce180599a4c54b875ae0 +Z bb1e7d38e72f541a9df8b1768869daa5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 92ecd4ac90..f227ffdecd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f353399932e9797198e635405a594c2987850070e3f9aee87a05c5a65d4c1e00 +44a736a700ab12b398873400dc06cd334817842b4fa08bf8070a9ad6dbff0b51 diff --git a/test/fptest01.sql b/test/fptest01.sql index af9307b7a8..6221760cf9 100644 --- a/test/fptest01.sql +++ b/test/fptest01.sql @@ -25,9 +25,52 @@ WITH i1(i) AS (VALUES(0) UNION ALL SELECT i+1 FROM i1 WHERE i<15), i2(j) AS (VALUES(0) UNION ALL SELECT j+1 FROM i2 WHERE j<0x7fe), i3(k) AS (VALUES(0x0000000000000000), - (0x000fffffffffff00), + (0x000ffffffffffff0), (0x0008080808080800)), fpint(n) AS (SELECT (j<<52)+i+k FROM i2, i1, i3), fp(n,r) AS (SELECT n, ieee754_from_int(n) FROM fpint) SELECT n, r FROM fp WHERE r<>(0.0 + (r||'')); .check '' + +# Another batch of 106,444 edge cases: All postiive floating point +# values that have only a single bit set in the mantissa part of the +# number. +# +.testcase 110 +WITH + i1(i) AS (VALUES(0) UNION ALL SELECT i+1 FROM i1 WHERE i<51), + i2(j) AS (VALUES(0) UNION ALL SELECT j+1 FROM i2 WHERE j<0x7fe), + fpint(n) AS (SELECT (j<<52)+(1<(0.0 + (r||'')); +.check '' + +# Verify that text -> binary64 conversions agree with system strtod(). +# for 98,256 different edge-cases. +# +.testcase 200 +.mode list +WITH + i1(i) AS (VALUES(0) UNION ALL SELECT i+1 FROM i1 WHERE i<15), + i2(j) AS (VALUES(0) UNION ALL SELECT j+1 FROM i2 WHERE j<0x7fe), + i3(k) AS (VALUES(0x0000000000000000), + (0x000ffffffffffff0), + (0x0008080808080800)), + fpint(n) AS (SELECT (j<<52)+i+k FROM i2, i1, i3), + fp(r) AS (SELECT ieee754_from_int(n) FROM fpint) +SELECT r FROM fp WHERE r<>strtod(r||''); +.check '' + + +# Another batch of 106,444 edge cases: All postiive floating point +# values that have only a single bit set in the mantissa part of the +# number. +# +.testcase 210 +WITH + i1(i) AS (VALUES(0) UNION ALL SELECT i+1 FROM i1 WHERE i<51), + i2(j) AS (VALUES(0) UNION ALL SELECT j+1 FROM i2 WHERE j<0x7fe), + fpint(n) AS (SELECT (j<<52)+(1<strtod(r||''); +.check '' From 93ad2e083e5507df02ded046575507c6e514f379 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 2 Mar 2026 00:06:02 +0000 Subject: [PATCH 071/197] The intck01.sql test should only be run if virtual tables work. FossilOrigin-Name: 641d6f31a7f7b4901061e24d4e624da5ed92282e79771bb019b82a882e5d1ae9 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/shellB.test | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 84db63d7c0..50991c7785 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\sfloating\spoint\sconversion\stest\scases. -D 2026-03-01T23:23:52.724 +C The\sintck01.sql\stest\sshould\sonly\sbe\srun\sif\svirtual\stables\swork. +D 2026-03-02T00:06:02.937 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -1631,7 +1631,7 @@ F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d F test/shell8.test 38c9e4d7e85d2a3ecfacaa9f6cda4f7a81bf4fffb5f3f37f9cd76827c6883192 F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209 F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480 -F test/shellB.test 73fd5aa8c126f6941493e22598bc9864be4af670bc989b426443a2baebc104dd +F test/shellB.test 7123d231158588401f332bf278754687b83ba5fc5b352ec8679fb19edfb4cc0a F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 @@ -2197,8 +2197,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f353399932e9797198e635405a594c2987850070e3f9aee87a05c5a65d4c1e00 -R 6cbc7c2f243f2aec8662e3be08e46909 +P 44a736a700ab12b398873400dc06cd334817842b4fa08bf8070a9ad6dbff0b51 +R 223513abbf0ce70fff122c39b03fcaaa U drh -Z bb1e7d38e72f541a9df8b1768869daa5 +Z d849c91a511c5348b9d66726e2bd71d7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f227ffdecd..007165ec47 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -44a736a700ab12b398873400dc06cd334817842b4fa08bf8070a9ad6dbff0b51 +641d6f31a7f7b4901061e24d4e624da5ed92282e79771bb019b82a882e5d1ae9 diff --git a/test/shellB.test b/test/shellB.test index 183465ac6a..d98a77cb5f 100644 --- a/test/shellB.test +++ b/test/shellB.test @@ -46,8 +46,8 @@ do_clitest imposter1.sql do_clitest dotcmd01.sql ifcapable vtab { do_clitest import01.sql + do_clitest intck01.sql } -do_clitest intck01.sql do_clitest fptest01.sql finish_test From 33478099c96c7921c8fd869bdb937c2dfc436358 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 2 Mar 2026 11:22:28 +0000 Subject: [PATCH 072/197] Fix a possible 9-byte buffer overread in the zipfile extension hit when processing a corrupt zip file. Forum post [forum:/forumpost/721a05d2c5 | 721a05d2c5]. FossilOrigin-Name: 5db21813d126554d80db903be6d36ab6c1f73f9135a54af6dcfcfce0bcc18e68 --- ext/misc/zipfile.c | 7 ++++++- manifest | 16 ++++++++-------- manifest.uuid | 2 +- test/zipfile2.test | 15 +++++++++++++++ 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/ext/misc/zipfile.c b/ext/misc/zipfile.c index 086b058cc5..c4862650b3 100644 --- a/ext/misc/zipfile.c +++ b/ext/misc/zipfile.c @@ -705,7 +705,12 @@ static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){ u8 *p = aExtra; u8 *pEnd = &aExtra[nExtra]; - while( p Date: Mon, 2 Mar 2026 11:41:48 +0000 Subject: [PATCH 073/197] Use only 64-bit memory allocation in FTS5. Fix for UAF reported by Zijie Zhao. FossilOrigin-Name: e8976d5041c929675772039b7a8fc4ff0b609537d86f9aa6e445ecd512a10673 --- ext/fts5/fts5_aux.c | 2 +- ext/fts5/fts5_buffer.c | 2 +- ext/fts5/fts5_config.c | 4 +--- ext/fts5/fts5_expr.c | 4 ++-- ext/fts5/fts5_hash.c | 2 +- ext/fts5/fts5_index.c | 29 +++++++++++++++-------------- ext/fts5/fts5_main.c | 4 ++-- ext/fts5/fts5_tcl.c | 8 ++++---- ext/fts5/fts5_test_tok.c | 10 +++++----- ext/fts5/fts5_tokenize.c | 8 ++++---- ext/fts5/fts5_vocab.c | 2 +- manifest | 34 +++++++++++++++++----------------- manifest.uuid | 2 +- 13 files changed, 55 insertions(+), 56 deletions(-) diff --git a/ext/fts5/fts5_aux.c b/ext/fts5/fts5_aux.c index 95b33ea318..ee43ca6cca 100644 --- a/ext/fts5/fts5_aux.c +++ b/ext/fts5/fts5_aux.c @@ -455,7 +455,7 @@ static void fts5SnippetFunction( iBestCol = (iCol>=0 ? iCol : 0); nPhrase = pApi->xPhraseCount(pFts); - aSeen = sqlite3_malloc(nPhrase); + aSeen = sqlite3_malloc64(nPhrase); if( aSeen==0 ){ rc = SQLITE_NOMEM; } diff --git a/ext/fts5/fts5_buffer.c b/ext/fts5/fts5_buffer.c index afcd83b6ba..d799e34cb4 100644 --- a/ext/fts5/fts5_buffer.c +++ b/ext/fts5/fts5_buffer.c @@ -288,7 +288,7 @@ char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){ if( nIn<0 ){ nIn = (int)strlen(pIn); } - zRet = (char*)sqlite3_malloc(nIn+1); + zRet = (char*)sqlite3_malloc64((i64)nIn+1); if( zRet ){ memcpy(zRet, pIn, nIn); zRet[nIn] = '\0'; diff --git a/ext/fts5/fts5_config.c b/ext/fts5/fts5_config.c index eea82b046d..cea14b500b 100644 --- a/ext/fts5/fts5_config.c +++ b/ext/fts5/fts5_config.c @@ -576,7 +576,7 @@ int sqlite3Fts5ConfigParse( sqlite3_int64 nByte; int bUnindexed = 0; /* True if there are one or more UNINDEXED */ - *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); + *ppOut = pRet = (Fts5Config*)sqlite3_malloc64(sizeof(Fts5Config)); if( pRet==0 ) return SQLITE_NOMEM; memset(pRet, 0, sizeof(Fts5Config)); pRet->pGlobal = pGlobal; @@ -1123,5 +1123,3 @@ void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){ va_end(ap); } - - diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c index 352df81f4f..8ecaca34fe 100644 --- a/ext/fts5/fts5_expr.c +++ b/ext/fts5/fts5_expr.c @@ -314,7 +314,7 @@ int sqlite3Fts5ExprNew( assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 ); if( sParse.rc==SQLITE_OK ){ - *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); + *ppNew = pNew = sqlite3_malloc64(sizeof(Fts5Expr)); if( pNew==0 ){ sParse.rc = SQLITE_NOMEM; sqlite3Fts5ParseNodeFree(sParse.pExpr); @@ -466,7 +466,7 @@ int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){ p2->pRoot = 0; if( sParse.rc==SQLITE_OK ){ - Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc( + Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc64( p1->apExprPhrase, nPhrase * sizeof(Fts5ExprPhrase*) ); if( ap==0 ){ diff --git a/ext/fts5/fts5_hash.c b/ext/fts5/fts5_hash.c index a33dec9a92..ba4a030b7d 100644 --- a/ext/fts5/fts5_hash.c +++ b/ext/fts5/fts5_hash.c @@ -91,7 +91,7 @@ int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){ int rc = SQLITE_OK; Fts5Hash *pNew; - *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); + *ppNew = pNew = (Fts5Hash*)sqlite3_malloc64(sizeof(Fts5Hash)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c index 4d979b9525..164d613881 100644 --- a/ext/fts5/fts5_index.c +++ b/ext/fts5/fts5_index.c @@ -2093,7 +2093,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ /* If necessary, grow the pIter->aRowidOffset[] array. */ if( iRowidOffset>=pIter->nRowidOffset ){ - int nNew = pIter->nRowidOffset + 8; + i64 nNew = pIter->nRowidOffset + 8; int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int)); if( aNew==0 ){ p->rc = SQLITE_NOMEM; @@ -6418,16 +6418,16 @@ struct Fts5TokenDataMap { ** aMap[] variables. */ struct Fts5TokenDataIter { - int nMapAlloc; /* Allocated size of aMap[] in entries */ - int nMap; /* Number of valid entries in aMap[] */ + i64 nMapAlloc; /* Allocated size of aMap[] in entries */ + i64 nMap; /* Number of valid entries in aMap[] */ Fts5TokenDataMap *aMap; /* Array of (rowid+pos -> token) mappings */ /* The following are used for prefix-queries only. */ Fts5Buffer terms; /* The following are used for other full-token tokendata queries only. */ - int nIter; - int nIterAlloc; + i64 nIter; + i64 nIterAlloc; Fts5PoslistReader *aPoslistReader; int *aPoslistToIter; Fts5Iter *apIter[FLEXARRAY]; @@ -6483,11 +6483,11 @@ static void fts5TokendataIterAppendMap( ){ if( p->rc==SQLITE_OK ){ if( pT->nMap==pT->nMapAlloc ){ - int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64; - int nAlloc = nNew * sizeof(Fts5TokenDataMap); + i64 nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64; + i64 nAlloc = nNew * sizeof(Fts5TokenDataMap); Fts5TokenDataMap *aNew; - aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nAlloc); + aNew = (Fts5TokenDataMap*)sqlite3_realloc64(pT->aMap, nAlloc); if( aNew==0 ){ p->rc = SQLITE_NOMEM; return; @@ -6513,7 +6513,7 @@ static void fts5TokendataIterAppendMap( */ static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){ Fts5TokenDataMap *aTmp = 0; - int nByte = pT->nMap * sizeof(Fts5TokenDataMap); + i64 nByte = pT->nMap * sizeof(Fts5TokenDataMap); aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte); if( aTmp ){ @@ -7047,9 +7047,10 @@ static Fts5TokenDataIter *fts5AppendTokendataIter( if( p->rc==SQLITE_OK ){ if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){ - int nAlloc = pIn ? pIn->nIterAlloc*2 : 16; - int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1); - Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte); + i64 nAlloc = pIn ? pIn->nIterAlloc*2 : 16; + i64 nByte = SZ_FTS5TOKENDATAITER(nAlloc+1); + Fts5TokenDataIter *pNew; + pNew = (Fts5TokenDataIter*)sqlite3_realloc64(pIn, nByte); if( pNew==0 ){ p->rc = SQLITE_NOMEM; @@ -7146,8 +7147,8 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){ /* Ensure the token-mapping is large enough */ if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){ - int nNew = (pT->nMapAlloc + nByte) * 2; - Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc( + i64 nNew = (pT->nMapAlloc + nByte) * 2; + Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc64( pT->aMap, nNew*sizeof(Fts5TokenDataMap) ); if( aNew==0 ){ diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c index 9d125095ef..cf033ab5de 100644 --- a/ext/fts5/fts5_main.c +++ b/ext/fts5/fts5_main.c @@ -631,7 +631,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ return SQLITE_ERROR; } - idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1); + idxStr = (char*)sqlite3_malloc64((i64)pInfo->nConstraint * 8 + 1); if( idxStr==0 ) return SQLITE_NOMEM; pInfo->idxStr = idxStr; pInfo->needToFreeIdxStr = 1; @@ -3763,7 +3763,7 @@ static int fts5Init(sqlite3 *db){ int rc; Fts5Global *pGlobal = 0; - pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global)); + pGlobal = (Fts5Global*)sqlite3_malloc64(sizeof(Fts5Global)); if( pGlobal==0 ){ rc = SQLITE_NOMEM; }else{ diff --git a/ext/fts5/fts5_tcl.c b/ext/fts5/fts5_tcl.c index 25cd5c0633..f5d8705ffe 100644 --- a/ext/fts5/fts5_tcl.c +++ b/ext/fts5/fts5_tcl.c @@ -391,7 +391,7 @@ static int SQLITE_TCLAPI xF5tApi( break; } CASE(12, "xSetAuxdata") { - F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc(sizeof(F5tAuxData)); + F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc64(sizeof(F5tAuxData)); if( pData==0 ){ Tcl_AppendResult(interp, "out of memory", (char*)0); return TCL_ERROR; @@ -780,7 +780,7 @@ static int SQLITE_TCLAPI f5tTokenize( } if( nText>0 ){ - pCopy = sqlite3_malloc(nText); + pCopy = sqlite3_malloc64(nText); if( pCopy==0 ){ tokenizer.xDelete(pTok); Tcl_AppendResult(interp, "error in sqlite3_malloc()", (char*)0); @@ -1420,7 +1420,7 @@ static int f5tOrigintextCreate( void *pTokCtx = 0; int rc = SQLITE_OK; - pTok = (OriginTextTokenizer*)sqlite3_malloc(sizeof(OriginTextTokenizer)); + pTok = (OriginTextTokenizer*)sqlite3_malloc64(sizeof(OriginTextTokenizer)); if( pTok==0 ){ rc = SQLITE_NOMEM; }else if( nArg<1 ){ @@ -1480,7 +1480,7 @@ static int xOriginToken( int nReq = nToken + 1 + (iEnd-iStart); if( nReq>p->nBuf ){ sqlite3_free(p->aBuf); - p->aBuf = sqlite3_malloc(nReq*2); + p->aBuf = sqlite3_malloc64(nReq*2); if( p->aBuf==0 ) return SQLITE_NOMEM; p->nBuf = nReq*2; } diff --git a/ext/fts5/fts5_test_tok.c b/ext/fts5/fts5_test_tok.c index 994d304dc6..c77c49de74 100644 --- a/ext/fts5/fts5_test_tok.c +++ b/ext/fts5/fts5_test_tok.c @@ -194,7 +194,7 @@ static int fts5tokConnectMethod( } if( rc==SQLITE_OK ){ - pTab = (Fts5tokTable*)sqlite3_malloc(sizeof(Fts5tokTable)); + pTab = (Fts5tokTable*)sqlite3_malloc64(sizeof(Fts5tokTable)); if( pTab==0 ){ rc = SQLITE_NOMEM; }else{ @@ -275,7 +275,7 @@ static int fts5tokBestIndexMethod( static int fts5tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ Fts5tokCursor *pCsr; - pCsr = (Fts5tokCursor *)sqlite3_malloc(sizeof(Fts5tokCursor)); + pCsr = (Fts5tokCursor *)sqlite3_malloc64(sizeof(Fts5tokCursor)); if( pCsr==0 ){ return SQLITE_NOMEM; } @@ -347,7 +347,7 @@ static int fts5tokCb( if( pCsr->nRow ){ pRow->iPos = pRow[-1].iPos + ((tflags & FTS5_TOKEN_COLOCATED) ? 0 : 1); } - pRow->zToken = sqlite3_malloc(nToken+1); + pRow->zToken = sqlite3_malloc64((sqlite3_int64)nToken+1); if( pRow->zToken==0 ) return SQLITE_NOMEM; memcpy(pRow->zToken, pToken, nToken); pRow->zToken[nToken] = 0; @@ -373,8 +373,8 @@ static int fts5tokFilterMethod( fts5tokResetCursor(pCsr); if( idxNum==1 ){ const char *zByte = (const char *)sqlite3_value_text(apVal[0]); - int nByte = sqlite3_value_bytes(apVal[0]); - pCsr->zInput = sqlite3_malloc(nByte+1); + sqlite3_int64 nByte = sqlite3_value_bytes(apVal[0]); + pCsr->zInput = sqlite3_malloc64(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; }else{ diff --git a/ext/fts5/fts5_tokenize.c b/ext/fts5/fts5_tokenize.c index b8a1136465..9908102392 100644 --- a/ext/fts5/fts5_tokenize.c +++ b/ext/fts5/fts5_tokenize.c @@ -72,7 +72,7 @@ static int fts5AsciiCreate( if( nArg%2 ){ rc = SQLITE_ERROR; }else{ - p = sqlite3_malloc(sizeof(AsciiTokenizer)); + p = sqlite3_malloc64(sizeof(AsciiTokenizer)); if( p==0 ){ rc = SQLITE_NOMEM; }else{ @@ -367,7 +367,7 @@ static int fts5UnicodeCreate( if( nArg%2 ){ rc = SQLITE_ERROR; }else{ - p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer)); + p = (Unicode61Tokenizer*)sqlite3_malloc64(sizeof(Unicode61Tokenizer)); if( p ){ const char *zCat = "L* N* Co"; int i; @@ -590,7 +590,7 @@ static int fts5PorterCreate( zBase = azArg[0]; } - pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer)); + pRet = (PorterTokenizer*)sqlite3_malloc64(sizeof(PorterTokenizer)); if( pRet ){ memset(pRet, 0, sizeof(PorterTokenizer)); rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2); @@ -1297,7 +1297,7 @@ static int fts5TriCreate( rc = SQLITE_ERROR; }else{ int i; - pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); + pNew = (TrigramTokenizer*)sqlite3_malloc64(sizeof(*pNew)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ diff --git a/ext/fts5/fts5_vocab.c b/ext/fts5/fts5_vocab.c index 3a6a968f7c..295ace6ba9 100644 --- a/ext/fts5/fts5_vocab.c +++ b/ext/fts5/fts5_vocab.c @@ -666,7 +666,7 @@ static int fts5VocabFilterMethod( const char *zCopy = (const char *)sqlite3_value_text(pLe); if( zCopy==0 ) zCopy = ""; pCsr->nLeTerm = sqlite3_value_bytes(pLe); - pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1); + pCsr->zLeTerm = sqlite3_malloc64((i64)pCsr->nLeTerm+1); if( pCsr->zLeTerm==0 ){ rc = SQLITE_NOMEM; }else{ diff --git a/manifest b/manifest index 930b09b421..403b2f0d10 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\spossible\s9-byte\sbuffer\soverread\sin\sthe\szipfile\sextension\shit\swhen\sprocessing\sa\scorrupt\szip\sfile.\sForum\spost\s[forum:/forumpost/721a05d2c5\s|\s721a05d2c5]. -D 2026-03-02T11:22:28.861 +C Use\sonly\s64-bit\smemory\sallocation\sin\sFTS5.\s\sFix\sfor\sUAF\sreported\sby\nZijie\sZhao. +D 2026-03-02T11:41:48.072 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -108,21 +108,21 @@ F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a0 F ext/fts5/extract_api_docs.tcl 009cf59c77afa86d137b0cca3e3b1a5efbe2264faa2df233f9a7aa8563926d15 F ext/fts5/fts5.h ff5d3cc88b29e41612bfb29eb723e29e38973de62ca75ba3e8f94ccb67f5b5f2 F ext/fts5/fts5Int.h 8d98f8e180fe28d6067e240ed45b9011735d29d5cfb5bac194e1e376baa7c708 -F ext/fts5/fts5_aux.c da4a7a9a11ec15c6df0699d908915a209bcde48f0b04101461316b59f71abffb -F ext/fts5/fts5_buffer.c f1e6d0324d7c55329d340673befc26681a372a4d36086caa8d1ec7d7c53066c7 -F ext/fts5/fts5_config.c e7d8dd062b44a66cd77e5a0f74f23a2354cd1f3f8575afb967b2773c3384f7f8 -F ext/fts5/fts5_expr.c b8c32da1127bafaf10d6b4768b0dcb92285798524bed2d87a8686f99a8e8d259 -F ext/fts5/fts5_hash.c a6266cedd801ab7964fa9e74ebcdda6d30ec6a96107fa24148ec6b7b5b80f6e0 -F ext/fts5/fts5_index.c 9b8118bfd0c2a4c3d3482d69ad28ba811fcc2d32e6ff7cf0634cec1c00b9d3da -F ext/fts5/fts5_main.c 4e7dc11824e681215c2ac6b702124918b946616f85e0d54f88d0f156152387ee +F ext/fts5/fts5_aux.c 042da27e97d38071312c111cf18f3cb7983b75ba5e724aa1c3164e61e90f428a +F ext/fts5/fts5_buffer.c dcc3f0352339fe79c9d8abbc1c2009bc3469206467880bf43558447ef4f846fb +F ext/fts5/fts5_config.c bfba970fe1e4eed18ee57c8d51458e226db9a960ddf775c5e50e3d76603a667e +F ext/fts5/fts5_expr.c 71d48e8cf0358deace4949276647d317ff7665db6db09f40b81e2e7fe6664c7c +F ext/fts5/fts5_hash.c d5871df92ce3fa210a650cf419ee916b87c29977e86084d06612edf772bff6f5 +F ext/fts5/fts5_index.c f8cfa37bb7397e5ede20242e4c9cb030bc8b4584ce3f23a5e2495038c0ae64bd +F ext/fts5/fts5_main.c 6889f1373c469d515e792fb3d783c2218e63c560433ebd66edc0f740ab086c1b F ext/fts5/fts5_storage.c 19bc7c4cbe1e6a2dd9849ef7d84b5ca1fcbf194cefc3e386b901e00e08bf05c2 -F ext/fts5/fts5_tcl.c 7fb5a3d3404099075aaa2457307cb459bbc257c0de3dbd52b1e80a5b503e0329 +F ext/fts5/fts5_tcl.c 2be6cc14f9448f720fd4418339cd202961a0801ea9424cb3d9de946f8f5a051c F ext/fts5/fts5_test_mi.c 4308d5658cb1f5eee5998dcbaac7d5bdf7a2ef43c8192ca6e0c843f856ccee26 -F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b -F ext/fts5/fts5_tokenize.c 49aea8cc400a690a6c4f83c4cedc67f4f8830c6789c4ee343404f62bcaebca7b +F ext/fts5/fts5_test_tok.c 6021033bd4f4feffe8579efb6e1f58156ed462256bf99a2acdbd629246529204 +F ext/fts5/fts5_tokenize.c cfc16dde905552fe238c0403670852e75c0330ba508a9fb4836c1f596618561d F ext/fts5/fts5_unicode2.c 536a6dae41d16edadd6a6b58c56e2ebbb133f0dfe757562a2edbcdc9b8362e50 F ext/fts5/fts5_varint.c e64d2113f6e1bfee0032972cffc1207b77af63319746951bf1d09885d1dadf80 -F ext/fts5/fts5_vocab.c 23e263ad94ac357cfffd19bd7e001c3f15c4420fb10fa35b5993142127e780e6 +F ext/fts5/fts5_vocab.c bebee4aabcd056a44b3731166433cfdecf17ece750c08cb58733216222bd39e2 F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05 F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba F ext/fts5/test/fts5_common.tcl c5aa7cf7148b6dcffb5b61520ae18212baf169936af734ab265143f59db328fe @@ -2197,8 +2197,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 641d6f31a7f7b4901061e24d4e624da5ed92282e79771bb019b82a882e5d1ae9 -R 7b806405410391d6c9e5cfebe6bc3c9f -U dan -Z b41f2b7c5fc9c26824062a452186e3fc +P 5db21813d126554d80db903be6d36ab6c1f73f9135a54af6dcfcfce0bcc18e68 +R 011ac2456c3bd87bb595ab34085bd4d8 +U drh +Z 31223c2ab955576e443d0b82ea2b6a5d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5a0a0cb427..e6c1353c36 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5db21813d126554d80db903be6d36ab6c1f73f9135a54af6dcfcfce0bcc18e68 +e8976d5041c929675772039b7a8fc4ff0b609537d86f9aa6e445ecd512a10673 From ea6b2a87d103fe71f3402d4b2fb6a495b28bbee0 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 2 Mar 2026 13:43:08 +0000 Subject: [PATCH 074/197] Disable test shell1-5.0 as it is causing a use of initialized deep inside of TCL. FossilOrigin-Name: 440bd6091e3767f0a2f42ffdc92ca5e4736c0a73324fdd15397c3b5dbbc31fb8 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/shell1.test | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 403b2f0d10..1e2d8e52db 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\sonly\s64-bit\smemory\sallocation\sin\sFTS5.\s\sFix\sfor\sUAF\sreported\sby\nZijie\sZhao. -D 2026-03-02T11:41:48.072 +C Disable\stest\sshell1-5.0\sas\sit\sis\scausing\sa\suse\sof\sinitialized\sdeep\sinside\nof\sTCL. +D 2026-03-02T13:43:08.964 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -1621,7 +1621,7 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21 F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707 F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test 5055a13bde31e92590311c91777d6b646082dc13250de8c07dc0db1efbdd864d +F test/shell1.test 2d658ceee13d9e4361d04d0ea16340ad17784ddf378fb6e9ca6d49c682cb4bae F test/shell2.test dc541d2681503e55466a24d35a4cbf8ca5b90b8fcdef37fc4db07373a67d31d3 F test/shell3.test 603b448e917537cf77be0f265c05c6f63bc677c63a533c8e96aae923b56f4a0e F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db @@ -2197,8 +2197,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 5db21813d126554d80db903be6d36ab6c1f73f9135a54af6dcfcfce0bcc18e68 -R 011ac2456c3bd87bb595ab34085bd4d8 +P e8976d5041c929675772039b7a8fc4ff0b609537d86f9aa6e445ecd512a10673 +R 196e96eb644b7fb48b6564a67ba146cd U drh -Z 31223c2ab955576e443d0b82ea2b6a5d +Z db4a137667e1314416d854cef3854055 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e6c1353c36..b3fac4eaf8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e8976d5041c929675772039b7a8fc4ff0b609537d86f9aa6e445ecd512a10673 +440bd6091e3767f0a2f42ffdc92ca5e4736c0a73324fdd15397c3b5dbbc31fb8 diff --git a/test/shell1.test b/test/shell1.test index 84b43c5d50..1d111d6161 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -1121,6 +1121,7 @@ do_test shell1-4.7 { # Test using arbitrary byte data with the shell via standard input/output. # +if 0 { # Causes a valgrind error in TCL. Seems to be a TCL problem. do_test shell1-5.0 { # # NOTE: Skip NUL byte because it appears to be incompatible with command @@ -1187,6 +1188,7 @@ do_test shell1-5.0 { } } } {} +} # These test cases do not work on MinGW if 0 { From c1454ee8331088c922f1ded8ffa2374842f5dd21 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 2 Mar 2026 13:44:04 +0000 Subject: [PATCH 075/197] Remove the experimental and incomplete ext/repair extension, to prevent AIs from scanning the (incomplete) code and reporting bugs against it. FossilOrigin-Name: 213b1c6608af4b3e9d6e0d8de6432cc6857931427baf4beac1e0a4294e4dc6ce --- Makefile.msc | 17 - ext/repair/README.md | 16 - ext/repair/checkfreelist.c | 310 --------- ext/repair/checkindex.c | 929 --------------------------- ext/repair/sqlite3_checker.c.in | 85 --- ext/repair/sqlite3_checker.tcl | 264 -------- ext/repair/test/README.md | 13 - ext/repair/test/checkfreelist01.test | 92 --- ext/repair/test/checkindex01.test | 349 ---------- ext/repair/test/test.tcl | 67 -- main.mk | 18 - manifest | 23 +- manifest.uuid | 2 +- 13 files changed, 8 insertions(+), 2177 deletions(-) delete mode 100644 ext/repair/README.md delete mode 100644 ext/repair/checkfreelist.c delete mode 100644 ext/repair/checkindex.c delete mode 100644 ext/repair/sqlite3_checker.c.in delete mode 100644 ext/repair/sqlite3_checker.tcl delete mode 100644 ext/repair/test/README.md delete mode 100644 ext/repair/test/checkfreelist01.test delete mode 100644 ext/repair/test/checkindex01.test delete mode 100644 ext/repair/test/test.tcl diff --git a/Makefile.msc b/Makefile.msc index 561d5f58e0..763616ce93 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -2660,23 +2660,6 @@ sqltclsh.exe: sqltclsh.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3_expert.exe: $(SQLITE3C) $(TOP)\ext\expert\sqlite3expert.h $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c $(LTLINK) $(NO_WARN) $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c $(SQLITE3C) $(TLIBS) -CHECKER_DEPS =\ - $(TOP)\tool\mkccode.tcl \ - sqlite3.c \ - tclsqlite-ex.c \ - $(TOP)\ext\repair\sqlite3_checker.tcl \ - $(TOP)\ext\repair\checkindex.c \ - $(TOP)\ext\repair\checkfreelist.c \ - $(TOP)\ext\misc\btreeinfo.c \ - $(TOP)\ext\repair\sqlite3_checker.c.in - -sqlite3_checker.c: $(CHECKER_DEPS) - $(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\ext\repair\sqlite3_checker.c.in > $@ - -sqlite3_checker.exe: sqlite3_checker.c $(LIBRESOBJS) - $(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_checker.c \ - /link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS) - dbdump.exe: $(TOP)\ext\misc\dbdump.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS) $(LTLINK) $(NO_WARN) -DDBDUMP_STANDALONE $(TOP)\ext\misc\dbdump.c $(SQLITE3C) \ /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) diff --git a/ext/repair/README.md b/ext/repair/README.md deleted file mode 100644 index 927ceb7c44..0000000000 --- a/ext/repair/README.md +++ /dev/null @@ -1,16 +0,0 @@ -This folder contains extensions and utility programs intended to analyze -live database files, detect problems, and possibly fix them. - -As SQLite is being used on larger and larger databases, database sizes -are growing into the terabyte range. At that size, hardware malfunctions -and/or cosmic rays will occasionally corrupt a database file. Detecting -problems and fixing errors a terabyte-sized databases can take hours or days, -and it is undesirable to take applications that depend on the databases -off-line for such a long time. -The utilities in the folder are intended to provide mechanisms for -detecting and fixing problems in large databases while those databases -are in active use. - -The utilities and extensions in this folder are experimental and under -active development at the time of this writing (2017-10-12). If and when -they stabilize, this README will be updated to reflect that fact. diff --git a/ext/repair/checkfreelist.c b/ext/repair/checkfreelist.c deleted file mode 100644 index d1d3d54074..0000000000 --- a/ext/repair/checkfreelist.c +++ /dev/null @@ -1,310 +0,0 @@ -/* -** 2017 October 11 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This module exports a single C function: -** -** int sqlite3_check_freelist(sqlite3 *db, const char *zDb); -** -** This function checks the free-list in database zDb (one of "main", -** "temp", etc.) and reports any errors by invoking the sqlite3_log() -** function. It returns SQLITE_OK if successful, or an SQLite error -** code otherwise. It is not an error if the free-list is corrupted but -** no IO or OOM errors occur. -** -** If this file is compiled and loaded as an SQLite loadable extension, -** it adds an SQL function "checkfreelist" to the database handle, to -** be invoked as follows: -** -** SELECT checkfreelist(); -** -** This function performs the same checks as sqlite3_check_freelist(), -** except that it returns all error messages as a single text value, -** separated by newline characters. If the freelist is not corrupted -** in any way, an empty string is returned. -** -** To compile this module for use as an SQLite loadable extension: -** -** gcc -Os -fPIC -shared checkfreelist.c -o checkfreelist.so -*/ - -#include "sqlite3ext.h" -SQLITE_EXTENSION_INIT1 - -#ifndef SQLITE_AMALGAMATION -# include -# include -# include -# include -# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) -# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 -# endif -# if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) -# define ALWAYS(X) (1) -# define NEVER(X) (0) -# elif !defined(NDEBUG) -# define ALWAYS(X) ((X)?1:(assert(0),0)) -# define NEVER(X) ((X)?(assert(0),1):0) -# else -# define ALWAYS(X) (X) -# define NEVER(X) (X) -# endif - typedef unsigned char u8; - typedef unsigned short u16; - typedef unsigned int u32; -#define get4byte(x) ( \ - ((u32)((x)[0])<<24) + \ - ((u32)((x)[1])<<16) + \ - ((u32)((x)[2])<<8) + \ - ((u32)((x)[3])) \ -) -#endif - -/* -** Execute a single PRAGMA statement and return the integer value returned -** via output parameter (*pnOut). -** -** The SQL statement passed as the third argument should be a printf-style -** format string containing a single "%s" which will be replace by the -** value passed as the second argument. e.g. -** -** sqlGetInteger(db, "main", "PRAGMA %s.page_count", pnOut) -** -** executes "PRAGMA main.page_count" and stores the results in (*pnOut). -*/ -static int sqlGetInteger( - sqlite3 *db, /* Database handle */ - const char *zDb, /* Database name ("main", "temp" etc.) */ - const char *zFmt, /* SQL statement format */ - u32 *pnOut /* OUT: Integer value */ -){ - int rc, rc2; - char *zSql; - sqlite3_stmt *pStmt = 0; - int bOk = 0; - - zSql = sqlite3_mprintf(zFmt, zDb); - if( zSql==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - } - - if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - *pnOut = (u32)sqlite3_column_int(pStmt, 0); - bOk = 1; - } - - rc2 = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ) rc = rc2; - if( rc==SQLITE_OK && bOk==0 ) rc = SQLITE_ERROR; - return rc; -} - -/* -** Argument zFmt must be a printf-style format string and must be -** followed by its required arguments. If argument pzOut is NULL, -** then the results of printf()ing the format string are passed to -** sqlite3_log(). Otherwise, they are appended to the string -** at (*pzOut). -*/ -static int checkFreelistError(char **pzOut, const char *zFmt, ...){ - int rc = SQLITE_OK; - char *zErr = 0; - va_list ap; - - va_start(ap, zFmt); - zErr = sqlite3_vmprintf(zFmt, ap); - if( zErr==0 ){ - rc = SQLITE_NOMEM; - }else{ - if( pzOut ){ - *pzOut = sqlite3_mprintf("%s%z%s", *pzOut?"\n":"", *pzOut, zErr); - if( *pzOut==0 ) rc = SQLITE_NOMEM; - }else{ - sqlite3_log(SQLITE_ERROR, "checkfreelist: %s", zErr); - } - sqlite3_free(zErr); - } - va_end(ap); - return rc; -} - -static int checkFreelist( - sqlite3 *db, - const char *zDb, - char **pzOut -){ - /* This query returns one row for each page on the free list. Each row has - ** two columns - the page number and page content. */ - const char *zTrunk = - "WITH freelist_trunk(i, d, n) AS (" - "SELECT 1, NULL, sqlite_readint32(data, 32) " - "FROM sqlite_dbpage(:1) WHERE pgno=1 " - "UNION ALL " - "SELECT n, data, sqlite_readint32(data) " - "FROM freelist_trunk, sqlite_dbpage(:1) WHERE pgno=n " - ")" - "SELECT i, d FROM freelist_trunk WHERE i!=1;"; - - int rc, rc2; /* Return code */ - sqlite3_stmt *pTrunk = 0; /* Compilation of zTrunk */ - u32 nPage = 0; /* Number of pages in db */ - u32 nExpected = 0; /* Expected number of free pages */ - u32 nFree = 0; /* Number of pages on free list */ - - if( zDb==0 ) zDb = "main"; - - if( (rc = sqlGetInteger(db, zDb, "PRAGMA %s.page_count", &nPage)) - || (rc = sqlGetInteger(db, zDb, "PRAGMA %s.freelist_count", &nExpected)) - ){ - return rc; - } - - rc = sqlite3_prepare_v2(db, zTrunk, -1, &pTrunk, 0); - if( rc!=SQLITE_OK ) return rc; - sqlite3_bind_text(pTrunk, 1, zDb, -1, SQLITE_STATIC); - while( rc==SQLITE_OK && sqlite3_step(pTrunk)==SQLITE_ROW ){ - u32 i; - u32 iTrunk = (u32)sqlite3_column_int(pTrunk, 0); - const u8 *aData = (const u8*)sqlite3_column_blob(pTrunk, 1); - u32 nData = (u32)sqlite3_column_bytes(pTrunk, 1); - u32 iNext = get4byte(&aData[0]); - u32 nLeaf = get4byte(&aData[4]); - - if( nLeaf>((nData/4)-2-6) ){ - rc = checkFreelistError(pzOut, - "leaf count out of range (%d) on trunk page %d", - (int)nLeaf, (int)iTrunk - ); - nLeaf = (nData/4) - 2 - 6; - } - - nFree += 1+nLeaf; - if( iNext>nPage ){ - rc = checkFreelistError(pzOut, - "trunk page %d is out of range", (int)iNext - ); - } - - for(i=0; rc==SQLITE_OK && inPage ){ - rc = checkFreelistError(pzOut, - "leaf page %d is out of range (child %d of trunk page %d)", - (int)iLeaf, (int)i, (int)iTrunk - ); - } - } - } - - if( rc==SQLITE_OK && nFree!=nExpected ){ - rc = checkFreelistError(pzOut, - "free-list count mismatch: actual=%d header=%d", - (int)nFree, (int)nExpected - ); - } - - rc2 = sqlite3_finalize(pTrunk); - if( rc==SQLITE_OK ) rc = rc2; - return rc; -} - -int sqlite3_check_freelist(sqlite3 *db, const char *zDb){ - return checkFreelist(db, zDb, 0); -} - -static void checkfreelist_function( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **apArg -){ - const char *zDb; - int rc; - char *zOut = 0; - sqlite3 *db = sqlite3_context_db_handle(pCtx); - - assert( nArg==1 ); - zDb = (const char*)sqlite3_value_text(apArg[0]); - rc = checkFreelist(db, zDb, &zOut); - if( rc==SQLITE_OK ){ - sqlite3_result_text(pCtx, zOut?zOut:"ok", -1, SQLITE_TRANSIENT); - }else{ - sqlite3_result_error_code(pCtx, rc); - } - - sqlite3_free(zOut); -} - -/* -** An SQL function invoked as follows: -** -** sqlite_readint32(BLOB) -- Decode 32-bit integer from start of blob -*/ -static void readint_function( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **apArg -){ - const u8 *zBlob; - int nBlob; - int iOff = 0; - u32 iRet = 0; - - if( nArg!=1 && nArg!=2 ){ - sqlite3_result_error( - pCtx, "wrong number of arguments to function sqlite_readint32()", -1 - ); - return; - } - if( nArg==2 ){ - iOff = sqlite3_value_int(apArg[1]); - } - - zBlob = sqlite3_value_blob(apArg[0]); - nBlob = sqlite3_value_bytes(apArg[0]); - - if( nBlob>=(iOff+4) ){ - iRet = get4byte(&zBlob[iOff]); - } - - sqlite3_result_int64(pCtx, (sqlite3_int64)iRet); -} - -/* -** Register the SQL functions. -*/ -static int cflRegister(sqlite3 *db){ - int rc = sqlite3_create_function( - db, "sqlite_readint32", -1, SQLITE_UTF8, 0, readint_function, 0, 0 - ); - if( rc!=SQLITE_OK ) return rc; - rc = sqlite3_create_function( - db, "checkfreelist", 1, SQLITE_UTF8, 0, checkfreelist_function, 0, 0 - ); - return rc; -} - -/* -** Extension load function. -*/ -#ifdef _WIN32 -__declspec(dllexport) -#endif -int sqlite3_checkfreelist_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - SQLITE_EXTENSION_INIT2(pApi); - return cflRegister(db); -} diff --git a/ext/repair/checkindex.c b/ext/repair/checkindex.c deleted file mode 100644 index ed30357e5d..0000000000 --- a/ext/repair/checkindex.c +++ /dev/null @@ -1,929 +0,0 @@ -/* -** 2017 October 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ - -#include "sqlite3ext.h" -SQLITE_EXTENSION_INIT1 - -/* -** Stuff that is available inside the amalgamation, but which we need to -** declare ourselves if this module is compiled separately. -*/ -#ifndef SQLITE_AMALGAMATION -# include -# include -# include -# include -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -#define get4byte(x) ( \ - ((u32)((x)[0])<<24) + \ - ((u32)((x)[1])<<16) + \ - ((u32)((x)[2])<<8) + \ - ((u32)((x)[3])) \ -) -#endif - -typedef struct CidxTable CidxTable; -typedef struct CidxCursor CidxCursor; - -struct CidxTable { - sqlite3_vtab base; /* Base class. Must be first */ - sqlite3 *db; -}; - -struct CidxCursor { - sqlite3_vtab_cursor base; /* Base class. Must be first */ - sqlite3_int64 iRowid; /* Row number of the output */ - char *zIdxName; /* Copy of the index_name parameter */ - char *zAfterKey; /* Copy of the after_key parameter */ - sqlite3_stmt *pStmt; /* SQL statement that generates the output */ -}; - -typedef struct CidxColumn CidxColumn; -struct CidxColumn { - char *zExpr; /* Text for indexed expression */ - int bDesc; /* True for DESC columns, otherwise false */ - int bKey; /* Part of index, not PK */ -}; - -typedef struct CidxIndex CidxIndex; -struct CidxIndex { - char *zWhere; /* WHERE clause, if any */ - int nCol; /* Elements in aCol[] array */ - CidxColumn aCol[1]; /* Array of indexed columns */ -}; - -static void *cidxMalloc(int *pRc, int n){ - void *pRet = 0; - assert( n!=0 ); - if( *pRc==SQLITE_OK ){ - pRet = sqlite3_malloc(n); - if( pRet ){ - memset(pRet, 0, n); - }else{ - *pRc = SQLITE_NOMEM; - } - } - return pRet; -} - -static void cidxCursorError(CidxCursor *pCsr, const char *zFmt, ...){ - va_list ap; - va_start(ap, zFmt); - assert( pCsr->base.pVtab->zErrMsg==0 ); - pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap); - va_end(ap); -} - -/* -** Connect to the incremental_index_check virtual table. -*/ -static int cidxConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - int rc = SQLITE_OK; - CidxTable *pRet; - -#define IIC_ERRMSG 0 -#define IIC_CURRENT_KEY 1 -#define IIC_INDEX_NAME 2 -#define IIC_AFTER_KEY 3 -#define IIC_SCANNER_SQL 4 - rc = sqlite3_declare_vtab(db, - "CREATE TABLE xyz(" - " errmsg TEXT," /* Error message or NULL if everything is ok */ - " current_key TEXT," /* SQLite quote() text of key values */ - " index_name HIDDEN," /* IN: name of the index being scanned */ - " after_key HIDDEN," /* IN: Start scanning after this key */ - " scanner_sql HIDDEN" /* debugging info: SQL used for scanner */ - ")" - ); - pRet = cidxMalloc(&rc, sizeof(CidxTable)); - if( pRet ){ - pRet->db = db; - } - - *ppVtab = (sqlite3_vtab*)pRet; - return rc; -} - -/* -** Disconnect from or destroy an incremental_index_check virtual table. -*/ -static int cidxDisconnect(sqlite3_vtab *pVtab){ - CidxTable *pTab = (CidxTable*)pVtab; - sqlite3_free(pTab); - return SQLITE_OK; -} - -/* -** idxNum and idxStr are not used. There are only three possible plans, -** which are all distinguished by the number of parameters. -** -** No parameters: A degenerate plan. The result is zero rows. -** 1 Parameter: Scan all of the index starting with first entry -** 2 parameters: Scan the index starting after the "after_key". -** -** Provide successively smaller costs for each of these plans to encourage -** the query planner to select the one with the most parameters. -*/ -static int cidxBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pInfo){ - int iIdxName = -1; - int iAfterKey = -1; - int i; - - for(i=0; inConstraint; i++){ - struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; - if( p->usable==0 ) continue; - if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - - if( p->iColumn==IIC_INDEX_NAME ){ - iIdxName = i; - } - if( p->iColumn==IIC_AFTER_KEY ){ - iAfterKey = i; - } - } - - if( iIdxName<0 ){ - pInfo->estimatedCost = 1000000000.0; - }else{ - pInfo->aConstraintUsage[iIdxName].argvIndex = 1; - pInfo->aConstraintUsage[iIdxName].omit = 1; - if( iAfterKey<0 ){ - pInfo->estimatedCost = 1000000.0; - }else{ - pInfo->aConstraintUsage[iAfterKey].argvIndex = 2; - pInfo->aConstraintUsage[iAfterKey].omit = 1; - pInfo->estimatedCost = 1000.0; - } - } - - return SQLITE_OK; -} - -/* -** Open a new btreeinfo cursor. -*/ -static int cidxOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ - CidxCursor *pRet; - int rc = SQLITE_OK; - - pRet = cidxMalloc(&rc, sizeof(CidxCursor)); - - *ppCursor = (sqlite3_vtab_cursor*)pRet; - return rc; -} - -/* -** Close a btreeinfo cursor. -*/ -static int cidxClose(sqlite3_vtab_cursor *pCursor){ - CidxCursor *pCsr = (CidxCursor*)pCursor; - sqlite3_finalize(pCsr->pStmt); - sqlite3_free(pCsr->zIdxName); - sqlite3_free(pCsr->zAfterKey); - sqlite3_free(pCsr); - return SQLITE_OK; -} - -/* -** Move a btreeinfo cursor to the next entry in the file. -*/ -static int cidxNext(sqlite3_vtab_cursor *pCursor){ - CidxCursor *pCsr = (CidxCursor*)pCursor; - int rc = sqlite3_step(pCsr->pStmt); - if( rc!=SQLITE_ROW ){ - rc = sqlite3_finalize(pCsr->pStmt); - pCsr->pStmt = 0; - if( rc!=SQLITE_OK ){ - sqlite3 *db = ((CidxTable*)pCsr->base.pVtab)->db; - cidxCursorError(pCsr, "Cursor error: %s", sqlite3_errmsg(db)); - } - }else{ - pCsr->iRowid++; - rc = SQLITE_OK; - } - return rc; -} - -/* We have reached EOF if previous sqlite3_step() returned -** anything other than SQLITE_ROW; -*/ -static int cidxEof(sqlite3_vtab_cursor *pCursor){ - CidxCursor *pCsr = (CidxCursor*)pCursor; - return pCsr->pStmt==0; -} - -static char *cidxMprintf(int *pRc, const char *zFmt, ...){ - char *zRet = 0; - va_list ap; - va_start(ap, zFmt); - zRet = sqlite3_vmprintf(zFmt, ap); - if( *pRc==SQLITE_OK ){ - if( zRet==0 ){ - *pRc = SQLITE_NOMEM; - } - }else{ - sqlite3_free(zRet); - zRet = 0; - } - va_end(ap); - return zRet; -} - -static sqlite3_stmt *cidxPrepare( - int *pRc, CidxCursor *pCsr, const char *zFmt, ... -){ - sqlite3_stmt *pRet = 0; - char *zSql; - va_list ap; /* ... printf arguments */ - va_start(ap, zFmt); - - zSql = sqlite3_vmprintf(zFmt, ap); - if( *pRc==SQLITE_OK ){ - if( zSql==0 ){ - *pRc = SQLITE_NOMEM; - }else{ - sqlite3 *db = ((CidxTable*)pCsr->base.pVtab)->db; - *pRc = sqlite3_prepare_v2(db, zSql, -1, &pRet, 0); - if( *pRc!=SQLITE_OK ){ - cidxCursorError(pCsr, "SQL error: %s", sqlite3_errmsg(db)); - } - } - } - sqlite3_free(zSql); - va_end(ap); - - return pRet; -} - -static void cidxFinalize(int *pRc, sqlite3_stmt *pStmt){ - int rc = sqlite3_finalize(pStmt); - if( *pRc==SQLITE_OK ) *pRc = rc; -} - -char *cidxStrdup(int *pRc, const char *zStr){ - char *zRet = 0; - if( *pRc==SQLITE_OK ){ - int n = (int)strlen(zStr); - zRet = cidxMalloc(pRc, n+1); - if( zRet ) memcpy(zRet, zStr, n+1); - } - return zRet; -} - -static void cidxFreeIndex(CidxIndex *pIdx){ - if( pIdx ){ - int i; - for(i=0; inCol; i++){ - sqlite3_free(pIdx->aCol[i].zExpr); - } - sqlite3_free(pIdx->zWhere); - sqlite3_free(pIdx); - } -} - -static int cidx_isspace(char c){ - return c==' ' || c=='\t' || c=='\r' || c=='\n'; -} - -static int cidx_isident(char c){ - return c<0 - || (c>='0' && c<='9') || (c>='a' && c<='z') - || (c>='A' && c<='Z') || c=='_'; -} - -#define CIDX_PARSE_EOF 0 -#define CIDX_PARSE_COMMA 1 /* "," */ -#define CIDX_PARSE_OPEN 2 /* "(" */ -#define CIDX_PARSE_CLOSE 3 /* ")" */ - -/* -** Argument zIn points into the start, middle or end of a CREATE INDEX -** statement. If argument pbDoNotTrim is non-NULL, then this function -** scans the input until it finds EOF, a comma (",") or an open or -** close parenthesis character. It then sets (*pzOut) to point to said -** character and returns a CIDX_PARSE_XXX constant as appropriate. The -** parser is smart enough that special characters inside SQL strings -** or comments are not returned for. -** -** Or, if argument pbDoNotTrim is NULL, then this function sets *pzOut -** to point to the first character of the string that is not whitespace -** or part of an SQL comment and returns CIDX_PARSE_EOF. -** -** Additionally, if pbDoNotTrim is not NULL and the element immediately -** before (*pzOut) is an SQL comment of the form "-- comment", then -** (*pbDoNotTrim) is set before returning. In all other cases it is -** cleared. -*/ -static int cidxFindNext( - const char *zIn, - const char **pzOut, - int *pbDoNotTrim /* OUT: True if prev is -- comment */ -){ - const char *z = zIn; - - while( 1 ){ - while( cidx_isspace(*z) ) z++; - if( z[0]=='-' && z[1]=='-' ){ - z += 2; - while( z[0]!='\n' ){ - if( z[0]=='\0' ) return CIDX_PARSE_EOF; - z++; - } - while( cidx_isspace(*z) ) z++; - if( pbDoNotTrim ) *pbDoNotTrim = 1; - }else - if( z[0]=='/' && z[1]=='*' ){ - z += 2; - while( z[0]!='*' || z[1]!='/' ){ - if( z[1]=='\0' ) return CIDX_PARSE_EOF; - z++; - } - z += 2; - }else{ - *pzOut = z; - if( pbDoNotTrim==0 ) return CIDX_PARSE_EOF; - switch( *z ){ - case '\0': - return CIDX_PARSE_EOF; - case '(': - return CIDX_PARSE_OPEN; - case ')': - return CIDX_PARSE_CLOSE; - case ',': - return CIDX_PARSE_COMMA; - - case '"': - case '\'': - case '`': { - char q = *z; - z++; - while( *z ){ - if( *z==q ){ - z++; - if( *z!=q ) break; - } - z++; - } - break; - } - - case '[': - while( *z++!=']' ); - break; - - default: - z++; - break; - } - *pbDoNotTrim = 0; - } - } - - assert( 0 ); - return -1; -} - -static int cidxParseSQL(CidxCursor *pCsr, CidxIndex *pIdx, const char *zSql){ - const char *z = zSql; - const char *z1; - int e; - int rc = SQLITE_OK; - int nParen = 1; - int bDoNotTrim = 0; - CidxColumn *pCol = pIdx->aCol; - - e = cidxFindNext(z, &z, &bDoNotTrim); - if( e!=CIDX_PARSE_OPEN ) goto parse_error; - z1 = z+1; - z++; - while( nParen>0 ){ - e = cidxFindNext(z, &z, &bDoNotTrim); - if( e==CIDX_PARSE_EOF ) goto parse_error; - if( (e==CIDX_PARSE_COMMA || e==CIDX_PARSE_CLOSE) && nParen==1 ){ - const char *z2 = z; - if( pCol->zExpr ) goto parse_error; - - if( bDoNotTrim==0 ){ - while( cidx_isspace(z[-1]) ) z--; - if( !sqlite3_strnicmp(&z[-3], "asc", 3) && 0==cidx_isident(z[-4]) ){ - z -= 3; - while( cidx_isspace(z[-1]) ) z--; - }else - if( !sqlite3_strnicmp(&z[-4], "desc", 4) && 0==cidx_isident(z[-5]) ){ - z -= 4; - while( cidx_isspace(z[-1]) ) z--; - } - while( cidx_isspace(z1[0]) ) z1++; - } - - pCol->zExpr = cidxMprintf(&rc, "%.*s", z-z1, z1); - pCol++; - z = z1 = z2+1; - } - if( e==CIDX_PARSE_OPEN ) nParen++; - if( e==CIDX_PARSE_CLOSE ) nParen--; - z++; - } - - /* Search for a WHERE clause */ - cidxFindNext(z, &z, 0); - if( 0==sqlite3_strnicmp(z, "where", 5) ){ - pIdx->zWhere = cidxMprintf(&rc, "%s\n", &z[5]); - }else if( z[0]!='\0' ){ - goto parse_error; - } - - return rc; - - parse_error: - cidxCursorError(pCsr, "Parse error in: %s", zSql); - return SQLITE_ERROR; -} - -static int cidxLookupIndex( - CidxCursor *pCsr, /* Cursor object */ - const char *zIdx, /* Name of index to look up */ - CidxIndex **ppIdx, /* OUT: Description of columns */ - char **pzTab /* OUT: Table name */ -){ - int rc = SQLITE_OK; - char *zTab = 0; - CidxIndex *pIdx = 0; - - sqlite3_stmt *pFindTab = 0; - sqlite3_stmt *pInfo = 0; - - /* Find the table for this index. */ - pFindTab = cidxPrepare(&rc, pCsr, - "SELECT tbl_name, sql FROM sqlite_schema WHERE name=%Q AND type='index'", - zIdx - ); - if( rc==SQLITE_OK && sqlite3_step(pFindTab)==SQLITE_ROW ){ - const char *zSql = (const char*)sqlite3_column_text(pFindTab, 1); - zTab = cidxStrdup(&rc, (const char*)sqlite3_column_text(pFindTab, 0)); - - pInfo = cidxPrepare(&rc, pCsr, "PRAGMA index_xinfo(%Q)", zIdx); - if( rc==SQLITE_OK ){ - int nAlloc = 0; - int iCol = 0; - - while( sqlite3_step(pInfo)==SQLITE_ROW ){ - const char *zName = (const char*)sqlite3_column_text(pInfo, 2); - const char *zColl = (const char*)sqlite3_column_text(pInfo, 4); - CidxColumn *p; - if( zName==0 ) zName = "rowid"; - if( iCol==nAlloc ){ - int nByte = sizeof(CidxIndex) + sizeof(CidxColumn)*(nAlloc+8); - pIdx = (CidxIndex*)sqlite3_realloc(pIdx, nByte); - nAlloc += 8; - } - p = &pIdx->aCol[iCol++]; - p->bDesc = sqlite3_column_int(pInfo, 3); - p->bKey = sqlite3_column_int(pInfo, 5); - if( zSql==0 || p->bKey==0 ){ - p->zExpr = cidxMprintf(&rc, "\"%w\" COLLATE %s",zName,zColl); - }else{ - p->zExpr = 0; - } - pIdx->nCol = iCol; - pIdx->zWhere = 0; - } - cidxFinalize(&rc, pInfo); - } - - if( rc==SQLITE_OK && zSql ){ - rc = cidxParseSQL(pCsr, pIdx, zSql); - } - } - - cidxFinalize(&rc, pFindTab); - if( rc==SQLITE_OK && zTab==0 ){ - rc = SQLITE_ERROR; - } - - if( rc!=SQLITE_OK ){ - sqlite3_free(zTab); - cidxFreeIndex(pIdx); - }else{ - *pzTab = zTab; - *ppIdx = pIdx; - } - - return rc; -} - -static int cidxDecodeAfter( - CidxCursor *pCsr, - int nCol, - const char *zAfterKey, - char ***pazAfter -){ - char **azAfter; - int rc = SQLITE_OK; - int nAfterKey = (int)strlen(zAfterKey); - - azAfter = cidxMalloc(&rc, sizeof(char*)*nCol + nAfterKey+1); - if( rc==SQLITE_OK ){ - int i; - char *zCopy = (char*)&azAfter[nCol]; - char *p = zCopy; - memcpy(zCopy, zAfterKey, nAfterKey+1); - for(i=0; i='0' && *p<='9') - || *p=='.' || *p=='+' || *p=='-' || *p=='e' || *p=='E' - ){ - p++; - } - } - - while( *p==' ' ) p++; - if( *p!=(i==(nCol-1) ? '\0' : ',') ){ - goto parse_error; - } - *p++ = '\0'; - } - } - - *pazAfter = azAfter; - return rc; - - parse_error: - sqlite3_free(azAfter); - *pazAfter = 0; - cidxCursorError(pCsr, "%s", "error parsing after value"); - return SQLITE_ERROR; -} - -static char *cidxWhere( - int *pRc, CidxColumn *aCol, char **azAfter, int iGt, int bLastIsNull -){ - char *zRet = 0; - const char *zSep = ""; - int i; - - for(i=0; i"), - azAfter[iGt] - ); - }else{ - zRet = cidxMprintf(pRc, "%z%s(%s) IS NOT NULL", zRet, zSep,aCol[iGt].zExpr); - } - - return zRet; -} - -#define CIDX_CLIST_ALL 0 -#define CIDX_CLIST_ORDERBY 1 -#define CIDX_CLIST_CURRENT_KEY 2 -#define CIDX_CLIST_SUBWHERE 3 -#define CIDX_CLIST_SUBEXPR 4 - -/* -** This function returns various strings based on the contents of the -** CidxIndex structure and the eType parameter. -*/ -static char *cidxColumnList( - int *pRc, /* IN/OUT: Error code */ - const char *zIdx, - CidxIndex *pIdx, /* Indexed columns */ - int eType /* True to include ASC/DESC */ -){ - char *zRet = 0; - if( *pRc==SQLITE_OK ){ - const char *aDir[2] = {"", " DESC"}; - int i; - const char *zSep = ""; - - for(i=0; inCol; i++){ - CidxColumn *p = &pIdx->aCol[i]; - assert( pIdx->aCol[i].bDesc==0 || pIdx->aCol[i].bDesc==1 ); - switch( eType ){ - - case CIDX_CLIST_ORDERBY: - zRet = cidxMprintf(pRc, "%z%s%d%s", zRet, zSep, i+1, aDir[p->bDesc]); - zSep = ","; - break; - - case CIDX_CLIST_CURRENT_KEY: - zRet = cidxMprintf(pRc, "%z%squote(i%d)", zRet, zSep, i); - zSep = "||','||"; - break; - - case CIDX_CLIST_SUBWHERE: - if( p->bKey==0 ){ - zRet = cidxMprintf(pRc, "%z%s%s IS i.i%d", zRet, - zSep, p->zExpr, i - ); - zSep = " AND "; - } - break; - - case CIDX_CLIST_SUBEXPR: - if( p->bKey==1 ){ - zRet = cidxMprintf(pRc, "%z%s%s IS i.i%d", zRet, - zSep, p->zExpr, i - ); - zSep = " AND "; - } - break; - - default: - assert( eType==CIDX_CLIST_ALL ); - zRet = cidxMprintf(pRc, "%z%s(%s) AS i%d", zRet, zSep, p->zExpr, i); - zSep = ", "; - break; - } - } - } - - return zRet; -} - -/* -** Generate SQL (in memory obtained from sqlite3_malloc()) that will -** continue the index scan for zIdxName starting after zAfterKey. -*/ -int cidxGenerateScanSql( - CidxCursor *pCsr, /* The cursor which needs the new statement */ - const char *zIdxName, /* index to be scanned */ - const char *zAfterKey, /* start after this key, if not NULL */ - char **pzSqlOut /* OUT: Write the generated SQL here */ -){ - int rc; - char *zTab = 0; - char *zCurrentKey = 0; - char *zOrderBy = 0; - char *zSubWhere = 0; - char *zSubExpr = 0; - char *zSrcList = 0; - char **azAfter = 0; - CidxIndex *pIdx = 0; - - *pzSqlOut = 0; - rc = cidxLookupIndex(pCsr, zIdxName, &pIdx, &zTab); - - zOrderBy = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_ORDERBY); - zCurrentKey = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_CURRENT_KEY); - zSubWhere = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_SUBWHERE); - zSubExpr = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_SUBEXPR); - zSrcList = cidxColumnList(&rc, zIdxName, pIdx, CIDX_CLIST_ALL); - - if( rc==SQLITE_OK && zAfterKey ){ - rc = cidxDecodeAfter(pCsr, pIdx->nCol, zAfterKey, &azAfter); - } - - if( rc==SQLITE_OK ){ - if( zAfterKey==0 ){ - *pzSqlOut = cidxMprintf(&rc, - "SELECT (SELECT %s FROM %Q AS t WHERE %s), %s " - "FROM (SELECT %s FROM %Q INDEXED BY %Q %s%sORDER BY %s) AS i", - zSubExpr, zTab, zSubWhere, zCurrentKey, - zSrcList, zTab, zIdxName, - (pIdx->zWhere ? "WHERE " : ""), (pIdx->zWhere ? pIdx->zWhere : ""), - zOrderBy - ); - }else{ - const char *zSep = ""; - char *zSql; - int i; - - zSql = cidxMprintf(&rc, - "SELECT (SELECT %s FROM %Q WHERE %s), %s FROM (", - zSubExpr, zTab, zSubWhere, zCurrentKey - ); - for(i=pIdx->nCol-1; i>=0; i--){ - int j; - if( pIdx->aCol[i].bDesc && azAfter[i]==0 ) continue; - for(j=0; j<2; j++){ - char *zWhere = cidxWhere(&rc, pIdx->aCol, azAfter, i, j); - zSql = cidxMprintf(&rc, "%z" - "%sSELECT * FROM (" - "SELECT %s FROM %Q INDEXED BY %Q WHERE %s%s%z ORDER BY %s" - ")", - zSql, zSep, zSrcList, zTab, zIdxName, - pIdx->zWhere ? pIdx->zWhere : "", - pIdx->zWhere ? " AND " : "", - zWhere, zOrderBy - ); - zSep = " UNION ALL "; - if( pIdx->aCol[i].bDesc==0 ) break; - } - } - *pzSqlOut = cidxMprintf(&rc, "%z) AS i", zSql); - } - } - - sqlite3_free(zTab); - sqlite3_free(zCurrentKey); - sqlite3_free(zOrderBy); - sqlite3_free(zSubWhere); - sqlite3_free(zSubExpr); - sqlite3_free(zSrcList); - cidxFreeIndex(pIdx); - sqlite3_free(azAfter); - return rc; -} - - -/* -** Position a cursor back to the beginning. -*/ -static int cidxFilter( - sqlite3_vtab_cursor *pCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - int rc = SQLITE_OK; - CidxCursor *pCsr = (CidxCursor*)pCursor; - const char *zIdxName = 0; - const char *zAfterKey = 0; - - sqlite3_free(pCsr->zIdxName); - pCsr->zIdxName = 0; - sqlite3_free(pCsr->zAfterKey); - pCsr->zAfterKey = 0; - sqlite3_finalize(pCsr->pStmt); - pCsr->pStmt = 0; - - if( argc>0 ){ - zIdxName = (const char*)sqlite3_value_text(argv[0]); - if( argc>1 ){ - zAfterKey = (const char*)sqlite3_value_text(argv[1]); - } - } - - if( zIdxName ){ - char *zSql = 0; - pCsr->zIdxName = sqlite3_mprintf("%s", zIdxName); - pCsr->zAfterKey = zAfterKey ? sqlite3_mprintf("%s", zAfterKey) : 0; - rc = cidxGenerateScanSql(pCsr, zIdxName, zAfterKey, &zSql); - if( zSql ){ - pCsr->pStmt = cidxPrepare(&rc, pCsr, "%z", zSql); - } - } - - if( pCsr->pStmt ){ - assert( rc==SQLITE_OK ); - rc = cidxNext(pCursor); - } - pCsr->iRowid = 1; - return rc; -} - -/* -** Return a column value. -*/ -static int cidxColumn( - sqlite3_vtab_cursor *pCursor, - sqlite3_context *ctx, - int iCol -){ - CidxCursor *pCsr = (CidxCursor*)pCursor; - assert( iCol>=IIC_ERRMSG && iCol<=IIC_SCANNER_SQL ); - switch( iCol ){ - case IIC_ERRMSG: { - const char *zVal = 0; - if( sqlite3_column_type(pCsr->pStmt, 0)==SQLITE_INTEGER ){ - if( sqlite3_column_int(pCsr->pStmt, 0)==0 ){ - zVal = "row data mismatch"; - } - }else{ - zVal = "row missing"; - } - sqlite3_result_text(ctx, zVal, -1, SQLITE_STATIC); - break; - } - case IIC_CURRENT_KEY: { - sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, 1)); - break; - } - case IIC_INDEX_NAME: { - sqlite3_result_text(ctx, pCsr->zIdxName, -1, SQLITE_TRANSIENT); - break; - } - case IIC_AFTER_KEY: { - sqlite3_result_text(ctx, pCsr->zAfterKey, -1, SQLITE_TRANSIENT); - break; - } - case IIC_SCANNER_SQL: { - char *zSql = 0; - cidxGenerateScanSql(pCsr, pCsr->zIdxName, pCsr->zAfterKey, &zSql); - sqlite3_result_text(ctx, zSql, -1, sqlite3_free); - break; - } - } - return SQLITE_OK; -} - -/* Return the ROWID for the sqlite_btreeinfo table */ -static int cidxRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ - CidxCursor *pCsr = (CidxCursor*)pCursor; - *pRowid = pCsr->iRowid; - return SQLITE_OK; -} - -/* -** Register the virtual table modules with the database handle passed -** as the only argument. -*/ -static int ciInit(sqlite3 *db){ - static sqlite3_module cidx_module = { - 0, /* iVersion */ - 0, /* xCreate */ - cidxConnect, /* xConnect */ - cidxBestIndex, /* xBestIndex */ - cidxDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - cidxOpen, /* xOpen - open a cursor */ - cidxClose, /* xClose - close a cursor */ - cidxFilter, /* xFilter - configure scan constraints */ - cidxNext, /* xNext - advance a cursor */ - cidxEof, /* xEof - check for end of scan */ - cidxColumn, /* xColumn - read data */ - cidxRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ - }; - return sqlite3_create_module(db, "incremental_index_check", &cidx_module, 0); -} - -/* -** Extension load function. -*/ -#ifdef _WIN32 -__declspec(dllexport) -#endif -int sqlite3_checkindex_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - SQLITE_EXTENSION_INIT2(pApi); - return ciInit(db); -} diff --git a/ext/repair/sqlite3_checker.c.in b/ext/repair/sqlite3_checker.c.in deleted file mode 100644 index 96b15f2713..0000000000 --- a/ext/repair/sqlite3_checker.c.in +++ /dev/null @@ -1,85 +0,0 @@ -/* -** Read an SQLite database file and analyze its space utilization. Generate -** text on standard output. -*/ -#define TCLSH_INIT_PROC sqlite3_checker_init_proc -#define SQLITE_ENABLE_DBPAGE_VTAB 1 -#undef SQLITE_THREADSAFE -#define SQLITE_THREADSAFE 0 -#undef SQLITE_ENABLE_COLUMN_METADATA -#define SQLITE_OMIT_DECLTYPE 1 -#define SQLITE_OMIT_DEPRECATED 1 -#define SQLITE_OMIT_PROGRESS_CALLBACK 1 -#define SQLITE_OMIT_SHARED_CACHE 1 -#define SQLITE_DEFAULT_MEMSTATUS 0 -#define SQLITE_MAX_EXPR_DEPTH 0 -INCLUDE sqlite3.c -INCLUDE $ROOT/src/tclsqlite.c -INCLUDE $ROOT/ext/misc/btreeinfo.c -INCLUDE $ROOT/ext/repair/checkindex.c -INCLUDE $ROOT/ext/repair/checkfreelist.c - -/* -** Decode a pointer to an sqlite3 object. -*/ -int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){ - struct SqliteDb *p; - Tcl_CmdInfo cmdInfo; - if( Tcl_GetCommandInfo(interp, zA, &cmdInfo) ){ - p = (struct SqliteDb*)cmdInfo.objClientData; - *ppDb = p->db; - return TCL_OK; - }else{ - *ppDb = 0; - return TCL_ERROR; - } - return TCL_OK; -} - -/* -** sqlite3_imposter db main rootpage {CREATE TABLE...} ;# setup an imposter -** sqlite3_imposter db main ;# rm all imposters -*/ -static int sqlite3_imposter( - void *clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - sqlite3 *db; - const char *zSchema; - int iRoot; - const char *zSql; - - if( objc!=3 && objc!=5 ){ - Tcl_WrongNumArgs(interp, 1, objv, "DB SCHEMA [ROOTPAGE SQL]"); - return TCL_ERROR; - } - if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; - zSchema = Tcl_GetString(objv[2]); - if( objc==3 ){ - sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zSchema, 0, 1); - }else{ - if( Tcl_GetIntFromObj(interp, objv[3], &iRoot) ) return TCL_ERROR; - zSql = Tcl_GetString(objv[4]); - sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zSchema, 1, iRoot); - sqlite3_exec(db, zSql, 0, 0, 0); - sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zSchema, 0, 0); - } - return TCL_OK; -} - -#include - -const char *sqlite3_checker_init_proc(Tcl_Interp *interp){ - Tcl_CreateObjCommand(interp, "sqlite3_imposter", - (Tcl_ObjCmdProc*)sqlite3_imposter, 0, 0); - sqlite3_auto_extension((void(*)(void))sqlite3_btreeinfo_init); - sqlite3_auto_extension((void(*)(void))sqlite3_checkindex_init); - sqlite3_auto_extension((void(*)(void))sqlite3_checkfreelist_init); - return -BEGIN_STRING -INCLUDE $ROOT/ext/repair/sqlite3_checker.tcl -END_STRING -; -} diff --git a/ext/repair/sqlite3_checker.tcl b/ext/repair/sqlite3_checker.tcl deleted file mode 100644 index 2ae6e15b12..0000000000 --- a/ext/repair/sqlite3_checker.tcl +++ /dev/null @@ -1,264 +0,0 @@ -# This TCL script is the main driver script for the sqlite3_checker utility -# program. -# - -# Special case: -# -# sqlite3_checker --test FILENAME ARGS -# -# uses FILENAME in place of this script. -# -if {[lindex $argv 0]=="--test" && [llength $argv]>1} { - set ::argv0 [lindex $argv 1] - set argv [lrange $argv 2 end] - source $argv0 - exit 0 -} - -# Emulate a TCL shell -# -proc tclsh {} { - set line {} - while {![eof stdin]} { - if {$line!=""} { - puts -nonewline "> " - } else { - puts -nonewline "% " - } - flush stdout - append line [gets stdin] - if {[info complete $line]} { - if {[catch {uplevel #0 $line} result]} { - puts stderr "Error: $result" - } elseif {$result!=""} { - puts $result - } - set line {} - } else { - append line \n - } - } -} - -# Do an incremental integrity check of a single index -# -proc check_index {idxname batchsize bTrace} { - set i 0 - set more 1 - set nerr 0 - set pct 00.0 - set max [db one {SELECT nEntry FROM sqlite_btreeinfo('main') - WHERE name=$idxname}] - puts -nonewline "$idxname: $i of $max rows ($pct%)\r" - flush stdout - if {$bTrace} { - set sql {SELECT errmsg, current_key AS key, - CASE WHEN rowid=1 THEN scanner_sql END AS traceOut - FROM incremental_index_check($idxname) - WHERE after_key=$key - LIMIT $batchsize} - } else { - set sql {SELECT errmsg, current_key AS key, NULL AS traceOut - FROM incremental_index_check($idxname) - WHERE after_key=$key - LIMIT $batchsize} - } - while {$more} { - set more 0 - db eval $sql { - set more 1 - if {$errmsg!=""} { - incr nerr - puts "$idxname: key($key): $errmsg" - } elseif {$traceOut!=""} { - puts "$idxname: $traceOut" - } - incr i - - } - set x [format {%.1f} [expr {($i*100.0)/$max}]] - if {$x!=$pct} { - puts -nonewline "$idxname: $i of $max rows ($pct%)\r" - flush stdout - set pct $x - } - } - puts "$idxname: $nerr errors out of $i entries" -} - -# Print a usage message on standard error, then quit. -# -proc usage {} { - set argv0 [file rootname [file tail [info nameofexecutable]]] - puts stderr "Usage: $argv0 OPTIONS database-filename" - puts stderr { -Do sanity checking on a live SQLite3 database file specified by the -"database-filename" argument. - -Options: - - --batchsize N Number of rows to check per transaction - - --freelist Perform a freelist check - - --index NAME Run a check of the index NAME - - --summary Print summary information about the database - - --table NAME Run a check of all indexes for table NAME - - --tclsh Run the built-in TCL interpreter (for debugging) - - --trace (Debugging only:) Output trace information on the scan - - --version Show the version number of SQLite -} - exit 1 -} - -set file_to_analyze {} -append argv {} -set bFreelistCheck 0 -set bSummary 0 -set zIndex {} -set zTable {} -set batchsize 1000 -set bAll 1 -set bTrace 0 -set argc [llength $argv] -for {set i 0} {$i<$argc} {incr i} { - set arg [lindex $argv $i] - if {[regexp {^-+tclsh$} $arg]} { - tclsh - exit 0 - } - if {[regexp {^-+version$} $arg]} { - sqlite3 mem :memory: - puts [mem one {SELECT sqlite_version()||' '||sqlite_source_id()}] - mem close - exit 0 - } - if {[regexp {^-+freelist$} $arg]} { - set bFreelistCheck 1 - set bAll 0 - continue - } - if {[regexp {^-+summary$} $arg]} { - set bSummary 1 - set bAll 0 - continue - } - if {[regexp {^-+trace$} $arg]} { - set bTrace 1 - continue - } - if {[regexp {^-+batchsize$} $arg]} { - incr i - if {$i>=$argc} { - puts stderr "missing argument on $arg" - exit 1 - } - set batchsize [lindex $argv $i] - continue - } - if {[regexp {^-+index$} $arg]} { - incr i - if {$i>=$argc} { - puts stderr "missing argument on $arg" - exit 1 - } - set zIndex [lindex $argv $i] - set bAll 0 - continue - } - if {[regexp {^-+table$} $arg]} { - incr i - if {$i>=$argc} { - puts stderr "missing argument on $arg" - exit 1 - } - set zTable [lindex $argv $i] - set bAll 0 - continue - } - if {[regexp {^-} $arg]} { - puts stderr "Unknown option: $arg" - usage - } - if {$file_to_analyze!=""} { - usage - } else { - set file_to_analyze $arg - } -} -if {$file_to_analyze==""} usage - -# If a TCL script is specified on the command-line, then run that -# script. -# -if {[file extension $file_to_analyze]==".tcl"} { - source $file_to_analyze - exit 0 -} - -set root_filename $file_to_analyze -regexp {^file:(//)?([^?]*)} $file_to_analyze all x1 root_filename -if {![file exists $root_filename]} { - puts stderr "No such file: $root_filename" - exit 1 -} -if {![file readable $root_filename]} { - puts stderr "File is not readable: $root_filename" - exit 1 -} - -if {[catch {sqlite3 db $file_to_analyze} res]} { - puts stderr "Cannot open datababase $root_filename: $res" - exit 1 -} - -if {$bFreelistCheck || $bAll} { - puts -nonewline "freelist-check: " - flush stdout - db eval BEGIN - puts [db one {SELECT checkfreelist('main')}] - db eval END -} -if {$bSummary} { - set scale 0 - set pgsz [db one {PRAGMA page_size}] - db eval {SELECT nPage*$pgsz AS sz, name, tbl_name - FROM sqlite_btreeinfo - WHERE type='index' - ORDER BY 1 DESC, name} { - if {$scale==0} { - if {$sz>10000000} { - set scale 1000000.0 - set unit MB - } else { - set scale 1000.0 - set unit KB - } - } - puts [format {%7.1f %s index %s of table %s} \ - [expr {$sz/$scale}] $unit $name $tbl_name] - } -} -if {$zIndex!=""} { - check_index $zIndex $batchsize $bTrace -} -if {$zTable!=""} { - foreach idx [db eval {SELECT name FROM sqlite_master - WHERE type='index' AND rootpage>0 - AND tbl_name=$zTable}] { - check_index $idx $batchsize $bTrace - } -} -if {$bAll} { - set allidx [db eval {SELECT name FROM sqlite_btreeinfo('main') - WHERE type='index' AND rootpage>0 - ORDER BY nEntry}] - foreach idx $allidx { - check_index $idx $batchsize $bTrace - } -} diff --git a/ext/repair/test/README.md b/ext/repair/test/README.md deleted file mode 100644 index 8cc954adf5..0000000000 --- a/ext/repair/test/README.md +++ /dev/null @@ -1,13 +0,0 @@ -To run these tests, first build sqlite3_checker: - - -> make sqlite3_checker - - -Then run the "test.tcl" script using: - - -> ./sqlite3_checker --test $path/test.tcl - - -Optionally add the full pathnames of individual *.test modules diff --git a/ext/repair/test/checkfreelist01.test b/ext/repair/test/checkfreelist01.test deleted file mode 100644 index 7e2dd51c37..0000000000 --- a/ext/repair/test/checkfreelist01.test +++ /dev/null @@ -1,92 +0,0 @@ -# 2017-10-11 - -set testprefix checkfreelist - -do_execsql_test 1.0 { - PRAGMA page_size=1024; - CREATE TABLE t1(a, b); -} - -do_execsql_test 1.2 { SELECT checkfreelist('main') } {ok} -do_execsql_test 1.3 { - WITH s(i) AS ( - SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10000 - ) - INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s; - DELETE FROM t1 WHERE rowid%3; - PRAGMA freelist_count; -} {6726} - -do_execsql_test 1.4 { SELECT checkfreelist('main') } {ok} -do_execsql_test 1.5 { - WITH freelist_trunk(i, d, n) AS ( - SELECT 1, NULL, sqlite_readint32(data, 32) FROM sqlite_dbpage WHERE pgno=1 - UNION ALL - SELECT n, data, sqlite_readint32(data) - FROM freelist_trunk, sqlite_dbpage WHERE pgno=n - ) - SELECT i FROM freelist_trunk WHERE i!=1; -} { - 10009 9715 9343 8969 8595 8222 7847 7474 7102 6727 6354 5982 5608 5234 - 4860 4487 4112 3740 3367 2992 2619 2247 1872 1499 1125 752 377 5 -} - -do_execsql_test 1.6 { SELECT checkfreelist('main') } {ok} - -proc set_int {blob idx newval} { - binary scan $blob I* ints - lset ints $idx $newval - binary format I* $ints -} -db func set_int set_int - -proc get_int {blob idx} { - binary scan $blob I* ints - lindex $ints $idx -} -db func get_int get_int - -do_execsql_test 1.7 { - BEGIN; - UPDATE sqlite_dbpage - SET data = set_int(data, 1, get_int(data, 1)-1) - WHERE pgno=4860; - SELECT checkfreelist('main'); - ROLLBACK; -} {{free-list count mismatch: actual=6725 header=6726}} - -do_execsql_test 1.8 { - BEGIN; - UPDATE sqlite_dbpage - SET data = set_int(data, 5, (SELECT * FROM pragma_page_count)+1) - WHERE pgno=4860; - SELECT checkfreelist('main'); - ROLLBACK; -} {{leaf page 10092 is out of range (child 3 of trunk page 4860)}} - -do_execsql_test 1.9 { - BEGIN; - UPDATE sqlite_dbpage - SET data = set_int(data, 5, 0) - WHERE pgno=4860; - SELECT checkfreelist('main'); - ROLLBACK; -} {{leaf page 0 is out of range (child 3 of trunk page 4860)}} - -do_execsql_test 1.10 { - BEGIN; - UPDATE sqlite_dbpage - SET data = set_int(data, get_int(data, 1)+1, 0) - WHERE pgno=5; - SELECT checkfreelist('main'); - ROLLBACK; -} {{leaf page 0 is out of range (child 247 of trunk page 5)}} - -do_execsql_test 1.11 { - BEGIN; - UPDATE sqlite_dbpage - SET data = set_int(data, 1, 249) - WHERE pgno=5; - SELECT checkfreelist('main'); - ROLLBACK; -} {{leaf count out of range (249) on trunk page 5}} diff --git a/ext/repair/test/checkindex01.test b/ext/repair/test/checkindex01.test deleted file mode 100644 index 97973aee71..0000000000 --- a/ext/repair/test/checkindex01.test +++ /dev/null @@ -1,349 +0,0 @@ -# 2017-10-11 -# -set testprefix checkindex - -do_execsql_test 1.0 { - CREATE TABLE t1(a, b); - CREATE INDEX i1 ON t1(a); - INSERT INTO t1 VALUES('one', 2); - INSERT INTO t1 VALUES('two', 4); - INSERT INTO t1 VALUES('three', 6); - INSERT INTO t1 VALUES('four', 8); - INSERT INTO t1 VALUES('five', 10); - - CREATE INDEX i2 ON t1(a DESC); -} {} - -proc incr_index_check {idx nStep} { - set Q { - SELECT errmsg, current_key FROM incremental_index_check($idx, $after) - LIMIT $nStep - } - - set res [list] - while {1} { - unset -nocomplain current_key - set res1 [db eval $Q] - if {[llength $res1]==0} break - set res [concat $res $res1] - set after [lindex $res end] - } - - return $res -} - -proc do_index_check_test {tn idx res} { - uplevel [list do_execsql_test $tn.1 " - SELECT errmsg, current_key FROM incremental_index_check('$idx'); - " $res] - - uplevel [list do_test $tn.2 "incr_index_check $idx 1" [list {*}$res]] - uplevel [list do_test $tn.3 "incr_index_check $idx 2" [list {*}$res]] - uplevel [list do_test $tn.4 "incr_index_check $idx 5" [list {*}$res]] -} - - -do_execsql_test 1.2.1 { - SELECT rowid, errmsg IS NULL, current_key FROM incremental_index_check('i1'); -} { - 1 1 'five',5 - 2 1 'four',4 - 3 1 'one',1 - 4 1 'three',3 - 5 1 'two',2 -} -do_execsql_test 1.2.2 { - SELECT errmsg IS NULL, current_key, index_name, after_key, scanner_sql - FROM incremental_index_check('i1') LIMIT 1; -} { - 1 - 'five',5 - i1 - {} - {SELECT (SELECT a IS i.i0 FROM 't1' AS t WHERE "rowid" COLLATE BINARY IS i.i1), quote(i0)||','||quote(i1) FROM (SELECT (a) AS i0, ("rowid" COLLATE BINARY) AS i1 FROM 't1' INDEXED BY 'i1' ORDER BY 1,2) AS i} -} - -do_index_check_test 1.3 i1 { - {} 'five',5 - {} 'four',4 - {} 'one',1 - {} 'three',3 - {} 'two',2 -} - -do_index_check_test 1.4 i2 { - {} 'two',2 - {} 'three',3 - {} 'one',1 - {} 'four',4 - {} 'five',5 -} - -do_test 1.5 { - set tblroot [db one { SELECT rootpage FROM sqlite_master WHERE name='t1' }] - sqlite3_imposter db main $tblroot {CREATE TABLE xt1(a,b)} - db eval { - UPDATE xt1 SET a='six' WHERE rowid=3; - DELETE FROM xt1 WHERE rowid = 5; - } - sqlite3_imposter db main -} {} - -do_index_check_test 1.6 i1 { - {row missing} 'five',5 - {} 'four',4 - {} 'one',1 - {row data mismatch} 'three',3 - {} 'two',2 -} - -do_index_check_test 1.7 i2 { - {} 'two',2 - {row data mismatch} 'three',3 - {} 'one',1 - {} 'four',4 - {row missing} 'five',5 -} - -#-------------------------------------------------------------------------- -do_execsql_test 2.0 { - - CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c, d); - - INSERT INTO t2 VALUES(1, NULL, 1, 1); - INSERT INTO t2 VALUES(2, 1, NULL, 1); - INSERT INTO t2 VALUES(3, 1, 1, NULL); - - INSERT INTO t2 VALUES(4, 2, 2, 1); - INSERT INTO t2 VALUES(5, 2, 2, 2); - INSERT INTO t2 VALUES(6, 2, 2, 3); - - INSERT INTO t2 VALUES(7, 2, 2, 1); - INSERT INTO t2 VALUES(8, 2, 2, 2); - INSERT INTO t2 VALUES(9, 2, 2, 3); - - CREATE INDEX i3 ON t2(b, c, d); - CREATE INDEX i4 ON t2(b DESC, c DESC, d DESC); - CREATE INDEX i5 ON t2(d, c DESC, b); -} {} - -do_index_check_test 2.1 i3 { - {} NULL,1,1,1 - {} 1,NULL,1,2 - {} 1,1,NULL,3 - {} 2,2,1,4 - {} 2,2,1,7 - {} 2,2,2,5 - {} 2,2,2,8 - {} 2,2,3,6 - {} 2,2,3,9 -} - -do_index_check_test 2.2 i4 { - {} 2,2,3,6 - {} 2,2,3,9 - {} 2,2,2,5 - {} 2,2,2,8 - {} 2,2,1,4 - {} 2,2,1,7 - {} 1,1,NULL,3 - {} 1,NULL,1,2 - {} NULL,1,1,1 -} - -do_index_check_test 2.3 i5 { - {} NULL,1,1,3 - {} 1,2,2,4 - {} 1,2,2,7 - {} 1,1,NULL,1 - {} 1,NULL,1,2 - {} 2,2,2,5 - {} 2,2,2,8 - {} 3,2,2,6 - {} 3,2,2,9 -} - -#-------------------------------------------------------------------------- -do_execsql_test 3.0 { - - CREATE TABLE t3(w, x, y, z PRIMARY KEY) WITHOUT ROWID; - CREATE INDEX t3wxy ON t3(w, x, y); - CREATE INDEX t3wxy2 ON t3(w DESC, x DESC, y DESC); - - INSERT INTO t3 VALUES(NULL, NULL, NULL, 1); - INSERT INTO t3 VALUES(NULL, NULL, NULL, 2); - INSERT INTO t3 VALUES(NULL, NULL, NULL, 3); - - INSERT INTO t3 VALUES('a', NULL, NULL, 4); - INSERT INTO t3 VALUES('a', NULL, NULL, 5); - INSERT INTO t3 VALUES('a', NULL, NULL, 6); - - INSERT INTO t3 VALUES('a', 'b', NULL, 7); - INSERT INTO t3 VALUES('a', 'b', NULL, 8); - INSERT INTO t3 VALUES('a', 'b', NULL, 9); - -} {} - -do_index_check_test 3.1 t3wxy { - {} NULL,NULL,NULL,1 {} NULL,NULL,NULL,2 {} NULL,NULL,NULL,3 - {} 'a',NULL,NULL,4 {} 'a',NULL,NULL,5 {} 'a',NULL,NULL,6 - {} 'a','b',NULL,7 {} 'a','b',NULL,8 {} 'a','b',NULL,9 -} -do_index_check_test 3.2 t3wxy2 { - {} 'a','b',NULL,7 {} 'a','b',NULL,8 {} 'a','b',NULL,9 - {} 'a',NULL,NULL,4 {} 'a',NULL,NULL,5 {} 'a',NULL,NULL,6 - {} NULL,NULL,NULL,1 {} NULL,NULL,NULL,2 {} NULL,NULL,NULL,3 -} - -#-------------------------------------------------------------------------- -# Test with an index that uses non-default collation sequences. -# -do_execsql_test 4.0 { - CREATE TABLE t4(a INTEGER PRIMARY KEY, c1 TEXT, c2 TEXT); - INSERT INTO t4 VALUES(1, 'aaa', 'bbb'); - INSERT INTO t4 VALUES(2, 'AAA', 'CCC'); - INSERT INTO t4 VALUES(3, 'aab', 'ddd'); - INSERT INTO t4 VALUES(4, 'AAB', 'EEE'); - - CREATE INDEX t4cc ON t4(c1 COLLATE nocase, c2 COLLATE nocase); -} - -do_index_check_test 4.1 t4cc { - {} 'aaa','bbb',1 - {} 'AAA','CCC',2 - {} 'aab','ddd',3 - {} 'AAB','EEE',4 -} - -do_test 4.2 { - set tblroot [db one { SELECT rootpage FROM sqlite_master WHERE name='t4' }] - sqlite3_imposter db main $tblroot \ - {CREATE TABLE xt4(a INTEGER PRIMARY KEY, c1 TEXT, c2 TEXT)} - - db eval { - UPDATE xt4 SET c1='hello' WHERE rowid=2; - DELETE FROM xt4 WHERE rowid = 3; - } - sqlite3_imposter db main -} {} - -do_index_check_test 4.3 t4cc { - {} 'aaa','bbb',1 - {row data mismatch} 'AAA','CCC',2 - {row missing} 'aab','ddd',3 - {} 'AAB','EEE',4 -} - -#-------------------------------------------------------------------------- -# Test an index on an expression. -# -do_execsql_test 5.0 { - CREATE TABLE t5(x INTEGER PRIMARY KEY, y TEXT, UNIQUE(y)); - INSERT INTO t5 VALUES(1, '{"x":1, "y":1}'); - INSERT INTO t5 VALUES(2, '{"x":2, "y":2}'); - INSERT INTO t5 VALUES(3, '{"x":3, "y":3}'); - INSERT INTO t5 VALUES(4, '{"w":4, "z":4}'); - INSERT INTO t5 VALUES(5, '{"x":5, "y":5}'); - - CREATE INDEX t5x ON t5( json_extract(y, '$.x') ); - CREATE INDEX t5y ON t5( json_extract(y, '$.y') DESC ); -} - -do_index_check_test 5.1.1 t5x { - {} NULL,4 {} 1,1 {} 2,2 {} 3,3 {} 5,5 -} - -do_index_check_test 5.1.2 t5y { - {} 5,5 {} 3,3 {} 2,2 {} 1,1 {} NULL,4 -} - -do_index_check_test 5.1.3 sqlite_autoindex_t5_1 { - {} {'{"w":4, "z":4}',4} - {} {'{"x":1, "y":1}',1} - {} {'{"x":2, "y":2}',2} - {} {'{"x":3, "y":3}',3} - {} {'{"x":5, "y":5}',5} -} - -do_test 5.2 { - set tblroot [db one { SELECT rootpage FROM sqlite_master WHERE name='t5' }] - sqlite3_imposter db main $tblroot \ - {CREATE TABLE xt5(a INTEGER PRIMARY KEY, c1 TEXT);} - db eval { - UPDATE xt5 SET c1='{"x":22, "y":11}' WHERE rowid=1; - DELETE FROM xt5 WHERE rowid = 4; - } - sqlite3_imposter db main -} {} - -do_index_check_test 5.3.1 t5x { - {row missing} NULL,4 - {row data mismatch} 1,1 - {} 2,2 - {} 3,3 - {} 5,5 -} - -do_index_check_test 5.3.2 sqlite_autoindex_t5_1 { - {row missing} {'{"w":4, "z":4}',4} - {row data mismatch} {'{"x":1, "y":1}',1} - {} {'{"x":2, "y":2}',2} - {} {'{"x":3, "y":3}',3} - {} {'{"x":5, "y":5}',5} -} - -#------------------------------------------------------------------------- -# -do_execsql_test 6.0 { - CREATE TABLE t6(x INTEGER PRIMARY KEY, y, z); - CREATE INDEX t6x1 ON t6(y, /* one,two,three */ z); - CREATE INDEX t6x2 ON t6(z, -- hello,world, - y); - - CREATE INDEX t6x3 ON t6(z -- hello,world - , y); - - INSERT INTO t6 VALUES(1, 2, 3); - INSERT INTO t6 VALUES(4, 5, 6); -} - -do_index_check_test 6.1 t6x1 { - {} 2,3,1 - {} 5,6,4 -} -do_index_check_test 6.2 t6x2 { - {} 3,2,1 - {} 6,5,4 -} -do_index_check_test 6.2 t6x3 { - {} 3,2,1 - {} 6,5,4 -} - -#------------------------------------------------------------------------- -# -do_execsql_test 7.0 { - CREATE TABLE t7(x INTEGER PRIMARY KEY, y, z); - INSERT INTO t7 VALUES(1, 1, 1); - INSERT INTO t7 VALUES(2, 2, 0); - INSERT INTO t7 VALUES(3, 3, 1); - INSERT INTO t7 VALUES(4, 4, 0); - - CREATE INDEX t7i1 ON t7(y) WHERE z=1; - CREATE INDEX t7i2 ON t7(y) /* hello,world */ WHERE z=1; - CREATE INDEX t7i3 ON t7(y) WHERE -- yep - z=1; - CREATE INDEX t7i4 ON t7(y) WHERE z=1 -- yep; -} -do_index_check_test 7.1 t7i1 { - {} 1,1 {} 3,3 -} -do_index_check_test 7.2 t7i2 { - {} 1,1 {} 3,3 -} -do_index_check_test 7.3 t7i3 { - {} 1,1 {} 3,3 -} -do_index_check_test 7.4 t7i4 { - {} 1,1 {} 3,3 -} diff --git a/ext/repair/test/test.tcl b/ext/repair/test/test.tcl deleted file mode 100644 index c073bb73c5..0000000000 --- a/ext/repair/test/test.tcl +++ /dev/null @@ -1,67 +0,0 @@ -# Run this script using -# -# sqlite3_checker --test $thisscript $testscripts -# -# The $testscripts argument is optional. If omitted, all *.test files -# in the same directory as $thisscript are run. -# -set NTEST 0 -set NERR 0 - - -# Invoke the do_test procedure to run a single test -# -# The $expected parameter is the expected result. The result is the return -# value from the last TCL command in $cmd. -# -# Normally, $expected must match exactly. But if $expected is of the form -# "/regexp/" then regular expression matching is used. If $expected is -# "~/regexp/" then the regular expression must NOT match. If $expected is -# of the form "#/value-list/" then each term in value-list must be numeric -# and must approximately match the corresponding numeric term in $result. -# Values must match within 10%. Or if the $expected term is A..B then the -# $result term must be in between A and B. -# -proc do_test {name cmd expected} { - if {[info exists ::testprefix]} { - set name "$::testprefix$name" - } - - incr ::NTEST - puts -nonewline $name... - flush stdout - - if {[catch {uplevel #0 "$cmd;\n"} result]} { - puts -nonewline $name... - puts "\nError: $result" - incr ::NERR - } else { - set ok [expr {[string compare $result $expected]==0}] - if {!$ok} { - puts "\n! $name expected: \[$expected\]\n! $name got: \[$result\]" - incr ::NERR - } else { - puts " Ok" - } - } - flush stdout -} - -# -# do_execsql_test TESTNAME SQL RES -# -proc do_execsql_test {testname sql {result {}}} { - uplevel [list do_test $testname [list db eval $sql] [list {*}$result]] -} - -if {[llength $argv]==0} { - set dir [file dirname $argv0] - set argv [glob -nocomplain $dir/*.test] -} -foreach testfile $argv { - file delete -force test.db - sqlite3 db test.db - source $testfile - catch {db close} -} -puts "$NERR errors out of $NTEST tests" diff --git a/main.mk b/main.mk index 8b5d2821cf..46d646d03a 100644 --- a/main.mk +++ b/main.mk @@ -1971,24 +1971,6 @@ sqlite3_expert$(T.exe): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqli $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert $(LDFLAGS.libsqlite3) xbin: sqlite3_expert$(T.exe) -CHECKER_DEPS =\ - $(TOP)/tool/mkccode.tcl \ - sqlite3.c \ - tclsqlite-ex.c \ - $(TOP)/ext/repair/sqlite3_checker.tcl \ - $(TOP)/ext/repair/checkindex.c \ - $(TOP)/ext/repair/checkfreelist.c \ - $(TOP)/ext/misc/btreeinfo.c \ - $(TOP)/ext/repair/sqlite3_checker.c.in - -sqlite3_checker.c: $(CHECKER_DEPS) - $(B.tclsh) $(TOP)/tool/mkccode.tcl $(TOP)/ext/repair/sqlite3_checker.c.in >$@ - -sqlite3_checker$(T.exe): $(T.tcl.env.sh) sqlite3_checker.c - $(T.link.tcl) sqlite3_checker.c -o $@ $$TCL_INCLUDE_SPEC \ - $$TCL_LIB_SPEC $(LDFLAGS.libsqlite3) -xbin: sqlite3_checker$(T.exe) - dbdump$(T.exe): $(TOP)/ext/misc/dbdump.c sqlite3.o $(T.link) -DDBDUMP_STANDALONE -o $@ \ $(TOP)/ext/misc/dbdump.c sqlite3.o $(LDFLAGS.libsqlite3) diff --git a/manifest b/manifest index 1e2d8e52db..559c825e7b 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C Disable\stest\sshell1-5.0\sas\sit\sis\scausing\sa\suse\sof\sinitialized\sdeep\sinside\nof\sTCL. -D 2026-03-02T13:43:08.964 +C Remove\sthe\sexperimental\sand\sincomplete\sext/repair\sextension,\s\sto\sprevent\sAIs\nfrom\sscanning\sthe\s(incomplete)\scode\sand\sreporting\sbugs\sagainst\sit. +D 2026-03-02T13:44:04.938 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0 -F Makefile.msc 1fa179beafd6d438b8479146cae77fb1724dd35b330b09dbfebd8a2f0823c62a +F Makefile.msc 174764cb7e80c80f9003c46b3e388d74c68c8c40230208904b3af8fcabee5f4e F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec F VERSION 74672bfd4c7826c0fc6f84762488a707c52e7d2d94af42ccb0edcc6c74311c41 F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5 @@ -488,15 +488,6 @@ F ext/recover/recoversql.test e66d01f95302a223bcd3fd42b5ee58dc2b53d70afa90b0d00e F ext/recover/sqlite3recover.c 56c216332ea91233d6d820d429f3384adbec9ecedda67aa98186b691d427cc57 F ext/recover/sqlite3recover.h 011c799f02deb70ab685916f6f538e6bb32c4e0025e79bfd0e24ff9c74820959 F ext/recover/test_recover.c 3d0fb1df7823f5bc22a0b93955034d16a2dfa2eb1e443e9a0123a77f120599a3 -F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15 -F ext/repair/checkfreelist.c e21f06995ff4efdc1622dcceaea4dcba2caa83ca2f31a1607b98a8509168a996 -F ext/repair/checkindex.c 7639b4f8928f82c10b950169e60cc45a7f6798df0b299771d17bef025736f657 -F ext/repair/sqlite3_checker.c.in 445118c5f7fea958b36fba1b2c464283e60ed4842039ddee3265f1698115ebf7 -F ext/repair/sqlite3_checker.tcl a9a2caa9660567257c177a91124d8c0dccdfa341e25c51e6da7f1fd9e601eafa -F ext/repair/test/README.md 34b2f542cf5be7bffe479242b33ee3492cea30711e447cc4a1a86cb5915f419e -F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc78249442da72ff3f8297398a69 -F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c335096108c12c01bddbadcec -F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c F ext/rtree/README 734aa36238bcd2dee91db5dba107d5fcbdb02396612811377a8ad50f1272b1c1 F ext/rtree/geopoly.c bd1971479184d559499ff3087c37f2823977d7b0ec80916141ae66f70345c88d F ext/rtree/rtree.c 9331997a76b88a9bc04e156bdfd6e2fe35c0aa93bc338ebc6aa0ae470fe4a852 @@ -660,7 +651,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2 F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61 F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0 -F main.mk 9393d5982db60f26e72c5af24a8c11cf39374ff5e695fadb5a4e7376f28150c6 +F main.mk e1a03e9206f6a042a9147035915cb944e9242d570779bc3ccd7ed6a39df10cae F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -2197,8 +2188,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P e8976d5041c929675772039b7a8fc4ff0b609537d86f9aa6e445ecd512a10673 -R 196e96eb644b7fb48b6564a67ba146cd +P 440bd6091e3767f0a2f42ffdc92ca5e4736c0a73324fdd15397c3b5dbbc31fb8 +R c2e39b4a7bc89f40ea6792af5222cc7a U drh -Z db4a137667e1314416d854cef3854055 +Z 26aaa04451a5b488441824f4e50b1bf2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b3fac4eaf8..a60931df6c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -440bd6091e3767f0a2f42ffdc92ca5e4736c0a73324fdd15397c3b5dbbc31fb8 +213b1c6608af4b3e9d6e0d8de6432cc6857931427baf4beac1e0a4294e4dc6ce From 7fa89ea90707f797b13a0d598f1567e4924cf34d Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 2 Mar 2026 15:06:59 +0000 Subject: [PATCH 076/197] Change some sqlite3_realloc() calls into sqlite3_realloc64(). FossilOrigin-Name: a391f5646926787fd9a004225ea406b61d20f282c852c0282fd26cada644b601 --- ext/misc/fuzzer.c | 2 +- ext/qrf/qrf.c | 2 +- ext/rbu/sqlite3rbu.c | 4 ++-- manifest | 23 +++++++++++++---------- manifest.tags | 4 ++-- manifest.uuid | 2 +- src/os_unix.c | 2 +- tool/sqldiff.c | 37 ++++++++++++++++++++----------------- 8 files changed, 41 insertions(+), 35 deletions(-) diff --git a/ext/misc/fuzzer.c b/ext/misc/fuzzer.c index e16d005d9c..3dcf1d667c 100644 --- a/ext/misc/fuzzer.c +++ b/ext/misc/fuzzer.c @@ -617,7 +617,7 @@ static int fuzzerRender( int *pnBuf /* Size of the buffer */ ){ const fuzzer_rule *pRule = pStem->pRule; - int n; /* Size of output term without nul-term */ + sqlite3_int64 n; /* Size of output term without nul-term */ char *z; /* Buffer to assemble output term in */ n = pStem->nBasis + pRule->nTo - pRule->nFrom; diff --git a/ext/qrf/qrf.c b/ext/qrf/qrf.c index b78b52e6ac..cacfa15263 100644 --- a/ext/qrf/qrf.c +++ b/ext/qrf/qrf.c @@ -2900,7 +2900,7 @@ static void qrfFinalize(Qrf *p){ char *zCombined; sz = strlen(p->spec.pzOutput[0]); n = sqlite3_str_length(p->pOut); - zCombined = sqlite3_realloc(p->spec.pzOutput[0], sz+n+1); + zCombined = sqlite3_realloc64(p->spec.pzOutput[0], sz+n+1); if( zCombined==0 ){ sqlite3_free(p->spec.pzOutput[0]); p->spec.pzOutput[0] = 0; diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c index e3bcd5fc79..f377d5c30d 100644 --- a/ext/rbu/sqlite3rbu.c +++ b/ext/rbu/sqlite3rbu.c @@ -2269,8 +2269,8 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ /* If necessary, grow the pIter->aIdxCol[] array */ if( iIdxCol==nIdxAlloc ){ - RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc( - pIter->aIdxCol, (nIdxAlloc+16)*sizeof(RbuSpan) + RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc64( + pIter->aIdxCol, nIdxAlloc*sizeof(RbuSpan) + 16*sizeof(RbuSpan) ); if( aIdxCol==0 ){ rc = SQLITE_NOMEM; diff --git a/manifest b/manifest index 559c825e7b..4784346c19 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\sexperimental\sand\sincomplete\sext/repair\sextension,\s\sto\sprevent\sAIs\nfrom\sscanning\sthe\s(incomplete)\scode\sand\sreporting\sbugs\sagainst\sit. -D 2026-03-02T13:44:04.938 +C Change\ssome\ssqlite3_realloc()\scalls\sinto\ssqlite3_realloc64(). +D 2026-03-02T15:06:59.535 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -375,7 +375,7 @@ F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755d F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b F ext/misc/fileio.c 33165b3cd99f83dcd333a338eb51491f6b01c8d96cb6ae81f96a6a096834e030 F ext/misc/fossildelta.c 86dfa83f85f7ccd640591d8a5c6865346d0c2ee6a949d78591eceb892f1cbfec -F ext/misc/fuzzer.c 6b231352815304ba60d8e9ec2ee73d4918e74d9b76bda8940ba2b64e8777515e +F ext/misc/fuzzer.c 684a4996b523ea89f495b38fd8a14a2ae00695089a88031366a4df6adc2c873b F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b F ext/misc/memstat.c 43705d795090efb78c85c736b89251e743c291e23daaa8382fe7a0df2c6a283d F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b @@ -420,7 +420,7 @@ F ext/misc/zipfile.c c8ee04e1b349270b5df401ad732f5d7c387146e69b33c02fa90322760cc F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee F ext/qrf/README.md e6e0ce2700acf6fd06312b42726a8f08ca240f30e1b122bff87c71c602046352 F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430 -F ext/qrf/qrf.c 78b93d1d773bdcc667ab41716dab2fa9ad26957aa239cc1244eaff61d2cffbc9 +F ext/qrf/qrf.c cd48c23500c3b129be5e0627ce9d41b5df3c2d715525b00a6ccbd1f30689fb17 F ext/qrf/qrf.h 2ac14b0aaacf44636d8c81051bfeab4afae50a98fbb2e10ff5aed0c28a87b2b2 F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8 F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255 @@ -466,7 +466,7 @@ F ext/rbu/rbuvacuum.test 542561741ff2b262e3694bc6012b44694ee62c545845319a06f3237 F ext/rbu/rbuvacuum2.test 1a9bd41f127be2826de2a65204df9118525a8af8d16e61e6bc63ba3ac0010a23 F ext/rbu/rbuvacuum3.test 3ce42695fdf21aaa3499e857d7d4253bc499ad759bcd6c9362042c13cd37d8de F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69eefaebb205 -F ext/rbu/sqlite3rbu.c 3fb2390575b261c365d3f6fea61ff15e74d5d89e373f2a2bfa4d80c24321e793 +F ext/rbu/sqlite3rbu.c e99400d29d029936075e27495b269a2dcdceae3cf8c86b1d0869b4af487be3ab F ext/rbu/sqlite3rbu.h e3a5bf21e09ca93ce4e8740e00d6a853e90a697968ec0ea98f40826938bdb68e F ext/rbu/test_rbu.c 8b6e64e486c28c41ef29f6f4ea6be7b3091958987812784904f5e903f6b56418 F ext/recover/dbdata.c 10d3c56968a9af6853722a47280805ad1564714d79ea45ac6f7da14bb57fd137 @@ -714,7 +714,7 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63 F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06 F src/os_kv.c e7d96727db5b67e39d590a68cc61c86daf4c093c36c011a09ebfb521182ec28d F src/os_setup.h 8efc64eda6a6c2f221387eefc2e7e45fd5a3d5c8337a7a83519ba4fbd2957ae2 -F src/os_unix.c dcf7988ddbdd68619b821c9a722f9377abb46f1d26c9279eb5a50402fd43d749 +F src/os_unix.c fa5e09b4df35ad845440cad67b86908cfe1fd4c28c51915f82e23633d1992bf4 F src/os_win.c 0d553b6e8b92c8eb85e7f1b4a8036fe8638c8b32c9ad8d9d72a861c10f81b4c5 F src/os_win.h 5e168adf482484327195d10f9c3bce3520f598e04e07ffe62c9c5a8067c1037b F src/pager.c fe34fd22ec251436985d7b6ebdd05bf238a17901c2cb23d3d28974dd2361a912 @@ -2167,7 +2167,7 @@ F tool/soak1.tcl a3892082ed1079671565c044e93b55c3c7f38829aedf53cc597c65d23ffdadd F tool/spaceanal.tcl 1f83962090a6b60e1d7bf92495d643e622bef9fe82ea3f2d22350dcbce9a12d0 F tool/spellsift.tcl 52b4b04dc4333c7ab024f09d9d66ed6b6f7c6eb00b38497a09f338fa55d40618 x F tool/split-sqlite3c.tcl 4969fd642dad0ea483e4e104163021d92baf98f6a8eac981fe48525f9b873430 -F tool/sqldiff.c 68f88017de3bed3aa65c93a4cf3a04d0989d158bc6fad8f1475beeeea1aae3ac +F tool/sqldiff.c 847edc1e0d1e1feb652d3d6128e504456deaf254ab9ad3e7cebd4317d2037182 F tool/sqlite3_analyzer.c.in 14f02cb5ec3c264cd6107d1f1dad77092b1cf440fc196c30b69ae87b56a1a43b F tool/sqlite3_rsync.c f510a8b230e1c5b0f62842acd0e94ff15d2f77a00ae782f7d20f9e39919fa19b F tool/sqltclsh.c.in c103c6fc7d42bce611f9d4596774d60b7ef3d0b291a1f58c9e6184e458b89296 @@ -2188,8 +2188,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 440bd6091e3767f0a2f42ffdc92ca5e4736c0a73324fdd15397c3b5dbbc31fb8 -R c2e39b4a7bc89f40ea6792af5222cc7a +P 213b1c6608af4b3e9d6e0d8de6432cc6857931427baf4beac1e0a4294e4dc6ce +R 692cefb01f40a202a11e71cff4bf7ea9 +T *branch * realloc64 +T *sym-realloc64 * +T -sym-trunk * U drh -Z 26aaa04451a5b488441824f4e50b1bf2 +Z a67612dc8e1ea9af8ba17382f23457df # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..c058ae815e 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch realloc64 +tag realloc64 diff --git a/manifest.uuid b/manifest.uuid index a60931df6c..9d848078c2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -213b1c6608af4b3e9d6e0d8de6432cc6857931427baf4beac1e0a4294e4dc6ce +a391f5646926787fd9a004225ea406b61d20f282c852c0282fd26cada644b601 diff --git a/src/os_unix.c b/src/os_unix.c index d73d899241..2f75829c85 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5190,7 +5190,7 @@ static int unixShmMap( } /* Map the requested memory region into this processes address space. */ - apNew = (char **)sqlite3_realloc( + apNew = (char **)sqlite3_realloc64( pShmNode->apRegion, nReqRegion*sizeof(char *) ); if( !apNew ){ diff --git a/tool/sqldiff.c b/tool/sqldiff.c index b1eec92fdb..d27a62e14e 100644 --- a/tool/sqldiff.c +++ b/tool/sqldiff.c @@ -28,6 +28,9 @@ #include "sqlite3.h" #include "sqlite3_stdio.h" +typedef sqlite3_int64 i64; +typedef sqlite3_uint64 u64; + /* ** All global variables are gathered into the "g" singleton. */ @@ -202,12 +205,12 @@ static char **columnNames( int *pbRowid /* OUT: True if PK is an implicit rowid */ ){ char **az = 0; /* List of column names to be returned */ - int naz = 0; /* Number of entries in az[] */ + i64 naz = 0; /* Number of entries in az[] */ sqlite3_stmt *pStmt; /* SQL statement being run */ char *zPkIdxName = 0; /* Name of the PRIMARY KEY index */ int truePk = 0; /* PRAGMA table_info identifies the PK to use */ - int nPK = 0; /* Number of PRIMARY KEY columns */ - int i, j; /* Loop counters */ + i64 nPK = 0; /* Number of PRIMARY KEY columns */ + i64 i, j; /* Loop counters */ if( g.bSchemaPK==0 ){ /* Normal case: Figure out what the true primary key is for the table. @@ -271,7 +274,7 @@ static char **columnNames( } *pnPKey = nPK; naz = nPK; - az = sqlite3_malloc( sizeof(char*)*(nPK+1) ); + az = sqlite3_malloc64( sizeof(char*)*(nPK+1) ); if( az==0 ) runtimeError("out of memory"); memset(az, 0, sizeof(char*)*(nPK+1)); if( g.bSchemaCompare ){ @@ -288,7 +291,7 @@ static char **columnNames( || !(strcmp(sid,"rootpage")==0 ||strcmp(sid,"name")==0 ||strcmp(sid,"type")==0)){ - az = sqlite3_realloc(az, sizeof(char*)*(naz+2) ); + az = sqlite3_realloc64(az, sizeof(char*)*(naz+2) ); if( az==0 ) runtimeError("out of memory"); az[naz++] = sid; } @@ -954,7 +957,7 @@ static int rbuDeltaCreate( unsigned int i, base; char *zOrigDelta = zDelta; hash h; - int nHash; /* Number of hash table entries */ + i64 nHash; /* Number of hash table entries */ int *landmark; /* Primary hash table */ int *collide; /* Collision chain */ int lastRead = -1; /* Last byte of zSrc read by a COPY command */ @@ -982,7 +985,7 @@ static int rbuDeltaCreate( ** source file. */ nHash = lenSrc/NHASH; - collide = sqlite3_malloc( nHash*2*sizeof(int) ); + collide = sqlite3_malloc64( nHash*2*sizeof(int) ); landmark = &collide[nHash]; memset(landmark, -1, nHash*sizeof(int)); memset(collide, -1, nHash*sizeof(int)); @@ -1286,9 +1289,9 @@ static void rbudiff_one_table(const char *zTab, FILE *out){ } }else{ char *zOtaControl; - int nOtaControl = sqlite3_column_bytes(pStmt, nCol); + i64 nOtaControl = sqlite3_column_bytes(pStmt, nCol); - zOtaControl = (char*)sqlite3_malloc(nOtaControl+1); + zOtaControl = (char*)sqlite3_malloc64(nOtaControl+1); memcpy(zOtaControl, sqlite3_column_text(pStmt, nCol), nOtaControl+1); for(i=0; i0 ){ if( i>nPk ){ nPk = i; - aiPk = sqlite3_realloc(aiPk, sizeof(int)*nPk); + aiPk = sqlite3_realloc64(aiPk, sizeof(int)*nPk); if( aiPk==0 ) runtimeError("out of memory"); } aiPk[i-1] = nCol-1; @@ -1913,7 +1916,7 @@ int main(int argc, char **argv){ FILE *out = stdout; void (*xDiff)(const char*,FILE*) = diff_one_table; #ifndef SQLITE_OMIT_LOAD_EXTENSION - int nExt = 0; + i64 nExt = 0; char **azExt = 0; #endif int useTransaction = 0; From 72afb50a6d7f3f85800329233e4604b33ddae2a3 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 2 Mar 2026 15:34:16 +0000 Subject: [PATCH 077/197] Fix TEMP INSTEAD OF triggers so that they work on TEMP views. [forum:/forumpost/2026-02-28T23:33:04z|Forum post 2026-02-28T23:33:04z]. FossilOrigin-Name: 0596bd508f0bc548158858a1dc113af2235d02632ce8c41cd27d1029e1a7e48d --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 559c825e7b..8abfffe086 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\sexperimental\sand\sincomplete\sext/repair\sextension,\s\sto\sprevent\sAIs\nfrom\sscanning\sthe\s(incomplete)\scode\sand\sreporting\sbugs\sagainst\sit. -D 2026-03-02T13:44:04.938 +C Fix\sTEMP\sINSTEAD\sOF\striggers\sso\sthat\sthey\swork\son\sTEMP\sviews.\n[forum:/forumpost/2026-02-28T23:33:04z|Forum\spost\s2026-02-28T23:33:04z]. +D 2026-03-02T15:34:16.932 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -790,7 +790,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c f297bbf02037639e7a93b37d9c6e4415b3de1273395ee8fa8183e741e1e7fb72 F src/treeview.c feaa59f14db4f7b5aacca9c5ad5aeb562c1f98262c1ffd74371f4186ade91fc5 -F src/trigger.c a40440614bdf523090cc07223f4878f7e3c892bcd1a13afe18f90190daa5945d +F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20 F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 @@ -2188,8 +2188,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 440bd6091e3767f0a2f42ffdc92ca5e4736c0a73324fdd15397c3b5dbbc31fb8 -R c2e39b4a7bc89f40ea6792af5222cc7a +P 213b1c6608af4b3e9d6e0d8de6432cc6857931427baf4beac1e0a4294e4dc6ce +R 996b11c4e53e27c110bbd4ecdaab164e U drh -Z 26aaa04451a5b488441824f4e50b1bf2 +Z b315db4b82b7c9cbeaa07c1d78d09cfe # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a60931df6c..7c62954430 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -213b1c6608af4b3e9d6e0d8de6432cc6857931427baf4beac1e0a4294e4dc6ce +0596bd508f0bc548158858a1dc113af2235d02632ce8c41cd27d1029e1a7e48d diff --git a/src/trigger.c b/src/trigger.c index d26d1dc860..4f9068ad80 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -820,6 +820,7 @@ static SQLITE_NOINLINE Trigger *triggersReallyExist( p = pList; if( (pParse->db->flags & SQLITE_EnableTrigger)==0 && pTab->pTrigger!=0 + && sqlite3SchemaToIndex(pParse->db, pTab->pTrigger->pSchema)!=1 ){ /* The SQLITE_DBCONFIG_ENABLE_TRIGGER setting is off. That means that ** only TEMP triggers are allowed. Truncate the pList so that it From f6c8adf3a2e6a38b90edeb8fbc479a6740445826 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 2 Mar 2026 16:40:16 +0000 Subject: [PATCH 078/197] Omit explain_i calls from TCL test scripts. FossilOrigin-Name: 204f25c882832058c3291d4d6a0a6ac2711c081cb91b19feb2cf94a25ed61ecf --- ext/fts5/test/fts5integrity.test | 3 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- test/bestindexB.test | 2 +- test/values.test | 6 +++--- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/ext/fts5/test/fts5integrity.test b/ext/fts5/test/fts5integrity.test index 4bf120c446..9b2720faf0 100644 --- a/ext/fts5/test/fts5integrity.test +++ b/ext/fts5/test/fts5integrity.test @@ -379,9 +379,6 @@ do_execsql_test 12.2 { db close sqlite3 db test.db -readonly 1 -explain_i { - PRAGMA integrity_check - } do_execsql_test 12.3 { PRAGMA integrity_check } {ok} diff --git a/manifest b/manifest index 8abfffe086..916a00bf89 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sTEMP\sINSTEAD\sOF\striggers\sso\sthat\sthey\swork\son\sTEMP\sviews.\n[forum:/forumpost/2026-02-28T23:33:04z|Forum\spost\s2026-02-28T23:33:04z]. -D 2026-03-02T15:34:16.932 +C Omit\sexplain_i\scalls\sfrom\sTCL\stest\sscripts. +D 2026-03-02T16:40:16.246 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -199,7 +199,7 @@ F ext/fts5/test/fts5first.test bfd685b96905bf541d99d8644e0a7219d1d833455a08ab64e F ext/fts5/test/fts5full.test 97d263c1072f4a560929cca31e70f65d2ae232610e17e6affcf7e979df59547b F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e F ext/fts5/test/fts5hash.test fd3e0367fbf0b0944d6936fdb22696350f57b9871069c6766251578a103e8a14 -F ext/fts5/test/fts5integrity.test c423ce16fd1ccadcac7fc22f794226b2bb00f5a187c0ab1d9f8502521b1bae05 +F ext/fts5/test/fts5integrity.test 613efcebe16b2d7a4096f03bcfb164f79a000b3354420ceda4a6f3e035090789 F ext/fts5/test/fts5integrity2.test 4c3636615c0201232c44a8105d5cb14fd5499fd0ee3014d7ffd7e83aac76ece8 F ext/fts5/test/fts5interrupt.test af7834ac6c2e71c05aea42d92f272eef3655e89b7a14a5620a2cd9de35e2e8ea F ext/fts5/test/fts5join.test 48b7ed36956948c5b8456c8bcaa5b087808d99000675918a43c4f51a925f1514 @@ -908,7 +908,7 @@ F test/bestindex7.test f094c669a6400777f4d2ddc3ed28e39169f1adb5be3d59b55f22ccf8c F test/bestindex8.test 4d8b1e8f30a7f405988ce4dbcc2b95c0775f0bed9ec08e0291a07e2f35f7e653 F test/bestindex9.test 1a4b93db117fd8abe74ae9be982f86aa72f01e60cd4ac541e6ede39673a451a0 F test/bestindexA.test e1b5def6b190797cacf008e6815ffb78fb30261999030d60a728d572eef44c7f -F test/bestindexB.test 328b97b69cd1a20928d5997f9ecb04d2e00f1d18e19ab27f9e9adb44d7bc51ce +F test/bestindexB.test 14db2f66ec9cc5064a74996033b74e5eec0fd2f3a327fbe34ff18de67e9d2671 F test/bestindexC.test 95b4a527b1a5d07951d731604a6d4cf7e5a806b39cea0e7819d4c9667e11c3fc F test/bestindexD.test 6a8f6f84990bcf17dfa59652a1f935beddb7afd96f8302830fbc86b0a13df3c3 F test/bestindexE.test 297f3ea8500a8f3c17d6f78e55bdfee089064c6144ee84a110bd005a03338f49 @@ -1940,7 +1940,7 @@ F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7 F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c F test/vacuum6.test b137b04bf3392d3f5c3b8fda0ce85a6775a70ca112f6559f74ff52dc9ce042fd F test/vacuummem.test 4b30f5b95a9ff86e9d5c20741e50a898b2dc10b0962a3211571eb165357003fb -F test/values.test 0eda08a6ce6545f1ab012dff4cc72a7dd0fee2510f42444136bb2b2b5ed84bc0 +F test/values.test 0e037c50789ac2a308746567d07b53b2f6026c1bb3a435d1b099424600e64caf F test/valuesfault.test 2ef23ed965e3bd08e268cdc38a0d11653390ddbbe1e8e2e98d16f55edd30f6e8 F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 @@ -2188,8 +2188,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 213b1c6608af4b3e9d6e0d8de6432cc6857931427baf4beac1e0a4294e4dc6ce -R 996b11c4e53e27c110bbd4ecdaab164e +P 0596bd508f0bc548158858a1dc113af2235d02632ce8c41cd27d1029e1a7e48d +R 09fb7350cf7b99eaff61319652331acd U drh -Z b315db4b82b7c9cbeaa07c1d78d09cfe +Z ef9eec11b410335060f4678d866b0a03 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7c62954430..e72b7081fb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0596bd508f0bc548158858a1dc113af2235d02632ce8c41cd27d1029e1a7e48d +204f25c882832058c3291d4d6a0a6ac2711c081cb91b19feb2cf94a25ed61ecf diff --git a/test/bestindexB.test b/test/bestindexB.test index b50e74fee3..5850e35bdf 100644 --- a/test/bestindexB.test +++ b/test/bestindexB.test @@ -34,7 +34,7 @@ proc vtab_command {method args} { set orderby [$hdl orderby] if {[info exists ::xbestindex_sql]} { - explain_i $::xbestindex_sql + # explain_i $::xbestindex_sql set ::xbestindex_res [ execsql $::xbestindex_sql ] } diff --git a/test/values.test b/test/values.test index c3c52ceb1e..58e764ce69 100644 --- a/test/values.test +++ b/test/values.test @@ -21,9 +21,9 @@ do_execsql_test 1.0 { } -explain_i { - INSERT INTO x1(a, b, c) VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4); -} +#explain_i { +# INSERT INTO x1(a, b, c) VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4); +#} do_execsql_test 1.1.1 { INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4); } From a2fef84b19dbda47244a9fcb11416c2029502d52 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 3 Mar 2026 01:48:18 +0000 Subject: [PATCH 079/197] Expose sqlite3_bind_zeroblob() to JS/WASM, per request in [forum:e7acf225f9|forum post e7acf225f9]. This is currently missing tests and is not planned for merge until the 3.53 dev cycle starts. FossilOrigin-Name: b0c2ef6046b53b6133fed6a890d2ab5e47eeebd7b0b32849b5f69ae54a03014c --- ext/wasm/api/EXPORTED_FUNCTIONS.c-pp | 1 + ext/wasm/api/sqlite3-api-glue.c-pp.js | 2 ++ manifest | 20 +++++++++++--------- manifest.tags | 4 ++-- manifest.uuid | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.c-pp b/ext/wasm/api/EXPORTED_FUNCTIONS.c-pp index 2cdddf1e7c..a43a7b0253 100644 --- a/ext/wasm/api/EXPORTED_FUNCTIONS.c-pp +++ b/ext/wasm/api/EXPORTED_FUNCTIONS.c-pp @@ -13,6 +13,7 @@ _sqlite3_bind_parameter_index _sqlite3_bind_parameter_name _sqlite3_bind_pointer _sqlite3_bind_text +_sqlite3_bind_zeroblob _sqlite3_busy_handler _sqlite3_busy_timeout _sqlite3_cancel_auto_extension diff --git a/ext/wasm/api/sqlite3-api-glue.c-pp.js b/ext/wasm/api/sqlite3-api-glue.c-pp.js index d268331a35..a51176e9e4 100644 --- a/ext/wasm/api/sqlite3-api-glue.c-pp.js +++ b/ext/wasm/api/sqlite3-api-glue.c-pp.js @@ -98,6 +98,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ ["sqlite3_bind_parameter_name", "string", "sqlite3_stmt*", "int"], ["sqlite3_bind_pointer", "int", "sqlite3_stmt*", "int", "*", "string:static", "*"], + /* sqlite_bind_text() is hand-written */ + ["sqlite3_bind_zeroblob", "int", "sqlite3_stmt*", "int", "int"], ["sqlite3_busy_handler","int", [ "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ diff --git a/manifest b/manifest index 4dd41bd07e..b2ad103aa9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Convert\smany\ssqlite3_realloc()\scalls\sto\ssqlite3_realloc64(). -D 2026-03-02T17:11:44.720 +C Expose\ssqlite3_bind_zeroblob()\sto\sJS/WASM,\sper\srequest\sin\s[forum:e7acf225f9|forum\spost\se7acf225f9].\sThis\sis\scurrently\smissing\stests\sand\sis\snot\splanned\sfor\smerge\suntil\sthe\s3.53\sdev\scycle\sstarts. +D 2026-03-03T01:48:18.383 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -580,14 +580,14 @@ F ext/wasm/SQLTester/SQLTester.mjs 6b3c52ed36a5573ca4883176f326332a8d4c0cecf5efd F ext/wasm/SQLTester/SQLTester.run.mjs 57f2adb33f43f2784abbf8026c1bfd049d8013af1998e7dcb8b50c89ffc332e0 F ext/wasm/SQLTester/index.html 64f3435084c7d6139b08d1f2a713828a73f68de2ae6a3112cbb5980d991ba06f F ext/wasm/SQLTester/touint8array.c 2d5ece04ec1393a6a60c4bf96385bda5e1a10ad49f3038b96460fc5e5aa7e536 -F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp 7ba933e8f1290cc65459dd371c0c9a031d96bdf14d7a2244fa761d9775117b90 +F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp 6ad5ace0a16b3300e8d40d4e596eee1c773424e22d57f9b8d37cbe87a101638a F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b47244781a7e81 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js d24bd0d065f3489c8b78ddf3ead6321e5d047187a162cd503c41700e03dd1f06 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f -F ext/wasm/api/sqlite3-api-glue.c-pp.js 9b33e3ee467791dec4fd1b444b12a8545dfbb6c8b28ac651c7bdc7661a3b5a5c +F ext/wasm/api/sqlite3-api-glue.c-pp.js 7afb3da3510facafd94ce31133ec847d0d4db5b2b5e4325941803fd3bca07c16 F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c41db98a22b534c15e543cfa F ext/wasm/api/sqlite3-api-prologue.js 1fefd40ab21e3dbf46f43b6fafb07f13eb13cc157a884f7c1134caf631ddb3f2 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 @@ -2188,9 +2188,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 204f25c882832058c3291d4d6a0a6ac2711c081cb91b19feb2cf94a25ed61ecf a391f5646926787fd9a004225ea406b61d20f282c852c0282fd26cada644b601 -R fd09c97895a4cac92ff79c9e4e8d0ece -T +closed a391f5646926787fd9a004225ea406b61d20f282c852c0282fd26cada644b601 -U drh -Z f2554e3cff169f1dfd8e4679b455ef58 +P 88dce64242552e7443d9fb496f6f3ad71dc5b4a882ce21b7ef1d5ea4e26f1e61 +R dd80d3380235dbbc70003a65e9b67c1b +T *branch * wasm-zeroblob +T *sym-wasm-zeroblob * +T -sym-trunk * Cancelled\sby\sbranch. +U stephan +Z de595f7c89f8223d07abcc59c70be259 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..555993a4d4 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch wasm-zeroblob +tag wasm-zeroblob diff --git a/manifest.uuid b/manifest.uuid index 1ae350648d..ec5732b4b3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -88dce64242552e7443d9fb496f6f3ad71dc5b4a882ce21b7ef1d5ea4e26f1e61 +b0c2ef6046b53b6133fed6a890d2ab5e47eeebd7b0b32849b5f69ae54a03014c From 5c4692b6a9d50e6571c61bff14d1ea69856a6f08 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 3 Mar 2026 14:13:34 +0000 Subject: [PATCH 080/197] Add JS tests for sqlite3_bind_zeroblob(). FossilOrigin-Name: 0473eeb3cefa1d7882375e3f89d239d570649349c5a0a8ddd90b0a336a9bb493 --- ext/wasm/tester1.c-pp.js | 14 ++++++++++++-- manifest | 15 ++++++--------- manifest.uuid | 2 +- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 083b5eca44..a1e5b5c344 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -4219,13 +4219,23 @@ globalThis.sqlite3InitModule = sqlite3InitModule; }else{ log("Column metadata APIs not enabled"); } // column metadata APIs - stmt.finalize(); - stmt = null; + stmt.finalize(); stmt = null; stmt = db.prepare("select ?1").bind(new Uint8Array([97,0,98,0,99])); stmt.step(); const sv = capi.sqlite3_column_value(stmt,0); T.assert("a\0b\0c"===capi.sqlite3_value_text(sv), "Expecting NULs to have survived."); + stmt.finalize(); stmt = null; + + /* sqlite3_bind_zeroblob() (added in 3.53) */ + stmt = db.prepare("select ?1"); + T.assert( 0===capi.sqlite3_bind_zeroblob(stmt, 1, 53) ); + T.assert( stmt.step() ); + const b = stmt.get(0); + stmt.finalize(); stmt = null; + T.assert( b instanceof Uint8Array ) + .assert( 53===b.length ); + }finally{ if(stmt) stmt.finalize(); db.close(); diff --git a/manifest b/manifest index b2ad103aa9..4fbfe4caee 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expose\ssqlite3_bind_zeroblob()\sto\sJS/WASM,\sper\srequest\sin\s[forum:e7acf225f9|forum\spost\se7acf225f9].\sThis\sis\scurrently\smissing\stests\sand\sis\snot\splanned\sfor\smerge\suntil\sthe\s3.53\sdev\scycle\sstarts. -D 2026-03-03T01:48:18.383 +C Add\sJS\stests\sfor\ssqlite3_bind_zeroblob(). +D 2026-03-03T14:13:34.724 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -641,7 +641,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c986e48af7d3d720fcd244 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb -F ext/wasm/tester1.c-pp.js 6b946cd6d4da130dbae4a401057716d27117ca02cad2ea8c29ae9c46c675d618 +F ext/wasm/tester1.c-pp.js 1c81b2b3f6c02adbb50ff48e07645946cd066cd215c0b8b500574fefecacf5c8 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88 F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2188,11 +2188,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 88dce64242552e7443d9fb496f6f3ad71dc5b4a882ce21b7ef1d5ea4e26f1e61 -R dd80d3380235dbbc70003a65e9b67c1b -T *branch * wasm-zeroblob -T *sym-wasm-zeroblob * -T -sym-trunk * Cancelled\sby\sbranch. +P b0c2ef6046b53b6133fed6a890d2ab5e47eeebd7b0b32849b5f69ae54a03014c +R ffd7065f0f9a8f57d4b7a6bb8200acf1 U stephan -Z de595f7c89f8223d07abcc59c70be259 +Z 4020d227612622b2996a6b1921359e48 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ec5732b4b3..95fe501b89 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b0c2ef6046b53b6133fed6a890d2ab5e47eeebd7b0b32849b5f69ae54a03014c +0473eeb3cefa1d7882375e3f89d239d570649349c5a0a8ddd90b0a336a9bb493 From fe57e14b49f9189b56da8233ab3415ce5ff6b1ff Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 3 Mar 2026 17:34:01 +0000 Subject: [PATCH 081/197] Avoid an obscure race condition between a checkpointer and a writer wrapping around to the start of the wal file. FossilOrigin-Name: 053bd3930f827156fd67ea4546a36227cffbb6f8bada3b5d1a7cf5f1867ac624 --- manifest | 19 ++++--- manifest.tags | 4 +- manifest.uuid | 2 +- src/wal.c | 131 ++++++++++++++++++++++++------------------- test/walrestart.test | 79 ++++++++++++++++++++++++++ 5 files changed, 166 insertions(+), 69 deletions(-) create mode 100644 test/walrestart.test diff --git a/manifest b/manifest index 4dd41bd07e..8c22fb57d4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Convert\smany\ssqlite3_realloc()\scalls\sto\ssqlite3_realloc64(). -D 2026-03-02T17:11:44.720 +C Avoid\san\sobscure\srace\scondition\sbetween\sa\scheckpointer\sand\sa\swriter\swrapping\saround\sto\sthe\sstart\sof\sthe\swal\sfile. +D 2026-03-03T17:34:01.231 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -808,7 +808,7 @@ F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 F src/vtab.c 5437ce986db2f70e639ce8a3fe68dcdfe64b0f1abb14eaebecdabd5e0766cc68 F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab -F src/wal.c 505a98fbc599a971d92cb90371cf54546c404cd61e04fd093e7b0c8ff978f9b6 +F src/wal.c 47e0d493ee7e5a9942467bf992f156d407e432af2b80bf0759a0b38d65a6505c F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 F src/where.c 9f09ee7b260010138d5f9fb5f195b98051119eae3096a99d72ff16c83230f4af @@ -2004,6 +2004,7 @@ F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03 F test/walpersist.test 8d78a1ec91299163451417b451a2bac3481f8eb9f455b1ca507a6625c927ca6e F test/walprotocol.test 1b3f922125e341703f6e946d77fdc564d38fb3e07a9385cfdc6c99cac1ecf878 F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131 +F test/walrestart.test e5caacd7fc0a13055a5f567f11afd99724ab827d8c0bd0670958ffedb6325b8f F test/walro.test 78a84bc0fdae1385c06b017215c426b6845734d6a5a3ac75c918dd9b801b1b9d F test/walro2.test 33955a6fd874dd9724005e17f77fef89d334b3171454a1256fe4941a96766cdc F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68 @@ -2188,9 +2189,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 204f25c882832058c3291d4d6a0a6ac2711c081cb91b19feb2cf94a25ed61ecf a391f5646926787fd9a004225ea406b61d20f282c852c0282fd26cada644b601 -R fd09c97895a4cac92ff79c9e4e8d0ece -T +closed a391f5646926787fd9a004225ea406b61d20f282c852c0282fd26cada644b601 -U drh -Z f2554e3cff169f1dfd8e4679b455ef58 +P 88dce64242552e7443d9fb496f6f3ad71dc5b4a882ce21b7ef1d5ea4e26f1e61 +R 7123c2f78c4a83a2b9a28313122c346f +T *branch * wal-restart-fix +T *sym-wal-restart-fix * +T -sym-trunk * +U dan +Z f02d11aee2845419e316ead57cf24834 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..1061d19237 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch wal-restart-fix +tag wal-restart-fix diff --git a/manifest.uuid b/manifest.uuid index 1ae350648d..6f85c8ff9f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -88dce64242552e7443d9fb496f6f3ad71dc5b4a882ce21b7ef1d5ea4e26f1e61 +053bd3930f827156fd67ea4546a36227cffbb6f8bada3b5d1a7cf5f1867ac624 diff --git a/src/wal.c b/src/wal.c index 0698521586..54b72cc562 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2254,68 +2254,82 @@ static int walCheckpoint( && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK ){ u32 nBackfill = pInfo->nBackfill; - pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT; - - /* Sync the WAL to disk */ - rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); - - /* If the database may grow as a result of this checkpoint, hint - ** about the eventual size of the db file to the VFS layer. - */ - if( rc==SQLITE_OK ){ - i64 nReq = ((i64)mxPage * szPage); - i64 nSize; /* Current size of database file */ - sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0); - rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); - if( rc==SQLITE_OK && nSizehdr.mxFrame*szPage)pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); + WalIndexHdr *pLive = (WalIndexHdr*)walIndexHdr(pWal); + + /* Now that read-lock slot 0 is locked, check that the wal has not been + ** wrapped since the header was read for this checkpoint. If it was, then + ** there was no work to do anyway. In this case the + ** (pInfo->nBackfillhdr.mxFrame) test above only passed because + ** pInfo->nBackfill had already been set to 0 by the writer that wrapped + ** the wal file. It would also be dangerous to proceed, as there may be + ** fewer than pWal->hdr.mxFrame valid frames in the wal file. */ + if( 0==memcmp(pLive->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) ){ + + pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT; + + /* Sync the WAL to disk */ + rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); + + /* If the database may grow as a result of this checkpoint, hint + ** about the eventual size of the db file to the VFS layer. + */ + if( rc==SQLITE_OK ){ + i64 nReq = ((i64)mxPage * szPage); + i64 nSize; /* Current size of database file */ + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0); + rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); + if( rc==SQLITE_OK && nSizehdr.mxFrame*szPage)pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); + } } + } - - } - - /* Iterate through the contents of the WAL, copying data to the db file */ - while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ - i64 iOffset; - assert( walFramePgno(pWal, iFrame)==iDbpage ); - SEH_INJECT_FAULT; - if( AtomicLoad(&db->u1.isInterrupted) ){ - rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; - break; - } - if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ - continue; - } - iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; - /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ - rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - iOffset = (iDbpage-1)*(i64)szPage; - testcase( IS_BIG_INT(iOffset) ); - rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - } - sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0); - - /* If work was actually accomplished... */ - if( rc==SQLITE_OK ){ - if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ - i64 szDb = pWal->hdr.nPage*(i64)szPage; - testcase( IS_BIG_INT(szDb) ); - rc = sqlite3OsTruncate(pWal->pDbFd, szDb); - if( rc==SQLITE_OK ){ - rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); + + /* Iterate through the contents of the WAL, copying data to the + ** db file */ + while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ + i64 iOffset; + assert( walFramePgno(pWal, iFrame)==iDbpage ); + SEH_INJECT_FAULT; + if( AtomicLoad(&db->u1.isInterrupted) ){ + rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; + break; } + if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ + continue; + } + iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; + /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ + rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; + iOffset = (iDbpage-1)*(i64)szPage; + testcase( IS_BIG_INT(iOffset) ); + rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; } + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0); + + /* If work was actually accomplished... */ if( rc==SQLITE_OK ){ - AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT; + if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ + i64 szDb = pWal->hdr.nPage*(i64)szPage; + testcase( IS_BIG_INT(szDb) ); + rc = sqlite3OsTruncate(pWal->pDbFd, szDb); + if( rc==SQLITE_OK ){ + rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); + } + } + if( rc==SQLITE_OK ){ + AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT; + } } } @@ -4362,9 +4376,10 @@ int sqlite3WalCheckpoint( sqlite3OsUnfetch(pWal->pDbFd, 0, 0); } } - + /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ + sqlite3FaultSim(660); if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; }else if( eMode2!=SQLITE_CHECKPOINT_NOOP ){ diff --git a/test/walrestart.test b/test/walrestart.test new file mode 100644 index 0000000000..f7fe9a676c --- /dev/null +++ b/test/walrestart.test @@ -0,0 +1,79 @@ +# 2026-03-03 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing a race condition in WAL restart. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +if {$::tcl_platform(platform) ne "unix"} { + # This test only works on unix + finish_test + return +} +set testprefix walrestart + +db close +sqlite3_shutdown + +proc faultsim {n} { return 0 } +sqlite3_test_control_fault_install faultsim + +# Populate database. Create a large wal file and checkpoint it. +# +reset_db +do_execsql_test 1.0 { + PRAGMA auto_vacuum = 0; + PRAGMA journal_mode = wal; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<20 + ) + INSERT INTO t1 SELECT NULL, randomblob(600) FROM s; + CREATE INDEX i1 ON t1(b); + PRAGMA wal_checkpoint; +} {wal 0 49 49} +do_execsql_test 1.1 { + UPDATE t1 SET b=randomblob(600); + PRAGMA wal_checkpoint; +} {0 45 45} + +# We have a completely checkpointed wal file on disk. mxFrame=$large, +# nBackfill=$large. Do another checkpoint with [db]. This time, after [db] +# reads mxFrame but before it reads nBackfill, write to the db such +# that 0 < mxFrame < large. +# +proc faultsim {n} { + if {$n==660} { + db2 eval { UPDATE t1 SET b=randomblob(600) WHERE a<5 } + } + return 0 +} +sqlite3 db2 test.db +do_execsql_test 1.3 { + PRAGMA wal_checkpoint; +} {0 45 0} + +# Now write another big update to the wal file and checkpoint it. +# +do_execsql_test -db db2 1.3 { + UPDATE t1 SET b=randomblob(600); +} +proc faultsim {n} { return 0 } +do_execsql_test 1.4 { + PRAGMA wal_checkpoint; +} {0 58 58} + +do_catchsql_test 1.5 { + PRAGMA integrity_check +} {0 ok} + +finish_test From bb80d688acfdd33706f6f7a773fbf8960aeb112b Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 3 Mar 2026 18:21:22 +0000 Subject: [PATCH 082/197] Minor tweaks to the previous, for testability. FossilOrigin-Name: decb69015457b4f70cf574aeef87d40f9de60b94965f4a915e8d0cd7559ef2ae --- manifest | 19 ++++++++----------- manifest.uuid | 2 +- src/wal.c | 4 ++-- test/walrestart.test | 2 +- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 8c22fb57d4..11d486ea92 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\san\sobscure\srace\scondition\sbetween\sa\scheckpointer\sand\sa\swriter\swrapping\saround\sto\sthe\sstart\sof\sthe\swal\sfile. -D 2026-03-03T17:34:01.231 +C Minor\stweaks\sto\sthe\sprevious,\sfor\stestability. +D 2026-03-03T18:21:22.946 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -808,7 +808,7 @@ F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 F src/vtab.c 5437ce986db2f70e639ce8a3fe68dcdfe64b0f1abb14eaebecdabd5e0766cc68 F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab -F src/wal.c 47e0d493ee7e5a9942467bf992f156d407e432af2b80bf0759a0b38d65a6505c +F src/wal.c 88d94fd15a75f6eda831fa32d1148a267ea37bf0a4b69829a73dfde06244b08f F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 F src/where.c 9f09ee7b260010138d5f9fb5f195b98051119eae3096a99d72ff16c83230f4af @@ -2004,7 +2004,7 @@ F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03 F test/walpersist.test 8d78a1ec91299163451417b451a2bac3481f8eb9f455b1ca507a6625c927ca6e F test/walprotocol.test 1b3f922125e341703f6e946d77fdc564d38fb3e07a9385cfdc6c99cac1ecf878 F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131 -F test/walrestart.test e5caacd7fc0a13055a5f567f11afd99724ab827d8c0bd0670958ffedb6325b8f +F test/walrestart.test 3e5eeae4fa3e4f0bf06119586723a5910a55a5e8594c127ee8c2abc996f4f0bb F test/walro.test 78a84bc0fdae1385c06b017215c426b6845734d6a5a3ac75c918dd9b801b1b9d F test/walro2.test 33955a6fd874dd9724005e17f77fef89d334b3171454a1256fe4941a96766cdc F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68 @@ -2189,11 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 88dce64242552e7443d9fb496f6f3ad71dc5b4a882ce21b7ef1d5ea4e26f1e61 -R 7123c2f78c4a83a2b9a28313122c346f -T *branch * wal-restart-fix -T *sym-wal-restart-fix * -T -sym-trunk * -U dan -Z f02d11aee2845419e316ead57cf24834 +P 053bd3930f827156fd67ea4546a36227cffbb6f8bada3b5d1a7cf5f1867ac624 +R 1e139d97b47e05b58d0b2ca5e08e6ef9 +U drh +Z 99ed9b0d5ac817bdb1642f3f701fad1c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 6f85c8ff9f..9f116798dd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -053bd3930f827156fd67ea4546a36227cffbb6f8bada3b5d1a7cf5f1867ac624 +decb69015457b4f70cf574aeef87d40f9de60b94965f4a915e8d0cd7559ef2ae diff --git a/src/wal.c b/src/wal.c index 54b72cc562..7f7bee6262 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2263,8 +2263,8 @@ static int walCheckpoint( ** pInfo->nBackfill had already been set to 0 by the writer that wrapped ** the wal file. It would also be dangerous to proceed, as there may be ** fewer than pWal->hdr.mxFrame valid frames in the wal file. */ - if( 0==memcmp(pLive->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) ){ - + int bChg = memcmp(pLive->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)); + if( 0==bChg ){ pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT; /* Sync the WAL to disk */ diff --git a/test/walrestart.test b/test/walrestart.test index f7fe9a676c..d8d963f12d 100644 --- a/test/walrestart.test +++ b/test/walrestart.test @@ -58,7 +58,7 @@ proc faultsim {n} { return 0 } sqlite3 db2 test.db -do_execsql_test 1.3 { +do_execsql_test 1.2 { PRAGMA wal_checkpoint; } {0 45 0} From 8ba2a38363b2a1065d156b46953b1b75b4b15902 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 3 Mar 2026 18:34:38 +0000 Subject: [PATCH 083/197] Do not run test script walrestart.test with the "memsubsys1" permutation. FossilOrigin-Name: 703cbb0f760515eac1e6f72a5e5cd928258c71378e4a976082b6518c90128135 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/walrestart.test | 8 ++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 11d486ea92..d9c8c6fae9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\stweaks\sto\sthe\sprevious,\sfor\stestability. -D 2026-03-03T18:21:22.946 +C Do\snot\srun\stest\sscript\swalrestart.test\swith\sthe\s"memsubsys1"\spermutation. +D 2026-03-03T18:34:38.064 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -2004,7 +2004,7 @@ F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03 F test/walpersist.test 8d78a1ec91299163451417b451a2bac3481f8eb9f455b1ca507a6625c927ca6e F test/walprotocol.test 1b3f922125e341703f6e946d77fdc564d38fb3e07a9385cfdc6c99cac1ecf878 F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131 -F test/walrestart.test 3e5eeae4fa3e4f0bf06119586723a5910a55a5e8594c127ee8c2abc996f4f0bb +F test/walrestart.test 3b0a9198ad2eb9f716d8f3846b133ba9f4619fb56decb1e67bba27743c766289 F test/walro.test 78a84bc0fdae1385c06b017215c426b6845734d6a5a3ac75c918dd9b801b1b9d F test/walro2.test 33955a6fd874dd9724005e17f77fef89d334b3171454a1256fe4941a96766cdc F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 053bd3930f827156fd67ea4546a36227cffbb6f8bada3b5d1a7cf5f1867ac624 -R 1e139d97b47e05b58d0b2ca5e08e6ef9 -U drh -Z 99ed9b0d5ac817bdb1642f3f701fad1c +P decb69015457b4f70cf574aeef87d40f9de60b94965f4a915e8d0cd7559ef2ae +R 081029f3feecf24cb4be31bd4056634e +U dan +Z 6e3cc1dc135fda8b3b63884b6a3aae0a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9f116798dd..f688381a36 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -decb69015457b4f70cf574aeef87d40f9de60b94965f4a915e8d0cd7559ef2ae +703cbb0f760515eac1e6f72a5e5cd928258c71378e4a976082b6518c90128135 diff --git a/test/walrestart.test b/test/walrestart.test index d8d963f12d..4274b2e33c 100644 --- a/test/walrestart.test +++ b/test/walrestart.test @@ -21,6 +21,14 @@ if {$::tcl_platform(platform) ne "unix"} { } set testprefix walrestart +if {[permutation]=="memsubsys1"} { + # memsubsys1 configures a very small page-cache, which causes different + # numbers of frames to be written to the wal file for some transactions, + # which causes some of the tests in this file to fail. + finish_test + return +} + db close sqlite3_shutdown From e2309eebd74193efe65014896ec264a743026810 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 3 Mar 2026 21:07:46 +0000 Subject: [PATCH 084/197] Implementations of WebLock-based opfs::xLock() and xUnlock(). Still completely untested and not yet integrated into the build. FossilOrigin-Name: 3343e3aabe465f4ab91dd148dfc5a60346e9afb560c10d1f92aeae98763ec3ce --- ext/wasm/api/sqlite3-opfs-async-proxy.js | 45 ++++++++++++++++++++-- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 48 ++++++++++++++++++------ manifest | 14 +++---- manifest.uuid | 2 +- 4 files changed, 86 insertions(+), 23 deletions(-) diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.js b/ext/wasm/api/sqlite3-opfs-async-proxy.js index 79fc47393e..ede2bc7cd4 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.js @@ -318,7 +318,7 @@ const installAsyncProxy = function(){ } log("Got",opName+"() sync handle for",fh.filenameAbs, 'in',performance.now() - t,'ms'); - if(!fh.xLock){ + if(!fh.xLock && !state.lock/*set by opfs-wl*/){ __implicitLocks.add(fh.fid); log("Acquired implicit lock for",opName+"()",fh.fid,fh.filenameAbs); } @@ -703,6 +703,39 @@ const installAsyncProxy = function(){ return state.s11n; }/*initS11n()*/; + /** + Starts a new WebLock request. + */ + const handleLockRequest = async function(){ + const args = state.s11n.deserialize(true) + || toss("Expecting a filename argument from the proxy xLock()"); + const view = state.sabOPView; + const slock = state.lock; + const lockType = Atomics.load(view, slock.type); + + await navigator.locks.request('sqlite3-vfs-opfs:'+args[0], { + mode: (lockType===state.sq3Codes.SQLITE_LOCK_EXCLUSIVE) + ? 'exclusive' : 'shared' + }, async (wl)=>{ + /** + A. Tell the C-side we have the browser lock. We use the same + handshake slot, but a specific 'Granted' value. + */ + Atomics.store(view, slock.atomicsHandshake, 2); + Atomics.notify(view, slock.atomicsHandshake); + /** + B. Sit here and keep the lock room occupied until the + Receptionist receives 'unlockControl'. + */ + while( 1!==Atomics.load(view, slock.atomicsHandshake) ){ + Atomics.wait(view. slock.atomicsHandshake, 2); + } + /* C. Reset the handshake slot. */ + Atomics.store(view, slock.atomicsHandshake, 0); + Atomics.notify(view, lock.atomicsHandshake); + }); + }; + const waitLoop = async function f(){ const opHandlers = Object.create(null); for(let k of Object.keys(state.opIds)){ @@ -713,10 +746,11 @@ const installAsyncProxy = function(){ o.key = k; o.f = vi; } + const opIds = state.opIds; while(!flagAsyncShutdown){ try { if('not-equal'!==Atomics.wait( - state.sabOPView, state.opIds.whichOp, 0, state.asyncIdleWaitTime + state.sabOPView, opIds.whichOp, 0, state.asyncIdleWaitTime )){ /* Maintenance note: we compare against 'not-equal' because @@ -736,8 +770,11 @@ const installAsyncProxy = function(){ await releaseImplicitLocks(); continue; } - const opId = Atomics.load(state.sabOPView, state.opIds.whichOp); - Atomics.store(state.sabOPView, state.opIds.whichOp, 0); + const opId = Atomics.exchange(state.sabOPView, opIds.whichOp, 0); + if( opId===opIds.lockControl ){ + handleLockRequest(); + continue; + } const hnd = opHandlers[opId] ?? toss("No waitLoop handler for whichOp #",opId); const args = state.s11n.deserialize( true /* clear s11n to keep the caller from confusing this with diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 9fe09269cf..99e176c396 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -372,7 +372,6 @@ const installOpfsVfs = function callee(options){ state.opIds.xWrite = i++; state.opIds.mkdir = i++; state.opIds.lockControl = i++ /* we signal the intent to lock here */; - state.opIds.lockType /** Internal signals which are used only during development and testing via the dev console. */ state.opIds['opfs-async-metrics'] = i++; @@ -384,8 +383,8 @@ const installOpfsVfs = function callee(options){ /* Slots for submitting the lock type and receiving its acknowledgement. */ state.lock = nu({ - type: i++, - atomicsHandshake: i++ + type: i++ /* SQLITE_LOCK_xyz value */, + atomicsHandshake: i++ /* 1=release, 2=granted */ }); state.sabOP = new SharedArrayBuffer( i * 4/* ==sizeof int32, noting that Atomics.wait() and friends @@ -425,7 +424,12 @@ const installOpfsVfs = function callee(options){ 'SQLITE_OPEN_CREATE', 'SQLITE_OPEN_DELETEONCLOSE', 'SQLITE_OPEN_MAIN_DB', - 'SQLITE_OPEN_READONLY' + 'SQLITE_OPEN_READONLY', + 'SQLITE_LOCK_NONE', + 'SQLITE_LOCK_SHARED', + 'SQLITE_LOCK_RESERVED', + 'SQLITE_LOCK_PENDING', + 'SQLITE_LOCK_EXCLUSIVE' ].forEach((k)=>{ if(undefined === (state.sq3Codes[k] = capi[k])){ toss("Maintenance required: not found:",k); @@ -787,7 +791,7 @@ const installOpfsVfs = function callee(options){ mTimeEnd(); return rc; }, - xLock: function(pFile,lockType){ + xLock: function(pFile, lockType){ mTimeStart('xLock'); const f = __openFiles[pFile]; let rc = 0; @@ -796,8 +800,23 @@ const installOpfsVfs = function callee(options){ type. If no lock is active, have the async counterpart lock the file. */ if( !f.lockType ) { - rc = opRun('xLock', pFile, lockType); - if( 0===rc ) f.lockType = lockType; + try{ + const view = state.sabOPView; + /* We need to pass pFile's name through so that the other + side can create the WebLock name. */ + state.s11n.serialize(f.filename) + Atomics.store(view, state.lock.type, lockType); + Atomics.store(view, state.opIds.whichOp, state.opIds.lockControl); + Atomics.notify(state.sabOPView, state.opIds.whichOp) + while('not-equal'!==Atomics.wait(view, state.lock.atomicsHandshake, 0)){ + /* Loop is a workaround for environment-specific quirks. See + notes in similar loops. */ + } + f.lockType = lockType; + }catch(e){ + error("xLock(",arguments,") failed", e, f); + rc = capi.SQLITE_IOERR_LOCK; + } }else{ f.lockType = lockType; } @@ -842,9 +861,16 @@ const installOpfsVfs = function callee(options){ mTimeStart('xUnlock'); const f = __openFiles[pFile]; let rc = 0; - if( capi.SQLITE_LOCK_NONE === lockType - && f.lockType ){ - rc = opRun('xUnlock', pFile, lockType); + if( lockType < f.lockType ){ + try{ + const view = state.sabOPView; + Atomics.store(view, state.lock.atomicsHandshake, 1); + Atomics.notify(view, state.lock.atomicsHandshake); + Atomics.wait(view, state.lock.atomicsHandshake, 1); + }catch(e){ + error("xUnlock(",pFile,lockType,") failed",e, f); + rc = capi.SQLITE_IOERR_LOCK; + } } if( 0===rc ) f.lockType = lockType; mTimeEnd(); @@ -932,7 +958,7 @@ const installOpfsVfs = function callee(options){ } const fh = Object.create(null); fh.fid = pFile; - fh.filename = zName; + fh.filename = wasm.cstrToJs(zName); fh.sab = new SharedArrayBuffer(state.fileBufferSize); fh.flags = flags; fh.readOnly = !(capi.SQLITE_OPEN_CREATE & flags) diff --git a/manifest b/manifest index 7e05ddc666..1ef5d804a8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\strunk\sinto\sthe\sopfs-wl\sbranch. -D 2026-03-03T18:34:59.705 +C Implementations\sof\sWebLock-based\sopfs::xLock()\sand\sxUnlock().\sStill\scompletely\suntested\sand\snot\syet\sintegrated\sinto\sthe\sbuild. +D 2026-03-03T21:07:46.412 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -592,11 +592,11 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 1fefd40ab21e3dbf46f43b6fafb07f13eb13cc157a884f7c1134caf631ddb3f2 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.js 92d6d327a862f1627ff3e88e60fdfea9def06ad539d98929ba46490e64372736 +F ext/wasm/api/sqlite3-opfs-async-proxy.js 912ddb17627e933eb9596d393227f7ea47b1136fc2fb0d957d9979e71de59e81 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 38484644c21b21b97f60979dddd620e47bdba628bde4ae62b6ce8859870e4f85 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js c3e453a5736ee1bb9b08247c6e97c1433933a320c7548bedd20481eae7922a48 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 372f18ae909bafd7167b70051935832e3107ede72aaeccbf5c042db7ba791912 88dce64242552e7443d9fb496f6f3ad71dc5b4a882ce21b7ef1d5ea4e26f1e61 -R 75fb07a85007c6410c69c66cd4391b75 +P 81bc4b3b6abc19f98d1f3b1065c4b39a42620a0d7abebe98605dca62dd2d6f9a +R f9d18b4e8da91823211b005773e17736 U stephan -Z 42a2789071a18d2bcb63e8ba8c976a45 +Z e389fe2e9ad12fa6369004db9e3f215f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cb69ee9652..976e29a881 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -81bc4b3b6abc19f98d1f3b1065c4b39a42620a0d7abebe98605dca62dd2d6f9a +3343e3aabe465f4ab91dd148dfc5a60346e9afb560c10d1f92aeae98763ec3ce From 0b7b802d8331cda0f5d9ee4714de078d1c4c3eaa Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 3 Mar 2026 21:46:44 +0000 Subject: [PATCH 085/197] Add a missing reset of the lock handshake SharedArrayBuffer slot. FossilOrigin-Name: 5910ed7ac843aa1fdb103ddcfaf6270d12cb39199205fc0b9f721fbf7fa2f851 --- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 1 + manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 99e176c396..0184bd480e 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -805,6 +805,7 @@ const installOpfsVfs = function callee(options){ /* We need to pass pFile's name through so that the other side can create the WebLock name. */ state.s11n.serialize(f.filename) + Atomics.store(view, state.lock.atomicsHandshake, 0); Atomics.store(view, state.lock.type, lockType); Atomics.store(view, state.opIds.whichOp, state.opIds.lockControl); Atomics.notify(state.sabOPView, state.opIds.whichOp) diff --git a/manifest b/manifest index 1ef5d804a8..b8efc4b0b2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Implementations\sof\sWebLock-based\sopfs::xLock()\sand\sxUnlock().\sStill\scompletely\suntested\sand\snot\syet\sintegrated\sinto\sthe\sbuild. -D 2026-03-03T21:07:46.412 +C Add\sa\smissing\sreset\sof\sthe\slock\shandshake\sSharedArrayBuffer\sslot. +D 2026-03-03T21:46:44.640 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -596,7 +596,7 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.js 912ddb17627e933eb9596d393227f7ea47b11 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js c3e453a5736ee1bb9b08247c6e97c1433933a320c7548bedd20481eae7922a48 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js deea0f903e8265f58fe57315c35f62170fd65d4730bece7978772c28cead1402 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 81bc4b3b6abc19f98d1f3b1065c4b39a42620a0d7abebe98605dca62dd2d6f9a -R f9d18b4e8da91823211b005773e17736 +P 3343e3aabe465f4ab91dd148dfc5a60346e9afb560c10d1f92aeae98763ec3ce +R f490861a3a61c6b12505aa6e9bec9268 U stephan -Z e389fe2e9ad12fa6369004db9e3f215f +Z 0dd9a22951092896d0ba74d53d905c49 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 976e29a881..757a353e6f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3343e3aabe465f4ab91dd148dfc5a60346e9afb560c10d1f92aeae98763ec3ce +5910ed7ac843aa1fdb103ddcfaf6270d12cb39199205fc0b9f721fbf7fa2f851 From a2d3a54f80b890a25e82877bcf2b612a64919255 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 3 Mar 2026 23:43:40 +0000 Subject: [PATCH 086/197] An initial attempt to plugging opfs-wl into the build but its initial handshake with the async half collides with the opfs VFS's handshake, causing bootstrapping to fail miserably. We'll need to either devise a handshake which can differentiate between the two instances or we'll need to preprocess sqlite3-opfs-async-proxy into two copies. Move the (now) three copies of some common code shared by the opfs pieces into a preprocessor #include. FossilOrigin-Name: 1e0b72631aecb0bb72f4089116da221e6c4abf962db589de08132cd52c2be0e2 --- ext/wasm/GNUmakefile | 11 +- ext/wasm/api/opfs-common.c-pp.js | 200 ++++++++++++++ ext/wasm/api/post-js-header.js | 1 + ext/wasm/api/sqlite3-api-prologue.js | 3 +- ...xy.js => sqlite3-opfs-async-proxy.c-pp.js} | 101 +------ ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 251 +++--------------- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 170 +----------- ext/wasm/mkwasmbuilds.c | 7 +- ext/wasm/tests/opfs/concurrency/worker.js | 9 +- manifest | 27 +- manifest.uuid | 2 +- 11 files changed, 274 insertions(+), 508 deletions(-) create mode 100644 ext/wasm/api/opfs-common.c-pp.js rename ext/wasm/api/{sqlite3-opfs-async-proxy.js => sqlite3-opfs-async-proxy.c-pp.js} (88%) diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index dc3c2d2555..371bec6bdd 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -913,6 +913,7 @@ endif sqlite3-api.jses += $(dir.api)/sqlite3-vfs-kvvfs.c-pp.js sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js +#sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-wl.c-pp.js # Parallel builds can fail if $(sqlite3-license-version.js) is not # created early enough, so make all files in $(sqlite-api.jses) except @@ -1182,13 +1183,13 @@ all: demos ####################################################################### # -# "SOAP" is a static file which is not part of the amalgamation but -# gets copied into the build output folder and into each of the fiddle -# builds. +# "SOAP" is not part of the amalgamation but gets copied into the +# build output folder and into each of the fiddle builds. # sqlite3.ext.js += $(dir.dout)/sqlite3-opfs-async-proxy.js -$(dir.dout)/sqlite3-opfs-async-proxy.js: $(dir.api)/sqlite3-opfs-async-proxy.js - @$(call b.cp,@,$<,$@) +$(eval $(call b.c-pp.target,soap,\ + $(dir.api)/sqlite3-opfs-async-proxy.c-pp.js,\ + $(dir.dout)/sqlite3-opfs-async-proxy.js)) # # Add a dep of $(sqlite3.ext.js) on every individual build's JS file. diff --git a/ext/wasm/api/opfs-common.c-pp.js b/ext/wasm/api/opfs-common.c-pp.js new file mode 100644 index 0000000000..1a7818927a --- /dev/null +++ b/ext/wasm/api/opfs-common.c-pp.js @@ -0,0 +1,200 @@ +//#if nope +/** + This file is for preprocessor #include into the "opfs" and + "opfs-wl" impls, as well as their async-proxy part. +*/ +//#endif + +//#if not defined opfs-async-proxy +/** + TODO: move the sqlite3.opfs (private/internal) namespace object + init from sqlite3-vfs-opfs*.js into here. That namespace gets + removed from the sqlite3 namespace in the final stages of library + bootstrapping except in test runs, where it's retained so that + tests can clean up OPFS so their test cases work (the down-side of + them being persistent). +*/ +//#endif not defined opfs-async-proxy + +// This function won't work as-is if we #include it, but the +// missing elements have not yet been identified. +const initS11n = function(){ + /* This function is needed by the "opfs" and "opfs-wl" VFSes + and sqlite-opfs-async-proxy.js (used by those of those). */ + /** + This proxy de/serializes cross-thread function arguments and + output-pointer values via the state.sabIO SharedArrayBuffer, + using the region defined by (state.sabS11nOffset, + state.sabS11nOffset + state.sabS11nSize]. Only one dataset is + recorded at a time. + + This is not a general-purpose format. It only supports the + range of operations, and data sizes, needed by the + sqlite3_vfs and sqlite3_io_methods operations. Serialized + data are transient and this serialization algorithm may + change at any time. + + The data format can be succinctly summarized as: + + Nt...Td...D + + Where: + + - N = number of entries (1 byte) + + - t = type ID of first argument (1 byte) + + - ...T = type IDs of the 2nd and subsequent arguments (1 byte + each). + + - d = raw bytes of first argument (per-type size). + + - ...D = raw bytes of the 2nd and subsequent arguments (per-type + size). + + All types except strings have fixed sizes. Strings are stored + using their TextEncoder/TextDecoder representations. It would + arguably make more sense to store them as Int16Arrays of + their JS character values, but how best/fastest to get that + in and out of string form is an open point. Initial + experimentation with that approach did not gain us any speed. + + Historical note: this impl was initially about 1% this size by + using using JSON.stringify/parse(), but using fit-to-purpose + serialization saves considerable runtime. + */ + if(state.s11n) return state.s11n; + const textDecoder = new TextDecoder(), + textEncoder = new TextEncoder('utf-8'), + viewU8 = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize), + viewDV = new DataView(state.sabIO, state.sabS11nOffset, state.sabS11nSize); + state.s11n = Object.create(null); + /* Only arguments and return values of these types may be + serialized. This covers the whole range of types needed by the + sqlite3_vfs API. */ + const TypeIds = Object.create(null); + TypeIds.number = { id: 1, size: 8, getter: 'getFloat64', setter: 'setFloat64' }; + TypeIds.bigint = { id: 2, size: 8, getter: 'getBigInt64', setter: 'setBigInt64' }; + TypeIds.boolean = { id: 3, size: 4, getter: 'getInt32', setter: 'setInt32' }; + TypeIds.string = { id: 4 }; + + const getTypeId = (v)=>( + TypeIds[typeof v] + || toss("Maintenance required: this value type cannot be serialized.",v) + ); + const getTypeIdById = (tid)=>{ + switch(tid){ + case TypeIds.number.id: return TypeIds.number; + case TypeIds.bigint.id: return TypeIds.bigint; + case TypeIds.boolean.id: return TypeIds.boolean; + case TypeIds.string.id: return TypeIds.string; + default: toss("Invalid type ID:",tid); + } + }; + + /** + Returns an array of the deserialized state stored by the most + recent serialize() operation (from this thread or the + counterpart thread), or null if the serialization buffer is + empty. If passed a truthy argument, the serialization buffer + is cleared after deserialization. + */ + state.s11n.deserialize = function(clear=false){ +//#if defined opfs-has-metrics + ++metrics.s11n.deserialize.count; +//#endif + const t = performance.now(); + const argc = viewU8[0]; + const rc = argc ? [] : null; + if(argc){ + const typeIds = []; + let offset = 1, i, n, v; + for(i = 0; i < argc; ++i, ++offset){ + typeIds.push(getTypeIdById(viewU8[offset])); + } + for(i = 0; i < argc; ++i){ + const t = typeIds[i]; + if(t.getter){ + v = viewDV[t.getter](offset, state.littleEndian); + offset += t.size; + }else{/*String*/ + n = viewDV.getInt32(offset, state.littleEndian); + offset += 4; + v = textDecoder.decode(viewU8.slice(offset, offset+n)); + offset += n; + } + rc.push(v); + } + } + if(clear) viewU8[0] = 0; + //log("deserialize:",argc, rc); +//#if defined opfs-has-metrics + metrics.s11n.deserialize.time += performance.now() - t; +//#endif + return rc; + }; + + /** + Serializes all arguments to the shared buffer for consumption + by the counterpart thread. + + This routine is only intended for serializing OPFS VFS + arguments and (in at least one special case) result values, + and the buffer is sized to be able to comfortably handle + those. + + If passed no arguments then it zeroes out the serialization + state. + */ + state.s11n.serialize = function(...args){ + const t = performance.now(); +//#if defined opfs-has-metrics + ++metrics.s11n.serialize.count; +//#endif + if(args.length){ + //log("serialize():",args); + const typeIds = []; + let i = 0, offset = 1; + viewU8[0] = args.length & 0xff /* header = # of args */; + for(; i < args.length; ++i, ++offset){ + /* Write the TypeIds.id value into the next args.length + bytes. */ + typeIds.push(getTypeId(args[i])); + viewU8[offset] = typeIds[i].id; + } + for(i = 0; i < args.length; ++i) { + /* Deserialize the following bytes based on their + corresponding TypeIds.id from the header. */ + const t = typeIds[i]; + if(t.setter){ + viewDV[t.setter](offset, args[i], state.littleEndian); + offset += t.size; + }else{/*String*/ + const s = textEncoder.encode(args[i]); + viewDV.setInt32(offset, s.byteLength, state.littleEndian); + offset += 4; + viewU8.set(s, offset); + offset += s.byteLength; + } + } + //log("serialize() result:",viewU8.slice(0,offset)); + }else{ + viewU8[0] = 0; + } +//#if defined opfs-has-metrics + metrics.s11n.serialize.time += performance.now() - t; +//#endif + }; + +//#if defined opfs-async-proxy + state.s11n.storeException = state.asyncS11nExceptions + ? ((priority,e)=>{ + if(priority<=state.asyncS11nExceptions){ + state.s11n.serialize([e.name,': ',e.message].join("")); + } + }) + : ()=>{}; +//#endif + + return state.s11n; +}/*initS11n()*/; diff --git a/ext/wasm/api/post-js-header.js b/ext/wasm/api/post-js-header.js index 670051bd86..348f80ea0b 100644 --- a/ext/wasm/api/post-js-header.js +++ b/ext/wasm/api/post-js-header.js @@ -34,6 +34,7 @@ Module.runSQLite3PostLoadInit = async function( - sqlite3-vtab-helper.c-pp.js => Utilities for virtual table impls - sqlite3-vfs-opfs.c-pp.js => OPFS VFS - sqlite3-vfs-opfs-sahpool.c-pp.js => OPFS SAHPool VFS + - sqlite3-vfs-opfs-wl.c-pp.js => WebLock-using OPFS VFS - post-js-footer.js => this file's epilogue And all of that gets sandwiched between extern-pre-js.js and diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index c53acee769..3ee44d33b0 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -2002,6 +2002,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( so that we can add tests for them. */ delete sqlite3.util; delete sqlite3.StructBinder; + delete sqlite3.opfs; } return sqlite3; }; @@ -2034,7 +2035,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( */ scriptInfo: undefined }; - if( ('undefined'!==typeof sqlite3IsUnderTest/* from post-js-header.js */) ){ + if( 'undefined'!==typeof sqlite3IsUnderTest/* from post-js-header.js */ ){ sqlite3.__isUnderTest = !!sqlite3IsUnderTest; } try{ diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js similarity index 88% rename from ext/wasm/api/sqlite3-opfs-async-proxy.js rename to ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index ede2bc7cd4..294e7687be 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -603,105 +603,8 @@ const installAsyncProxy = function(){ } }/*vfsAsyncImpls*/; - const initS11n = ()=>{ - /** - ACHTUNG: this code is 100% duplicated in the other half of this - proxy! The documentation is maintained in the "synchronous half". - */ - if(state.s11n) return state.s11n; - const textDecoder = new TextDecoder(), - textEncoder = new TextEncoder('utf-8'), - viewU8 = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize), - viewDV = new DataView(state.sabIO, state.sabS11nOffset, state.sabS11nSize); - state.s11n = Object.create(null); - const TypeIds = Object.create(null); - TypeIds.number = { id: 1, size: 8, getter: 'getFloat64', setter: 'setFloat64' }; - TypeIds.bigint = { id: 2, size: 8, getter: 'getBigInt64', setter: 'setBigInt64' }; - TypeIds.boolean = { id: 3, size: 4, getter: 'getInt32', setter: 'setInt32' }; - TypeIds.string = { id: 4 }; - const getTypeId = (v)=>( - TypeIds[typeof v] - || toss("Maintenance required: this value type cannot be serialized.",v) - ); - const getTypeIdById = (tid)=>{ - switch(tid){ - case TypeIds.number.id: return TypeIds.number; - case TypeIds.bigint.id: return TypeIds.bigint; - case TypeIds.boolean.id: return TypeIds.boolean; - case TypeIds.string.id: return TypeIds.string; - default: toss("Invalid type ID:",tid); - } - }; - state.s11n.deserialize = function(clear=false){ - const argc = viewU8[0]; - const rc = argc ? [] : null; - if(argc){ - const typeIds = []; - let offset = 1, i, n, v; - for(i = 0; i < argc; ++i, ++offset){ - typeIds.push(getTypeIdById(viewU8[offset])); - } - for(i = 0; i < argc; ++i){ - const t = typeIds[i]; - if(t.getter){ - v = viewDV[t.getter](offset, state.littleEndian); - offset += t.size; - }else{/*String*/ - n = viewDV.getInt32(offset, state.littleEndian); - offset += 4; - v = textDecoder.decode(viewU8.slice(offset, offset+n)); - offset += n; - } - rc.push(v); - } - } - if(clear) viewU8[0] = 0; - //log("deserialize:",argc, rc); - return rc; - }; - state.s11n.serialize = function(...args){ - if(args.length){ - //log("serialize():",args); - const typeIds = []; - let i = 0, offset = 1; - viewU8[0] = args.length & 0xff /* header = # of args */; - for(; i < args.length; ++i, ++offset){ - /* Write the TypeIds.id value into the next args.length - bytes. */ - typeIds.push(getTypeId(args[i])); - viewU8[offset] = typeIds[i].id; - } - for(i = 0; i < args.length; ++i) { - /* Deserialize the following bytes based on their - corresponding TypeIds.id from the header. */ - const t = typeIds[i]; - if(t.setter){ - viewDV[t.setter](offset, args[i], state.littleEndian); - offset += t.size; - }else{/*String*/ - const s = textEncoder.encode(args[i]); - viewDV.setInt32(offset, s.byteLength, state.littleEndian); - offset += 4; - viewU8.set(s, offset); - offset += s.byteLength; - } - } - //log("serialize() result:",viewU8.slice(0,offset)); - }else{ - viewU8[0] = 0; - } - }; - - state.s11n.storeException = state.asyncS11nExceptions - ? ((priority,e)=>{ - if(priority<=state.asyncS11nExceptions){ - state.s11n.serialize([e.name,': ',e.message].join("")); - } - }) - : ()=>{}; - - return state.s11n; - }/*initS11n()*/; +//#define opfs-async-proxy +//#include api/opfs-common.c-pp.js /** Starts a new WebLock request. diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 0184bd480e..dfa44af5e1 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -11,54 +11,51 @@ *********************************************************************** - This file is a placeholder for a reimplementation of the "opfs" VFS - (as distinct from "opfs-sahpool") which uses WebLocks instead - locking based on a bespoke custom Atomics.wait()/notify() - protocol. This file holds the "synchronous half" of the VFS, whereas - it shares the "asynchronous half" of the "opfs" VFS. + This file is a reimplementation of the "opfs" VFS (as distinct from + "opfs-sahpool") which uses WebLocks for locking instead of a bespoke + custom Atomics.wait()/notify() protocol. This file holds the + "synchronous half" of the VFS, whereas it shares the "asynchronous + half" of the "opfs" VFS. This file is intended to be appended to the main sqlite3 JS deliverable somewhere after sqlite3-api-oo1.js. + + TODOs (2026-0303): + + - Move pieces of this file which are common to it, + sqlite3-vfs-opfs.c-pp.js, and/or sqlite3-opfs-async-proxy.js into + separate files and #include them in each using the preprocessor. + e.g. the s11n namespace object is duplicated in all three files. + + - For purposes of tester1.js we need to figure out which of these + VFSes will install the (internal-use-only) sqlite3.opfs utility code + namespace. We need that in order to clean up OPFS files during test + runs. Alternately, move those into their own + sqlite3ApiBootstrap.initializers entry which precedes both of the + VFSes, so they'll have access to it during bootstrapping. The + sqlite3.opfs namespace is removed at the end of bootstrapping unless + the library is told to run in testing mode (which is not a + documented feature). */ 'use strict'; globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ /** installOpfsVfs() returns a Promise which, on success, installs an - sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs + sqlite3_vfs named "opfs-wl", suitable for use with all sqlite3 APIs which accept a VFS. It is intended to be called via sqlite3ApiBootstrap.initializers or an equivalent mechanism. - The installed VFS uses the Origin-Private FileSystem API for - all file storage. On error it is rejected with an exception - explaining the problem. Reasons for rejection include, but are - not limited to: - - - The counterpart Worker (see below) could not be loaded. - - - The environment does not support OPFS. That includes when - this function is called from the main window thread. + This VFS is essentially a copy of the "opfs" VFS but uses + WebLocks for its xLock() and xUnlock() implementations. - Significant notes and limitations: + Quirks specific to this VFS: - - The OPFS features used here are only available in dedicated Worker - threads. This file tries to detect that case, resulting in a - rejected Promise if those features do not seem to be available. + - Because WebLocks effectively block until they return, they will + effectively hang on locks rather than returning SQLITE_BUSY. - - It requires the SharedArrayBuffer and Atomics classes, and the - former is only available if the HTTP server emits the so-called - COOP and COEP response headers. These features are required for - proxying OPFS's synchronous API via the synchronous interface - required by the sqlite3_vfs API. - - This function may only be called a single time. When called, this - function removes itself from the sqlite3 object. - - All arguments to this function are for internal/development purposes - only. They do not constitute a public API and may change at any - time. - - The argument may optionally be a plain object with the following - configuration options: + The argument may optionally be a plain object with the following + configuration options: - proxyUri: name of the async proxy JS file. @@ -67,14 +64,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ additionally enables debugging info. Logging is performed via the sqlite3.config.{log|warn|error}() functions. - - sanityChecks (=false): if true, some basic sanity tests are run on - the OPFS VFS API after it's initialized, before the returned - Promise resolves. This is only intended for testing and - development of the VFS, not client-side use. - On success, the Promise resolves to the top-most sqlite3 namespace - object and that object gets a new object installed in its - `opfs` property, containing several OPFS-specific utilities. + object. */ const installOpfsVfs = function callee(options){ if(!globalThis.SharedArrayBuffer @@ -115,9 +106,6 @@ const installOpfsVfs = function callee(options){ if(undefined===options.proxyUri){ options.proxyUri = callee.defaultProxyUri; } - - //sqlite3.config.warn("OPFS options =",options,globalThis.location); - if('function' === typeof options.proxyUri){ options.proxyUri = options.proxyUri(); } @@ -524,171 +512,8 @@ const installOpfsVfs = function callee(options){ } }; - const initS11n = ()=>{ - /** - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ACHTUNG: this code is 100% duplicated in the other half of - this proxy! The documentation is maintained in the - "synchronous half". - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - This proxy de/serializes cross-thread function arguments and - output-pointer values via the state.sabIO SharedArrayBuffer, - using the region defined by (state.sabS11nOffset, - state.sabS11nOffset + state.sabS11nSize]. Only one dataset is - recorded at a time. - - This is not a general-purpose format. It only supports the - range of operations, and data sizes, needed by the - sqlite3_vfs and sqlite3_io_methods operations. Serialized - data are transient and this serialization algorithm may - change at any time. - - The data format can be succinctly summarized as: - - Nt...Td...D - - Where: - - - N = number of entries (1 byte) - - - t = type ID of first argument (1 byte) - - - ...T = type IDs of the 2nd and subsequent arguments (1 byte - each). - - - d = raw bytes of first argument (per-type size). - - - ...D = raw bytes of the 2nd and subsequent arguments (per-type - size). - - All types except strings have fixed sizes. Strings are stored - using their TextEncoder/TextDecoder representations. It would - arguably make more sense to store them as Int16Arrays of - their JS character values, but how best/fastest to get that - in and out of string form is an open point. Initial - experimentation with that approach did not gain us any speed. - - Historical note: this impl was initially about 1% this size by - using using JSON.stringify/parse(), but using fit-to-purpose - serialization saves considerable runtime. - */ - if(state.s11n) return state.s11n; - const textDecoder = new TextDecoder(), - textEncoder = new TextEncoder('utf-8'), - viewU8 = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize), - viewDV = new DataView(state.sabIO, state.sabS11nOffset, state.sabS11nSize); - state.s11n = Object.create(null); - /* Only arguments and return values of these types may be - serialized. This covers the whole range of types needed by the - sqlite3_vfs API. */ - const TypeIds = Object.create(null); - TypeIds.number = { id: 1, size: 8, getter: 'getFloat64', setter: 'setFloat64' }; - TypeIds.bigint = { id: 2, size: 8, getter: 'getBigInt64', setter: 'setBigInt64' }; - TypeIds.boolean = { id: 3, size: 4, getter: 'getInt32', setter: 'setInt32' }; - TypeIds.string = { id: 4 }; - - const getTypeId = (v)=>( - TypeIds[typeof v] - || toss("Maintenance required: this value type cannot be serialized.",v) - ); - const getTypeIdById = (tid)=>{ - switch(tid){ - case TypeIds.number.id: return TypeIds.number; - case TypeIds.bigint.id: return TypeIds.bigint; - case TypeIds.boolean.id: return TypeIds.boolean; - case TypeIds.string.id: return TypeIds.string; - default: toss("Invalid type ID:",tid); - } - }; - - /** - Returns an array of the deserialized state stored by the most - recent serialize() operation (from this thread or the - counterpart thread), or null if the serialization buffer is - empty. If passed a truthy argument, the serialization buffer - is cleared after deserialization. - */ - state.s11n.deserialize = function(clear=false){ - ++metrics.s11n.deserialize.count; - const t = performance.now(); - const argc = viewU8[0]; - const rc = argc ? [] : null; - if(argc){ - const typeIds = []; - let offset = 1, i, n, v; - for(i = 0; i < argc; ++i, ++offset){ - typeIds.push(getTypeIdById(viewU8[offset])); - } - for(i = 0; i < argc; ++i){ - const t = typeIds[i]; - if(t.getter){ - v = viewDV[t.getter](offset, state.littleEndian); - offset += t.size; - }else{/*String*/ - n = viewDV.getInt32(offset, state.littleEndian); - offset += 4; - v = textDecoder.decode(viewU8.slice(offset, offset+n)); - offset += n; - } - rc.push(v); - } - } - if(clear) viewU8[0] = 0; - //log("deserialize:",argc, rc); - metrics.s11n.deserialize.time += performance.now() - t; - return rc; - }; - - /** - Serializes all arguments to the shared buffer for consumption - by the counterpart thread. - - This routine is only intended for serializing OPFS VFS - arguments and (in at least one special case) result values, - and the buffer is sized to be able to comfortably handle - those. - - If passed no arguments then it zeroes out the serialization - state. - */ - state.s11n.serialize = function(...args){ - const t = performance.now(); - ++metrics.s11n.serialize.count; - if(args.length){ - //log("serialize():",args); - const typeIds = []; - let i = 0, offset = 1; - viewU8[0] = args.length & 0xff /* header = # of args */; - for(; i < args.length; ++i, ++offset){ - /* Write the TypeIds.id value into the next args.length - bytes. */ - typeIds.push(getTypeId(args[i])); - viewU8[offset] = typeIds[i].id; - } - for(i = 0; i < args.length; ++i) { - /* Deserialize the following bytes based on their - corresponding TypeIds.id from the header. */ - const t = typeIds[i]; - if(t.setter){ - viewDV[t.setter](offset, args[i], state.littleEndian); - offset += t.size; - }else{/*String*/ - const s = textEncoder.encode(args[i]); - viewDV.setInt32(offset, s.byteLength, state.littleEndian); - offset += 4; - viewU8.set(s, offset); - offset += s.byteLength; - } - } - //log("serialize() result:",viewU8.slice(0,offset)); - }else{ - viewU8[0] = 0; - } - metrics.s11n.serialize.time += performance.now() - t; - }; - return state.s11n; - }/*initS11n()*/; +//#define opfs-has-metrics +//#include api/opfs-common.c-pp.js /** Generates a random ASCII string len characters long, intended for @@ -1323,14 +1148,14 @@ const installOpfsVfs = function callee(options){ }; if(sqlite3.oo1){ - const OpfsDb = function(...args){ + const OpfsWlDb = function(...args){ const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); opt.vfs = opfsVfs.$zName; sqlite3.oo1.DB.dbCtorHelper.call(this, opt); }; - OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype); - sqlite3.oo1.OpfsDb = OpfsDb; - OpfsDb.importDb = opfsUtil.importDb; + OpfsWlDb.prototype = Object.create(sqlite3.oo1.DB.prototype); + sqlite3.oo1.OpfsWlDb = OpfsWlDb; + OpfsWlDb.importDb = opfsUtil.importDb; sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback( opfsVfs.pointer, function(oo1Db, sqlite3){ @@ -1446,7 +1271,7 @@ const installOpfsVfs = function callee(options){ navigator.storage.getDirectory().then((d)=>{ W.onerror = W._originalOnError; delete W._originalOnError; - sqlite3.opfs = opfsUtil; + //sqlite3.opfs = opfsUtil; opfsUtil.rootDirectory = d; log("End of OPFS sqlite3_vfs setup.", opfsVfs); promiseResolve(); diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index ffa90ed068..dd1b4ba90b 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -71,8 +71,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ development of the VFS, not client-side use. On success, the Promise resolves to the top-most sqlite3 namespace - object and that object gets a new object installed in its - `opfs` property, containing several OPFS-specific utilities. + object. */ const installOpfsVfs = function callee(options){ if(!globalThis.SharedArrayBuffer @@ -509,171 +508,8 @@ const installOpfsVfs = function callee(options){ } }; - const initS11n = ()=>{ - /** - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ACHTUNG: this code is 100% duplicated in the other half of - this proxy! The documentation is maintained in the - "synchronous half". - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - This proxy de/serializes cross-thread function arguments and - output-pointer values via the state.sabIO SharedArrayBuffer, - using the region defined by (state.sabS11nOffset, - state.sabS11nOffset + state.sabS11nSize]. Only one dataset is - recorded at a time. - - This is not a general-purpose format. It only supports the - range of operations, and data sizes, needed by the - sqlite3_vfs and sqlite3_io_methods operations. Serialized - data are transient and this serialization algorithm may - change at any time. - - The data format can be succinctly summarized as: - - Nt...Td...D - - Where: - - - N = number of entries (1 byte) - - - t = type ID of first argument (1 byte) - - - ...T = type IDs of the 2nd and subsequent arguments (1 byte - each). - - - d = raw bytes of first argument (per-type size). - - - ...D = raw bytes of the 2nd and subsequent arguments (per-type - size). - - All types except strings have fixed sizes. Strings are stored - using their TextEncoder/TextDecoder representations. It would - arguably make more sense to store them as Int16Arrays of - their JS character values, but how best/fastest to get that - in and out of string form is an open point. Initial - experimentation with that approach did not gain us any speed. - - Historical note: this impl was initially about 1% this size by - using using JSON.stringify/parse(), but using fit-to-purpose - serialization saves considerable runtime. - */ - if(state.s11n) return state.s11n; - const textDecoder = new TextDecoder(), - textEncoder = new TextEncoder('utf-8'), - viewU8 = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize), - viewDV = new DataView(state.sabIO, state.sabS11nOffset, state.sabS11nSize); - state.s11n = Object.create(null); - /* Only arguments and return values of these types may be - serialized. This covers the whole range of types needed by the - sqlite3_vfs API. */ - const TypeIds = Object.create(null); - TypeIds.number = { id: 1, size: 8, getter: 'getFloat64', setter: 'setFloat64' }; - TypeIds.bigint = { id: 2, size: 8, getter: 'getBigInt64', setter: 'setBigInt64' }; - TypeIds.boolean = { id: 3, size: 4, getter: 'getInt32', setter: 'setInt32' }; - TypeIds.string = { id: 4 }; - - const getTypeId = (v)=>( - TypeIds[typeof v] - || toss("Maintenance required: this value type cannot be serialized.",v) - ); - const getTypeIdById = (tid)=>{ - switch(tid){ - case TypeIds.number.id: return TypeIds.number; - case TypeIds.bigint.id: return TypeIds.bigint; - case TypeIds.boolean.id: return TypeIds.boolean; - case TypeIds.string.id: return TypeIds.string; - default: toss("Invalid type ID:",tid); - } - }; - - /** - Returns an array of the deserialized state stored by the most - recent serialize() operation (from this thread or the - counterpart thread), or null if the serialization buffer is - empty. If passed a truthy argument, the serialization buffer - is cleared after deserialization. - */ - state.s11n.deserialize = function(clear=false){ - ++metrics.s11n.deserialize.count; - const t = performance.now(); - const argc = viewU8[0]; - const rc = argc ? [] : null; - if(argc){ - const typeIds = []; - let offset = 1, i, n, v; - for(i = 0; i < argc; ++i, ++offset){ - typeIds.push(getTypeIdById(viewU8[offset])); - } - for(i = 0; i < argc; ++i){ - const t = typeIds[i]; - if(t.getter){ - v = viewDV[t.getter](offset, state.littleEndian); - offset += t.size; - }else{/*String*/ - n = viewDV.getInt32(offset, state.littleEndian); - offset += 4; - v = textDecoder.decode(viewU8.slice(offset, offset+n)); - offset += n; - } - rc.push(v); - } - } - if(clear) viewU8[0] = 0; - //log("deserialize:",argc, rc); - metrics.s11n.deserialize.time += performance.now() - t; - return rc; - }; - - /** - Serializes all arguments to the shared buffer for consumption - by the counterpart thread. - - This routine is only intended for serializing OPFS VFS - arguments and (in at least one special case) result values, - and the buffer is sized to be able to comfortably handle - those. - - If passed no arguments then it zeroes out the serialization - state. - */ - state.s11n.serialize = function(...args){ - const t = performance.now(); - ++metrics.s11n.serialize.count; - if(args.length){ - //log("serialize():",args); - const typeIds = []; - let i = 0, offset = 1; - viewU8[0] = args.length & 0xff /* header = # of args */; - for(; i < args.length; ++i, ++offset){ - /* Write the TypeIds.id value into the next args.length - bytes. */ - typeIds.push(getTypeId(args[i])); - viewU8[offset] = typeIds[i].id; - } - for(i = 0; i < args.length; ++i) { - /* Deserialize the following bytes based on their - corresponding TypeIds.id from the header. */ - const t = typeIds[i]; - if(t.setter){ - viewDV[t.setter](offset, args[i], state.littleEndian); - offset += t.size; - }else{/*String*/ - const s = textEncoder.encode(args[i]); - viewDV.setInt32(offset, s.byteLength, state.littleEndian); - offset += 4; - viewU8.set(s, offset); - offset += s.byteLength; - } - } - //log("serialize() result:",viewU8.slice(0,offset)); - }else{ - viewU8[0] = 0; - } - metrics.s11n.serialize.time += performance.now() - t; - }; - return state.s11n; - }/*initS11n()*/; +//#define opfs-has-metrics +//#include api/opfs-common.c-pp.js /** Generates a random ASCII string len characters long, intended for diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c index 37f2967d88..748594f4ca 100644 --- a/ext/wasm/mkwasmbuilds.c +++ b/ext/wasm/mkwasmbuilds.c @@ -994,7 +994,8 @@ static void mk_fiddle(void){ pf("$(out.%s.js): $(MAKEFILE_LIST) " "$(EXPORTED_FUNCTIONS.fiddle) " "$(fiddle.c.in) " - "$(pre-post.%s.deps)", + "$(pre-post.%s.deps) " + "$(dir.dout)/sqlite3-opfs-async-proxy.js", zBuildName, zBuildName); if( isDebug ){ pf(" $(dir.fiddle)/fiddle-worker.js" @@ -1014,10 +1015,6 @@ static void mk_fiddle(void){ pf("\t@$(call b.call.wasm-strip,%s)\n", zBuildName); pf("\t@$(call b.strip-js-emcc-bindings,$(logtag.%s))\n", zBuildName); - pf("\t@$(call b.cp," - "%s," - "$(dir.api)/sqlite3-opfs-async-proxy.js," - "$(dir $@))\n", zBuildName); if( isDebug ){ pf("\t@$(call b.cp,%s," "$(dir.fiddle)/index.html " diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index 5d28bedee0..a28d80f202 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -1,8 +1,9 @@ importScripts( - (new URL(self.location.href).searchParams).get('sqlite3.dir') + '/sqlite3.js' + (new URL(globalThis.location.href).searchParams).get('sqlite3.dir') + '/sqlite3.js' ); -self.sqlite3InitModule().then(async function(sqlite3){ - const urlArgs = new URL(self.location.href).searchParams; +globalThis.sqlite3InitModule.__isUnderTest = true; +globalThis.sqlite3InitModule().then(async function(sqlite3){ + const urlArgs = new URL(globalThis.location.href).searchParams; const options = { workerName: urlArgs.get('workerId') || Math.round(Math.random()*10000), unlockAsap: urlArgs.get('opfs-unlock-asap') || 0 /*EXPERIMENTAL*/ @@ -98,7 +99,7 @@ self.sqlite3InitModule().then(async function(sqlite3){ } }/*run()*/; - self.onmessage = function({data}){ + globalThis.onmessage = function({data}){ switch(data.type){ case 'run': run().catch((e)=>{ if(!interval.error) interval.error = e; diff --git a/manifest b/manifest index b8efc4b0b2..a23506fd3a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\smissing\sreset\sof\sthe\slock\shandshake\sSharedArrayBuffer\sslot. -D 2026-03-03T21:46:44.640 +C An\sinitial\sattempt\sto\splugging\sopfs-wl\sinto\sthe\sbuild\sbut\sits\sinitial\shandshake\swith\sthe\sasync\shalf\scollides\swith\sthe\sopfs\sVFS's\shandshake,\scausing\sbootstrapping\sto\sfail\smiserably.\sWe'll\sneed\sto\seither\sdevise\sa\shandshake\swhich\scan\sdifferentiate\sbetween\sthe\stwo\sinstances\sor\swe'll\sneed\sto\spreprocess\ssqlite3-opfs-async-proxy\sinto\stwo\scopies.\sMove\sthe\s(now)\sthree\scopies\sof\ssome\scommon\scode\sshared\sby\sthe\sopfs\spieces\sinto\sa\spreprocessor\s#include. +D 2026-03-03T23:43:40.326 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -572,7 +572,7 @@ F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009e F ext/session/sqlite3session.c 6ebd02be470f36d41c4bd78927f39d507b62051ba025eacaed9936c769902a07 F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a F ext/session/test_session.c 190110e3bd9463717248dec1272b44fe9943e57b7646d0b4200dcf11e4dccee6 -F ext/wasm/GNUmakefile 79236447d750609aa6beda30feec1314180c5462a493ad94214122887232bfd4 +F ext/wasm/GNUmakefile a64605e68d4561f440bdc538e01364210f75052469d6ea21bf2843f1539144e9 F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259 F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff @@ -584,20 +584,21 @@ F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp 7ba933e8f1290cc65459dd371c0c9a031d96bdf14 F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b47244781a7e81 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 +F ext/wasm/api/opfs-common.c-pp.js 5540c58aee8fbbf2c67984e0a35e2b680a7603052f2cc442d407da3cc81c4819 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b -F ext/wasm/api/post-js-header.js d24bd0d065f3489c8b78ddf3ead6321e5d047187a162cd503c41700e03dd1f06 +F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f F ext/wasm/api/sqlite3-api-glue.c-pp.js 9b33e3ee467791dec4fd1b444b12a8545dfbb6c8b28ac651c7bdc7661a3b5a5c F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c41db98a22b534c15e543cfa -F ext/wasm/api/sqlite3-api-prologue.js 1fefd40ab21e3dbf46f43b6fafb07f13eb13cc157a884f7c1134caf631ddb3f2 +F ext/wasm/api/sqlite3-api-prologue.js ccd8ece4b4580d2a70996218f28e810d70a86f5e2795f4d4a75f0603af24aef6 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.js 912ddb17627e933eb9596d393227f7ea47b1136fc2fb0d957d9979e71de59e81 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 0ec326d4c66c7af5a4c79a1be65c07c1e1844e641f133ba026a4a01eb1a37c56 w ext/wasm/api/sqlite3-opfs-async-proxy.js F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js deea0f903e8265f58fe57315c35f62170fd65d4730bece7978772c28cead1402 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 1abe919013d759b311e7e3f5c4a326f9027b1b6a0fbe89db5f303e2ff109d5d4 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js ab2a73f41a2e109f25fd3159531e801ca14c782c297b2fc1836e6a02b795321b F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -626,7 +627,7 @@ F ext/wasm/index.html 475bc283338749db4e3fbf24cf3f5aa020cc85a1fffb780d400a915fcb F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b F ext/wasm/jaccwabyt/jaccwabyt.md 6aa90fa1a973d0ad10d077088bea163b241d8470c75eafdef87620a1de1dea41 F ext/wasm/mkdist.sh f8883b077a2ca47cf92e6f0ce305fbf72ca648c3501810125056c4b09c2d5554 x -F ext/wasm/mkwasmbuilds.c 0e9198eb90acae4bcf57cf62d7186f6af5aaac02efdb075a1aded33614b3805a +F ext/wasm/mkwasmbuilds.c b1ed20dfba178e6ccae91b4594ac9439992fd0cb783f202c639ca761f1b1d2a3 F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2 F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96 F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63 @@ -645,7 +646,7 @@ F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3 F ext/wasm/tester1.c-pp.js 6b946cd6d4da130dbae4a401057716d27117ca02cad2ea8c29ae9c46c675d618 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88 -F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 +F ext/wasm/tests/opfs/concurrency/worker.js 3e29c07bdd11f4ff9ee50e641e39c254d39243bbb83fb20a255755ee92739d12 F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2189,8 +2190,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 3343e3aabe465f4ab91dd148dfc5a60346e9afb560c10d1f92aeae98763ec3ce -R f490861a3a61c6b12505aa6e9bec9268 +P 5910ed7ac843aa1fdb103ddcfaf6270d12cb39199205fc0b9f721fbf7fa2f851 +R d999a6bf319e44a9103bde13f0ab87af U stephan -Z 0dd9a22951092896d0ba74d53d905c49 +Z 097c558a7425489e055f6ff0be38c909 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 757a353e6f..9be206dbe2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5910ed7ac843aa1fdb103ddcfaf6270d12cb39199205fc0b9f721fbf7fa2f851 +1e0b72631aecb0bb72f4089116da221e6c4abf962db589de08132cd52c2be0e2 From 9ac95d9ce1324d2acce9877b4c7c389c223d7a39 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 4 Mar 2026 00:37:55 +0000 Subject: [PATCH 087/197] opfs-wl is now loading and registering but it's still untested. FossilOrigin-Name: 9a471f7491a371052bf1785098ba966dd0d03503e7d8b9fbcd65f07b038e5021 --- ext/wasm/GNUmakefile | 2 +- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 8 ++++++++ ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 9 ++++++--- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 7 ++++--- manifest | 18 +++++++++--------- manifest.uuid | 2 +- 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index 371bec6bdd..7e48113ed2 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -913,7 +913,7 @@ endif sqlite3-api.jses += $(dir.api)/sqlite3-vfs-kvvfs.c-pp.js sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js -#sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-wl.c-pp.js +sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-wl.c-pp.js # Parallel builds can fail if $(sqlite3-license-version.js) is not # created early enough, so make all files in $(sqlite-api.jses) except diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 294e7687be..740be8938b 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -51,6 +51,14 @@ */ "use strict"; const wPost = (type,...args)=>postMessage({type, payload:args}); +//#if nope +const urlParams = new URL(globalThis.location.href).searchParams; +if( !urlParams.has('vfs') ){ + throw new Error("Expecting vfs=opfs|opfs-wl URL argument for this worker"); +} +const isWebLocker = 'opfs-wl'===urlParams.get('vfs'); +const msgKeyPrefix = 'opfs-'; //isWebLocker ? 'opfs-wl-' : 'opfs-'; +//#endif const installAsyncProxy = function(){ const toss = function(...args){throw new Error(args.join(' '))}; if(globalThis.window === globalThis){ diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index dfa44af5e1..c53bebdfe1 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -197,13 +197,14 @@ const installOpfsVfs = function callee(options){ promiseWasRejected = false; return promiseResolve_(sqlite3); }; + const workerArgs = '?vfs=opfs-wl'; const W = //#if target:es6-bundler-friendly - new Worker(new URL("sqlite3-opfs-async-proxy.js", import.meta.url)); + new Worker(new URL("sqlite3-opfs-async-proxy.js"+workerArgs, import.meta.url)); //#elif target:es6-module - new Worker(new URL(options.proxyUri, import.meta.url)); + new Worker(new URL(options.proxyUri+workerArgs, import.meta.url)); //#else - new Worker(options.proxyUri); + new Worker(options.proxyUri+workerArgs); //#endif setTimeout(()=>{ /* At attempt to work around a browser-specific quirk in which @@ -1156,6 +1157,7 @@ const installOpfsVfs = function callee(options){ OpfsWlDb.prototype = Object.create(sqlite3.oo1.DB.prototype); sqlite3.oo1.OpfsWlDb = OpfsWlDb; OpfsWlDb.importDb = opfsUtil.importDb; +//#if nope sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback( opfsVfs.pointer, function(oo1Db, sqlite3){ @@ -1165,6 +1167,7 @@ const installOpfsVfs = function callee(options){ sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000); } ); +//#endif }/*extend sqlite3.oo1*/ const sanityCheck = function(){ diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index dd1b4ba90b..934564c5ea 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -207,13 +207,14 @@ const installOpfsVfs = function callee(options){ promiseWasRejected = false; return promiseResolve_(sqlite3); }; + const workerArgs = '?vfs=opfs'; const W = //#if target:es6-bundler-friendly - new Worker(new URL("sqlite3-opfs-async-proxy.js", import.meta.url)); + new Worker(new URL("sqlite3-opfs-async-proxy.js"+workerArgs, import.meta.url)); //#elif target:es6-module - new Worker(new URL(options.proxyUri, import.meta.url)); + new Worker(new URL(options.proxyUri+workerArgs, import.meta.url)); //#else - new Worker(options.proxyUri); + new Worker(options.proxyUri+workerArgs); //#endif setTimeout(()=>{ /* At attempt to work around a browser-specific quirk in which diff --git a/manifest b/manifest index a23506fd3a..2f56d2c256 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C An\sinitial\sattempt\sto\splugging\sopfs-wl\sinto\sthe\sbuild\sbut\sits\sinitial\shandshake\swith\sthe\sasync\shalf\scollides\swith\sthe\sopfs\sVFS's\shandshake,\scausing\sbootstrapping\sto\sfail\smiserably.\sWe'll\sneed\sto\seither\sdevise\sa\shandshake\swhich\scan\sdifferentiate\sbetween\sthe\stwo\sinstances\sor\swe'll\sneed\sto\spreprocess\ssqlite3-opfs-async-proxy\sinto\stwo\scopies.\sMove\sthe\s(now)\sthree\scopies\sof\ssome\scommon\scode\sshared\sby\sthe\sopfs\spieces\sinto\sa\spreprocessor\s#include. -D 2026-03-03T23:43:40.326 +C opfs-wl\sis\snow\sloading\sand\sregistering\sbut\sit's\sstill\suntested. +D 2026-03-04T00:37:55.997 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -572,7 +572,7 @@ F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009e F ext/session/sqlite3session.c 6ebd02be470f36d41c4bd78927f39d507b62051ba025eacaed9936c769902a07 F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a F ext/session/test_session.c 190110e3bd9463717248dec1272b44fe9943e57b7646d0b4200dcf11e4dccee6 -F ext/wasm/GNUmakefile a64605e68d4561f440bdc538e01364210f75052469d6ea21bf2843f1539144e9 +F ext/wasm/GNUmakefile a0afdb3e6306997de1e123e8b8270affb744519c9e384dbc277d0af6a6ba1c91 F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259 F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff @@ -593,12 +593,12 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js ccd8ece4b4580d2a70996218f28e810d70a86f5e2795f4d4a75f0603af24aef6 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 0ec326d4c66c7af5a4c79a1be65c07c1e1844e641f133ba026a4a01eb1a37c56 w ext/wasm/api/sqlite3-opfs-async-proxy.js +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 041f24cd61d470072303b0cd1bb73dd2928bf2c96c0fbf3d3f4a39024c4e9ae7 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 1abe919013d759b311e7e3f5c4a326f9027b1b6a0fbe89db5f303e2ff109d5d4 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js ab2a73f41a2e109f25fd3159531e801ca14c782c297b2fc1836e6a02b795321b +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 072abf5bd30e5a611f9d15039bb41795fb517b5ade1b1973cbdd70c171a1f822 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e44649cf72b303b857ce4d7e33b13b88a1f97009514b1b84d2e9c2ecf511fca1 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -2190,8 +2190,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 5910ed7ac843aa1fdb103ddcfaf6270d12cb39199205fc0b9f721fbf7fa2f851 -R d999a6bf319e44a9103bde13f0ab87af +P 1e0b72631aecb0bb72f4089116da221e6c4abf962db589de08132cd52c2be0e2 +R 32d905549a7b0f1874fdf6ef84b0e8af U stephan -Z 097c558a7425489e055f6ff0be38c909 +Z 466cb2ea030b3f6732fe2aeb3d4128c0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9be206dbe2..558d2665e6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1e0b72631aecb0bb72f4089116da221e6c4abf962db589de08132cd52c2be0e2 +9a471f7491a371052bf1785098ba966dd0d03503e7d8b9fbcd65f07b038e5021 From 6d6bf30735240776ecbfc6ebd86a267e47f06fe0 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 4 Mar 2026 00:48:03 +0000 Subject: [PATCH 088/197] A potential fix for the probable breakage of bundler-friendly builds in the previous check-in. Pending review from someone who uses those tools. FossilOrigin-Name: 8ea85776116521526d684f221d67e288126e62931d4a0ea7fc7f164cd2d5b2ec --- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 2 +- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index c53bebdfe1..6113657021 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -200,7 +200,7 @@ const installOpfsVfs = function callee(options){ const workerArgs = '?vfs=opfs-wl'; const W = //#if target:es6-bundler-friendly - new Worker(new URL("sqlite3-opfs-async-proxy.js"+workerArgs, import.meta.url)); + new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs-wl", import.meta.url)); //#elif target:es6-module new Worker(new URL(options.proxyUri+workerArgs, import.meta.url)); //#else diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 934564c5ea..216cd83a2a 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -210,7 +210,7 @@ const installOpfsVfs = function callee(options){ const workerArgs = '?vfs=opfs'; const W = //#if target:es6-bundler-friendly - new Worker(new URL("sqlite3-opfs-async-proxy.js"+workerArgs, import.meta.url)); + new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs", import.meta.url)); //#elif target:es6-module new Worker(new URL(options.proxyUri+workerArgs, import.meta.url)); //#else diff --git a/manifest b/manifest index 2f56d2c256..037a053c93 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C opfs-wl\sis\snow\sloading\sand\sregistering\sbut\sit's\sstill\suntested. -D 2026-03-04T00:37:55.997 +C A\spotential\sfix\sfor\sthe\sprobable\sbreakage\sof\sbundler-friendly\sbuilds\sin\sthe\sprevious\scheck-in.\sPending\sreview\sfrom\ssomeone\swho\suses\sthose\stools. +D 2026-03-04T00:48:03.758 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -597,8 +597,8 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 041f24cd61d470072303b0cd1bb73dd2 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 072abf5bd30e5a611f9d15039bb41795fb517b5ade1b1973cbdd70c171a1f822 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e44649cf72b303b857ce4d7e33b13b88a1f97009514b1b84d2e9c2ecf511fca1 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 8c79bf3ea89102772225e6539c030787ea85203b6cc0354c545df69d81a2d910 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b2b4c7570ec816c49e7b3293f451992bd7fb7154dcd4cec6fb05d032c6cedf52 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -2190,8 +2190,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 1e0b72631aecb0bb72f4089116da221e6c4abf962db589de08132cd52c2be0e2 -R 32d905549a7b0f1874fdf6ef84b0e8af +P 9a471f7491a371052bf1785098ba966dd0d03503e7d8b9fbcd65f07b038e5021 +R 8aa8acc5e3e3610acfaa4dc12ceb0c5d U stephan -Z 466cb2ea030b3f6732fe2aeb3d4128c0 +Z dc633fdeffefdb99fdb4ea173110ea63 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 558d2665e6..3a2f818401 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9a471f7491a371052bf1785098ba966dd0d03503e7d8b9fbcd65f07b038e5021 +8ea85776116521526d684f221d67e288126e62931d4a0ea7fc7f164cd2d5b2ec From 96daad10faab55aca79d53fe78bd5d1bcaaf18df Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 4 Mar 2026 11:37:39 +0000 Subject: [PATCH 089/197] Consolidate much of the OPFS utility code into a new file for use by two of the OPFS VFSes. FossilOrigin-Name: db19a6e9663c3a44996178cb8c35dc4ccd60f48cb4b81b6c214411a56c57def7 --- ext/wasm/GNUmakefile | 1 + ...mon.c-pp.js => opfs-common-inline.c-pp.js} | 22 +- ext/wasm/api/opfs-common-shared.c-pp.js | 430 ++++++++++++++++ ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 13 +- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 481 ++---------------- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 464 ++--------------- manifest | 21 +- manifest.uuid | 2 +- 8 files changed, 543 insertions(+), 891 deletions(-) rename ext/wasm/api/{opfs-common.c-pp.js => opfs-common-inline.c-pp.js} (89%) create mode 100644 ext/wasm/api/opfs-common-shared.c-pp.js diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index 7e48113ed2..1b7c5269e8 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -911,6 +911,7 @@ ifeq (0,$(wasm-bare-bones)) sqlite3-api.jses += $(dir.api)/sqlite3-vtab-helper.c-pp.js endif sqlite3-api.jses += $(dir.api)/sqlite3-vfs-kvvfs.c-pp.js +sqlite3-api.jses += $(dir.api)/opfs-common-shared.c-pp.js sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-wl.c-pp.js diff --git a/ext/wasm/api/opfs-common.c-pp.js b/ext/wasm/api/opfs-common-inline.c-pp.js similarity index 89% rename from ext/wasm/api/opfs-common.c-pp.js rename to ext/wasm/api/opfs-common-inline.c-pp.js index 1a7818927a..dcff8a05bd 100644 --- a/ext/wasm/api/opfs-common.c-pp.js +++ b/ext/wasm/api/opfs-common-inline.c-pp.js @@ -1,26 +1,14 @@ //#if nope /** This file is for preprocessor #include into the "opfs" and - "opfs-wl" impls, as well as their async-proxy part. + "opfs-wl" impls, as well as their async-proxy part. It must be + inlined in those files, as opposed to being a shared copy in the + library, because (A) the async proxy does not load the library and + (B) it references an object which is local to each of those files + but which has a 99% identical structure for each. */ //#endif - -//#if not defined opfs-async-proxy -/** - TODO: move the sqlite3.opfs (private/internal) namespace object - init from sqlite3-vfs-opfs*.js into here. That namespace gets - removed from the sqlite3 namespace in the final stages of library - bootstrapping except in test runs, where it's retained so that - tests can clean up OPFS so their test cases work (the down-side of - them being persistent). -*/ -//#endif not defined opfs-async-proxy - -// This function won't work as-is if we #include it, but the -// missing elements have not yet been identified. const initS11n = function(){ - /* This function is needed by the "opfs" and "opfs-wl" VFSes - and sqlite-opfs-async-proxy.js (used by those of those). */ /** This proxy de/serializes cross-thread function arguments and output-pointer values via the state.sabIO SharedArrayBuffer, diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js new file mode 100644 index 0000000000..56af5585bc --- /dev/null +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -0,0 +1,430 @@ +//#if not target:node +/* + 2026-03-04 + + The author disclaims copyright to this source code. In place of a + legal notice, here is a blessing: + + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. + + *********************************************************************** + + This file holds code shared by sqlite3-vfs-opfs{,-wl}.c-pp.js. It + creates a private/internal sqlite3.opfs namespace common to the two + and used (only) by them and the test framework. It is not part of + the public API. +*/ +globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ + 'use strict'; + const toss = sqlite3.util.toss; + const toss3 = sqlite3.util.toss3; + const capi = sqlite3.capi; + const util = sqlite3.util; + const wasm = sqlite3.wasm; + + /** + Generic utilities for working with OPFS. This will get filled out + by the Promise setup and, on success, installed as sqlite3.opfs. + + This is an internal/private namespace intended for use solely + by the OPFS VFSes and test code for them. The library bootstrapping + process removes this object in non-testing contexts. + + */ + const opfsUtil = sqlite3.opfs = Object.create(null); + + /** + Returns true if _this_ thread has access to the OPFS APIs. + */ + opfsUtil.thisThreadHasOPFS = ()=>{ + return globalThis.FileSystemHandle && + globalThis.FileSystemDirectoryHandle && + globalThis.FileSystemFileHandle && + globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle && + navigator?.storage?.getDirectory; + }; + + /** + Must be called by the OPFS VFSes immediately after they determine + whether OPFS is available by calling + thisThreadHasOPFS(). Resolves to the OPFS storage root directory + and sets opfsUtil.rootDirectory to that value. + */ + opfsUtil.getRootDir = async function f(){ + return f.promise ??= navigator.storage.getDirectory().then(d=>{ + opfsUtil.rootDirectory = d; + return d; + }).catch(e=>{ + delete f.promise; + throw e; + }); + }; + + /** + Expects an OPFS file path. It gets resolved, such that ".." + components are properly expanded, and returned. If the 2nd arg + is true, the result is returned as an array of path elements, + else an absolute path string is returned. + */ + opfsUtil.getResolvedPath = function(filename,splitIt){ + const p = new URL(filename, "file://irrelevant").pathname; + return splitIt ? p.split('/').filter((v)=>!!v) : p; + }; + + /** + Takes the absolute path to a filesystem element. Returns an + array of [handleOfContainingDir, filename]. If the 2nd argument + is truthy then each directory element leading to the file is + created along the way. Throws if any creation or resolution + fails. + */ + opfsUtil.getDirForFilename = async function f(absFilename, createDirs = false){ + const path = opfsUtil.getResolvedPath(absFilename, true); + const filename = path.pop(); + let dh = await opfsUtil.getRootDir(); + for(const dirName of path){ + if(dirName){ + dh = await dh.getDirectoryHandle(dirName, {create: !!createDirs}); + } + } + return [dh, filename]; + }; + + /** + Creates the given directory name, recursively, in + the OPFS filesystem. Returns true if it succeeds or the + directory already exists, else false. + */ + opfsUtil.mkdir = async function(absDirName){ + try { + await opfsUtil.getDirForFilename(absDirName+"/filepart", true); + return true; + }catch(e){ + //sqlite3.config.warn("mkdir(",absDirName,") failed:",e); + return false; + } + }; + /** + Checks whether the given OPFS filesystem entry exists, + returning true if it does, false if it doesn't or if an + exception is intercepted while trying to make the + determination. + */ + opfsUtil.entryExists = async function(fsEntryName){ + try { + const [dh, fn] = await opfsUtil.getDirForFilename(fsEntryName); + await dh.getFileHandle(fn); + return true; + }catch(e){ + return false; + } + }; + + /** + Generates a random ASCII string len characters long, intended for + use as a temporary file name. + */ + opfsUtil.randomFilename = function f(len=16){ + if(!f._chars){ + f._chars = "abcdefghijklmnopqrstuvwxyz"+ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+ + "012346789"; + f._n = f._chars.length; + } + const a = []; + let i = 0; + for( ; i < len; ++i){ + const ndx = Math.random() * (f._n * 64) % f._n | 0; + a[i] = f._chars[ndx]; + } + return a.join(""); + /* + An alternative impl. with an unpredictable length + but much simpler: + + Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36) + */ + }; + + /** + Returns a promise which resolves to an object which represents + all files and directories in the OPFS tree. The top-most object + has two properties: `dirs` is an array of directory entries + (described below) and `files` is a list of file names for all + files in that directory. + + Traversal starts at sqlite3.opfs.rootDirectory. + + Each `dirs` entry is an object in this form: + + ``` + { name: directoryName, + dirs: [...subdirs], + files: [...file names] + } + ``` + + The `files` and `subdirs` entries are always set but may be + empty arrays. + + The returned object has the same structure but its `name` is + an empty string. All returned objects are created with + Object.create(null), so have no prototype. + + Design note: the entries do not contain more information, + e.g. file sizes, because getting such info is not only + expensive but is subject to locking-related errors. + */ + opfsUtil.treeList = async function(){ + const doDir = async function callee(dirHandle,tgt){ + tgt.name = dirHandle.name; + tgt.dirs = []; + tgt.files = []; + for await (const handle of dirHandle.values()){ + if('directory' === handle.kind){ + const subDir = Object.create(null); + tgt.dirs.push(subDir); + await callee(handle, subDir); + }else{ + tgt.files.push(handle.name); + } + } + }; + const root = Object.create(null); + const dir = await opfsUtil.getRootDir(); + await doDir(dir, root); + return root; + }; + + /** + Irrevocably deletes _all_ files in the current origin's OPFS. + Obviously, this must be used with great caution. It may throw + an exception if removal of anything fails (e.g. a file is + locked), but the precise conditions under which the underlying + APIs will throw are not documented (so we cannot tell you what + they are). + */ + opfsUtil.rmfr = async function(){ + const rd = await opfsUtil.getRootDir(); + const dir = rd, opt = {recurse: true}; + for await (const handle of dir.values()){ + dir.removeEntry(handle.name, opt); + } + }; + + /** + Deletes the given OPFS filesystem entry. As this environment + has no notion of "current directory", the given name must be an + absolute path. If the 2nd argument is truthy, deletion is + recursive (use with caution!). + + The returned Promise resolves to true if the deletion was + successful, else false (but...). The OPFS API reports the + reason for the failure only in human-readable form, not + exceptions which can be type-checked to determine the + failure. Because of that... + + If the final argument is truthy then this function will + propagate any exception on error, rather than returning false. + */ + opfsUtil.unlink = async function(fsEntryName, recursive = false, + throwOnError = false){ + try { + const [hDir, filenamePart] = + await opfsUtil.getDirForFilename(fsEntryName, false); + await hDir.removeEntry(filenamePart, {recursive}); + return true; + }catch(e){ + if(throwOnError){ + throw new Error("unlink(",arguments[0],") failed: "+e.message,{ + cause: e + }); + } + return false; + } + }; + + /** + Traverses the OPFS filesystem, calling a callback for each + entry. The argument may be either a callback function or an + options object with any of the following properties: + + - `callback`: function which gets called for each filesystem + entry. It gets passed 3 arguments: 1) the + FileSystemFileHandle or FileSystemDirectoryHandle of each + entry (noting that both are instanceof FileSystemHandle). 2) + the FileSystemDirectoryHandle of the parent directory. 3) the + current depth level, with 0 being at the top of the tree + relative to the starting directory. If the callback returns a + literal false, as opposed to any other falsy value, traversal + stops without an error. Any exceptions it throws are + propagated. Results are undefined if the callback manipulate + the filesystem (e.g. removing or adding entries) because the + how OPFS iterators behave in the face of such changes is + undocumented. + + - `recursive` [bool=true]: specifies whether to recurse into + subdirectories or not. Whether recursion is depth-first or + breadth-first is unspecified! + + - `directory` [FileSystemDirectoryEntry=sqlite3.opfs.rootDirectory] + specifies the starting directory. + + If this function is passed a function, it is assumed to be the + callback. + + Returns a promise because it has to (by virtue of being async) + but that promise has no specific meaning: the traversal it + performs is synchronous. The promise must be used to catch any + exceptions propagated by the callback, however. + */ + opfsUtil.traverse = async function(opt){ + const defaultOpt = { + recursive: true, + directory: await opfsUtil.getRootDir() + }; + if('function'===typeof opt){ + opt = {callback:opt}; + } + opt = Object.assign(defaultOpt, opt||{}); + const doDir = async function callee(dirHandle, depth){ + for await (const handle of dirHandle.values()){ + if(false === opt.callback(handle, dirHandle, depth)) return false; + else if(opt.recursive && 'directory' === handle.kind){ + if(false === await callee(handle, depth + 1)) break; + } + } + }; + doDir(opt.directory, 0); + }; + + /** + Impl of opfsUtil.importDb() when it's given a function as its + second argument. + */ + const importDbChunked = async function(filename, callback){ + const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true); + const hFile = await hDir.getFileHandle(fnamePart, {create:true}); + let sah = await hFile.createSyncAccessHandle(); + let nWrote = 0, chunk, checkedHeader = false, err = false; + try{ + sah.truncate(0); + while( undefined !== (chunk = await callback()) ){ + if(chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk); + if( !checkedHeader && 0===nWrote && chunk.byteLength>=15 ){ + util.affirmDbHeader(chunk); + checkedHeader = true; + } + sah.write(chunk, {at: nWrote}); + nWrote += chunk.byteLength; + } + if( nWrote < 512 || 0!==nWrote % 512 ){ + toss("Input size",nWrote,"is not correct for an SQLite database."); + } + if( !checkedHeader ){ + const header = new Uint8Array(20); + sah.read( header, {at: 0} ); + util.affirmDbHeader( header ); + } + sah.write(new Uint8Array([1,1]), {at: 18}/*force db out of WAL mode*/); + return nWrote; + }catch(e){ + await sah.close(); + sah = undefined; + await hDir.removeEntry( fnamePart ).catch(()=>{}); + throw e; + }finally { + if( sah ) await sah.close(); + } + }; + + /** + Asynchronously imports the given bytes (a byte array or + ArrayBuffer) into the given database file. + + Results are undefined if the given db name refers to an opened + db. + + If passed a function for its second argument, its behaviour + changes: imports its data in chunks fed to it by the given + callback function. It calls the callback (which may be async) + repeatedly, expecting either a Uint8Array or ArrayBuffer (to + denote new input) or undefined (to denote EOF). For so long as + the callback continues to return non-undefined, it will append + incoming data to the given VFS-hosted database file. When + called this way, the resolved value of the returned Promise is + the number of bytes written to the target file. + + It very specifically requires the input to be an SQLite3 + database and throws if that's not the case. It does so in + order to prevent this function from taking on a larger scope + than it is specifically intended to. i.e. we do not want it to + become a convenience for importing arbitrary files into OPFS. + + This routine rewrites the database header bytes in the output + file (not the input array) to force disabling of WAL mode. + + On error this throws and the state of the input file is + undefined (it depends on where the exception was triggered). + + On success, resolves to the number of bytes written. + */ + opfsUtil.importDb = async function(filename, bytes){ + if( bytes instanceof Function ){ + return importDbChunked(filename, bytes); + } + if(bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); + util.affirmIsDb(bytes); + const n = bytes.byteLength; + const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true); + let sah, err, nWrote = 0; + try { + const hFile = await hDir.getFileHandle(fnamePart, {create:true}); + sah = await hFile.createSyncAccessHandle(); + sah.truncate(0); + nWrote = sah.write(bytes, {at: 0}); + if(nWrote != n){ + toss("Expected to write "+n+" bytes but wrote "+nWrote+"."); + } + sah.write(new Uint8Array([1,1]), {at: 18}) /* force db out of WAL mode */; + return nWrote; + }catch(e){ + if( sah ){ await sah.close(); sah = undefined; } + await hDir.removeEntry( fnamePart ).catch(()=>{}); + throw e; + }finally{ + if( sah ) await sah.close(); + } + }; + + /** + Checks for features required for OPFS VFSes and throws with a + descriptive error message if they're not found. This is intended + to be run as part of async VFS installation steps. + */ + opfsUtil.vfsInstallationFeatureCheck = function(){ + if(!globalThis.SharedArrayBuffer + || !globalThis.Atomics){ + throw new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. "+ + "The server must emit the COOP/COEP response headers to enable those. "+ + "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep"); + }else if('undefined'===typeof WorkerGlobalScope){ + throw new Error("The OPFS sqlite3_vfs cannot run in the main thread "+ + "because it requires Atomics.wait()."); + }else if(!globalThis.FileSystemHandle || + !globalThis.FileSystemDirectoryHandle || + !globalThis.FileSystemFileHandle || + !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || + !navigator?.storage?.getDirectory){ + throw new newError("Missing required OPFS APIs."); + } + }; + +}/*sqlite3ApiBootstrap.initializers*/); +//#else +/* + The OPFS SAH Pool parts are elided from builds targeting node.js. +*/ +//#endif target:node diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 740be8938b..98eeb1639b 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -46,19 +46,16 @@ theFunc().then(...) is not compatible with the change to synchronous, but we do do not use those APIs that way. i.e. we don't _need_ to change anything for this, but at some point (after Chrome - versions (approximately) 104-107 are extinct) should change our + versions (approximately) 104-107 are extinct) we should change our usage of those methods to remove the "await". */ "use strict"; const wPost = (type,...args)=>postMessage({type, payload:args}); -//#if nope const urlParams = new URL(globalThis.location.href).searchParams; if( !urlParams.has('vfs') ){ throw new Error("Expecting vfs=opfs|opfs-wl URL argument for this worker"); } const isWebLocker = 'opfs-wl'===urlParams.get('vfs'); -const msgKeyPrefix = 'opfs-'; //isWebLocker ? 'opfs-wl-' : 'opfs-'; -//#endif const installAsyncProxy = function(){ const toss = function(...args){throw new Error(args.join(' '))}; if(globalThis.window === globalThis){ @@ -73,6 +70,9 @@ const installAsyncProxy = function(){ this API. */ const state = Object.create(null); +//#define opfs-async-proxy +//#include api/opfs-common-inline.c-pp.js +//#undef opfs-async-proxy /** verbose: @@ -326,7 +326,7 @@ const installAsyncProxy = function(){ } log("Got",opName+"() sync handle for",fh.filenameAbs, 'in',performance.now() - t,'ms'); - if(!fh.xLock && !state.lock/*set by opfs-wl*/){ + if(!isWebLocker && !fh.xLock){ __implicitLocks.add(fh.fid); log("Acquired implicit lock for",opName+"()",fh.fid,fh.filenameAbs); } @@ -611,9 +611,6 @@ const installAsyncProxy = function(){ } }/*vfsAsyncImpls*/; -//#define opfs-async-proxy -//#include api/opfs-common.c-pp.js - /** Starts a new WebLock request. */ diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 6113657021..e2f4ff2f93 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -20,12 +20,7 @@ This file is intended to be appended to the main sqlite3 JS deliverable somewhere after sqlite3-api-oo1.js. - TODOs (2026-0303): - - - Move pieces of this file which are common to it, - sqlite3-vfs-opfs.c-pp.js, and/or sqlite3-opfs-async-proxy.js into - separate files and #include them in each using the preprocessor. - e.g. the s11n namespace object is duplicated in all three files. + TODOs (2026-03-03): - For purposes of tester1.js we need to figure out which of these VFSes will install the (internal-use-only) sqlite3.opfs utility code @@ -39,8 +34,11 @@ */ 'use strict'; globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ + const opfsUtil = sqlite3.opfs || sqlite3.util.toss("Missing sqlite3.opfs") + /* Gets removed from sqlite3 during bootstrap, so we need an + early reference to it. */; /** - installOpfsVfs() returns a Promise which, on success, installs an + installOpfsWlVfs() returns a Promise which, on success, installs an sqlite3_vfs named "opfs-wl", suitable for use with all sqlite3 APIs which accept a VFS. It is intended to be called via sqlite3ApiBootstrap.initializers or an equivalent mechanism. @@ -67,27 +65,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ On success, the Promise resolves to the top-most sqlite3 namespace object. */ -const installOpfsVfs = function callee(options){ - if(!globalThis.SharedArrayBuffer - || !globalThis.Atomics){ - return Promise.reject( - new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. "+ - "The server must emit the COOP/COEP response headers to enable those. "+ - "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep") - ); - }else if('undefined'===typeof WorkerGlobalScope){ - return Promise.reject( - new Error("The OPFS sqlite3_vfs cannot run in the main thread "+ - "because it requires Atomics.wait().") - ); - }else if(!globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || - !navigator?.storage?.getDirectory){ - return Promise.reject( - new Error("Missing required OPFS APIs.") - ); +const installOpfsWlVfs = function callee(options){ + try{ + opfsUtil.vfsInstallationFeatureCheck(); + }catch(e){ + return Promise.reject(e); } const nu = (...obj)=>Object.assign(Object.create(null),...obj); options = nu(options); @@ -129,31 +111,34 @@ const installOpfsVfs = function callee(options){ const sqlite3_file = capi.sqlite3_file; const sqlite3_io_methods = capi.sqlite3_io_methods; /** - Generic utilities for working with OPFS. This will get filled out - by the Promise setup and, on success, installed as sqlite3.opfs. + State which we send to the async-api Worker or share with it. + This object must initially contain only cloneable or sharable + objects. After the worker's "inited" message arrives, other types + of data may be added to it. - ACHTUNG: do not rely on these APIs in client code. They are - experimental and subject to change or removal as the - OPFS-specific sqlite3_vfs evolves. - */ - const opfsUtil = Object.create(null); + For purposes of Atomics.wait() and Atomics.notify(), we use a + SharedArrayBuffer with one slot reserved for each of the API + proxy's methods. The sync side of the API uses Atomics.wait() + on the corresponding slot and the async side uses + Atomics.notify() on that slot. - /** - Returns true if _this_ thread has access to the OPFS APIs. + The approach of using a single SAB to serialize comms for all + instances might(?) lead to deadlock situations in multi-db + cases. We should probably have one SAB here with a single slot + for locking a per-file initialization step and then allocate a + separate SAB like the above one for each file. That will + require a bit of acrobatics but should be feasible. The most + problematic part is that xOpen() would have to use + postMessage() to communicate its SharedArrayBuffer, and mixing + that approach with Atomics.wait/notify() gets a bit messy. */ - const thisThreadHasOPFS = ()=>{ - return globalThis.FileSystemHandle && - globalThis.FileSystemDirectoryHandle && - globalThis.FileSystemFileHandle && - globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle && - navigator?.storage?.getDirectory; - }; + const state = Object.create(null); + const metrics = Object.create(null); +//#define opfs-has-metrics +//#include api/opfs-common-inline.c-pp.js +//#undef opfs-has-metrics - /** - Not part of the public API. Solely for internal/development - use. - */ - opfsUtil.metrics = { + const vfsMetrics = { dump: function(){ let k, n = 0, t = 0, w = 0; for(k in state.opIds){ @@ -254,29 +239,7 @@ const installOpfsVfs = function callee(options){ environment or the other when sqlite3_os_end() is called (_if_ it gets called at all in a wasm build, which is undefined). */ - /** - State which we send to the async-api Worker or share with it. - This object must initially contain only cloneable or sharable - objects. After the worker's "inited" message arrives, other types - of data may be added to it. - - For purposes of Atomics.wait() and Atomics.notify(), we use a - SharedArrayBuffer with one slot reserved for each of the API - proxy's methods. The sync side of the API uses Atomics.wait() - on the corresponding slot and the async side uses - Atomics.notify() on that slot. - The approach of using a single SAB to serialize comms for all - instances might(?) lead to deadlock situations in multi-db - cases. We should probably have one SAB here with a single slot - for locking a per-file initialization step and then allocate a - separate SAB like the above one for each file. That will - require a bit of acrobatics but should be feasible. The most - problematic part is that xOpen() would have to use - postMessage() to communicate its SharedArrayBuffer, and mixing - that approach with Atomics.wait/notify() gets a bit messy. - */ - const state = Object.create(null); state.verbose = options.verbose; state.littleEndian = (()=>{ const buffer = new ArrayBuffer(2); @@ -331,7 +294,6 @@ const installOpfsVfs = function callee(options){ + state.sabS11nSize/* argument/result serialization block */ ); state.opIds = Object.create(null); - const metrics = Object.create(null); { /* Indexes for use in our SharedArrayBuffer... */ let i = 0; @@ -378,7 +340,7 @@ const installOpfsVfs = function callee(options){ state.sabOP = new SharedArrayBuffer( i * 4/* ==sizeof int32, noting that Atomics.wait() and friends can only function on Int32Array views of an SAB. */); - opfsUtil.metrics.reset(); + vfsMetrics.reset(); } /** SQLITE_xxx constants to export to the async worker @@ -499,6 +461,7 @@ const installOpfsVfs = function callee(options){ return rc; }; +//#if nope /** Not part of the public API. Only for test/development use. */ @@ -512,35 +475,7 @@ const installOpfsVfs = function callee(options){ W.postMessage({type: 'opfs-async-restart'}); } }; - -//#define opfs-has-metrics -//#include api/opfs-common.c-pp.js - - /** - Generates a random ASCII string len characters long, intended for - use as a temporary file name. - */ - const randomFilename = function f(len=16){ - if(!f._chars){ - f._chars = "abcdefghijklmnopqrstuvwxyz"+ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+ - "012346789"; - f._n = f._chars.length; - } - const a = []; - let i = 0; - for( ; i < len; ++i){ - const ndx = Math.random() * (f._n * 64) % f._n | 0; - a[i] = f._chars[ndx]; - } - return a.join(""); - /* - An alternative impl. with an unpredictable length - but much simpler: - - Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36) - */ - }; +//#endif /** Map of sqlite3_file pointers to objects constructed by xOpen(). @@ -770,7 +705,7 @@ const installOpfsVfs = function callee(options){ mTimeStart('xOpen'); let opfsFlags = 0; if(0===zName){ - zName = randomFilename(); + zName = opfsUtil.randomFilename(); }else if(wasm.isPtr(zName)){ if(capi.sqlite3_uri_boolean(zName, "opfs-unlock-asap", 0)){ /* -----------------------^^^^^ MUST pass the untranslated @@ -832,322 +767,6 @@ const installOpfsVfs = function callee(options){ }; } - /** - Expects an OPFS file path. It gets resolved, such that ".." - components are properly expanded, and returned. If the 2nd arg - is true, the result is returned as an array of path elements, - else an absolute path string is returned. - */ - opfsUtil.getResolvedPath = function(filename,splitIt){ - const p = new URL(filename, "file://irrelevant").pathname; - return splitIt ? p.split('/').filter((v)=>!!v) : p; - }; - - /** - Takes the absolute path to a filesystem element. Returns an - array of [handleOfContainingDir, filename]. If the 2nd argument - is truthy then each directory element leading to the file is - created along the way. Throws if any creation or resolution - fails. - */ - opfsUtil.getDirForFilename = async function f(absFilename, createDirs = false){ - const path = opfsUtil.getResolvedPath(absFilename, true); - const filename = path.pop(); - let dh = opfsUtil.rootDirectory; - for(const dirName of path){ - if(dirName){ - dh = await dh.getDirectoryHandle(dirName, {create: !!createDirs}); - } - } - return [dh, filename]; - }; - - /** - Creates the given directory name, recursively, in - the OPFS filesystem. Returns true if it succeeds or the - directory already exists, else false. - */ - opfsUtil.mkdir = async function(absDirName){ - try { - await opfsUtil.getDirForFilename(absDirName+"/filepart", true); - return true; - }catch(e){ - //sqlite3.config.warn("mkdir(",absDirName,") failed:",e); - return false; - } - }; - /** - Checks whether the given OPFS filesystem entry exists, - returning true if it does, false if it doesn't or if an - exception is intercepted while trying to make the - determination. - */ - opfsUtil.entryExists = async function(fsEntryName){ - try { - const [dh, fn] = await opfsUtil.getDirForFilename(fsEntryName); - await dh.getFileHandle(fn); - return true; - }catch(e){ - return false; - } - }; - - /** - Generates a random ASCII string, intended for use as a - temporary file name. Its argument is the length of the string, - defaulting to 16. - */ - opfsUtil.randomFilename = randomFilename; - - /** - Returns a promise which resolves to an object which represents - all files and directories in the OPFS tree. The top-most object - has two properties: `dirs` is an array of directory entries - (described below) and `files` is a list of file names for all - files in that directory. - - Traversal starts at sqlite3.opfs.rootDirectory. - - Each `dirs` entry is an object in this form: - - ``` - { name: directoryName, - dirs: [...subdirs], - files: [...file names] - } - ``` - - The `files` and `subdirs` entries are always set but may be - empty arrays. - - The returned object has the same structure but its `name` is - an empty string. All returned objects are created with - Object.create(null), so have no prototype. - - Design note: the entries do not contain more information, - e.g. file sizes, because getting such info is not only - expensive but is subject to locking-related errors. - */ - opfsUtil.treeList = async function(){ - const doDir = async function callee(dirHandle,tgt){ - tgt.name = dirHandle.name; - tgt.dirs = []; - tgt.files = []; - for await (const handle of dirHandle.values()){ - if('directory' === handle.kind){ - const subDir = Object.create(null); - tgt.dirs.push(subDir); - await callee(handle, subDir); - }else{ - tgt.files.push(handle.name); - } - } - }; - const root = Object.create(null); - await doDir(opfsUtil.rootDirectory, root); - return root; - }; - - /** - Irrevocably deletes _all_ files in the current origin's OPFS. - Obviously, this must be used with great caution. It may throw - an exception if removal of anything fails (e.g. a file is - locked), but the precise conditions under which the underlying - APIs will throw are not documented (so we cannot tell you what - they are). - */ - opfsUtil.rmfr = async function(){ - const dir = opfsUtil.rootDirectory, opt = {recurse: true}; - for await (const handle of dir.values()){ - dir.removeEntry(handle.name, opt); - } - }; - - /** - Deletes the given OPFS filesystem entry. As this environment - has no notion of "current directory", the given name must be an - absolute path. If the 2nd argument is truthy, deletion is - recursive (use with caution!). - - The returned Promise resolves to true if the deletion was - successful, else false (but...). The OPFS API reports the - reason for the failure only in human-readable form, not - exceptions which can be type-checked to determine the - failure. Because of that... - - If the final argument is truthy then this function will - propagate any exception on error, rather than returning false. - */ - opfsUtil.unlink = async function(fsEntryName, recursive = false, - throwOnError = false){ - try { - const [hDir, filenamePart] = - await opfsUtil.getDirForFilename(fsEntryName, false); - await hDir.removeEntry(filenamePart, {recursive}); - return true; - }catch(e){ - if(throwOnError){ - throw new Error("unlink(",arguments[0],") failed: "+e.message,{ - cause: e - }); - } - return false; - } - }; - - /** - Traverses the OPFS filesystem, calling a callback for each - entry. The argument may be either a callback function or an - options object with any of the following properties: - - - `callback`: function which gets called for each filesystem - entry. It gets passed 3 arguments: 1) the - FileSystemFileHandle or FileSystemDirectoryHandle of each - entry (noting that both are instanceof FileSystemHandle). 2) - the FileSystemDirectoryHandle of the parent directory. 3) the - current depth level, with 0 being at the top of the tree - relative to the starting directory. If the callback returns a - literal false, as opposed to any other falsy value, traversal - stops without an error. Any exceptions it throws are - propagated. Results are undefined if the callback manipulate - the filesystem (e.g. removing or adding entries) because the - how OPFS iterators behave in the face of such changes is - undocumented. - - - `recursive` [bool=true]: specifies whether to recurse into - subdirectories or not. Whether recursion is depth-first or - breadth-first is unspecified! - - - `directory` [FileSystemDirectoryEntry=sqlite3.opfs.rootDirectory] - specifies the starting directory. - - If this function is passed a function, it is assumed to be the - callback. - - Returns a promise because it has to (by virtue of being async) - but that promise has no specific meaning: the traversal it - performs is synchronous. The promise must be used to catch any - exceptions propagated by the callback, however. - */ - opfsUtil.traverse = async function(opt){ - const defaultOpt = { - recursive: true, - directory: opfsUtil.rootDirectory - }; - if('function'===typeof opt){ - opt = {callback:opt}; - } - opt = Object.assign(defaultOpt, opt||{}); - const doDir = async function callee(dirHandle, depth){ - for await (const handle of dirHandle.values()){ - if(false === opt.callback(handle, dirHandle, depth)) return false; - else if(opt.recursive && 'directory' === handle.kind){ - if(false === await callee(handle, depth + 1)) break; - } - } - }; - doDir(opt.directory, 0); - }; - - /** - impl of importDb() when it's given a function as its second - argument. - */ - const importDbChunked = async function(filename, callback){ - const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true); - const hFile = await hDir.getFileHandle(fnamePart, {create:true}); - let sah = await hFile.createSyncAccessHandle(); - let nWrote = 0, chunk, checkedHeader = false, err = false; - try{ - sah.truncate(0); - while( undefined !== (chunk = await callback()) ){ - if(chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk); - if( !checkedHeader && 0===nWrote && chunk.byteLength>=15 ){ - util.affirmDbHeader(chunk); - checkedHeader = true; - } - sah.write(chunk, {at: nWrote}); - nWrote += chunk.byteLength; - } - if( nWrote < 512 || 0!==nWrote % 512 ){ - toss("Input size",nWrote,"is not correct for an SQLite database."); - } - if( !checkedHeader ){ - const header = new Uint8Array(20); - sah.read( header, {at: 0} ); - util.affirmDbHeader( header ); - } - sah.write(new Uint8Array([1,1]), {at: 18}/*force db out of WAL mode*/); - return nWrote; - }catch(e){ - await sah.close(); - sah = undefined; - await hDir.removeEntry( fnamePart ).catch(()=>{}); - throw e; - }finally { - if( sah ) await sah.close(); - } - }; - - /** - Asynchronously imports the given bytes (a byte array or - ArrayBuffer) into the given database file. - - Results are undefined if the given db name refers to an opened - db. - - If passed a function for its second argument, its behaviour - changes: imports its data in chunks fed to it by the given - callback function. It calls the callback (which may be async) - repeatedly, expecting either a Uint8Array or ArrayBuffer (to - denote new input) or undefined (to denote EOF). For so long as - the callback continues to return non-undefined, it will append - incoming data to the given VFS-hosted database file. When - called this way, the resolved value of the returned Promise is - the number of bytes written to the target file. - - It very specifically requires the input to be an SQLite3 - database and throws if that's not the case. It does so in - order to prevent this function from taking on a larger scope - than it is specifically intended to. i.e. we do not want it to - become a convenience for importing arbitrary files into OPFS. - - This routine rewrites the database header bytes in the output - file (not the input array) to force disabling of WAL mode. - - On error this throws and the state of the input file is - undefined (it depends on where the exception was triggered). - - On success, resolves to the number of bytes written. - */ - opfsUtil.importDb = async function(filename, bytes){ - if( bytes instanceof Function ){ - return importDbChunked(filename, bytes); - } - if(bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); - util.affirmIsDb(bytes); - const n = bytes.byteLength; - const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true); - let sah, err, nWrote = 0; - try { - const hFile = await hDir.getFileHandle(fnamePart, {create:true}); - sah = await hFile.createSyncAccessHandle(); - sah.truncate(0); - nWrote = sah.write(bytes, {at: 0}); - if(nWrote != n){ - toss("Expected to write "+n+" bytes but wrote "+nWrote+"."); - } - sah.write(new Uint8Array([1,1]), {at: 18}) /* force db out of WAL mode */; - return nWrote; - }catch(e){ - if( sah ){ await sah.close(); sah = undefined; } - await hDir.removeEntry( fnamePart ).catch(()=>{}); - throw e; - }finally{ - if( sah ) await sah.close(); - } - }; - if(sqlite3.oo1){ const OpfsWlDb = function(...args){ const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); @@ -1270,13 +889,11 @@ const installOpfsVfs = function callee(options){ warn("Running sanity checks because of opfs-sanity-check URL arg..."); sanityCheck(); } - if(thisThreadHasOPFS()){ - navigator.storage.getDirectory().then((d)=>{ + if(opfsUtil.thisThreadHasOPFS()){ + opfsUtil.getRootDir().then((d)=>{ W.onerror = W._originalOnError; delete W._originalOnError; - //sqlite3.opfs = opfsUtil; - opfsUtil.rootDirectory = d; - log("End of OPFS sqlite3_vfs setup.", opfsVfs); + log("End of OPFS-WL sqlite3_vfs setup.", opfsVfs); promiseResolve(); }).catch(promiseReject); }else{ @@ -1301,22 +918,22 @@ const installOpfsVfs = function callee(options){ }/*W.onmessage()*/; })/*thePromise*/; return thePromise; -}/*installOpfsVfs()*/; -installOpfsVfs.defaultProxyUri = +}/*installOpfsWlVfs()*/; +installOpfsWlVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ try{ - let proxyJs = installOpfsVfs.defaultProxyUri; + let proxyJs = installOpfsWlVfs.defaultProxyUri; if( sqlite3?.scriptInfo?.sqlite3Dir ){ - installOpfsVfs.defaultProxyUri = + installOpfsWlVfs.defaultProxyUri = sqlite3.scriptInfo.sqlite3Dir + proxyJs; - //sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri); + //sqlite3.config.warn("installOpfsWlVfs.defaultProxyUri =",installOpfsWlVfs.defaultProxyUri); } - return installOpfsVfs().catch((e)=>{ - sqlite3.config.warn("Ignoring inability to install OPFS sqlite3_vfs:",e.message); + return installOpfsWlVfs().catch((e)=>{ + sqlite3.config.warn("Ignoring inability to install OPFS-WL sqlite3_vfs:",e.message); }); }catch(e){ - sqlite3.config.error("installOpfsVfs() exception:",e); + sqlite3.config.error("installOpfsWlVfs() exception:",e); return Promise.reject(e); } }); diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 216cd83a2a..7ba7427d0a 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -20,7 +20,10 @@ */ 'use strict'; globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ -/** + const opfsUtil = sqlite3.opfs || sqlite3.util.toss("Missing sqlite3.opfs") + /* Gets removed from sqlite3 during bootstrap, so we need an + early reference to it. */; + /** installOpfsVfs() returns a Promise which, on success, installs an sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs which accept a VFS. It is intended to be called via @@ -74,30 +77,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ object. */ const installOpfsVfs = function callee(options){ - if(!globalThis.SharedArrayBuffer - || !globalThis.Atomics){ - return Promise.reject( - new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. "+ - "The server must emit the COOP/COEP response headers to enable those. "+ - "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep") - ); - }else if('undefined'===typeof WorkerGlobalScope){ - return Promise.reject( - new Error("The OPFS sqlite3_vfs cannot run in the main thread "+ - "because it requires Atomics.wait().") - ); - }else if(!globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || - !navigator?.storage?.getDirectory){ - return Promise.reject( - new Error("Missing required OPFS APIs.") - ); - } - if(!options || 'object'!==typeof options){ - options = Object.create(null); + try{ + opfsUtil.vfsInstallationFeatureCheck(); + }catch(e){ + return Promise.reject(e); } + options = Object.assign(Object.create(null), options); const urlParams = new URL(globalThis.location.href).searchParams; if(urlParams.has('opfs-disable')){ //sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.'); @@ -113,12 +98,10 @@ const installOpfsVfs = function callee(options){ if(undefined===options.proxyUri){ options.proxyUri = callee.defaultProxyUri; } - - //sqlite3.config.warn("OPFS options =",options,globalThis.location); - if('function' === typeof options.proxyUri){ options.proxyUri = options.proxyUri(); } + //sqlite3.config.warn("OPFS options =",options,globalThis.location); const thePromise = new Promise(function(promiseResolve_, promiseReject_){ const loggers = [ sqlite3.config.error, @@ -138,32 +121,36 @@ const installOpfsVfs = function callee(options){ const sqlite3_vfs = capi.sqlite3_vfs; const sqlite3_file = capi.sqlite3_file; const sqlite3_io_methods = capi.sqlite3_io_methods; + /** - Generic utilities for working with OPFS. This will get filled out - by the Promise setup and, on success, installed as sqlite3.opfs. + State which we send to the async-api Worker or share with it. + This object must initially contain only cloneable or sharable + objects. After the worker's "inited" message arrives, other types + of data may be added to it. - ACHTUNG: do not rely on these APIs in client code. They are - experimental and subject to change or removal as the - OPFS-specific sqlite3_vfs evolves. - */ - const opfsUtil = Object.create(null); + For purposes of Atomics.wait() and Atomics.notify(), we use a + SharedArrayBuffer with one slot reserved for each of the API + proxy's methods. The sync side of the API uses Atomics.wait() + on the corresponding slot and the async side uses + Atomics.notify() on that slot. - /** - Returns true if _this_ thread has access to the OPFS APIs. + The approach of using a single SAB to serialize comms for all + instances might(?) lead to deadlock situations in multi-db + cases. We should probably have one SAB here with a single slot + for locking a per-file initialization step and then allocate a + separate SAB like the above one for each file. That will + require a bit of acrobatics but should be feasible. The most + problematic part is that xOpen() would have to use + postMessage() to communicate its SharedArrayBuffer, and mixing + that approach with Atomics.wait/notify() gets a bit messy. */ - const thisThreadHasOPFS = ()=>{ - return globalThis.FileSystemHandle && - globalThis.FileSystemDirectoryHandle && - globalThis.FileSystemFileHandle && - globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle && - navigator?.storage?.getDirectory; - }; + const state = Object.create(null); + const metrics = Object.create(null); +//#define opfs-has-metrics +//#include api/opfs-common-inline.c-pp.js +//#undef opfs-has-metrics - /** - Not part of the public API. Solely for internal/development - use. - */ - opfsUtil.metrics = { + const vfsMetrics = { dump: function(){ let k, n = 0, t = 0, w = 0; for(k in state.opIds){ @@ -264,29 +251,6 @@ const installOpfsVfs = function callee(options){ environment or the other when sqlite3_os_end() is called (_if_ it gets called at all in a wasm build, which is undefined). */ - /** - State which we send to the async-api Worker or share with it. - This object must initially contain only cloneable or sharable - objects. After the worker's "inited" message arrives, other types - of data may be added to it. - - For purposes of Atomics.wait() and Atomics.notify(), we use a - SharedArrayBuffer with one slot reserved for each of the API - proxy's methods. The sync side of the API uses Atomics.wait() - on the corresponding slot and the async side uses - Atomics.notify() on that slot. - - The approach of using a single SAB to serialize comms for all - instances might(?) lead to deadlock situations in multi-db - cases. We should probably have one SAB here with a single slot - for locking a per-file initialization step and then allocate a - separate SAB like the above one for each file. That will - require a bit of acrobatics but should be feasible. The most - problematic part is that xOpen() would have to use - postMessage() to communicate its SharedArrayBuffer, and mixing - that approach with Atomics.wait/notify() gets a bit messy. - */ - const state = Object.create(null); state.verbose = options.verbose; state.littleEndian = (()=>{ const buffer = new ArrayBuffer(2); @@ -341,7 +305,6 @@ const installOpfsVfs = function callee(options){ + state.sabS11nSize/* argument/result serialization block */ ); state.opIds = Object.create(null); - const metrics = Object.create(null); { /* Indexes for use in our SharedArrayBuffer... */ let i = 0; @@ -379,7 +342,7 @@ const installOpfsVfs = function callee(options){ state.sabOP = new SharedArrayBuffer( i * 4/* ==sizeof int32, noting that Atomics.wait() and friends can only function on Int32Array views of an SAB. */); - opfsUtil.metrics.reset(); + vfsMetrics.reset(); } /** SQLITE_xxx constants to export to the async worker @@ -495,6 +458,7 @@ const installOpfsVfs = function callee(options){ return rc; }; +//#if nope /** Not part of the public API. Only for test/development use. */ @@ -508,35 +472,7 @@ const installOpfsVfs = function callee(options){ W.postMessage({type: 'opfs-async-restart'}); } }; - -//#define opfs-has-metrics -//#include api/opfs-common.c-pp.js - - /** - Generates a random ASCII string len characters long, intended for - use as a temporary file name. - */ - const randomFilename = function f(len=16){ - if(!f._chars){ - f._chars = "abcdefghijklmnopqrstuvwxyz"+ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+ - "012346789"; - f._n = f._chars.length; - } - const a = []; - let i = 0; - for( ; i < len; ++i){ - const ndx = Math.random() * (f._n * 64) % f._n | 0; - a[i] = f._chars[ndx]; - } - return a.join(""); - /* - An alternative impl. with an unpredictable length - but much simpler: - - Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36) - */ - }; +//#endif /** Map of sqlite3_file pointers to objects constructed by xOpen(). @@ -743,7 +679,7 @@ const installOpfsVfs = function callee(options){ mTimeStart('xOpen'); let opfsFlags = 0; if(0===zName){ - zName = randomFilename(); + zName = opfsUtil.randomFilename(); }else if(wasm.isPtr(zName)){ if(capi.sqlite3_uri_boolean(zName, "opfs-unlock-asap", 0)){ /* -----------------------^^^^^ MUST pass the untranslated @@ -805,322 +741,6 @@ const installOpfsVfs = function callee(options){ }; } - /** - Expects an OPFS file path. It gets resolved, such that ".." - components are properly expanded, and returned. If the 2nd arg - is true, the result is returned as an array of path elements, - else an absolute path string is returned. - */ - opfsUtil.getResolvedPath = function(filename,splitIt){ - const p = new URL(filename, "file://irrelevant").pathname; - return splitIt ? p.split('/').filter((v)=>!!v) : p; - }; - - /** - Takes the absolute path to a filesystem element. Returns an - array of [handleOfContainingDir, filename]. If the 2nd argument - is truthy then each directory element leading to the file is - created along the way. Throws if any creation or resolution - fails. - */ - opfsUtil.getDirForFilename = async function f(absFilename, createDirs = false){ - const path = opfsUtil.getResolvedPath(absFilename, true); - const filename = path.pop(); - let dh = opfsUtil.rootDirectory; - for(const dirName of path){ - if(dirName){ - dh = await dh.getDirectoryHandle(dirName, {create: !!createDirs}); - } - } - return [dh, filename]; - }; - - /** - Creates the given directory name, recursively, in - the OPFS filesystem. Returns true if it succeeds or the - directory already exists, else false. - */ - opfsUtil.mkdir = async function(absDirName){ - try { - await opfsUtil.getDirForFilename(absDirName+"/filepart", true); - return true; - }catch(e){ - //sqlite3.config.warn("mkdir(",absDirName,") failed:",e); - return false; - } - }; - /** - Checks whether the given OPFS filesystem entry exists, - returning true if it does, false if it doesn't or if an - exception is intercepted while trying to make the - determination. - */ - opfsUtil.entryExists = async function(fsEntryName){ - try { - const [dh, fn] = await opfsUtil.getDirForFilename(fsEntryName); - await dh.getFileHandle(fn); - return true; - }catch(e){ - return false; - } - }; - - /** - Generates a random ASCII string, intended for use as a - temporary file name. Its argument is the length of the string, - defaulting to 16. - */ - opfsUtil.randomFilename = randomFilename; - - /** - Returns a promise which resolves to an object which represents - all files and directories in the OPFS tree. The top-most object - has two properties: `dirs` is an array of directory entries - (described below) and `files` is a list of file names for all - files in that directory. - - Traversal starts at sqlite3.opfs.rootDirectory. - - Each `dirs` entry is an object in this form: - - ``` - { name: directoryName, - dirs: [...subdirs], - files: [...file names] - } - ``` - - The `files` and `subdirs` entries are always set but may be - empty arrays. - - The returned object has the same structure but its `name` is - an empty string. All returned objects are created with - Object.create(null), so have no prototype. - - Design note: the entries do not contain more information, - e.g. file sizes, because getting such info is not only - expensive but is subject to locking-related errors. - */ - opfsUtil.treeList = async function(){ - const doDir = async function callee(dirHandle,tgt){ - tgt.name = dirHandle.name; - tgt.dirs = []; - tgt.files = []; - for await (const handle of dirHandle.values()){ - if('directory' === handle.kind){ - const subDir = Object.create(null); - tgt.dirs.push(subDir); - await callee(handle, subDir); - }else{ - tgt.files.push(handle.name); - } - } - }; - const root = Object.create(null); - await doDir(opfsUtil.rootDirectory, root); - return root; - }; - - /** - Irrevocably deletes _all_ files in the current origin's OPFS. - Obviously, this must be used with great caution. It may throw - an exception if removal of anything fails (e.g. a file is - locked), but the precise conditions under which the underlying - APIs will throw are not documented (so we cannot tell you what - they are). - */ - opfsUtil.rmfr = async function(){ - const dir = opfsUtil.rootDirectory, opt = {recurse: true}; - for await (const handle of dir.values()){ - dir.removeEntry(handle.name, opt); - } - }; - - /** - Deletes the given OPFS filesystem entry. As this environment - has no notion of "current directory", the given name must be an - absolute path. If the 2nd argument is truthy, deletion is - recursive (use with caution!). - - The returned Promise resolves to true if the deletion was - successful, else false (but...). The OPFS API reports the - reason for the failure only in human-readable form, not - exceptions which can be type-checked to determine the - failure. Because of that... - - If the final argument is truthy then this function will - propagate any exception on error, rather than returning false. - */ - opfsUtil.unlink = async function(fsEntryName, recursive = false, - throwOnError = false){ - try { - const [hDir, filenamePart] = - await opfsUtil.getDirForFilename(fsEntryName, false); - await hDir.removeEntry(filenamePart, {recursive}); - return true; - }catch(e){ - if(throwOnError){ - throw new Error("unlink(",arguments[0],") failed: "+e.message,{ - cause: e - }); - } - return false; - } - }; - - /** - Traverses the OPFS filesystem, calling a callback for each - entry. The argument may be either a callback function or an - options object with any of the following properties: - - - `callback`: function which gets called for each filesystem - entry. It gets passed 3 arguments: 1) the - FileSystemFileHandle or FileSystemDirectoryHandle of each - entry (noting that both are instanceof FileSystemHandle). 2) - the FileSystemDirectoryHandle of the parent directory. 3) the - current depth level, with 0 being at the top of the tree - relative to the starting directory. If the callback returns a - literal false, as opposed to any other falsy value, traversal - stops without an error. Any exceptions it throws are - propagated. Results are undefined if the callback manipulate - the filesystem (e.g. removing or adding entries) because the - how OPFS iterators behave in the face of such changes is - undocumented. - - - `recursive` [bool=true]: specifies whether to recurse into - subdirectories or not. Whether recursion is depth-first or - breadth-first is unspecified! - - - `directory` [FileSystemDirectoryEntry=sqlite3.opfs.rootDirectory] - specifies the starting directory. - - If this function is passed a function, it is assumed to be the - callback. - - Returns a promise because it has to (by virtue of being async) - but that promise has no specific meaning: the traversal it - performs is synchronous. The promise must be used to catch any - exceptions propagated by the callback, however. - */ - opfsUtil.traverse = async function(opt){ - const defaultOpt = { - recursive: true, - directory: opfsUtil.rootDirectory - }; - if('function'===typeof opt){ - opt = {callback:opt}; - } - opt = Object.assign(defaultOpt, opt||{}); - const doDir = async function callee(dirHandle, depth){ - for await (const handle of dirHandle.values()){ - if(false === opt.callback(handle, dirHandle, depth)) return false; - else if(opt.recursive && 'directory' === handle.kind){ - if(false === await callee(handle, depth + 1)) break; - } - } - }; - doDir(opt.directory, 0); - }; - - /** - impl of importDb() when it's given a function as its second - argument. - */ - const importDbChunked = async function(filename, callback){ - const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true); - const hFile = await hDir.getFileHandle(fnamePart, {create:true}); - let sah = await hFile.createSyncAccessHandle(); - let nWrote = 0, chunk, checkedHeader = false, err = false; - try{ - sah.truncate(0); - while( undefined !== (chunk = await callback()) ){ - if(chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk); - if( !checkedHeader && 0===nWrote && chunk.byteLength>=15 ){ - util.affirmDbHeader(chunk); - checkedHeader = true; - } - sah.write(chunk, {at: nWrote}); - nWrote += chunk.byteLength; - } - if( nWrote < 512 || 0!==nWrote % 512 ){ - toss("Input size",nWrote,"is not correct for an SQLite database."); - } - if( !checkedHeader ){ - const header = new Uint8Array(20); - sah.read( header, {at: 0} ); - util.affirmDbHeader( header ); - } - sah.write(new Uint8Array([1,1]), {at: 18}/*force db out of WAL mode*/); - return nWrote; - }catch(e){ - await sah.close(); - sah = undefined; - await hDir.removeEntry( fnamePart ).catch(()=>{}); - throw e; - }finally { - if( sah ) await sah.close(); - } - }; - - /** - Asynchronously imports the given bytes (a byte array or - ArrayBuffer) into the given database file. - - Results are undefined if the given db name refers to an opened - db. - - If passed a function for its second argument, its behaviour - changes: imports its data in chunks fed to it by the given - callback function. It calls the callback (which may be async) - repeatedly, expecting either a Uint8Array or ArrayBuffer (to - denote new input) or undefined (to denote EOF). For so long as - the callback continues to return non-undefined, it will append - incoming data to the given VFS-hosted database file. When - called this way, the resolved value of the returned Promise is - the number of bytes written to the target file. - - It very specifically requires the input to be an SQLite3 - database and throws if that's not the case. It does so in - order to prevent this function from taking on a larger scope - than it is specifically intended to. i.e. we do not want it to - become a convenience for importing arbitrary files into OPFS. - - This routine rewrites the database header bytes in the output - file (not the input array) to force disabling of WAL mode. - - On error this throws and the state of the input file is - undefined (it depends on where the exception was triggered). - - On success, resolves to the number of bytes written. - */ - opfsUtil.importDb = async function(filename, bytes){ - if( bytes instanceof Function ){ - return importDbChunked(filename, bytes); - } - if(bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes); - util.affirmIsDb(bytes); - const n = bytes.byteLength; - const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true); - let sah, err, nWrote = 0; - try { - const hFile = await hDir.getFileHandle(fnamePart, {create:true}); - sah = await hFile.createSyncAccessHandle(); - sah.truncate(0); - nWrote = sah.write(bytes, {at: 0}); - if(nWrote != n){ - toss("Expected to write "+n+" bytes but wrote "+nWrote+"."); - } - sah.write(new Uint8Array([1,1]), {at: 18}) /* force db out of WAL mode */; - return nWrote; - }catch(e){ - if( sah ){ await sah.close(); sah = undefined; } - await hDir.removeEntry( fnamePart ).catch(()=>{}); - throw e; - }finally{ - if( sah ) await sah.close(); - } - }; - if(sqlite3.oo1){ const OpfsDb = function(...args){ const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); @@ -1241,12 +861,10 @@ const installOpfsVfs = function callee(options){ warn("Running sanity checks because of opfs-sanity-check URL arg..."); sanityCheck(); } - if(thisThreadHasOPFS()){ - navigator.storage.getDirectory().then((d)=>{ + if(opfsUtil.thisThreadHasOPFS()){ + opfsUtil.getRootDir().then((d)=>{ W.onerror = W._originalOnError; delete W._originalOnError; - sqlite3.opfs = opfsUtil; - opfsUtil.rootDirectory = d; log("End of OPFS sqlite3_vfs setup.", opfsVfs); promiseResolve(); }).catch(promiseReject); diff --git a/manifest b/manifest index 037a053c93..f334f15c5a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C A\spotential\sfix\sfor\sthe\sprobable\sbreakage\sof\sbundler-friendly\sbuilds\sin\sthe\sprevious\scheck-in.\sPending\sreview\sfrom\ssomeone\swho\suses\sthose\stools. -D 2026-03-04T00:48:03.758 +C Consolidate\smuch\sof\sthe\sOPFS\sutility\scode\sinto\sa\snew\sfile\sfor\suse\sby\stwo\sof\sthe\sOPFS\sVFSes. +D 2026-03-04T11:37:39.256 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -572,7 +572,7 @@ F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009e F ext/session/sqlite3session.c 6ebd02be470f36d41c4bd78927f39d507b62051ba025eacaed9936c769902a07 F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a F ext/session/test_session.c 190110e3bd9463717248dec1272b44fe9943e57b7646d0b4200dcf11e4dccee6 -F ext/wasm/GNUmakefile a0afdb3e6306997de1e123e8b8270affb744519c9e384dbc277d0af6a6ba1c91 +F ext/wasm/GNUmakefile 4496669ca5785c7bfc7af76565f1dd45e8f9ec7529b58c485fd374088162bef1 F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259 F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff @@ -584,7 +584,8 @@ F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp 7ba933e8f1290cc65459dd371c0c9a031d96bdf14 F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b47244781a7e81 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 -F ext/wasm/api/opfs-common.c-pp.js 5540c58aee8fbbf2c67984e0a35e2b680a7603052f2cc442d407da3cc81c4819 +F ext/wasm/api/opfs-common-inline.c-pp.js b9c4e080698792cbc04ce9dd9dda7d8316c6db0262f74820706f98b352b949d5 w ext/wasm/api/opfs-common.c-pp.js +F ext/wasm/api/opfs-common-shared.c-pp.js 3f8f3f2ab4790fdd1e6d1d9224e232cef07f1c8753827c18bbba965dbe98795f F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -593,12 +594,12 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js ccd8ece4b4580d2a70996218f28e810d70a86f5e2795f4d4a75f0603af24aef6 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 041f24cd61d470072303b0cd1bb73dd2928bf2c96c0fbf3d3f4a39024c4e9ae7 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 25b856508ac94336419133c6ec10594f576b469f85cc69cde4c09cfa06a8e1c7 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 8c79bf3ea89102772225e6539c030787ea85203b6cc0354c545df69d81a2d910 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b2b4c7570ec816c49e7b3293f451992bd7fb7154dcd4cec6fb05d032c6cedf52 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 54f71e563dda30af73ed84ff9de03441537b2e8fb8d2ae2a0b0c8187f51db67a +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 2e2a72a40e2ad6ea92f52eb7adbd925d4acd874ffeecaa00b85234ad49862655 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -2190,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 9a471f7491a371052bf1785098ba966dd0d03503e7d8b9fbcd65f07b038e5021 -R 8aa8acc5e3e3610acfaa4dc12ceb0c5d +P 8ea85776116521526d684f221d67e288126e62931d4a0ea7fc7f164cd2d5b2ec +R 82203270087631af34878be94f4d1594 U stephan -Z dc633fdeffefdb99fdb4ea173110ea63 +Z 1548da853f7a79cab3a86616c1bf35cc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3a2f818401..65aadb1877 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8ea85776116521526d684f221d67e288126e62931d4a0ea7fc7f164cd2d5b2ec +db19a6e9663c3a44996178cb8c35dc4ccd60f48cb4b81b6c214411a56c57def7 From 76e562e2225651f91fbe34d36be76170b3fe8714 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 4 Mar 2026 13:02:08 +0000 Subject: [PATCH 090/197] Fix a code-generator bug introduced by the UNION/INTERSECT/EXISTS optimization of check-in [132ba781b031972c] and reported in [forum:/forumpost/2026-03-04T05:06:26Z|forum post 2026-03-04T05:06:26Z]. FossilOrigin-Name: 6ba7797cac7dc873b62a12be5712511c9199b379342dac4a1887bfd65227a298 --- manifest | 17 ++++++++--------- manifest.uuid | 2 +- src/select.c | 1 - test/with1.test | 19 +++++++++++++++++++ 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index ea0c2eff2d..6dcb09672c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\san\sobscure\srace\scondition\sbetween\sa\scheckpointer\sand\sa\swriter\swrapping\saround\sto\sthe\sstart\sof\sthe\swal\sfile. -D 2026-03-03T19:43:19.771 +C Fix\sa\scode-generator\sbug\sintroduced\sby\sthe\sUNION/INTERSECT/EXISTS\noptimization\sof\scheck-in\s[132ba781b031972c]\sand\sreported\sin\n[forum:/forumpost/2026-03-04T05:06:26Z|forum\spost\s2026-03-04T05:06:26Z]. +D 2026-03-04T13:02:08.305 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -729,7 +729,7 @@ F src/printf.c 9cff219dba73b1aa9a8113e83e962f03f7bea8b6eb51cefb25bc468d5a69fb2d F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c 8fe87c39a45037dac2e3dc02e1dc13ca09c1155cc14df9daaa65e5318179beaf +F src/select.c d739fb0ac7e632327b9fb4a1ac46629ec93f5e3438943df813f230f7822c56ab F src/shell.c.in 2acdfca982deb70cdfefb8b422822d4e0234fe4dde6ff2bd9020b26445853917 F src/sqlite.h.in 1f853f1d836af3e5a0b451521041d05658988a45f6978aaae08286e483fee5ac F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 @@ -2074,7 +2074,7 @@ F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387 F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c F test/windowpushd.test c420e2265f0e09a0e798d0513a660d71b51602088d81b3dbd038918ee1339dcc -F test/with1.test 1ee171d7c306ab8b0771f3511d870f56c735607729836585bbceb1fc2f47e0b1 +F test/with1.test 31db84788e0429885b63995149fab57d32e26196b752a3a926249ae74c0adddd F test/with2.test 181674a6cc86a601ca2ac052741cdfad5b529e07e870435d2f6cdb92d589ff17 F test/with3.test e30369ea27aa27eb1bda4c5e510c8a9f782c8afd2ab99d1a02b8a7f25a5d3e65 F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205 @@ -2189,9 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 88dce64242552e7443d9fb496f6f3ad71dc5b4a882ce21b7ef1d5ea4e26f1e61 703cbb0f760515eac1e6f72a5e5cd928258c71378e4a976082b6518c90128135 -R 081029f3feecf24cb4be31bd4056634e -T +closed 703cbb0f760515eac1e6f72a5e5cd928258c71378e4a976082b6518c90128135 -U dan -Z aa660315ed5ec6682f68be7645c0d8b8 +P 7168988acbec2d8d51106a263e553f8942b8b23d983dbbe5028e0f9be68cbb83 +R 919bab5ba9cb4a7afc21d24bdc3fa2c5 +U drh +Z 463d87a5025767bf46752b6593cc33c4 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5e463bf5c6..171b2c7c09 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7168988acbec2d8d51106a263e553f8942b8b23d983dbbe5028e0f9be68cbb83 +6ba7797cac7dc873b62a12be5712511c9199b379342dac4a1887bfd65227a298 diff --git a/src/select.c b/src/select.c index 62e73a699c..027c776911 100644 --- a/src/select.c +++ b/src/select.c @@ -3268,7 +3268,6 @@ static int generateOutputSubroutine( sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r3); if( pDest->eDest==SRT_DistQueue ){ sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3); - sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); } for(ii=0; ii Date: Wed, 4 Mar 2026 13:08:14 +0000 Subject: [PATCH 091/197] Remove dead (commented-out) code that came to my attention because it ws nearby the fix of the previous check-in. FossilOrigin-Name: 61f8a28591a833b1f5834a347feefeba8414fecc7ff154f1b6ef19963f181812 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/select.c | 17 ----------------- 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index 6dcb09672c..c825abc294 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\scode-generator\sbug\sintroduced\sby\sthe\sUNION/INTERSECT/EXISTS\noptimization\sof\scheck-in\s[132ba781b031972c]\sand\sreported\sin\n[forum:/forumpost/2026-03-04T05:06:26Z|forum\spost\s2026-03-04T05:06:26Z]. -D 2026-03-04T13:02:08.305 +C Remove\sdead\s(commented-out)\scode\sthat\scame\sto\smy\sattention\sbecause\sit\nws\snearby\sthe\sfix\sof\sthe\sprevious\scheck-in. +D 2026-03-04T13:08:14.899 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -729,7 +729,7 @@ F src/printf.c 9cff219dba73b1aa9a8113e83e962f03f7bea8b6eb51cefb25bc468d5a69fb2d F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c d739fb0ac7e632327b9fb4a1ac46629ec93f5e3438943df813f230f7822c56ab +F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576 F src/shell.c.in 2acdfca982deb70cdfefb8b422822d4e0234fe4dde6ff2bd9020b26445853917 F src/sqlite.h.in 1f853f1d836af3e5a0b451521041d05658988a45f6978aaae08286e483fee5ac F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 7168988acbec2d8d51106a263e553f8942b8b23d983dbbe5028e0f9be68cbb83 -R 919bab5ba9cb4a7afc21d24bdc3fa2c5 +P 6ba7797cac7dc873b62a12be5712511c9199b379342dac4a1887bfd65227a298 +R 7127c439ea41ec62f75cef8391656a07 U drh -Z 463d87a5025767bf46752b6593cc33c4 +Z 05c4a0745826c227013aa02b8d852b71 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 171b2c7c09..78bbfcdc32 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6ba7797cac7dc873b62a12be5712511c9199b379342dac4a1887bfd65227a298 +61f8a28591a833b1f5834a347feefeba8414fecc7ff154f1b6ef19963f181812 diff --git a/src/select.c b/src/select.c index 027c776911..e8e9f36a88 100644 --- a/src/select.c +++ b/src/select.c @@ -3251,20 +3251,6 @@ static int generateOutputSubroutine( r2 = sqlite3GetTempRange(pParse, nKey+2); r3 = r2+nKey+1; -#if 0 /* <-- Why the next block of code is commented out: (tag-20260125-a) - ** - ** If the destination is DistQueue, then cursor (iParm+1) is open - ** on a second ephemeral index that holds all values previously - ** added to the queue. This code only runs during the setup phase - ** using the merge algorithm, and so the values here are already - ** guaranteed to be unique. - */ - if( pDest->eDest==SRT_DistQueue ){ - addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0, - pIn->iSdst, pIn->nSdst); - VdbeCoverage(v); - } -#endif sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r3); if( pDest->eDest==SRT_DistQueue ){ sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3); @@ -3277,9 +3263,6 @@ static int generateOutputSubroutine( sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey); sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2); -#if 0 /* tag-20260125-a */ - if( addrTest ) sqlite3VdbeJumpHere(v, addrTest); -#endif sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempRange(pParse, r2, nKey+2); break; From 6ff9fcfad25f5eaab13c0e2a7a73fd4eecadf737 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 4 Mar 2026 14:33:33 +0000 Subject: [PATCH 092/197] Baby steps in consolidating common OPFS VFS code. FossilOrigin-Name: b0dd23299e97ff975f213cb3a8b051f4d7b785b29def82e01f53427fdf77ecb6 --- ext/wasm/api/opfs-common-inline.c-pp.js | 11 +- ext/wasm/api/opfs-common-shared.c-pp.js | 232 ++++++++++++- ext/wasm/api/sqlite3-api-prologue.js | 1 + ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 2 +- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 308 +++--------------- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 239 +++----------- manifest | 22 +- manifest.uuid | 2 +- 8 files changed, 337 insertions(+), 480 deletions(-) diff --git a/ext/wasm/api/opfs-common-inline.c-pp.js b/ext/wasm/api/opfs-common-inline.c-pp.js index dcff8a05bd..04ae17d555 100644 --- a/ext/wasm/api/opfs-common-inline.c-pp.js +++ b/ext/wasm/api/opfs-common-inline.c-pp.js @@ -8,6 +8,8 @@ but which has a 99% identical structure for each. */ //#endif +//#// vfs.metrics.enable is a refactoring crutch. +//#define vfs.metrics.enable=0 const initS11n = function(){ /** This proxy de/serializes cross-thread function arguments and @@ -88,7 +90,7 @@ const initS11n = function(){ is cleared after deserialization. */ state.s11n.deserialize = function(clear=false){ -//#if defined opfs-has-metrics +//#if vfs.metrics.enable ++metrics.s11n.deserialize.count; //#endif const t = performance.now(); @@ -116,7 +118,7 @@ const initS11n = function(){ } if(clear) viewU8[0] = 0; //log("deserialize:",argc, rc); -//#if defined opfs-has-metrics +//#if vfs.metrics.enable metrics.s11n.deserialize.time += performance.now() - t; //#endif return rc; @@ -136,7 +138,7 @@ const initS11n = function(){ */ state.s11n.serialize = function(...args){ const t = performance.now(); -//#if defined opfs-has-metrics +//#if vfs.metrics.enable ++metrics.s11n.serialize.count; //#endif if(args.length){ @@ -169,7 +171,7 @@ const initS11n = function(){ }else{ viewU8[0] = 0; } -//#if defined opfs-has-metrics +//#if vfs.metrics.enable metrics.s11n.serialize.time += performance.now() - t; //#endif }; @@ -185,4 +187,5 @@ const initS11n = function(){ //#endif return state.s11n; +//#undef vfs.metrics.enable }/*initS11n()*/; diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 56af5585bc..077f4c5a6a 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -19,7 +19,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'use strict'; const toss = sqlite3.util.toss; - const toss3 = sqlite3.util.toss3; const capi = sqlite3.capi; const util = sqlite3.util; const wasm = sqlite3.wasm; @@ -422,9 +421,232 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } }; + /** + Populates the main state object used by "opfs" and "opfs-wl", and + transfered from those to their async counterpart. + + State which we send to the async-api Worker or share with it. + This object must initially contain only cloneable or sharable + objects. After the worker's "inited" message arrives, other types + of data may be added to it. + + For purposes of Atomics.wait() and Atomics.notify(), we use a + SharedArrayBuffer with one slot reserved for each of the API + proxy's methods. The sync side of the API uses Atomics.wait() + on the corresponding slot and the async side uses + Atomics.notify() on that slot. + + The approach of using a single SAB to serialize comms for all + instances might(?) lead to deadlock situations in multi-db + cases. We should probably have one SAB here with a single slot + for locking a per-file initialization step and then allocate a + separate SAB like the above one for each file. That will + require a bit of acrobatics but should be feasible. The most + problematic part is that xOpen() would have to use + postMessage() to communicate its SharedArrayBuffer, and mixing + that approach with Atomics.wait/notify() gets a bit messy. + */ + opfsUtil.createVfsStateObject = function(opfsVfs){ + if( !(opfsVfs instanceof capi.sqlite3_vfs) ){ + toss("Expecting a sqlite3_vfs instance"); + } + const vfsName = wasm.cstrToJs(opfsVfs.$zName); + const isWebLocker = 'opfs-wl'===vfsName; + const state = util.nu(); + /** + asyncIdleWaitTime is how long (ms) to wait, in the async proxy, + for each Atomics.wait() when waiting on inbound VFS API calls. + We need to wake up periodically to give the thread a chance to + do other things. If this is too high (e.g. 500ms) then even two + workers/tabs can easily run into locking errors. Some multiple + of this value is also used for determining how long to wait on + lock contention to free up. + */ + state.asyncIdleWaitTime = isWebLocker ? 100 : 150; + + /** + Whether the async counterpart should log exceptions to + the serialization channel. That produces a great deal of + noise for seemingly innocuous things like xAccess() checks + for missing files, so this option may have one of 3 values: + + 0 = no exception logging. + + 1 = only log exceptions for "significant" ops like xOpen(), + xRead(), and xWrite(). + + 2 = log all exceptions. + */ + state.asyncS11nExceptions = 1; + /* Size of file I/O buffer block. 64k = max sqlite3 page size, and + xRead/xWrite() will never deal in blocks larger than that. */ + state.fileBufferSize = 1024 * 64; + state.sabS11nOffset = state.fileBufferSize; + /** + The size of the block in our SAB for serializing arguments and + result values. Needs to be large enough to hold serialized + values of any of the proxied APIs. Filenames are the largest + part but are limited to opfsVfs.$mxPathname bytes. We also + store exceptions there, so it needs to be long enough to hold + a reasonably long exception string. + */ + state.sabS11nSize = opfsVfs.$mxPathname * 2; + /** + The SAB used for all data I/O between the synchronous and + async halves (file i/o and arg/result s11n). + */ + state.sabIO = new SharedArrayBuffer( + state.fileBufferSize/* file i/o block */ + + state.sabS11nSize/* argument/result serialization block */ + ); + state.opIds = Object.create(null); + { + /* + Maintenance reminder: + + Some of these fields are only for use by the "opfs-wl" VFS, + but they must also be set up for the "ofps" VFS so that the + sizes and offsets calculated here are consistent in the async + proxy. Hypothetically they could differ and it would cope + but... why invite disaster over eliding a few superfluous (for + "opfs') properties? + */ + /* Indexes for use in our SharedArrayBuffer... */ + let i = 0; + /* SAB slot used to communicate which operation is desired + between both workers. This worker writes to it and the other + listens for changes. */ + state.opIds.whichOp = i++; + /* Slot for storing return values. This worker listens to that + slot and the other worker writes to it. */ + state.opIds.rc = i++; + /* Each function gets an ID which this worker writes to + the whichOp slot. The async-api worker uses Atomic.wait() + on the whichOp slot to figure out which operation to run + next. */ + state.opIds.xAccess = i++; + state.opIds.xClose = i++; + state.opIds.xDelete = i++; + state.opIds.xDeleteNoWait = i++; + state.opIds.xFileSize = i++; + state.opIds.xLock = i++; + state.opIds.xOpen = i++; + state.opIds.xRead = i++; + state.opIds.xSleep = i++; + state.opIds.xSync = i++; + state.opIds.xTruncate = i++; + state.opIds.xUnlock = i++; + state.opIds.xWrite = i++; + state.opIds.mkdir = i++; + state.opIds.lockControl = i++ /* opfs-wl signals the intent to lock here */; + /** Internal signals which are used only during development and + testing via the dev console. */ + state.opIds['opfs-async-metrics'] = i++; + state.opIds['opfs-async-shutdown'] = i++; + /* The retry slot is used by the async part for wait-and-retry + semantics. Though we could hypothetically use the xSleep slot + for that, doing so might lead to undesired side effects. */ + state.opIds.retry = i++; + + /* Slots for submitting the lock type and receiving its acknowledgement. + Only used by "opfs-wl". */ + state.lock = util.nu({ + type: i++ /* SQLITE_LOCK_xyz value */, + atomicsHandshake: i++ /* 0=pending, 1=release, 2=granted */ + }); + state.sabOP = new SharedArrayBuffer( + i * 4/* ==sizeof int32, noting that Atomics.wait() and friends + can only function on Int32Array views of an SAB. */); + } + /** + SQLITE_xxx constants to export to the async worker + counterpart... + */ + state.sq3Codes = Object.create(null); + [ + 'SQLITE_ACCESS_EXISTS', + 'SQLITE_ACCESS_READWRITE', + 'SQLITE_BUSY', + 'SQLITE_CANTOPEN', + 'SQLITE_ERROR', + 'SQLITE_IOERR', + 'SQLITE_IOERR_ACCESS', + 'SQLITE_IOERR_CLOSE', + 'SQLITE_IOERR_DELETE', + 'SQLITE_IOERR_FSYNC', + 'SQLITE_IOERR_LOCK', + 'SQLITE_IOERR_READ', + 'SQLITE_IOERR_SHORT_READ', + 'SQLITE_IOERR_TRUNCATE', + 'SQLITE_IOERR_UNLOCK', + 'SQLITE_IOERR_WRITE', + 'SQLITE_LOCK_EXCLUSIVE', + 'SQLITE_LOCK_NONE', + 'SQLITE_LOCK_PENDING', + 'SQLITE_LOCK_RESERVED', + 'SQLITE_LOCK_SHARED', + 'SQLITE_LOCKED', + 'SQLITE_MISUSE', + 'SQLITE_NOTFOUND', + 'SQLITE_OPEN_CREATE', + 'SQLITE_OPEN_DELETEONCLOSE', + 'SQLITE_OPEN_MAIN_DB', + 'SQLITE_OPEN_READONLY', + 'SQLITE_LOCK_NONE', + 'SQLITE_LOCK_SHARED', + 'SQLITE_LOCK_RESERVED', + 'SQLITE_LOCK_PENDING', + 'SQLITE_LOCK_EXCLUSIVE' + ].forEach((k)=>{ + if(undefined === (state.sq3Codes[k] = capi[k])){ + toss("Maintenance required: not found:",k); + } + }); + + state.opfsFlags = Object.assign(Object.create(null),{ + /** + Flag for use with xOpen(). URI flag "opfs-unlock-asap=1" + enables this. See defaultUnlockAsap, below. + */ + OPFS_UNLOCK_ASAP: 0x01, + /** + Flag for use with xOpen(). URI flag "delete-before-open=1" + tells the VFS to delete the db file before attempting to open + it. This can be used, e.g., to replace a db which has been + corrupted (without forcing us to expose a delete/unlink() + function in the public API). + + Failure to unlink the file is ignored but may lead to + downstream errors. An unlink can fail if, e.g., another tab + has the handle open. + + It goes without saying that deleting a file out from under another + instance results in Undefined Behavior. + */ + OPFS_UNLINK_BEFORE_OPEN: 0x02, + /** + If true, any async routine which implicitly acquires a sync + access handle (i.e. an OPFS lock) will release that lock at + the end of the call which acquires it. If false, such + "autolocks" are not released until the VFS is idle for some + brief amount of time. + + The benefit of enabling this is much higher concurrency. The + down-side is much-reduced performance (as much as a 4x decrease + in speedtest1). + */ + defaultUnlockAsap: false + }); + +//#if nope +/* does not yet work this way */ +//#define opfs-has-metrics +//#include api/opfs-common-inline.c-pp.js +//#undef opfs-has-metrics + state.initS11n = initS11n; +//#endif + return state; + }/*createVfsStateObject()*/; + }/*sqlite3ApiBootstrap.initializers*/); -//#else -/* - The OPFS SAH Pool parts are elided from builds targeting node.js. -*/ //#endif target:node diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 3ee44d33b0..7bb31dc60b 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -752,6 +752,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( toss: function(...args){throw new Error(args.join(' '))}, toss3, typedArrayPart: wasm.typedArrayPart, + nu: (...obj)=>Object.assign(Object.create(null),...obj), assert: function(arg,msg){ if( !arg ){ util.toss("Assertion failed:",msg); diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 98eeb1639b..c9bd620fa5 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -50,12 +50,12 @@ usage of those methods to remove the "await". */ "use strict"; -const wPost = (type,...args)=>postMessage({type, payload:args}); const urlParams = new URL(globalThis.location.href).searchParams; if( !urlParams.has('vfs') ){ throw new Error("Expecting vfs=opfs|opfs-wl URL argument for this worker"); } const isWebLocker = 'opfs-wl'===urlParams.get('vfs'); +const wPost = (type,...args)=>postMessage({type, payload:args}); const installAsyncProxy = function(){ const toss = function(...args){throw new Error(args.join(' '))}; if(globalThis.window === globalThis){ diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index e2f4ff2f93..dee1f6d190 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -34,9 +34,11 @@ */ 'use strict'; globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ - const opfsUtil = sqlite3.opfs || sqlite3.util.toss("Missing sqlite3.opfs") - /* Gets removed from sqlite3 during bootstrap, so we need an - early reference to it. */; + /* These get removed from sqlite3 during bootstrap, so we need an + early reference to it. */ + const util = sqlite3.util; + const opfsUtil = sqlite3.opfs || sqlite3.util.toss("Missing sqlite3.opfs"); + /** installOpfsWlVfs() returns a Promise which, on success, installs an sqlite3_vfs named "opfs-wl", suitable for use with all sqlite3 APIs @@ -64,6 +66,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ On success, the Promise resolves to the top-most sqlite3 namespace object. + + Code-diver notes: this file is particularly sparse on documentation + because much of it is identical to the code in + sqlite3-vfs-opfs.c-pp.js. See that file for more details. */ const installOpfsWlVfs = function callee(options){ try{ @@ -71,8 +77,7 @@ const installOpfsWlVfs = function callee(options){ }catch(e){ return Promise.reject(e); } - const nu = (...obj)=>Object.assign(Object.create(null),...obj); - options = nu(options); + options = util.nu(options); const urlParams = new URL(globalThis.location.href).searchParams; if(urlParams.has('opfs-disable')){ //sqlite3.config.warn('Explicitly not installing 'opfs-wl' VFS due to opfs-disable flag.'); @@ -105,34 +110,30 @@ const installOpfsWlVfs = function callee(options){ const error = (...args)=>logImpl(0, ...args); const toss = sqlite3.util.toss; const capi = sqlite3.capi; - const util = sqlite3.util; const wasm = sqlite3.wasm; const sqlite3_vfs = capi.sqlite3_vfs; const sqlite3_file = capi.sqlite3_file; const sqlite3_io_methods = capi.sqlite3_io_methods; - /** - State which we send to the async-api Worker or share with it. - This object must initially contain only cloneable or sharable - objects. After the worker's "inited" message arrives, other types - of data may be added to it. - - For purposes of Atomics.wait() and Atomics.notify(), we use a - SharedArrayBuffer with one slot reserved for each of the API - proxy's methods. The sync side of the API uses Atomics.wait() - on the corresponding slot and the async side uses - Atomics.notify() on that slot. - - The approach of using a single SAB to serialize comms for all - instances might(?) lead to deadlock situations in multi-db - cases. We should probably have one SAB here with a single slot - for locking a per-file initialization step and then allocate a - separate SAB like the above one for each file. That will - require a bit of acrobatics but should be feasible. The most - problematic part is that xOpen() would have to use - postMessage() to communicate its SharedArrayBuffer, and mixing - that approach with Atomics.wait/notify() gets a bit messy. - */ - const state = Object.create(null); + const pDVfs = capi.sqlite3_vfs_find(null)/*pointer to default VFS*/; + const dVfs = pDVfs + ? new sqlite3_vfs(pDVfs) + : null /* dVfs will be null when sqlite3 is built with + SQLITE_OS_OTHER. */; + const opfsIoMethods = new sqlite3_io_methods(); + const opfsVfs = new sqlite3_vfs() + .addOnDispose( ()=>opfsIoMethods.dispose()); + opfsIoMethods.$iVersion = 1; + opfsVfs.$iVersion = 2/*yes, two*/; + opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; + opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit + is undocumented/unspecified. */; + opfsVfs.$zName = wasm.allocCString('opfs-wl'); + opfsVfs.addOnDispose( + '$zName', opfsVfs.$zName, + 'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null) + ); + const state = opfsUtil.createVfsStateObject(opfsVfs); + state.verbose = options.verbose; const metrics = Object.create(null); //#define opfs-has-metrics //#include api/opfs-common-inline.c-pp.js @@ -168,10 +169,8 @@ const installOpfsWlVfs = function callee(options){ s = metrics.s11n.deserialize = Object.create(null); s.count = s.time = 0; } - }/*metrics*/; - const opfsIoMethods = new sqlite3_io_methods(); - const opfsVfs = new sqlite3_vfs() - .addOnDispose( ()=>opfsIoMethods.dispose()); + }/*vfsMetrics*/; + vfsMetrics.reset(); let promiseWasRejected = undefined; const promiseReject = (err)=>{ promiseWasRejected = true; @@ -182,14 +181,14 @@ const installOpfsWlVfs = function callee(options){ promiseWasRejected = false; return promiseResolve_(sqlite3); }; - const workerArgs = '?vfs=opfs-wl'; + options.proxyUri += '?vfs=opfs-wl'; const W = //#if target:es6-bundler-friendly new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs-wl", import.meta.url)); //#elif target:es6-module - new Worker(new URL(options.proxyUri+workerArgs, import.meta.url)); + new Worker(new URL(options.proxyUri, import.meta.url)); //#else - new Worker(options.proxyUri+workerArgs); + new Worker(options.proxyUri); //#endif setTimeout(()=>{ /* At attempt to work around a browser-specific quirk in which @@ -210,216 +209,6 @@ const installOpfsWlVfs = function callee(options){ error("Error initializing OPFS asyncer:",err); promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons.")); }; - const pDVfs = capi.sqlite3_vfs_find(null)/*pointer to default VFS*/; - const dVfs = pDVfs - ? new sqlite3_vfs(pDVfs) - : null /* dVfs will be null when sqlite3 is built with - SQLITE_OS_OTHER. */; - opfsIoMethods.$iVersion = 1; - opfsVfs.$iVersion = 2/*yes, two*/; - opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; - opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit - is undocumented/unspecified. */; - opfsVfs.$zName = wasm.allocCString('opfs-wl'); - // All C-side memory of opfsVfs is zeroed out, but just to be explicit: - opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null; - opfsVfs.addOnDispose( - '$zName', opfsVfs.$zName, - 'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null) - ); - /** - Pedantic sidebar about opfsVfs.ondispose: the entries in that array - are items to clean up when opfsVfs.dispose() is called, but in this - environment it will never be called. The VFS instance simply - hangs around until the WASM module instance is cleaned up. We - "could" _hypothetically_ clean it up by "importing" an - sqlite3_os_end() impl into the wasm build, but the shutdown order - of the wasm engine and the JS one are undefined so there is no - guaranty that the opfsVfs instance would be available in one - environment or the other when sqlite3_os_end() is called (_if_ it - gets called at all in a wasm build, which is undefined). - */ - - state.verbose = options.verbose; - state.littleEndian = (()=>{ - const buffer = new ArrayBuffer(2); - new DataView(buffer).setInt16(0, 256, true /* ==>littleEndian */); - // Int16Array uses the platform's endianness. - return new Int16Array(buffer)[0] === 256; - })(); - /** - asyncIdleWaitTime is how long (ms) to wait, in the async proxy, - for each Atomics.wait() when waiting on inbound VFS API calls. - We need to wake up periodically to give the thread a chance to - do other things. If this is too high (e.g. 500ms) then even two - workers/tabs can easily run into locking errors. Some multiple - of this value is also used for determining how long to wait on - lock contention to free up. - */ - state.asyncIdleWaitTime = 150; - - /** - Whether the async counterpart should log exceptions to - the serialization channel. That produces a great deal of - noise for seemingly innocuous things like xAccess() checks - for missing files, so this option may have one of 3 values: - - 0 = no exception logging. - - 1 = only log exceptions for "significant" ops like xOpen(), - xRead(), and xWrite(). - - 2 = log all exceptions. - */ - state.asyncS11nExceptions = 1; - /* Size of file I/O buffer block. 64k = max sqlite3 page size, and - xRead/xWrite() will never deal in blocks larger than that. */ - state.fileBufferSize = 1024 * 64; - state.sabS11nOffset = state.fileBufferSize; - /** - The size of the block in our SAB for serializing arguments and - result values. Needs to be large enough to hold serialized - values of any of the proxied APIs. Filenames are the largest - part but are limited to opfsVfs.$mxPathname bytes. We also - store exceptions there, so it needs to be long enough to hold - a reasonably long exception string. - */ - state.sabS11nSize = opfsVfs.$mxPathname * 2; - /** - The SAB used for all data I/O between the synchronous and - async halves (file i/o and arg/result s11n). - */ - state.sabIO = new SharedArrayBuffer( - state.fileBufferSize/* file i/o block */ - + state.sabS11nSize/* argument/result serialization block */ - ); - state.opIds = Object.create(null); - { - /* Indexes for use in our SharedArrayBuffer... */ - let i = 0; - /* SAB slot used to communicate which operation is desired - between both workers. This worker writes to it and the other - listens for changes. */ - state.opIds.whichOp = i++; - /* Slot for storing return values. This worker listens to that - slot and the other worker writes to it. */ - state.opIds.rc = i++; - /* Each function gets an ID which this worker writes to - the whichOp slot. The async-api worker uses Atomic.wait() - on the whichOp slot to figure out which operation to run - next. */ - state.opIds.xAccess = i++; - state.opIds.xClose = i++; - state.opIds.xDelete = i++; - state.opIds.xDeleteNoWait = i++; - state.opIds.xFileSize = i++; - state.opIds.xLock = i++; - state.opIds.xOpen = i++; - state.opIds.xRead = i++; - state.opIds.xSleep = i++; - state.opIds.xSync = i++; - state.opIds.xTruncate = i++; - state.opIds.xUnlock = i++; - state.opIds.xWrite = i++; - state.opIds.mkdir = i++; - state.opIds.lockControl = i++ /* we signal the intent to lock here */; - /** Internal signals which are used only during development and - testing via the dev console. */ - state.opIds['opfs-async-metrics'] = i++; - state.opIds['opfs-async-shutdown'] = i++; - /* The retry slot is used by the async part for wait-and-retry - semantics. Though we could hypothetically use the xSleep slot - for that, doing so might lead to undesired side effects. */ - state.opIds.retry = i++; - - /* Slots for submitting the lock type and receiving its acknowledgement. */ - state.lock = nu({ - type: i++ /* SQLITE_LOCK_xyz value */, - atomicsHandshake: i++ /* 1=release, 2=granted */ - }); - state.sabOP = new SharedArrayBuffer( - i * 4/* ==sizeof int32, noting that Atomics.wait() and friends - can only function on Int32Array views of an SAB. */); - vfsMetrics.reset(); - } - /** - SQLITE_xxx constants to export to the async worker - counterpart... - */ - state.sq3Codes = Object.create(null); - [ - 'SQLITE_ACCESS_EXISTS', - 'SQLITE_ACCESS_READWRITE', - 'SQLITE_BUSY', - 'SQLITE_CANTOPEN', - 'SQLITE_ERROR', - 'SQLITE_IOERR', - 'SQLITE_IOERR_ACCESS', - 'SQLITE_IOERR_CLOSE', - 'SQLITE_IOERR_DELETE', - 'SQLITE_IOERR_FSYNC', - 'SQLITE_IOERR_LOCK', - 'SQLITE_IOERR_READ', - 'SQLITE_IOERR_SHORT_READ', - 'SQLITE_IOERR_TRUNCATE', - 'SQLITE_IOERR_UNLOCK', - 'SQLITE_IOERR_WRITE', - 'SQLITE_LOCK_EXCLUSIVE', - 'SQLITE_LOCK_NONE', - 'SQLITE_LOCK_PENDING', - 'SQLITE_LOCK_RESERVED', - 'SQLITE_LOCK_SHARED', - 'SQLITE_LOCKED', - 'SQLITE_MISUSE', - 'SQLITE_NOTFOUND', - 'SQLITE_OPEN_CREATE', - 'SQLITE_OPEN_DELETEONCLOSE', - 'SQLITE_OPEN_MAIN_DB', - 'SQLITE_OPEN_READONLY', - 'SQLITE_LOCK_NONE', - 'SQLITE_LOCK_SHARED', - 'SQLITE_LOCK_RESERVED', - 'SQLITE_LOCK_PENDING', - 'SQLITE_LOCK_EXCLUSIVE' - ].forEach((k)=>{ - if(undefined === (state.sq3Codes[k] = capi[k])){ - toss("Maintenance required: not found:",k); - } - }); - state.opfsFlags = Object.assign(Object.create(null),{ - /** - Flag for use with xOpen(). URI flag "opfs-unlock-asap=1" - enables this. See defaultUnlockAsap, below. - */ - OPFS_UNLOCK_ASAP: 0x01, - /** - Flag for use with xOpen(). URI flag "delete-before-open=1" - tells the VFS to delete the db file before attempting to open - it. This can be used, e.g., to replace a db which has been - corrupted (without forcing us to expose a delete/unlink() - function in the public API). - - Failure to unlink the file is ignored but may lead to - downstream errors. An unlink can fail if, e.g., another tab - has the handle open. - - It goes without saying that deleting a file out from under another - instance results in Undefined Behavior. - */ - OPFS_UNLINK_BEFORE_OPEN: 0x02, - /** - If true, any async routine which implicitly acquires a sync - access handle (i.e. an OPFS lock) will release that lock at - the end of the call which acquires it. If false, such - "autolocks" are not released until the VFS is idle for some - brief amount of time. - - The benefit of enabling this is much higher concurrency. The - down-side is much-reduced performance (as much as a 4x decrease - in speedtest1). - */ - defaultUnlockAsap: false - }); /** Runs the given operation (by name) in the async worker @@ -501,18 +290,17 @@ const installOpfsWlVfs = function callee(options){ const ioSyncWrappers = { xCheckReservedLock: function(pFile,pOut){ /** - As of late 2022, only a single lock can be held on an OPFS - file. We have no way of checking whether any _other_ db - connection has a lock except by trying to obtain and (on - success) release a sync-handle for it, but doing so would - involve an inherent race condition. For the time being, - pending a better solution, we simply report whether the - given pFile is open. - - Update 2024-06-12: based on forum discussions, this - function now always sets pOut to 0 (false): - - https://sqlite.org/forum/forumpost/a2f573b00cda1372 + After consultation with a topic expert: "opfs-wl" will + continue to use the same no-op impl which "opfs" does + because: + + - xCheckReservedLock() is just a hint. If SQLite needs to + lock, it's still going to try to lock. + + - We cannot do this check synchronously in "opfs-wl", + so would need to pass it to the async proxy. That would + make it inordinately expensive considering that it's + just a hint. */ wasm.poke(pOut, 0, 'i32'); return 0; @@ -855,6 +643,8 @@ const installOpfsWlVfs = function callee(options){ } }/*sanityCheck()*/; + //const initS11n = state.initS11n || toss("Missing state.initS11n()"); + //delete state.initS11n; W.onmessage = function({data}){ //log("Worker.onmessage:",data); switch(data.type){ @@ -867,7 +657,7 @@ const installOpfsWlVfs = function callee(options){ /* Arrives as soon as the asyc proxy finishes loading. Pass our config and shared state on to the async worker. */ - W.postMessage({type: 'opfs-async-init',args: state}); + W.postMessage({type: 'opfs-async-init', args: util.nu(state)}); break; case 'opfs-async-inited': { /* Indicates that the async partner has received the 'init' diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 7ba7427d0a..b294163236 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -122,6 +122,41 @@ const installOpfsVfs = function callee(options){ const sqlite3_file = capi.sqlite3_file; const sqlite3_io_methods = capi.sqlite3_io_methods; + const opfsIoMethods = new sqlite3_io_methods(); + const opfsVfs = new sqlite3_vfs() + .addOnDispose( ()=>opfsIoMethods.dispose()); + const pDVfs = capi.sqlite3_vfs_find(null)/*pointer to default VFS*/; + const dVfs = pDVfs + ? new sqlite3_vfs(pDVfs) + : null /* dVfs will be null when sqlite3 is built with + SQLITE_OS_OTHER. */; + + opfsIoMethods.$iVersion = 1; + opfsVfs.$iVersion = 2/*yes, two*/; + opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; + opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit + is undocumented/unspecified. */; + opfsVfs.$zName = wasm.allocCString("opfs"); + // All C-side memory of opfsVfs is zeroed out, but just to be explicit: + opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null; + opfsVfs.addOnDispose( + '$zName', opfsVfs.$zName, + 'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null) + /** + Pedantic sidebar: the entries in this array are items to + clean up when opfsVfs.dispose() is called, but in this + environment it will never be called. The VFS instance simply + hangs around until the WASM module instance is cleaned up. We + "could" _hypothetically_ clean it up by "importing" an + sqlite3_os_end() impl into the wasm build, but the shutdown + order of the wasm engine and the JS one are undefined so + there is no guaranty that the opfsVfs instance would be + available in one environment or the other when + sqlite3_os_end() is called (_if_ it gets called at all in a + wasm build, which is undefined). + */ + ); + /** State which we send to the async-api Worker or share with it. This object must initially contain only cloneable or sharable @@ -144,7 +179,8 @@ const installOpfsVfs = function callee(options){ postMessage() to communicate its SharedArrayBuffer, and mixing that approach with Atomics.wait/notify() gets a bit messy. */ - const state = Object.create(null); + const state = opfsUtil.createVfsStateObject(opfsVfs); + state.verbose = options.verbose; const metrics = Object.create(null); //#define opfs-has-metrics //#include api/opfs-common-inline.c-pp.js @@ -181,9 +217,7 @@ const installOpfsVfs = function callee(options){ s.count = s.time = 0; } }/*metrics*/; - const opfsIoMethods = new sqlite3_io_methods(); - const opfsVfs = new sqlite3_vfs() - .addOnDispose( ()=>opfsIoMethods.dispose()); + vfsMetrics.reset(); let promiseWasRejected = undefined; const promiseReject = (err)=>{ promiseWasRejected = true; @@ -222,201 +256,6 @@ const installOpfsVfs = function callee(options){ error("Error initializing OPFS asyncer:",err); promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons.")); }; - const pDVfs = capi.sqlite3_vfs_find(null)/*pointer to default VFS*/; - const dVfs = pDVfs - ? new sqlite3_vfs(pDVfs) - : null /* dVfs will be null when sqlite3 is built with - SQLITE_OS_OTHER. */; - opfsIoMethods.$iVersion = 1; - opfsVfs.$iVersion = 2/*yes, two*/; - opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; - opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit - is undocumented/unspecified. */; - opfsVfs.$zName = wasm.allocCString("opfs"); - // All C-side memory of opfsVfs is zeroed out, but just to be explicit: - opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null; - opfsVfs.addOnDispose( - '$zName', opfsVfs.$zName, - 'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null) - ); - /** - Pedantic sidebar about opfsVfs.ondispose: the entries in that array - are items to clean up when opfsVfs.dispose() is called, but in this - environment it will never be called. The VFS instance simply - hangs around until the WASM module instance is cleaned up. We - "could" _hypothetically_ clean it up by "importing" an - sqlite3_os_end() impl into the wasm build, but the shutdown order - of the wasm engine and the JS one are undefined so there is no - guaranty that the opfsVfs instance would be available in one - environment or the other when sqlite3_os_end() is called (_if_ it - gets called at all in a wasm build, which is undefined). - */ - state.verbose = options.verbose; - state.littleEndian = (()=>{ - const buffer = new ArrayBuffer(2); - new DataView(buffer).setInt16(0, 256, true /* ==>littleEndian */); - // Int16Array uses the platform's endianness. - return new Int16Array(buffer)[0] === 256; - })(); - /** - asyncIdleWaitTime is how long (ms) to wait, in the async proxy, - for each Atomics.wait() when waiting on inbound VFS API calls. - We need to wake up periodically to give the thread a chance to - do other things. If this is too high (e.g. 500ms) then even two - workers/tabs can easily run into locking errors. Some multiple - of this value is also used for determining how long to wait on - lock contention to free up. - */ - state.asyncIdleWaitTime = 150; - - /** - Whether the async counterpart should log exceptions to - the serialization channel. That produces a great deal of - noise for seemingly innocuous things like xAccess() checks - for missing files, so this option may have one of 3 values: - - 0 = no exception logging. - - 1 = only log exceptions for "significant" ops like xOpen(), - xRead(), and xWrite(). - - 2 = log all exceptions. - */ - state.asyncS11nExceptions = 1; - /* Size of file I/O buffer block. 64k = max sqlite3 page size, and - xRead/xWrite() will never deal in blocks larger than that. */ - state.fileBufferSize = 1024 * 64; - state.sabS11nOffset = state.fileBufferSize; - /** - The size of the block in our SAB for serializing arguments and - result values. Needs to be large enough to hold serialized - values of any of the proxied APIs. Filenames are the largest - part but are limited to opfsVfs.$mxPathname bytes. We also - store exceptions there, so it needs to be long enough to hold - a reasonably long exception string. - */ - state.sabS11nSize = opfsVfs.$mxPathname * 2; - /** - The SAB used for all data I/O between the synchronous and - async halves (file i/o and arg/result s11n). - */ - state.sabIO = new SharedArrayBuffer( - state.fileBufferSize/* file i/o block */ - + state.sabS11nSize/* argument/result serialization block */ - ); - state.opIds = Object.create(null); - { - /* Indexes for use in our SharedArrayBuffer... */ - let i = 0; - /* SAB slot used to communicate which operation is desired - between both workers. This worker writes to it and the other - listens for changes. */ - state.opIds.whichOp = i++; - /* Slot for storing return values. This worker listens to that - slot and the other worker writes to it. */ - state.opIds.rc = i++; - /* Each function gets an ID which this worker writes to - the whichOp slot. The async-api worker uses Atomic.wait() - on the whichOp slot to figure out which operation to run - next. */ - state.opIds.xAccess = i++; - state.opIds.xClose = i++; - state.opIds.xDelete = i++; - state.opIds.xDeleteNoWait = i++; - state.opIds.xFileSize = i++; - state.opIds.xLock = i++; - state.opIds.xOpen = i++; - state.opIds.xRead = i++; - state.opIds.xSleep = i++; - state.opIds.xSync = i++; - state.opIds.xTruncate = i++; - state.opIds.xUnlock = i++; - state.opIds.xWrite = i++; - state.opIds.mkdir = i++; - state.opIds['opfs-async-metrics'] = i++; - state.opIds['opfs-async-shutdown'] = i++; - /* The retry slot is used by the async part for wait-and-retry - semantics. Though we could hypothetically use the xSleep slot - for that, doing so might lead to undesired side effects. */ - state.opIds.retry = i++; - state.sabOP = new SharedArrayBuffer( - i * 4/* ==sizeof int32, noting that Atomics.wait() and friends - can only function on Int32Array views of an SAB. */); - vfsMetrics.reset(); - } - /** - SQLITE_xxx constants to export to the async worker - counterpart... - */ - state.sq3Codes = Object.create(null); - [ - 'SQLITE_ACCESS_EXISTS', - 'SQLITE_ACCESS_READWRITE', - 'SQLITE_BUSY', - 'SQLITE_CANTOPEN', - 'SQLITE_ERROR', - 'SQLITE_IOERR', - 'SQLITE_IOERR_ACCESS', - 'SQLITE_IOERR_CLOSE', - 'SQLITE_IOERR_DELETE', - 'SQLITE_IOERR_FSYNC', - 'SQLITE_IOERR_LOCK', - 'SQLITE_IOERR_READ', - 'SQLITE_IOERR_SHORT_READ', - 'SQLITE_IOERR_TRUNCATE', - 'SQLITE_IOERR_UNLOCK', - 'SQLITE_IOERR_WRITE', - 'SQLITE_LOCK_EXCLUSIVE', - 'SQLITE_LOCK_NONE', - 'SQLITE_LOCK_PENDING', - 'SQLITE_LOCK_RESERVED', - 'SQLITE_LOCK_SHARED', - 'SQLITE_LOCKED', - 'SQLITE_MISUSE', - 'SQLITE_NOTFOUND', - 'SQLITE_OPEN_CREATE', - 'SQLITE_OPEN_DELETEONCLOSE', - 'SQLITE_OPEN_MAIN_DB', - 'SQLITE_OPEN_READONLY' - ].forEach((k)=>{ - if(undefined === (state.sq3Codes[k] = capi[k])){ - toss("Maintenance required: not found:",k); - } - }); - state.opfsFlags = Object.assign(Object.create(null),{ - /** - Flag for use with xOpen(). URI flag "opfs-unlock-asap=1" - enables this. See defaultUnlockAsap, below. - */ - OPFS_UNLOCK_ASAP: 0x01, - /** - Flag for use with xOpen(). URI flag "delete-before-open=1" - tells the VFS to delete the db file before attempting to open - it. This can be used, e.g., to replace a db which has been - corrupted (without forcing us to expose a delete/unlink() - function in the public API). - - Failure to unlink the file is ignored but may lead to - downstream errors. An unlink can fail if, e.g., another tab - has the handle open. - - It goes without saying that deleting a file out from under another - instance results in Undefined Behavior. - */ - OPFS_UNLINK_BEFORE_OPEN: 0x02, - /** - If true, any async routine which implicitly acquires a sync - access handle (i.e. an OPFS lock) will release that lock at - the end of the call which acquires it. If false, such - "autolocks" are not released until the VFS is idle for some - brief amount of time. - - The benefit of enabling this is much higher concurrency. The - down-side is much-reduced performance (as much as a 4x decrease - in speedtest1). - */ - defaultUnlockAsap: false - }); /** Runs the given operation (by name) in the async worker @@ -827,6 +666,8 @@ const installOpfsVfs = function callee(options){ } }/*sanityCheck()*/; + //const initS11n = state.initS11n || toss("Missing state.initS11n()"); + //delete state.initS11n; W.onmessage = function({data}){ //log("Worker.onmessage:",data); switch(data.type){ diff --git a/manifest b/manifest index f334f15c5a..82c6c5bf4a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Consolidate\smuch\sof\sthe\sOPFS\sutility\scode\sinto\sa\snew\sfile\sfor\suse\sby\stwo\sof\sthe\sOPFS\sVFSes. -D 2026-03-04T11:37:39.256 +C Baby\ssteps\sin\sconsolidating\scommon\sOPFS\sVFS\scode. +D 2026-03-04T14:33:33.214 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -584,22 +584,22 @@ F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp 7ba933e8f1290cc65459dd371c0c9a031d96bdf14 F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b47244781a7e81 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 -F ext/wasm/api/opfs-common-inline.c-pp.js b9c4e080698792cbc04ce9dd9dda7d8316c6db0262f74820706f98b352b949d5 w ext/wasm/api/opfs-common.c-pp.js -F ext/wasm/api/opfs-common-shared.c-pp.js 3f8f3f2ab4790fdd1e6d1d9224e232cef07f1c8753827c18bbba965dbe98795f +F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 +F ext/wasm/api/opfs-common-shared.c-pp.js fdebcb821f9f732eb263e3ee2dbd6af5709aaa5fec9da6eaa0e10fd93b72f547 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f F ext/wasm/api/sqlite3-api-glue.c-pp.js 9b33e3ee467791dec4fd1b444b12a8545dfbb6c8b28ac651c7bdc7661a3b5a5c F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c41db98a22b534c15e543cfa -F ext/wasm/api/sqlite3-api-prologue.js ccd8ece4b4580d2a70996218f28e810d70a86f5e2795f4d4a75f0603af24aef6 +F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 25b856508ac94336419133c6ec10594f576b469f85cc69cde4c09cfa06a8e1c7 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js f0a2aa8712211ff9db2ef548ae8b676be3e7c82f61586d03fd8317fbc95bbedd F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 54f71e563dda30af73ed84ff9de03441537b2e8fb8d2ae2a0b0c8187f51db67a -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 2e2a72a40e2ad6ea92f52eb7adbd925d4acd874ffeecaa00b85234ad49862655 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js c6e5a281756e8ed7bbabf086dae765021486e17b91b6c4eee3c08dc2485fa348 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b8db3ccfedb457634cc07df7a955bc44c6d1be8b40d35f47822c2168ab8b1968 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 8ea85776116521526d684f221d67e288126e62931d4a0ea7fc7f164cd2d5b2ec -R 82203270087631af34878be94f4d1594 +P db19a6e9663c3a44996178cb8c35dc4ccd60f48cb4b81b6c214411a56c57def7 +R a1c4d958895cbdc094c8287aa9f23443 U stephan -Z 1548da853f7a79cab3a86616c1bf35cc +Z b1a56499cd2b6bf9891139561c1b1fe5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 65aadb1877..8f61158031 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -db19a6e9663c3a44996178cb8c35dc4ccd60f48cb4b81b6c214411a56c57def7 +b0dd23299e97ff975f213cb3a8b051f4d7b785b29def82e01f53427fdf77ecb6 From 691494a93bcfd6753c8594e9874077fcec44a920 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 4 Mar 2026 16:30:51 +0000 Subject: [PATCH 093/197] Consolidate the OPFS VFS's metrics-tracking code. FossilOrigin-Name: b71c79ef9672c77a72a976ffcd7cbebfaf0ff314dff97b274f7d092de6a7773f --- ext/wasm/api/opfs-common-shared.c-pp.js | 47 +++++++++++++++++++++--- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 46 +++-------------------- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 45 ++--------------------- ext/wasm/mkwasmbuilds.c | 6 +++ manifest | 18 ++++----- manifest.uuid | 2 +- 6 files changed, 67 insertions(+), 97 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 077f4c5a6a..376780217d 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -453,6 +453,40 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const vfsName = wasm.cstrToJs(opfsVfs.$zName); const isWebLocker = 'opfs-wl'===vfsName; const state = util.nu(); + opfsVfs.metrics = util.nu({ + counters: util.nu(), + dump: function(){ + let k, n = 0, t = 0, w = 0; + for(k in state.opIds){ + const m = metrics[k]; + n += m.count; + t += m.time; + w += m.wait; + m.avgTime = (m.count && m.time) ? (m.time / m.count) : 0; + m.avgWait = (m.count && m.wait) ? (m.wait / m.count) : 0; + } + sqlite3.config.log(globalThis.location.href, + "metrics for",globalThis.location.href,":",metrics, + "\nTotal of",n,"op(s) for",t, + "ms (incl. "+w+" ms of waiting on the async side)"); + sqlite3.config.log("Serialization metrics:",opfsVfs.metrics.counters.s11n); + //W.postMessage({type:'opfs-async-metrics'}); + }, + reset: function(){ + let k; + const r = (m)=>(m.count = m.time = m.wait = 0); + const m = opfsVfs.metrics.counters; + for(k in state.opIds){ + r(m[k] = Object.create(null)); + } + let s = m.s11n = Object.create(null); + s = s.serialize = Object.create(null); + s.count = s.time = 0; + s = m.s11n.deserialize = Object.create(null); + s.count = s.time = 0; + } + })/*opfsVfs.metrics*/; + /** asyncIdleWaitTime is how long (ms) to wait, in the async proxy, for each Atomics.wait() when waiting on inbound VFS API calls. @@ -638,12 +672,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ defaultUnlockAsap: false }); -//#if nope -/* does not yet work this way */ -//#define opfs-has-metrics + opfsVfs.metrics.reset(); +//#if not defined nope +//#// does not yet work this way +//#define vfs.metrics.enable + const metrics = opfsVfs.metrics.counters; //#include api/opfs-common-inline.c-pp.js -//#undef opfs-has-metrics - state.initS11n = initS11n; +//#// import initS11n() +//#undef vfs.metrics.enable + opfsVfs.initS11n = initS11n; //#endif return state; }/*createVfsStateObject()*/; diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index dee1f6d190..288f01e650 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -134,43 +134,8 @@ const installOpfsWlVfs = function callee(options){ ); const state = opfsUtil.createVfsStateObject(opfsVfs); state.verbose = options.verbose; - const metrics = Object.create(null); -//#define opfs-has-metrics -//#include api/opfs-common-inline.c-pp.js -//#undef opfs-has-metrics - - const vfsMetrics = { - dump: function(){ - let k, n = 0, t = 0, w = 0; - for(k in state.opIds){ - const m = metrics[k]; - n += m.count; - t += m.time; - w += m.wait; - m.avgTime = (m.count && m.time) ? (m.time / m.count) : 0; - m.avgWait = (m.count && m.wait) ? (m.wait / m.count) : 0; - } - sqlite3.config.log(globalThis.location.href, - "metrics for",globalThis.location.href,":",metrics, - "\nTotal of",n,"op(s) for",t, - "ms (incl. "+w+" ms of waiting on the async side)"); - sqlite3.config.log("Serialization metrics:",metrics.s11n); - W.postMessage({type:'opfs-async-metrics'}); - }, - reset: function(){ - let k; - const r = (m)=>(m.count = m.time = m.wait = 0); - for(k in state.opIds){ - r(metrics[k] = Object.create(null)); - } - let s = metrics.s11n = Object.create(null); - s = s.serialize = Object.create(null); - s.count = s.time = 0; - s = metrics.s11n.deserialize = Object.create(null); - s.count = s.time = 0; - } - }/*vfsMetrics*/; - vfsMetrics.reset(); + const metrics = opfsVfs.metrics.counters; + let promiseWasRejected = undefined; const promiseReject = (err)=>{ promiseWasRejected = true; @@ -643,8 +608,6 @@ const installOpfsWlVfs = function callee(options){ } }/*sanityCheck()*/; - //const initS11n = state.initS11n || toss("Missing state.initS11n()"); - //delete state.initS11n; W.onmessage = function({data}){ //log("Worker.onmessage:",data); switch(data.type){ @@ -674,7 +637,8 @@ const installOpfsWlVfs = function callee(options){ state.sabOPView = new Int32Array(state.sabOP); state.sabFileBufView = new Uint8Array(state.sabIO, 0, state.fileBufferSize); state.sabS11nView = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize); - initS11n(); + opfsVfs.initS11n(); + delete opfsVfs.initS11n; if(options.sanityChecks){ warn("Running sanity checks because of opfs-sanity-check URL arg..."); sanityCheck(); @@ -720,7 +684,7 @@ globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ //sqlite3.config.warn("installOpfsWlVfs.defaultProxyUri =",installOpfsWlVfs.defaultProxyUri); } return installOpfsWlVfs().catch((e)=>{ - sqlite3.config.warn("Ignoring inability to install OPFS-WL sqlite3_vfs:",e.message); + sqlite3.config.warn("Ignoring inability to install OPFS-WL sqlite3_vfs:",e); }); }catch(e){ sqlite3.config.error("installOpfsWlVfs() exception:",e); diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index b294163236..ba5fe9918e 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -181,43 +181,7 @@ const installOpfsVfs = function callee(options){ */ const state = opfsUtil.createVfsStateObject(opfsVfs); state.verbose = options.verbose; - const metrics = Object.create(null); -//#define opfs-has-metrics -//#include api/opfs-common-inline.c-pp.js -//#undef opfs-has-metrics - - const vfsMetrics = { - dump: function(){ - let k, n = 0, t = 0, w = 0; - for(k in state.opIds){ - const m = metrics[k]; - n += m.count; - t += m.time; - w += m.wait; - m.avgTime = (m.count && m.time) ? (m.time / m.count) : 0; - m.avgWait = (m.count && m.wait) ? (m.wait / m.count) : 0; - } - sqlite3.config.log(globalThis.location.href, - "metrics for",globalThis.location.href,":",metrics, - "\nTotal of",n,"op(s) for",t, - "ms (incl. "+w+" ms of waiting on the async side)"); - sqlite3.config.log("Serialization metrics:",metrics.s11n); - W.postMessage({type:'opfs-async-metrics'}); - }, - reset: function(){ - let k; - const r = (m)=>(m.count = m.time = m.wait = 0); - for(k in state.opIds){ - r(metrics[k] = Object.create(null)); - } - let s = metrics.s11n = Object.create(null); - s = s.serialize = Object.create(null); - s.count = s.time = 0; - s = metrics.s11n.deserialize = Object.create(null); - s.count = s.time = 0; - } - }/*metrics*/; - vfsMetrics.reset(); + const metrics = opfsVfs.metrics.counters; let promiseWasRejected = undefined; const promiseReject = (err)=>{ promiseWasRejected = true; @@ -666,8 +630,6 @@ const installOpfsVfs = function callee(options){ } }/*sanityCheck()*/; - //const initS11n = state.initS11n || toss("Missing state.initS11n()"); - //delete state.initS11n; W.onmessage = function({data}){ //log("Worker.onmessage:",data); switch(data.type){ @@ -697,7 +659,8 @@ const installOpfsVfs = function callee(options){ state.sabOPView = new Int32Array(state.sabOP); state.sabFileBufView = new Uint8Array(state.sabIO, 0, state.fileBufferSize); state.sabS11nView = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize); - initS11n(); + opfsVfs.initS11n(); + delete opfsVfs.initS11n; if(options.sanityChecks){ warn("Running sanity checks because of opfs-sanity-check URL arg..."); sanityCheck(); @@ -743,7 +706,7 @@ globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ //sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri); } return installOpfsVfs().catch((e)=>{ - sqlite3.config.warn("Ignoring inability to install OPFS sqlite3_vfs:",e.message); + sqlite3.config.warn("Ignoring inability to install OPFS sqlite3_vfs:",e); }); }catch(e){ sqlite3.config.error("installOpfsVfs() exception:",e); diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c index 748594f4ca..022a926397 100644 --- a/ext/wasm/mkwasmbuilds.c +++ b/ext/wasm/mkwasmbuilds.c @@ -747,6 +747,12 @@ static void emit_api_js(char const *zBuildName){ zBuildName, zBuildName, zBuildName); pf("$(out.%s.js): $(sqlite3-api.%s.js)\n", zBuildName, zBuildName); + pf("$(sqlite3-api.%s.js):" + /* Extra deps needed by the OPFS pieces... */ + " $(dir.api)/opfs-common-shared.c-pp.js" + " $(dir.api)/opfs-common-inline.c-pp.js" + "\n", + zBuildName); } /* diff --git a/manifest b/manifest index 82c6c5bf4a..ea250bde8e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Baby\ssteps\sin\sconsolidating\scommon\sOPFS\sVFS\scode. -D 2026-03-04T14:33:33.214 +C Consolidate\sthe\sOPFS\sVFS's\smetrics-tracking\scode. +D 2026-03-04T16:30:51.574 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js fdebcb821f9f732eb263e3ee2dbd6af5709aaa5fec9da6eaa0e10fd93b72f547 +F ext/wasm/api/opfs-common-shared.c-pp.js e00a2f18b6ed6d560b19503d9adce49f2151d1b488cbca24545a631bbed72d25 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -598,8 +598,8 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js f0a2aa8712211ff9db2ef548ae8b676b F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js c6e5a281756e8ed7bbabf086dae765021486e17b91b6c4eee3c08dc2485fa348 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b8db3ccfedb457634cc07df7a955bc44c6d1be8b40d35f47822c2168ab8b1968 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 007430b82089b2aa8720a5866a9a9b0e9a7ddf3a1e7bafd1b652bec6c6a18196 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 9061455eb3a51aa898d02737aae1210c439d9f412b97d342ae9123746f72fcad F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -628,7 +628,7 @@ F ext/wasm/index.html 475bc283338749db4e3fbf24cf3f5aa020cc85a1fffb780d400a915fcb F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b F ext/wasm/jaccwabyt/jaccwabyt.md 6aa90fa1a973d0ad10d077088bea163b241d8470c75eafdef87620a1de1dea41 F ext/wasm/mkdist.sh f8883b077a2ca47cf92e6f0ce305fbf72ca648c3501810125056c4b09c2d5554 x -F ext/wasm/mkwasmbuilds.c b1ed20dfba178e6ccae91b4594ac9439992fd0cb783f202c639ca761f1b1d2a3 +F ext/wasm/mkwasmbuilds.c 5961177b9d6ad2b49efbdbb3076527e6886fecef7adf99d71cce58bfca89be08 F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2 F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96 F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P db19a6e9663c3a44996178cb8c35dc4ccd60f48cb4b81b6c214411a56c57def7 -R a1c4d958895cbdc094c8287aa9f23443 +P b0dd23299e97ff975f213cb3a8b051f4d7b785b29def82e01f53427fdf77ecb6 +R 950709f8ceba3a494ed70c19c6d2296a U stephan -Z b1a56499cd2b6bf9891139561c1b1fe5 +Z a91e3522d6c27cde9f5c40c8510d95f1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8f61158031..3dfa0db211 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b0dd23299e97ff975f213cb3a8b051f4d7b785b29def82e01f53427fdf77ecb6 +b71c79ef9672c77a72a976ffcd7cbebfaf0ff314dff97b274f7d092de6a7773f From 080da5f56da5c9a1c13e2002d670f22e9b2da599 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 4 Mar 2026 17:54:02 +0000 Subject: [PATCH 094/197] Factor out about 300 lines of common OPFS VFS bootstrapping code. FossilOrigin-Name: 57adecbab71795b62b1c2e4570ff504f35681e81dd8c94f78ad8e05ef39d36fd --- ext/wasm/api/opfs-common-shared.c-pp.js | 403 ++++++++++++++++-- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 506 +++++------------------ ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 486 ++++------------------ manifest | 16 +- manifest.uuid | 2 +- 5 files changed, 554 insertions(+), 859 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 376780217d..feefca5eb4 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -421,38 +421,80 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } }; + opfsUtil.initOptions = function(options, callee){ + options = util.nu(options); + const urlParams = new URL(globalThis.location.href).searchParams; + if(urlParams.has('opfs-disable')){ + //sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.'); + options.disableOpfs = true; + return options; + } + if(undefined===options.verbose){ + options.verbose = urlParams.has('opfs-verbose') + ? (+urlParams.get('opfs-verbose') || 2) : 1; + } + if(undefined===options.sanityChecks){ + options.sanityChecks = urlParams.has('opfs-sanity-check'); + } + if(undefined===options.proxyUri){ + options.proxyUri = callee.defaultProxyUri; + } + if('function' === typeof options.proxyUri){ + options.proxyUri = options.proxyUri(); + } + return options; + }; + /** - Populates the main state object used by "opfs" and "opfs-wl", and + Creates and populates the main state object used by "opfs" and "opfs-wl", and transfered from those to their async counterpart. - State which we send to the async-api Worker or share with it. - This object must initially contain only cloneable or sharable - objects. After the worker's "inited" message arrives, other types - of data may be added to it. - - For purposes of Atomics.wait() and Atomics.notify(), we use a - SharedArrayBuffer with one slot reserved for each of the API - proxy's methods. The sync side of the API uses Atomics.wait() - on the corresponding slot and the async side uses - Atomics.notify() on that slot. - - The approach of using a single SAB to serialize comms for all - instances might(?) lead to deadlock situations in multi-db - cases. We should probably have one SAB here with a single slot - for locking a per-file initialization step and then allocate a - separate SAB like the above one for each file. That will - require a bit of acrobatics but should be feasible. The most - problematic part is that xOpen() would have to use - postMessage() to communicate its SharedArrayBuffer, and mixing - that approach with Atomics.wait/notify() gets a bit messy. + Returns an object containing state which we send to the async-api + Worker or share with it. + + Because the returned object must be serializable to be posted to + the async proxy, after this returns, the caller must: + + - Make a local-scope reference of state.vfs then (delete + state.vfs). That's the capi.sqlite3_vfs instance for the VFS. + + This object must, when it's passed to the async part, contain + only cloneable or sharable objects. After the worker's "inited" + message arrives, other types of data may be added to it. */ - opfsUtil.createVfsStateObject = function(opfsVfs){ - if( !(opfsVfs instanceof capi.sqlite3_vfs) ){ - toss("Expecting a sqlite3_vfs instance"); - } - const vfsName = wasm.cstrToJs(opfsVfs.$zName); - const isWebLocker = 'opfs-wl'===vfsName; + opfsUtil.createVfsState = function(vfsName, options){ const state = util.nu(); + state.verbose = options.verbose; + + const opfsVfs = state.vfs = new capi.sqlite3_vfs(); + const opfsIoMethods = opfsVfs.ioMethods = new capi.sqlite3_io_methods(); + + opfsIoMethods.$iVersion = 1; + opfsVfs.$iVersion = 2/*yes, two*/; + opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; + opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit + is undocumented/unspecified. */; + opfsVfs.$zName = wasm.allocCString(vfsName); + opfsVfs.addOnDispose( + '$zName', opfsVfs.$zName, opfsIoMethods + /** + Pedantic sidebar: the entries in this array are items to + clean up when opfsVfs.dispose() is called, but in this + environment it will never be called. The VFS instance simply + hangs around until the WASM module instance is cleaned up. We + "could" _hypothetically_ clean it up by "importing" an + sqlite3_os_end() impl into the wasm build, but the shutdown + order of the wasm engine and the JS one are undefined so + there is no guaranty that the opfsVfs instance would be + available in one environment or the other when + sqlite3_os_end() is called (_if_ it gets called at all in a + wasm build, which is undefined). i.e. addOnDispose() here is + a matter of "correctness", not necessity. It just wouldn't do + to leave the impression that we're blindly leaking memory. + */ + ); + + const isWebLocker = 'opfs-wl'===vfsName; opfsVfs.metrics = util.nu({ counters: util.nu(), dump: function(){ @@ -470,7 +512,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ "\nTotal of",n,"op(s) for",t, "ms (incl. "+w+" ms of waiting on the async side)"); sqlite3.config.log("Serialization metrics:",opfsVfs.metrics.counters.s11n); - //W.postMessage({type:'opfs-async-metrics'}); + opfsVfs.worker?.postMessage?.({type:'opfs-async-metrics'}); }, reset: function(){ let k; @@ -533,6 +575,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ state.fileBufferSize/* file i/o block */ + state.sabS11nSize/* argument/result serialization block */ ); + + /** + For purposes of Atomics.wait() and Atomics.notify(), we use a + SharedArrayBuffer with one slot reserved for each of the API + proxy's methods. The sync side of the API uses Atomics.wait() + on the corresponding slot and the async side uses + Atomics.notify() on that slot. state.opIds holds the SAB slot + IDs of each of those. + */ state.opIds = Object.create(null); { /* @@ -582,9 +633,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ for that, doing so might lead to undesired side effects. */ state.opIds.retry = i++; - /* Slots for submitting the lock type and receiving its acknowledgement. - Only used by "opfs-wl". */ state.lock = util.nu({ + /* Slots for submitting the lock type and receiving its + acknowledgement. Only used by "opfs-wl". */ type: i++ /* SQLITE_LOCK_xyz value */, atomicsHandshake: i++ /* 0=pending, 1=release, 2=granted */ }); @@ -673,17 +724,297 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }); opfsVfs.metrics.reset(); -//#if not defined nope -//#// does not yet work this way -//#define vfs.metrics.enable const metrics = opfsVfs.metrics.counters; -//#include api/opfs-common-inline.c-pp.js + + /** + Runs the given operation (by name) in the async worker + counterpart, waits for its response, and returns the result + which the async worker writes to SAB[state.opIds.rc]. The + 2nd and subsequent arguments must be the arguments for the + async op. + */ + const opRun = opfsVfs.opRun = (op,...args)=>{ + const opNdx = state.opIds[op] || toss("Invalid op ID:",op); + state.s11n.serialize(...args); + Atomics.store(state.sabOPView, state.opIds.rc, -1); + Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); + Atomics.notify(state.sabOPView, state.opIds.whichOp) + /* async thread will take over here */; + const t = performance.now(); + while('not-equal'!==Atomics.wait(state.sabOPView, state.opIds.rc, -1)){ + /* + The reason for this loop is buried in the details of a long + discussion at: + + https://github.com/sqlite/sqlite-wasm/issues/12 + + Summary: in at least one browser flavor, under high loads, + the wait()/notify() pairings can get out of sync. Calling + wait() here until it returns 'not-equal' gets them back in + sync. + */ + } + /* When the above wait() call returns 'not-equal', the async + half will have completed the operation and reported its results + in the state.opIds.rc slot of the SAB. */ + const rc = Atomics.load(state.sabOPView, state.opIds.rc); + metrics[op].wait += performance.now() - t; + if(rc && state.asyncS11nExceptions){ + const err = state.s11n.deserialize(); + if(err) error(op+"() async error:",...err); + } + return rc; + }; + + const opTimer = Object.create(null); + opTimer.op = undefined; + opTimer.start = undefined; + const mTimeStart = opfsVfs.mTimeStart = (op)=>{ + opTimer.start = performance.now(); + opTimer.op = op; + ++metrics[op].count; + }; + const mTimeEnd = opfsVfs.mTimeEnd = ()=>( + metrics[opTimer.op].time += performance.now() - opTimer.start + ); + + /** + Map of sqlite3_file pointers to objects constructed by xOpen(). + */ + const __openFiles = opfsVfs.__openFiles = Object.create(null); + + /** + Impls for the sqlite3_io_methods methods. Maintenance reminder: + members are in alphabetical order to simplify finding them. + */ + const ioSyncWrappers = opfsVfs.ioSyncWrappers = util.nu({ + xCheckReservedLock: function(pFile,pOut){ + /** + After consultation with a topic expert: "opfs-wl" will + continue to use the same no-op impl which "opfs" does + because: + + - xCheckReservedLock() is just a hint. If SQLite needs to + lock, it's still going to try to lock. + + - We cannot do this check synchronously in "opfs-wl", + so would need to pass it to the async proxy. That would + make it inordinately expensive considering that it's + just a hint. + */ + wasm.poke(pOut, 0, 'i32'); + return 0; + }, + xClose: function(pFile){ + mTimeStart('xClose'); + let rc = 0; + const f = __openFiles[pFile]; + if(f){ + delete __openFiles[pFile]; + rc = opRun('xClose', pFile); + if(f.sq3File) f.sq3File.dispose(); + } + mTimeEnd(); + return rc; + }, + xDeviceCharacteristics: function(pFile){ + return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; + }, + xFileControl: function(pFile, opId, pArg){ + /*mTimeStart('xFileControl'); + mTimeEnd();*/ + return capi.SQLITE_NOTFOUND; + }, + xFileSize: function(pFile,pSz64){ + mTimeStart('xFileSize'); + let rc = opRun('xFileSize', pFile); + if(0==rc){ + try { + const sz = state.s11n.deserialize()[0]; + wasm.poke(pSz64, sz, 'i64'); + }catch(e){ + error("Unexpected error reading xFileSize() result:",e); + rc = state.sq3Codes.SQLITE_IOERR; + } + } + mTimeEnd(); + return rc; + }, + xRead: function(pFile,pDest,n,offset64){ + mTimeStart('xRead'); + const f = __openFiles[pFile]; + let rc; + try { + rc = opRun('xRead',pFile, n, Number(offset64)); + if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){ + /** + Results get written to the SharedArrayBuffer f.sabView. + Because the heap is _not_ a SharedArrayBuffer, we have + to copy the results. TypedArray.set() seems to be the + fastest way to copy this. */ + wasm.heap8u().set(f.sabView.subarray(0, n), Number(pDest)); + } + }catch(e){ + error("xRead(",arguments,") failed:",e,f); + rc = capi.SQLITE_IOERR_READ; + } + mTimeEnd(); + return rc; + }, + xSync: function(pFile,flags){ + mTimeStart('xSync'); + ++metrics.xSync.count; + const rc = opRun('xSync', pFile, flags); + mTimeEnd(); + return rc; + }, + xTruncate: function(pFile,sz64){ + mTimeStart('xTruncate'); + const rc = opRun('xTruncate', pFile, Number(sz64)); + mTimeEnd(); + return rc; + }, + xWrite: function(pFile,pSrc,n,offset64){ + mTimeStart('xWrite'); + const f = __openFiles[pFile]; + let rc; + try { + f.sabView.set(wasm.heap8u().subarray( + Number(pSrc), Number(pSrc) + n + )); + rc = opRun('xWrite', pFile, n, Number(offset64)); + }catch(e){ + error("xWrite(",arguments,") failed:",e,f); + rc = capi.SQLITE_IOERR_WRITE; + } + mTimeEnd(); + return rc; + } + })/*ioSyncWrappers*/; + + /** + Impls for the sqlite3_vfs methods. Maintenance reminder: members + are in alphabetical order to simplify finding them. + */ + const vfsSyncWrappers = opfsVfs.vfsSyncWrappers = { + xAccess: function(pVfs,zName,flags,pOut){ + mTimeStart('xAccess'); + const rc = opRun('xAccess', wasm.cstrToJs(zName)); + wasm.poke( pOut, (rc ? 0 : 1), 'i32' ); + mTimeEnd(); + return 0; + }, + xCurrentTime: function(pVfs,pOut){ + wasm.poke(pOut, 2440587.5 + (new Date().getTime()/86400000), + 'double'); + return 0; + }, + xCurrentTimeInt64: function(pVfs,pOut){ + wasm.poke(pOut, (2440587.5 * 86400000) + new Date().getTime(), + 'i64'); + return 0; + }, + xDelete: function(pVfs, zName, doSyncDir){ + mTimeStart('xDelete'); + const rc = opRun('xDelete', wasm.cstrToJs(zName), doSyncDir, false); + mTimeEnd(); + return rc; + }, + xFullPathname: function(pVfs,zName,nOut,pOut){ + /* Until/unless we have some notion of "current dir" + in OPFS, simply copy zName to pOut... */ + const i = wasm.cstrncpy(pOut, zName, nOut); + return i{ if(options.verbose>level) loggers[level]("OPFS syncer:",...args); }; - const log = (...args)=>logImpl(2, ...args); - const warn = (...args)=>logImpl(1, ...args); - const error = (...args)=>logImpl(0, ...args); - const toss = sqlite3.util.toss; - const capi = sqlite3.capi; - const wasm = sqlite3.wasm; - const sqlite3_vfs = capi.sqlite3_vfs; - const sqlite3_file = capi.sqlite3_file; - const sqlite3_io_methods = capi.sqlite3_io_methods; - const pDVfs = capi.sqlite3_vfs_find(null)/*pointer to default VFS*/; - const dVfs = pDVfs - ? new sqlite3_vfs(pDVfs) - : null /* dVfs will be null when sqlite3 is built with - SQLITE_OS_OTHER. */; - const opfsIoMethods = new sqlite3_io_methods(); - const opfsVfs = new sqlite3_vfs() - .addOnDispose( ()=>opfsIoMethods.dispose()); - opfsIoMethods.$iVersion = 1; - opfsVfs.$iVersion = 2/*yes, two*/; - opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; - opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit - is undocumented/unspecified. */; - opfsVfs.$zName = wasm.allocCString('opfs-wl'); - opfsVfs.addOnDispose( - '$zName', opfsVfs.$zName, - 'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null) - ); - const state = opfsUtil.createVfsStateObject(opfsVfs); - state.verbose = options.verbose; - const metrics = opfsVfs.metrics.counters; + const log = (...args)=>logImpl(2, ...args), + warn = (...args)=>logImpl(1, ...args), + error = (...args)=>logImpl(0, ...args), + capi = sqlite3.capi, + wasm = sqlite3.wasm; + const state = opfsUtil.createVfsState('opfs-wl', options), + opfsVfs = state.vfs, + metrics = opfsVfs.metrics.counters, + mTimeStart = opfsVfs.mTimeStart, + mTimeEnd = opfsVfs.mTimeEnd, + __openFiles = opfsVfs.__openFiles; + delete state.vfs; + + /* At this point, createVfsState() has populated state and + opfsVfs with any code common to both the "opfs" and "opfs-wl" + VFSes. Now comes the VFS-dependent work... */ + + opfsVfs.ioSyncWrappers.xLock = function(pFile, lockType){ + mTimeStart('xLock'); + ++metrics.xLock.count; + const f = __openFiles[pFile]; + let rc = 0; + /* All OPFS locks are exclusive locks. If xLock() has + previously succeeded, do nothing except record the lock + type. If no lock is active, have the async counterpart + lock the file. */ + if( f.lockType ) { + f.lockType = lockType; + }else{ + try{ + const view = state.sabOPView; + /* We need to pass pFile's name to the async proxy so that + it can create the WebLock name. */ + state.s11n.serialize(f.filename) + Atomics.store(view, state.lock.atomicsHandshake, 0); + Atomics.store(view, state.lock.type, lockType); + Atomics.store(view, state.opIds.whichOp, state.opIds.lockControl); + Atomics.notify(state.sabOPView, state.opIds.whichOp) + while('not-equal'!==Atomics.wait(view, state.lock.atomicsHandshake, 0)){ + /* Loop is a workaround for environment-specific quirks. See + notes in similar loops. */ + } + f.lockType = lockType; + }catch(e){ + error("xLock(",arguments,") failed", e, f); + rc = capi.SQLITE_IOERR_LOCK; + } + } + mTimeEnd(); + return rc; + }; + + opfsVfs.ioSyncWrappers.xUnlock =function(pFile,lockType){ + mTimeStart('xUnlock'); + ++metrics.xUnlock.count; + const f = __openFiles[pFile]; + let rc = 0; + if( lockType < f.lockType ){ + try{ + const view = state.sabOPView; + Atomics.store(view, state.lock.atomicsHandshake, 1); + Atomics.notify(view, state.lock.atomicsHandshake); + Atomics.wait(view, state.lock.atomicsHandshake, 1); + }catch(e){ + error("xUnlock(",pFile,lockType,") failed",e, f); + rc = capi.SQLITE_IOERR_LOCK; + } + } + if( 0===rc ) f.lockType = lockType; + mTimeEnd(); + return rc; + }; + + let promiseWasRejected = undefined; const promiseReject = (err)=>{ @@ -147,7 +177,7 @@ const installOpfsWlVfs = function callee(options){ return promiseResolve_(sqlite3); }; options.proxyUri += '?vfs=opfs-wl'; - const W = + const W = opfsVfs.worker = //#if target:es6-bundler-friendly new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs-wl", import.meta.url)); //#elif target:es6-module @@ -175,47 +205,7 @@ const installOpfsWlVfs = function callee(options){ promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons.")); }; - /** - Runs the given operation (by name) in the async worker - counterpart, waits for its response, and returns the result - which the async worker writes to SAB[state.opIds.rc]. The - 2nd and subsequent arguments must be the arguments for the - async op. - */ - const opRun = (op,...args)=>{ - const opNdx = state.opIds[op] || toss("Invalid op ID:",op); - state.s11n.serialize(...args); - Atomics.store(state.sabOPView, state.opIds.rc, -1); - Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); - Atomics.notify(state.sabOPView, state.opIds.whichOp) - /* async thread will take over here */; - const t = performance.now(); - while('not-equal'!==Atomics.wait(state.sabOPView, state.opIds.rc, -1)){ - /* - The reason for this loop is buried in the details of a long - discussion at: - - https://github.com/sqlite/sqlite-wasm/issues/12 - - Summary: in at least one browser flavor, under high loads, - the wait()/notify() pairings can get out of sync. Calling - wait() here until it returns 'not-equal' gets them back in - sync. - */ - } - /* When the above wait() call returns 'not-equal', the async - half will have completed the operation and reported its results - in the state.opIds.rc slot of the SAB. */ - const rc = Atomics.load(state.sabOPView, state.opIds.rc); - metrics[op].wait += performance.now() - t; - if(rc && state.asyncS11nExceptions){ - const err = state.s11n.deserialize(); - if(err) error(op+"() async error:",...err); - } - return rc; - }; - -//#if nope + const opRun = opfsVfs.opRun; /** Not part of the public API. Only for test/development use. */ @@ -229,296 +219,6 @@ const installOpfsWlVfs = function callee(options){ W.postMessage({type: 'opfs-async-restart'}); } }; -//#endif - - /** - Map of sqlite3_file pointers to objects constructed by xOpen(). - */ - const __openFiles = Object.create(null); - - const opTimer = Object.create(null); - opTimer.op = undefined; - opTimer.start = undefined; - const mTimeStart = (op)=>{ - opTimer.start = performance.now(); - opTimer.op = op; - ++metrics[op].count; - }; - const mTimeEnd = ()=>( - metrics[opTimer.op].time += performance.now() - opTimer.start - ); - - /** - Impls for the sqlite3_io_methods methods. Maintenance reminder: - members are in alphabetical order to simplify finding them. - */ - const ioSyncWrappers = { - xCheckReservedLock: function(pFile,pOut){ - /** - After consultation with a topic expert: "opfs-wl" will - continue to use the same no-op impl which "opfs" does - because: - - - xCheckReservedLock() is just a hint. If SQLite needs to - lock, it's still going to try to lock. - - - We cannot do this check synchronously in "opfs-wl", - so would need to pass it to the async proxy. That would - make it inordinately expensive considering that it's - just a hint. - */ - wasm.poke(pOut, 0, 'i32'); - return 0; - }, - xClose: function(pFile){ - mTimeStart('xClose'); - let rc = 0; - const f = __openFiles[pFile]; - if(f){ - delete __openFiles[pFile]; - rc = opRun('xClose', pFile); - if(f.sq3File) f.sq3File.dispose(); - } - mTimeEnd(); - return rc; - }, - xDeviceCharacteristics: function(pFile){ - return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; - }, - xFileControl: function(pFile, opId, pArg){ - /*mTimeStart('xFileControl'); - mTimeEnd();*/ - return capi.SQLITE_NOTFOUND; - }, - xFileSize: function(pFile,pSz64){ - mTimeStart('xFileSize'); - let rc = opRun('xFileSize', pFile); - if(0==rc){ - try { - const sz = state.s11n.deserialize()[0]; - wasm.poke(pSz64, sz, 'i64'); - }catch(e){ - error("Unexpected error reading xFileSize() result:",e); - rc = state.sq3Codes.SQLITE_IOERR; - } - } - mTimeEnd(); - return rc; - }, - xLock: function(pFile, lockType){ - mTimeStart('xLock'); - const f = __openFiles[pFile]; - let rc = 0; - /* All OPFS locks are exclusive locks. If xLock() has - previously succeeded, do nothing except record the lock - type. If no lock is active, have the async counterpart - lock the file. */ - if( !f.lockType ) { - try{ - const view = state.sabOPView; - /* We need to pass pFile's name through so that the other - side can create the WebLock name. */ - state.s11n.serialize(f.filename) - Atomics.store(view, state.lock.atomicsHandshake, 0); - Atomics.store(view, state.lock.type, lockType); - Atomics.store(view, state.opIds.whichOp, state.opIds.lockControl); - Atomics.notify(state.sabOPView, state.opIds.whichOp) - while('not-equal'!==Atomics.wait(view, state.lock.atomicsHandshake, 0)){ - /* Loop is a workaround for environment-specific quirks. See - notes in similar loops. */ - } - f.lockType = lockType; - }catch(e){ - error("xLock(",arguments,") failed", e, f); - rc = capi.SQLITE_IOERR_LOCK; - } - }else{ - f.lockType = lockType; - } - mTimeEnd(); - return rc; - }, - xRead: function(pFile,pDest,n,offset64){ - mTimeStart('xRead'); - const f = __openFiles[pFile]; - let rc; - try { - rc = opRun('xRead',pFile, n, Number(offset64)); - if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){ - /** - Results get written to the SharedArrayBuffer f.sabView. - Because the heap is _not_ a SharedArrayBuffer, we have - to copy the results. TypedArray.set() seems to be the - fastest way to copy this. */ - wasm.heap8u().set(f.sabView.subarray(0, n), Number(pDest)); - } - }catch(e){ - error("xRead(",arguments,") failed:",e,f); - rc = capi.SQLITE_IOERR_READ; - } - mTimeEnd(); - return rc; - }, - xSync: function(pFile,flags){ - mTimeStart('xSync'); - ++metrics.xSync.count; - const rc = opRun('xSync', pFile, flags); - mTimeEnd(); - return rc; - }, - xTruncate: function(pFile,sz64){ - mTimeStart('xTruncate'); - const rc = opRun('xTruncate', pFile, Number(sz64)); - mTimeEnd(); - return rc; - }, - xUnlock: function(pFile,lockType){ - mTimeStart('xUnlock'); - const f = __openFiles[pFile]; - let rc = 0; - if( lockType < f.lockType ){ - try{ - const view = state.sabOPView; - Atomics.store(view, state.lock.atomicsHandshake, 1); - Atomics.notify(view, state.lock.atomicsHandshake); - Atomics.wait(view, state.lock.atomicsHandshake, 1); - }catch(e){ - error("xUnlock(",pFile,lockType,") failed",e, f); - rc = capi.SQLITE_IOERR_LOCK; - } - } - if( 0===rc ) f.lockType = lockType; - mTimeEnd(); - return rc; - }, - xWrite: function(pFile,pSrc,n,offset64){ - mTimeStart('xWrite'); - const f = __openFiles[pFile]; - let rc; - try { - f.sabView.set(wasm.heap8u().subarray( - Number(pSrc), Number(pSrc) + n - )); - rc = opRun('xWrite', pFile, n, Number(offset64)); - }catch(e){ - error("xWrite(",arguments,") failed:",e,f); - rc = capi.SQLITE_IOERR_WRITE; - } - mTimeEnd(); - return rc; - } - }/*ioSyncWrappers*/; - - /** - Impls for the sqlite3_vfs methods. Maintenance reminder: members - are in alphabetical order to simplify finding them. - */ - const vfsSyncWrappers = { - xAccess: function(pVfs,zName,flags,pOut){ - mTimeStart('xAccess'); - const rc = opRun('xAccess', wasm.cstrToJs(zName)); - wasm.poke( pOut, (rc ? 0 : 1), 'i32' ); - mTimeEnd(); - return 0; - }, - xCurrentTime: function(pVfs,pOut){ - /* If it turns out that we need to adjust for timezone, see: - https://stackoverflow.com/a/11760121/1458521 */ - wasm.poke(pOut, 2440587.5 + (new Date().getTime()/86400000), - 'double'); - return 0; - }, - xCurrentTimeInt64: function(pVfs,pOut){ - wasm.poke(pOut, (2440587.5 * 86400000) + new Date().getTime(), - 'i64'); - return 0; - }, - xDelete: function(pVfs, zName, doSyncDir){ - mTimeStart('xDelete'); - const rc = opRun('xDelete', wasm.cstrToJs(zName), doSyncDir, false); - mTimeEnd(); - return rc; - }, - xFullPathname: function(pVfs,zName,nOut,pOut){ - /* Until/unless we have some notion of "current dir" - in OPFS, simply copy zName to pOut... */ - const i = wasm.cstrncpy(pOut, zName, nOut); - return ilogImpl(2, ...args); - const warn = (...args)=>logImpl(1, ...args); - const error = (...args)=>logImpl(0, ...args); - const toss = sqlite3.util.toss; - const capi = sqlite3.capi; - const util = sqlite3.util; - const wasm = sqlite3.wasm; - const sqlite3_vfs = capi.sqlite3_vfs; - const sqlite3_file = capi.sqlite3_file; - const sqlite3_io_methods = capi.sqlite3_io_methods; - - const opfsIoMethods = new sqlite3_io_methods(); - const opfsVfs = new sqlite3_vfs() - .addOnDispose( ()=>opfsIoMethods.dispose()); - const pDVfs = capi.sqlite3_vfs_find(null)/*pointer to default VFS*/; - const dVfs = pDVfs - ? new sqlite3_vfs(pDVfs) - : null /* dVfs will be null when sqlite3 is built with - SQLITE_OS_OTHER. */; - - opfsIoMethods.$iVersion = 1; - opfsVfs.$iVersion = 2/*yes, two*/; - opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; - opfsVfs.$mxPathname = 1024/* sure, why not? The OPFS name length limit - is undocumented/unspecified. */; - opfsVfs.$zName = wasm.allocCString("opfs"); - // All C-side memory of opfsVfs is zeroed out, but just to be explicit: - opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null; - opfsVfs.addOnDispose( - '$zName', opfsVfs.$zName, - 'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null) - /** - Pedantic sidebar: the entries in this array are items to - clean up when opfsVfs.dispose() is called, but in this - environment it will never be called. The VFS instance simply - hangs around until the WASM module instance is cleaned up. We - "could" _hypothetically_ clean it up by "importing" an - sqlite3_os_end() impl into the wasm build, but the shutdown - order of the wasm engine and the JS one are undefined so - there is no guaranty that the opfsVfs instance would be - available in one environment or the other when - sqlite3_os_end() is called (_if_ it gets called at all in a - wasm build, which is undefined). - */ - ); - - /** - State which we send to the async-api Worker or share with it. - This object must initially contain only cloneable or sharable - objects. After the worker's "inited" message arrives, other types - of data may be added to it. - - For purposes of Atomics.wait() and Atomics.notify(), we use a - SharedArrayBuffer with one slot reserved for each of the API - proxy's methods. The sync side of the API uses Atomics.wait() - on the corresponding slot and the async side uses - Atomics.notify() on that slot. + const log = (...args)=>logImpl(2, ...args), + warn = (...args)=>logImpl(1, ...args), + error = (...args)=>logImpl(0, ...args), + capi = sqlite3.capi, + wasm = sqlite3.wasm; + + const state = opfsUtil.createVfsState('opfs', options), + opfsVfs = state.vfs, + metrics = opfsVfs.metrics.counters, + mTimeStart = opfsVfs.mTimeStart, + mTimeEnd = opfsVfs.mTimeEnd, + __openFiles = opfsVfs.__openFiles; + delete state.vfs; + + /* At this point, createVfsState() has populated state and + opfsVfs with any code common to both the "opfs" and "opfs-wl" + VFSes. Now comes the VFS-dependent work... */ - The approach of using a single SAB to serialize comms for all - instances might(?) lead to deadlock situations in multi-db - cases. We should probably have one SAB here with a single slot - for locking a per-file initialization step and then allocate a - separate SAB like the above one for each file. That will - require a bit of acrobatics but should be feasible. The most - problematic part is that xOpen() would have to use - postMessage() to communicate its SharedArrayBuffer, and mixing - that approach with Atomics.wait/notify() gets a bit messy. - */ - const state = opfsUtil.createVfsStateObject(opfsVfs); - state.verbose = options.verbose; - const metrics = opfsVfs.metrics.counters; let promiseWasRejected = undefined; const promiseReject = (err)=>{ promiseWasRejected = true; @@ -192,14 +129,14 @@ const installOpfsVfs = function callee(options){ promiseWasRejected = false; return promiseResolve_(sqlite3); }; - const workerArgs = '?vfs=opfs'; - const W = + options.proxyUri += '?vfs=opfs'; + const W = opfsVfs.worker = //#if target:es6-bundler-friendly new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs", import.meta.url)); //#elif target:es6-module - new Worker(new URL(options.proxyUri+workerArgs, import.meta.url)); + new Worker(new URL(options.proxyUri, import.meta.url)); //#else - new Worker(options.proxyUri+workerArgs); + new Worker(options.proxyUri); //#endif setTimeout(()=>{ /* At attempt to work around a browser-specific quirk in which @@ -221,46 +158,7 @@ const installOpfsVfs = function callee(options){ promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons.")); }; - /** - Runs the given operation (by name) in the async worker - counterpart, waits for its response, and returns the result - which the async worker writes to SAB[state.opIds.rc]. The - 2nd and subsequent arguments must be the arguments for the - async op. - */ - const opRun = (op,...args)=>{ - const opNdx = state.opIds[op] || toss("Invalid op ID:",op); - state.s11n.serialize(...args); - Atomics.store(state.sabOPView, state.opIds.rc, -1); - Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); - Atomics.notify(state.sabOPView, state.opIds.whichOp) - /* async thread will take over here */; - const t = performance.now(); - while('not-equal'!==Atomics.wait(state.sabOPView, state.opIds.rc, -1)){ - /* - The reason for this loop is buried in the details of a long - discussion at: - - https://github.com/sqlite/sqlite-wasm/issues/12 - - Summary: in at least one browser flavor, under high loads, - the wait()/notify() pairings can get out of sync. Calling - wait() here until it returns 'not-equal' gets them back in - sync. - */ - } - /* When the above wait() call returns 'not-equal', the async - half will have completed the operation and reported its results - in the state.opIds.rc slot of the SAB. */ - const rc = Atomics.load(state.sabOPView, state.opIds.rc); - metrics[op].wait += performance.now() - t; - if(rc && state.asyncS11nExceptions){ - const err = state.s11n.deserialize(); - if(err) error(op+"() async error:",...err); - } - return rc; - }; - + const opRun = opfsVfs.opRun; //#if nope /** Not part of the public API. Only for test/development use. @@ -277,272 +175,38 @@ const installOpfsVfs = function callee(options){ }; //#endif - /** - Map of sqlite3_file pointers to objects constructed by xOpen(). - */ - const __openFiles = Object.create(null); - - const opTimer = Object.create(null); - opTimer.op = undefined; - opTimer.start = undefined; - const mTimeStart = (op)=>{ - opTimer.start = performance.now(); - opTimer.op = op; - ++metrics[op].count; + opfsVfs.ioSyncWrappers.xLock = function(pFile,lockType){ + mTimeStart('xLock'); + ++metrics.xLock.count; + const f = __openFiles[pFile]; + let rc = 0; + /* All OPFS locks are exclusive locks. If xLock() has + previously succeeded, do nothing except record the lock + type. If no lock is active, have the async counterpart + lock the file. */ + if( f.lockType ) { + f.lockType = lockType; + }else{ + rc = opRun('xLock', pFile, lockType); + if( 0===rc ) f.lockType = lockType; + } + mTimeEnd(); + return rc; }; - const mTimeEnd = ()=>( - metrics[opTimer.op].time += performance.now() - opTimer.start - ); - - /** - Impls for the sqlite3_io_methods methods. Maintenance reminder: - members are in alphabetical order to simplify finding them. - */ - const ioSyncWrappers = { - xCheckReservedLock: function(pFile,pOut){ - /** - As of late 2022, only a single lock can be held on an OPFS - file. We have no way of checking whether any _other_ db - connection has a lock except by trying to obtain and (on - success) release a sync-handle for it, but doing so would - involve an inherent race condition. For the time being, - pending a better solution, we simply report whether the - given pFile is open. - - Update 2024-06-12: based on forum discussions, this - function now always sets pOut to 0 (false): - https://sqlite.org/forum/forumpost/a2f573b00cda1372 - */ - wasm.poke(pOut, 0, 'i32'); - return 0; - }, - xClose: function(pFile){ - mTimeStart('xClose'); - let rc = 0; - const f = __openFiles[pFile]; - if(f){ - delete __openFiles[pFile]; - rc = opRun('xClose', pFile); - if(f.sq3File) f.sq3File.dispose(); - } - mTimeEnd(); - return rc; - }, - xDeviceCharacteristics: function(pFile){ - return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; - }, - xFileControl: function(pFile, opId, pArg){ - /*mTimeStart('xFileControl'); - mTimeEnd();*/ - return capi.SQLITE_NOTFOUND; - }, - xFileSize: function(pFile,pSz64){ - mTimeStart('xFileSize'); - let rc = opRun('xFileSize', pFile); - if(0==rc){ - try { - const sz = state.s11n.deserialize()[0]; - wasm.poke(pSz64, sz, 'i64'); - }catch(e){ - error("Unexpected error reading xFileSize() result:",e); - rc = state.sq3Codes.SQLITE_IOERR; - } - } - mTimeEnd(); - return rc; - }, - xLock: function(pFile,lockType){ - mTimeStart('xLock'); - const f = __openFiles[pFile]; - let rc = 0; - /* All OPFS locks are exclusive locks. If xLock() has - previously succeeded, do nothing except record the lock - type. If no lock is active, have the async counterpart - lock the file. */ - if( !f.lockType ) { - rc = opRun('xLock', pFile, lockType); - if( 0===rc ) f.lockType = lockType; - }else{ - f.lockType = lockType; - } - mTimeEnd(); - return rc; - }, - xRead: function(pFile,pDest,n,offset64){ - mTimeStart('xRead'); - const f = __openFiles[pFile]; - let rc; - try { - rc = opRun('xRead',pFile, n, Number(offset64)); - if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){ - /** - Results get written to the SharedArrayBuffer f.sabView. - Because the heap is _not_ a SharedArrayBuffer, we have - to copy the results. TypedArray.set() seems to be the - fastest way to copy this. */ - wasm.heap8u().set(f.sabView.subarray(0, n), Number(pDest)); - } - }catch(e){ - error("xRead(",arguments,") failed:",e,f); - rc = capi.SQLITE_IOERR_READ; - } - mTimeEnd(); - return rc; - }, - xSync: function(pFile,flags){ - mTimeStart('xSync'); - ++metrics.xSync.count; - const rc = opRun('xSync', pFile, flags); - mTimeEnd(); - return rc; - }, - xTruncate: function(pFile,sz64){ - mTimeStart('xTruncate'); - const rc = opRun('xTruncate', pFile, Number(sz64)); - mTimeEnd(); - return rc; - }, - xUnlock: function(pFile,lockType){ - mTimeStart('xUnlock'); - const f = __openFiles[pFile]; - let rc = 0; - if( capi.SQLITE_LOCK_NONE === lockType + opfsVfs.ioSyncWrappers.xUnlock = function(pFile,lockType){ + mTimeStart('xUnlock'); + ++metrics.xUnlock.count; + const f = __openFiles[pFile]; + let rc = 0; + if( capi.SQLITE_LOCK_NONE === lockType && f.lockType ){ - rc = opRun('xUnlock', pFile, lockType); - } - if( 0===rc ) f.lockType = lockType; - mTimeEnd(); - return rc; - }, - xWrite: function(pFile,pSrc,n,offset64){ - mTimeStart('xWrite'); - const f = __openFiles[pFile]; - let rc; - try { - f.sabView.set(wasm.heap8u().subarray( - Number(pSrc), Number(pSrc) + n - )); - rc = opRun('xWrite', pFile, n, Number(offset64)); - }catch(e){ - error("xWrite(",arguments,") failed:",e,f); - rc = capi.SQLITE_IOERR_WRITE; - } - mTimeEnd(); - return rc; + rc = opRun('xUnlock', pFile, lockType); } - }/*ioSyncWrappers*/; - - /** - Impls for the sqlite3_vfs methods. Maintenance reminder: members - are in alphabetical order to simplify finding them. - */ - const vfsSyncWrappers = { - xAccess: function(pVfs,zName,flags,pOut){ - mTimeStart('xAccess'); - const rc = opRun('xAccess', wasm.cstrToJs(zName)); - wasm.poke( pOut, (rc ? 0 : 1), 'i32' ); - mTimeEnd(); - return 0; - }, - xCurrentTime: function(pVfs,pOut){ - /* If it turns out that we need to adjust for timezone, see: - https://stackoverflow.com/a/11760121/1458521 */ - wasm.poke(pOut, 2440587.5 + (new Date().getTime()/86400000), - 'double'); - return 0; - }, - xCurrentTimeInt64: function(pVfs,pOut){ - wasm.poke(pOut, (2440587.5 * 86400000) + new Date().getTime(), - 'i64'); - return 0; - }, - xDelete: function(pVfs, zName, doSyncDir){ - mTimeStart('xDelete'); - const rc = opRun('xDelete', wasm.cstrToJs(zName), doSyncDir, false); - mTimeEnd(); - return rc; - }, - xFullPathname: function(pVfs,zName,nOut,pOut){ - /* Until/unless we have some notion of "current dir" - in OPFS, simply copy zName to pOut... */ - const i = wasm.cstrncpy(pOut, zName, nOut); - return i Date: Wed, 4 Mar 2026 19:21:09 +0000 Subject: [PATCH 095/197] Consolidate the last 200 lines of common OPFS VFS code. "opfs" still works, "opfs-wl" registers fine but is still otherwise untested. FossilOrigin-Name: 5978ee4902e4223fed6b95bd2d8f489bb300af8b762650e7113d1f3e97519d88 --- ext/wasm/api/opfs-common-shared.c-pp.js | 287 ++++++++++++++++++++-- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 296 +++-------------------- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 269 +++----------------- manifest | 16 +- manifest.uuid | 2 +- 5 files changed, 335 insertions(+), 535 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index feefca5eb4..5150fb8e61 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -18,19 +18,18 @@ */ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'use strict'; - const toss = sqlite3.util.toss; - const capi = sqlite3.capi; - const util = sqlite3.util; - const wasm = sqlite3.wasm; + const toss = sqlite3.util.toss, + capi = sqlite3.capi, + util = sqlite3.util, + wasm = sqlite3.wasm; /** Generic utilities for working with OPFS. This will get filled out by the Promise setup and, on success, installed as sqlite3.opfs. - This is an internal/private namespace intended for use solely - by the OPFS VFSes and test code for them. The library bootstrapping + This is an internal/private namespace intended for use solely by + the OPFS VFSes and test code for them. The library bootstrapping process removes this object in non-testing contexts. - */ const opfsUtil = sqlite3.opfs = Object.create(null); @@ -421,14 +420,44 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } }; + /** + Must be called by the VFS's main installation routine and passed + the options object that function receives and a reference to that + function itself (which is assumed to have a defaultProxyUri + property set on it. See sqlite3-vfs-opfs{,-wl}.c-pp.js for + examples. + + It throws if OPFS is not available. + + If it returns falsy, it detected that OPFS should be disabled, in + which case the callee should immediately return/resolve to the + sqlite3 object. + + Else it returns a new copy of the options object, fleshed out + with any missing defaults. The caller must: + + - Set up any local state they need. + + - Call opfsUtil.createVfsState(vfsName,opt), where opt is the + object returned by this function. + + - Set up any references they may need to state returned + by the previous step. + + - Call opfvs.doTheThing() + */ opfsUtil.initOptions = function(options, callee){ - options = util.nu(options); const urlParams = new URL(globalThis.location.href).searchParams; if(urlParams.has('opfs-disable')){ //sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.'); - options.disableOpfs = true; - return options; + return; + } + try{ + opfsUtil.vfsInstallationFeatureCheck(); + }catch(e){ + return; } + options = util.nu(options); if(undefined===options.verbose){ options.verbose = urlParams.has('opfs-verbose') ? (+urlParams.get('opfs-verbose') || 2) : 1; @@ -449,14 +478,18 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ Creates and populates the main state object used by "opfs" and "opfs-wl", and transfered from those to their async counterpart. - Returns an object containing state which we send to the async-api - Worker or share with it. + Returns an object containing state which we send to the async + proxy Worker. - Because the returned object must be serializable to be posted to - the async proxy, after this returns, the caller must: + The returned object's vfs property holds the fully-populated + capi.sqlite3_vfs instance. - - Make a local-scope reference of state.vfs then (delete - state.vfs). That's the capi.sqlite3_vfs instance for the VFS. + After setting up any local state needed, the caller must + call theVfs.doTheThing(X,Y), where X is an object containing + the sqlite3_io_methods to override and Y is a callback which + gets triggered if init succeeds, before the final Promise + decides whether or not to reject. The result of doTheThing() + must be returned from their main installation function. This object must, when it's passed to the async part, contain only cloneable or sharable objects. After the worker's "inited" @@ -1013,6 +1046,228 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ //#include api/opfs-common-inline.c-pp.js //#undef vfs.metrics.enable opfsVfs.initS11n = initS11n; + + /** + To be called by the VFS's main installation routine after it has + wired up enough state to provide its overridden io-method impls + (which must be properties of the ioMethods argument). Returns a + Promise which the installation routine must return. callback must + be a function which performs any post-bootstrap touchups, namely + plugging in a sqlite3.oo1 wrapper. It is passed (sqlite3, opfsVfs), + where opfsVfs is the sqlite3_vfs object which was set up by + opfsUtil.createVfsState(). + */ + opfsVfs.doTheThing = function(ioMethods, callback){ + Object.assign(opfsVfs.ioSyncWrappers, ioMethods); + const thePromise = new Promise(function(promiseResolve_, promiseReject_){ + const loggers = [ + sqlite3.config.error, + sqlite3.config.warn, + sqlite3.config.log + ]; + const logImpl = (level,...args)=>{ + if(options.verbose>level) loggers[level]("OPFS syncer:",...args); + }; + const log = (...args)=>logImpl(2, ...args), + warn = (...args)=>logImpl(1, ...args), + error = (...args)=>logImpl(0, ...args), + capi = sqlite3.capi, + wasm = sqlite3.wasm; + + let promiseWasRejected = undefined; + const promiseReject = (err)=>{ + promiseWasRejected = true; + opfsVfs.dispose(); + return promiseReject_(err); + }; + const promiseResolve = ()=>{ + try{ + callback(sqlite3, opfsVfs); + }catch(e){ + return promiseReject(e); + } + promiseWasRejected = false; + return promiseResolve_(sqlite3); + }; + options.proxyUri += '?vfs='+vfsName; + const W = opfsVfs.worker = +//#if target:es6-bundler-friendly + new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs", import.meta.url)); +//#elif target:es6-module + new Worker(new URL(options.proxyUri, import.meta.url)); +//#else + new Worker(options.proxyUri); +//#endif + setTimeout(()=>{ + /* At attempt to work around a browser-specific quirk in which + the Worker load is failing in such a way that we neither + resolve nor reject it. This workaround gives that resolve/reject + a time limit and rejects if that timer expires. Discussion: + https://sqlite.org/forum/forumpost/a708c98dcb3ef */ + if(undefined===promiseWasRejected){ + promiseReject( + new Error("Timeout while waiting for OPFS async proxy worker.") + ); + } + }, 4000); + W._originalOnError = W.onerror /* will be restored later */; + W.onerror = function(err){ + // The error object doesn't contain any useful info when the + // failure is, e.g., that the remote script is 404. + error("Error initializing OPFS asyncer:",err); + promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons.")); + }; + + const opRun = opfsVfs.opRun; +//#if nope + /** + Not part of the public API. Only for test/development use. + */ + opfsVfs.debug = { + asyncShutdown: ()=>{ + warn("Shutting down OPFS async listener. The OPFS VFS will no longer work."); + opRun('opfs-async-shutdown'); + }, + asyncRestart: ()=>{ + warn("Attempting to restart OPFS VFS async listener. Might work, might not."); + W.postMessage({type: 'opfs-async-restart'}); + } + }; +//#endif + + const sanityCheck = function(){ + const scope = wasm.scopedAllocPush(); + const sq3File = new capi.sqlite3_file(); + try{ + const fid = sq3File.pointer; + const openFlags = capi.SQLITE_OPEN_CREATE + | capi.SQLITE_OPEN_READWRITE + //| capi.SQLITE_OPEN_DELETEONCLOSE + | capi.SQLITE_OPEN_MAIN_DB; + const pOut = wasm.scopedAlloc(8); + const dbFile = "/sanity/check/file"+randomFilename(8); + const zDbFile = wasm.scopedAllocCString(dbFile); + let rc; + state.s11n.serialize("This is ä string."); + rc = state.s11n.deserialize(); + log("deserialize() says:",rc); + if("This is ä string."!==rc[0]) toss("String d13n error."); + opfsVfs.vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); + rc = wasm.peek(pOut,'i32'); + log("xAccess(",dbFile,") exists ?=",rc); + rc = opfsVfs.vfsSyncWrappers.xOpen(opfsVfs.pointer, zDbFile, + fid, openFlags, pOut); + log("open rc =",rc,"state.sabOPView[xOpen] =", + state.sabOPView[state.opIds.xOpen]); + if(0!==rc){ + error("open failed with code",rc); + return; + } + opfsVfs.vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); + rc = wasm.peek(pOut,'i32'); + if(!rc) toss("xAccess() failed to detect file."); + rc = opfsVfs.ioSyncWrappers.xSync(sq3File.pointer, 0); + if(rc) toss('sync failed w/ rc',rc); + rc = opfsVfs.ioSyncWrappers.xTruncate(sq3File.pointer, 1024); + if(rc) toss('truncate failed w/ rc',rc); + wasm.poke(pOut,0,'i64'); + rc = opfsVfs.ioSyncWrappers.xFileSize(sq3File.pointer, pOut); + if(rc) toss('xFileSize failed w/ rc',rc); + log("xFileSize says:",wasm.peek(pOut, 'i64')); + rc = opfsVfs.ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1); + if(rc) toss("xWrite() failed!"); + const readBuf = wasm.scopedAlloc(16); + rc = opfsVfs.ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2); + wasm.poke(readBuf+6,0); + let jRead = wasm.cstrToJs(readBuf); + log("xRead() got:",jRead); + if("sanity"!==jRead) toss("Unexpected xRead() value."); + if(opfsVfs.vfsSyncWrappers.xSleep){ + log("xSleep()ing before close()ing..."); + opfsVfs.vfsSyncWrappers.xSleep(opfsVfs.pointer,2000); + log("waking up from xSleep()"); + } + rc = opfsVfs.ioSyncWrappers.xClose(fid); + log("xClose rc =",rc,"sabOPView =",state.sabOPView); + log("Deleting file:",dbFile); + opfsVfs.vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 0x1234); + opfsVfs.vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); + rc = wasm.peek(pOut,'i32'); + if(rc) toss("Expecting 0 from xAccess(",dbFile,") after xDelete()."); + warn("End of OPFS sanity checks."); + }finally{ + sq3File.dispose(); + wasm.scopedAllocPop(scope); + } + }/*sanityCheck()*/; + + W.onmessage = function({data}){ + //log("Worker.onmessage:",data); + switch(data.type){ + case 'opfs-unavailable': + /* Async proxy has determined that OPFS is unavailable. There's + nothing more for us to do here. */ + promiseReject(new Error(data.payload.join(' '))); + break; + case 'opfs-async-loaded': + /* Arrives as soon as the asyc proxy finishes loading. + Pass our config and shared state on to the async + worker. */ + delete state.vfs; + W.postMessage({type: 'opfs-async-init', args: util.nu(state)}); + break; + case 'opfs-async-inited': { + /* Indicates that the async partner has received the 'init' + and has finished initializing, so the real work can + begin... */ + if(true===promiseWasRejected){ + break /* promise was already rejected via timer */; + } + try { + sqlite3.vfs.installVfs({ + io: {struct: opfsVfs.ioMethods, methods: opfsVfs.ioSyncWrappers}, + vfs: {struct: opfsVfs, methods: opfsVfs.vfsSyncWrappers} + }); + state.sabOPView = new Int32Array(state.sabOP); + state.sabFileBufView = new Uint8Array(state.sabIO, 0, state.fileBufferSize); + state.sabS11nView = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize); + opfsVfs.initS11n(); + delete opfsVfs.initS11n; + if(options.sanityChecks){ + warn("Running sanity checks because of opfs-sanity-check URL arg..."); + sanityCheck(); + } + if(opfsUtil.thisThreadHasOPFS()){ + opfsUtil.getRootDir().then((d)=>{ + W.onerror = W._originalOnError; + delete W._originalOnError; + log("End of OPFS sqlite3_vfs setup.", opfsVfs); + promiseResolve(); + }).catch(promiseReject); + }else{ + promiseResolve(); + } + }catch(e){ + error(e); + promiseReject(e); + } + break; + } + default: { + const errMsg = ( + "Unexpected message from the OPFS async worker: " + + JSON.stringify(data) + ); + error(errMsg); + promiseReject(new Error(errMsg)); + break; + } + }/*switch(data.type)*/ + }/*W.onmessage()*/; + })/*thePromise*/; + return thePromise; + }/*doTheThing()*/; + return state; }/*createVfsState()*/; diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 134b62b107..e62f23ed14 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -36,9 +36,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const util = sqlite3.util, toss = sqlite3.util.toss; - const opfsUtil = sqlite3.opfs || sqlite3.util.toss("Missing sqlite3.opfs") - /* These get removed from sqlite3 during bootstrap, so we need an - early reference to it. */; + const opfsUtil = sqlite3.opfs || toss("Missing sqlite3.opfs"); /** installOpfsWlVfs() returns a Promise which, on success, installs an @@ -46,7 +44,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ which accept a VFS. It is intended to be called via sqlite3ApiBootstrap.initializers or an equivalent mechanism. - This VFS is essentially a copy of the "opfs" VFS but uses + This VFS is essentially identical to the "opfs" VFS but uses WebLocks for its xLock() and xUnlock() implementations. Quirks specific to this VFS: @@ -54,69 +52,30 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ - Because WebLocks effectively block until they return, they will effectively hang on locks rather than returning SQLITE_BUSY. - - The argument may optionally be a plain object with the following - configuration options: - - - proxyUri: name of the async proxy JS file. - - - verbose (=2): an integer 0-3. 0 disables all logging, 1 enables - logging of errors. 2 enables logging of warnings and errors. 3 - additionally enables debugging info. Logging is performed - via the sqlite3.config.{log|warn|error}() functions. - - - On success, the Promise resolves to the top-most sqlite3 namespace - object. Success does not necessarily mean that it installs the VFS, - as there are legitimate non-error reasons for OPFS not to be - available. + Aside from locking differences in the VFSes, this function + otherwise behaves the same as + sqlite3-vfs-opfs.c-pp.js:installOpfsVfs(). */ -const installOpfsWlVfs = function callee(options){ - try{ - opfsUtil.vfsInstallationFeatureCheck(); - }catch(e){ - return Promise.reject(e); - } +const installOpfsWlVfs = async function callee(options){ options = opfsUtil.initOptions(options, callee); - if( options.disableOpfs ){ - return Promise.resolve(sqlite3); - } - - const thePromise = new Promise(function(promiseResolve_, promiseReject_){ - const loggers = [ - sqlite3.config.error, - sqlite3.config.warn, - sqlite3.config.log - ]; - const logImpl = (level,...args)=>{ - if(options.verbose>level) loggers[level]("OPFS syncer:",...args); - }; - const log = (...args)=>logImpl(2, ...args), - warn = (...args)=>logImpl(1, ...args), - error = (...args)=>logImpl(0, ...args), - capi = sqlite3.capi, - wasm = sqlite3.wasm; - const state = opfsUtil.createVfsState('opfs-wl', options), - opfsVfs = state.vfs, - metrics = opfsVfs.metrics.counters, - mTimeStart = opfsVfs.mTimeStart, - mTimeEnd = opfsVfs.mTimeEnd, - __openFiles = opfsVfs.__openFiles; - delete state.vfs; - - /* At this point, createVfsState() has populated state and - opfsVfs with any code common to both the "opfs" and "opfs-wl" - VFSes. Now comes the VFS-dependent work... */ - - opfsVfs.ioSyncWrappers.xLock = function(pFile, lockType){ + if( !options ) return sqlite3; + const capi = sqlite3.capi, + state = opfsUtil.createVfsState('opfs-wl', options), + opfsVfs = state.vfs, + metrics = opfsVfs.metrics.counters, + mTimeStart = opfsVfs.mTimeStart, + mTimeEnd = opfsVfs.mTimeEnd, + __openFiles = opfsVfs.__openFiles; + /* At this point, createVfsState() has populated state and opfsVfs + with any code common to both the "opfs" and "opfs-wl" VFSes. Now + comes the VFS-dependent work... */ + return opfsVfs.doTheThing(util.nu({ + xLock: function(pFile, lockType){ mTimeStart('xLock'); ++metrics.xLock.count; const f = __openFiles[pFile]; let rc = 0; - /* All OPFS locks are exclusive locks. If xLock() has - previously succeeded, do nothing except record the lock - type. If no lock is active, have the async counterpart - lock the file. */ + /* See notes in sqlite3-vfs-opfs.c-pp.js. */ if( f.lockType ) { f.lockType = lockType; }else{ @@ -141,9 +100,8 @@ const installOpfsWlVfs = function callee(options){ } mTimeEnd(); return rc; - }; - - opfsVfs.ioSyncWrappers.xUnlock =function(pFile,lockType){ + }, + xUnlock: function(pFile,lockType){ mTimeStart('xUnlock'); ++metrics.xUnlock.count; const f = __openFiles[pFile]; @@ -162,64 +120,8 @@ const installOpfsWlVfs = function callee(options){ if( 0===rc ) f.lockType = lockType; mTimeEnd(); return rc; - }; - - - - let promiseWasRejected = undefined; - const promiseReject = (err)=>{ - promiseWasRejected = true; - opfsVfs.dispose(); - return promiseReject_(err); - }; - const promiseResolve = ()=>{ - promiseWasRejected = false; - return promiseResolve_(sqlite3); - }; - options.proxyUri += '?vfs=opfs-wl'; - const W = opfsVfs.worker = -//#if target:es6-bundler-friendly - new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs-wl", import.meta.url)); -//#elif target:es6-module - new Worker(new URL(options.proxyUri, import.meta.url)); -//#else - new Worker(options.proxyUri); -//#endif - setTimeout(()=>{ - /* At attempt to work around a browser-specific quirk in which - the Worker load is failing in such a way that we neither - resolve nor reject it. This workaround gives that resolve/reject - a time limit and rejects if that timer expires. Discussion: - https://sqlite.org/forum/forumpost/a708c98dcb3ef */ - if(undefined===promiseWasRejected){ - promiseReject( - new Error("Timeout while waiting for OPFS async proxy worker.") - ); - } - }, 4000); - W._originalOnError = W.onerror /* will be restored later */; - W.onerror = function(err){ - // The error object doesn't contain any useful info when the - // failure is, e.g., that the remote script is 404. - error("Error initializing OPFS asyncer:",err); - promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons.")); - }; - - const opRun = opfsVfs.opRun; - /** - Not part of the public API. Only for test/development use. - */ - opfsUtil.debug = { - asyncShutdown: ()=>{ - warn("Shutting down OPFS async listener. The OPFS VFS will no longer work."); - opRun('opfs-async-shutdown'); - }, - asyncRestart: ()=>{ - warn("Attempting to restart OPFS VFS async listener. Might work, might not."); - W.postMessage({type: 'opfs-async-restart'}); - } - }; - + } + }), function(sqlite3, vfs){ if(sqlite3.oo1){ const OpfsWlDb = function(...args){ const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); @@ -229,156 +131,14 @@ const installOpfsWlVfs = function callee(options){ OpfsWlDb.prototype = Object.create(sqlite3.oo1.DB.prototype); sqlite3.oo1.OpfsWlDb = OpfsWlDb; OpfsWlDb.importDb = opfsUtil.importDb; -//#if nope - sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback( - opfsVfs.pointer, - function(oo1Db, sqlite3){ - /* Set a relatively high default busy-timeout handler to - help OPFS dbs deal with multi-tab/multi-worker - contention. */ - sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000); - } - ); -//#endif }/*extend sqlite3.oo1*/ - - const sanityCheck = function(){ - const scope = wasm.scopedAllocPush(); - const sq3File = new capi.sqlite3_file(); - try{ - const fid = sq3File.pointer; - const openFlags = capi.SQLITE_OPEN_CREATE - | capi.SQLITE_OPEN_READWRITE - //| capi.SQLITE_OPEN_DELETEONCLOSE - | capi.SQLITE_OPEN_MAIN_DB; - const pOut = wasm.scopedAlloc(8); - const dbFile = "/sanity/check/file"+randomFilename(8); - const zDbFile = wasm.scopedAllocCString(dbFile); - let rc; - state.s11n.serialize("This is ä string."); - rc = state.s11n.deserialize(); - log("deserialize() says:",rc); - if("This is ä string."!==rc[0]) toss("String d13n error."); - opfsVfs.vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut,'i32'); - log("xAccess(",dbFile,") exists ?=",rc); - rc = opfsVfs.vfsSyncWrappers.xOpen(opfsVfs.pointer, zDbFile, - fid, openFlags, pOut); - log("open rc =",rc,"state.sabOPView[xOpen] =", - state.sabOPView[state.opIds.xOpen]); - if(0!==rc){ - error("open failed with code",rc); - return; - } - opfsVfs.vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut,'i32'); - if(!rc) toss("xAccess() failed to detect file."); - rc = opfsVfs.ioSyncWrappers.xSync(sq3File.pointer, 0); - if(rc) toss('sync failed w/ rc',rc); - rc = opfsVfs.ioSyncWrappers.xTruncate(sq3File.pointer, 1024); - if(rc) toss('truncate failed w/ rc',rc); - wasm.poke(pOut,0,'i64'); - rc = opfsVfs.ioSyncWrappers.xFileSize(sq3File.pointer, pOut); - if(rc) toss('xFileSize failed w/ rc',rc); - log("xFileSize says:",wasm.peek(pOut, 'i64')); - rc = opfsVfs.ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1); - if(rc) toss("xWrite() failed!"); - const readBuf = wasm.scopedAlloc(16); - rc = opfsVfs.ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2); - wasm.poke(readBuf+6,0); - let jRead = wasm.cstrToJs(readBuf); - log("xRead() got:",jRead); - if("sanity"!==jRead) toss("Unexpected xRead() value."); - if(opfsVfs.vfsSyncWrappers.xSleep){ - log("xSleep()ing before close()ing..."); - opfsVfs.vfsSyncWrappers.xSleep(opfsVfs.pointer,2000); - log("waking up from xSleep()"); - } - rc = opfsVfs.ioSyncWrappers.xClose(fid); - log("xClose rc =",rc,"sabOPView =",state.sabOPView); - log("Deleting file:",dbFile); - opfsVfs.vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 0x1234); - opfsVfs.vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut,'i32'); - if(rc) toss("Expecting 0 from xAccess(",dbFile,") after xDelete()."); - warn("End of OPFS sanity checks."); - }finally{ - sq3File.dispose(); - wasm.scopedAllocPop(scope); - } - }/*sanityCheck()*/; - - W.onmessage = function({data}){ - //log("Worker.onmessage:",data); - switch(data.type){ - case 'opfs-unavailable': - /* Async proxy has determined that OPFS is unavailable. There's - nothing more for us to do here. */ - promiseReject(new Error(data.payload.join(' '))); - break; - case 'opfs-async-loaded': - /* Arrives as soon as the asyc proxy finishes loading. - Pass our config and shared state on to the async - worker. */ - W.postMessage({type: 'opfs-async-init', args: util.nu(state)}); - break; - case 'opfs-async-inited': { - /* Indicates that the async partner has received the 'init' - and has finished initializing, so the real work can - begin... */ - if(true===promiseWasRejected){ - break /* promise was already rejected via timer */; - } - try { - sqlite3.vfs.installVfs({ - io: {struct: opfsVfs.ioMethods, methods: opfsVfs.ioSyncWrappers}, - vfs: {struct: opfsVfs, methods: opfsVfs.vfsSyncWrappers} - }); - state.sabOPView = new Int32Array(state.sabOP); - state.sabFileBufView = new Uint8Array(state.sabIO, 0, state.fileBufferSize); - state.sabS11nView = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize); - opfsVfs.initS11n(); - delete opfsVfs.initS11n; - if(options.sanityChecks){ - warn("Running sanity checks because of opfs-sanity-check URL arg..."); - sanityCheck(); - } - if(opfsUtil.thisThreadHasOPFS()){ - opfsUtil.getRootDir().then((d)=>{ - W.onerror = W._originalOnError; - delete W._originalOnError; - log("End of OPFS-WL sqlite3_vfs setup.", opfsVfs); - promiseResolve(); - }).catch(promiseReject); - }else{ - promiseResolve(); - } - }catch(e){ - error(e); - promiseReject(e); - } - break; - } - default: { - const errMsg = ( - "Unexpected message from the OPFS async worker: " + - JSON.stringify(data) - ); - error(errMsg); - promiseReject(new Error(errMsg)); - break; - } - }/*switch(data.type)*/ - }/*W.onmessage()*/; - })/*thePromise*/; - return thePromise; + })/*doTheThing()*/; }/*installOpfsWlVfs()*/; -installOpfsWlVfs.defaultProxyUri = - "sqlite3-opfs-async-proxy.js"; +installOpfsWlVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ try{ let proxyJs = installOpfsWlVfs.defaultProxyUri; - if( sqlite3?.scriptInfo?.sqlite3Dir ){ + if( sqlite3.scriptInfo?.sqlite3Dir ){ installOpfsWlVfs.defaultProxyUri = sqlite3.scriptInfo.sqlite3Dir + proxyJs; //sqlite3.config.warn("installOpfsWlVfs.defaultProxyUri =",installOpfsWlVfs.defaultProxyUri); @@ -392,6 +152,4 @@ globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ } }); }/*sqlite3ApiBootstrap.initializers.push()*/); -//#else -/* The OPFS VFS parts are elided from builds targeting node.js. */ //#endif target:node diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 7b72199e65..6fe317ec8d 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -21,10 +21,7 @@ 'use strict'; globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const util = sqlite3.util, - toss = sqlite3.util.toss; - const opfsUtil = sqlite3.opfs || sqlite3.util.toss("Missing sqlite3.opfs") - /* These get removed from sqlite3 during bootstrap, so we need an - early reference to it. */; + opfsUtil = sqlite3.opfs || sqlite3.util.toss("Missing sqlite3.opfs"); /** installOpfsVfs() returns a Promise which, on success, installs an sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs @@ -75,107 +72,31 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ Promise resolves. This is only intended for testing and development of the VFS, not client-side use. + Additionaly, the (officially undocumented) 'opfs-disable' URL + argument will disable OPFS, making this function a no-op. + On success, the Promise resolves to the top-most sqlite3 namespace object. Success does not necessarily mean that it installs the VFS, as there are legitimate non-error reasons for OPFS not to be available. */ -const installOpfsVfs = function callee(options){ - try{ - opfsUtil.vfsInstallationFeatureCheck(); - }catch(e){ - return Promise.reject(e); - } +const installOpfsVfs = async function callee(options){ options = opfsUtil.initOptions(options, callee); - if( options.disableOpfs ){ - return Promise.resolve(sqlite3); - } - - //sqlite3.config.warn("OPFS options =",options,globalThis.location); - const thePromise = new Promise(function(promiseResolve_, promiseReject_){ - const loggers = [ - sqlite3.config.error, - sqlite3.config.warn, - sqlite3.config.log - ]; - const logImpl = (level,...args)=>{ - if(options.verbose>level) loggers[level]("OPFS syncer:",...args); - }; - const log = (...args)=>logImpl(2, ...args), - warn = (...args)=>logImpl(1, ...args), - error = (...args)=>logImpl(0, ...args), - capi = sqlite3.capi, - wasm = sqlite3.wasm; - - const state = opfsUtil.createVfsState('opfs', options), - opfsVfs = state.vfs, - metrics = opfsVfs.metrics.counters, - mTimeStart = opfsVfs.mTimeStart, - mTimeEnd = opfsVfs.mTimeEnd, - __openFiles = opfsVfs.__openFiles; - delete state.vfs; - - /* At this point, createVfsState() has populated state and - opfsVfs with any code common to both the "opfs" and "opfs-wl" - VFSes. Now comes the VFS-dependent work... */ - - let promiseWasRejected = undefined; - const promiseReject = (err)=>{ - promiseWasRejected = true; - opfsVfs.dispose(); - return promiseReject_(err); - }; - const promiseResolve = ()=>{ - promiseWasRejected = false; - return promiseResolve_(sqlite3); - }; - options.proxyUri += '?vfs=opfs'; - const W = opfsVfs.worker = -//#if target:es6-bundler-friendly - new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs", import.meta.url)); -//#elif target:es6-module - new Worker(new URL(options.proxyUri, import.meta.url)); -//#else - new Worker(options.proxyUri); -//#endif - setTimeout(()=>{ - /* At attempt to work around a browser-specific quirk in which - the Worker load is failing in such a way that we neither - resolve nor reject it. This workaround gives that resolve/reject - a time limit and rejects if that timer expires. Discussion: - https://sqlite.org/forum/forumpost/a708c98dcb3ef */ - if(undefined===promiseWasRejected){ - promiseReject( - new Error("Timeout while waiting for OPFS async proxy worker.") - ); - } - }, 4000); - W._originalOnError = W.onerror /* will be restored later */; - W.onerror = function(err){ - // The error object doesn't contain any useful info when the - // failure is, e.g., that the remote script is 404. - error("Error initializing OPFS asyncer:",err); - promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons.")); - }; - - const opRun = opfsVfs.opRun; -//#if nope - /** - Not part of the public API. Only for test/development use. - */ - opfsUtil.debug = { - asyncShutdown: ()=>{ - warn("Shutting down OPFS async listener. The OPFS VFS will no longer work."); - opRun('opfs-async-shutdown'); - }, - asyncRestart: ()=>{ - warn("Attempting to restart OPFS VFS async listener. Might work, might not."); - W.postMessage({type: 'opfs-async-restart'}); - } - }; -//#endif - - opfsVfs.ioSyncWrappers.xLock = function(pFile,lockType){ + if( !options ) return sqlite3; + const capi = sqlite3.capi, + state = opfsUtil.createVfsState('opfs', options), + opfsVfs = state.vfs, + metrics = opfsVfs.metrics.counters, + mTimeStart = opfsVfs.mTimeStart, + mTimeEnd = opfsVfs.mTimeEnd, + opRun = opfsVfs.opRun, + __openFiles = opfsVfs.__openFiles; + + /* At this point, createVfsState() has populated state and + opfsVfs with any code common to both the "opfs" and "opfs-wl" + VFSes. Now comes the VFS-dependent work... */ + return opfsVfs.doTheThing(util.nu({ + xLock: function(pFile,lockType){ mTimeStart('xLock'); ++metrics.xLock.count; const f = __openFiles[pFile]; @@ -192,9 +113,8 @@ const installOpfsVfs = function callee(options){ } mTimeEnd(); return rc; - }; - - opfsVfs.ioSyncWrappers.xUnlock = function(pFile,lockType){ + }, + xUnlock: function(pFile,lockType){ mTimeStart('xUnlock'); ++metrics.xUnlock.count; const f = __openFiles[pFile]; @@ -206,12 +126,12 @@ const installOpfsVfs = function callee(options){ if( 0===rc ) f.lockType = lockType; mTimeEnd(); return rc; - }; - + } + }), function(sqlite3, vfs){ if(sqlite3.oo1){ const OpfsDb = function(...args){ const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); - opt.vfs = opfsVfs.$zName; + opt.vfs = vfs.$zName; sqlite3.oo1.DB.dbCtorHelper.call(this, opt); }; OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype); @@ -227,144 +147,13 @@ const installOpfsVfs = function callee(options){ } ); }/*extend sqlite3.oo1*/ - - const sanityCheck = function(){ - const scope = wasm.scopedAllocPush(); - const sq3File = new capi.sqlite3_file(); - try{ - const fid = sq3File.pointer; - const openFlags = capi.SQLITE_OPEN_CREATE - | capi.SQLITE_OPEN_READWRITE - //| capi.SQLITE_OPEN_DELETEONCLOSE - | capi.SQLITE_OPEN_MAIN_DB; - const pOut = wasm.scopedAlloc(8); - const dbFile = "/sanity/check/file"+randomFilename(8); - const zDbFile = wasm.scopedAllocCString(dbFile); - let rc; - state.s11n.serialize("This is ä string."); - rc = state.s11n.deserialize(); - log("deserialize() says:",rc); - if("This is ä string."!==rc[0]) toss("String d13n error."); - opfsVfs.vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut,'i32'); - log("xAccess(",dbFile,") exists ?=",rc); - rc = opfsVfs.vfsSyncWrappers.xOpen(opfsVfs.pointer, zDbFile, - fid, openFlags, pOut); - log("open rc =",rc,"state.sabOPView[xOpen] =", - state.sabOPView[state.opIds.xOpen]); - if(0!==rc){ - error("open failed with code",rc); - return; - } - opfsVfs.vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut,'i32'); - if(!rc) toss("xAccess() failed to detect file."); - rc = opfsVfs.ioSyncWrappers.xSync(sq3File.pointer, 0); - if(rc) toss('sync failed w/ rc',rc); - rc = opfsVfs.ioSyncWrappers.xTruncate(sq3File.pointer, 1024); - if(rc) toss('truncate failed w/ rc',rc); - wasm.poke(pOut,0,'i64'); - rc = opfsVfs.ioSyncWrappers.xFileSize(sq3File.pointer, pOut); - if(rc) toss('xFileSize failed w/ rc',rc); - log("xFileSize says:",wasm.peek(pOut, 'i64')); - rc = opfsVfs.ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1); - if(rc) toss("xWrite() failed!"); - const readBuf = wasm.scopedAlloc(16); - rc = opfsVfs.ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2); - wasm.poke(readBuf+6,0); - let jRead = wasm.cstrToJs(readBuf); - log("xRead() got:",jRead); - if("sanity"!==jRead) toss("Unexpected xRead() value."); - if(opfsVfs.vfsSyncWrappers.xSleep){ - log("xSleep()ing before close()ing..."); - opfsVfs.vfsSyncWrappers.xSleep(opfsVfs.pointer,2000); - log("waking up from xSleep()"); - } - rc = opfsVfs.ioSyncWrappers.xClose(fid); - log("xClose rc =",rc,"sabOPView =",state.sabOPView); - log("Deleting file:",dbFile); - opfsVfs.vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 0x1234); - opfsVfs.vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut); - rc = wasm.peek(pOut,'i32'); - if(rc) toss("Expecting 0 from xAccess(",dbFile,") after xDelete()."); - warn("End of OPFS sanity checks."); - }finally{ - sq3File.dispose(); - wasm.scopedAllocPop(scope); - } - }/*sanityCheck()*/; - - W.onmessage = function({data}){ - //log("Worker.onmessage:",data); - switch(data.type){ - case 'opfs-unavailable': - /* Async proxy has determined that OPFS is unavailable. There's - nothing more for us to do here. */ - promiseReject(new Error(data.payload.join(' '))); - break; - case 'opfs-async-loaded': - /* Arrives as soon as the asyc proxy finishes loading. - Pass our config and shared state on to the async - worker. */ - W.postMessage({type: 'opfs-async-init',args: state}); - break; - case 'opfs-async-inited': { - /* Indicates that the async partner has received the 'init' - and has finished initializing, so the real work can - begin... */ - if(true===promiseWasRejected){ - break /* promise was already rejected via timer */; - } - try { - sqlite3.vfs.installVfs({ - io: {struct: opfsVfs.ioMethods, methods: opfsVfs.ioSyncWrappers}, - vfs: {struct: opfsVfs, methods: opfsVfs.vfsSyncWrappers} - }); - state.sabOPView = new Int32Array(state.sabOP); - state.sabFileBufView = new Uint8Array(state.sabIO, 0, state.fileBufferSize); - state.sabS11nView = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize); - opfsVfs.initS11n(); - delete opfsVfs.initS11n; - if(options.sanityChecks){ - warn("Running sanity checks because of opfs-sanity-check URL arg..."); - sanityCheck(); - } - if(opfsUtil.thisThreadHasOPFS()){ - opfsUtil.getRootDir().then((d)=>{ - W.onerror = W._originalOnError; - delete W._originalOnError; - log("End of OPFS sqlite3_vfs setup.", opfsVfs); - promiseResolve(); - }).catch(promiseReject); - }else{ - promiseResolve(); - } - }catch(e){ - error(e); - promiseReject(e); - } - break; - } - default: { - const errMsg = ( - "Unexpected message from the OPFS async worker: " + - JSON.stringify(data) - ); - error(errMsg); - promiseReject(new Error(errMsg)); - break; - } - }/*switch(data.type)*/ - }/*W.onmessage()*/; - })/*thePromise*/; - return thePromise; + })/*doTheThing()*/; }/*installOpfsVfs()*/; -installOpfsVfs.defaultProxyUri = - "sqlite3-opfs-async-proxy.js"; +installOpfsVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ try{ let proxyJs = installOpfsVfs.defaultProxyUri; - if( sqlite3?.scriptInfo?.sqlite3Dir ){ + if( sqlite3.scriptInfo?.sqlite3Dir ){ installOpfsVfs.defaultProxyUri = sqlite3.scriptInfo.sqlite3Dir + proxyJs; //sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri); @@ -378,6 +167,4 @@ globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ } }); }/*sqlite3ApiBootstrap.initializers.push()*/); -//#else -/* The OPFS VFS parts are elided from builds targeting node.js. */ //#endif target:node diff --git a/manifest b/manifest index 34b1032854..003a670b2e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Factor\sout\sabout\s300\slines\sof\scommon\sOPFS\sVFS\sbootstrapping\scode. -D 2026-03-04T17:54:02.085 +C Consolidate\sthe\slast\s200\slines\sof\scommon\sOPFS\sVFS\scode.\s"opfs"\sstill\sworks,\s"opfs-wl"\sregisters\sfine\sbut\sis\sstill\sotherwise\suntested. +D 2026-03-04T19:21:09.278 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js 91b1291447c689a77ffcc3297dc478dd29196311facb063737aeaaf70660a0f0 +F ext/wasm/api/opfs-common-shared.c-pp.js d8ecb1c7f6b29c2eb501ab8da6f9d9867c1ceb8a42c9c883dd53aed8ddfe106a F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -598,8 +598,8 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js f0a2aa8712211ff9db2ef548ae8b676b F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 929bad4b98f176b2d0a8c1509ca833b42a11f5f0871d2b3bb2597b9e29c8ea24 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 9babe167f28ecd8fe67c97fe0734ec88beecbb61a0580d5218edcb8b3d8670ce +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js a755ea941f254f89fcd519789097a7401362d9e9dfba19a9bfc972861257c3c5 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 50a955ef393722d498177ad09c9e2d05bbe8dccae4c40c501482a860ca30017d F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b71c79ef9672c77a72a976ffcd7cbebfaf0ff314dff97b274f7d092de6a7773f -R c0d13d0a3e8b693179cc92fc3fedae39 +P 57adecbab71795b62b1c2e4570ff504f35681e81dd8c94f78ad8e05ef39d36fd +R 18d89b2ee7fb09440d0eac4e9c8dc540 U stephan -Z 3ba0938d21136544be85b7e2c587b666 +Z d66223f806eab9c2d766ad2e9d73c95d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a8ccc41dc5..5c99fbd65b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -57adecbab71795b62b1c2e4570ff504f35681e81dd8c94f78ad8e05ef39d36fd +5978ee4902e4223fed6b95bd2d8f489bb300af8b762650e7113d1f3e97519d88 From 232446b532f6a88395bf1ca3583942a7a11ac59a Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 4 Mar 2026 20:33:21 +0000 Subject: [PATCH 096/197] Get opfs-wl plugged in to the concurrency tester. Somewhat ironically, all competing workers fail with locking errors while worker 1 is busy running off the rails somewhere. Stashing for closer investigation later. FossilOrigin-Name: 3b27310aa29ea84f459974981a600301abac5c705029a289d3872ecacf231da3 --- ext/wasm/api/opfs-common-shared.c-pp.js | 67 +++++++++++++---------- ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js | 3 + ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 5 +- ext/wasm/tests/opfs/concurrency/test.js | 12 +++- ext/wasm/tests/opfs/concurrency/worker.js | 16 +++++- manifest | 20 +++---- manifest.uuid | 2 +- 7 files changed, 77 insertions(+), 48 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 5150fb8e61..72c366adab 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -499,6 +499,20 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const state = util.nu(); state.verbose = options.verbose; + const loggers = [ + sqlite3.config.error, + sqlite3.config.warn, + sqlite3.config.log + ]; + const logImpl = (level,...args)=>{ + if(options.verbose>level) loggers[level]("OPFS syncer:",...args); + }; + const log = (...args)=>logImpl(2, ...args), + warn = (...args)=>logImpl(1, ...args), + error = (...args)=>logImpl(0, ...args), + capi = sqlite3.capi, + wasm = sqlite3.wasm; + const opfsVfs = state.vfs = new capi.sqlite3_vfs(); const opfsIoMethods = opfsVfs.ioMethods = new capi.sqlite3_io_methods(); @@ -571,7 +585,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ of this value is also used for determining how long to wait on lock contention to free up. */ - state.asyncIdleWaitTime = isWebLocker ? 100 : 150; + state.asyncIdleWaitTime = isWebLocker ? 300 : 150; /** Whether the async counterpart should log exceptions to @@ -966,15 +980,17 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ convey error messages from xOpen() because there would be a race condition between sqlite3_open()'s call to xOpen() and this function. */ - warn("OPFS xGetLastError() has nothing sensible to return."); + sqlite3.config.warn("OPFS xGetLastError() has nothing sensible to return."); return 0; }, //xSleep is optionally defined below xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){ mTimeStart('xOpen'); let opfsFlags = 0; - if(0===zName){ - zName = opfsUtil.randomFilename(); + let jzName, zToFree; + if( !zName ){ + jzName = opfsUtil.randomFilename(); + zName = zToFree = wasm.allocCString(jzName); }else if(wasm.isPtr(zName)){ if(capi.sqlite3_uri_boolean(zName, "opfs-unlock-asap", 0)){ /* -----------------------^^^^^ MUST pass the untranslated @@ -984,18 +1000,24 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ if(capi.sqlite3_uri_boolean(zName, "delete-before-open", 0)){ opfsFlags |= state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN; } - zName = wasm.cstrToJs(zName); - //warn("xOpen zName =",zName, "opfsFlags =",opfsFlags); + jzName = wasm.cstrToJs(zName); + //sqlite3.config.warn("xOpen zName =",zName, "opfsFlags =",opfsFlags); + }else{ + sqlite3.config.error("Impossible zName value in xOpen?", zName); + return capi.SQLITE_CANTOPEN; } - const fh = Object.create(null); - fh.fid = pFile; - fh.filename = wasm.cstrToJs(zName); - fh.sab = new SharedArrayBuffer(state.fileBufferSize); - fh.flags = flags; - fh.readOnly = !(capi.SQLITE_OPEN_CREATE & flags) - && !!(flags & capi.SQLITE_OPEN_READONLY); - const rc = opRun('xOpen', pFile, zName, flags, opfsFlags); - if(!rc){ + const fh = util.nu({ + fid: pFile, + filename: jzName, + sab: new SharedArrayBuffer(state.fileBufferSize), + flags: flags, + readOnly: !(capi.SQLITE_OPEN_CREATE & flags) + && !!(flags & capi.SQLITE_OPEN_READONLY) + }); + const rc = opRun('xOpen', pFile, jzName, flags, opfsFlags); + if(rc){ + if( zToFree ) wasm.dealloc(zToFree); + }else{ /* Recall that sqlite3_vfs::xClose() will be called, even on error, unless pFile->pMethods is NULL. */ if(fh.readOnly){ @@ -1004,6 +1026,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ __openFiles[pFile] = fh; fh.sabView = state.sabFileBufView; fh.sq3File = new capi.sqlite3_file(pFile); + if( zToFree ) fh.sq3File.addOnDispose(zToFree); fh.sq3File.$pMethods = opfsIoMethods.pointer; fh.lockType = capi.SQLITE_LOCK_NONE; } @@ -1060,20 +1083,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ opfsVfs.doTheThing = function(ioMethods, callback){ Object.assign(opfsVfs.ioSyncWrappers, ioMethods); const thePromise = new Promise(function(promiseResolve_, promiseReject_){ - const loggers = [ - sqlite3.config.error, - sqlite3.config.warn, - sqlite3.config.log - ]; - const logImpl = (level,...args)=>{ - if(options.verbose>level) loggers[level]("OPFS syncer:",...args); - }; - const log = (...args)=>logImpl(2, ...args), - warn = (...args)=>logImpl(1, ...args), - error = (...args)=>logImpl(0, ...args), - capi = sqlite3.capi, - wasm = sqlite3.wasm; - let promiseWasRejected = undefined; const promiseReject = (err)=>{ promiseWasRejected = true; diff --git a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js index e3fb722877..0fdd7cb4cc 100644 --- a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js @@ -1137,9 +1137,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }/*.ioJrnl*/ }/*methodOverrides*/; +//#if nope debug("pVfs and friends", pVfs, pIoDb, pIoJrnl, kvvfsMethods, capi.sqlite3_file.structInfo, KVVfsFile.structInfo); +//#endif + try { util.assert( cache.buffer.n>1024*129, "Heap buffer is not large enough" /* Native is SQLITE_KVOS_SZ is 133073 as of this writing */ ); diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index e62f23ed14..4b2094ee81 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -60,6 +60,7 @@ const installOpfsWlVfs = async function callee(options){ options = opfsUtil.initOptions(options, callee); if( !options ) return sqlite3; const capi = sqlite3.capi, + debug = sqlite3.config.debug, state = opfsUtil.createVfsState('opfs-wl', options), opfsVfs = state.vfs, metrics = opfsVfs.metrics.counters, @@ -94,7 +95,7 @@ const installOpfsWlVfs = async function callee(options){ } f.lockType = lockType; }catch(e){ - error("xLock(",arguments,") failed", e, f); + sqlite3.config.error("xLock(",arguments,") failed", e, f); rc = capi.SQLITE_IOERR_LOCK; } } @@ -113,7 +114,7 @@ const installOpfsWlVfs = async function callee(options){ Atomics.notify(view, state.lock.atomicsHandshake); Atomics.wait(view, state.lock.atomicsHandshake, 1); }catch(e){ - error("xUnlock(",pFile,lockType,") failed",e, f); + sqlite3.config.error("xUnlock(",pFile,lockType,") failed",e, f); rc = capi.SQLITE_IOERR_LOCK; } } diff --git a/ext/wasm/tests/opfs/concurrency/test.js b/ext/wasm/tests/opfs/concurrency/test.js index 1848901afe..c2932290b7 100644 --- a/ext/wasm/tests/opfs/concurrency/test.js +++ b/ext/wasm/tests/opfs/concurrency/test.js @@ -55,8 +55,8 @@ const options = Object.create(null); options.sqlite3Dir = urlArgsJs.get('sqlite3.dir'); options.workerCount = ( - urlArgsHtml.has('workers') ? +urlArgsHtml.get('workers') : 3 - ) || 4; + urlArgsHtml.has('workers') ? +urlArgsHtml.get('workers') : 0 + ) || 3; options.opfsVerbose = ( urlArgsHtml.has('verbose') ? +urlArgsHtml.get('verbose') : 1 ) || 1; @@ -69,6 +69,7 @@ options.unlockAsap = ( urlArgsHtml.has('unlock-asap') ? +urlArgsHtml.get('unlock-asap') : 0 ) || 0; + options.vfs = urlArgsHtml.get('vfs') || 'opfs'; options.noUnlink = !!urlArgsHtml.has('no-unlink'); const workers = []; workers.post = (type,...args)=>{ @@ -118,12 +119,16 @@ const eTestLinks = document.querySelector('#testlinks'); const optArgs = function(obj){ const li = []; - for(const k of ['interval','iterations','workers','verbose','unlock-asap']){ + for(const k of [ + 'interval','iterations','unlock-asap', + 'verbose','vfs','workers', + ]){ if( obj.hasOwnProperty(k) ) li.push(k+'='+obj[k]); } return li.join('&'); }; for(const opt of [ + {interval: 500, workers: 3, iterations: 30, vfs: 'opfs-wl'}, {interval: 1000, workers: 5, iterations: 30}, {interval: 500, workers: 5, iterations: 30}, {interval: 250, workers: 3, iterations: 30}, @@ -142,6 +147,7 @@ workers.uri = ( 'worker.js?' + 'sqlite3.dir='+options.sqlite3Dir + + '&vfs='+options.vfs + '&interval='+options.interval + '&iterations='+options.iterations + '&opfs-verbose='+options.opfsVerbose diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index a28d80f202..f68bf3516b 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -6,7 +6,8 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ const urlArgs = new URL(globalThis.location.href).searchParams; const options = { workerName: urlArgs.get('workerId') || Math.round(Math.random()*10000), - unlockAsap: urlArgs.get('opfs-unlock-asap') || 0 /*EXPERIMENTAL*/ + unlockAsap: urlArgs.get('opfs-unlock-asap') || 0 /*EXPERIMENTAL*/, + vfs: urlArgs.get('vfs') }; const wPost = (type,...payload)=>{ postMessage({type, worker: options.workerName, payload}); @@ -14,7 +15,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ const stdout = (...args)=>wPost('stdout',...args); const stderr = (...args)=>wPost('stderr',...args); if(!sqlite3.opfs){ - stderr("OPFS support not detected. Aborting."); + stderr("This code requires the (private) sqlite3.opfs object. Aborting."); return; } @@ -47,7 +48,16 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ } }; const run = async function(){ - db = new sqlite3.oo1.OpfsDb({ + const Ctors = Object.assign(Object.create(null),{ + opfs: sqlite3.oo1.OpfsDb, + 'opfs-wl': sqlite3.oo1.OpfsWlDb + }); + const ctor = Ctors[options.vfs]; + if( !ctor ){ + stderr("Invalid VFS name:",vfs); + return; + } + db = new ctor({ filename: 'file:'+dbName+'?opfs-unlock-asap='+options.unlockAsap, flags: 'c' }); diff --git a/manifest b/manifest index 003a670b2e..fa51c7fc6c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Consolidate\sthe\slast\s200\slines\sof\scommon\sOPFS\sVFS\scode.\s"opfs"\sstill\sworks,\s"opfs-wl"\sregisters\sfine\sbut\sis\sstill\sotherwise\suntested. -D 2026-03-04T19:21:09.278 +C Get\sopfs-wl\splugged\sin\sto\sthe\sconcurrency\stester.\sSomewhat\sironically,\sall\scompeting\sworkers\sfail\swith\slocking\serrors\swhile\sworker\s1\sis\sbusy\srunning\soff\sthe\srails\ssomewhere.\sStashing\sfor\scloser\sinvestigation\slater. +D 2026-03-04T20:33:21.840 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js d8ecb1c7f6b29c2eb501ab8da6f9d9867c1ceb8a42c9c883dd53aed8ddfe106a +F ext/wasm/api/opfs-common-shared.c-pp.js 1218fb9e72f3a208e62a4caafcf1fb0a41b66ca46df27601e5bfb06220822f24 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -596,9 +596,9 @@ F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js f0a2aa8712211ff9db2ef548ae8b676be3e7c82f61586d03fd8317fbc95bbedd F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d -F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e +F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js a755ea941f254f89fcd519789097a7401362d9e9dfba19a9bfc972861257c3c5 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 62d41024ad20c388c022f032d3f25838809cb00915ebeb97b598b9f370fba2c3 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 50a955ef393722d498177ad09c9e2d05bbe8dccae4c40c501482a860ca30017d F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 @@ -646,8 +646,8 @@ F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c9 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb F ext/wasm/tester1.c-pp.js 6b946cd6d4da130dbae4a401057716d27117ca02cad2ea8c29ae9c46c675d618 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e -F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88 -F ext/wasm/tests/opfs/concurrency/worker.js 3e29c07bdd11f4ff9ee50e641e39c254d39243bbb83fb20a255755ee92739d12 +F ext/wasm/tests/opfs/concurrency/test.js 2150850176a1ffbe7f6b19f5cf5db9c77290764d6d54430b2796b6512b676a4a +F ext/wasm/tests/opfs/concurrency/worker.js 537e11f86fdc5d5bc64032aaa48cd027a2f8cf4b020aca6c3c012fec85da2eb1 F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 57adecbab71795b62b1c2e4570ff504f35681e81dd8c94f78ad8e05ef39d36fd -R 18d89b2ee7fb09440d0eac4e9c8dc540 +P 5978ee4902e4223fed6b95bd2d8f489bb300af8b762650e7113d1f3e97519d88 +R 0cf8357d9b35fb1b75ea83762f01c38b U stephan -Z d66223f806eab9c2d766ad2e9d73c95d +Z eba11c8254e99ee26ae9feba85ef81c4 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5c99fbd65b..15d2b8cd82 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5978ee4902e4223fed6b95bd2d8f489bb300af8b762650e7113d1f3e97519d88 +3b27310aa29ea84f459974981a600301abac5c705029a289d3872ecacf231da3 From 671a6f83f455991801efa25a030d375e23f7023f Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 4 Mar 2026 21:16:36 +0000 Subject: [PATCH 097/197] Add some debugging output to opfs and track down the breakage to the initial WebLock request, which is never reaching its callback. Still broken, but this is progress. FossilOrigin-Name: 62fc8b35aeec75f5648b3daa24162c638999d447aa874bdfcbac1431c5c97b6f --- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 7 ++- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 8 +++- ext/wasm/tests/opfs/concurrency/test.js | 8 ++-- ext/wasm/tests/opfs/concurrency/worker.js | 46 ++++++++----------- manifest | 18 ++++---- manifest.uuid | 2 +- 6 files changed, 45 insertions(+), 44 deletions(-) diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index c9bd620fa5..f682c4ce42 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -620,11 +620,12 @@ const installAsyncProxy = function(){ const view = state.sabOPView; const slock = state.lock; const lockType = Atomics.load(view, slock.type); - - await navigator.locks.request('sqlite3-vfs-opfs:'+args[0], { + warn("handleLockRequest()", args, lockType); + navigator.locks.request('sqlite3-vfs-opfs:'+args[0], { mode: (lockType===state.sq3Codes.SQLITE_LOCK_EXCLUSIVE) ? 'exclusive' : 'shared' }, async (wl)=>{ + warn("handleLockRequest() starting lock", args, lockType); /** A. Tell the C-side we have the browser lock. We use the same handshake slot, but a specific 'Granted' value. @@ -642,6 +643,7 @@ const installAsyncProxy = function(){ Atomics.store(view, slock.atomicsHandshake, 0); Atomics.notify(view, lock.atomicsHandshake); }); + warn("handleLockRequest() ending", args, lockType); }; const waitLoop = async function f(){ @@ -679,6 +681,7 @@ const installAsyncProxy = function(){ continue; } const opId = Atomics.exchange(state.sabOPView, opIds.whichOp, 0); + warn("opId =",opId, opIds); if( opId===opIds.lockControl ){ handleLockRequest(); continue; diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 4b2094ee81..6b18a38691 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -60,13 +60,14 @@ const installOpfsWlVfs = async function callee(options){ options = opfsUtil.initOptions(options, callee); if( !options ) return sqlite3; const capi = sqlite3.capi, - debug = sqlite3.config.debug, + debug = (...args)=>sqlite3.config.warn("opfs-wl:",...args), state = opfsUtil.createVfsState('opfs-wl', options), opfsVfs = state.vfs, metrics = opfsVfs.metrics.counters, mTimeStart = opfsVfs.mTimeStart, mTimeEnd = opfsVfs.mTimeEnd, __openFiles = opfsVfs.__openFiles; + debug("state",JSON.stringify(state,false,' ')); /* At this point, createVfsState() has populated state and opfsVfs with any code common to both the "opfs" and "opfs-wl" VFSes. Now comes the VFS-dependent work... */ @@ -75,6 +76,7 @@ const installOpfsWlVfs = async function callee(options){ mTimeStart('xLock'); ++metrics.xLock.count; const f = __openFiles[pFile]; + debug("xLock()",f,lockType); let rc = 0; /* See notes in sqlite3-vfs-opfs.c-pp.js. */ if( f.lockType ) { @@ -89,10 +91,13 @@ const installOpfsWlVfs = async function callee(options){ Atomics.store(view, state.lock.type, lockType); Atomics.store(view, state.opIds.whichOp, state.opIds.lockControl); Atomics.notify(state.sabOPView, state.opIds.whichOp) + debug("xLock waiting..."); while('not-equal'!==Atomics.wait(view, state.lock.atomicsHandshake, 0)){ /* Loop is a workaround for environment-specific quirks. See notes in similar loops. */ + debug("xLock still waiting..."); } + debug("xLock done waiting"); f.lockType = lockType; }catch(e){ sqlite3.config.error("xLock(",arguments,") failed", e, f); @@ -103,6 +108,7 @@ const installOpfsWlVfs = async function callee(options){ return rc; }, xUnlock: function(pFile,lockType){ + debug("xUnlock()",f,lockType); mTimeStart('xUnlock'); ++metrics.xUnlock.count; const f = __openFiles[pFile]; diff --git a/ext/wasm/tests/opfs/concurrency/test.js b/ext/wasm/tests/opfs/concurrency/test.js index c2932290b7..9208ff47fc 100644 --- a/ext/wasm/tests/opfs/concurrency/test.js +++ b/ext/wasm/tests/opfs/concurrency/test.js @@ -120,15 +120,15 @@ const optArgs = function(obj){ const li = []; for(const k of [ - 'interval','iterations','unlock-asap', - 'verbose','vfs','workers', + 'interval', 'iterations', 'unlock-asap', + 'verbose', 'vfs', 'workers' ]){ if( obj.hasOwnProperty(k) ) li.push(k+'='+obj[k]); } return li.join('&'); }; for(const opt of [ - {interval: 500, workers: 3, iterations: 30, vfs: 'opfs-wl'}, + {interval: 500, workers: 2, iterations: 30, vfs: 'opfs-wl', verbose: 2}, {interval: 1000, workers: 5, iterations: 30}, {interval: 500, workers: 5, iterations: 30}, {interval: 250, workers: 3, iterations: 30}, @@ -154,7 +154,7 @@ + '&opfs-unlock-asap='+options.unlockAsap ); for(let i = 0; i < options.workerCount; ++i){ - stdout("Launching worker..."); + stdout("Launching worker...", i, ); workers.push(new Worker( workers.uri+'&workerId='+(i+1)+( (i || options.noUnlink) ? '' : '&unlink-db' diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index f68bf3516b..b4cb5a30a4 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -36,8 +36,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ count: 0 }); const finish = ()=>{ - if(db){ - if(!db.pointer) return; + if(db?.pointer){ db.close(); } if(interval.error){ @@ -71,7 +70,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ const maxIterations = urlArgs.has('iterations') ? (+urlArgs.get('iterations') || 10) : 10; - stdout("Starting interval-based db updates with delay of",interval.delay,"ms."); + stdout("Starting",maxIterations,"interval-based db updates with delay of",interval.delay,"ms."); const doWork = async ()=>{ const tm = new Date().getTime(); ++interval.count; @@ -86,39 +85,32 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ }catch(e){ interval.error = e; } + stdout("doWork()",prefix,"error ",interval.error); }; - if(1){/*use setInterval()*/ - setTimeout(async function timer(){ - await doWork(); - if(interval.error || maxIterations === interval.count){ - finish(); - }else{ - setTimeout(timer, interval.delay); - } - }, interval.delay); - }else{ - /*This approach provides no concurrency whatsoever: each worker - is run to completion before any others can work.*/ - let i; - for(i = 0; i < maxIterations; ++i){ - await doWork(); - if(interval.error) break; - await wait(interval.ms); + setTimeout(async function timer(){ + await doWork(); + if(interval.error || maxIterations === interval.count){ + finish(); + }else{ + setTimeout(timer, interval.delay); } - finish(); - } + }, interval.delay); }/*run()*/; globalThis.onmessage = function({data}){ switch(data.type){ - case 'run': run().catch((e)=>{ + case 'run': + run().catch((e)=>{ if(!interval.error) interval.error = e; + }).catch(e=>{ + /* Don't do this in finally() - it fires too soon. */ finish(); + throw e; }); - break; - default: - stderr("Unhandled message type '"+data.type+"'."); - break; + break; + default: + stderr("Unhandled message type '"+data.type+"'."); + break; } }; }); diff --git a/manifest b/manifest index fa51c7fc6c..68ce7cc015 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Get\sopfs-wl\splugged\sin\sto\sthe\sconcurrency\stester.\sSomewhat\sironically,\sall\scompeting\sworkers\sfail\swith\slocking\serrors\swhile\sworker\s1\sis\sbusy\srunning\soff\sthe\srails\ssomewhere.\sStashing\sfor\scloser\sinvestigation\slater. -D 2026-03-04T20:33:21.840 +C Add\ssome\sdebugging\soutput\sto\sopfs\sand\strack\sdown\sthe\sbreakage\sto\sthe\sinitial\sWebLock\srequest,\swhich\sis\snever\sreaching\sits\scallback.\sStill\sbroken,\sbut\sthis\sis\sprogress. +D 2026-03-04T21:16:36.068 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -594,11 +594,11 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js f0a2aa8712211ff9db2ef548ae8b676be3e7c82f61586d03fd8317fbc95bbedd +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 792a18708a6207d9bf274b04dcddd06fd805e93d1b7f716230df3c745f2800ee F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 62d41024ad20c388c022f032d3f25838809cb00915ebeb97b598b9f370fba2c3 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 1e6e087a89e9cd202d457c84dae29fa4808612ff9f37210c383eb6bbab3dfd34 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 50a955ef393722d498177ad09c9e2d05bbe8dccae4c40c501482a860ca30017d F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 @@ -646,8 +646,8 @@ F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c9 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb F ext/wasm/tester1.c-pp.js 6b946cd6d4da130dbae4a401057716d27117ca02cad2ea8c29ae9c46c675d618 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e -F ext/wasm/tests/opfs/concurrency/test.js 2150850176a1ffbe7f6b19f5cf5db9c77290764d6d54430b2796b6512b676a4a -F ext/wasm/tests/opfs/concurrency/worker.js 537e11f86fdc5d5bc64032aaa48cd027a2f8cf4b020aca6c3c012fec85da2eb1 +F ext/wasm/tests/opfs/concurrency/test.js b80e17488a8e4d5500deaf68f73a7298d7d351f74bb952691a4e7b6c02a5643b +F ext/wasm/tests/opfs/concurrency/worker.js de0be3be41da20e6639cdea10467fb5d9cdf540e711b403728a08d99bbb82ee6 F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 5978ee4902e4223fed6b95bd2d8f489bb300af8b762650e7113d1f3e97519d88 -R 0cf8357d9b35fb1b75ea83762f01c38b +P 3b27310aa29ea84f459974981a600301abac5c705029a289d3872ecacf231da3 +R 5c13d459ac5b107e6cc5943524da9a40 U stephan -Z eba11c8254e99ee26ae9feba85ef81c4 +Z 9fafbc035e4ee3a2d442f9b59c8a5807 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 15d2b8cd82..6c88a8044b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3b27310aa29ea84f459974981a600301abac5c705029a289d3872ecacf231da3 +62fc8b35aeec75f5648b3daa24162c638999d447aa874bdfcbac1431c5c97b6f From bef2a1e33efa8a9ce5506a7b0242fe3031abc657 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 5 Mar 2026 00:30:05 +0000 Subject: [PATCH 098/197] Add a little flexibility to checkpoint sizes in the walrestart.test script. FossilOrigin-Name: e438b564ca84377746464034d770e9c1f5899d935c6a4dffc546acb92afb800e --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/walrestart.test | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index c825abc294..ff582d3103 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sdead\s(commented-out)\scode\sthat\scame\sto\smy\sattention\sbecause\sit\nws\snearby\sthe\sfix\sof\sthe\sprevious\scheck-in. -D 2026-03-04T13:08:14.899 +C Add\sa\slittle\sflexibility\sto\scheckpoint\ssizes\sin\sthe\swalrestart.test\sscript. +D 2026-03-05T00:30:05.130 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -2004,7 +2004,7 @@ F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03 F test/walpersist.test 8d78a1ec91299163451417b451a2bac3481f8eb9f455b1ca507a6625c927ca6e F test/walprotocol.test 1b3f922125e341703f6e946d77fdc564d38fb3e07a9385cfdc6c99cac1ecf878 F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131 -F test/walrestart.test 3b0a9198ad2eb9f716d8f3846b133ba9f4619fb56decb1e67bba27743c766289 +F test/walrestart.test df92e581d169429f0cc44f49cacccc9dfd749495d536467379668a6d073369dc F test/walro.test 78a84bc0fdae1385c06b017215c426b6845734d6a5a3ac75c918dd9b801b1b9d F test/walro2.test 33955a6fd874dd9724005e17f77fef89d334b3171454a1256fe4941a96766cdc F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 6ba7797cac7dc873b62a12be5712511c9199b379342dac4a1887bfd65227a298 -R 7127c439ea41ec62f75cef8391656a07 +P 61f8a28591a833b1f5834a347feefeba8414fecc7ff154f1b6ef19963f181812 +R ae5ae7b3ea3c5883e95986d59e781f25 U drh -Z 05c4a0745826c227013aa02b8d852b71 +Z 684be6d6a05353fa19523ecf503b665a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 78bbfcdc32..0ab5334ecc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -61f8a28591a833b1f5834a347feefeba8414fecc7ff154f1b6ef19963f181812 +e438b564ca84377746464034d770e9c1f5899d935c6a4dffc546acb92afb800e diff --git a/test/walrestart.test b/test/walrestart.test index 4274b2e33c..9c3f76d71b 100644 --- a/test/walrestart.test +++ b/test/walrestart.test @@ -78,7 +78,7 @@ do_execsql_test -db db2 1.3 { proc faultsim {n} { return 0 } do_execsql_test 1.4 { PRAGMA wal_checkpoint; -} {0 58 58} +} {/0 5. 5./} do_catchsql_test 1.5 { PRAGMA integrity_check From cef3ff74cd89cecc1ee88068f1f8cc8fbce9f51c Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 5 Mar 2026 06:30:57 +0000 Subject: [PATCH 099/197] The opfs-wl lock hang has been traced to starvation between the WebLock and the tight wait-on-VFS-calls Atomics.wait() loop. This can reportedly be resolved with another level of indirection in which the WebLock takes over the wait-on-VFS-calls part until it's unlocked, returning to the global loop when it's done. That exceeds this morning's ambitions but is next to try out. FossilOrigin-Name: 113bd910e12fea17f9f4a0a3baf706f15627c08cfa6b47a960a83eee761ef4dd --- ext/wasm/api/opfs-common-shared.c-pp.js | 5 +- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 69 ++++++++++++++----- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 6 ++ manifest | 16 ++--- manifest.uuid | 2 +- 5 files changed, 72 insertions(+), 26 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 72c366adab..43a1b05cdc 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -585,7 +585,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ of this value is also used for determining how long to wait on lock contention to free up. */ - state.asyncIdleWaitTime = isWebLocker ? 300 : 150; + state.asyncIdleWaitTime = isWebLocker ? 100 : 150; /** Whether the async counterpart should log exceptions to @@ -1262,6 +1262,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } break; } + case 'debug': + warn("debug message from worker:",data); + break; default: { const errMsg = ( "Unexpected message from the OPFS async worker: " + diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index f682c4ce42..8338b96c05 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -615,15 +615,18 @@ const installAsyncProxy = function(){ Starts a new WebLock request. */ const handleLockRequest = async function(){ + const view = state.sabOPView; +//#if not nope const args = state.s11n.deserialize(true) || toss("Expecting a filename argument from the proxy xLock()"); - const view = state.sabOPView; const slock = state.lock; const lockType = Atomics.load(view, slock.type); - warn("handleLockRequest()", args, lockType); - navigator.locks.request('sqlite3-vfs-opfs:'+args[0], { - mode: (lockType===state.sq3Codes.SQLITE_LOCK_EXCLUSIVE) - ? 'exclusive' : 'shared' + warn("handleLockRequest()", args, lockType, JSON.stringify(slock)); + //hangs warn(JSON.stringify((await navigator.locks.query()).held)); + //warn("Navigator locks:", !!navigator.locks); + await navigator.locks.request('sqlite3-vfs-opfs:'+args[0], { + mode: 'exclusive' /*(lockType===state.sq3Codes.SQLITE_LOCK_EXCLUSIVE) + ? 'exclusive' : 'shared'*/ }, async (wl)=>{ warn("handleLockRequest() starting lock", args, lockType); /** @@ -637,24 +640,57 @@ const installAsyncProxy = function(){ Receptionist receives 'unlockControl'. */ while( 1!==Atomics.load(view, slock.atomicsHandshake) ){ - Atomics.wait(view. slock.atomicsHandshake, 2); + Atomics.wait(view, slock.atomicsHandshake, 2); } /* C. Reset the handshake slot. */ Atomics.store(view, slock.atomicsHandshake, 0); Atomics.notify(view, lock.atomicsHandshake); }); warn("handleLockRequest() ending", args, lockType); + //setTimeout(waitLoop, 0); +//#else + warn("handleLockRequest()", ...arguments); + const [filename] = state.s11n.deserialize(true); + const lockType = Atomics.load(view, state.lock.type); + warn("handleLockRequest()", filename, lockType); + // Use 'exclusive' to ensure we aren't getting a weak shared lock + navigator.locks.request(filename, { mode: 'exclusive' }, (lock) => { + warn("handleLockRequest() inside the lock"); + // VIOLENT DEBUGGING: Use globalThis.postMessage to bypass Atomics + globalThis.postMessage({type: 'debug', msg: 'CALLBACK ENTERED'}); + + // 1. Signal C-side: "I have it" + Atomics.store(view, state.lock.atomicsHandshake, 2); + Atomics.notify(view, state.lock.atomicsHandshake); + + // 2. The Guard: This loop must not be async. + // It must stay synchronous to keep the callback alive. + while(Atomics.load(view, state.lock.atomicsHandshake) !== 1){ + Atomics.wait(view, state.lock.atomicsHandshake, 2, 100); + } + + // 3. Departure + Atomics.store(view, state.lock.atomicsHandshake, 0); + globalThis.postMessage({type: 'debug', msg: 'CALLBACK EXITING'}); + return new Promise(()=>{/* never resolve to keep lock held until Departure */}); + }).catch(e => { + globalThis.postMessage({type: 'debug', msg: 'LOCK ERROR: ' + e.message}); + }); +//#endif }; const waitLoop = async function f(){ - const opHandlers = Object.create(null); - for(let k of Object.keys(state.opIds)){ - const vi = vfsAsyncImpls[k]; - if(!vi) continue; - const o = Object.create(null); - opHandlers[state.opIds[k]] = o; - o.key = k; - o.f = vi; + if( !f.inited ){ + f.inited = true; + f.opHandlers = Object.create(null); + for(let k of Object.keys(state.opIds)){ + const vi = vfsAsyncImpls[k]; + if(!vi) continue; + const o = Object.create(null); + f.opHandlers[state.opIds[k]] = o; + o.key = k; + o.f = vi; + } } const opIds = state.opIds; while(!flagAsyncShutdown){ @@ -684,9 +720,10 @@ const installAsyncProxy = function(){ warn("opId =",opId, opIds); if( opId===opIds.lockControl ){ handleLockRequest(); - continue; + setTimeout(f, 50); + return; } - const hnd = opHandlers[opId] ?? toss("No waitLoop handler for whichOp #",opId); + const hnd = f.opHandlers[opId] ?? toss("No waitLoop handler for whichOp #",opId); const args = state.s11n.deserialize( true /* clear s11n to keep the caller from confusing this with an exception string written by the upcoming diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 6b18a38691..b2d25b85e4 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -92,11 +92,17 @@ const installOpfsWlVfs = async function callee(options){ Atomics.store(view, state.opIds.whichOp, state.opIds.lockControl); Atomics.notify(state.sabOPView, state.opIds.whichOp) debug("xLock waiting..."); +//#if not nope + while( 2 !== Atomics.load(view, state.lock.atomicsHandshake) ){ + Atomics.wait(view, state.lock.atomicsHandshake, 0); + } +//#else while('not-equal'!==Atomics.wait(view, state.lock.atomicsHandshake, 0)){ /* Loop is a workaround for environment-specific quirks. See notes in similar loops. */ debug("xLock still waiting..."); } +//#endif debug("xLock done waiting"); f.lockType = lockType; }catch(e){ diff --git a/manifest b/manifest index 68ce7cc015..a92a7a8886 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssome\sdebugging\soutput\sto\sopfs\sand\strack\sdown\sthe\sbreakage\sto\sthe\sinitial\sWebLock\srequest,\swhich\sis\snever\sreaching\sits\scallback.\sStill\sbroken,\sbut\sthis\sis\sprogress. -D 2026-03-04T21:16:36.068 +C The\sopfs-wl\slock\shang\shas\sbeen\straced\sto\sstarvation\sbetween\sthe\sWebLock\sand\sthe\stight\swait-on-VFS-calls\sAtomics.wait()\sloop.\sThis\scan\sreportedly\sbe\sresolved\swith\sanother\slevel\sof\sindirection\sin\swhich\sthe\sWebLock\stakes\sover\sthe\swait-on-VFS-calls\spart\suntil\sit's\sunlocked,\sreturning\sto\sthe\sglobal\sloop\swhen\sit's\sdone.\sThat\sexceeds\sthis\smorning's\sambitions\sbut\sis\snext\sto\stry\sout. +D 2026-03-05T06:30:57.097 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js 1218fb9e72f3a208e62a4caafcf1fb0a41b66ca46df27601e5bfb06220822f24 +F ext/wasm/api/opfs-common-shared.c-pp.js 404aa8fd676791f0ce71e5c48f5f19e13e7b8e967a9af6a76927d524bbb46158 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -594,11 +594,11 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 792a18708a6207d9bf274b04dcddd06fd805e93d1b7f716230df3c745f2800ee +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 82339eb043af53638b127a4649685da62b6fa33426d2013520eb6aeb114ede46 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 1e6e087a89e9cd202d457c84dae29fa4808612ff9f37210c383eb6bbab3dfd34 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 88add6362468df4ecbbd00878c7a83cd81e555c677103ead51c34bd2be1a3963 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 50a955ef393722d498177ad09c9e2d05bbe8dccae4c40c501482a860ca30017d F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 3b27310aa29ea84f459974981a600301abac5c705029a289d3872ecacf231da3 -R 5c13d459ac5b107e6cc5943524da9a40 +P 62fc8b35aeec75f5648b3daa24162c638999d447aa874bdfcbac1431c5c97b6f +R 4e4429a4d6f21ed4af3f33058413d5c8 U stephan -Z 9fafbc035e4ee3a2d442f9b59c8a5807 +Z 5eeca3e1560bb544ee40d011df9232c0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 6c88a8044b..c36b9ce9ac 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -62fc8b35aeec75f5648b3daa24162c638999d447aa874bdfcbac1431c5c97b6f +113bd910e12fea17f9f4a0a3baf706f15627c08cfa6b47a960a83eee761ef4dd From 14b5eadefe0e8285f097fa948bfb08ae0dfa9f00 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 5 Mar 2026 11:51:27 +0000 Subject: [PATCH 100/197] Strip the opfs-wl "back to formula", removing the current false starts so that this can be tried again without tripping over any cruft. The current impl is subject, with no obvious way out of it, to starvation in the async proxy. FossilOrigin-Name: d022f1f5e74dedae044801330eb099022498f359f408e69b3574885641b312f5 --- ext/wasm/api/opfs-common-shared.c-pp.js | 36 +++++---- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 79 +------------------ ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 61 ++++---------- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 4 +- ext/wasm/tests/opfs/concurrency/test.js | 5 +- ext/wasm/tests/opfs/concurrency/worker.js | 3 +- manifest | 22 +++--- manifest.uuid | 2 +- 8 files changed, 57 insertions(+), 155 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 43a1b05cdc..c709e0d15b 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -444,7 +444,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ - Set up any references they may need to state returned by the previous step. - - Call opfvs.doTheThing() + - Call opfvs.bindVfs() */ opfsUtil.initOptions = function(options, callee){ const urlParams = new URL(globalThis.location.href).searchParams; @@ -485,10 +485,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ capi.sqlite3_vfs instance. After setting up any local state needed, the caller must - call theVfs.doTheThing(X,Y), where X is an object containing + call theVfs.bindVfs(X,Y), where X is an object containing the sqlite3_io_methods to override and Y is a callback which gets triggered if init succeeds, before the final Promise - decides whether or not to reject. The result of doTheThing() + decides whether or not to reject. The result of bindVfs() must be returned from their main installation function. This object must, when it's passed to the async part, contain @@ -505,7 +505,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ sqlite3.config.log ]; const logImpl = (level,...args)=>{ - if(options.verbose>level) loggers[level]("OPFS syncer:",...args); + if(state.verbose>level) loggers[level]("OPFS syncer:",...args); }; const log = (...args)=>logImpl(2, ...args), warn = (...args)=>logImpl(1, ...args), @@ -670,7 +670,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ state.opIds.xUnlock = i++; state.opIds.xWrite = i++; state.opIds.mkdir = i++; - state.opIds.lockControl = i++ /* opfs-wl signals the intent to lock here */; /** Internal signals which are used only during development and testing via the dev console. */ state.opIds['opfs-async-metrics'] = i++; @@ -679,13 +678,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ semantics. Though we could hypothetically use the xSleep slot for that, doing so might lead to undesired side effects. */ state.opIds.retry = i++; - - state.lock = util.nu({ - /* Slots for submitting the lock type and receiving its - acknowledgement. Only used by "opfs-wl". */ - type: i++ /* SQLITE_LOCK_xyz value */, - atomicsHandshake: i++ /* 0=pending, 1=release, 2=granted */ - }); state.sabOP = new SharedArrayBuffer( i * 4/* ==sizeof int32, noting that Atomics.wait() and friends can only function on Int32Array views of an SAB. */); @@ -1080,7 +1072,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ where opfsVfs is the sqlite3_vfs object which was set up by opfsUtil.createVfsState(). */ - opfsVfs.doTheThing = function(ioMethods, callback){ + opfsVfs.bindVfs = function(ioMethods, callback){ Object.assign(opfsVfs.ioSyncWrappers, ioMethods); const thePromise = new Promise(function(promiseResolve_, promiseReject_){ let promiseWasRejected = undefined; @@ -1101,13 +1093,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ options.proxyUri += '?vfs='+vfsName; const W = opfsVfs.worker = //#if target:es6-bundler-friendly - new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs", import.meta.url)); + (()=>{ + /* _Sigh_... */ + switch(vfsName){ + case 'opfs': + return new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs", import.meta.url)); + case 'opfs-wl': + return new Worker(new URL("sqlite3-opfs-async-proxy.js?vfs=opfs-wl", import.meta.url)); + } + })(); //#elif target:es6-module new Worker(new URL(options.proxyUri, import.meta.url)); //#else new Worker(options.proxyUri); //#endif - setTimeout(()=>{ + let zombieTimer = setTimeout(()=>{ /* At attempt to work around a browser-specific quirk in which the Worker load is failing in such a way that we neither resolve nor reject it. This workaround gives that resolve/reject @@ -1211,7 +1211,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }/*sanityCheck()*/; W.onmessage = function({data}){ - //log("Worker.onmessage:",data); + //sqlite3.config.warn(vfsName,"Worker.onmessage:",data); switch(data.type){ case 'opfs-unavailable': /* Async proxy has determined that OPFS is unavailable. There's @@ -1232,6 +1232,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ if(true===promiseWasRejected){ break /* promise was already rejected via timer */; } + clearTimeout(zombieTimer); + zombieTimer = null; try { sqlite3.vfs.installVfs({ io: {struct: opfsVfs.ioMethods, methods: opfsVfs.ioSyncWrappers}, @@ -1278,7 +1280,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }/*W.onmessage()*/; })/*thePromise*/; return thePromise; - }/*doTheThing()*/; + }/*bindVfs()*/; return state; }/*createVfsState()*/; diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 8338b96c05..0db9a99141 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -326,7 +326,7 @@ const installAsyncProxy = function(){ } log("Got",opName+"() sync handle for",fh.filenameAbs, 'in',performance.now() - t,'ms'); - if(!isWebLocker && !fh.xLock){ + if(!fh.xLock){ __implicitLocks.add(fh.fid); log("Acquired implicit lock for",opName+"()",fh.fid,fh.filenameAbs); } @@ -611,74 +611,6 @@ const installAsyncProxy = function(){ } }/*vfsAsyncImpls*/; - /** - Starts a new WebLock request. - */ - const handleLockRequest = async function(){ - const view = state.sabOPView; -//#if not nope - const args = state.s11n.deserialize(true) - || toss("Expecting a filename argument from the proxy xLock()"); - const slock = state.lock; - const lockType = Atomics.load(view, slock.type); - warn("handleLockRequest()", args, lockType, JSON.stringify(slock)); - //hangs warn(JSON.stringify((await navigator.locks.query()).held)); - //warn("Navigator locks:", !!navigator.locks); - await navigator.locks.request('sqlite3-vfs-opfs:'+args[0], { - mode: 'exclusive' /*(lockType===state.sq3Codes.SQLITE_LOCK_EXCLUSIVE) - ? 'exclusive' : 'shared'*/ - }, async (wl)=>{ - warn("handleLockRequest() starting lock", args, lockType); - /** - A. Tell the C-side we have the browser lock. We use the same - handshake slot, but a specific 'Granted' value. - */ - Atomics.store(view, slock.atomicsHandshake, 2); - Atomics.notify(view, slock.atomicsHandshake); - /** - B. Sit here and keep the lock room occupied until the - Receptionist receives 'unlockControl'. - */ - while( 1!==Atomics.load(view, slock.atomicsHandshake) ){ - Atomics.wait(view, slock.atomicsHandshake, 2); - } - /* C. Reset the handshake slot. */ - Atomics.store(view, slock.atomicsHandshake, 0); - Atomics.notify(view, lock.atomicsHandshake); - }); - warn("handleLockRequest() ending", args, lockType); - //setTimeout(waitLoop, 0); -//#else - warn("handleLockRequest()", ...arguments); - const [filename] = state.s11n.deserialize(true); - const lockType = Atomics.load(view, state.lock.type); - warn("handleLockRequest()", filename, lockType); - // Use 'exclusive' to ensure we aren't getting a weak shared lock - navigator.locks.request(filename, { mode: 'exclusive' }, (lock) => { - warn("handleLockRequest() inside the lock"); - // VIOLENT DEBUGGING: Use globalThis.postMessage to bypass Atomics - globalThis.postMessage({type: 'debug', msg: 'CALLBACK ENTERED'}); - - // 1. Signal C-side: "I have it" - Atomics.store(view, state.lock.atomicsHandshake, 2); - Atomics.notify(view, state.lock.atomicsHandshake); - - // 2. The Guard: This loop must not be async. - // It must stay synchronous to keep the callback alive. - while(Atomics.load(view, state.lock.atomicsHandshake) !== 1){ - Atomics.wait(view, state.lock.atomicsHandshake, 2, 100); - } - - // 3. Departure - Atomics.store(view, state.lock.atomicsHandshake, 0); - globalThis.postMessage({type: 'debug', msg: 'CALLBACK EXITING'}); - return new Promise(()=>{/* never resolve to keep lock held until Departure */}); - }).catch(e => { - globalThis.postMessage({type: 'debug', msg: 'LOCK ERROR: ' + e.message}); - }); -//#endif - }; - const waitLoop = async function f(){ if( !f.inited ){ f.inited = true; @@ -717,12 +649,6 @@ const installAsyncProxy = function(){ continue; } const opId = Atomics.exchange(state.sabOPView, opIds.whichOp, 0); - warn("opId =",opId, opIds); - if( opId===opIds.lockControl ){ - handleLockRequest(); - setTimeout(f, 50); - return; - } const hnd = f.opHandlers[opId] ?? toss("No waitLoop handler for whichOp #",opId); const args = state.s11n.deserialize( true /* clear s11n to keep the caller from confusing this with @@ -741,6 +667,7 @@ const installAsyncProxy = function(){ navigator.storage.getDirectory().then(function(d){ state.rootDir = d; globalThis.onmessage = function({data}){ + warn(globalThis.location.href,"onmessage()",data); switch(data.type){ case 'opfs-async-init':{ /* Receive shared state from synchronous partner */ @@ -767,7 +694,7 @@ const installAsyncProxy = function(){ flagAsyncShutdown = false; waitLoop(); } - break; + break; } }; wPost('opfs-async-loaded'); diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index b2d25b85e4..8119b32469 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -59,6 +59,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const installOpfsWlVfs = async function callee(options){ options = opfsUtil.initOptions(options, callee); if( !options ) return sqlite3; + options.verbose = 2; const capi = sqlite3.capi, debug = (...args)=>sqlite3.config.warn("opfs-wl:",...args), state = opfsUtil.createVfsState('opfs-wl', options), @@ -67,85 +68,55 @@ const installOpfsWlVfs = async function callee(options){ mTimeStart = opfsVfs.mTimeStart, mTimeEnd = opfsVfs.mTimeEnd, __openFiles = opfsVfs.__openFiles; - debug("state",JSON.stringify(state,false,' ')); + //debug("state",JSON.stringify(state,false,' ')); /* At this point, createVfsState() has populated state and opfsVfs with any code common to both the "opfs" and "opfs-wl" VFSes. Now comes the VFS-dependent work... */ - return opfsVfs.doTheThing(util.nu({ - xLock: function(pFile, lockType){ + return opfsVfs.bindVfs(util.nu({ + xLock: function(pFile,lockType){ mTimeStart('xLock'); ++metrics.xLock.count; const f = __openFiles[pFile]; - debug("xLock()",f,lockType); let rc = 0; - /* See notes in sqlite3-vfs-opfs.c-pp.js. */ + /* All OPFS locks are exclusive locks. If xLock() has + previously succeeded, do nothing except record the lock + type. If no lock is active, have the async counterpart + lock the file. */ if( f.lockType ) { f.lockType = lockType; }else{ - try{ - const view = state.sabOPView; - /* We need to pass pFile's name to the async proxy so that - it can create the WebLock name. */ - state.s11n.serialize(f.filename) - Atomics.store(view, state.lock.atomicsHandshake, 0); - Atomics.store(view, state.lock.type, lockType); - Atomics.store(view, state.opIds.whichOp, state.opIds.lockControl); - Atomics.notify(state.sabOPView, state.opIds.whichOp) - debug("xLock waiting..."); -//#if not nope - while( 2 !== Atomics.load(view, state.lock.atomicsHandshake) ){ - Atomics.wait(view, state.lock.atomicsHandshake, 0); - } -//#else - while('not-equal'!==Atomics.wait(view, state.lock.atomicsHandshake, 0)){ - /* Loop is a workaround for environment-specific quirks. See - notes in similar loops. */ - debug("xLock still waiting..."); - } -//#endif - debug("xLock done waiting"); - f.lockType = lockType; - }catch(e){ - sqlite3.config.error("xLock(",arguments,") failed", e, f); - rc = capi.SQLITE_IOERR_LOCK; - } + rc = opRun('xLock', pFile, lockType); + if( 0===rc ) f.lockType = lockType; } mTimeEnd(); return rc; }, xUnlock: function(pFile,lockType){ - debug("xUnlock()",f,lockType); mTimeStart('xUnlock'); ++metrics.xUnlock.count; const f = __openFiles[pFile]; let rc = 0; - if( lockType < f.lockType ){ - try{ - const view = state.sabOPView; - Atomics.store(view, state.lock.atomicsHandshake, 1); - Atomics.notify(view, state.lock.atomicsHandshake); - Atomics.wait(view, state.lock.atomicsHandshake, 1); - }catch(e){ - sqlite3.config.error("xUnlock(",pFile,lockType,") failed",e, f); - rc = capi.SQLITE_IOERR_LOCK; - } + if( capi.SQLITE_LOCK_NONE === lockType + && f.lockType ){ + rc = opRun('xUnlock', pFile, lockType); } if( 0===rc ) f.lockType = lockType; mTimeEnd(); return rc; } }), function(sqlite3, vfs){ + //debug("registered VFS"); if(sqlite3.oo1){ const OpfsWlDb = function(...args){ const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); - opt.vfs = opfsVfs.$zName; + opt.vfs = vfs.$zName; sqlite3.oo1.DB.dbCtorHelper.call(this, opt); }; OpfsWlDb.prototype = Object.create(sqlite3.oo1.DB.prototype); sqlite3.oo1.OpfsWlDb = OpfsWlDb; OpfsWlDb.importDb = opfsUtil.importDb; }/*extend sqlite3.oo1*/ - })/*doTheThing()*/; + })/*bindVfs()*/; }/*installOpfsWlVfs()*/; installOpfsWlVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 6fe317ec8d..89b52c836d 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -95,7 +95,7 @@ const installOpfsVfs = async function callee(options){ /* At this point, createVfsState() has populated state and opfsVfs with any code common to both the "opfs" and "opfs-wl" VFSes. Now comes the VFS-dependent work... */ - return opfsVfs.doTheThing(util.nu({ + return opfsVfs.bindVfs(util.nu({ xLock: function(pFile,lockType){ mTimeStart('xLock'); ++metrics.xLock.count; @@ -147,7 +147,7 @@ const installOpfsVfs = async function callee(options){ } ); }/*extend sqlite3.oo1*/ - })/*doTheThing()*/; + })/*bindVfs()*/; }/*installOpfsVfs()*/; installOpfsVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ diff --git a/ext/wasm/tests/opfs/concurrency/test.js b/ext/wasm/tests/opfs/concurrency/test.js index 9208ff47fc..18c01a5b7e 100644 --- a/ext/wasm/tests/opfs/concurrency/test.js +++ b/ext/wasm/tests/opfs/concurrency/test.js @@ -121,14 +121,15 @@ const li = []; for(const k of [ 'interval', 'iterations', 'unlock-asap', - 'verbose', 'vfs', 'workers' + 'opfsVerbose', 'vfs', 'workers' ]){ if( obj.hasOwnProperty(k) ) li.push(k+'='+obj[k]); } return li.join('&'); }; for(const opt of [ - {interval: 500, workers: 2, iterations: 30, vfs: 'opfs-wl', verbose: 2}, + {interval: 500, workers: 1, iterations: 5, vfs: 'opfs-wl', opfsVerbose: 2}, + {interval: 500, workers: 2, iterations: 5, vfs: 'opfs-wl', opfsVerbose: 2}, {interval: 1000, workers: 5, iterations: 30}, {interval: 500, workers: 5, iterations: 30}, {interval: 250, workers: 3, iterations: 30}, diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index b4cb5a30a4..77e320e9af 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -1,6 +1,7 @@ importScripts( (new URL(globalThis.location.href).searchParams).get('sqlite3.dir') + '/sqlite3.js' ); +//const sqlite3InitModule = (await import("../../../jswasm/sqlite3.mjs", )).default; globalThis.sqlite3InitModule.__isUnderTest = true; globalThis.sqlite3InitModule().then(async function(sqlite3){ const urlArgs = new URL(globalThis.location.href).searchParams; @@ -85,7 +86,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ }catch(e){ interval.error = e; } - stdout("doWork()",prefix,"error ",interval.error); + //stdout("doWork()",prefix,"error ",interval.error); }; setTimeout(async function timer(){ await doWork(); diff --git a/manifest b/manifest index a92a7a8886..c3f7604220 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sopfs-wl\slock\shang\shas\sbeen\straced\sto\sstarvation\sbetween\sthe\sWebLock\sand\sthe\stight\swait-on-VFS-calls\sAtomics.wait()\sloop.\sThis\scan\sreportedly\sbe\sresolved\swith\sanother\slevel\sof\sindirection\sin\swhich\sthe\sWebLock\stakes\sover\sthe\swait-on-VFS-calls\spart\suntil\sit's\sunlocked,\sreturning\sto\sthe\sglobal\sloop\swhen\sit's\sdone.\sThat\sexceeds\sthis\smorning's\sambitions\sbut\sis\snext\sto\stry\sout. -D 2026-03-05T06:30:57.097 +C Strip\sthe\sopfs-wl\s"back\sto\sformula",\sremoving\sthe\scurrent\sfalse\sstarts\sso\sthat\sthis\scan\sbe\stried\sagain\swithout\stripping\sover\sany\scruft.\sThe\scurrent\simpl\sis\ssubject,\swith\sno\sobvious\sway\sout\sof\sit,\sto\sstarvation\sin\sthe\sasync\sproxy. +D 2026-03-05T11:51:27.592 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js 404aa8fd676791f0ce71e5c48f5f19e13e7b8e967a9af6a76927d524bbb46158 +F ext/wasm/api/opfs-common-shared.c-pp.js d54054b9b39ceb088692153f400d2d9a147e4a45d039c8a027575bdc7a02ac68 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -594,12 +594,12 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 82339eb043af53638b127a4649685da62b6fa33426d2013520eb6aeb114ede46 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 81d24de69b43d3c0940dbaa9bc82de193b720107e5a2ddfd31bc50640dd4903d F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 88add6362468df4ecbbd00878c7a83cd81e555c677103ead51c34bd2be1a3963 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 50a955ef393722d498177ad09c9e2d05bbe8dccae4c40c501482a860ca30017d +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 8233c5f9021b0213134e2adbaf6036b8f1dffd4747083a4087c1c19ae107f962 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js f3b7296480984bcc6050fe9724a8b215c405977dd69daea7145ece25751e4b33 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -646,8 +646,8 @@ F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c9 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb F ext/wasm/tester1.c-pp.js 6b946cd6d4da130dbae4a401057716d27117ca02cad2ea8c29ae9c46c675d618 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e -F ext/wasm/tests/opfs/concurrency/test.js b80e17488a8e4d5500deaf68f73a7298d7d351f74bb952691a4e7b6c02a5643b -F ext/wasm/tests/opfs/concurrency/worker.js de0be3be41da20e6639cdea10467fb5d9cdf540e711b403728a08d99bbb82ee6 +F ext/wasm/tests/opfs/concurrency/test.js 74f4ef9a827d081e6bb0ffb1d124bb54015dab8f7ae47abd5b5f26d71633331a +F ext/wasm/tests/opfs/concurrency/worker.js 3425e6dad755a1c69a6efc63a47a3ade4e7f0a9a138994ba37f996571fb46288 F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 62fc8b35aeec75f5648b3daa24162c638999d447aa874bdfcbac1431c5c97b6f -R 4e4429a4d6f21ed4af3f33058413d5c8 +P 113bd910e12fea17f9f4a0a3baf706f15627c08cfa6b47a960a83eee761ef4dd +R 4ea42d5818e8a1a0aa1e2fe935a1308b U stephan -Z 5eeca3e1560bb544ee40d011df9232c0 +Z 71a80b89b42b2027ae01cf15e67091dc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c36b9ce9ac..e12e126346 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -113bd910e12fea17f9f4a0a3baf706f15627c08cfa6b47a960a83eee761ef4dd +d022f1f5e74dedae044801330eb099022498f359f408e69b3574885641b312f5 From 46686ac681c1622fb9e1fabbe4b7f63fd6242276 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 5 Mar 2026 14:39:27 +0000 Subject: [PATCH 101/197] Fix a long-standing problem with DISTINCT LEFT JOIN queries. FossilOrigin-Name: f43294a5582b540a33c584ec8c69b6a5006a4d243ad5cf36125b2b0806e3518b --- manifest | 19 +++++++++++-------- manifest.tags | 4 ++-- manifest.uuid | 2 +- src/where.c | 7 +++++++ test/distinct2.test | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index ff582d3103..49e7b5f812 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\slittle\sflexibility\sto\scheckpoint\ssizes\sin\sthe\swalrestart.test\sscript. -D 2026-03-05T00:30:05.130 +C Fix\sa\slong-standing\sproblem\swith\sDISTINCT\sLEFT\sJOIN\squeries. +D 2026-03-05T14:39:27.298 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -811,7 +811,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab F src/wal.c 88d94fd15a75f6eda831fa32d1148a267ea37bf0a4b69829a73dfde06244b08f F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 -F src/where.c 9f09ee7b260010138d5f9fb5f195b98051119eae3096a99d72ff16c83230f4af +F src/where.c d17b2ed5977d823bf0af8e78a029c05539b82f350cdf07e3427c288ce655e4ab F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da F src/wherecode.c 783ecd30061c875c919a5163e4b55f9a0eccdaf7c9b17ad2908a1668a8766bc4 F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6 @@ -1050,7 +1050,7 @@ F test/descidx2.test a0ba347037ff3b811f4c6ceca5fd0f9d5d72e74e59f2d9de346a9d2f6ad F test/descidx3.test 953c831df7ea219c73826dfbf2f6ee02d95040725aa88ccb4fa43d1a1999b926 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e F test/distinct.test 691c9e850b0d0b56b66e7e235453198cb4cf0760e324b7403d3c5abbeab0a014 -F test/distinct2.test a6af6a90b2c1eea64c3cc87ea7f8feb832053f7276fe3c212abacf646de4762a +F test/distinct2.test 072f33e1348b5cae4156e7ca4c124d21053f77d96d5d960a1ba21806416074ab F test/distinctagg.test 40d7169ae5846caaf62c6e307d2ca3c333daf9b6f7cde888956a339a97afe85f F test/dotcmd01.sql 0388a778912ed08436ae5c80e03389d8bd347fa724611193257a18c69692019d F test/e_blobbytes.test 4c01dfe4f12087b92b20705a3fdfded45dc4ed16d5a211fed4e1d2786ba68a52 @@ -2189,8 +2189,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 61f8a28591a833b1f5834a347feefeba8414fecc7ff154f1b6ef19963f181812 -R ae5ae7b3ea3c5883e95986d59e781f25 -U drh -Z 684be6d6a05353fa19523ecf503b665a +P e438b564ca84377746464034d770e9c1f5899d935c6a4dffc546acb92afb800e +R 0c0331354057ee00c385580cdf2cbb8e +T *branch * pending-3.52 +T *sym-pending-3.52 * +T -sym-trunk * +U dan +Z 2ed2ecdf12f98df5afd42bce2e836452 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..0249cadd8a 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch pending-3.52 +tag pending-3.52 diff --git a/manifest.uuid b/manifest.uuid index 0ab5334ecc..11ad8e3e34 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e438b564ca84377746464034d770e9c1f5899d935c6a4dffc546acb92afb800e +f43294a5582b540a33c584ec8c69b6a5006a4d243ad5cf36125b2b0806e3518b diff --git a/src/where.c b/src/where.c index 2ef2ce0bee..216a75c233 100644 --- a/src/where.c +++ b/src/where.c @@ -7554,6 +7554,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ){ int r1 = pParse->nMem+1; int j, op; + int addrIfNull; + if( pLevel->iLeftJoin ){ + addrIfNull = sqlite3VdbeAddOp2(v, OP_IfNullRow, pLevel->iIdxCur, r1); + } for(j=0; jiIdxCur, j, r1+j); } @@ -7563,6 +7567,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ VdbeCoverageIf(v, op==OP_SeekLT); VdbeCoverageIf(v, op==OP_SeekGT); sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2); + if( pLevel->iLeftJoin ){ + sqlite3VdbeJumpHere(v, addrIfNull); + } } #endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */ } diff --git a/test/distinct2.test b/test/distinct2.test index 5de4d30940..a410d9abbf 100644 --- a/test/distinct2.test +++ b/test/distinct2.test @@ -380,4 +380,36 @@ do_execsql_test 5080 { ); } 0 +#------------------------------------------------------------------------- +# 2026-03-05 - do not "skip-ahead" of a null-row on the RHS of a +# LEFT JOIN. +# +reset_db + +do_execsql_test 6000 { + CREATE TABLE t1(c1 UNIQUE NOT NULL); + INSERT INTO t1 VALUES(1); + CREATE TABLE t0(c0 UNIQUE); + INSERT INTO t0 VALUES(0); + WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<1000) + INSERT INTO t0(c0) SELECT NULL FROM c; +} {} + +do_execsql_test 6010 { + SELECT DISTINCT * FROM t1 LEFT OUTER JOIN t0 ON c0>c1; +} {1 {}} + +do_execsql_test 6020 { + SELECT DISTINCT * FROM t1 FULL OUTER JOIN t0 ON c0>c1; +} {1 {} {} 0 {} {}} + +do_execsql_test 6040 { + ANALYZE; + SELECT DISTINCT * FROM t1 LEFT OUTER JOIN t0 ON c0>c1; +} {1 {}} + +do_execsql_test 6050 { + SELECT DISTINCT * FROM t1 FULL OUTER JOIN t0 ON c0>c1; +} {1 {} {} 0 {} {}} + finish_test From 21bdb75ac804bf693227f3bbb44941ece550a10e Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 5 Mar 2026 16:23:04 +0000 Subject: [PATCH 102/197] Ensure xMutexInit() is called in SQLITE_THREAD_MISUSE_WARNINGS builds. FossilOrigin-Name: ac6a389e09a0de1b622af4a7136dc66875e8009c27950f2260a96f17fec4f9bc --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/mutex.c | 5 +++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index ff582d3103..afabf2d61f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\slittle\sflexibility\sto\scheckpoint\ssizes\sin\sthe\swalrestart.test\sscript. -D 2026-03-05T00:30:05.130 +C Ensure\sxMutexInit()\sis\scalled\sin\sSQLITE_THREAD_MISUSE_WARNINGS\sbuilds. +D 2026-03-05T16:23:04.263 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -703,7 +703,7 @@ F src/mem5.c b7da5c10a726aacacc9ad7cdcb0667deec643e117591cc69cf9b4b9e7f3e96ff F src/memdb.c a3feb427cdd4036ea2db0ba56d152f14c8212ca760ccb05fb7aa49ff6b897df3 F src/memjournal.c c283c6c95d940eb9dc70f1863eef3ee40382dbd35e5a1108026e7817c206e8a0 F src/msvc.h 80b35f95d93bf996ccb3e498535255f2ef1118c78764719a7cd15ab4106ccac9 -F src/mutex.c 5dc0dd69c4216dd976bd463f4ee62a0fa0c24860c0815238ff205f62e194431f +F src/mutex.c 00b8cee206a67fd764d001f3a148494331d8d0b3b9c3974ecd69ff29bb444462 F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4 F src/mutex_unix.c f7ee5a2061a4c11815a2bf4fc0e2bfa6fb8d9dc89390eb613ca0cec32fc9a3d1 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 61f8a28591a833b1f5834a347feefeba8414fecc7ff154f1b6ef19963f181812 -R ae5ae7b3ea3c5883e95986d59e781f25 -U drh -Z 684be6d6a05353fa19523ecf503b665a +P e438b564ca84377746464034d770e9c1f5899d935c6a4dffc546acb92afb800e +R 98b343070b572cbf7a5ff6d9141f79c1 +U dan +Z e4acde8ab7cdeb14914c6809a0a8cc28 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0ab5334ecc..cbe7f51d64 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e438b564ca84377746464034d770e9c1f5899d935c6a4dffc546acb92afb800e +ac6a389e09a0de1b622af4a7136dc66875e8009c27950f2260a96f17fec4f9bc diff --git a/src/mutex.c b/src/mutex.c index f0936af91d..21b47e511b 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -84,11 +84,12 @@ static int checkMutexNotheld(sqlite3_mutex *p){ */ static int checkMutexInit(void){ pGlobalMutexMethods = sqlite3DefaultMutex(); - return SQLITE_OK; + return pGlobalMutexMethods->xMutexInit(); } static int checkMutexEnd(void){ + int rc = pGlobalMutexMethods->xMutexEnd(); pGlobalMutexMethods = 0; - return SQLITE_OK; + return rc; } /* From d61ecd83b831ec2527c0bc6c34af142893845522 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 5 Mar 2026 18:16:25 +0000 Subject: [PATCH 103/197] Enhance ./configure to automatically detect linenoise in ../linenoise relative to the build directory, or ../linenoise relative to the source directory, or at $HOME/linenoise. FossilOrigin-Name: eb6b47c667e52d5c8682d650dbd114c08d2ecce4bb7bce6fdf2589d1ea09f5c0 --- autosetup/sqlite-config.tcl | 23 +++++++++++++++++++++++ manifest | 17 +++++++---------- manifest.uuid | 2 +- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/autosetup/sqlite-config.tcl b/autosetup/sqlite-config.tcl index fe1b355ab5..3c8be3797c 100644 --- a/autosetup/sqlite-config.tcl +++ b/autosetup/sqlite-config.tcl @@ -1138,6 +1138,27 @@ proc sqlite-check-line-editing {} { set editLibName "readline" ; # "readline" or "editline" set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE" set dirLn [opt-val with-linenoise] + + # If none of --with-linenoise, --enable-readline, or --enable-editline + # are provided, but there exists a directory "linenoise" at $HOME or + # a sibling of the build or source directory, then try to use that linenoise + # direcctory. + # + if {"" eq $dirLn + && ![proj-opt-was-provided readline] + && ![proj-opt-was-provided editline] + } { + set dirlist ../linenoise + catch {lappend dirlist [file normalize $::autosetup(srcdir)/../linenoise]} + catch {lappend dirlist $::env(HOME)/linenoise} + foreach d $dirlist { + if {[file exists $d/linenoise.c] && [file exists $d/linenoise.h]} { + set dirLn $d + break + } + } + } + if {"" ne $dirLn} { # Use linenoise from a copy of its sources (not a library)... if {![file isdir $dirLn]} { @@ -1173,6 +1194,8 @@ proc sqlite-check-line-editing {} { if {$::sqliteConfig(use-jim-for-codegen) && 2 == $lnVal} { define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE] user-notice "Adding linenoise support to jimsh." + } else { + user-notice "Using linenoise at [file normalize $dirLn]" } return "linenoise ($flavor)" } elseif {[opt-bool editline]} { diff --git a/manifest b/manifest index 49e7b5f812..0ad71e084b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\slong-standing\sproblem\swith\sDISTINCT\sLEFT\sJOIN\squeries. -D 2026-03-05T14:39:27.298 +C Enhance\s./configure\sto\sautomatically\sdetect\slinenoise\sin\s../linenoise\nrelative\sto\sthe\sbuild\sdirectory,\sor\s../linenoise\srelative\sto\sthe\ssource\ndirectory,\sor\sat\s$HOME/linenoise. +D 2026-03-05T18:16:25.845 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -47,7 +47,7 @@ F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1 F autosetup/jimsh0.c 916bbdf8023fbda9937afae57d81a853d8c2ea00f2320aa27becbc33574f963d F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba F autosetup/proj.tcl ce301197f364f7ce2acabbbd84b43d19e917ec73653157ca134a06f32d322712 -F autosetup/sqlite-config.tcl 7463d59c9c5e86ca286ea16fdab943058beb9346110049eca435154795890f71 +F autosetup/sqlite-config.tcl d7f456247e25592c7e47266da4bcd1d5d22268cfc901da826682b1043dd8e212 F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9 F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca F autosetup/teaish/core.tcl e014dd95900c7f9a34e8e0f460f47e94841059827bce8b4c49668b0c7ae3f1a0 @@ -2189,11 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P e438b564ca84377746464034d770e9c1f5899d935c6a4dffc546acb92afb800e -R 0c0331354057ee00c385580cdf2cbb8e -T *branch * pending-3.52 -T *sym-pending-3.52 * -T -sym-trunk * -U dan -Z 2ed2ecdf12f98df5afd42bce2e836452 +P f43294a5582b540a33c584ec8c69b6a5006a4d243ad5cf36125b2b0806e3518b +R 347a8275875a278d651ac2f82cbca624 +U drh +Z e79345a4344873cde92cb59e7eccc257 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 11ad8e3e34..4cdb395950 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f43294a5582b540a33c584ec8c69b6a5006a4d243ad5cf36125b2b0806e3518b +eb6b47c667e52d5c8682d650dbd114c08d2ecce4bb7bce6fdf2589d1ea09f5c0 From 7a125b97d7d3145e0a3af5356672c83f685d25c5 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 5 Mar 2026 18:28:43 +0000 Subject: [PATCH 104/197] Fix the build for -DSQLITE_OMIT_FLOATING_POINT. FossilOrigin-Name: f41b9ad98c474755c6701eb6ab3dc9864ace9b52a81581f73ca0912cedbc3c37 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqliteInt.h | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index afabf2d61f..4ba7455c1a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sxMutexInit()\sis\scalled\sin\sSQLITE_THREAD_MISUSE_WARNINGS\sbuilds. -D 2026-03-05T16:23:04.263 +C Fix\sthe\sbuild\sfor\s-DSQLITE_OMIT_FLOATING_POINT. +D 2026-03-05T18:28:43.554 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -734,7 +734,7 @@ F src/shell.c.in 2acdfca982deb70cdfefb8b422822d4e0234fe4dde6ff2bd9020b2644585391 F src/sqlite.h.in 1f853f1d836af3e5a0b451521041d05658988a45f6978aaae08286e483fee5ac F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h 185abb373dc2a311e3292540ef177ea301d8140b976ecd8ba381a5a0162cd6e9 +F src/sqliteInt.h 1c7f23ab9d6efdf3dc434880b6320f158937284f6e2cebd2a024def0c749cb04 F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P e438b564ca84377746464034d770e9c1f5899d935c6a4dffc546acb92afb800e -R 98b343070b572cbf7a5ff6d9141f79c1 -U dan -Z e4acde8ab7cdeb14914c6809a0a8cc28 +P ac6a389e09a0de1b622af4a7136dc66875e8009c27950f2260a96f17fec4f9bc +R d830c5400560d57c4c701eac20806654 +U drh +Z 9616ac8ea29aa5673148444bb1d01109 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cbe7f51d64..f1ab2dfb02 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ac6a389e09a0de1b622af4a7136dc66875e8009c27950f2260a96f17fec4f9bc +f41b9ad98c474755c6701eb6ab3dc9864ace9b52a81581f73ca0912cedbc3c37 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 795f874b61..c4a8768615 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -661,6 +661,7 @@ # define float sqlite_int64 # define fabs(X) ((X)<0?-(X):(X)) # define sqlite3IsOverflow(X) 0 +# define INFINITY (9223372036854775807LL) # ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) # endif From 831e2332027c0b70ba801bef4148b6b2ca79f8a1 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 09:06:24 +0000 Subject: [PATCH 105/197] Reimplement the OPFS async proxy's wait-forever loop to be more async-friendly for upcoming changes. FossilOrigin-Name: fd775772fbb50b04c8c37977b90a708784eefed403e3668196c9d95559d3a5e1 --- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 30 +++++++------------ manifest | 12 ++++---- manifest.uuid | 2 +- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 0db9a99141..16e2d2aa1c 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -625,31 +625,21 @@ const installAsyncProxy = function(){ } } const opIds = state.opIds; + const opView = state.sabOPView; + const slotWhichOp = opIds.whichOp; + const idleWaitTime = state.asyncIdleWaitTime; while(!flagAsyncShutdown){ try { - if('not-equal'!==Atomics.wait( - state.sabOPView, opIds.whichOp, 0, state.asyncIdleWaitTime - )){ - /* Maintenance note: we compare against 'not-equal' because - - https://github.com/tomayac/sqlite-wasm/issues/12 - - is reporting that this occasionally, under high loads, - returns 'ok', which leads to the whichOp being 0 (which - isn't a valid operation ID and leads to an exception, - along with a corresponding ugly console log - message). Unfortunately, the conditions for that cannot - be reliably reproduced. The only place in our code which - writes a 0 to the state.opIds.whichOp SharedArrayBuffer - index is a few lines down from here, and that instance - is required in order for clear communication between - the sync half of this proxy and this half. - */ + const opId = Atomics.load(opView, slotWhichOp); + if( 0===opId ){ + const rv = Atomics.waitAsync(opView, slotWhichOp, 0, + idleWaitTime); + if( rv.async ) await rv.value; await releaseImplicitLocks(); continue; } - const opId = Atomics.exchange(state.sabOPView, opIds.whichOp, 0); const hnd = f.opHandlers[opId] ?? toss("No waitLoop handler for whichOp #",opId); + Atomics.store(opView, slotWhichOp, 0); const args = state.s11n.deserialize( true /* clear s11n to keep the caller from confusing this with an exception string written by the upcoming @@ -659,7 +649,7 @@ const installAsyncProxy = function(){ if(hnd.f) await hnd.f(...args); else error("Missing callback for opId",opId); }catch(e){ - error('in waitLoop():',e); + error('in waitLoop():', e); } } }; diff --git a/manifest b/manifest index c3f7604220..db41159ec8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Strip\sthe\sopfs-wl\s"back\sto\sformula",\sremoving\sthe\scurrent\sfalse\sstarts\sso\sthat\sthis\scan\sbe\stried\sagain\swithout\stripping\sover\sany\scruft.\sThe\scurrent\simpl\sis\ssubject,\swith\sno\sobvious\sway\sout\sof\sit,\sto\sstarvation\sin\sthe\sasync\sproxy. -D 2026-03-05T11:51:27.592 +C Reimplement\sthe\sOPFS\sasync\sproxy's\swait-forever\sloop\sto\sbe\smore\sasync-friendly\sfor\supcoming\schanges. +D 2026-03-06T09:06:24.644 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -594,7 +594,7 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 81d24de69b43d3c0940dbaa9bc82de193b720107e5a2ddfd31bc50640dd4903d +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js df2c3be6bcdbfab5c7426c14edf768d97de81af0c9d22282c618ab7c4bb3f48f F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 113bd910e12fea17f9f4a0a3baf706f15627c08cfa6b47a960a83eee761ef4dd -R 4ea42d5818e8a1a0aa1e2fe935a1308b +P d022f1f5e74dedae044801330eb099022498f359f408e69b3574885641b312f5 +R 29e425791ac08c7a9478759e76e59fc3 U stephan -Z 71a80b89b42b2027ae01cf15e67091dc +Z fa163f510f2e4230b70e49c7b3e367ed # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e12e126346..22849172c8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d022f1f5e74dedae044801330eb099022498f359f408e69b3574885641b312f5 +fd775772fbb50b04c8c37977b90a708784eefed403e3668196c9d95559d3a5e1 From 891f5a176b66dc2428f44b1f4c9fd1ebd0949c47 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 09:11:47 +0000 Subject: [PATCH 106/197] A slight simplification/optimization in the OPFS proxy's waitLoop(). FossilOrigin-Name: 521bb140b7ed237c118ac9094732d06907229a6ff385502e850c679bd623fd58 --- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 5 ++--- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 16e2d2aa1c..0fc23540e1 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -638,16 +638,15 @@ const installAsyncProxy = function(){ await releaseImplicitLocks(); continue; } - const hnd = f.opHandlers[opId] ?? toss("No waitLoop handler for whichOp #",opId); Atomics.store(opView, slotWhichOp, 0); + const hnd = f.opHandlers[opId]?.f ?? toss("No waitLoop handler for whichOp #",opId); const args = state.s11n.deserialize( true /* clear s11n to keep the caller from confusing this with an exception string written by the upcoming operation */ ) || []; //warn("waitLoop() whichOp =",opId, hnd, args); - if(hnd.f) await hnd.f(...args); - else error("Missing callback for opId",opId); + await hnd(...args); }catch(e){ error('in waitLoop():', e); } diff --git a/manifest b/manifest index db41159ec8..654ff7de0b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Reimplement\sthe\sOPFS\sasync\sproxy's\swait-forever\sloop\sto\sbe\smore\sasync-friendly\sfor\supcoming\schanges. -D 2026-03-06T09:06:24.644 +C A\sslight\ssimplification/optimization\sin\sthe\sOPFS\sproxy's\swaitLoop(). +D 2026-03-06T09:11:47.789 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -594,7 +594,7 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js df2c3be6bcdbfab5c7426c14edf768d97de81af0c9d22282c618ab7c4bb3f48f +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 5f95c210183d203c7bc5be4a8139cc7fa2e50810c306bb2651648c32ab419fcf F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d022f1f5e74dedae044801330eb099022498f359f408e69b3574885641b312f5 -R 29e425791ac08c7a9478759e76e59fc3 +P fd775772fbb50b04c8c37977b90a708784eefed403e3668196c9d95559d3a5e1 +R f7984b1956caa0bacce9f6eadf906e85 U stephan -Z fa163f510f2e4230b70e49c7b3e367ed +Z c9e43a6b144c73d106bca120c0ac01f1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 22849172c8..82686c7137 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fd775772fbb50b04c8c37977b90a708784eefed403e3668196c9d95559d3a5e1 +521bb140b7ed237c118ac9094732d06907229a6ff385502e850c679bd623fd58 From ea595494e202c9aa9d733bfe379e228f5cb828b6 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 6 Mar 2026 11:18:12 +0000 Subject: [PATCH 107/197] Uninstall faultsim at the end of the walrestart.test script. FossilOrigin-Name: 798905a1277ecb17245f2a7378fdc8dc608374fde50bdfe44d09195a7c78cb5c --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/walrestart.test | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 4ba7455c1a..45a28abe06 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sbuild\sfor\s-DSQLITE_OMIT_FLOATING_POINT. -D 2026-03-05T18:28:43.554 +C Uninstall\sfaultsim\sat\sthe\send\sof\sthe\swalrestart.test\sscript. +D 2026-03-06T11:18:12.116 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -2004,7 +2004,7 @@ F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03 F test/walpersist.test 8d78a1ec91299163451417b451a2bac3481f8eb9f455b1ca507a6625c927ca6e F test/walprotocol.test 1b3f922125e341703f6e946d77fdc564d38fb3e07a9385cfdc6c99cac1ecf878 F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131 -F test/walrestart.test df92e581d169429f0cc44f49cacccc9dfd749495d536467379668a6d073369dc +F test/walrestart.test 5168c0c2414d1971d8dec949c1070a0144cf15402361ba0d0e6a8054f5598a64 F test/walro.test 78a84bc0fdae1385c06b017215c426b6845734d6a5a3ac75c918dd9b801b1b9d F test/walro2.test 33955a6fd874dd9724005e17f77fef89d334b3171454a1256fe4941a96766cdc F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P ac6a389e09a0de1b622af4a7136dc66875e8009c27950f2260a96f17fec4f9bc -R d830c5400560d57c4c701eac20806654 -U drh -Z 9616ac8ea29aa5673148444bb1d01109 +P f41b9ad98c474755c6701eb6ab3dc9864ace9b52a81581f73ca0912cedbc3c37 +R 03d8212f429198d99a6abf4dff94f1bb +U dan +Z 94f4389a9d22dd05b3615fbebb37a126 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f1ab2dfb02..a073e410c3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f41b9ad98c474755c6701eb6ab3dc9864ace9b52a81581f73ca0912cedbc3c37 +798905a1277ecb17245f2a7378fdc8dc608374fde50bdfe44d09195a7c78cb5c diff --git a/test/walrestart.test b/test/walrestart.test index 9c3f76d71b..cf27a40980 100644 --- a/test/walrestart.test +++ b/test/walrestart.test @@ -84,4 +84,6 @@ do_catchsql_test 1.5 { PRAGMA integrity_check } {0 ok} +sqlite3_test_control_fault_install + finish_test From 544ef18bbdaa9ac6dcae07182640dd7893b52e1c Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 11:49:36 +0000 Subject: [PATCH 108/197] Remove an extraneous OPFS metrics increment. FossilOrigin-Name: bf3548a37712e848c7a9cadfdc1669a2be572ea0a0c28d84c157ab30f8c30c44 --- ext/wasm/api/opfs-common-shared.c-pp.js | 1 - manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index c709e0d15b..6540939b44 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -902,7 +902,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }, xSync: function(pFile,flags){ mTimeStart('xSync'); - ++metrics.xSync.count; const rc = opRun('xSync', pFile, flags); mTimeEnd(); return rc; diff --git a/manifest b/manifest index 654ff7de0b..94e2e47dac 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C A\sslight\ssimplification/optimization\sin\sthe\sOPFS\sproxy's\swaitLoop(). -D 2026-03-06T09:11:47.789 +C Remove\san\sextraneous\sOPFS\smetrics\sincrement. +D 2026-03-06T11:49:36.430 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js d54054b9b39ceb088692153f400d2d9a147e4a45d039c8a027575bdc7a02ac68 +F ext/wasm/api/opfs-common-shared.c-pp.js ecc3c69dc8a3b676f6999ef1b2ac4be825b7952ce5acbe86941f4f2f38607cb7 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P fd775772fbb50b04c8c37977b90a708784eefed403e3668196c9d95559d3a5e1 -R f7984b1956caa0bacce9f6eadf906e85 +P 521bb140b7ed237c118ac9094732d06907229a6ff385502e850c679bd623fd58 +R 334abfd624b27a29d02bb7116f94ced4 U stephan -Z c9e43a6b144c73d106bca120c0ac01f1 +Z 944b558939ff5f7ba7e037ff2a332b5b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 82686c7137..48801140c5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -521bb140b7ed237c118ac9094732d06907229a6ff385502e850c679bd623fd58 +bf3548a37712e848c7a9cadfdc1669a2be572ea0a0c28d84c157ab30f8c30c44 From 93353c0bc297f08c22dc0681b3fd34d65456da4c Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 6 Mar 2026 14:33:12 +0000 Subject: [PATCH 109/197] Add the new realpath() extension function to the list of functions prohibited in --safe mode of the CLI. FossilOrigin-Name: 5fa49c4d592778fb82c4e25c77cf0442d3dc23cc7f8d91d25952c722af866930 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/shell.c.in | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 45a28abe06..2ab14b61b6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Uninstall\sfaultsim\sat\sthe\send\sof\sthe\swalrestart.test\sscript. -D 2026-03-06T11:18:12.116 +C Add\sthe\snew\srealpath()\sextension\sfunction\sto\sthe\slist\sof\sfunctions\nprohibited\sin\s--safe\smode\sof\sthe\sCLI. +D 2026-03-06T14:33:12.191 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -730,7 +730,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576 -F src/shell.c.in 2acdfca982deb70cdfefb8b422822d4e0234fe4dde6ff2bd9020b26445853917 +F src/shell.c.in d4e9ce266ca8f7364da6e86df011f8655beeb5f0d074d624215a2d8ce220a0ad F src/sqlite.h.in 1f853f1d836af3e5a0b451521041d05658988a45f6978aaae08286e483fee5ac F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f41b9ad98c474755c6701eb6ab3dc9864ace9b52a81581f73ca0912cedbc3c37 -R 03d8212f429198d99a6abf4dff94f1bb -U dan -Z 94f4389a9d22dd05b3615fbebb37a126 +P 798905a1277ecb17245f2a7378fdc8dc608374fde50bdfe44d09195a7c78cb5c +R b4a00b0f2cf0b157145ad751c36ae742 +U drh +Z 5fa431d1c8b551cd38716eecab285bc0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a073e410c3..033010bfd3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -798905a1277ecb17245f2a7378fdc8dc608374fde50bdfe44d09195a7c78cb5c +5fa49c4d592778fb82c4e25c77cf0442d3dc23cc7f8d91d25952c722af866930 diff --git a/src/shell.c.in b/src/shell.c.in index fb1dc2c2cd..ef30194fac 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -2222,6 +2222,7 @@ static int safeModeAuth( "fts3_tokenizer", "load_extension", "readfile", + "realpath", "writefile", "zipfile", "zipfile_cds", From ad2fe531d0f051394871fed612509a900b63f9f4 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 15:41:17 +0000 Subject: [PATCH 110/197] Expose SQLITE_{DBCONFIG_FP_DIGITS,LIMIT_PARSER_DEPTH,PREPARE_FROM_DDL} to WASM and add support for DBCONFIG_FP_DIGITS to the variadic wrapper for sqlite3_db_config(). These unfortunately went overlooked before the 3.52 release. FossilOrigin-Name: 837069635e53849cbca0aa876bad7c7ff44e17578ae492e07acf354067b7e16d --- ext/wasm/api/sqlite3-api-prologue.js | 1 + ext/wasm/api/sqlite3-wasm.c | 5 +++++ manifest | 19 +++++++++++-------- manifest.tags | 4 ++-- manifest.uuid | 2 +- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index c53acee769..5e6514b35d 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -1643,6 +1643,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( case capi.SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE: case capi.SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE: case capi.SQLITE_DBCONFIG_ENABLE_COMMENTS: + case capi.SQLITE_DBCONFIG_FP_DIGITS: if( !this.ip ){ this.ip = wasm.xWrap('sqlite3__wasm_db_config_ip','int', ['sqlite3*', 'int', 'int', '*']); diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c index dbfcdb7047..0c5f4f8ea5 100644 --- a/ext/wasm/api/sqlite3-wasm.c +++ b/ext/wasm/api/sqlite3-wasm.c @@ -571,6 +571,7 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){ DefInt(SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE); DefInt(SQLITE_DBCONFIG_ENABLE_COMMENTS); DefInt(SQLITE_DBCONFIG_MAX); + DefInt(SQLITE_DBCONFIG_FP_DIGITS); } _DefGroup; DefGroup(dbStatus){ @@ -698,6 +699,8 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){ DefInt(SQLITE_MAX_TRIGGER_DEPTH); DefInt(SQLITE_LIMIT_WORKER_THREADS); DefInt(SQLITE_MAX_WORKER_THREADS); + DefInt(SQLITE_LIMIT_PARSER_DEPTH); + DefInt(SQLITE_MAX_PARSER_DEPTH); } _DefGroup; DefGroup(openFlags) { @@ -731,6 +734,7 @@ SQLITE_WASM_EXPORT2(const char *,sqlite3__wasm_enum_json,(void)){ DefInt(SQLITE_PREPARE_PERSISTENT); DefInt(SQLITE_PREPARE_NORMALIZE); DefInt(SQLITE_PREPARE_NO_VTAB); + DefInt(SQLITE_PREPARE_FROM_DDL); } _DefGroup; DefGroup(resultCodes) { @@ -1640,6 +1644,7 @@ SQLITE_WASM_EXPORT2(int,sqlite3__wasm_db_config_ip, case SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE: case SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE: case SQLITE_DBCONFIG_ENABLE_COMMENTS: + case SQLITE_DBCONFIG_FP_DIGITS: return sqlite3_db_config(pDb, op, arg1, pArg2); default: return SQLITE_MISUSE; } diff --git a/manifest b/manifest index 2ab14b61b6..3319d44dad 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\snew\srealpath()\sextension\sfunction\sto\sthe\slist\sof\sfunctions\nprohibited\sin\s--safe\smode\sof\sthe\sCLI. -D 2026-03-06T14:33:12.191 +C Expose\sSQLITE_{DBCONFIG_FP_DIGITS,LIMIT_PARSER_DEPTH,PREPARE_FROM_DDL}\sto\sWASM\sand\sadd\ssupport\sfor\sDBCONFIG_FP_DIGITS\sto\sthe\svariadic\swrapper\sfor\ssqlite3_db_config().\sThese\sunfortunately\swent\soverlooked\sbefore\sthe\s3.52\srelease. +D 2026-03-06T15:41:17.227 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -589,7 +589,7 @@ F ext/wasm/api/post-js-header.js d24bd0d065f3489c8b78ddf3ead6321e5d047187a162cd5 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f F ext/wasm/api/sqlite3-api-glue.c-pp.js 9b33e3ee467791dec4fd1b444b12a8545dfbb6c8b28ac651c7bdc7661a3b5a5c F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c41db98a22b534c15e543cfa -F ext/wasm/api/sqlite3-api-prologue.js 1fefd40ab21e3dbf46f43b6fafb07f13eb13cc157a884f7c1134caf631ddb3f2 +F ext/wasm/api/sqlite3-api-prologue.js 2eac3d601c8a824fda1529f9eb894518672d3e575b49c0601094afda442b294f F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc F ext/wasm/api/sqlite3-opfs-async-proxy.js 92d6d327a862f1627ff3e88e60fdfea9def06ad539d98929ba46490e64372736 @@ -598,7 +598,7 @@ F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 -F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 +F ext/wasm/api/sqlite3-wasm.c ddf9d435b2e901eaceb805ff694e9609c2f32b5cf89a4f164e734a6fa303fdd2 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 F ext/wasm/api/sqlite3-worker1.c-pp.js bd0655687090e3b1657268a6a9cacde1ea2a734079d194e16dbbed9083e51b38 F ext/wasm/c-pp-lite.c f38254fba42561728c2e4764a7ba8d68700091e7c2f4418112868c0daba16783 @@ -2189,8 +2189,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 798905a1277ecb17245f2a7378fdc8dc608374fde50bdfe44d09195a7c78cb5c -R b4a00b0f2cf0b157145ad751c36ae742 -U drh -Z 5fa431d1c8b551cd38716eecab285bc0 +P 5fa49c4d592778fb82c4e25c77cf0442d3dc23cc7f8d91d25952c722af866930 +R c204de2a6ba2b9951694d38c8e0cee6f +T *branch * wasm-post-3.52 +T *sym-wasm-post-3.52 * +T -sym-trunk * Cancelled\sby\sbranch. +U stephan +Z 8bd0294641b2b5c614c8dd53244c48f3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..233ecf8d52 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch wasm-post-3.52 +tag wasm-post-3.52 diff --git a/manifest.uuid b/manifest.uuid index 033010bfd3..4ae4073848 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5fa49c4d592778fb82c4e25c77cf0442d3dc23cc7f8d91d25952c722af866930 +837069635e53849cbca0aa876bad7c7ff44e17578ae492e07acf354067b7e16d From 257fdf8496d3b70e6fe7dac910c124fb9b9776dc Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 6 Mar 2026 16:01:44 +0000 Subject: [PATCH 111/197] Version 3.52.0 FossilOrigin-Name: 557aeb43869d3585137b17690cb3b64f7de6921774daae9e56403c3717dceab6 --- manifest | 11 +++++++---- manifest.tags | 3 +++ manifest.uuid | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/manifest b/manifest index 2ab14b61b6..079aacfd79 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\snew\srealpath()\sextension\sfunction\sto\sthe\slist\sof\sfunctions\nprohibited\sin\s--safe\smode\sof\sthe\sCLI. -D 2026-03-06T14:33:12.191 +C Version\s3.52.0 +D 2026-03-06T16:01:44.367 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -2189,8 +2189,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 798905a1277ecb17245f2a7378fdc8dc608374fde50bdfe44d09195a7c78cb5c +P 5fa49c4d592778fb82c4e25c77cf0442d3dc23cc7f8d91d25952c722af866930 R b4a00b0f2cf0b157145ad751c36ae742 +T +sym-major-release * +T +sym-release * +T +sym-version-3.52.0 * U drh -Z 5fa431d1c8b551cd38716eecab285bc0 +Z ee8b8689818d3dfbd1a3f7d6f78a36ce # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..e0b8607c18 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,5 @@ branch trunk tag trunk +tag release +tag major-release +tag version-3.52.0 diff --git a/manifest.uuid b/manifest.uuid index 033010bfd3..55fe12eaa3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5fa49c4d592778fb82c4e25c77cf0442d3dc23cc7f8d91d25952c722af866930 +557aeb43869d3585137b17690cb3b64f7de6921774daae9e56403c3717dceab6 From 7b9cd03c0ad4b7bdfc3f07434345a5ad7496d47a Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 16:04:21 +0000 Subject: [PATCH 112/197] This Web Lock impl can reliably run a single OPFS connection but rather unreliably 'loses' workers with higher counts, presumably due to deadlock or deadly embrace (how _all_ of them can deadlock at once is unclear, but clearly a bug). FossilOrigin-Name: d4e8583e2e80665adfe4e814adb6c219936af1dcac4105795045cb1a7b1e4864 --- ext/wasm/api/opfs-common-shared.c-pp.js | 38 ++- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 259 +++++++++++++++--- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 50 ++-- ext/wasm/tester1.c-pp.js | 24 +- ext/wasm/tests/opfs/concurrency/worker.js | 26 +- manifest | 20 +- manifest.uuid | 2 +- 7 files changed, 299 insertions(+), 120 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 6540939b44..2020184173 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -446,7 +446,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ - Call opfvs.bindVfs() */ - opfsUtil.initOptions = function(options, callee){ + opfsUtil.initOptions = function callee(options, callee){ const urlParams = new URL(globalThis.location.href).searchParams; if(urlParams.has('opfs-disable')){ //sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.'); @@ -458,19 +458,22 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return; } options = util.nu(options); - if(undefined===options.verbose){ - options.verbose = urlParams.has('opfs-verbose') - ? (+urlParams.get('opfs-verbose') || 2) : 1; - } - if(undefined===options.sanityChecks){ - options.sanityChecks = urlParams.has('opfs-sanity-check'); - } - if(undefined===options.proxyUri){ - options.proxyUri = callee.defaultProxyUri; - } + options.verbose ??= urlParams.has('opfs-verbose') + ? (+urlParams.get('opfs-verbose') || 2) : 1; + options.sanityChecks ??= urlParams.has('opfs-sanity-check'); + options.proxyUri ??= callee.defaultProxyUri; if('function' === typeof options.proxyUri){ options.proxyUri = options.proxyUri(); } + if( false ){ + /* This ends up with the same values for all Worker instances. */ + callee.counter ??= 0; + ++callee.counter; + options.workerId ??= urlParams.get('opfs-async-proxy-id') ?? callee.counter; + }else{ + options.workerId ??= (Math.random() * 10000000) | 0; + } + //sqlite3.config.warn("opfsUtil options =",JSON.stringify(options), 'urlParams =', urlParams); return options; }; @@ -585,7 +588,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ of this value is also used for determining how long to wait on lock contention to free up. */ - state.asyncIdleWaitTime = isWebLocker ? 100 : 150; + state.asyncIdleWaitTime = isWebLocker ? 150 : 150; /** Whether the async counterpart should log exceptions to @@ -1089,7 +1092,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ promiseWasRejected = false; return promiseResolve_(sqlite3); }; - options.proxyUri += '?vfs='+vfsName; + let proxyUri = options.proxyUri +( + (options.proxyUri.indexOf('?')<0) ? '?' : '&' + )+'vfs='+vfsName; + if( options.workerId ){ + proxyUri += '&opfs-async-proxy-id='+encodeURIComponent(options.workerId); + } const W = opfsVfs.worker = //#if target:es6-bundler-friendly (()=>{ @@ -1102,9 +1110,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } })(); //#elif target:es6-module - new Worker(new URL(options.proxyUri, import.meta.url)); + new Worker(new URL(proxyUri, import.meta.url)); //#else - new Worker(options.proxyUri); + new Worker(proxyUri); //#endif let zombieTimer = setTimeout(()=>{ /* At attempt to work around a browser-specific quirk in which diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 0fc23540e1..5c6a11dfd2 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -54,7 +54,9 @@ const urlParams = new URL(globalThis.location.href).searchParams; if( !urlParams.has('vfs') ){ throw new Error("Expecting vfs=opfs|opfs-wl URL argument for this worker"); } -const isWebLocker = 'opfs-wl'===urlParams.get('vfs'); +const workerId = urlParams.get('opfs-async-proxy-id') + ?? 'unnamed'; +const isWebLocker = true; //'opfs-wl'===urlParams.get('vfs'); const wPost = (type,...args)=>postMessage({type, payload:args}); const installAsyncProxy = function(){ const toss = function(...args){throw new Error(args.join(' '))}; @@ -70,6 +72,10 @@ const installAsyncProxy = function(){ this API. */ const state = Object.create(null); + + /* initS11n() is preprocessor-injected so that we have identical + copies in the synchronous and async halves. This side does not + load the SQLite library, so does not have access to that copy. */ //#define opfs-async-proxy //#include api/opfs-common-inline.c-pp.js //#undef opfs-async-proxy @@ -82,7 +88,7 @@ const installAsyncProxy = function(){ 2 = warnings and errors 3 = debug, warnings, and errors */ - state.verbose = 1; + state.verbose = 2; const loggers = { 0:console.error.bind(console), @@ -90,7 +96,7 @@ const installAsyncProxy = function(){ 2:console.log.bind(console) }; const logImpl = (level,...args)=>{ - if(state.verbose>level) loggers[level]("OPFS asyncer:",...args); + if(state.verbose>level) loggers[level]('opfs-async-proxy',workerId+":",...args); }; const log = (...args)=>logImpl(2, ...args); const warn = (...args)=>logImpl(1, ...args); @@ -297,13 +303,26 @@ const installAsyncProxy = function(){ there's another race condition there). That's easy to say but creating a viable test for that condition has proven challenging so far. + + 2026-03-06: + + - baseWaitTime is the number of milliseconds to wait for the + first retry, doubling for each retry. It defaults to + (state.asyncIdleWaitTime*2). + + - maxTries is the number of attempt to make, each one spaced out + by one additional factor of the baseWaitTime (e.g. 300, then 600, + then 900, the 1200...). This MUST be an integer >0 and defaults + to 6. + + Only the Web Locks impl should use the 3rd and 4th parameters. */ - const getSyncHandle = async (fh,opName)=>{ + const getSyncHandle = async (fh,opName, baseWaitTime, maxTries)=>{ if(!fh.syncHandle){ const t = performance.now(); log("Acquiring sync handle for",fh.filenameAbs); - const maxTries = 6, - msBase = state.asyncIdleWaitTime * 2; + const msBase = baseWaitTime ?? (state.asyncIdleWaitTime * 2); + maxTries ??= 6; let i = 1, ms = msBase; for(; true; ms = msBase * ++i){ try { @@ -337,6 +356,9 @@ const installAsyncProxy = function(){ /** Stores the given value at state.sabOPView[state.opIds.rc] and then Atomics.notify()'s it. + + The opName is only used for logging and debugging - all result + codes are expected on the same state.sabOPView slot. */ const storeAndNotify = (opName, value)=>{ log(opName+"() => notify(",value,")"); @@ -466,24 +488,12 @@ const installAsyncProxy = function(){ await releaseImplicitLock(fh); storeAndNotify('xFileSize', rc); }, - xLock: async function(fid/*sqlite3_file pointer*/, - lockType/*SQLITE_LOCK_...*/){ - const fh = __openFiles[fid]; - let rc = 0; - const oldLockType = fh.xLock; - fh.xLock = lockType; - if( !fh.syncHandle ){ - try { - await getSyncHandle(fh,'xLock'); - __implicitLocks.delete(fid); - }catch(e){ - state.s11n.storeException(1,e); - rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_LOCK); - fh.xLock = oldLockType; - } - } - storeAndNotify('xLock',rc); - }, + /** + The first argument is semantically invalid here - it's an + address in the synchronous side's heap. We can do nothing with + it here except use it as a unique-per-file identifier. + i.e. a lookup key. + */ xOpen: async function(fid/*sqlite3_file pointer*/, filename, flags/*SQLITE_OPEN_...*/, opfsFlags/*OPFS_...*/){ @@ -575,22 +585,6 @@ const installAsyncProxy = function(){ await releaseImplicitLock(fh); storeAndNotify('xTruncate',rc); }, - xUnlock: async function(fid/*sqlite3_file pointer*/, - lockType/*SQLITE_LOCK_...*/){ - let rc = 0; - const fh = __openFiles[fid]; - if( fh.syncHandle - && state.sq3Codes.SQLITE_LOCK_NONE===lockType - /* Note that we do not differentiate between lock types in - this VFS. We're either locked or unlocked. */ ){ - try { await closeSyncHandle(fh) } - catch(e){ - state.s11n.storeException(1,e); - rc = state.sq3Codes.SQLITE_IOERR_UNLOCK; - } - } - storeAndNotify('xUnlock',rc); - }, xWrite: async function(fid/*sqlite3_file pointer*/,n,offset64){ let rc; const fh = __openFiles[fid]; @@ -611,6 +605,187 @@ const installAsyncProxy = function(){ } }/*vfsAsyncImpls*/; + if( isWebLocker ){ + /* We require separate xLock() and xUnlock() implementations for the + original and Web Lock implementations. The ones in this block + are for the WebLock impl. */ + + /** Registry of active Web Locks: fid -> { mode, resolveRelease } */ + const __activeWebLocks = Object.create(null); + + vfsAsyncImpls.xLock = async function(fid/*sqlite3_file pointer*/, + lockType/*SQLITE_LOCK_...*/, + isFromUnlock/*only if called from this.xUnlock()*/){ + const whichOp = isFromUnlock ? 'xUnlock' : 'xLock'; + const fh = __openFiles[fid]; + const lockName = "sqlite3-vfs-opfs:" + fh.filenameAbs; + //error("xLock()",fid, lockType, isFromUnlock, fh); + const requestedMode = (lockType >= state.sq3Codes.SQLITE_LOCK_RESERVED) + ? 'exclusive' : 'shared'; + const existing = __activeWebLocks[fid]; + if( existing ){ + if( existing.mode === requestedMode + || (existing.mode === 'exclusive' + && requestedMode === 'shared') ) { + storeAndNotify(whichOp, 0); + existing.mode = requestedMode/* ??? */; + fh.lockType = lockType; + return 0 /* Already held at required or higher level */; + } + /* + Upgrade path: we must release shared and acquire exclusive. + This transition is NOT atomic in Web Locks API. + */ + if( 0 ){ + /* Except that it _effectively_ is atomic if we don't call + closeSyncHandle(fh), as no other worker can lock that + until we let it go. */ + await closeSyncHandle(fh); + } + existing.resolveRelease(); + delete __activeWebLocks[fid]; + } + + const oldLockType = fh.xLock; + let didNotify = false; + return new Promise((resolveWaitLoop) => { + //error("xLock() initial promise entered..."); + navigator.locks.request(lockName, { mode: requestedMode }, async (lock) => { + //error("xLock() Web Lock entered.", fh); + fh.xLock = lockType; + __implicitLocks.delete(fid); + if( 1 ){ + /* Make ONE attempt to get the handle, but with a + higher-than-default retry-wait time. */ + await getSyncHandle(fh, 'xLock', 1000, 5); + }else{ + /* Try to get a lock until either we get one or trying to + results in a "not found" error (see getSyncHandle() docs). */ + while( !fh.syncHandle ){ + try{ + await getSyncHandle(fh, 'xLock', 1000, 3); + }catch(e){ + const rc = GetSyncHandleError.convertRc(e, 0); + if( rc === state.sq3Codes.SQLITE_CANTOPEN ){ + /* File was deleted - see getSyncHandle() */ + throw e; + } + error("xLock() still waiting to unlock SyncAccessHandle",fh); + } + } + } + error("xLock() SAH acquired.", fh); + const releasePromise = new Promise((resolveRelease) => { + __activeWebLocks[fid] = { mode: requestedMode, resolveRelease }; + }); + didNotify = true; + storeAndNotify(whichOp, 0) /* Unblock the C side */; + resolveWaitLoop(0) /* Unblock waitLoop() */; + await releasePromise; // Hold the lock until xUnlock + }).catch(e=>{ + /** + We have(?) a potential deadlock situation: if the above + throws, we can't just blindly storeAndNotify() here to + unlock the C side, as it might interfere with an + unrelated operation. The `didNotify` check here assumes + that any exception which can be thrown will happen before + the above `didNotify=true`. e.g. getSyncHandle() can + throw. Apropos: we probably need to be able to configure + the async side with busy timeout values, and try until + that limit is reached, or tell it to wait indefinitely. + + Because waitLoop() is `await`ing on this Promise, we can + be sure that the following storeAndNotify() is not + crossing wires with a different operation. + */ + fh.xLock = oldLockType; + error("Exception acquiring Web Lock", e); + if( !didNotify ){ + state.s11n.storeException(1, e); + const rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_LOCK); + storeAndNotify(whichOp, rc); + } + throw e /* what else can we do? */; + }) + }); + }; + + vfsAsyncImpls.xUnlock = async function(fid/*sqlite3_file pointer*/, + lockType/*SQLITE_LOCK_...*/){ + const fh = __openFiles[fid]; + const existing = __activeWebLocks[fid]; + if( !existing ){ + await closeSyncHandle(fh); + storeAndNotify('xUnlock', 0); + return 0; + } + error("xUnlock()",fid, lockType, fh); + let rc = 0; + if( lockType === state.sq3Codes.SQLITE_LOCK_NONE ){ + /* SQLite usually unlocks all the way to NONE */ + existing.resolveRelease(); + delete __activeWebLocks[fid]; + try {await closeSyncHandle(fh)} + catch(e){ + state.s11n.storeException(1,e); + rc = state.sq3Codes.SQLITE_IOERR_UNLOCK; + } + }else if( lockType === state.sq3Codes.SQLITE_LOCK_SHARED + && existing.mode === 'exclusive' ){ + /* downgrade Exclusive -> Shared */ + existing.resolveRelease(); + delete __activeWebLocks[fid]; + return vfsAsyncImpls.xLock(fid, lockType, true); + }else{ + /* ??? */ + error("xUnlock() unhandled condition", fh); + } + storeAndNotify('xUnlock', rc); + if( 0===rc ) fh.lockType = lockType; + return 0; + } + + }else{ + + /* Original/"legacy" xLock() and xUnlock() */ + vfsAsyncImpls.xLock = async function(fid/*sqlite3_file pointer*/, + lockType/*SQLITE_LOCK_...*/){ + const fh = __openFiles[fid]; + let rc = 0; + const oldLockType = fh.xLock; + fh.xLock = lockType; + if( !fh.syncHandle ){ + try { + await getSyncHandle(fh,'xLock'); + __implicitLocks.delete(fid); + }catch(e){ + state.s11n.storeException(1,e); + rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_LOCK); + fh.xLock = oldLockType; + } + } + storeAndNotify('xLock',rc); + }; + + vfsAsyncImpls.xUnlock = async function(fid/*sqlite3_file pointer*/, + lockType/*SQLITE_LOCK_...*/){ + let rc = 0; + const fh = __openFiles[fid]; + if( fh.syncHandle + && state.sq3Codes.SQLITE_LOCK_NONE===lockType + /* Note that we do not differentiate between lock types in + this VFS. We're either locked or unlocked. */ ){ + try { await closeSyncHandle(fh) } + catch(e){ + state.s11n.storeException(1,e); + rc = state.sq3Codes.SQLITE_IOERR_UNLOCK; + } + } + storeAndNotify('xUnlock',rc); + } + + }/*xLock() and xUnlock() impls*/ + const waitLoop = async function f(){ if( !f.inited ){ f.inited = true; @@ -645,7 +820,7 @@ const installAsyncProxy = function(){ an exception string written by the upcoming operation */ ) || []; - //warn("waitLoop() whichOp =",opId, hnd, args); + //error("waitLoop() whichOp =",opId, f.opHandlers[opId].key, args); await hnd(...args); }catch(e){ error('in waitLoop():', e); @@ -656,7 +831,7 @@ const installAsyncProxy = function(){ navigator.storage.getDirectory().then(function(d){ state.rootDir = d; globalThis.onmessage = function({data}){ - warn(globalThis.location.href,"onmessage()",data); + //log(globalThis.location.href,"onmessage()",data); switch(data.type){ case 'opfs-async-init':{ /* Receive shared state from synchronous partner */ diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 89b52c836d..6d0988d6d7 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -86,43 +86,31 @@ const installOpfsVfs = async function callee(options){ const capi = sqlite3.capi, state = opfsUtil.createVfsState('opfs', options), opfsVfs = state.vfs, - metrics = opfsVfs.metrics.counters, mTimeStart = opfsVfs.mTimeStart, mTimeEnd = opfsVfs.mTimeEnd, opRun = opfsVfs.opRun, + debug = (...args)=>sqlite3.config.debug("opfs:",...args), __openFiles = opfsVfs.__openFiles; - /* At this point, createVfsState() has populated state and - opfsVfs with any code common to both the "opfs" and "opfs-wl" + //debug("options:",JSON.stringify(options)); + /* At this point, createVfsState() has populated `state` and + `opfsVfs` with any code common to both the "opfs" and "opfs-wl" VFSes. Now comes the VFS-dependent work... */ return opfsVfs.bindVfs(util.nu({ xLock: function(pFile,lockType){ mTimeStart('xLock'); - ++metrics.xLock.count; + debug("xLock()..."); const f = __openFiles[pFile]; - let rc = 0; - /* All OPFS locks are exclusive locks. If xLock() has - previously succeeded, do nothing except record the lock - type. If no lock is active, have the async counterpart - lock the file. */ - if( f.lockType ) { - f.lockType = lockType; - }else{ - rc = opRun('xLock', pFile, lockType); - if( 0===rc ) f.lockType = lockType; - } + const rc = opRun('xLock', pFile, lockType); + debug("xLock() rc ",rc); + if( 0===rc ) f.lockType = lockType; mTimeEnd(); return rc; }, xUnlock: function(pFile,lockType){ mTimeStart('xUnlock'); - ++metrics.xUnlock.count; const f = __openFiles[pFile]; - let rc = 0; - if( capi.SQLITE_LOCK_NONE === lockType - && f.lockType ){ - rc = opRun('xUnlock', pFile, lockType); - } + const rc = opRun('xUnlock', pFile, lockType); if( 0===rc ) f.lockType = lockType; mTimeEnd(); return rc; @@ -137,15 +125,17 @@ const installOpfsVfs = async function callee(options){ OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype); sqlite3.oo1.OpfsDb = OpfsDb; OpfsDb.importDb = opfsUtil.importDb; - sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback( - opfsVfs.pointer, - function(oo1Db, sqlite3){ - /* Set a relatively high default busy-timeout handler to - help OPFS dbs deal with multi-tab/multi-worker - contention. */ - sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000); - } - ); + if( false ){ + sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback( + opfsVfs.pointer, + function(oo1Db, sqlite3){ + /* Set a relatively high default busy-timeout handler to + help OPFS dbs deal with multi-tab/multi-worker + contention. */ + sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000); + } + ); + } }/*extend sqlite3.oo1*/ })/*bindVfs()*/; }/*installOpfsVfs()*/; diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 083b5eca44..8c0ba19165 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -129,17 +129,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule; }; } } - const reportFinalTestStatus = function(pass){ - if(isUIThread()){ - let e = document.querySelector('#color-target'); - e.classList.add(pass ? 'tests-pass' : 'tests-fail'); - e = document.querySelector('title'); - e.innerText = (pass ? 'PASS' : 'FAIL') + ': ' + e.innerText; - }else{ - postMessage({type:'test-result', payload:{pass}}); - } - TestUtil.checkHeapSize(true); - }; const log = (...args)=>{ //console.log(...args); logClass('',...args); @@ -157,6 +146,19 @@ globalThis.sqlite3InitModule = sqlite3InitModule; console.debug('tester1',...args); }; + const reportFinalTestStatus = function(pass){ + debug("Final test status:",pass); + if(isUIThread()){ + let e = document.querySelector('#color-target'); + e.classList.add(pass ? 'tests-pass' : 'tests-fail'); + e = document.querySelector('title'); + e.innerText = (pass ? 'PASS' : 'FAIL') + ': ' + e.innerText; + }else{ + postMessage({type:'test-result', payload:{pass}}); + } + TestUtil.checkHeapSize(true); + }; + const toss = (...args)=>{ error(...args); throw new Error(args.join(' ')); diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index 77e320e9af..365900c2d5 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -1,15 +1,17 @@ -importScripts( - (new URL(globalThis.location.href).searchParams).get('sqlite3.dir') + '/sqlite3.js' -); -//const sqlite3InitModule = (await import("../../../jswasm/sqlite3.mjs", )).default; +'use strict'; +const urlArgs = new URL(globalThis.location.href).searchParams; +const options = { + workerName: urlArgs.get('workerId') || Math.round(Math.random()*10000), + unlockAsap: urlArgs.get('opfs-unlock-asap') || 0, + vfs: urlArgs.get('vfs') +}; +const jsSqlite = urlArgs.get('sqlite3.dir') + +'/sqlite3.js?opfs-async-proxy-id=' + +options.workerName; +importScripts(jsSqlite)/*Sigh - URL args are not propagated this way*/; +//const sqlite3InitModule = (await import(jsSqlite)).default; globalThis.sqlite3InitModule.__isUnderTest = true; globalThis.sqlite3InitModule().then(async function(sqlite3){ - const urlArgs = new URL(globalThis.location.href).searchParams; - const options = { - workerName: urlArgs.get('workerId') || Math.round(Math.random()*10000), - unlockAsap: urlArgs.get('opfs-unlock-asap') || 0 /*EXPERIMENTAL*/, - vfs: urlArgs.get('vfs') - }; const wPost = (type,...payload)=>{ postMessage({type, worker: options.workerName, payload}); }; @@ -41,7 +43,9 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ db.close(); } if(interval.error){ - wPost('failed',"Ending work after interval #"+interval.count, + stderr("Ending work at interval #"+interval.count, + "due to error:", interval.error); + wPost('failed', "at interval #"+interval.count, "due to error:",interval.error); }else{ wPost('finished',"Ending work after",interval.count,"intervals."); diff --git a/manifest b/manifest index 94e2e47dac..78515cb419 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sextraneous\sOPFS\smetrics\sincrement. -D 2026-03-06T11:49:36.430 +C This\sWeb\sLock\simpl\scan\sreliably\srun\sa\ssingle\sOPFS\sconnection\sbut\srather\sunreliably\s'loses'\sworkers\swith\shigher\scounts,\spresumably\sdue\sto\sdeadlock\sor\sdeadly\sembrace\s(how\s_all_\sof\sthem\scan\sdeadlock\sat\sonce\sis\sunclear,\sbut\sclearly\sa\sbug). +D 2026-03-06T16:04:21.050 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js ecc3c69dc8a3b676f6999ef1b2ac4be825b7952ce5acbe86941f4f2f38607cb7 +F ext/wasm/api/opfs-common-shared.c-pp.js 7bfbf3a5ce1b558ec3d0b3e14f375e9f6003b6bb49c58480e2fbf2726cf59b2c F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -594,12 +594,12 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 5f95c210183d203c7bc5be4a8139cc7fa2e50810c306bb2651648c32ab419fcf +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js f471178310dd8c27f46aaa3bb2bdfb8e0b695b37a54b9a9c66b820e413b55f68 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 8233c5f9021b0213134e2adbaf6036b8f1dffd4747083a4087c1c19ae107f962 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js f3b7296480984bcc6050fe9724a8b215c405977dd69daea7145ece25751e4b33 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 3fde62ac67c963ee04030cf279357bb19b98a420973f55245c44396828b582d6 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -644,10 +644,10 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c986e48af7d3d720fcd244 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb -F ext/wasm/tester1.c-pp.js 6b946cd6d4da130dbae4a401057716d27117ca02cad2ea8c29ae9c46c675d618 +F ext/wasm/tester1.c-pp.js a4e79fbf63bb3255d2b8ffc1cd538c115d2f6b599bc324904c80f6644379a284 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e F ext/wasm/tests/opfs/concurrency/test.js 74f4ef9a827d081e6bb0ffb1d124bb54015dab8f7ae47abd5b5f26d71633331a -F ext/wasm/tests/opfs/concurrency/worker.js 3425e6dad755a1c69a6efc63a47a3ade4e7f0a9a138994ba37f996571fb46288 +F ext/wasm/tests/opfs/concurrency/worker.js d0303b1403867e97455f7563285af3eb4471961b19bc22e45d021d896d48e27c F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 521bb140b7ed237c118ac9094732d06907229a6ff385502e850c679bd623fd58 -R 334abfd624b27a29d02bb7116f94ced4 +P bf3548a37712e848c7a9cadfdc1669a2be572ea0a0c28d84c157ab30f8c30c44 +R aeb14d0bd734de11301263e4e120c1e3 U stephan -Z 944b558939ff5f7ba7e037ff2a332b5b +Z c3b8772f8a9f1db66a44dbdb2829ac29 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 48801140c5..17f5b7a2ef 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bf3548a37712e848c7a9cadfdc1669a2be572ea0a0c28d84c157ab30f8c30c44 +d4e8583e2e80665adfe4e814adb6c219936af1dcac4105795045cb1a7b1e4864 From c008b8fe3ee8bd06ca8f17cf45052566fa669ca2 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 16:15:32 +0000 Subject: [PATCH 113/197] Correct an internal doc falsehood. FossilOrigin-Name: 53aa080e357d7a2ffeab68a3584fda43d51ecef3dc8a1d46dd32392ae4f9740c --- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 4 ++-- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 5c6a11dfd2..89b1339a9e 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -307,8 +307,8 @@ const installAsyncProxy = function(){ 2026-03-06: - baseWaitTime is the number of milliseconds to wait for the - first retry, doubling for each retry. It defaults to - (state.asyncIdleWaitTime*2). + first retry, increasing by one factor for each retry. It defaults + to (state.asyncIdleWaitTime*2). - maxTries is the number of attempt to make, each one spaced out by one additional factor of the baseWaitTime (e.g. 300, then 600, diff --git a/manifest b/manifest index 78515cb419..b868981442 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C This\sWeb\sLock\simpl\scan\sreliably\srun\sa\ssingle\sOPFS\sconnection\sbut\srather\sunreliably\s'loses'\sworkers\swith\shigher\scounts,\spresumably\sdue\sto\sdeadlock\sor\sdeadly\sembrace\s(how\s_all_\sof\sthem\scan\sdeadlock\sat\sonce\sis\sunclear,\sbut\sclearly\sa\sbug). -D 2026-03-06T16:04:21.050 +C Correct\san\sinternal\sdoc\sfalsehood. +D 2026-03-06T16:15:32.423 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -594,7 +594,7 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js f471178310dd8c27f46aaa3bb2bdfb8e0b695b37a54b9a9c66b820e413b55f68 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js fd41c554fa0f25770841f4973eeaeda78db5fd9c24b2cbe7c62ce43bfae89840 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P bf3548a37712e848c7a9cadfdc1669a2be572ea0a0c28d84c157ab30f8c30c44 -R aeb14d0bd734de11301263e4e120c1e3 +P d4e8583e2e80665adfe4e814adb6c219936af1dcac4105795045cb1a7b1e4864 +R 88b88687281dda4abda2f12f0e145b46 U stephan -Z c3b8772f8a9f1db66a44dbdb2829ac29 +Z de5c6fc88fd27ce91eec8f28640e7eb1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 17f5b7a2ef..0a3bf6f088 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d4e8583e2e80665adfe4e814adb6c219936af1dcac4105795045cb1a7b1e4864 +53aa080e357d7a2ffeab68a3584fda43d51ecef3dc8a1d46dd32392ae4f9740c From a98f278f581c1cf7517fed71370e102f97c019a6 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 17:10:28 +0000 Subject: [PATCH 114/197] This one reliably runs 5 workers. Checking in before subsequent cleanups and debug output removal break it. FossilOrigin-Name: ba81d95febc5fd0f9bbb2685fef5b1b10f9991751f2bdfafba80c15877af1cef --- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 109 +++++++----------- manifest | 12 +- manifest.uuid | 2 +- 3 files changed, 50 insertions(+), 73 deletions(-) diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 89b1339a9e..e2b48bff57 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -629,17 +629,18 @@ const installAsyncProxy = function(){ && requestedMode === 'shared') ) { storeAndNotify(whichOp, 0); existing.mode = requestedMode/* ??? */; - fh.lockType = lockType; + fh.xLock = lockType; return 0 /* Already held at required or higher level */; } /* Upgrade path: we must release shared and acquire exclusive. This transition is NOT atomic in Web Locks API. */ - if( 0 ){ + if( 1 ){ /* Except that it _effectively_ is atomic if we don't call closeSyncHandle(fh), as no other worker can lock that - until we let it go. */ + until we let it go. But we can't do that without leading + to a deadly embrace, so... */ await closeSyncHandle(fh); } existing.resolveRelease(); @@ -647,101 +648,77 @@ const installAsyncProxy = function(){ } const oldLockType = fh.xLock; - let didNotify = false; return new Promise((resolveWaitLoop) => { //error("xLock() initial promise entered..."); navigator.locks.request(lockName, { mode: requestedMode }, async (lock) => { //error("xLock() Web Lock entered.", fh); - fh.xLock = lockType; + fh.xLock = lockType/*must be set before getSyncHandle() is called*/; __implicitLocks.delete(fid); - if( 1 ){ + let rc = 0; + try{ /* Make ONE attempt to get the handle, but with a - higher-than-default retry-wait time. */ - await getSyncHandle(fh, 'xLock', 1000, 5); - }else{ - /* Try to get a lock until either we get one or trying to - results in a "not found" error (see getSyncHandle() docs). */ - while( !fh.syncHandle ){ - try{ - await getSyncHandle(fh, 'xLock', 1000, 3); - }catch(e){ - const rc = GetSyncHandleError.convertRc(e, 0); - if( rc === state.sq3Codes.SQLITE_CANTOPEN ){ - /* File was deleted - see getSyncHandle() */ - throw e; - } - error("xLock() still waiting to unlock SyncAccessHandle",fh); - } - } + higher-than-default retry-wait. */ + await getSyncHandle(fh, 'xLock', 317, 5); + }catch(e){ + fh.xLock = oldLockType; + state.s11n.storeException(1, e); + rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_BUSY); } - error("xLock() SAH acquired.", fh); - const releasePromise = new Promise((resolveRelease) => { - __activeWebLocks[fid] = { mode: requestedMode, resolveRelease }; - }); - didNotify = true; - storeAndNotify(whichOp, 0) /* Unblock the C side */; + const releasePromise = rc + ? undefined + : new Promise((resolveRelease) => { + __activeWebLocks[fid] = { mode: requestedMode, resolveRelease }; + }); + storeAndNotify(whichOp, rc) /* Unblock the C side */; resolveWaitLoop(0) /* Unblock waitLoop() */; await releasePromise; // Hold the lock until xUnlock - }).catch(e=>{ - /** - We have(?) a potential deadlock situation: if the above - throws, we can't just blindly storeAndNotify() here to - unlock the C side, as it might interfere with an - unrelated operation. The `didNotify` check here assumes - that any exception which can be thrown will happen before - the above `didNotify=true`. e.g. getSyncHandle() can - throw. Apropos: we probably need to be able to configure - the async side with busy timeout values, and try until - that limit is reached, or tell it to wait indefinitely. - - Because waitLoop() is `await`ing on this Promise, we can - be sure that the following storeAndNotify() is not - crossing wires with a different operation. - */ - fh.xLock = oldLockType; - error("Exception acquiring Web Lock", e); - if( !didNotify ){ - state.s11n.storeException(1, e); - const rc = GetSyncHandleError.convertRc(e, state.sq3Codes.SQLITE_IOERR_LOCK); - storeAndNotify(whichOp, rc); - } - throw e /* what else can we do? */; - }) + }); }); }; + const wlCloseHandle = async(fh)=>{ + let rc = 0; + try{ + await closeSyncHandle(fh); + }catch(e){ + state.s11n.storeException(1,e); + rc = state.sq3Codes.SQLITE_IOERR_UNLOCK; + } + return rc; + }; + vfsAsyncImpls.xUnlock = async function(fid/*sqlite3_file pointer*/, lockType/*SQLITE_LOCK_...*/){ const fh = __openFiles[fid]; const existing = __activeWebLocks[fid]; if( !existing ){ - await closeSyncHandle(fh); - storeAndNotify('xUnlock', 0); - return 0; + const rc = await wlCloseHandle(fh); + storeAndNotify('xUnlock', rc); + return rc; } error("xUnlock()",fid, lockType, fh); let rc = 0; if( lockType === state.sq3Codes.SQLITE_LOCK_NONE ){ /* SQLite usually unlocks all the way to NONE */ + rc = await wlCloseHandle(fh); existing.resolveRelease(); delete __activeWebLocks[fid]; - try {await closeSyncHandle(fh)} - catch(e){ - state.s11n.storeException(1,e); - rc = state.sq3Codes.SQLITE_IOERR_UNLOCK; - } + fh.xLock = lockType; }else if( lockType === state.sq3Codes.SQLITE_LOCK_SHARED && existing.mode === 'exclusive' ){ /* downgrade Exclusive -> Shared */ - existing.resolveRelease(); - delete __activeWebLocks[fid]; - return vfsAsyncImpls.xLock(fid, lockType, true); + rc = await wlCloseHandle(fh); + if( 0===rc ){ + fh.xLock = lockType; + existing.resolveRelease(); + delete __activeWebLocks[fid]; + return vfsAsyncImpls.xLock(fid, lockType, true); + } }else{ /* ??? */ error("xUnlock() unhandled condition", fh); } storeAndNotify('xUnlock', rc); - if( 0===rc ) fh.lockType = lockType; return 0; } diff --git a/manifest b/manifest index b868981442..d85a70c591 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Correct\san\sinternal\sdoc\sfalsehood. -D 2026-03-06T16:15:32.423 +C This\sone\sreliably\sruns\s5\sworkers.\sChecking\sin\sbefore\ssubsequent\scleanups\sand\sdebug\soutput\sremoval\sbreak\sit. +D 2026-03-06T17:10:28.455 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -594,7 +594,7 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js fd41c554fa0f25770841f4973eeaeda78db5fd9c24b2cbe7c62ce43bfae89840 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b3235922c15ee9b92a5424e34580bf16cb971adf23559c9e7119d563b8da2fe9 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d4e8583e2e80665adfe4e814adb6c219936af1dcac4105795045cb1a7b1e4864 -R 88b88687281dda4abda2f12f0e145b46 +P 53aa080e357d7a2ffeab68a3584fda43d51ecef3dc8a1d46dd32392ae4f9740c +R fcfb0bfb06d58bd7f0d57908763a15cf U stephan -Z de5c6fc88fd27ce91eec8f28640e7eb1 +Z 62318d6c194878a798365e388df66b6b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0a3bf6f088..fc702daf45 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -53aa080e357d7a2ffeab68a3584fda43d51ecef3dc8a1d46dd32392ae4f9740c +ba81d95febc5fd0f9bbb2685fef5b1b10f9991751f2bdfafba80c15877af1cef From 88e552f1b9213bdada82ee787be01b63cc49ed8a Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 6 Mar 2026 18:26:50 +0000 Subject: [PATCH 115/197] Fix the linenoise auto-detection added by the previous check-in. FossilOrigin-Name: e36958584511d83666590abef223c2edc3da15b5b32e280baf08159ddae80e50 --- autosetup/sqlite-config.tcl | 2 +- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/autosetup/sqlite-config.tcl b/autosetup/sqlite-config.tcl index 3c8be3797c..04ef10f0b0 100644 --- a/autosetup/sqlite-config.tcl +++ b/autosetup/sqlite-config.tcl @@ -1195,7 +1195,7 @@ proc sqlite-check-line-editing {} { define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE] user-notice "Adding linenoise support to jimsh." } else { - user-notice "Using linenoise at [file normalize $dirLn]" + msg-result "Using linenoise at [file normalize $dirLn]" } return "linenoise ($flavor)" } elseif {[opt-bool editline]} { diff --git a/manifest b/manifest index 0ad71e084b..a4b4b6d5cf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\s./configure\sto\sautomatically\sdetect\slinenoise\sin\s../linenoise\nrelative\sto\sthe\sbuild\sdirectory,\sor\s../linenoise\srelative\sto\sthe\ssource\ndirectory,\sor\sat\s$HOME/linenoise. -D 2026-03-05T18:16:25.845 +C Fix\sthe\slinenoise\sauto-detection\sadded\sby\sthe\sprevious\scheck-in. +D 2026-03-06T18:26:50.758 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -47,7 +47,7 @@ F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1 F autosetup/jimsh0.c 916bbdf8023fbda9937afae57d81a853d8c2ea00f2320aa27becbc33574f963d F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba F autosetup/proj.tcl ce301197f364f7ce2acabbbd84b43d19e917ec73653157ca134a06f32d322712 -F autosetup/sqlite-config.tcl d7f456247e25592c7e47266da4bcd1d5d22268cfc901da826682b1043dd8e212 +F autosetup/sqlite-config.tcl b215e97ad734f148069da3efd57ac8b2b2b893e6f08d20dd1eceff1e8b95313d F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9 F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca F autosetup/teaish/core.tcl e014dd95900c7f9a34e8e0f460f47e94841059827bce8b4c49668b0c7ae3f1a0 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f43294a5582b540a33c584ec8c69b6a5006a4d243ad5cf36125b2b0806e3518b -R 347a8275875a278d651ac2f82cbca624 +P eb6b47c667e52d5c8682d650dbd114c08d2ecce4bb7bce6fdf2589d1ea09f5c0 +R 0cadac181c83be746400699057062f7a U drh -Z e79345a4344873cde92cb59e7eccc257 +Z 81cdf0136c0c9317b6d002766c42b636 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4cdb395950..a5ea5a31c4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eb6b47c667e52d5c8682d650dbd114c08d2ecce4bb7bce6fdf2589d1ea09f5c0 +e36958584511d83666590abef223c2edc3da15b5b32e280baf08159ddae80e50 From a85d09f1a47854b5279868bc8cfa79ec90241315 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 19:33:25 +0000 Subject: [PATCH 116/197] Minor cleanups and docs. Teach the OPFS concurrency tester to deal with SQLITE_BUSY instead of failing. FossilOrigin-Name: 247ffed141f66a6a5a396a3e002995a9f00c70333271199200530066e77956c4 --- ext/wasm/api/opfs-common-shared.c-pp.js | 98 +++++++++---------- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 50 ++++++---- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 10 +- ext/wasm/tests/opfs/concurrency/worker.js | 62 ++++++++---- manifest | 18 ++-- manifest.uuid | 2 +- 6 files changed, 138 insertions(+), 102 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 2020184173..734b211c09 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -588,7 +588,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ of this value is also used for determining how long to wait on lock contention to free up. */ - state.asyncIdleWaitTime = isWebLocker ? 150 : 150; + state.asyncIdleWaitTime = isWebLocker ? 250 : 150; /** Whether the async counterpart should log exceptions to @@ -599,7 +599,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 0 = no exception logging. 1 = only log exceptions for "significant" ops like xOpen(), - xRead(), and xWrite(). + xRead(), and xWrite(). Exceptions related to, e.g., wait/retry + loops in acquiring SyncAccessHandles are not logged. 2 = log all exceptions. */ @@ -636,29 +637,20 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ */ state.opIds = Object.create(null); { - /* - Maintenance reminder: - - Some of these fields are only for use by the "opfs-wl" VFS, - but they must also be set up for the "ofps" VFS so that the - sizes and offsets calculated here are consistent in the async - proxy. Hypothetically they could differ and it would cope - but... why invite disaster over eliding a few superfluous (for - "opfs') properties? - */ /* Indexes for use in our SharedArrayBuffer... */ let i = 0; /* SAB slot used to communicate which operation is desired between both workers. This worker writes to it and the other - listens for changes. */ + listens for changes and clears it. The values written to it + are state.opIds.x[A-Z][a-z]+, defined below.*/ state.opIds.whichOp = i++; - /* Slot for storing return values. This worker listens to that - slot and the other worker writes to it. */ + /* Slot for storing return values. This side listens to that + slot and the async proxy writes to it. */ state.opIds.rc = i++; - /* Each function gets an ID which this worker writes to - the whichOp slot. The async-api worker uses Atomic.wait() - on the whichOp slot to figure out which operation to run - next. */ + /* Each function gets an ID which this worker writes to the + state.opIds.whichOp slot. The async-api worker uses + Atomic.wait() on the whichOp slot to figure out which + operation to run next. */ state.opIds.xAccess = i++; state.opIds.xClose = i++; state.opIds.xDelete = i++; @@ -672,25 +664,28 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ state.opIds.xTruncate = i++; state.opIds.xUnlock = i++; state.opIds.xWrite = i++; - state.opIds.mkdir = i++; + state.opIds.mkdir = i++ /*currently unused*/; /** Internal signals which are used only during development and testing via the dev console. */ state.opIds['opfs-async-metrics'] = i++; state.opIds['opfs-async-shutdown'] = i++; /* The retry slot is used by the async part for wait-and-retry - semantics. Though we could hypothetically use the xSleep slot - for that, doing so might lead to undesired side effects. */ + semantics. It is never written to, only used as a convenient + place to wait-with-timeout for a value which will never be + written, i.e. sleep()ing, before retrying a failed attempt to + acquire a SharedAccessHandle. */ state.opIds.retry = i++; state.sabOP = new SharedArrayBuffer( - i * 4/* ==sizeof int32, noting that Atomics.wait() and friends - can only function on Int32Array views of an SAB. */); + i * 4/* 4==sizeof int32, noting that Atomics.wait() and + friends can only function on Int32Array views of an + SAB. */); } /** SQLITE_xxx constants to export to the async worker counterpart... */ state.sq3Codes = Object.create(null); - [ + for(const k of [ 'SQLITE_ACCESS_EXISTS', 'SQLITE_ACCESS_READWRITE', 'SQLITE_BUSY', @@ -724,17 +719,16 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'SQLITE_LOCK_RESERVED', 'SQLITE_LOCK_PENDING', 'SQLITE_LOCK_EXCLUSIVE' - ].forEach((k)=>{ - if(undefined === (state.sq3Codes[k] = capi[k])){ - toss("Maintenance required: not found:",k); - } - }); + ]){ + state.sq3Codes[k] = + capi[k] ?? toss("Maintenance required: not found:",k); + } state.opfsFlags = Object.assign(Object.create(null),{ /** Flag for use with xOpen(). URI flag "opfs-unlock-asap=1" enables this. See defaultUnlockAsap, below. - */ + */ OPFS_UNLOCK_ASAP: 0x01, /** Flag for use with xOpen(). URI flag "delete-before-open=1" @@ -747,33 +741,34 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ downstream errors. An unlink can fail if, e.g., another tab has the handle open. - It goes without saying that deleting a file out from under another - instance results in Undefined Behavior. + It goes without saying that deleting a file out from under + another instance results in Undefined Behavior. */ OPFS_UNLINK_BEFORE_OPEN: 0x02, /** - If true, any async routine which implicitly acquires a sync - access handle (i.e. an OPFS lock) will release that lock at - the end of the call which acquires it. If false, such - "autolocks" are not released until the VFS is idle for some - brief amount of time. - - The benefit of enabling this is much higher concurrency. The - down-side is much-reduced performance (as much as a 4x decrease - in speedtest1). + If true, any async routine which must implicitly acquire a + sync access handle (i.e. an OPFS lock), without an active + xLock(), will release that lock at the end of the call which + acquires it. If false, such implicit locks are not released + until the VFS is idle for some brief amount of time, as + defined by state.asyncIdleWaitTime. + + The benefit of enabling this is higher concurrency. The + down-side is much-reduced performance (as much as a 4x + decrease in speedtest1). */ defaultUnlockAsap: false }); - opfsVfs.metrics.reset(); + opfsVfs.metrics.reset()/*must not be called until state.opIds is set up*/; const metrics = opfsVfs.metrics.counters; /** Runs the given operation (by name) in the async worker counterpart, waits for its response, and returns the result - which the async worker writes to SAB[state.opIds.rc]. The - 2nd and subsequent arguments must be the arguments for the - async op. + which the async worker writes to SAB[state.opIds.rc]. The 2nd + and subsequent arguments must be the arguments for the async op + (see sqlite3-opfs-async-proxy.c-pp.js). */ const opRun = opfsVfs.opRun = (op,...args)=>{ const opNdx = state.opIds[op] || toss("Invalid op ID:",op); @@ -791,14 +786,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ https://github.com/sqlite/sqlite-wasm/issues/12 Summary: in at least one browser flavor, under high loads, - the wait()/notify() pairings can get out of sync. Calling - wait() here until it returns 'not-equal' gets them back in - sync. + the wait()/notify() pairings can get out of sync and/or + spuriously wake up. Calling wait() here until it returns + 'not-equal' gets them back in sync. */ } /* When the above wait() call returns 'not-equal', the async - half will have completed the operation and reported its results - in the state.opIds.rc slot of the SAB. */ + half will have completed the operation and reported its + results in the state.opIds.rc slot of the SAB. It may have + also serialized an exception for us. */ const rc = Atomics.load(state.sabOPView, state.opIds.rc); metrics[op].wait += performance.now() - t; if(rc && state.asyncS11nExceptions){ diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index e2b48bff57..e83cdf416d 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -618,7 +618,6 @@ const installAsyncProxy = function(){ isFromUnlock/*only if called from this.xUnlock()*/){ const whichOp = isFromUnlock ? 'xUnlock' : 'xLock'; const fh = __openFiles[fid]; - const lockName = "sqlite3-vfs-opfs:" + fh.filenameAbs; //error("xLock()",fid, lockType, isFromUnlock, fh); const requestedMode = (lockType >= state.sq3Codes.SQLITE_LOCK_RESERVED) ? 'exclusive' : 'shared'; @@ -627,38 +626,48 @@ const installAsyncProxy = function(){ if( existing.mode === requestedMode || (existing.mode === 'exclusive' && requestedMode === 'shared') ) { - storeAndNotify(whichOp, 0); - existing.mode = requestedMode/* ??? */; fh.xLock = lockType; + storeAndNotify(whichOp, 0); + /* Don't do this: existing.mode = requestedMode; + + Paraphrased from advice given by a consultanting + developer: + + If you hold an exclusive lock and SQLite requests shared, + you should keep exiting.mode as exclusive in because the + underlying Web Lock is still exclusive. Changing it to + shared would trick xLock into thinking it needs to + perform a release/re-acquire dance if an exclusive is + later requested. + */ return 0 /* Already held at required or higher level */; } /* Upgrade path: we must release shared and acquire exclusive. This transition is NOT atomic in Web Locks API. + + Except that it _effectively_ is atomic if we don't call + closeSyncHandle(fh), as no other worker can lock that + until we let it go. But we can't do that without leading + to a deadly embrace, so... */ - if( 1 ){ - /* Except that it _effectively_ is atomic if we don't call - closeSyncHandle(fh), as no other worker can lock that - until we let it go. But we can't do that without leading - to a deadly embrace, so... */ - await closeSyncHandle(fh); - } + await closeSyncHandle(fh); existing.resolveRelease(); delete __activeWebLocks[fid]; } + const lockName = "sqlite3-vfs-opfs:" + fh.filenameAbs; const oldLockType = fh.xLock; return new Promise((resolveWaitLoop) => { //error("xLock() initial promise entered..."); navigator.locks.request(lockName, { mode: requestedMode }, async (lock) => { //error("xLock() Web Lock entered.", fh); - fh.xLock = lockType/*must be set before getSyncHandle() is called*/; + fh.xLock = lockType/*must be set before getSyncHandle() is called!*/; __implicitLocks.delete(fid); let rc = 0; try{ - /* Make ONE attempt to get the handle, but with a - higher-than-default retry-wait. */ - await getSyncHandle(fh, 'xLock', 317, 5); + /* Make only one attempt to get the handle. */ + await getSyncHandle(fh, 'xLock'); }catch(e){ fh.xLock = oldLockType; state.s11n.storeException(1, e); @@ -669,16 +678,19 @@ const installAsyncProxy = function(){ : new Promise((resolveRelease) => { __activeWebLocks[fid] = { mode: requestedMode, resolveRelease }; }); - storeAndNotify(whichOp, rc) /* Unblock the C side */; - resolveWaitLoop(0) /* Unblock waitLoop() */; - await releasePromise; // Hold the lock until xUnlock + storeAndNotify(whichOp, rc) /* unblock the C side */; + resolveWaitLoop(0) /* unblock waitLoop() */; + await releasePromise /* hold the lock until xUnlock */; }); }); }; + /** Internal helper for the opfs-wl xUnlock() */ const wlCloseHandle = async(fh)=>{ let rc = 0; try{ + /* For the record, we've never once seen closeSyncHandle() + throw, nor should it because destructors do not throw. */ await closeSyncHandle(fh); }catch(e){ state.s11n.storeException(1,e); @@ -696,7 +708,7 @@ const installAsyncProxy = function(){ storeAndNotify('xUnlock', rc); return rc; } - error("xUnlock()",fid, lockType, fh); + //error("xUnlock()",fid, lockType, fh); let rc = 0; if( lockType === state.sq3Codes.SQLITE_LOCK_NONE ){ /* SQLite usually unlocks all the way to NONE */ @@ -723,8 +735,8 @@ const installAsyncProxy = function(){ } }else{ - /* Original/"legacy" xLock() and xUnlock() */ + vfsAsyncImpls.xLock = async function(fid/*sqlite3_file pointer*/, lockType/*SQLITE_LOCK_...*/){ const fh = __openFiles[fid]; diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 6d0988d6d7..ebe74e38b6 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -90,6 +90,7 @@ const installOpfsVfs = async function callee(options){ mTimeEnd = opfsVfs.mTimeEnd, opRun = opfsVfs.opRun, debug = (...args)=>sqlite3.config.debug("opfs:",...args), + warn = (...args)=>sqlite3.config.warn("opfs:",...args), __openFiles = opfsVfs.__openFiles; //debug("options:",JSON.stringify(options)); @@ -99,11 +100,14 @@ const installOpfsVfs = async function callee(options){ return opfsVfs.bindVfs(util.nu({ xLock: function(pFile,lockType){ mTimeStart('xLock'); - debug("xLock()..."); + //debug("xLock()..."); const f = __openFiles[pFile]; const rc = opRun('xLock', pFile, lockType); - debug("xLock() rc ",rc); - if( 0===rc ) f.lockType = lockType; + if( rc ){ + warn("xLock() rc ",rc); + }else{ + f.lockType = lockType; + } mTimeEnd(); return rc; }, diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index 365900c2d5..0f9c9b68cb 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -61,17 +61,31 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ stderr("Invalid VFS name:",vfs); return; } - db = new ctor({ - filename: 'file:'+dbName+'?opfs-unlock-asap='+options.unlockAsap, - flags: 'c' - }); - sqlite3.capi.sqlite3_busy_timeout(db.pointer, 5000); - db.transaction((db)=>{ - db.exec([ - "create table if not exists t1(w TEXT UNIQUE ON CONFLICT REPLACE,v);", - "create table if not exists t2(w TEXT UNIQUE ON CONFLICT REPLACE,v);" - ]); - }); + while(true){ + try{ + if( !db ){ + db = new ctor({ + filename: 'file:'+dbName+'?opfs-unlock-asap='+options.unlockAsap, + flags: 'c' + }); + sqlite3.capi.sqlite3_busy_timeout(db.pointer, 15000); + } + db.transaction((db)=>{ + db.exec([ + "create table if not exists t1(w TEXT UNIQUE ON CONFLICT REPLACE,v);", + "create table if not exists t2(w TEXT UNIQUE ON CONFLICT REPLACE,v);" + ]); + }); + break; + }catch(e){ + if(e instanceof sqlite3.SQLite3Error + && sqlite3.capi.SQLITE_BUSY===e.resultCode){ + stderr("Retrying for BUSY: ",e.message); + continue; + } + throw e; + } + } const maxIterations = urlArgs.has('iterations') ? (+urlArgs.get('iterations') || 10) : 10; @@ -81,14 +95,24 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ ++interval.count; const prefix = "v(#"+interval.count+")"; stdout("Setting",prefix,"=",tm); - try{ - db.exec({ - sql:"INSERT OR REPLACE INTO t1(w,v) VALUES(?,?)", - bind: [options.workerName, new Date().getTime()] - }); - //stdout("Set",prefix); - }catch(e){ - interval.error = e; + while(true){ + try{ + db.exec({ + sql:"INSERT OR REPLACE INTO t1(w,v) VALUES(?,?)", + bind: [options.workerName, new Date().getTime()] + }); + //stdout("Set",prefix); + break; + }catch(e){ + if(e instanceof sqlite3.SQLite3Error + && sqlite3.capi.SQLITE_BUSY===e.resultCode){ + stderr("Retrying for BUSY: ",e.message); + continue; + } + stderr("Error: ",e.message); + interval.error = e; + throw e; + } } //stdout("doWork()",prefix,"error ",interval.error); }; diff --git a/manifest b/manifest index d85a70c591..0974a04f21 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C This\sone\sreliably\sruns\s5\sworkers.\sChecking\sin\sbefore\ssubsequent\scleanups\sand\sdebug\soutput\sremoval\sbreak\sit. -D 2026-03-06T17:10:28.455 +C Minor\scleanups\sand\sdocs.\sTeach\sthe\sOPFS\sconcurrency\stester\sto\sdeal\swith\sSQLITE_BUSY\sinstead\sof\sfailing. +D 2026-03-06T19:33:25.647 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js 7bfbf3a5ce1b558ec3d0b3e14f375e9f6003b6bb49c58480e2fbf2726cf59b2c +F ext/wasm/api/opfs-common-shared.c-pp.js eccb37a2347b8b17a664401cd8ef0ee0a7e18cb81939ee4ef404905e8e9188bf F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -594,12 +594,12 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b3235922c15ee9b92a5424e34580bf16cb971adf23559c9e7119d563b8da2fe9 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js c19ca5986bceb60561973635bd68acbb93f5e1752b1d1b7f4cae20abaa8d5bd1 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 8233c5f9021b0213134e2adbaf6036b8f1dffd4747083a4087c1c19ae107f962 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 3fde62ac67c963ee04030cf279357bb19b98a420973f55245c44396828b582d6 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js f3bef4dbb8364a37471e4bc33e9b1e52795596456090007aaeae25acc35d2e85 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -647,7 +647,7 @@ F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3 F ext/wasm/tester1.c-pp.js a4e79fbf63bb3255d2b8ffc1cd538c115d2f6b599bc324904c80f6644379a284 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e F ext/wasm/tests/opfs/concurrency/test.js 74f4ef9a827d081e6bb0ffb1d124bb54015dab8f7ae47abd5b5f26d71633331a -F ext/wasm/tests/opfs/concurrency/worker.js d0303b1403867e97455f7563285af3eb4471961b19bc22e45d021d896d48e27c +F ext/wasm/tests/opfs/concurrency/worker.js ce1d5d7545b17f62bac2dcce2505a89c3690e1d9209512cc51512cee6e3024f5 F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 53aa080e357d7a2ffeab68a3584fda43d51ecef3dc8a1d46dd32392ae4f9740c -R fcfb0bfb06d58bd7f0d57908763a15cf +P ba81d95febc5fd0f9bbb2685fef5b1b10f9991751f2bdfafba80c15877af1cef +R 5bd89f58e70b2c6dcff7610e01717205 U stephan -Z 62318d6c194878a798365e388df66b6b +Z 52bcc9f2059e4acc631f2cd7a59885ba # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fc702daf45..e3c556d7b3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ba81d95febc5fd0f9bbb2685fef5b1b10f9991751f2bdfafba80c15877af1cef +247ffed141f66a6a5a396a3e002995a9f00c70333271199200530066e77956c4 From 7cc8db2f5df22fb7cd94daaa8d389dd7c4454349 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 19:39:03 +0000 Subject: [PATCH 117/197] Small typo fix in the FP_DIGITS API docs. FossilOrigin-Name: 0286f97f34fd560d4ba423bd28d18ac080c918b0e99b8d16c4a213cf205b5e5b --- manifest | 16 +++++++--------- manifest.uuid | 2 +- src/sqlite.h.in | 4 ++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index f057d51f29..d749f14c27 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sfixes\sthat\swere\sdeferred\suntil\safter\sthe\s3.52.0\srelease,\sincluding:\n(1)\sFix\shandling\sof\sDISTINCT\swith\sOUTER\sJOIN,\s(2)\sEnhance\sconfigure\sto\nauto-detect\slinenoise,\s(3)\sAdd\srecent\sconfiguration\ssettings\sto\sWASM. -D 2026-03-06T18:51:49.681 +C Small\stypo\sfix\sin\sthe\sFP_DIGITS\sAPI\sdocs. +D 2026-03-06T19:39:03.260 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -731,7 +731,7 @@ F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576 F src/shell.c.in d4e9ce266ca8f7364da6e86df011f8655beeb5f0d074d624215a2d8ce220a0ad -F src/sqlite.h.in 1f853f1d836af3e5a0b451521041d05658988a45f6978aaae08286e483fee5ac +F src/sqlite.h.in 307c7c1d1a71071b8572e8c6943f7a2e9483b008afb375758871881366f33e59 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca F src/sqliteInt.h 1c7f23ab9d6efdf3dc434880b6320f158937284f6e2cebd2a024def0c749cb04 @@ -2189,10 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 557aeb43869d3585137b17690cb3b64f7de6921774daae9e56403c3717dceab6 e36958584511d83666590abef223c2edc3da15b5b32e280baf08159ddae80e50 837069635e53849cbca0aa876bad7c7ff44e17578ae492e07acf354067b7e16d -R 9b8a424125f66f63fcc120bc22e6fba2 -T +closed 837069635e53849cbca0aa876bad7c7ff44e17578ae492e07acf354067b7e16d -T +closed e36958584511d83666590abef223c2edc3da15b5b32e280baf08159ddae80e50 -U drh -Z 44da1c0bb960ee973745a6af2376fae6 +P 9d51bec1b17925f5cac0d590c0d70bb34e77fdb7253d18007f52711d42f6f5d0 +R faafbd0263980f02c26e6b799ca07352 +U stephan +Z c2682495642bf42a556122ce9916399d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4160e85390..c35891a833 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9d51bec1b17925f5cac0d590c0d70bb34e77fdb7253d18007f52711d42f6f5d0 +0286f97f34fd560d4ba423bd28d18ac080c918b0e99b8d16c4a213cf205b5e5b diff --git a/src/sqlite.h.in b/src/sqlite.h.in index b6773e1d9b..0f208e7373 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2644,7 +2644,7 @@ struct sqlite3_mem_methods { ** to an integer. The first argument is 1, 0, or -1 to enable, disable, or ** leave unchanged the ability to use comments in SQL text, ** respectively. If the second argument is not NULL, then 0 or 1 is written -** into the integer that the second argument points to depending on if +** into the integer that the second argument points to depending on if ** comments are allowed in SQL text after processing the first argument. **
** @@ -2658,7 +2658,7 @@ struct sqlite3_mem_methods { ** This option takes two arguments which are an integer and a pointer ** to an integer. The first argument is a small integer, between 3 and 23, or ** zero. The FP_DIGITS setting is changed to that small integer, or left -** altered if the first argument is zero or out of range. The second argument +** unaltered if the first argument is zero or out of range. The second argument ** is a pointer to an integer. If the pointer is not NULL, then the value of ** the FP_DIGITS setting, after possibly being modified by the first ** arguments, is written into the integer to which the second argument points. From 7c483444a1259e15ffdc4191e54370721dd054e2 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 6 Mar 2026 21:31:07 +0000 Subject: [PATCH 118/197] Fix a NULL pointer dereference in the (undocumented) two-argument version of the decimal() extension SQL function. [forum:/forumpost/fa9c2dc83f|Forum post fa9c2dc83f]. FossilOrigin-Name: a0266351df8700383d50c2ef2d179dd82b0e0fd7fc70d05a91d5e4e845983b46 --- ext/misc/decimal.c | 1 + manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c index be4321ca8c..796c510a43 100644 --- a/ext/misc/decimal.c +++ b/ext/misc/decimal.c @@ -298,6 +298,7 @@ static void decimal_round(Decimal *p, int N){ int i; int nZero; if( N<1 ) return; + if( p==0 ) return; for(nZero=0; nZeronDigit && p->a[nZero]==0; nZero++){} N += nZero; if( p->nDigit<=N ) return; diff --git a/manifest b/manifest index d749f14c27..68dcf4a413 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Small\stypo\sfix\sin\sthe\sFP_DIGITS\sAPI\sdocs. -D 2026-03-06T19:39:03.260 +C Fix\sa\sNULL\spointer\sdereference\sin\sthe\s(undocumented)\stwo-argument\sversion\nof\sthe\sdecimal()\sextension\sSQL\sfunction.\n[forum:/forumpost/fa9c2dc83f|Forum\spost\sfa9c2dc83f]. +D 2026-03-06T21:31:07.243 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -370,7 +370,7 @@ F ext/misc/completion.c c27b64fdd0943c1b7f152376599814cee2641f7d67a7bb9bd2b957c2 F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565 F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680 -F ext/misc/decimal.c e1da22eee70d7e3eaa99a6b761bc03c4d01d7ffa554bf3178b1f1f184932806c +F ext/misc/decimal.c e365fa7e6f1f44a36150cb137c842635341333a1249cd29eb615a5bebdccd841 F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b F ext/misc/fileio.c 33165b3cd99f83dcd333a338eb51491f6b01c8d96cb6ae81f96a6a096834e030 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 9d51bec1b17925f5cac0d590c0d70bb34e77fdb7253d18007f52711d42f6f5d0 -R faafbd0263980f02c26e6b799ca07352 -U stephan -Z c2682495642bf42a556122ce9916399d +P 0286f97f34fd560d4ba423bd28d18ac080c918b0e99b8d16c4a213cf205b5e5b +R d74b29182b81b1577e729e296083a691 +U drh +Z ea2fda05a11c54db1476c63179e8b074 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c35891a833..bb008180f4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0286f97f34fd560d4ba423bd28d18ac080c918b0e99b8d16c4a213cf205b5e5b +a0266351df8700383d50c2ef2d179dd82b0e0fd7fc70d05a91d5e4e845983b46 From 3ed9043c71575d0bf16aa877843236761c887e73 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 6 Mar 2026 21:34:49 +0000 Subject: [PATCH 119/197] Increase the version number to 3.52.1. FossilOrigin-Name: 94a650b169bfd1056995c1cfe584d3d92667bce5e9cf93e6381607ed87251bf3 --- VERSION | 2 +- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index 7ac0b0a686..426d048447 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.52.0 +3.52.1 diff --git a/manifest b/manifest index 68dcf4a413..537e3d8a58 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sNULL\spointer\sdereference\sin\sthe\s(undocumented)\stwo-argument\sversion\nof\sthe\sdecimal()\sextension\sSQL\sfunction.\n[forum:/forumpost/fa9c2dc83f|Forum\spost\sfa9c2dc83f]. -D 2026-03-06T21:31:07.243 +C Increase\sthe\sversion\snumber\sto\s3.52.1. +D 2026-03-06T21:34:49.052 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -8,7 +8,7 @@ F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0 F Makefile.msc 174764cb7e80c80f9003c46b3e388d74c68c8c40230208904b3af8fcabee5f4e F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec -F VERSION 74672bfd4c7826c0fc6f84762488a707c52e7d2d94af42ccb0edcc6c74311c41 +F VERSION ed5325177122f86b7a25c21bee36fda8171a34ab86e4c72007798d7837a752be F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5 F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 0286f97f34fd560d4ba423bd28d18ac080c918b0e99b8d16c4a213cf205b5e5b -R d74b29182b81b1577e729e296083a691 +P a0266351df8700383d50c2ef2d179dd82b0e0fd7fc70d05a91d5e4e845983b46 +R ef47400364456c50ccaf35d3e0213c06 U drh -Z ea2fda05a11c54db1476c63179e8b074 +Z 4b5606aa812b4812b9b3f4dc11c310ee # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bb008180f4..936e9e5dca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a0266351df8700383d50c2ef2d179dd82b0e0fd7fc70d05a91d5e4e845983b46 +94a650b169bfd1056995c1cfe584d3d92667bce5e9cf93e6381607ed87251bf3 From 1bf79ca4450a94135fe10339b1aa74113c297b8c Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 6 Mar 2026 22:09:39 +0000 Subject: [PATCH 120/197] Rename the initializer functions for base64() and base85() to include the number at the end. FossilOrigin-Name: af18b68978ec9b1ff732505bfb92bb65e4f7381b904123f42c638b747569fa28 --- ext/misc/base64.c | 2 +- ext/misc/base85.c | 15 ++++++++------- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/shell.c.in | 5 ----- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/ext/misc/base64.c b/ext/misc/base64.c index 2da767bb0d..28dd74a3b1 100644 --- a/ext/misc/base64.c +++ b/ext/misc/base64.c @@ -275,7 +275,7 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){ #ifdef _WIN32 __declspec(dllexport) #endif -int sqlite3_base_init +int sqlite3_base64_init #else static int sqlite3_base64_init #endif diff --git a/ext/misc/base85.c b/ext/misc/base85.c index 63245e2e4a..76f242d7e5 100644 --- a/ext/misc/base85.c +++ b/ext/misc/base85.c @@ -79,6 +79,7 @@ #include #include #include +#define OMIT_BASE85_CHECKER #ifndef OMIT_BASE85_CHECKER # include #endif @@ -262,7 +263,7 @@ static int allBase85( char *p, int len ){ #ifndef BASE85_STANDALONE -# ifndef OMIT_BASE85_CHECKER +#ifndef OMIT_BASE85_CHECKER /* This function does the work for the SQLite is_base85(t) UDF. */ static void is_base85(sqlite3_context *context, int na, sqlite3_value *av[]){ assert(na==1); @@ -282,7 +283,7 @@ static void is_base85(sqlite3_context *context, int na, sqlite3_value *av[]){ return; } } -# endif +#endif /* This function does the work for the SQLite base85(x) UDF. */ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){ @@ -352,14 +353,14 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){ #ifdef _WIN32 __declspec(dllexport) #endif -int sqlite3_base_init +int sqlite3_base85_init #else static int sqlite3_base85_init #endif (sqlite3 *db, char **pzErr, const sqlite3_api_routines *pApi){ SQLITE_EXTENSION_INIT2(pApi); (void)pzErr; -# ifndef OMIT_BASE85_CHECKER +#ifndef OMIT_BASE85_CHECKER { int rc = sqlite3_create_function (db, "is_base85", 1, @@ -367,7 +368,7 @@ static int sqlite3_base85_init 0, is_base85, 0, 0); if( rc!=SQLITE_OK ) return rc; } -# endif +#endif return sqlite3_create_function (db, "base85", 1, SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_DIRECTONLY|SQLITE_UTF8, @@ -432,9 +433,9 @@ int main(int na, char *av[]){ int nc = strlen(cBuf); size_t nbo = fromBase85( cBuf, nc, bBuf ) - bBuf; if( 1 != fwrite(bBuf, nbo, 1, fb) ) rc = 1; -# ifndef OMIT_BASE85_CHECKER +#ifndef OMIT_BASE85_CHECKER b85Clean &= allBase85( cBuf, nc ); -# endif +#endif } break; default: diff --git a/manifest b/manifest index 537e3d8a58..75f92ac375 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Increase\sthe\sversion\snumber\sto\s3.52.1. -D 2026-03-06T21:34:49.052 +C Rename\sthe\sinitializer\sfunctions\sfor\sbase64()\sand\sbase85()\sto\sinclude\sthe\nnumber\sat\sthe\send. +D 2026-03-06T22:09:39.887 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -359,8 +359,8 @@ F ext/misc/README.md 6243cdc4d7eb791c41ef0716f3980b8b5f6aa8c61ff76a3958cbf0031c6 F ext/misc/amatch.c 0e0124c1e03ee4cb99b25969f6b7b39c53a847b8bf12279efbcb896b0df1059a F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824 -F ext/misc/base64.c 8dc0a08cee11722822858a62625f1b63e5d5f1adac1cf4492d5732b571e37aa0 -F ext/misc/base85.c ff54cc676c6ec86231f75ecc86ea45416fcb69751dfb79690d5f5da5f7d39867 +F ext/misc/base64.c 313bd363214ba732198f205eead2f445e5caf6248f0384bc29a0430e1edc497f +F ext/misc/base85.c da9e7655102df04308788722fa85fc41f18f465a71d92a0740d2ae0d0b10febd F ext/misc/basexx.c 89ad6b76558efbceb627afd5e2ef1d84b2e96d9aaf9b7ecb20e3d00b51be6fcf F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a F ext/misc/btreeinfo.c 13bc9e9f1c13cde370d0e4a6a2683e9f1926a4cead7fb72c71871b11a06d78a1 @@ -730,7 +730,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576 -F src/shell.c.in d4e9ce266ca8f7364da6e86df011f8655beeb5f0d074d624215a2d8ce220a0ad +F src/shell.c.in 1845b4c2028b6a264ec994628ac34b36c35eefbe61d6fb6a0370643f0e458aa9 F src/sqlite.h.in 307c7c1d1a71071b8572e8c6943f7a2e9483b008afb375758871881366f33e59 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P a0266351df8700383d50c2ef2d179dd82b0e0fd7fc70d05a91d5e4e845983b46 -R ef47400364456c50ccaf35d3e0213c06 +P 94a650b169bfd1056995c1cfe584d3d92667bce5e9cf93e6381607ed87251bf3 +R 989a666377fa6d7e98c6cb3b06508470 U drh -Z 4b5606aa812b4812b9b3f4dc11c310ee +Z e6a51fa6f64f4c1724ac4878d85b6bf3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 936e9e5dca..ce33b12c89 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -94a650b169bfd1056995c1cfe584d3d92667bce5e9cf93e6381607ed87251bf3 +af18b68978ec9b1ff732505bfb92bb65e4f7381b904123f42c638b747569fa28 diff --git a/src/shell.c.in b/src/shell.c.in index ef30194fac..e67879b8ec 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1024,12 +1024,7 @@ INCLUDE ../ext/misc/shathree.c INCLUDE ../ext/misc/sha1.c INCLUDE ../ext/misc/uint.c INCLUDE ../ext/misc/decimal.c -#undef sqlite3_base_init -#define sqlite3_base_init sqlite3_base64_init INCLUDE ../ext/misc/base64.c -#undef sqlite3_base_init -#define sqlite3_base_init sqlite3_base85_init -#define OMIT_BASE85_CHECKER INCLUDE ../ext/misc/base85.c INCLUDE ../ext/misc/ieee754.c INCLUDE ../ext/misc/series.c From 2251f0c4cc7823e338902c4c83675c4cfdc2ceb4 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 22:21:06 +0000 Subject: [PATCH 121/197] Get "opfs" and "opfs-wl" properly split. Speedtest1 and the concurrency tester are happy with opfs-wl but it is not yet plugged in to tester1. FossilOrigin-Name: 12dcd5425967b6306f3e3178babeac130962edb78e6298d545a429a1a20457cc --- ext/wasm/api/opfs-common-shared.c-pp.js | 39 ++++++--- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 27 +++--- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 86 +++++++++---------- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 71 ++++++++------- manifest | 18 ++-- manifest.uuid | 2 +- 6 files changed, 135 insertions(+), 108 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 734b211c09..0bbaed930e 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -423,9 +423,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ /** Must be called by the VFS's main installation routine and passed the options object that function receives and a reference to that - function itself (which is assumed to have a defaultProxyUri - property set on it. See sqlite3-vfs-opfs{,-wl}.c-pp.js for - examples. + function itself (we don't need this anymore). It throws if OPFS is not available. @@ -446,9 +444,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ - Call opfvs.bindVfs() */ - opfsUtil.initOptions = function callee(options, callee){ + opfsUtil.initOptions = function callee(vfsName, options){ const urlParams = new URL(globalThis.location.href).searchParams; - if(urlParams.has('opfs-disable')){ + if(urlParams.has(vfsName+'-disable')){ //sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.'); return; } @@ -458,10 +456,23 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return; } options = util.nu(options); + options.vfsName = vfsName; options.verbose ??= urlParams.has('opfs-verbose') ? (+urlParams.get('opfs-verbose') || 2) : 1; options.sanityChecks ??= urlParams.has('opfs-sanity-check'); - options.proxyUri ??= callee.defaultProxyUri; + + if( true ){ + /* Doing this from one scope up does not work */ + opfsUtil.proxyUri = "sqlite3-opfs-async-proxy.js"; + if( sqlite3.scriptInfo?.sqlite3Dir ){ + opfsUtil.proxyUri = ( + sqlite3.scriptInfo.sqlite3Dir + opfsUtil.proxyUri + ); + } + //sqlite3.config.error("proxyUri =",opfsUtil.proxyUri, sqlite3.scriptInfo); + } + + options.proxyUri ??= opfsUtil.proxyUri; if('function' === typeof options.proxyUri){ options.proxyUri = options.proxyUri(); } @@ -474,7 +485,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ options.workerId ??= (Math.random() * 10000000) | 0; } //sqlite3.config.warn("opfsUtil options =",JSON.stringify(options), 'urlParams =', urlParams); - return options; + return opfsUtil.options = options; }; /** @@ -498,8 +509,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ only cloneable or sharable objects. After the worker's "inited" message arrives, other types of data may be added to it. */ - opfsUtil.createVfsState = function(vfsName, options){ + opfsUtil.createVfsState = function(){ const state = util.nu(); + const options = opfsUtil.options; state.verbose = options.verbose; const loggers = [ @@ -507,8 +519,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ sqlite3.config.warn, sqlite3.config.log ]; + const vfsName = options.vfsName + || toss("Maintenance required: missing VFS name"); const logImpl = (level,...args)=>{ - if(state.verbose>level) loggers[level]("OPFS syncer:",...args); + if(state.verbose>level) loggers[level](vfsName+":",...args); }; const log = (...args)=>logImpl(2, ...args), warn = (...args)=>logImpl(1, ...args), @@ -544,7 +558,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ */ ); - const isWebLocker = 'opfs-wl'===vfsName; opfsVfs.metrics = util.nu({ counters: util.nu(), dump: function(){ @@ -588,7 +601,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ of this value is also used for determining how long to wait on lock contention to free up. */ - state.asyncIdleWaitTime = isWebLocker ? 250 : 150; + state.asyncIdleWaitTime = 150; /** Whether the async counterpart should log exceptions to @@ -771,7 +784,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ (see sqlite3-opfs-async-proxy.c-pp.js). */ const opRun = opfsVfs.opRun = (op,...args)=>{ - const opNdx = state.opIds[op] || toss("Invalid op ID:",op); + const opNdx = state.opIds[op] || toss(opfsVfs.vfsName+": Invalid op ID:",op); state.s11n.serialize(...args); Atomics.store(state.sabOPView, state.opIds.rc, -1); Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); @@ -1088,12 +1101,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ promiseWasRejected = false; return promiseResolve_(sqlite3); }; + const options = opfsUtil.options; let proxyUri = options.proxyUri +( (options.proxyUri.indexOf('?')<0) ? '?' : '&' )+'vfs='+vfsName; if( options.workerId ){ proxyUri += '&opfs-async-proxy-id='+encodeURIComponent(options.workerId); } + //sqlite3.config.error("proxyUri",options.proxyUri, (new Error())); const W = opfsVfs.worker = //#if target:es6-bundler-friendly (()=>{ diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index e83cdf416d..797407e2c4 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -51,7 +51,8 @@ */ "use strict"; const urlParams = new URL(globalThis.location.href).searchParams; -if( !urlParams.has('vfs') ){ +const vfsName = urlParams.get('vfs'); +if( !vfsName ){ throw new Error("Expecting vfs=opfs|opfs-wl URL argument for this worker"); } const workerId = urlParams.get('opfs-async-proxy-id') @@ -111,12 +112,13 @@ const installAsyncProxy = function(){ */ const __openFiles = Object.create(null); /** - __implicitLocks is a Set of sqlite3_file pointers (integers) which were - "auto-locked". i.e. those for which we obtained a sync access - handle without an explicit xLock() call. Such locks will be - released during db connection idle time, whereas a sync access - handle obtained via xLock(), or subsequently xLock()'d after - auto-acquisition, will not be released until xUnlock() is called. + __implicitLocks is a Set of sqlite3_file pointers (integers) + which were "auto-locked". i.e. those for which we necessarily + obtain a sync access handle without an explicit xLock() call + guarding access. Such locks will be released during + `waitLoop()`'s idle time, whereas a sync access handle obtained + via xLock(), or subsequently xLock()'d after auto-acquisition, + will not be released until xUnlock() is called. Maintenance reminder: if we relinquish auto-locks at the end of the operation which acquires them, we pay a massive performance @@ -853,16 +855,21 @@ const installAsyncProxy = function(){ wPost('opfs-async-loaded'); }).catch((e)=>error("error initializing OPFS asyncer:",e)); }/*installAsyncProxy()*/; -if(!globalThis.SharedArrayBuffer){ +if(globalThis.window === globalThis){ + wPost('opfs-unavailable', + "This code cannot run from the main thread.", + "Load it as a Worker from a separate Worker."); +}else if(!globalThis.SharedArrayBuffer){ wPost('opfs-unavailable', "Missing SharedArrayBuffer API.", "The server must emit the COOP/COEP response headers to enable that."); }else if(!globalThis.Atomics){ wPost('opfs-unavailable', "Missing Atomics API.", "The server must emit the COOP/COEP response headers to enable that."); +}else if('opfs-wl'===vfsName && !globalThis.Atomics.waitAsync){ + wPost('opfs-unavailable',"Missing required Atomics.waitSync() for "+vfsName); }else if(!globalThis.FileSystemHandle || !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || + !globalThis.FileSystemFileHandle?.prototype?.createSyncAccessHandle || !navigator?.storage?.getDirectory){ wPost('opfs-unavailable',"Missing required OPFS APIs."); }else{ diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 8119b32469..c1d34f192d 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -49,63 +49,60 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ Quirks specific to this VFS: - - Because WebLocks effectively block until they return, they will - effectively hang on locks rather than returning SQLITE_BUSY. + - The (officially undocumented) 'opfs-wl-disable' URL + argument will disable OPFS, making this function a no-op. Aside from locking differences in the VFSes, this function otherwise behaves the same as sqlite3-vfs-opfs.c-pp.js:installOpfsVfs(). */ -const installOpfsWlVfs = async function callee(options){ - options = opfsUtil.initOptions(options, callee); +const installOpfsWlVfs = async function(options){ + options = opfsUtil.initOptions('opfs-wl',options); if( !options ) return sqlite3; options.verbose = 2; const capi = sqlite3.capi, - debug = (...args)=>sqlite3.config.warn("opfs-wl:",...args), - state = opfsUtil.createVfsState('opfs-wl', options), + state = opfsUtil.createVfsState(), opfsVfs = state.vfs, metrics = opfsVfs.metrics.counters, mTimeStart = opfsVfs.mTimeStart, mTimeEnd = opfsVfs.mTimeEnd, + opRun = opfsVfs.opRun, + debug = (...args)=>sqlite3.config.debug("opfs-wl:",...args), + warn = (...args)=>sqlite3.config.warn("opfs-wl:",...args), __openFiles = opfsVfs.__openFiles; - //debug("state",JSON.stringify(state,false,' ')); - /* At this point, createVfsState() has populated state and opfsVfs - with any code common to both the "opfs" and "opfs-wl" VFSes. Now - comes the VFS-dependent work... */ + + //debug("state",JSON.stringify(options)); + /* + At this point, createVfsState() has populated: + + - state: the configuration object we share with the async proxy. + + - opfsVfs: an sqlite3_vfs instance with lots of JS state attached + to it. + + with any code common to both the "opfs" and "opfs-wl" VFSes. Now + comes the VFS-dependent work... + */ return opfsVfs.bindVfs(util.nu({ - xLock: function(pFile,lockType){ + xLock: function(pFile,lockType){ mTimeStart('xLock'); - ++metrics.xLock.count; + //debug("xLock()..."); const f = __openFiles[pFile]; - let rc = 0; - /* All OPFS locks are exclusive locks. If xLock() has - previously succeeded, do nothing except record the lock - type. If no lock is active, have the async counterpart - lock the file. */ - if( f.lockType ) { - f.lockType = lockType; - }else{ - rc = opRun('xLock', pFile, lockType); - if( 0===rc ) f.lockType = lockType; - } + const rc = opRun('xLock', pFile, lockType); + if( !rc ) f.lockType = lockType; mTimeEnd(); return rc; }, xUnlock: function(pFile,lockType){ mTimeStart('xUnlock'); - ++metrics.xUnlock.count; const f = __openFiles[pFile]; - let rc = 0; - if( capi.SQLITE_LOCK_NONE === lockType - && f.lockType ){ - rc = opRun('xUnlock', pFile, lockType); - } - if( 0===rc ) f.lockType = lockType; + const rc = opRun('xUnlock', pFile, lockType); + if( !rc ) f.lockType = lockType; mTimeEnd(); return rc; } }), function(sqlite3, vfs){ - //debug("registered VFS"); + /* Post-VFS-registration initialization... */ if(sqlite3.oo1){ const OpfsWlDb = function(...args){ const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); @@ -115,25 +112,20 @@ const installOpfsWlVfs = async function callee(options){ OpfsWlDb.prototype = Object.create(sqlite3.oo1.DB.prototype); sqlite3.oo1.OpfsWlDb = OpfsWlDb; OpfsWlDb.importDb = opfsUtil.importDb; - }/*extend sqlite3.oo1*/ + /* The "opfs" VFS variant adds a + oo1.DB.dbCtorHelper.setVfsPostOpenCallback() callback to set + a high busy_timeout. That was a design mis-decision and is + inconsistent with sqlite3_open() and friends, but is retained + against the risk of introducing regressions if it's removed. + This variant does not repeat that mistake. + */ + } })/*bindVfs()*/; }/*installOpfsWlVfs()*/; -installOpfsWlVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ - try{ - let proxyJs = installOpfsWlVfs.defaultProxyUri; - if( sqlite3.scriptInfo?.sqlite3Dir ){ - installOpfsWlVfs.defaultProxyUri = - sqlite3.scriptInfo.sqlite3Dir + proxyJs; - //sqlite3.config.warn("installOpfsWlVfs.defaultProxyUri =",installOpfsWlVfs.defaultProxyUri); - } - return installOpfsWlVfs().catch((e)=>{ - sqlite3.config.warn("Ignoring inability to install OPFS-WL sqlite3_vfs:",e); - }); - }catch(e){ - sqlite3.config.error("installOpfsWlVfs() exception:",e); - return Promise.reject(e); - } + return installOpfsWlVfs().catch((e)=>{ + sqlite3.config.warn("Ignoring inability to install the 'opfs-wl' sqlite3_vfs:",e); + }); }); }/*sqlite3ApiBootstrap.initializers.push()*/); //#endif target:node diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index ebe74e38b6..05e6a3f09f 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -60,7 +60,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ The argument may optionally be a plain object with the following configuration options: - - proxyUri: name of the async proxy JS file. + - proxyUri: name of the async proxy JS file or a synchronous function + which, when called, returns such a name. - verbose (=2): an integer 0-3. 0 disables all logging, 1 enables logging of errors. 2 enables logging of warnings and errors. 3 @@ -80,12 +81,13 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ as there are legitimate non-error reasons for OPFS not to be available. */ -const installOpfsVfs = async function callee(options){ - options = opfsUtil.initOptions(options, callee); +const installOpfsVfs = async function(options){ + options = opfsUtil.initOptions('opfs',options); if( !options ) return sqlite3; const capi = sqlite3.capi, - state = opfsUtil.createVfsState('opfs', options), + state = opfsUtil.createVfsState(), opfsVfs = state.vfs, + metrics = opfsVfs.metrics.counters, mTimeStart = opfsVfs.mTimeStart, mTimeEnd = opfsVfs.mTimeEnd, opRun = opfsVfs.opRun, @@ -94,32 +96,51 @@ const installOpfsVfs = async function callee(options){ __openFiles = opfsVfs.__openFiles; //debug("options:",JSON.stringify(options)); - /* At this point, createVfsState() has populated `state` and - `opfsVfs` with any code common to both the "opfs" and "opfs-wl" - VFSes. Now comes the VFS-dependent work... */ + /* + At this point, createVfsState() has populated: + + - state: the configuration object we share with the async proxy. + + - opfsVfs: an sqlite3_vfs instance with lots of JS state attached + to it. + + with any code common to both the "opfs" and "opfs-wl" VFSes. Now + comes the VFS-dependent work... + */ return opfsVfs.bindVfs(util.nu({ xLock: function(pFile,lockType){ mTimeStart('xLock'); - //debug("xLock()..."); + ++metrics.xLock.count; const f = __openFiles[pFile]; - const rc = opRun('xLock', pFile, lockType); - if( rc ){ - warn("xLock() rc ",rc); - }else{ + let rc = 0; + /* All OPFS locks are exclusive locks. If xLock() has + previously succeeded, do nothing except record the lock + type. If no lock is active, have the async counterpart + lock the file. */ + if( f.lockType ) { f.lockType = lockType; + }else{ + rc = opRun('xLock', pFile, lockType); + if( 0===rc ) f.lockType = lockType; } mTimeEnd(); return rc; }, xUnlock: function(pFile,lockType){ mTimeStart('xUnlock'); + ++metrics.xUnlock.count; const f = __openFiles[pFile]; - const rc = opRun('xUnlock', pFile, lockType); + let rc = 0; + if( capi.SQLITE_LOCK_NONE === lockType + && f.lockType ){ + rc = opRun('xUnlock', pFile, lockType); + } if( 0===rc ) f.lockType = lockType; mTimeEnd(); return rc; } }), function(sqlite3, vfs){ + /* Post-VFS-registration initialization... */ if(sqlite3.oo1){ const OpfsDb = function(...args){ const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); @@ -129,7 +150,11 @@ const installOpfsVfs = async function callee(options){ OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype); sqlite3.oo1.OpfsDb = OpfsDb; OpfsDb.importDb = opfsUtil.importDb; - if( false ){ + if( true ){ + /* 2026-03-06: this was a design mis-decision and is + inconsistent with sqlite3_open() and friends, but is + retained against the risk of introducing regressions if + it's removed. */ sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback( opfsVfs.pointer, function(oo1Db, sqlite3){ @@ -143,22 +168,10 @@ const installOpfsVfs = async function callee(options){ }/*extend sqlite3.oo1*/ })/*bindVfs()*/; }/*installOpfsVfs()*/; -installOpfsVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ - try{ - let proxyJs = installOpfsVfs.defaultProxyUri; - if( sqlite3.scriptInfo?.sqlite3Dir ){ - installOpfsVfs.defaultProxyUri = - sqlite3.scriptInfo.sqlite3Dir + proxyJs; - //sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri); - } - return installOpfsVfs().catch((e)=>{ - sqlite3.config.warn("Ignoring inability to install OPFS sqlite3_vfs:",e); - }); - }catch(e){ - sqlite3.config.error("installOpfsVfs() exception:",e); - return Promise.reject(e); - } + return installOpfsVfs().catch((e)=>{ + sqlite3.config.warn("Ignoring inability to install 'opfs' sqlite3_vfs:",e); + }) }); }/*sqlite3ApiBootstrap.initializers.push()*/); //#endif target:node diff --git a/manifest b/manifest index 0974a04f21..72316086e1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\scleanups\sand\sdocs.\sTeach\sthe\sOPFS\sconcurrency\stester\sto\sdeal\swith\sSQLITE_BUSY\sinstead\sof\sfailing. -D 2026-03-06T19:33:25.647 +C Get\s"opfs"\sand\s"opfs-wl"\sproperly\ssplit.\sSpeedtest1\sand\sthe\sconcurrency\stester\sare\shappy\swith\sopfs-wl\sbut\sit\sis\snot\syet\splugged\sin\sto\stester1. +D 2026-03-06T22:21:06.784 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js eccb37a2347b8b17a664401cd8ef0ee0a7e18cb81939ee4ef404905e8e9188bf +F ext/wasm/api/opfs-common-shared.c-pp.js b41b71ac06264e2d2db9a08e9cd7d5ee0e5730d224a4e81e0c42b0928028844e F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -594,12 +594,12 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js c19ca5986bceb60561973635bd68acbb93f5e1752b1d1b7f4cae20abaa8d5bd1 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 6025b22ebb92f9216e68d85c4e27c228e148f4d081e306f27d0a50342e56ec37 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 8233c5f9021b0213134e2adbaf6036b8f1dffd4747083a4087c1c19ae107f962 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js f3bef4dbb8364a37471e4bc33e9b1e52795596456090007aaeae25acc35d2e85 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js f65903e15f49a5475eaf8fd3f35971d4c4c4b43f0a00167f1a2c98389cf84900 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 872c29aa760b05c2703185368a39b4b2e1a8abf15c29ee7e23ee8ca7cdcbed9d F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P ba81d95febc5fd0f9bbb2685fef5b1b10f9991751f2bdfafba80c15877af1cef -R 5bd89f58e70b2c6dcff7610e01717205 +P 247ffed141f66a6a5a396a3e002995a9f00c70333271199200530066e77956c4 +R d5ab78b2216c6ac5e35f6ab8d6aa4867 U stephan -Z 52bcc9f2059e4acc631f2cd7a59885ba +Z 836eb4f55d744876555cc67389157d1f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e3c556d7b3..31efc532c3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -247ffed141f66a6a5a396a3e002995a9f00c70333271199200530066e77956c4 +12dcd5425967b6306f3e3178babeac130962edb78e6298d545a429a1a20457cc From 8f65da4574021d5f526de7486eefb31a4f95ad71 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 6 Mar 2026 23:37:45 +0000 Subject: [PATCH 122/197] Fix a memory leak in the decimal extension that follows an OOM. FossilOrigin-Name: 8d59e47e7ae0aae01cb25c6c054cf9a4d9651e858bc0dd1a0e2a013ec6579012 --- ext/misc/decimal.c | 10 ++++++---- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c index 796c510a43..50f6ce511c 100644 --- a/ext/misc/decimal.c +++ b/ext/misc/decimal.c @@ -128,9 +128,10 @@ static Decimal *decimalNewFromText(const char *zIn, int n){ } } if( iExp>0 ){ - p->a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit + signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit + (sqlite3_int64)iExp + 1 ); - if( p->a==0 ) goto new_from_text_failed; + if( a==0 ) goto new_from_text_failed; + p->a = a; memset(p->a+p->nDigit, 0, iExp); p->nDigit += iExp; } @@ -148,9 +149,10 @@ static Decimal *decimalNewFromText(const char *zIn, int n){ } } if( iExp>0 ){ - p->a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit + signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit + (sqlite3_int64)iExp + 1 ); - if( p->a==0 ) goto new_from_text_failed; + if( a==0 ) goto new_from_text_failed; + p->a = a; memmove(p->a+iExp, p->a, p->nDigit); memset(p->a, 0, iExp); p->nDigit += iExp; diff --git a/manifest b/manifest index 75f92ac375..872a56c9c7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rename\sthe\sinitializer\sfunctions\sfor\sbase64()\sand\sbase85()\sto\sinclude\sthe\nnumber\sat\sthe\send. -D 2026-03-06T22:09:39.887 +C Fix\sa\smemory\sleak\sin\sthe\sdecimal\sextension\sthat\sfollows\san\sOOM. +D 2026-03-06T23:37:45.381 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -370,7 +370,7 @@ F ext/misc/completion.c c27b64fdd0943c1b7f152376599814cee2641f7d67a7bb9bd2b957c2 F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565 F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680 -F ext/misc/decimal.c e365fa7e6f1f44a36150cb137c842635341333a1249cd29eb615a5bebdccd841 +F ext/misc/decimal.c ab8525b6870735e9991700c605977b697484c57a161729c810c37edb515c45a2 F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b F ext/misc/fileio.c 33165b3cd99f83dcd333a338eb51491f6b01c8d96cb6ae81f96a6a096834e030 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 94a650b169bfd1056995c1cfe584d3d92667bce5e9cf93e6381607ed87251bf3 -R 989a666377fa6d7e98c6cb3b06508470 +P af18b68978ec9b1ff732505bfb92bb65e4f7381b904123f42c638b747569fa28 +R 11f0753acd82d511ab8c1d1c160af2a5 U drh -Z e6a51fa6f64f4c1724ac4878d85b6bf3 +Z 81ddf101166dcc9f59cb1dc6cb89c1a9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ce33b12c89..9659f9a3cb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -af18b68978ec9b1ff732505bfb92bb65e4f7381b904123f42c638b747569fa28 +8d59e47e7ae0aae01cb25c6c054cf9a4d9651e858bc0dd1a0e2a013ec6579012 From ac63b524acdf789c9a44623023bda10d693a4e7e Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 6 Mar 2026 23:50:44 +0000 Subject: [PATCH 123/197] Add some jitter and duration info to the opfs concurrency tester. Ensure that Atomics.waitAsync() is available for opfs-wl. Further testing has shown that Web opfs-wl is consistently fairer about doling out contested locks but it's dog slow compared to the original VFS under moderate concurrency. In single-connection use they're effectively on par. FossilOrigin-Name: a9aecc987512d60f2663973f43c769cf086fc14149edfbcb18c0aec9f5aa3dbf --- ext/wasm/api/opfs-common-shared.c-pp.js | 34 ++++++------ ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 2 +- ext/wasm/tests/opfs/concurrency/test.js | 55 +++++++++++-------- ext/wasm/tests/opfs/concurrency/worker.js | 7 ++- manifest | 18 +++--- manifest.uuid | 2 +- 6 files changed, 65 insertions(+), 53 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 0bbaed930e..17916426ef 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -402,21 +402,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ descriptive error message if they're not found. This is intended to be run as part of async VFS installation steps. */ - opfsUtil.vfsInstallationFeatureCheck = function(){ - if(!globalThis.SharedArrayBuffer - || !globalThis.Atomics){ - throw new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. "+ - "The server must emit the COOP/COEP response headers to enable those. "+ - "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep"); - }else if('undefined'===typeof WorkerGlobalScope){ - throw new Error("The OPFS sqlite3_vfs cannot run in the main thread "+ - "because it requires Atomics.wait()."); - }else if(!globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || - !navigator?.storage?.getDirectory){ - throw new newError("Missing required OPFS APIs."); + opfsUtil.vfsInstallationFeatureCheck = function(vfsName){ + if( !globalThis.SharedArrayBuffer || !globalThis.Atomics ){ + toss("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics.", + "The server must emit the COOP/COEP response headers to enable those.", + "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep"); + }else if( 'undefined'===typeof WorkerGlobalScope ){ + toss("The OPFS sqlite3_vfs cannot run in the main thread", + "because it requires Atomics.wait()."); + }else if( !globalThis.FileSystemHandle || + !globalThis.FileSystemDirectoryHandle || + !globalThis.FileSystemFileHandle?.prototype?.createSyncAccessHandle || + !navigator?.storage?.getDirectory ){ + toss("Missing required OPFS APIs."); + }else if( 'opfs-wl'===vfsName && !globalThis.Atomics.waitAsync ){ + toss('The',vfsName,'VFS requires Atomics.waitAsync(), which is not available.'); } }; @@ -446,12 +446,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ */ opfsUtil.initOptions = function callee(vfsName, options){ const urlParams = new URL(globalThis.location.href).searchParams; - if(urlParams.has(vfsName+'-disable')){ + if( urlParams.has(vfsName+'-disable') ){ //sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.'); return; } try{ - opfsUtil.vfsInstallationFeatureCheck(); + opfsUtil.vfsInstallationFeatureCheck(vfsName); }catch(e){ return; } diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 797407e2c4..f89f73c311 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -89,7 +89,7 @@ const installAsyncProxy = function(){ 2 = warnings and errors 3 = debug, warnings, and errors */ - state.verbose = 2; + state.verbose = 1; const loggers = { 0:console.error.bind(console), diff --git a/ext/wasm/tests/opfs/concurrency/test.js b/ext/wasm/tests/opfs/concurrency/test.js index 18c01a5b7e..bdc15a3c4b 100644 --- a/ext/wasm/tests/opfs/concurrency/test.js +++ b/ext/wasm/tests/opfs/concurrency/test.js @@ -59,7 +59,7 @@ ) || 3; options.opfsVerbose = ( urlArgsHtml.has('verbose') ? +urlArgsHtml.get('verbose') : 1 - ) || 1; + ) || 0; options.interval = ( urlArgsHtml.has('interval') ? +urlArgsHtml.get('interval') : 1000 ) || 1000; @@ -76,41 +76,52 @@ for(const w of workers) w.postMessage({type, payload:args}); }; workers.counts = {loaded: 0, passed: 0, failed: 0}; + let timeStart; + const calcTime = (endDate)=>{ + return endDate.getTime() - timeStart?.getTime?.(); + }; const checkFinished = function(){ if(workers.counts.passed + workers.counts.failed !== workers.length){ return; } + stdout("Total Worker run time:",calcTime(new Date()),"ms"); if(workers.counts.failed>0){ logCss('tests-fail',"Finished with",workers.counts.failed,"failure(s)."); }else{ logCss('tests-pass',"All",workers.length,"workers finished."); } }; + workers.onmessage = function(msg){ msg = msg.data; const prefix = 'Worker #'+msg.worker+':'; switch(msg.type){ - case 'loaded': - stdout(prefix,"loaded"); - if(++workers.counts.loaded === workers.length){ - stdout("All",workers.length,"workers loaded. Telling them to run..."); - workers.post('run'); - } - break; - case 'stdout': stdout(prefix,...msg.payload); break; - case 'stderr': stderr(prefix,...msg.payload); break; - case 'error': stderr(prefix,"ERROR:",...msg.payload); break; - case 'finished': - ++workers.counts.passed; - logCss('tests-pass',prefix,...msg.payload); - checkFinished(); - break; - case 'failed': - ++workers.counts.failed; - logCss('tests-fail',prefix,"FAILED:",...msg.payload); - checkFinished(); - break; - default: logCss('error',"Unhandled message type:",msg); break; + case 'loaded': + stdout(prefix,"loaded"); + if(++workers.counts.loaded === workers.length){ + timeStart = new Date(); + stdout(timeStart,"All",workers.length,"workers loaded. Telling them to run..."); + workers.post('run'); + } + break; + case 'stdout': stdout(prefix,...msg.payload); break; + case 'stderr': stderr(prefix,...msg.payload); break; + case 'error': stderr(prefix,"ERROR:",...msg.payload); break; + case 'finished': { + ++workers.counts.passed; + const timeEnd = new Date(); + logCss('tests-pass',prefix,timeEnd,"("+calcTime(timeEnd)+"ms) ", ...msg.payload); + checkFinished(); + break; + } + case 'failed': { + ++workers.counts.failed; + const timeEnd = new Date(); + logCss('tests-fail',prefix,timeEnd,"("+calcTime(timeEnd)+"ms) FAILED:",...msg.payload); + checkFinished(); + break; + } + default: logCss('error',"Unhandled message type:",msg); break; } }; diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index 0f9c9b68cb..75c2b8a64d 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -80,7 +80,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ }catch(e){ if(e instanceof sqlite3.SQLite3Error && sqlite3.capi.SQLITE_BUSY===e.resultCode){ - stderr("Retrying for BUSY: ",e.message); + stderr("Retrying",(db ? "db init" : "open()"),"for BUSY:",e.message); continue; } throw e; @@ -106,7 +106,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ }catch(e){ if(e instanceof sqlite3.SQLite3Error && sqlite3.capi.SQLITE_BUSY===e.resultCode){ - stderr("Retrying for BUSY: ",e.message); + stderr("Retrying interval #",interval.count,"for BUSY:",e.message); continue; } stderr("Error: ",e.message); @@ -121,7 +121,8 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ if(interval.error || maxIterations === interval.count){ finish(); }else{ - setTimeout(timer, interval.delay); + const jitter = (Math.random()*150 - Math.random()*150) | 0; + setTimeout(timer, interval.delay + jitter); } }, interval.delay); }/*run()*/; diff --git a/manifest b/manifest index 72316086e1..6c368d0569 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Get\s"opfs"\sand\s"opfs-wl"\sproperly\ssplit.\sSpeedtest1\sand\sthe\sconcurrency\stester\sare\shappy\swith\sopfs-wl\sbut\sit\sis\snot\syet\splugged\sin\sto\stester1. -D 2026-03-06T22:21:06.784 +C Add\ssome\sjitter\sand\sduration\sinfo\sto\sthe\sopfs\sconcurrency\stester.\sEnsure\sthat\sAtomics.waitAsync()\sis\savailable\sfor\sopfs-wl.\sFurther\stesting\shas\sshown\sthat\sWeb\sopfs-wl\sis\sconsistently\sfairer\sabout\sdoling\sout\scontested\slocks\sbut\sit's\sdog\sslow\scompared\sto\sthe\soriginal\sVFS\sunder\smoderate\sconcurrency.\sIn\ssingle-connection\suse\sthey're\seffectively\son\spar. +D 2026-03-06T23:50:44.079 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js b41b71ac06264e2d2db9a08e9cd7d5ee0e5730d224a4e81e0c42b0928028844e +F ext/wasm/api/opfs-common-shared.c-pp.js 612df64a2a159db30786c742c70a09d75b993d034f360367125747d2eca531a5 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -594,7 +594,7 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 6025b22ebb92f9216e68d85c4e27c228e148f4d081e306f27d0a50342e56ec37 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 341468dc0f322d98b032c6922c9865ef9028fafc8f713b950c5ff2c0305e2c87 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 @@ -646,8 +646,8 @@ F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c9 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb F ext/wasm/tester1.c-pp.js a4e79fbf63bb3255d2b8ffc1cd538c115d2f6b599bc324904c80f6644379a284 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e -F ext/wasm/tests/opfs/concurrency/test.js 74f4ef9a827d081e6bb0ffb1d124bb54015dab8f7ae47abd5b5f26d71633331a -F ext/wasm/tests/opfs/concurrency/worker.js ce1d5d7545b17f62bac2dcce2505a89c3690e1d9209512cc51512cee6e3024f5 +F ext/wasm/tests/opfs/concurrency/test.js b315a5480197e8da80c626d21b7939a485784bc6a13ec681115d4f5384c9b971 +F ext/wasm/tests/opfs/concurrency/worker.js b247316330d2c11817b6debc7d16e4cbc51c689f56a4cb5d6c4ec4a2bca45ca7 F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 247ffed141f66a6a5a396a3e002995a9f00c70333271199200530066e77956c4 -R d5ab78b2216c6ac5e35f6ab8d6aa4867 +P 12dcd5425967b6306f3e3178babeac130962edb78e6298d545a429a1a20457cc +R 587bc730112047fe7757e9bed1469d73 U stephan -Z 836eb4f55d744876555cc67389157d1f +Z cdae14ec494ba9a4ab6ec30704fa3278 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 31efc532c3..3ea9463f59 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -12dcd5425967b6306f3e3178babeac130962edb78e6298d545a429a1a20457cc +a9aecc987512d60f2663973f43c769cf086fc14149edfbcb18c0aec9f5aa3dbf From 84334c941a3539d6a4db90a29acad51e9686f8d1 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 6 Mar 2026 23:56:03 +0000 Subject: [PATCH 124/197] Fix a memory leak following OOM in the completion extension. FossilOrigin-Name: ff5b1efbf80875a82b3707b56440551eb6f68a899ade27363bc62872fe46fd75 --- ext/misc/completion.c | 20 ++++++++++++-------- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/ext/misc/completion.c b/ext/misc/completion.c index 67b40d84d1..42d78ab86b 100644 --- a/ext/misc/completion.c +++ b/ext/misc/completion.c @@ -224,20 +224,22 @@ static int completionNext(sqlite3_vtab_cursor *cur){ case COMPLETION_TABLES: { if( pCur->pStmt==0 ){ sqlite3_stmt *pS2; + sqlite3_str* pStr = sqlite3_str_new(pCur->db); char *zSql = 0; const char *zSep = ""; sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); while( sqlite3_step(pS2)==SQLITE_ROW ){ const char *zDb = (const char*)sqlite3_column_text(pS2, 1); - zSql = sqlite3_mprintf( - "%z%s" + sqlite3_str_appendf(pStr, + "%s" "SELECT name FROM \"%w\".sqlite_schema", - zSql, zSep, zDb + zSep, zDb ); - if( zSql==0 ) return SQLITE_NOMEM; zSep = " UNION "; } sqlite3_finalize(pS2); + zSql = sqlite3_str_finish(pStr); + if( zSql==0 ) return SQLITE_NOMEM; sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); sqlite3_free(zSql); } @@ -248,22 +250,24 @@ static int completionNext(sqlite3_vtab_cursor *cur){ case COMPLETION_COLUMNS: { if( pCur->pStmt==0 ){ sqlite3_stmt *pS2; + sqlite3_str *pStr = sqlite3_str_new(pCur->db); char *zSql = 0; const char *zSep = ""; sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); while( sqlite3_step(pS2)==SQLITE_ROW ){ const char *zDb = (const char*)sqlite3_column_text(pS2, 1); - zSql = sqlite3_mprintf( - "%z%s" + sqlite3_str_appendf(pStr, + "%s" "SELECT pti.name FROM \"%w\".sqlite_schema AS sm" " JOIN pragma_table_xinfo(sm.name,%Q) AS pti" " WHERE sm.type='table'", - zSql, zSep, zDb, zDb + zSep, zDb, zDb ); - if( zSql==0 ) return SQLITE_NOMEM; zSep = " UNION "; } sqlite3_finalize(pS2); + zSql = sqlite3_str_finish(pStr); + if( zSql==0 ) return SQLITE_NOMEM; sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); sqlite3_free(zSql); } diff --git a/manifest b/manifest index 872a56c9c7..6541716d3c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\smemory\sleak\sin\sthe\sdecimal\sextension\sthat\sfollows\san\sOOM. -D 2026-03-06T23:37:45.381 +C Fix\sa\smemory\sleak\sfollowing\sOOM\sin\sthe\scompletion\sextension. +D 2026-03-06T23:56:03.830 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -366,7 +366,7 @@ F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0e F ext/misc/btreeinfo.c 13bc9e9f1c13cde370d0e4a6a2683e9f1926a4cead7fb72c71871b11a06d78a1 F ext/misc/cksumvfs.c 9d7d0cf1a8893ac5d48922bfe9f3f217b4a61a6265f559263a02bb2001259913 F ext/misc/closure.c 5559daf1daf742228431db929d1aa86dd535a4224cc634a81d2fd0d1e6ad7839 -F ext/misc/completion.c c27b64fdd0943c1b7f152376599814cee2641f7d67a7bb9bd2b957c2a64a5591 +F ext/misc/completion.c 99589a9f04113e9a169312d132730131963451a30abd6704d780862333cb091c F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565 F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P af18b68978ec9b1ff732505bfb92bb65e4f7381b904123f42c638b747569fa28 -R 11f0753acd82d511ab8c1d1c160af2a5 +P 8d59e47e7ae0aae01cb25c6c054cf9a4d9651e858bc0dd1a0e2a013ec6579012 +R d09aa847db130508a6d4900fb29fd697 U drh -Z 81ddf101166dcc9f59cb1dc6cb89c1a9 +Z 0dec6b08e07aa5f4cda86237d4ed7b37 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9659f9a3cb..91dfc86471 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8d59e47e7ae0aae01cb25c6c054cf9a4d9651e858bc0dd1a0e2a013ec6579012 +ff5b1efbf80875a82b3707b56440551eb6f68a899ade27363bc62872fe46fd75 From 56b571780ef811a4e92ddb07fee42d8837b67a0c Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 6 Mar 2026 23:58:58 +0000 Subject: [PATCH 125/197] Fix a NULL pointer dereference following OOM in the decimal extension. FossilOrigin-Name: de37f30b2100e0c249e5c0853d6af90cd3c2069899747dcf0889e6a3d6b94061 --- ext/misc/decimal.c | 1 + manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c index 50f6ce511c..e6adb20e8b 100644 --- a/ext/misc/decimal.c +++ b/ext/misc/decimal.c @@ -69,6 +69,7 @@ static Decimal *decimalNewFromText(const char *zIn, int n){ int i; int iExp = 0; + if( zIn==0 ) goto new_from_text_failed; p = sqlite3_malloc( sizeof(*p) ); if( p==0 ) goto new_from_text_failed; p->sign = 0; diff --git a/manifest b/manifest index 6541716d3c..4bc71943dc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\smemory\sleak\sfollowing\sOOM\sin\sthe\scompletion\sextension. -D 2026-03-06T23:56:03.830 +C Fix\sa\sNULL\spointer\sdereference\sfollowing\sOOM\sin\sthe\sdecimal\sextension. +D 2026-03-06T23:58:58.125 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -370,7 +370,7 @@ F ext/misc/completion.c 99589a9f04113e9a169312d132730131963451a30abd6704d7808623 F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565 F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680 -F ext/misc/decimal.c ab8525b6870735e9991700c605977b697484c57a161729c810c37edb515c45a2 +F ext/misc/decimal.c caba30af5af57f3227353905265fe471a65c6cb8b8f9a99a073681efb5ab967c F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b F ext/misc/fileio.c 33165b3cd99f83dcd333a338eb51491f6b01c8d96cb6ae81f96a6a096834e030 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 8d59e47e7ae0aae01cb25c6c054cf9a4d9651e858bc0dd1a0e2a013ec6579012 -R d09aa847db130508a6d4900fb29fd697 +P ff5b1efbf80875a82b3707b56440551eb6f68a899ade27363bc62872fe46fd75 +R 7ea284c35bf74e815ff10548f3d8dfa2 U drh -Z 0dec6b08e07aa5f4cda86237d4ed7b37 +Z 29cd4895bd91142236530cfa8c3ded9e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 91dfc86471..db6ee847e1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ff5b1efbf80875a82b3707b56440551eb6f68a899ade27363bc62872fe46fd75 +de37f30b2100e0c249e5c0853d6af90cd3c2069899747dcf0889e6a3d6b94061 From 7f6236bed1617358a7ae503d073304be277f397e Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 7 Mar 2026 00:03:47 +0000 Subject: [PATCH 126/197] Fix a NULL pointer dereference following OOM in the sha1 extension. FossilOrigin-Name: 530b3f97ca4e8b1d263266855743b0d57d048104a6c3bed6c4d7958985767bc6 --- ext/misc/sha1.c | 7 +++++-- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ext/misc/sha1.c b/ext/misc/sha1.c index 02d8649556..3262e32d83 100644 --- a/ext/misc/sha1.c +++ b/ext/misc/sha1.c @@ -249,16 +249,19 @@ static void sha1Func( SHA1Context cx; int eType = sqlite3_value_type(argv[0]); int nByte = sqlite3_value_bytes(argv[0]); + const unsigned char *pData; char zOut[44]; assert( argc==1 ); if( eType==SQLITE_NULL ) return; hash_init(&cx); if( eType==SQLITE_BLOB ){ - hash_step(&cx, sqlite3_value_blob(argv[0]), nByte); + pData = (const unsigned char*)sqlite3_value_blob(argv[0]); }else{ - hash_step(&cx, sqlite3_value_text(argv[0]), nByte); + pData = (const unsigned char*)sqlite3_value_text(argv[0]); } + if( pData==0 ) return; + hash_step(&cx, pData, nByte); if( sqlite3_user_data(context)!=0 ){ /* sha1b() - binary result */ hash_finish(&cx, zOut, 1); diff --git a/manifest b/manifest index 4bc71943dc..aa38de496d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sNULL\spointer\sdereference\sfollowing\sOOM\sin\sthe\sdecimal\sextension. -D 2026-03-06T23:58:58.125 +C Fix\sa\sNULL\spointer\sdereference\sfollowing\sOOM\sin\sthe\ssha1\sextension. +D 2026-03-07T00:03:47.603 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -393,7 +393,7 @@ F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6 F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946 F ext/misc/series.c 22c6d8f00cc1b5089b1b37392e9097e9df9a5db53be86daf9a7669d95bb179f4 -F ext/misc/sha1.c 3030b5926b34bb09459200e100fae34e48c04077cf175381a7560f72bbf3d9cf +F ext/misc/sha1.c 7e7dafd21f99b0881f5ff86132bda6bb4b918de4a1b820a1fb63018a928865b9 F ext/misc/shathree.c fd22d70620f86a0467acfdd3acd8435d5cb54eb1e2d9ff36ae44e389826993df F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52 F ext/misc/spellfix.c 693c8fd3293087fa821322967a97e59dfa24051e5d2ca7fa85790a4034db6fa4 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P ff5b1efbf80875a82b3707b56440551eb6f68a899ade27363bc62872fe46fd75 -R 7ea284c35bf74e815ff10548f3d8dfa2 +P de37f30b2100e0c249e5c0853d6af90cd3c2069899747dcf0889e6a3d6b94061 +R 9ddd6b7b1d56576ec468a44fa084a4a6 U drh -Z 29cd4895bd91142236530cfa8c3ded9e +Z b2af67a70e2f8c8bfde1636eeb5d1fa8 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index db6ee847e1..1e837f9ba8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -de37f30b2100e0c249e5c0853d6af90cd3c2069899747dcf0889e6a3d6b94061 +530b3f97ca4e8b1d263266855743b0d57d048104a6c3bed6c4d7958985767bc6 From 02d9860c8e453373acfd8935f7774f1f6b3f9958 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 7 Mar 2026 00:10:34 +0000 Subject: [PATCH 127/197] Fix another NULL ptr deref following OOM in the sha1 extension. FossilOrigin-Name: c4843e4cce71acb1e3743c45e0ee8cf62e91c39b57cec4f356bf7a4a10f81352 --- ext/misc/sha1.c | 1 + manifest | 12 ++++++------ manifest.tags | 4 ++-- manifest.uuid | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ext/misc/sha1.c b/ext/misc/sha1.c index 3262e32d83..fb8f625f51 100644 --- a/ext/misc/sha1.c +++ b/ext/misc/sha1.c @@ -323,6 +323,7 @@ static void sha1QueryFunc( } nCol = sqlite3_column_count(pStmt); z = sqlite3_sql(pStmt); + if( z==0 ) z = ""; n = (int)strlen(z); hash_step_vformat(&cx,"S%d:",n); hash_step(&cx,(unsigned char*)z,n); diff --git a/manifest b/manifest index aa38de496d..420190b2a1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sNULL\spointer\sdereference\sfollowing\sOOM\sin\sthe\ssha1\sextension. -D 2026-03-07T00:03:47.603 +C Fix\sanother\sNULL\sptr\sderef\sfollowing\sOOM\sin\sthe\ssha1\sextension. +D 2026-03-07T00:10:34.645 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -393,7 +393,7 @@ F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6 F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946 F ext/misc/series.c 22c6d8f00cc1b5089b1b37392e9097e9df9a5db53be86daf9a7669d95bb179f4 -F ext/misc/sha1.c 7e7dafd21f99b0881f5ff86132bda6bb4b918de4a1b820a1fb63018a928865b9 +F ext/misc/sha1.c 8bf60344c11a525384c2efd1ae77f160b06be336db679effaadf292d4b41451c F ext/misc/shathree.c fd22d70620f86a0467acfdd3acd8435d5cb54eb1e2d9ff36ae44e389826993df F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52 F ext/misc/spellfix.c 693c8fd3293087fa821322967a97e59dfa24051e5d2ca7fa85790a4034db6fa4 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P de37f30b2100e0c249e5c0853d6af90cd3c2069899747dcf0889e6a3d6b94061 -R 9ddd6b7b1d56576ec468a44fa084a4a6 +P 530b3f97ca4e8b1d263266855743b0d57d048104a6c3bed6c4d7958985767bc6 +R 68d7e539387dc166cbf2bf5523a7998a U drh -Z b2af67a70e2f8c8bfde1636eeb5d1fa8 +Z a6d283ed4760a59d40fbc8bcecb600f0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..464f6c31a3 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch extfunc-fuzz +tag extfunc-fuzz diff --git a/manifest.uuid b/manifest.uuid index 1e837f9ba8..cf592c9888 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -530b3f97ca4e8b1d263266855743b0d57d048104a6c3bed6c4d7958985767bc6 +c4843e4cce71acb1e3743c45e0ee8cf62e91c39b57cec4f356bf7a4a10f81352 From 3866d01907fea0b341c6d55f29e45e817577e0cf Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 7 Mar 2026 00:14:36 +0000 Subject: [PATCH 128/197] Reenable the is_base85() extension function that was disabled by [af18b68978ec9b1f]. FossilOrigin-Name: be07c16e3a7d28b95bea4b987a880d5b4b2b44d9a31ac5b48caa5b6c6dc5bec3 --- ext/misc/base85.c | 1 - manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ext/misc/base85.c b/ext/misc/base85.c index 76f242d7e5..52b542bdaa 100644 --- a/ext/misc/base85.c +++ b/ext/misc/base85.c @@ -79,7 +79,6 @@ #include #include #include -#define OMIT_BASE85_CHECKER #ifndef OMIT_BASE85_CHECKER # include #endif diff --git a/manifest b/manifest index 420190b2a1..d6e68ba3ab 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sanother\sNULL\sptr\sderef\sfollowing\sOOM\sin\sthe\ssha1\sextension. -D 2026-03-07T00:10:34.645 +C Reenable\sthe\sis_base85()\sextension\sfunction\sthat\swas\sdisabled\nby\s[af18b68978ec9b1f]. +D 2026-03-07T00:14:36.107 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -360,7 +360,7 @@ F ext/misc/amatch.c 0e0124c1e03ee4cb99b25969f6b7b39c53a847b8bf12279efbcb896b0df1 F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824 F ext/misc/base64.c 313bd363214ba732198f205eead2f445e5caf6248f0384bc29a0430e1edc497f -F ext/misc/base85.c da9e7655102df04308788722fa85fc41f18f465a71d92a0740d2ae0d0b10febd +F ext/misc/base85.c 6fff354a637554f2574dbcf32d5f18898a98d4bb0ba0d73a2af91f6e87d02b62 F ext/misc/basexx.c 89ad6b76558efbceb627afd5e2ef1d84b2e96d9aaf9b7ecb20e3d00b51be6fcf F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a F ext/misc/btreeinfo.c 13bc9e9f1c13cde370d0e4a6a2683e9f1926a4cead7fb72c71871b11a06d78a1 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 530b3f97ca4e8b1d263266855743b0d57d048104a6c3bed6c4d7958985767bc6 -R 68d7e539387dc166cbf2bf5523a7998a +P c4843e4cce71acb1e3743c45e0ee8cf62e91c39b57cec4f356bf7a4a10f81352 +R c5fa0800e812db087ddb1eb453804f3f U drh -Z a6d283ed4760a59d40fbc8bcecb600f0 +Z 89905c27e4448987191e485f141a5327 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cf592c9888..cbd33e7ca3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c4843e4cce71acb1e3743c45e0ee8cf62e91c39b57cec4f356bf7a4a10f81352 +be07c16e3a7d28b95bea4b987a880d5b4b2b44d9a31ac5b48caa5b6c6dc5bec3 From 57d0fe254a9628776eb081750543c8ce1c62fc83 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 7 Mar 2026 01:01:13 +0000 Subject: [PATCH 129/197] For backwards compatibility, ensure that the "opfs" VFS does not specifically require Atomics.waitAsync() (a new requirement of "opfs-wl"), but make use of it if available. Only apply jitter to the concurrency test runs at random intervals. FossilOrigin-Name: f2175f526c00cfe562e8f332eb197b5ef2c3d6be1fff2aab1566c2c533a293ac --- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 78 ++++++++++++++++--- ext/wasm/tests/opfs/concurrency/index.html | 11 ++- ext/wasm/tests/opfs/concurrency/test.js | 9 ++- ext/wasm/tests/opfs/concurrency/worker.js | 9 ++- manifest | 18 ++--- manifest.uuid | 2 +- 6 files changed, 94 insertions(+), 33 deletions(-) diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index f89f73c311..6362c6efd4 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -668,8 +668,7 @@ const installAsyncProxy = function(){ __implicitLocks.delete(fid); let rc = 0; try{ - /* Make only one attempt to get the handle. */ - await getSyncHandle(fh, 'xLock'); + await getSyncHandle(fh, 'xLock', state.asyncIdleWaitTime, 5); }catch(e){ fh.xLock = oldLockType; state.s11n.storeException(1, e); @@ -794,15 +793,64 @@ const installAsyncProxy = function(){ const opView = state.sabOPView; const slotWhichOp = opIds.whichOp; const idleWaitTime = state.asyncIdleWaitTime; + const hasWaitAsync = !!Atomics.waitAsync; while(!flagAsyncShutdown){ try { - const opId = Atomics.load(opView, slotWhichOp); - if( 0===opId ){ - const rv = Atomics.waitAsync(opView, slotWhichOp, 0, - idleWaitTime); - if( rv.async ) await rv.value; - await releaseImplicitLocks(); - continue; + let opId; + if( hasWaitAsync ){ + opId = Atomics.load(opView, slotWhichOp); + if( 0===opId ){ + const rv = Atomics.waitAsync(opView, slotWhichOp, 0, + idleWaitTime); + if( rv.async ) await rv.value; + await releaseImplicitLocks(); + continue; + } + }else{ + /** + For browsers without Atomics.waitAsync(), we require + the legacy implementation. Browser versions where + waitAsync() arrived: + + Chrome: 90 (2021-04-13) + Firefox: 145 (2025-11-11) + Safari: 16.4 (2023-03-27) + + The "opfs" VFS was not born until Chrome was somewhere in + the v104-108 range and did not work with Safari < v17 + (2023-09-18) due to a WebKit bug which restricted OPFS + access from sub-Workers. + + The waitAsync() counterpart of this block has shown to be + slightly more performant for the "opfs" VFS than this + block (whereas "opfs-wl" _requires_ that block), so we + enable it where it's available, regardless of the value + of isWebLocker, with the note that if isWebLocker is true + then the bootstrapping of this script will have failed if + waitAsync() is not available. + */ + if('not-equal'!==Atomics.wait( + state.sabOPView, slotWhichOp, 0, state.asyncIdleWaitTime + )){ + /* Maintenance note: we compare against 'not-equal' because + + https://github.com/tomayac/sqlite-wasm/issues/12 + + is reporting that this occasionally, under high loads, + returns 'ok', which leads to the whichOp being 0 (which + isn't a valid operation ID and leads to an exception, + along with a corresponding ugly console log + message). Unfortunately, the conditions for that cannot + be reliably reproduced. The only place in our code which + writes a 0 to the state.opIds.whichOp SharedArrayBuffer + index is a few lines down from here, and that instance + is required in order for clear communication between + the sync half of this proxy and this half. + */ + await releaseImplicitLocks(); + continue; + } + opId = Atomics.load(state.sabOPView, slotWhichOp); } Atomics.store(opView, slotWhichOp, 0); const hnd = f.opHandlers[opId]?.f ?? toss("No waitLoop handler for whichOp #",opId); @@ -812,6 +860,16 @@ const installAsyncProxy = function(){ operation */ ) || []; //error("waitLoop() whichOp =",opId, f.opHandlers[opId].key, args); +//#if nope + if( isWebLocker && (opId==opIds.xLock || opIds==opIds.xUnlock) ){ + /* An expert suggests that this introduces a race condition, + but my eyes aren't seeing it. The hope was that this + would improve the lock speed a tick, but it does not + appear to. */ + hnd(...args); + continue; + } +//#endif await hnd(...args); }catch(e){ error('in waitLoop():', e); @@ -865,7 +923,7 @@ if(globalThis.window === globalThis){ }else if(!globalThis.Atomics){ wPost('opfs-unavailable', "Missing Atomics API.", "The server must emit the COOP/COEP response headers to enable that."); -}else if('opfs-wl'===vfsName && !globalThis.Atomics.waitAsync){ +}else if(isWebLocker && !globalThis.Atomics.waitAsync){ wPost('opfs-unavailable',"Missing required Atomics.waitSync() for "+vfsName); }else if(!globalThis.FileSystemHandle || !globalThis.FileSystemDirectoryHandle || diff --git a/ext/wasm/tests/opfs/concurrency/index.html b/ext/wasm/tests/opfs/concurrency/index.html index 54ed04a4f6..c5e929b010 100644 --- a/ext/wasm/tests/opfs/concurrency/index.html +++ b/ext/wasm/tests/opfs/concurrency/index.html @@ -25,15 +25,14 @@

the workers=N URL flag. Set the time between each workload with interval=N (milliseconds). Set the number of worker iterations with iterations=N. - Enable OPFS VFS verbosity with verbose=1-3 (output - goes to the dev console). Disable/enable "unlock ASAP" mode - (higher concurrency, lower speed) with unlock-asap=0-1. + Disable/enable "unlock ASAP" mode (potentially higher + concurrency but lower speed) with unlock-asap=0-1.

Achtung: if it does not start to do anything within a couple of seconds, check the dev console: Chrome sometimes fails to load - the wasm module due to "cannot allocate WasmMemory." Closing and - re-opening the tab usually resolves it, but sometimes restarting - the browser is required. + the wasm module due to "cannot allocate WasmMemory" when + reloading the page. Closing and re-opening the tab usually + resolves it, but sometimes restarting the browser is required.

Links for various testing options:

diff --git a/ext/wasm/tests/opfs/concurrency/test.js b/ext/wasm/tests/opfs/concurrency/test.js index bdc15a3c4b..f8d7f10399 100644 --- a/ext/wasm/tests/opfs/concurrency/test.js +++ b/ext/wasm/tests/opfs/concurrency/test.js @@ -139,12 +139,13 @@ return li.join('&'); }; for(const opt of [ - {interval: 500, workers: 1, iterations: 5, vfs: 'opfs-wl', opfsVerbose: 2}, - {interval: 500, workers: 2, iterations: 5, vfs: 'opfs-wl', opfsVerbose: 2}, {interval: 1000, workers: 5, iterations: 30}, {interval: 500, workers: 5, iterations: 30}, {interval: 250, workers: 3, iterations: 30}, - {interval: 600, workers: 5, iterations: 100} + {interval: 600, workers: 5, iterations: 100}, + {interval: 500, workers: 1, iterations: 5, vfs: 'opfs-wl'}, + {interval: 500, workers: 2, iterations: 10, vfs: 'opfs-wl'}, + {interval: 500, workers: 5, iterations: 20, vfs: 'opfs-wl'}, ]){ const li = document.createElement('li'); eTestLinks.appendChild(li); @@ -176,4 +177,4 @@ // Have to delay onmessage assignment until after the loop // to avoid that early workers get an undue head start. workers.forEach((w)=>w.onmessage = workers.onmessage); -})(self); +})(globalThis); diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index 75c2b8a64d..ccd1df932a 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -68,7 +68,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ filename: 'file:'+dbName+'?opfs-unlock-asap='+options.unlockAsap, flags: 'c' }); - sqlite3.capi.sqlite3_busy_timeout(db.pointer, 15000); + sqlite3.capi.sqlite3_busy_timeout(db.pointer, 5000); } db.transaction((db)=>{ db.exec([ @@ -121,8 +121,11 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ if(interval.error || maxIterations === interval.count){ finish(); }else{ - const jitter = (Math.random()*150 - Math.random()*150) | 0; - setTimeout(timer, interval.delay + jitter); + const jitter = (Math.random()>=0.5) + ? ((Math.random()*100 - Math.random()*100) | 0) + : 0; + const n = interval.delay + jitter; + setTimeout(timer, n<50 ? interval.delay : n); } }, interval.delay); }/*run()*/; diff --git a/manifest b/manifest index 6c368d0569..ecc54ab16c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssome\sjitter\sand\sduration\sinfo\sto\sthe\sopfs\sconcurrency\stester.\sEnsure\sthat\sAtomics.waitAsync()\sis\savailable\sfor\sopfs-wl.\sFurther\stesting\shas\sshown\sthat\sWeb\sopfs-wl\sis\sconsistently\sfairer\sabout\sdoling\sout\scontested\slocks\sbut\sit's\sdog\sslow\scompared\sto\sthe\soriginal\sVFS\sunder\smoderate\sconcurrency.\sIn\ssingle-connection\suse\sthey're\seffectively\son\spar. -D 2026-03-06T23:50:44.079 +C For\sbackwards\scompatibility,\sensure\sthat\sthe\s"opfs"\sVFS\sdoes\snot\sspecifically\srequire\sAtomics.waitAsync()\s(a\snew\srequirement\sof\s"opfs-wl"),\sbut\smake\suse\sof\sit\sif\savailable.\sOnly\sapply\sjitter\sto\sthe\sconcurrency\stest\sruns\sat\srandom\sintervals. +D 2026-03-07T01:01:13.846 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -594,7 +594,7 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 341468dc0f322d98b032c6922c9865ef9028fafc8f713b950c5ff2c0305e2c87 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 296b3d3701c3b42918357e4d9e5d82c5321b371115fb51a8a405c2eaeebd9f0f F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 @@ -645,9 +645,9 @@ F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f80 F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c986e48af7d3d720fcd244 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb F ext/wasm/tester1.c-pp.js a4e79fbf63bb3255d2b8ffc1cd538c115d2f6b599bc324904c80f6644379a284 -F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e -F ext/wasm/tests/opfs/concurrency/test.js b315a5480197e8da80c626d21b7939a485784bc6a13ec681115d4f5384c9b971 -F ext/wasm/tests/opfs/concurrency/worker.js b247316330d2c11817b6debc7d16e4cbc51c689f56a4cb5d6c4ec4a2bca45ca7 +F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226 +F ext/wasm/tests/opfs/concurrency/test.js 520061e6a624fe0a7c07cf3438cb6b9b7c9dcbd606e644ccb5fb52518c48b342 +F ext/wasm/tests/opfs/concurrency/worker.js 90e51ff3e781a6e08f265cbaaa993bb10eb0b798893b78cf4d8a8a8b3b561392 F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 12dcd5425967b6306f3e3178babeac130962edb78e6298d545a429a1a20457cc -R 587bc730112047fe7757e9bed1469d73 +P a9aecc987512d60f2663973f43c769cf086fc14149edfbcb18c0aec9f5aa3dbf +R 825063f48a3ce6fa65e33b9852885bae U stephan -Z cdae14ec494ba9a4ab6ec30704fa3278 +Z a8fffcaa59d459a1613276d07e6e1f6d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3ea9463f59..a5dd212704 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a9aecc987512d60f2663973f43c769cf086fc14149edfbcb18c0aec9f5aa3dbf +f2175f526c00cfe562e8f332eb197b5ef2c3d6be1fff2aab1566c2c533a293ac From 9be458e61134fc0fb3a442b7c028cc12fc3b96d9 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 7 Mar 2026 02:19:23 +0000 Subject: [PATCH 130/197] Cleanups and docs in the new opfs code structure. FossilOrigin-Name: 3b470c4c7a1fcc710e6b9eae32134c7f6c3f6008b24c7351257f66f5e8f70311 --- ext/wasm/api/opfs-common-shared.c-pp.js | 55 +++++++------------ ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 53 ++++++++++++------ manifest | 14 ++--- manifest.uuid | 2 +- 4 files changed, 64 insertions(+), 60 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 17916426ef..c0b028160e 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -14,7 +14,10 @@ This file holds code shared by sqlite3-vfs-opfs{,-wl}.c-pp.js. It creates a private/internal sqlite3.opfs namespace common to the two and used (only) by them and the test framework. It is not part of - the public API. + the public API. The library deletes sqlite3.opfs in its final + bootstrapping steps unless it's specifically told to keep them (for + testing purposes only) using an undocumented and unsupported + mechanism. */ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'use strict'; @@ -461,49 +464,36 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ ? (+urlParams.get('opfs-verbose') || 2) : 1; options.sanityChecks ??= urlParams.has('opfs-sanity-check'); - if( true ){ - /* Doing this from one scope up does not work */ - opfsUtil.proxyUri = "sqlite3-opfs-async-proxy.js"; - if( sqlite3.scriptInfo?.sqlite3Dir ){ - opfsUtil.proxyUri = ( - sqlite3.scriptInfo.sqlite3Dir + opfsUtil.proxyUri - ); - } - //sqlite3.config.error("proxyUri =",opfsUtil.proxyUri, sqlite3.scriptInfo); + opfsUtil.proxyUri ??= "sqlite3-opfs-async-proxy.js"; + if( sqlite3.scriptInfo?.sqlite3Dir ){ + /* Doing this from one scope up, outside of this function, does + not work. */ + opfsUtil.proxyUri = ( + sqlite3.scriptInfo.sqlite3Dir + opfsUtil.proxyUri + ); } - options.proxyUri ??= opfsUtil.proxyUri; if('function' === typeof options.proxyUri){ options.proxyUri = options.proxyUri(); } - if( false ){ - /* This ends up with the same values for all Worker instances. */ - callee.counter ??= 0; - ++callee.counter; - options.workerId ??= urlParams.get('opfs-async-proxy-id') ?? callee.counter; - }else{ - options.workerId ??= (Math.random() * 10000000) | 0; - } //sqlite3.config.warn("opfsUtil options =",JSON.stringify(options), 'urlParams =', urlParams); return opfsUtil.options = options; }; /** - Creates and populates the main state object used by "opfs" and "opfs-wl", and - transfered from those to their async counterpart. - - Returns an object containing state which we send to the async - proxy Worker. + Creates, populates, and returns the main state object used by the + "opfs" and "opfs-wl" VFSes, and transfered from those to their + async counterparts. The returned object's vfs property holds the fully-populated - capi.sqlite3_vfs instance. + capi.sqlite3_vfs instance, tagged with lots of extra state which + the current VFSes need to have exposed to them. - After setting up any local state needed, the caller must - call theVfs.bindVfs(X,Y), where X is an object containing - the sqlite3_io_methods to override and Y is a callback which - gets triggered if init succeeds, before the final Promise - decides whether or not to reject. The result of bindVfs() - must be returned from their main installation function. + After setting up any local state needed, the caller must call + theVfs.bindVfs(X,Y), where X is an object containing the + sqlite3_io_methods to override and Y is a callback which gets + triggered if init succeeds, before the final Promise decides + whether or not to reject. This object must, when it's passed to the async part, contain only cloneable or sharable objects. After the worker's "inited" @@ -1105,9 +1095,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ let proxyUri = options.proxyUri +( (options.proxyUri.indexOf('?')<0) ? '?' : '&' )+'vfs='+vfsName; - if( options.workerId ){ - proxyUri += '&opfs-async-proxy-id='+encodeURIComponent(options.workerId); - } //sqlite3.config.error("proxyUri",options.proxyUri, (new Error())); const W = opfsVfs.worker = //#if target:es6-bundler-friendly diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 6362c6efd4..d09dd2b350 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -55,8 +55,12 @@ const vfsName = urlParams.get('vfs'); if( !vfsName ){ throw new Error("Expecting vfs=opfs|opfs-wl URL argument for this worker"); } -const workerId = urlParams.get('opfs-async-proxy-id') - ?? 'unnamed'; +/** + We use this to allow us to differentiate debug output from + multiple instances, e.g. multiple Workers to the "opfs" + VFS or both the "opfs" and "opfs-wl" VFSes. +*/ +const workerId = (Math.random() * 10000000) | 0; const isWebLocker = true; //'opfs-wl'===urlParams.get('vfs'); const wPost = (type,...args)=>postMessage({type, payload:args}); const installAsyncProxy = function(){ @@ -287,10 +291,11 @@ const installAsyncProxy = function(){ In order to help alleviate cross-tab contention for a dabase, if an exception is thrown while acquiring the handle, this routine - will wait briefly and try again, up to some fixed number of - times. If acquisition still fails at that point it will give up - and propagate the exception. Client-level code will see that as - an I/O error. + will wait briefly and try again, up to `maxTries` of times. If + acquisition still fails at that point it will give up and + propagate the exception. Client-level code will see that either + as an I/O error or SQLITE_BUSY, depending on the exception and + the context. 2024-06-12: there is a rare race condition here which has been reported a single time: @@ -306,6 +311,12 @@ const installAsyncProxy = function(){ creating a viable test for that condition has proven challenging so far. + Interface quirk: if fh.xLock is falsy and the handle is acquired + then fh.fid is added to __implicitLocks(). If fh.xLock is truthy, + it is not added as an implicit lock. i.e. xLock() impls must set + fh.xLock immediately _before_ calling this and must arrange to + restore it to its previous value if this function throws. + 2026-03-06: - baseWaitTime is the number of milliseconds to wait for the @@ -314,12 +325,11 @@ const installAsyncProxy = function(){ - maxTries is the number of attempt to make, each one spaced out by one additional factor of the baseWaitTime (e.g. 300, then 600, - then 900, the 1200...). This MUST be an integer >0 and defaults - to 6. + then 900, the 1200...). This MUST be an integer >0. Only the Web Locks impl should use the 3rd and 4th parameters. */ - const getSyncHandle = async (fh,opName, baseWaitTime, maxTries)=>{ + const getSyncHandle = async (fh, opName, baseWaitTime, maxTries = 6)=>{ if(!fh.syncHandle){ const t = performance.now(); log("Acquiring sync handle for",fh.filenameAbs); @@ -610,8 +620,15 @@ const installAsyncProxy = function(){ if( isWebLocker ){ /* We require separate xLock() and xUnlock() implementations for the original and Web Lock implementations. The ones in this block - are for the WebLock impl. */ - + are for the WebLock impl. + + The Golden Rule for this impl is: if we have a web lock, we + must also hold the SAH. When "upgrading" an implicit lock to a + requested (explicit) lock, we must remove the SAH from the + __implicitLocks set. When we unlock, we release both the web + lock and the SAH. That invariant must be kept intact or race + conditions on SAHs will ensue. + */ /** Registry of active Web Locks: fid -> { mode, resolveRelease } */ const __activeWebLocks = Object.create(null); @@ -632,8 +649,7 @@ const installAsyncProxy = function(){ storeAndNotify(whichOp, 0); /* Don't do this: existing.mode = requestedMode; - Paraphrased from advice given by a consultanting - developer: + Paraphrased from advice given by a consulting developer: If you hold an exclusive lock and SQLite requests shared, you should keep exiting.mode as exclusive in because the @@ -648,10 +664,11 @@ const installAsyncProxy = function(){ Upgrade path: we must release shared and acquire exclusive. This transition is NOT atomic in Web Locks API. - Except that it _effectively_ is atomic if we don't call - closeSyncHandle(fh), as no other worker can lock that - until we let it go. But we can't do that without leading - to a deadly embrace, so... + It _effectively_ is atomic if we don't call + closeSyncHandle(fh), as no other worker can lock that until + we let it go. But we can't do that without eventually + leading to deadly embrace situations, so we don't do that. + (That's not a hypothetical, it has happened.) */ await closeSyncHandle(fh); existing.resolveRelease(); @@ -664,10 +681,10 @@ const installAsyncProxy = function(){ //error("xLock() initial promise entered..."); navigator.locks.request(lockName, { mode: requestedMode }, async (lock) => { //error("xLock() Web Lock entered.", fh); - fh.xLock = lockType/*must be set before getSyncHandle() is called!*/; __implicitLocks.delete(fid); let rc = 0; try{ + fh.xLock = lockType/*must be set before getSyncHandle() is called!*/; await getSyncHandle(fh, 'xLock', state.asyncIdleWaitTime, 5); }catch(e){ fh.xLock = oldLockType; diff --git a/manifest b/manifest index ecc54ab16c..c12974dd15 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C For\sbackwards\scompatibility,\sensure\sthat\sthe\s"opfs"\sVFS\sdoes\snot\sspecifically\srequire\sAtomics.waitAsync()\s(a\snew\srequirement\sof\s"opfs-wl"),\sbut\smake\suse\sof\sit\sif\savailable.\sOnly\sapply\sjitter\sto\sthe\sconcurrency\stest\sruns\sat\srandom\sintervals. -D 2026-03-07T01:01:13.846 +C Cleanups\sand\sdocs\sin\sthe\snew\sopfs\scode\sstructure. +D 2026-03-07T02:19:23.636 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js 612df64a2a159db30786c742c70a09d75b993d034f360367125747d2eca531a5 +F ext/wasm/api/opfs-common-shared.c-pp.js 81a2429027b76df8691e6c134d3fedbf7cb804585ac28165b857ecb2260a99f3 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -594,7 +594,7 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 296b3d3701c3b42918357e4d9e5d82c5321b371115fb51a8a405c2eaeebd9f0f +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 5c84524885393b90b57d27446872fe980a48e8b9f5f2bb728e7ba63e905feb3f F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P a9aecc987512d60f2663973f43c769cf086fc14149edfbcb18c0aec9f5aa3dbf -R 825063f48a3ce6fa65e33b9852885bae +P f2175f526c00cfe562e8f332eb197b5ef2c3d6be1fff2aab1566c2c533a293ac +R 226e3a09fddd6452554266d606d70e1e U stephan -Z a8fffcaa59d459a1613276d07e6e1f6d +Z 2eb7dcbdcae5965bf20b0b5469f42aa6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a5dd212704..d013e9cb8f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f2175f526c00cfe562e8f332eb197b5ef2c3d6be1fff2aab1566c2c533a293ac +3b470c4c7a1fcc710e6b9eae32134c7f6c3f6008b24c7351257f66f5e8f70311 From 6142524b7040c66114edc6648d4128fe18f109e9 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 7 Mar 2026 02:36:39 +0000 Subject: [PATCH 131/197] The optional SQLITE_DECIMAL_MAX_DIGIT compile-time option limits the maximum number of digits that the decimal extension will operate on. FossilOrigin-Name: 4214485b2fe4b95d9440008158d458b4b957a111f201965de1a518623589fd79 --- ext/misc/decimal.c | 16 ++++++++++++++-- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c index e6adb20e8b..e2709b3017 100644 --- a/ext/misc/decimal.c +++ b/ext/misc/decimal.c @@ -164,6 +164,9 @@ static Decimal *decimalNewFromText(const char *zIn, int n){ for(i=0; inDigit && p->a[i]==0; i++){} if( i>=p->nDigit ) p->sign = 0; } +#if SQLITE_DECIMAL_MAX_DIGIT+0>10 + if( p->nDigit>SQLITE_DECIMAL_MAX_DIGIT ) goto new_from_text_failed; +#endif return p; new_from_text_failed: @@ -463,6 +466,9 @@ static void decimal_expand(Decimal *p, int nDigit, int nFrac){ nAddFrac = nFrac - p->nFrac; nAddSig = (nDigit - p->nDigit) - nAddFrac; if( nAddFrac==0 && nAddSig==0 ) return; +#if SQLITE_DECIMAL_MAX_DIGIT+0>10 + if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; } +#endif p->a = sqlite3_realloc64(p->a, nDigit+1); if( p->a==0 ){ p->oom = 1; @@ -562,14 +568,20 @@ static void decimalMul(Decimal *pA, Decimal *pB){ signed char *acc = 0; int i, j, k; int minFrac; + sqlite3_int64 sumDigit; if( pA==0 || pA->oom || pA->isNull || pB==0 || pB->oom || pB->isNull ){ goto mul_end; } - acc = sqlite3_malloc64( (sqlite3_int64)pA->nDigit + - (sqlite3_int64)pB->nDigit + 2 ); + sumDigit = pA->nDigit; + sumDigit += pB->nDigit; + sumDigit += 2; +#if SQLITE_DECIMAL_MAX_DIGIT+0>10 + if( sumDigit>SQLITE_DECIMAL_MAX_DIGIT ){ pA->oom = 1; return; } +#endif + acc = sqlite3_malloc64( sumDigit ); if( acc==0 ){ pA->oom = 1; goto mul_end; diff --git a/manifest b/manifest index d6e68ba3ab..de3dc9b203 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Reenable\sthe\sis_base85()\sextension\sfunction\sthat\swas\sdisabled\nby\s[af18b68978ec9b1f]. -D 2026-03-07T00:14:36.107 +C The\soptional\sSQLITE_DECIMAL_MAX_DIGIT\scompile-time\soption\slimits\sthe\nmaximum\snumber\sof\sdigits\sthat\sthe\sdecimal\sextension\swill\soperate\son. +D 2026-03-07T02:36:39.331 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -370,7 +370,7 @@ F ext/misc/completion.c 99589a9f04113e9a169312d132730131963451a30abd6704d7808623 F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565 F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680 -F ext/misc/decimal.c caba30af5af57f3227353905265fe471a65c6cb8b8f9a99a073681efb5ab967c +F ext/misc/decimal.c 30cefa0e3324a5378cd92338ca76b4fd2f4bdd9412d28c8d8749767e64780397 F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b F ext/misc/fileio.c 33165b3cd99f83dcd333a338eb51491f6b01c8d96cb6ae81f96a6a096834e030 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P c4843e4cce71acb1e3743c45e0ee8cf62e91c39b57cec4f356bf7a4a10f81352 -R c5fa0800e812db087ddb1eb453804f3f +P be07c16e3a7d28b95bea4b987a880d5b4b2b44d9a31ac5b48caa5b6c6dc5bec3 +R fb41484273ea6a90bfb888fdbf07d432 U drh -Z 89905c27e4448987191e485f141a5327 +Z 8c85ca12d73e44b1162bbbb4c821fd82 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cbd33e7ca3..b03d21fbe1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -be07c16e3a7d28b95bea4b987a880d5b4b2b44d9a31ac5b48caa5b6c6dc5bec3 +4214485b2fe4b95d9440008158d458b4b957a111f201965de1a518623589fd79 From f20c4e650dbde03c90d2f49366f14e2cbd7f4957 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 7 Mar 2026 03:29:26 +0000 Subject: [PATCH 132/197] Elide more of the 64-bit was stuff from the default build target. FossilOrigin-Name: 3b74ad9081daee560bf9b400e69a75abcc62dae7c5f55dcf46de84daae50ed9f --- ext/wasm/mkwasmbuilds.c | 4 ++-- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c index 022a926397..1f60a89bb7 100644 --- a/ext/wasm/mkwasmbuilds.c +++ b/ext/wasm/mkwasmbuilds.c @@ -246,7 +246,7 @@ const BuildDefs oBuildDefs = { .zEnv = 0, .zDeps = 0, .zIfCond = 0, - .flags = CP_ALL | F_64BIT + .flags = CP_ALL | F_64BIT | F_NOT_IN_ALL }, /* The canonical esm build. */ @@ -274,7 +274,7 @@ const BuildDefs oBuildDefs = { .zEnv = 0, .zDeps = 0, .zIfCond = 0, - .flags = CP_JS | F_ESM | F_64BIT + .flags = CP_JS | F_ESM | F_64BIT | F_NOT_IN_ALL }, /* speedtest1, our primary benchmarking tool */ diff --git a/manifest b/manifest index c12974dd15..640a34ab1e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Cleanups\sand\sdocs\sin\sthe\snew\sopfs\scode\sstructure. -D 2026-03-07T02:19:23.636 +C Elide\smore\sof\sthe\s64-bit\swas\sstuff\sfrom\sthe\sdefault\sbuild\starget. +D 2026-03-07T03:29:26.758 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -628,7 +628,7 @@ F ext/wasm/index.html 475bc283338749db4e3fbf24cf3f5aa020cc85a1fffb780d400a915fcb F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b F ext/wasm/jaccwabyt/jaccwabyt.md 6aa90fa1a973d0ad10d077088bea163b241d8470c75eafdef87620a1de1dea41 F ext/wasm/mkdist.sh f8883b077a2ca47cf92e6f0ce305fbf72ca648c3501810125056c4b09c2d5554 x -F ext/wasm/mkwasmbuilds.c 5961177b9d6ad2b49efbdbb3076527e6886fecef7adf99d71cce58bfca89be08 +F ext/wasm/mkwasmbuilds.c d4479af2774a43104b819d9286961b7c09793ca39440e20191e693ceff21f911 F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2 F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96 F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f2175f526c00cfe562e8f332eb197b5ef2c3d6be1fff2aab1566c2c533a293ac -R 226e3a09fddd6452554266d606d70e1e +P 3b470c4c7a1fcc710e6b9eae32134c7f6c3f6008b24c7351257f66f5e8f70311 +R fd6275af0aa6341e83c30c2e83b929c6 U stephan -Z 2eb7dcbdcae5965bf20b0b5469f42aa6 +Z 401ca0507277c8f3e4ba9832533ffae5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d013e9cb8f..cc74046192 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3b470c4c7a1fcc710e6b9eae32134c7f6c3f6008b24c7351257f66f5e8f70311 +3b74ad9081daee560bf9b400e69a75abcc62dae7c5f55dcf46de84daae50ed9f From 7d10030d75122cc26cf5e71b75b258835b3afd72 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 7 Mar 2026 03:32:17 +0000 Subject: [PATCH 133/197] Cleanups and docs in the opfs vfs and its concurrency tester. Experimentally add sqlite3.capi.sqlite3_js_retry_busy(), which runs a callback repeatedly until it _stops_ returning (or throwing) an SQLITE_BUSY error. FossilOrigin-Name: 45c02ed21635f7ef45214ab5ec6230b6b8bd89e35ef5889db318523e1c679fea --- ext/wasm/api/opfs-common-shared.c-pp.js | 3 +- ext/wasm/api/sqlite3-api-prologue.js | 56 +++++++++++++++++++ ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 38 +++++++------ ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 1 - ext/wasm/tests/opfs/concurrency/test.js | 8 ++- ext/wasm/tests/opfs/concurrency/worker.js | 49 ++++++++-------- manifest | 22 ++++---- manifest.uuid | 2 +- 8 files changed, 119 insertions(+), 60 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index c0b028160e..15eec1ff8d 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -107,6 +107,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return false; } }; + /** Checks whether the given OPFS filesystem entry exists, returning true if it does, false if it doesn't or if an @@ -461,7 +462,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ options = util.nu(options); options.vfsName = vfsName; options.verbose ??= urlParams.has('opfs-verbose') - ? (+urlParams.get('opfs-verbose') || 2) : 1; + ? +urlParams.get('opfs-verbose') : 1; options.sanityChecks ??= urlParams.has('opfs-sanity-check'); opfsUtil.proxyUri ??= "sqlite3-opfs-async-proxy.js"; diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 7bb31dc60b..d1055c1cfb 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -1939,6 +1939,62 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( 'sqlite3changeset_old'); }/*changeset/preupdate additions*/ + /** + EXPERIMENTAL. For tentative addition in 3.53.0. + + sqlite3_js_retry_busy(maxTimes,callback[,beforeRetry]) + + Calls the given _synchronous_ callback function. If that function + returns sqlite3.capi.SQLITE_BUSY _or_ throws an SQLite3Error + which a resultCode property of that value then it will suppress + that error and try again, up to the given maximum number of + times. If the callback returns any other value than that, + it is returned. If the maximum number of retries has been + reached, an SQLite3Error with a resultCode value of + sqlite3.capi.SQLITE_BUSY is thrown. If the callback throws any + exception other than the aforementioned BUSY exception, it is + propagated. If it throws a BUSY exception on its final attempt, + that is propagated as well. + + If the beforeRetry argument is given, it must be a _synchronous_ + function. It is called immediately before each retry of the + callback (not for the initial call), passed the attempt number + (so it starts with 2, not 1). If it throws, the exception is + handled as described above. Its result value is ignored. + + To effectively retry "forever", pass a negative maxTimes value, + with the caveat that there is no recovery from that if the code + gets stuck in a deadlock situation. + + TODO: an async variant of this. + */ + capi.sqlite3_js_retry_busy = function(maxTimes, callback, beforeRetry){ + for(let n = 1; n <= maxTimes; ++n){ + try{ + if( beforeRetry && n>1 ) beforeRetry(n); + const rc = callback(); + if( capi.SQLITE_BUSY===rc ){ + if( n===maxTimes ){ + throw new SQLite3Error(rc, [ + "sqlite3_js_retry_busy() max retry attempts (", + maxTimes, + ") reached." + ].join('')); + } + continue; + } + return rc; + }catch(e){ + if( npostMessage({type, payload:args}); const installAsyncProxy = function(){ const toss = function(...args){throw new Error(args.join(' '))}; @@ -101,7 +101,7 @@ const installAsyncProxy = function(){ 2:console.log.bind(console) }; const logImpl = (level,...args)=>{ - if(state.verbose>level) loggers[level]('opfs-async-proxy',workerId+":",...args); + if(state.verbose>level) loggers[level](vfsName+' async-proxy',workerId+":",...args); }; const log = (...args)=>logImpl(2, ...args); const warn = (...args)=>logImpl(1, ...args); @@ -563,7 +563,7 @@ const installAsyncProxy = function(){ rc = state.sq3Codes.SQLITE_IOERR_SHORT_READ; } }catch(e){ - error("xRead() failed",e,fh); + //error("xRead() failed",e,fh); state.s11n.storeException(1,e); rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_READ); } @@ -590,7 +590,7 @@ const installAsyncProxy = function(){ affirmNotRO('xTruncate', fh); await (await getSyncHandle(fh,'xTruncate')).truncate(size); }catch(e){ - error("xTruncate():",e,fh); + //error("xTruncate():",e,fh); state.s11n.storeException(2,e); rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_TRUNCATE); } @@ -608,7 +608,7 @@ const installAsyncProxy = function(){ {at: Number(offset64)}) ) ? 0 : state.sq3Codes.SQLITE_IOERR_WRITE; }catch(e){ - error("xWrite():",e,fh); + //error("xWrite():",e,fh); state.s11n.storeException(1,e); rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_WRITE); } @@ -811,6 +811,11 @@ const installAsyncProxy = function(){ const slotWhichOp = opIds.whichOp; const idleWaitTime = state.asyncIdleWaitTime; const hasWaitAsync = !!Atomics.waitAsync; +//#if nope + error("waitLoop init: isWebLocker",isWebLocker, + "idleWaitTime",idleWaitTime, + "hasWaitAsync",hasWaitAsync); +//#endif while(!flagAsyncShutdown){ try { let opId; @@ -834,17 +839,14 @@ const installAsyncProxy = function(){ Safari: 16.4 (2023-03-27) The "opfs" VFS was not born until Chrome was somewhere in - the v104-108 range and did not work with Safari < v17 - (2023-09-18) due to a WebKit bug which restricted OPFS - access from sub-Workers. - - The waitAsync() counterpart of this block has shown to be - slightly more performant for the "opfs" VFS than this - block (whereas "opfs-wl" _requires_ that block), so we - enable it where it's available, regardless of the value - of isWebLocker, with the note that if isWebLocker is true - then the bootstrapping of this script will have failed if - waitAsync() is not available. + the v104-108 range (Summer/Autumn 2022) and did not work + with Safari < v17 (2023-09-18) due to a WebKit bug which + restricted OPFS access from sub-Workers. + + The waitAsync() counterpart of this block can be used by + both "opfs" and "opfs-wl", whereas this block can only be + used by "opfs". Performance comparisons between the two + in high-contention tests have been indecisive. */ if('not-equal'!==Atomics.wait( state.sabOPView, slotWhichOp, 0, state.asyncIdleWaitTime @@ -863,6 +865,9 @@ const installAsyncProxy = function(){ index is a few lines down from here, and that instance is required in order for clear communication between the sync half of this proxy and this half. + + Much later (2026-03-07): that phenomenon is apparently + called a spurious wakeup. */ await releaseImplicitLocks(); continue; @@ -913,6 +918,7 @@ const installAsyncProxy = function(){ } }); initS11n(); + //warn("verbosity =",opt.verbose, state.verbose); log("init state",state); wPost('opfs-async-inited'); waitLoop(); diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index c1d34f192d..349819b0e1 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -59,7 +59,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const installOpfsWlVfs = async function(options){ options = opfsUtil.initOptions('opfs-wl',options); if( !options ) return sqlite3; - options.verbose = 2; const capi = sqlite3.capi, state = opfsUtil.createVfsState(), opfsVfs = state.vfs, diff --git a/ext/wasm/tests/opfs/concurrency/test.js b/ext/wasm/tests/opfs/concurrency/test.js index f8d7f10399..a73bc2e47d 100644 --- a/ext/wasm/tests/opfs/concurrency/test.js +++ b/ext/wasm/tests/opfs/concurrency/test.js @@ -8,6 +8,7 @@ return ''+v; default: break; } + if( v instanceof Date ) return v.toString(); if(null===v) return 'null'; if(v instanceof Error){ v = { @@ -84,11 +85,12 @@ if(workers.counts.passed + workers.counts.failed !== workers.length){ return; } - stdout("Total Worker run time:",calcTime(new Date()),"ms"); if(workers.counts.failed>0){ - logCss('tests-fail',"Finished with",workers.counts.failed,"failure(s)."); + logCss('tests-fail',"Finished with",workers.counts.failed,"failure(s) in", + calcTime(new Date()),"ms"); }else{ - logCss('tests-pass',"All",workers.length,"workers finished."); + logCss('tests-pass',"All",workers.length,"workers finished in", + calcTime(new Date()),"ms"); } }; diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index ccd1df932a..a698fc96f7 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -63,29 +63,29 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ } while(true){ try{ - if( !db ){ - db = new ctor({ - filename: 'file:'+dbName+'?opfs-unlock-asap='+options.unlockAsap, - flags: 'c' - }); - sqlite3.capi.sqlite3_busy_timeout(db.pointer, 5000); - } - db.transaction((db)=>{ - db.exec([ - "create table if not exists t1(w TEXT UNIQUE ON CONFLICT REPLACE,v);", - "create table if not exists t2(w TEXT UNIQUE ON CONFLICT REPLACE,v);" - ]); + db = new ctor({ + filename: 'file:'+dbName+'?opfs-unlock-asap='+options.unlockAsap, + flags: 'c' }); break; }catch(e){ if(e instanceof sqlite3.SQLite3Error && sqlite3.capi.SQLITE_BUSY===e.resultCode){ - stderr("Retrying",(db ? "db init" : "open()"),"for BUSY:",e.message); + stderr("Retrying open() for BUSY:",e.message); continue; } throw e; } } + sqlite3.capi.sqlite3_busy_timeout(db.pointer, 5000); + sqlite3.capi.sqlite3_js_retry_busy(-1, ()=>{ + db.transaction((db)=>{ + db.exec([ + "create table if not exists t1(w TEXT UNIQUE ON CONFLICT REPLACE,v);", + "create table if not exists t2(w TEXT UNIQUE ON CONFLICT REPLACE,v);" + ]); + }); + }); const maxIterations = urlArgs.has('iterations') ? (+urlArgs.get('iterations') || 10) : 10; @@ -95,24 +95,19 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ ++interval.count; const prefix = "v(#"+interval.count+")"; stdout("Setting",prefix,"=",tm); - while(true){ - try{ + try{ + sqlite3.capi.sqlite3_js_retry_busy(-1, ()=>{ db.exec({ sql:"INSERT OR REPLACE INTO t1(w,v) VALUES(?,?)", bind: [options.workerName, new Date().getTime()] }); - //stdout("Set",prefix); - break; - }catch(e){ - if(e instanceof sqlite3.SQLite3Error - && sqlite3.capi.SQLITE_BUSY===e.resultCode){ - stderr("Retrying interval #",interval.count,"for BUSY:",e.message); - continue; - } - stderr("Error: ",e.message); - interval.error = e; - throw e; - } + }, (n)=>{ + stderr("Attempt #",n,"for interval #",interval.count,"due to BUSY"); + }); + }catch(e){ + stderr("Error: ",e.message); + interval.error = e; + throw e; } //stdout("doWork()",prefix,"error ",interval.error); }; diff --git a/manifest b/manifest index 640a34ab1e..44ee1e7107 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Elide\smore\sof\sthe\s64-bit\swas\sstuff\sfrom\sthe\sdefault\sbuild\starget. -D 2026-03-07T03:29:26.758 +C Cleanups\sand\sdocs\sin\sthe\sopfs\svfs\sand\sits\sconcurrency\stester.\sExperimentally\sadd\ssqlite3.capi.sqlite3_js_retry_busy(),\swhich\sruns\sa\scallback\srepeatedly\suntil\sit\s_stops_\sreturning\s(or\sthrowing)\san\sSQLITE_BUSY\serror. +D 2026-03-07T03:32:17.361 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,20 +585,20 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js 81a2429027b76df8691e6c134d3fedbf7cb804585ac28165b857ecb2260a99f3 +F ext/wasm/api/opfs-common-shared.c-pp.js d58f16b8bf00401d954249d154c91abc4d4f54221f755d774cf5c4e8f83a1a9f F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f F ext/wasm/api/sqlite3-api-glue.c-pp.js 9b33e3ee467791dec4fd1b444b12a8545dfbb6c8b28ac651c7bdc7661a3b5a5c F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c41db98a22b534c15e543cfa -F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385 +F ext/wasm/api/sqlite3-api-prologue.js c616bff3bdff1fcbb6a39bd429a96de9c3e5f1e8c0d287083cea5e98e8b0151c F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 5c84524885393b90b57d27446872fe980a48e8b9f5f2bb728e7ba63e905feb3f +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js c2236c9037ccac368be6eeed3e5f6ed3cefed0d20539c9092139f27a76aaf1ba F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js f65903e15f49a5475eaf8fd3f35971d4c4c4b43f0a00167f1a2c98389cf84900 +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js c518aee3c2f537ae73aa3afd67463d1eb63db0559a41d64fe4d1361b9966b52f F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 872c29aa760b05c2703185368a39b4b2e1a8abf15c29ee7e23ee8ca7cdcbed9d F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 @@ -646,8 +646,8 @@ F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c9 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb F ext/wasm/tester1.c-pp.js a4e79fbf63bb3255d2b8ffc1cd538c115d2f6b599bc324904c80f6644379a284 F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226 -F ext/wasm/tests/opfs/concurrency/test.js 520061e6a624fe0a7c07cf3438cb6b9b7c9dcbd606e644ccb5fb52518c48b342 -F ext/wasm/tests/opfs/concurrency/worker.js 90e51ff3e781a6e08f265cbaaa993bb10eb0b798893b78cf4d8a8a8b3b561392 +F ext/wasm/tests/opfs/concurrency/test.js 46c772bc18abb0fcbb058d57b5aaee9e7938f948ecdd802c6ca0850ad3519f92 +F ext/wasm/tests/opfs/concurrency/worker.js fc985ec86b70b057224e8caaa9c5a11892ea9b980a5c5da21b1efdf5f12bc3f6 F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 3b470c4c7a1fcc710e6b9eae32134c7f6c3f6008b24c7351257f66f5e8f70311 -R fd6275af0aa6341e83c30c2e83b929c6 +P 3b74ad9081daee560bf9b400e69a75abcc62dae7c5f55dcf46de84daae50ed9f +R 5251eca545de3a2827b98f8a138c1479 U stephan -Z 401ca0507277c8f3e4ba9832533ffae5 +Z e640850ae89db803157694e7fdf4c165 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cc74046192..d297924b93 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3b74ad9081daee560bf9b400e69a75abcc62dae7c5f55dcf46de84daae50ed9f +45c02ed21635f7ef45214ab5ec6230b6b8bd89e35ef5889db318523e1c679fea From 78649bb4215fe180cd78beae3b137bdfbbe24388 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 7 Mar 2026 04:19:08 +0000 Subject: [PATCH 134/197] Fix the mangling of the opfs async proxy script's URI caused by both OPFS VFSes modifying it to accound for sqlite3.dir. Add a link to speedtest1 with opfw-wl to index.html. FossilOrigin-Name: c1cb61f473a11a325ef421ba8edfb20257203688565f7db62309044be183af5f --- ext/wasm/api/opfs-common-shared.c-pp.js | 16 +++++++++------- ext/wasm/index.html | 5 +++++ manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 15eec1ff8d..ae750e75d3 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -465,13 +465,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ ? +urlParams.get('opfs-verbose') : 1; options.sanityChecks ??= urlParams.has('opfs-sanity-check'); - opfsUtil.proxyUri ??= "sqlite3-opfs-async-proxy.js"; - if( sqlite3.scriptInfo?.sqlite3Dir ){ - /* Doing this from one scope up, outside of this function, does - not work. */ - opfsUtil.proxyUri = ( - sqlite3.scriptInfo.sqlite3Dir + opfsUtil.proxyUri - ); + if( !opfsUtil.proxyUri ){ + opfsUtil.proxyUri = "sqlite3-opfs-async-proxy.js"; + if( sqlite3.scriptInfo?.sqlite3Dir ){ + /* Doing this from one scope up, outside of this function, does + not work. */ + opfsUtil.proxyUri = ( + sqlite3.scriptInfo.sqlite3Dir + opfsUtil.proxyUri + ); + } } options.proxyUri ??= opfsUtil.proxyUri; if('function' === typeof options.proxyUri){ diff --git a/ext/wasm/index.html b/ext/wasm/index.html index fd65dbc339..6f22dc150b 100644 --- a/ext/wasm/index.html +++ b/ext/wasm/index.html @@ -115,6 +115,11 @@ 64-bit): speedtest1-worker with the OPFS VFS preselected and configured for a moderate workload. +
  • speedtest1-worker?vfs=opfs-wl + (32-bit, + 64-bit): + speedtest1-worker with the + OPFS Web Locks VFS preselected and configured for a moderate workload.
  • speedtest1-worker?vfs=opfs-sahpool (32-bit, 64-bit): diff --git a/manifest b/manifest index 44ee1e7107..313bebc506 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Cleanups\sand\sdocs\sin\sthe\sopfs\svfs\sand\sits\sconcurrency\stester.\sExperimentally\sadd\ssqlite3.capi.sqlite3_js_retry_busy(),\swhich\sruns\sa\scallback\srepeatedly\suntil\sit\s_stops_\sreturning\s(or\sthrowing)\san\sSQLITE_BUSY\serror. -D 2026-03-07T03:32:17.361 +C Fix\sthe\smangling\sof\sthe\sopfs\sasync\sproxy\sscript's\sURI\scaused\sby\sboth\sOPFS\sVFSes\smodifying\sit\sto\saccound\sfor\ssqlite3.dir.\sAdd\sa\slink\sto\sspeedtest1\swith\sopfw-wl\sto\sindex.html. +D 2026-03-07T04:19:08.919 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js d58f16b8bf00401d954249d154c91abc4d4f54221f755d774cf5c4e8f83a1a9f +F ext/wasm/api/opfs-common-shared.c-pp.js 7ff4b6cfd486a9fff1781af9c1fe2e3f328fd2a6b3a2d7dd3d5f83979e2ca552 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -624,7 +624,7 @@ F ext/wasm/fiddle/fiddle-worker.js 6c72acac2d381480bc9f5eb538e3f2faf2c1f72dd4fcb F ext/wasm/fiddle/fiddle.js 84fd75967e0af8b69d3dd849818342227d0f81d13db92e0dcbc63649b31a4893 F ext/wasm/fiddle/index.c-pp.html 72c7e5517217960b3809648429ea396a7cbad0ffb2c92f6a2f5703abecb27317 F ext/wasm/index-dist.html db23748044e286773f2768eec287669501703b5d5f72755e8db73607dc54d290 -F ext/wasm/index.html 475bc283338749db4e3fbf24cf3f5aa020cc85a1fffb780d400a915fcb5f1756 +F ext/wasm/index.html 5bf6cf1b0a3c8b9f5f54d77f2219d7ae87a15162055ce308109c49b1dcab4239 F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b F ext/wasm/jaccwabyt/jaccwabyt.md 6aa90fa1a973d0ad10d077088bea163b241d8470c75eafdef87620a1de1dea41 F ext/wasm/mkdist.sh f8883b077a2ca47cf92e6f0ce305fbf72ca648c3501810125056c4b09c2d5554 x @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 3b74ad9081daee560bf9b400e69a75abcc62dae7c5f55dcf46de84daae50ed9f -R 5251eca545de3a2827b98f8a138c1479 +P 45c02ed21635f7ef45214ab5ec6230b6b8bd89e35ef5889db318523e1c679fea +R a0b14fb61a3f361676cb6a84638efe48 U stephan -Z e640850ae89db803157694e7fdf4c165 +Z 3353e988da2dca384c44895dc97fbee8 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d297924b93..988c55dc18 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -45c02ed21635f7ef45214ab5ec6230b6b8bd89e35ef5889db318523e1c679fea +c1cb61f473a11a325ef421ba8edfb20257203688565f7db62309044be183af5f From 237fce8205a8350dc933aa4d3a283a97f3ada829 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 7 Mar 2026 06:10:29 +0000 Subject: [PATCH 135/197] Extend the JS pre-bootstrapping configuration to include an option to disable inclusion of any given extension VFS (not the default VFSes, like memdb). The primary motivation for this is to give people who don't use OPFS to a way to keep the OPFS VFSes from loading their proxy workers, which are expensive. FossilOrigin-Name: 9a07eb7a941479510891d1444aacbeb440efaad3e9a13f186833618d8b60a8da --- ext/wasm/api/opfs-common-shared.c-pp.js | 4 +++ ext/wasm/api/sqlite3-api-prologue.js | 32 ++++++++++++------- ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js | 4 +++ ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js | 4 +++ ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 15 +++++---- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 3 ++ ext/wasm/tester1.c-pp.js | 28 ++++++++-------- manifest | 24 +++++++------- manifest.uuid | 2 +- 9 files changed, 70 insertions(+), 46 deletions(-) diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index ae750e75d3..11acf40bdc 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -21,6 +21,10 @@ */ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'use strict'; + if( sqlite3.config.disable?.vfs?.opfs && + sqlite3.config.disable.vfs['opfs-vfs'] ){ + return; + } const toss = sqlite3.util.toss, capi = sqlite3.capi, util = sqlite3.util, diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index d1055c1cfb..e71b6c9570 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -99,6 +99,13 @@ used in WASMFS-capable builds of the library (which the canonical builds do not include). + - `disable` (as of 3.53.0) may be an object with the following + properties: + - `vfs`, an object, may contain a map of VFS names to booleans. + Any mapping to falsy are disabled. The supported names + are: "kvvfs", "opfs", "opfs-sahpool", "opfs-wl". + - Other disabling options may be added in the future. + [^1] = This property may optionally be a function, in which case this function calls that function to fetch the value, enabling delayed evaluation. @@ -145,7 +152,8 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( ); return sqlite3ApiBootstrap.sqlite3; } - const config = Object.assign(Object.create(null),{ + const nu = (...obj)=>Object.assign(Object.create(null),...obj); + const config = nu({ exports: undefined, memory: undefined, bigIntEnabled: !!globalThis.BigInt64Array, @@ -162,7 +170,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( certain wasm.xWrap.resultAdapter()s. */ useStdAlloc: false - }, apiConfig || {}); + }, apiConfig); Object.assign(config, { allocExportName: config.useStdAlloc ? 'malloc' : 'sqlite3_malloc', @@ -195,7 +203,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( not documented are installed as 1-to-1 proxies for their C-side counterparts. */ - const capi = Object.create(null); + const capi = nu(); /** Holds state which are specific to the WASM-related infrastructure and glue code. @@ -204,7 +212,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( dynamically after the api object is fully constructed, so not all are documented in this file. */ - const wasm = Object.create(null); + const wasm = nu(); /** Internal helper for SQLite3Error ctor. */ const __rcStr = (rc)=>{ @@ -752,7 +760,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( toss: function(...args){throw new Error(args.join(' '))}, toss3, typedArrayPart: wasm.typedArrayPart, - nu: (...obj)=>Object.assign(Object.create(null),...obj), + nu, assert: function(arg,msg){ if( !arg ){ util.toss("Assertion failed:",msg); @@ -1009,7 +1017,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true; }; } - const rc = Object.create(null), ov = [0,0]; + const rc = nu(), ov = [0,0]; let i = 0, k; while((k = capi.sqlite3_compileoption_get(i++))){ f._opt(k,ov); @@ -1017,7 +1025,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( } return f._result = rc; }else if(Array.isArray(optName)){ - const rc = Object.create(null); + const rc = nu(); optName.forEach((v)=>{ rc[v] = capi.sqlite3_compileoption_used(v); }); @@ -1068,7 +1076,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( The memory lives in the WASM heap and can be used with routines such as wasm.poke() and wasm.heap8u().slice(). */ - wasm.pstack = Object.assign(Object.create(null),{ + wasm.pstack = nu({ /** Sets the current pstack position to the given pointer. Results are undefined if the passed-in value did not come from @@ -1290,7 +1298,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( // sqlite3__wasm_init_wasmfs() is not available return this.dir = ""; } - }.bind(Object.create(null)); + }.bind(nu()); /** Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a @@ -1665,7 +1673,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( default: return capi.SQLITE_MISUSE; } - }.bind(Object.create(null)); + }.bind(nu()); /** Given a (sqlite3_value*), this function attempts to convert it @@ -1899,7 +1907,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( if(rc) return SQLite3Error.toss(rc,arguments[2]+"() failed with code "+rc); const pv = wasm.peekPtr(this.ptr); return pv ? capi.sqlite3_value_to_js( pv, true ) : undefined; - }.bind(Object.create(null)); + }.bind(nu()); /** A wrapper around sqlite3_preupdate_new() which fetches the @@ -2013,7 +2021,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( This object is initially a placeholder which gets replaced by a build-generated object. */ - version: Object.create(null), + version: nu(), /** The library reserves the 'client' property for client-side use diff --git a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js index 0fdd7cb4cc..88f81226a6 100644 --- a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js @@ -28,6 +28,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ //#@policy error //#savepoint begin //#define kvvfs-v2-added-in=3.52.0 + /** kvvfs - the Key/Value VFS - is an SQLite3 VFS which delegates storage of its pages and metadata to a key-value store. @@ -85,6 +86,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ backups. */ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ + if( sqlite3.config.disable?.vfs?.kvvfs ){ + return; + } 'use strict'; const capi = sqlite3.capi, sqlite3_kvvfs_methods = capi.sqlite3_kvvfs_methods, diff --git a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js index c1fee5e1ab..689f53d4a7 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js @@ -55,6 +55,10 @@ */ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'use strict'; + if( sqlite3.config.disable?.vfs?.['opfs-sahpool'] ){ + return; + } + const toss = sqlite3.util.toss; const toss3 = sqlite3.util.toss3; const initPromises = Object.create(null) /* cache of (name:result) of VFS init results */; diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 349819b0e1..dbd786410a 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -34,10 +34,13 @@ */ 'use strict'; globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ + if( !sqlite3.opfs || sqlite3.config.disable?.vfs?.['opfs-wl'] ){ + return; + } const util = sqlite3.util, toss = sqlite3.util.toss; - const opfsUtil = sqlite3.opfs || toss("Missing sqlite3.opfs"); - + const opfsUtil = sqlite3.opfs; + const vfsName = 'opfs-wl'; /** installOpfsWlVfs() returns a Promise which, on success, installs an sqlite3_vfs named "opfs-wl", suitable for use with all sqlite3 APIs @@ -57,7 +60,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ sqlite3-vfs-opfs.c-pp.js:installOpfsVfs(). */ const installOpfsWlVfs = async function(options){ - options = opfsUtil.initOptions('opfs-wl',options); + options = opfsUtil.initOptions(vfsName,options); if( !options ) return sqlite3; const capi = sqlite3.capi, state = opfsUtil.createVfsState(), @@ -66,8 +69,8 @@ const installOpfsWlVfs = async function(options){ mTimeStart = opfsVfs.mTimeStart, mTimeEnd = opfsVfs.mTimeEnd, opRun = opfsVfs.opRun, - debug = (...args)=>sqlite3.config.debug("opfs-wl:",...args), - warn = (...args)=>sqlite3.config.warn("opfs-wl:",...args), + debug = (...args)=>sqlite3.config.debug(vfsName+":",...args), + warn = (...args)=>sqlite3.config.warn(vfsName+":",...args), __openFiles = opfsVfs.__openFiles; //debug("state",JSON.stringify(options)); @@ -123,7 +126,7 @@ const installOpfsWlVfs = async function(options){ }/*installOpfsWlVfs()*/; globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ return installOpfsWlVfs().catch((e)=>{ - sqlite3.config.warn("Ignoring inability to install the 'opfs-wl' sqlite3_vfs:",e); + sqlite3.config.warn("Ignoring inability to install the",vfsName,"sqlite3_vfs:",e); }); }); }/*sqlite3ApiBootstrap.initializers.push()*/); diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 05e6a3f09f..53619bfc92 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -20,6 +20,9 @@ */ 'use strict'; globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ + if( !sqlite3.opfs || sqlite3.config.disable?.vfs?.opfs ){ + return; + } const util = sqlite3.util, opfsUtil = sqlite3.opfs || sqlite3.util.toss("Missing sqlite3.opfs"); /** diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 8c0ba19165..6ed66d7853 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -66,15 +66,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule; const haveWasmCTests = ()=>{ return !!wasm.exports.sqlite3__wasm_test_intptr; }; - const hasOpfs = ()=>{ - return globalThis.FileSystemHandle - && globalThis.FileSystemDirectoryHandle - && globalThis.FileSystemFileHandle - && globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle - && navigator?.storage?.getDirectory; - }; let SQLite3 /* populated after module load */; + const hasOpfs = ()=>!!SQLite3?.oo1?.OpfsDb; { const mapToString = (v)=>{ @@ -3773,8 +3767,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule; //////////////////////////////////////////////////////////////////////// T.g('OPFS: Origin-Private File System', - (sqlite3)=>(sqlite3.capi.sqlite3_vfs_find("opfs") - || 'requires "opfs" VFS')) + (sqlite3)=>(hasOpfs() || 'requires "opfs" VFS')) .t({ name: 'OPFS db sanity checks', test: async function(sqlite3){ @@ -3914,7 +3907,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule; //////////////////////////////////////////////////////////////////////// T.g('OPFS SyncAccessHandle Pool VFS', - (sqlite3)=>(hasOpfs() || "requires OPFS APIs")) + (sqlite3)=>(!!sqlite3.installOpfsSAHPoolVfs || "requires OPFS SAH Pool APIs")) .t({ name: 'SAH sanity checks', test: async function(sqlite3){ @@ -4430,12 +4423,17 @@ globalThis.sqlite3InitModule = sqlite3InitModule; //////////////////////////////////////////////////////////////////////// log("Loading and initializing sqlite3 WASM module..."); - if(0){ + if(1){ globalThis.sqlite3ApiConfig = { - debug: ()=>{}, - log: ()=>{}, - warn: ()=>{}, - error: ()=>{} + //debug: ()=>{}, log: ()=>{}, warn: ()=>{}, error: ()=>{}, + disable: { + vfs: { + kvvfs: false, + opfs: false, + "opfs-sahpool": false, + "opfs-wl": false + } + } } } //#if not target:es6-module diff --git a/manifest b/manifest index 313bebc506..d2f8ed2331 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\smangling\sof\sthe\sopfs\sasync\sproxy\sscript's\sURI\scaused\sby\sboth\sOPFS\sVFSes\smodifying\sit\sto\saccound\sfor\ssqlite3.dir.\sAdd\sa\slink\sto\sspeedtest1\swith\sopfw-wl\sto\sindex.html. -D 2026-03-07T04:19:08.919 +C Extend\sthe\sJS\spre-bootstrapping\sconfiguration\sto\sinclude\san\soption\sto\sdisable\sinclusion\sof\sany\sgiven\sextension\sVFS\s(not\sthe\sdefault\sVFSes,\slike\smemdb).\sThe\sprimary\smotivation\sfor\sthis\sis\sto\sgive\speople\swho\sdon't\suse\sOPFS\sto\sa\sway\sto\skeep\sthe\sOPFS\sVFSes\sfrom\sloading\stheir\sproxy\sworkers,\swhich\sare\sexpensive. +D 2026-03-07T06:10:29.452 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,21 +585,21 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js 7ff4b6cfd486a9fff1781af9c1fe2e3f328fd2a6b3a2d7dd3d5f83979e2ca552 +F ext/wasm/api/opfs-common-shared.c-pp.js 49f4b044dfb3becd8c926ef42b7494da680e5ac878c6d10ef510b66f74ad55a1 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f F ext/wasm/api/sqlite3-api-glue.c-pp.js 9b33e3ee467791dec4fd1b444b12a8545dfbb6c8b28ac651c7bdc7661a3b5a5c F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c41db98a22b534c15e543cfa -F ext/wasm/api/sqlite3-api-prologue.js c616bff3bdff1fcbb6a39bd429a96de9c3e5f1e8c0d287083cea5e98e8b0151c +F ext/wasm/api/sqlite3-api-prologue.js df30ccb31affb2bbe9a2de63d6276c7ec1192ec732e79a0138449a19ec04b988 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js c2236c9037ccac368be6eeed3e5f6ed3cefed0d20539c9092139f27a76aaf1ba F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d -F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490 -F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9 -F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js c518aee3c2f537ae73aa3afd67463d1eb63db0559a41d64fe4d1361b9966b52f -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 872c29aa760b05c2703185368a39b4b2e1a8abf15c29ee7e23ee8ca7cdcbed9d +F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js f907fa712d1c9d98a3c08393f3e97a664857782da11670e129d39e383f45f968 +F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js cf5fba74978d3e0983f68505d9695ee7836853855590a92ccc5a96e27db5350b +F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 743650cfefed0df900171971065c2d618e5652177a98844ddb6695c70149968e +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 4b02d7063d00e2d4f42d4ca79a8a0bca1b275257e135bc154d35b701ed1d234a F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66 @@ -644,7 +644,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c986e48af7d3d720fcd244 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb -F ext/wasm/tester1.c-pp.js a4e79fbf63bb3255d2b8ffc1cd538c115d2f6b599bc324904c80f6644379a284 +F ext/wasm/tester1.c-pp.js 31cde3c4db4b955d5554c21cb0aa6ec3a0743b03d7c5262a38bfa303e7955942 F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226 F ext/wasm/tests/opfs/concurrency/test.js 46c772bc18abb0fcbb058d57b5aaee9e7938f948ecdd802c6ca0850ad3519f92 F ext/wasm/tests/opfs/concurrency/worker.js fc985ec86b70b057224e8caaa9c5a11892ea9b980a5c5da21b1efdf5f12bc3f6 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 45c02ed21635f7ef45214ab5ec6230b6b8bd89e35ef5889db318523e1c679fea -R a0b14fb61a3f361676cb6a84638efe48 +P c1cb61f473a11a325ef421ba8edfb20257203688565f7db62309044be183af5f +R bd137899af2cd4094f0a4f5a1f4094af U stephan -Z 3353e988da2dca384c44895dc97fbee8 +Z 147d7dd643bc15130deceeb0e6d52d6f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 988c55dc18..06ded776dc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c1cb61f473a11a325ef421ba8edfb20257203688565f7db62309044be183af5f +9a07eb7a941479510891d1444aacbeb440efaad3e9a13f186833618d8b60a8da From b4f257f5e0ce7913141a925c65118a0da06bb3e4 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 7 Mar 2026 11:23:11 +0000 Subject: [PATCH 136/197] Fix another memory leak following OOM in the decimal extension. FossilOrigin-Name: 414f6dbc09c2a3cf04ccdfd8f11eecb7ef781facff979ae4236a452913001391 --- ext/misc/decimal.c | 6 ++++-- manifest | 13 ++++++------- manifest.uuid | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c index e2709b3017..541ef33768 100644 --- a/ext/misc/decimal.c +++ b/ext/misc/decimal.c @@ -462,6 +462,7 @@ static void decimalCmpFunc( static void decimal_expand(Decimal *p, int nDigit, int nFrac){ int nAddSig; int nAddFrac; + signed char *a; if( p==0 ) return; nAddFrac = nFrac - p->nFrac; nAddSig = (nDigit - p->nDigit) - nAddFrac; @@ -469,11 +470,12 @@ static void decimal_expand(Decimal *p, int nDigit, int nFrac){ #if SQLITE_DECIMAL_MAX_DIGIT+0>10 if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; } #endif - p->a = sqlite3_realloc64(p->a, nDigit+1); - if( p->a==0 ){ + a = sqlite3_realloc64(p->a, nDigit+1); + if( a==0 ){ p->oom = 1; return; } + p->a = a; if( nAddSig ){ memmove(p->a+nAddSig, p->a, p->nDigit); memset(p->a, 0, nAddSig); diff --git a/manifest b/manifest index cb459b8619..4790d7f179 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhancements\sand\sfixes\sto\ssome\sof\sthe\sextensions\sused\sin\sthe\sCLI\sso\sthat\nthey\scan\sbe\sfuzzed\susing\sdbsqlfuzz. -D 2026-03-07T02:42:27.506 +C Fix\sanother\smemory\sleak\sfollowing\sOOM\sin\sthe\sdecimal\sextension. +D 2026-03-07T11:23:11.290 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -370,7 +370,7 @@ F ext/misc/completion.c 99589a9f04113e9a169312d132730131963451a30abd6704d7808623 F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565 F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680 -F ext/misc/decimal.c 30cefa0e3324a5378cd92338ca76b4fd2f4bdd9412d28c8d8749767e64780397 +F ext/misc/decimal.c 0b6273955de8fd42fa54723e4976a8306965dd398e7134a8d9d65787d07d87a9 F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b F ext/misc/fileio.c 33165b3cd99f83dcd333a338eb51491f6b01c8d96cb6ae81f96a6a096834e030 @@ -2189,9 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 94a650b169bfd1056995c1cfe584d3d92667bce5e9cf93e6381607ed87251bf3 4214485b2fe4b95d9440008158d458b4b957a111f201965de1a518623589fd79 -R fb41484273ea6a90bfb888fdbf07d432 -T +closed 4214485b2fe4b95d9440008158d458b4b957a111f201965de1a518623589fd79 +P d800ea06d231957cf571327d9eaf81564d5439aeee099987101050a41f9676c0 +R 9eaddb6689944d3172f39000a66b14ba U drh -Z 8bf22c85e2b30a99cb46d02f1a65fdd7 +Z 7cd74c4c551cb8d08a9f4d015d3c61ad # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 327dd9e708..59faf6ecfa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d800ea06d231957cf571327d9eaf81564d5439aeee099987101050a41f9676c0 +414f6dbc09c2a3cf04ccdfd8f11eecb7ef781facff979ae4236a452913001391 From cde22e88065f4016e2de32534ab1b46b0617fb75 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 7 Mar 2026 12:00:56 +0000 Subject: [PATCH 137/197] An attempt to get the CLI build to work with mingw32. [forum:/forumpost/086cb1ef66|Forum post 086cb1ef66]. FossilOrigin-Name: d95b9e7c1746b9cbd067aa65806b1f74d0dfe77ab6084cb3da9ef2242cac9134 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 4790d7f179..80db6ffee4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sanother\smemory\sleak\sfollowing\sOOM\sin\sthe\sdecimal\sextension. -D 2026-03-07T11:23:11.290 +C An\sattempt\sto\sget\sthe\sCLI\sbuild\sto\swork\swith\smingw32.\n[forum:/forumpost/086cb1ef66|Forum\spost\s086cb1ef66]. +D 2026-03-07T12:00:56.357 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -730,7 +730,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576 -F src/shell.c.in 1845b4c2028b6a264ec994628ac34b36c35eefbe61d6fb6a0370643f0e458aa9 +F src/shell.c.in d74e8b78bbbf0297e427c7e76abdbfb2769d5e9d67fec69806b1812c56316d8c F src/sqlite.h.in 307c7c1d1a71071b8572e8c6943f7a2e9483b008afb375758871881366f33e59 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d800ea06d231957cf571327d9eaf81564d5439aeee099987101050a41f9676c0 -R 9eaddb6689944d3172f39000a66b14ba +P 414f6dbc09c2a3cf04ccdfd8f11eecb7ef781facff979ae4236a452913001391 +R fb5997ea5564a7223207fc543e841a6b U drh -Z 7cd74c4c551cb8d08a9f4d015d3c61ad +Z 2f19e76929c8a5d942993c71d8f7951f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 59faf6ecfa..042d9ede3c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -414f6dbc09c2a3cf04ccdfd8f11eecb7ef781facff979ae4236a452913001391 +d95b9e7c1746b9cbd067aa65806b1f74d0dfe77ab6084cb3da9ef2242cac9134 diff --git a/src/shell.c.in b/src/shell.c.in index e67879b8ec..a9dd158aff 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -12776,7 +12776,7 @@ static int vfstraceOut(const char *z, void *pArg){ ** UTF8, then invoke the traditional main() entry point which is ** renamed using a #define to utf8_main() . */ -#if defined(_WIN32) && !defined(main) +#if defined(_WIN32) && !defined(__MINGW32__) && !defined(main) # define main utf8_main /* Rename entry point to utf_main() */ int SQLITE_CDECL utf8_main(int,char**); /* Forward declaration */ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ From ac2617019169ba50f5448db72681113e8e60eaed Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 7 Mar 2026 15:15:37 +0000 Subject: [PATCH 138/197] Minor typo fixes from [forum:8fc8bc34291d6f45|forum post 8fc8bc34291d6f45]. FossilOrigin-Name: c8fb88c19ed91dc5e205f719aedb895f7ceb62b113f61ec94cc6e435051da15c --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqlite.h.in | 18 +++++++++--------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 80db6ffee4..ab56ac8ef7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C An\sattempt\sto\sget\sthe\sCLI\sbuild\sto\swork\swith\smingw32.\n[forum:/forumpost/086cb1ef66|Forum\spost\s086cb1ef66]. -D 2026-03-07T12:00:56.357 +C Minor\stypo\sfixes\sfrom\s[forum:8fc8bc34291d6f45|forum\spost\s8fc8bc34291d6f45]. +D 2026-03-07T15:15:37.009 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -731,7 +731,7 @@ F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576 F src/shell.c.in d74e8b78bbbf0297e427c7e76abdbfb2769d5e9d67fec69806b1812c56316d8c -F src/sqlite.h.in 307c7c1d1a71071b8572e8c6943f7a2e9483b008afb375758871881366f33e59 +F src/sqlite.h.in 4d657846d68a58b028f0c4c331b9d3b4a79306f25c3b0d04fb56060343f73d85 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca F src/sqliteInt.h 1c7f23ab9d6efdf3dc434880b6320f158937284f6e2cebd2a024def0c749cb04 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 414f6dbc09c2a3cf04ccdfd8f11eecb7ef781facff979ae4236a452913001391 -R fb5997ea5564a7223207fc543e841a6b -U drh -Z 2f19e76929c8a5d942993c71d8f7951f +P d95b9e7c1746b9cbd067aa65806b1f74d0dfe77ab6084cb3da9ef2242cac9134 +R cb1a2c68558e309e187139402ca5ab2b +U stephan +Z 961086411a3f50c7f371dac5d105ca77 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 042d9ede3c..42c20143a2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d95b9e7c1746b9cbd067aa65806b1f74d0dfe77ab6084cb3da9ef2242cac9134 +c8fb88c19ed91dc5e205f719aedb895f7ceb62b113f61ec94cc6e435051da15c diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 0f208e7373..f1d0f73a1b 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4487,8 +4487,8 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** ** The preferred routine to use is [sqlite3_prepare_v2()]. The ** [sqlite3_prepare()] interface is legacy and should be avoided. -** [sqlite3_prepare_v3()] has an extra -** [SQLITE_PREPARE_FROM_DDL|"prepFlags" option] that is some times +** [sqlite3_prepare_v3()] has an extra +** [SQLITE_PREPARE_FROM_DDL|"prepFlags" option] that is sometimes ** needed for special purpose or to pass along security restrictions. ** ** The use of the UTF-8 interfaces is preferred, as SQLite currently @@ -6495,7 +6495,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** of [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], ** or [SQLITE_UTF16LE]. ^The special value [SQLITE_UTF8_ZT] means that ** the result text is both UTF-8 and zero-terminated. In other words, -** SQLITE_UTF8_ZT means that the Z array holds at least N+1 byes and that +** SQLITE_UTF8_ZT means that the Z array holds at least N+1 bytes and that ** the Z[N] is zero. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. @@ -8862,10 +8862,10 @@ void sqlite3_str_free(sqlite3_str*); ** ^This method can be used, for example, to add whitespace indentation. ** ** ^The [sqlite3_str_reset(X)] method resets the string under construction -** inside [sqlite3_str] object X back to zero bytes in length. +** inside [sqlite3_str] object X back to zero bytes in length. ** ** ^The [sqlite3_str_truncate(X,N)] method changes the length of the string -** under construction to be N bytes are less. This routine is a no-op if +** under construction to be N bytes or less. This routine is a no-op if ** N is negative or if the string is already N bytes or smaller in size. ** ** These methods do not return a result code. ^If an error occurs, that fact @@ -10729,7 +10729,7 @@ int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal); ** the variable that pOut points to is unchanged. ** ** See also: [sqlite3_stmt_scanstatus_reset()] and the -** [nexec and ncycle] columnes of the [bytecode virtual table]. +** [nexec and ncycle] columns of the [bytecode virtual table]. */ int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ @@ -11285,17 +11285,17 @@ int sqlite3_deserialize( ** values [SQLITE_STATIC] or [SQLITE_TRANSIENT], then SQLite will invoke ** the function X with argument D when it is finished using the data in P. ** The call to X(D) is a destructor for the array P. The destructor X(D) -** is invoked even if the call to sqlite3_carray_bind() fails. If the X +** is invoked even if the call to sqlite3_carray_bind_v2() fails. If the X ** parameter is the special-case value [SQLITE_STATIC], then SQLite assumes ** that the data static and the destructor is never invoked. If the X ** parameter is the special-case value [SQLITE_TRANSIENT], then ** sqlite3_carray_bind_v2() makes its own private copy of the data prior ** to returning and never invokes the destructor X. ** -** The sqlite3_carray_bind() function works the same as sqlite_carray_bind_v2() +** The sqlite3_carray_bind() function works the same as sqlite3_carray_bind_v2() ** with a D parameter set to P. In other words, ** sqlite3_carray_bind(S,I,P,N,F,X) is same as -** sqlite3_carray_bind(S,I,P,N,F,X,P). +** sqlite3_carray_bind_v2(S,I,P,N,F,X,P). */ int sqlite3_carray_bind_v2( sqlite3_stmt *pStmt, /* Statement to be bound */ From 85ee7e15e309e2aafb546dc7ded306da4462be33 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 7 Mar 2026 17:50:32 +0000 Subject: [PATCH 139/197] Fix harmless compiler warnings on Windows. FossilOrigin-Name: 358d78da75033d4d1fcb27b5f95c940dcc306cdf34ef999262da901e71f2b306 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/threads.c | 1 + src/where.c | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index ab56ac8ef7..e1b4eafa73 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\stypo\sfixes\sfrom\s[forum:8fc8bc34291d6f45|forum\spost\s8fc8bc34291d6f45]. -D 2026-03-07T15:15:37.009 +C Fix\sharmless\scompiler\swarnings\son\sWindows. +D 2026-03-07T17:50:32.369 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -787,7 +787,7 @@ F src/test_vdbecov.c 5c426d9cd2b351f5f9ceb30cabf8c64a63bfcad644c507e0bd9ce2f6ae1 F src/test_vfs.c b4135c1308516adf0dfd494e6d6c33114e03732be899eace0502919b674586b5 F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8ea72 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 -F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c +F src/threads.c 85d8b9f05f78211c61e3739ab5db761d7118766d1916ae7f2764735106bc4e13 F src/tokenize.c f297bbf02037639e7a93b37d9c6e4415b3de1273395ee8fa8183e741e1e7fb72 F src/treeview.c feaa59f14db4f7b5aacca9c5ad5aeb562c1f98262c1ffd74371f4186ade91fc5 F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20 @@ -811,7 +811,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab F src/wal.c 88d94fd15a75f6eda831fa32d1148a267ea37bf0a4b69829a73dfde06244b08f F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 -F src/where.c d17b2ed5977d823bf0af8e78a029c05539b82f350cdf07e3427c288ce655e4ab +F src/where.c 406d9ec8d12f646c28c4b4a645ea20329eb343b19cfa3dcd8aab938066c4ae66 F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da F src/wherecode.c 783ecd30061c875c919a5163e4b55f9a0eccdaf7c9b17ad2908a1668a8766bc4 F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d95b9e7c1746b9cbd067aa65806b1f74d0dfe77ab6084cb3da9ef2242cac9134 -R cb1a2c68558e309e187139402ca5ab2b -U stephan -Z 961086411a3f50c7f371dac5d105ca77 +P c8fb88c19ed91dc5e205f719aedb895f7ceb62b113f61ec94cc6e435051da15c +R 850172d46551c7d57e3d40eea58d626b +U drh +Z dfa517086561e3dc7a550e4649699f74 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 42c20143a2..5449291ae9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c8fb88c19ed91dc5e205f719aedb895f7ceb62b113f61ec94cc6e435051da15c +358d78da75033d4d1fcb27b5f95c940dcc306cdf34ef999262da901e71f2b306 diff --git a/src/threads.c b/src/threads.c index f128d69fc2..c7b2e893f4 100644 --- a/src/threads.c +++ b/src/threads.c @@ -196,6 +196,7 @@ int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ rc = sqlite3Win32Wait((HANDLE)p->tid); assert( rc!=WAIT_IO_COMPLETION ); bRc = CloseHandle((HANDLE)p->tid); + (void)bRc; /* Prevent warning when assert() is a no-op */ assert( bRc ); } if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; diff --git a/src/where.c b/src/where.c index 216a75c233..085ba8aa8d 100644 --- a/src/where.c +++ b/src/where.c @@ -7554,7 +7554,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ){ int r1 = pParse->nMem+1; int j, op; - int addrIfNull; + int addrIfNull = 0; /* Init to avoid false-positive compiler warning */ if( pLevel->iLeftJoin ){ addrIfNull = sqlite3VdbeAddOp2(v, OP_IfNullRow, pLevel->iIdxCur, r1); } From 13a494fddd47fcdec9274fafdf3c72bf00017363 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 7 Mar 2026 21:07:18 +0000 Subject: [PATCH 140/197] Give the fuzzcheck test program access to all the same extensions that dbsqlfuzz has access to. FossilOrigin-Name: d9c23b49e355233bbfcdc8305dcae21640e66a0bbf1daed0dd3f9d132c1ef69f --- Makefile.msc | 11 +++++++++++ main.mk | 40 +++++++++++++++++++++++++++------------- manifest | 16 ++++++++-------- manifest.uuid | 2 +- test/fuzzcheck.c | 24 ++++++++++++++++++++++-- 5 files changed, 69 insertions(+), 24 deletions(-) diff --git a/Makefile.msc b/Makefile.msc index 763616ce93..368a84be22 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1719,6 +1719,7 @@ FUZZERSHELL_COMPILE_OPTS = FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -I$(TOP)\test -I$(TOP)\ext\recover FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_MEMSYS5 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OSS_FUZZ +FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_DECIMAL_MAX_DIGIT=1000 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_CARRAY FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB @@ -1765,7 +1766,17 @@ FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\fuzzinvariants.c FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\vt02.c FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\dbdata.c FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\sqlite3recover.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\base64.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\base85.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\completion.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\decimal.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\ieee754.c FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\randomjson.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\regexp.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\series.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\shathree.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\sha1.c +FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\stmtrand.c OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION diff --git a/main.mk b/main.mk index 46d646d03a..aca5fc7856 100644 --- a/main.mk +++ b/main.mk @@ -957,6 +957,7 @@ FUZZCHECK_OPT += -I$(TOP)/test FUZZCHECK_OPT += -I$(TOP)/ext/recover FUZZCHECK_OPT += \ -DSQLITE_OSS_FUZZ \ + -DSQLITE_DECIMAL_MAX_DIGIT=1000 \ -DSQLITE_ENABLE_BYTECODE_VTAB \ -DSQLITE_ENABLE_CARRAY \ -DSQLITE_ENABLE_DBPAGE_VTAB \ @@ -988,13 +989,26 @@ FUZZCHECK_OPT += \ -DSQLITE_STRICT_SUBTYPE=1 \ -DSQLITE_STATIC_RANDOMJSON -FUZZCHECK_SRC += $(TOP)/test/fuzzcheck.c -FUZZCHECK_SRC += $(TOP)/test/ossfuzz.c -FUZZCHECK_SRC += $(TOP)/test/fuzzinvariants.c -FUZZCHECK_SRC += $(TOP)/ext/recover/dbdata.c -FUZZCHECK_SRC += $(TOP)/ext/recover/sqlite3recover.c -FUZZCHECK_SRC += $(TOP)/test/vt02.c -FUZZCHECK_SRC += $(TOP)/ext/misc/randomjson.c +FUZZCHECK_SRC = sqlite3.c \ + $(TOP)/test/fuzzcheck.c \ + $(TOP)/test/ossfuzz.c \ + $(TOP)/test/fuzzinvariants.c \ + $(TOP)/ext/recover/dbdata.c \ + $(TOP)/ext/recover/sqlite3recover.c \ + $(TOP)/test/vt02.c \ + $(TOP)/ext/misc/base64.c \ + $(TOP)/ext/misc/base85.c \ + $(TOP)/ext/misc/completion.c \ + $(TOP)/ext/misc/decimal.c \ + $(TOP)/ext/misc/ieee754.c \ + $(TOP)/ext/misc/randomjson.c \ + $(TOP)/ext/misc/regexp.c \ + $(TOP)/ext/misc/series.c \ + $(TOP)/ext/misc/shathree.c \ + $(TOP)/ext/misc/sha1.c \ + $(TOP)/ext/misc/stmtrand.c + +FUZZCHECK_DEP = sqlite3.h DBFUZZ_OPT = ST_OPT = -DSQLITE_OS_KV_OPTIONAL @@ -2261,23 +2275,23 @@ fuzzershell$(T.exe): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h fuzzy: fuzzershell$(T.exe) xbin: fuzzershell$(T.exe) -fuzzcheck$(T.exe): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP) - $(T.link) -o $@ $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(LDFLAGS.libsqlite3) +fuzzcheck$(T.exe): $(FUZZCHECK_SRC) $(FUZZCHECK_DEP) + $(T.link) -o $@ $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) $(LDFLAGS.libsqlite3) fuzzy: fuzzcheck$(T.exe) xbin: fuzzcheck$(T.exe) # -fsanitize=... flags for fuzzcheck-asan. CFLAGS.fuzzcheck-asan.fsanitize ?= -fsanitize=address -fuzzcheck-asan$(T.exe): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP) +fuzzcheck-asan$(T.exe): $(FUZZCHECK_SRC) $(FUZZCHECK_DEP) $(T.link) -o $@ $(CFLAGS.fuzzcheck-asan.fsanitize) $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) \ - sqlite3.c $(LDFLAGS.libsqlite3) + $(LDFLAGS.libsqlite3) fuzzy: fuzzcheck-asan$(T.exe) xbin: fuzzcheck-asan$(T.exe) -fuzzcheck-ubsan$(T.exe): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP) +fuzzcheck-ubsan$(T.exe): $(FUZZCHECK_SRC) $(FUZZCHECK_DEP) $(T.link) -o $@ -fsanitize=undefined $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) \ - sqlite3.c $(LDFLAGS.libsqlite3) + $(LDFLAGS.libsqlite3) fuzzy: fuzzcheck-ubsan$(T.exe) xbin: fuzzcheck-ubsan$(T.exe) diff --git a/manifest b/manifest index e1b4eafa73..3964e7e066 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C Fix\sharmless\scompiler\swarnings\son\sWindows. -D 2026-03-07T17:50:32.369 +C Give\sthe\sfuzzcheck\stest\sprogram\saccess\sto\sall\sthe\ssame\sextensions\sthat\ndbsqlfuzz\shas\saccess\sto. +D 2026-03-07T21:07:18.432 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0 -F Makefile.msc 174764cb7e80c80f9003c46b3e388d74c68c8c40230208904b3af8fcabee5f4e +F Makefile.msc d6448b1066932640e0ab2b01376c4ee7615a2b978c3c92e010f8fe222183c201 F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec F VERSION ed5325177122f86b7a25c21bee36fda8171a34ab86e4c72007798d7837a752be F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5 @@ -651,7 +651,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2 F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61 F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0 -F main.mk e1a03e9206f6a042a9147035915cb944e9242d570779bc3ccd7ed6a39df10cae +F main.mk 4aad7346b8a3b82462db63a7ad1657162cf2619738c7acb0ef7d06507344a22e F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -1238,7 +1238,7 @@ F test/fuzz3.test 70ba57260364b83e964707b9d4b5625284239768ab907dd387c740c0370ce3 F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634 F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830 F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2 -F test/fuzzcheck.c 9096506277f33cc242eb59743c409c81306492b6ebb84571198f864e536ebe22 +F test/fuzzcheck.c 207d3d1c1d578928f16dec20df781c5d13c2fd4694b4d70e72242f4dcb799830 F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517 F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P c8fb88c19ed91dc5e205f719aedb895f7ceb62b113f61ec94cc6e435051da15c -R 850172d46551c7d57e3d40eea58d626b +P 358d78da75033d4d1fcb27b5f95c940dcc306cdf34ef999262da901e71f2b306 +R 5e16e73b2cbd96262b64b9972a9ecca5 U drh -Z dfa517086561e3dc7a550e4649699f74 +Z 607592826a2b890309bb03fac2620dab # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5449291ae9..900630c0a5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -358d78da75033d4d1fcb27b5f95c940dcc306cdf34ef999262da901e71f2b306 +d9c23b49e355233bbfcdc8305dcae21640e66a0bbf1daed0dd3f9d132c1ef69f diff --git a/test/fuzzcheck.c b/test/fuzzcheck.c index f056d2d93a..46328fb14a 100644 --- a/test/fuzzcheck.c +++ b/test/fuzzcheck.c @@ -169,8 +169,18 @@ static struct GlobalVars { /* ** Include various extensions. */ -extern int sqlite3_vt02_init(sqlite3*,char**,const sqlite3_api_routines*); -extern int sqlite3_randomjson_init(sqlite3*,char**,const sqlite3_api_routines*); +extern int sqlite3_vt02_init(sqlite3*,char**,void*); +extern int sqlite3_randomjson_init(sqlite3*,char**,void*); +extern int sqlite3_series_init(sqlite3*,char**,void*); +extern int sqlite3_base64_init(sqlite3*,char**,void*); +extern int sqlite3_base85_init(sqlite3*,char**,void*); +extern int sqlite3_completion_init(sqlite3*,char**,void*); +extern int sqlite3_decimal_init(sqlite3*,char**,void*); +extern int sqlite3_ieee_init(sqlite3*,char**,void*); +extern int sqlite3_regexp_init(sqlite3*,char**,void*); +extern int sqlite3_shathree_init(sqlite3*,char**,void*); +extern int sqlite3_sha_init(sqlite3*,char**,void*); +extern int sqlite3_stmtrand_init(sqlite3*,char**,void*); /* ** Print an error message and quit. @@ -1382,6 +1392,16 @@ int runCombinedDbSqlInput( /* Activate extensions */ sqlite3_randomjson_init(cx.db, 0, 0); + sqlite3_series_init(cx.db, 0, 0); + sqlite3_base64_init(cx.db, 0, 0); + sqlite3_base85_init(cx.db, 0, 0); + sqlite3_completion_init(cx.db, 0, 0); + sqlite3_decimal_init(cx.db, 0, 0); + sqlite3_ieee_init(cx.db, 0, 0); + sqlite3_regexp_init(cx.db, 0, 0); + sqlite3_shathree_init(cx.db, 0, 0); + sqlite3_sha_init(cx.db, 0, 0); + sqlite3_stmtrand_init(cx.db, 0, 0); /* Add support for sqlite_dbdata and sqlite_dbptr virtual tables used ** by the recovery API */ From eac7cd634df798e641d1fc4b58c849e13442f725 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 7 Mar 2026 22:37:28 +0000 Subject: [PATCH 141/197] Use the UINT64_C() macro rather than the LLU suffix on integer literals for portability to older Microsoft compilers. [forum:/forumpost/0a9ffaff6fcdedb3|Forum thread 0a9ffaff6fcdedb3]. FossilOrigin-Name: 27be26566fdb4d01c44dc111f1c18c835797de0990d4fcc876e91edc216e9e93 --- manifest | 14 +++---- manifest.uuid | 2 +- src/sqliteInt.h | 2 - src/util.c | 106 ++++++++++++++++++++++++------------------------ 4 files changed, 61 insertions(+), 63 deletions(-) diff --git a/manifest b/manifest index 3964e7e066..392814254e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Give\sthe\sfuzzcheck\stest\sprogram\saccess\sto\sall\sthe\ssame\sextensions\sthat\ndbsqlfuzz\shas\saccess\sto. -D 2026-03-07T21:07:18.432 +C Use\sthe\sUINT64_C()\smacro\srather\sthan\sthe\sLLU\ssuffix\son\sinteger\sliterals\nfor\sportability\sto\solder\sMicrosoft\scompilers.\n[forum:/forumpost/0a9ffaff6fcdedb3|Forum\sthread\s0a9ffaff6fcdedb3]. +D 2026-03-07T22:37:28.390 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -734,7 +734,7 @@ F src/shell.c.in d74e8b78bbbf0297e427c7e76abdbfb2769d5e9d67fec69806b1812c56316d8 F src/sqlite.h.in 4d657846d68a58b028f0c4c331b9d3b4a79306f25c3b0d04fb56060343f73d85 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h 1c7f23ab9d6efdf3dc434880b6320f158937284f6e2cebd2a024def0c749cb04 +F src/sqliteInt.h 9716721fb57e32938a1d30a84560ce7633c63860a2209e188c87afad15d4b464 F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -794,7 +794,7 @@ F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20 F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c eccfa8b3b414bb64c6543421c9fd10e5f07e103baae36427a273a9131527694c +F src/util.c 0cb2e590e9dcac6807352017fcbf5a52e0f836d74a338cb8c02ee3162bcf6508 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 358d78da75033d4d1fcb27b5f95c940dcc306cdf34ef999262da901e71f2b306 -R 5e16e73b2cbd96262b64b9972a9ecca5 +P d9c23b49e355233bbfcdc8305dcae21640e66a0bbf1daed0dd3f9d132c1ef69f +R 9d2dec494ff9f4831260cc9b7a06a387 U drh -Z 607592826a2b890309bb03fac2620dab +Z 3b9c42eed985a9a23d549d066c314144 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 900630c0a5..60025ac28b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d9c23b49e355233bbfcdc8305dcae21640e66a0bbf1daed0dd3f9d132c1ef69f +27be26566fdb4d01c44dc111f1c18c835797de0990d4fcc876e91edc216e9e93 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c4a8768615..26a1947824 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -246,9 +246,7 @@ /* ** Include standard header files as necessary */ -#ifdef HAVE_STDINT_H #include -#endif #ifdef HAVE_INTTYPES_H #include #endif diff --git a/src/util.c b/src/util.c index 071029173d..0ffed16c0b 100644 --- a/src/util.c +++ b/src/util.c @@ -515,61 +515,61 @@ static u64 sqlite3Multiply128(u64 a, u64 b){ */ static u64 powerOfTen(int p){ static const u64 aBase[] = { - 0x8000000000000000LLU, /* 0: 1.0e+0 << 63 */ - 0xa000000000000000LLU, /* 1: 1.0e+1 << 60 */ - 0xc800000000000000LLU, /* 2: 1.0e+2 << 57 */ - 0xfa00000000000000LLU, /* 3: 1.0e+3 << 54 */ - 0x9c40000000000000LLU, /* 4: 1.0e+4 << 50 */ - 0xc350000000000000LLU, /* 5: 1.0e+5 << 47 */ - 0xf424000000000000LLU, /* 6: 1.0e+6 << 44 */ - 0x9896800000000000LLU, /* 7: 1.0e+7 << 40 */ - 0xbebc200000000000LLU, /* 8: 1.0e+8 << 37 */ - 0xee6b280000000000LLU, /* 9: 1.0e+9 << 34 */ - 0x9502f90000000000LLU, /* 10: 1.0e+10 << 30 */ - 0xba43b74000000000LLU, /* 11: 1.0e+11 << 27 */ - 0xe8d4a51000000000LLU, /* 12: 1.0e+12 << 24 */ - 0x9184e72a00000000LLU, /* 13: 1.0e+13 << 20 */ - 0xb5e620f480000000LLU, /* 14: 1.0e+14 << 17 */ - 0xe35fa931a0000000LLU, /* 15: 1.0e+15 << 14 */ - 0x8e1bc9bf04000000LLU, /* 16: 1.0e+16 << 10 */ - 0xb1a2bc2ec5000000LLU, /* 17: 1.0e+17 << 7 */ - 0xde0b6b3a76400000LLU, /* 18: 1.0e+18 << 4 */ - 0x8ac7230489e80000LLU, /* 19: 1.0e+19 >> 0 */ - 0xad78ebc5ac620000LLU, /* 20: 1.0e+20 >> 3 */ - 0xd8d726b7177a8000LLU, /* 21: 1.0e+21 >> 6 */ - 0x878678326eac9000LLU, /* 22: 1.0e+22 >> 10 */ - 0xa968163f0a57b400LLU, /* 23: 1.0e+23 >> 13 */ - 0xd3c21bcecceda100LLU, /* 24: 1.0e+24 >> 16 */ - 0x84595161401484a0LLU, /* 25: 1.0e+25 >> 20 */ - 0xa56fa5b99019a5c8LLU, /* 26: 1.0e+26 >> 23 */ + UINT64_C(0x8000000000000000), /* 0: 1.0e+0 << 63 */ + UINT64_C(0xa000000000000000), /* 1: 1.0e+1 << 60 */ + UINT64_C(0xc800000000000000), /* 2: 1.0e+2 << 57 */ + UINT64_C(0xfa00000000000000), /* 3: 1.0e+3 << 54 */ + UINT64_C(0x9c40000000000000), /* 4: 1.0e+4 << 50 */ + UINT64_C(0xc350000000000000), /* 5: 1.0e+5 << 47 */ + UINT64_C(0xf424000000000000), /* 6: 1.0e+6 << 44 */ + UINT64_C(0x9896800000000000), /* 7: 1.0e+7 << 40 */ + UINT64_C(0xbebc200000000000), /* 8: 1.0e+8 << 37 */ + UINT64_C(0xee6b280000000000), /* 9: 1.0e+9 << 34 */ + UINT64_C(0x9502f90000000000), /* 10: 1.0e+10 << 30 */ + UINT64_C(0xba43b74000000000), /* 11: 1.0e+11 << 27 */ + UINT64_C(0xe8d4a51000000000), /* 12: 1.0e+12 << 24 */ + UINT64_C(0x9184e72a00000000), /* 13: 1.0e+13 << 20 */ + UINT64_C(0xb5e620f480000000), /* 14: 1.0e+14 << 17 */ + UINT64_C(0xe35fa931a0000000), /* 15: 1.0e+15 << 14 */ + UINT64_C(0x8e1bc9bf04000000), /* 16: 1.0e+16 << 10 */ + UINT64_C(0xb1a2bc2ec5000000), /* 17: 1.0e+17 << 7 */ + UINT64_C(0xde0b6b3a76400000), /* 18: 1.0e+18 << 4 */ + UINT64_C(0x8ac7230489e80000), /* 19: 1.0e+19 >> 0 */ + UINT64_C(0xad78ebc5ac620000), /* 20: 1.0e+20 >> 3 */ + UINT64_C(0xd8d726b7177a8000), /* 21: 1.0e+21 >> 6 */ + UINT64_C(0x878678326eac9000), /* 22: 1.0e+22 >> 10 */ + UINT64_C(0xa968163f0a57b400), /* 23: 1.0e+23 >> 13 */ + UINT64_C(0xd3c21bcecceda100), /* 24: 1.0e+24 >> 16 */ + UINT64_C(0x84595161401484a0), /* 25: 1.0e+25 >> 20 */ + UINT64_C(0xa56fa5b99019a5c8), /* 26: 1.0e+26 >> 23 */ }; static const u64 aScale[] = { - 0x8049a4ac0c5811aeLLU, /* 0: 1.0e-351 << 1229 */ - 0xcf42894a5dce35eaLLU, /* 1: 1.0e-324 << 1140 */ - 0xa76c582338ed2622LLU, /* 2: 1.0e-297 << 1050 */ - 0x873e4f75e2224e68LLU, /* 3: 1.0e-270 << 960 */ - 0xda7f5bf590966849LLU, /* 4: 1.0e-243 << 871 */ - 0xb080392cc4349dedLLU, /* 5: 1.0e-216 << 781 */ - 0x8e938662882af53eLLU, /* 6: 1.0e-189 << 691 */ - 0xe65829b3046b0afaLLU, /* 7: 1.0e-162 << 602 */ - 0xba121a4650e4ddecLLU, /* 8: 1.0e-135 << 512 */ - 0x964e858c91ba2655LLU, /* 9: 1.0e-108 << 422 */ - 0xf2d56790ab41c2a3LLU, /* 10: 1.0e-81 << 333 */ - 0xc428d05aa4751e4dLLU, /* 11: 1.0e-54 << 243 */ - 0x9e74d1b791e07e48LLU, /* 12: 1.0e-27 << 153 */ - 0x8000000000000000LLU, /* 13: 1.0e+0 << 63 */ - 0xcecb8f27f4200f3aLLU, /* 14: 1.0e+27 >> 26 */ - 0xa70c3c40a64e6c52LLU, /* 15: 1.0e+54 >> 116 */ - 0x86f0ac99b4e8dafdLLU, /* 16: 1.0e+81 >> 206 */ - 0xda01ee641a708deaLLU, /* 17: 1.0e+108 >> 295 */ - 0xb01ae745b101e9e4LLU, /* 18: 1.0e+135 >> 385 */ - 0x8e41ade9fbebc27dLLU, /* 19: 1.0e+162 >> 475 */ - 0xe5d3ef282a242e82LLU, /* 20: 1.0e+189 >> 564 */ - 0xb9a74a0637ce2ee1LLU, /* 21: 1.0e+216 >> 654 */ - 0x95f83d0a1fb69cd9LLU, /* 22: 1.0e+243 >> 744 */ - 0xf24a01a73cf2dcd0LLU, /* 23: 1.0e+270 >> 833 */ - 0xc3b8358109e84f07LLU, /* 24: 1.0e+297 >> 923 */ - 0x9e19db92b4e31ba9LLU, /* 25: 1.0e+324 >> 1013 */ + UINT64_C(0x8049a4ac0c5811ae), /* 0: 1.0e-351 << 1229 */ + UINT64_C(0xcf42894a5dce35ea), /* 1: 1.0e-324 << 1140 */ + UINT64_C(0xa76c582338ed2622), /* 2: 1.0e-297 << 1050 */ + UINT64_C(0x873e4f75e2224e68), /* 3: 1.0e-270 << 960 */ + UINT64_C(0xda7f5bf590966849), /* 4: 1.0e-243 << 871 */ + UINT64_C(0xb080392cc4349ded), /* 5: 1.0e-216 << 781 */ + UINT64_C(0x8e938662882af53e), /* 6: 1.0e-189 << 691 */ + UINT64_C(0xe65829b3046b0afa), /* 7: 1.0e-162 << 602 */ + UINT64_C(0xba121a4650e4ddec), /* 8: 1.0e-135 << 512 */ + UINT64_C(0x964e858c91ba2655), /* 9: 1.0e-108 << 422 */ + UINT64_C(0xf2d56790ab41c2a3), /* 10: 1.0e-81 << 333 */ + UINT64_C(0xc428d05aa4751e4d), /* 11: 1.0e-54 << 243 */ + UINT64_C(0x9e74d1b791e07e48), /* 12: 1.0e-27 << 153 */ + UINT64_C(0x8000000000000000), /* 13: 1.0e+0 << 63 */ + UINT64_C(0xcecb8f27f4200f3a), /* 14: 1.0e+27 >> 26 */ + UINT64_C(0xa70c3c40a64e6c52), /* 15: 1.0e+54 >> 116 */ + UINT64_C(0x86f0ac99b4e8dafd), /* 16: 1.0e+81 >> 206 */ + UINT64_C(0xda01ee641a708dea), /* 17: 1.0e+108 >> 295 */ + UINT64_C(0xb01ae745b101e9e4), /* 18: 1.0e+135 >> 385 */ + UINT64_C(0x8e41ade9fbebc27d), /* 19: 1.0e+162 >> 475 */ + UINT64_C(0xe5d3ef282a242e82), /* 20: 1.0e+189 >> 564 */ + UINT64_C(0xb9a74a0637ce2ee1), /* 21: 1.0e+216 >> 654 */ + UINT64_C(0x95f83d0a1fb69cd9), /* 22: 1.0e+243 >> 744 */ + UINT64_C(0xf24a01a73cf2dcd0), /* 23: 1.0e+270 >> 833 */ + UINT64_C(0xc3b8358109e84f07), /* 24: 1.0e+297 >> 923 */ + UINT64_C(0x9e19db92b4e31ba9), /* 25: 1.0e+324 >> 1013 */ }; int g, n; u64 x, y; From 84ad6f302fb80550ec70b67b8d2d721ff590a0a4 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 8 Mar 2026 07:02:46 +0000 Subject: [PATCH 142/197] Add parens around an expression in the CLI shell to account for operator precedence, as reported in [forum:856ff7a2f1|forum post 856ff7a2f1]. FossilOrigin-Name: da3ad170aebf57f2202e56673ac149bc51077d126ab5928f1db16492e403d5b9 --- manifest | 13 ++++++------- manifest.uuid | 2 +- src/shell.c.in | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index edbc454f92..9b6f4841be 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expose\ssqlite3_bind_zeroblob()\sto\sJS/WASM. -D 2026-03-08T05:53:47.701 +C Add\sparens\saround\san\sexpression\sin\sthe\sCLI\sshell\sto\saccount\sfor\soperator\sprecedence,\sas\sreported\sin\s[forum:856ff7a2f1|forum\spost\s856ff7a2f1]. +D 2026-03-08T07:02:46.194 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -730,7 +730,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576 -F src/shell.c.in d74e8b78bbbf0297e427c7e76abdbfb2769d5e9d67fec69806b1812c56316d8c +F src/shell.c.in 437863e7d9fed5525d5b7a669f40f926a3a536d8e41747431949f8de53324a96 F src/sqlite.h.in 4d657846d68a58b028f0c4c331b9d3b4a79306f25c3b0d04fb56060343f73d85 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca @@ -2189,9 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 27be26566fdb4d01c44dc111f1c18c835797de0990d4fcc876e91edc216e9e93 0473eeb3cefa1d7882375e3f89d239d570649349c5a0a8ddd90b0a336a9bb493 -R 4c2e89b0f91b21484e69896ee4014c01 -T +closed 0473eeb3cefa1d7882375e3f89d239d570649349c5a0a8ddd90b0a336a9bb493 Closed\sby\sintegrate-merge. +P 0c5d4fe0bd322b4c8dbd0800001317a21cd511b00244de74b4db3fd051153879 +R d722ffeb4d76b155994400ff67e06b8f U stephan -Z 8d110bf3e994011a5b14c867fd6c96aa +Z f680be3a93bb03be191e09867e313221 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 04e791092e..56e3347d8a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0c5d4fe0bd322b4c8dbd0800001317a21cd511b00244de74b4db3fd051153879 +da3ad170aebf57f2202e56673ac149bc51077d126ab5928f1db16492e403d5b9 diff --git a/src/shell.c.in b/src/shell.c.in index a9dd158aff..6a982854b6 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -7340,7 +7340,7 @@ static int outputDumpWarning(ShellState *p, const char *zLike){ sqlite3_stmt *pStmt = 0; shellPreparePrintf(p->db, &rc, &pStmt, "SELECT 1 FROM sqlite_schema o WHERE " - "sql LIKE 'CREATE VIRTUAL TABLE%%' AND %s", zLike ? zLike : "true" + "sql LIKE 'CREATE VIRTUAL TABLE%%' AND (%s)", zLike ? zLike : "true" ); if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ cli_puts("/* WARNING: " From 03b0f8fc9ceb46c3745d5ffadca089a78a8612c4 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 8 Mar 2026 07:58:02 +0000 Subject: [PATCH 143/197] Refactor tester1 OPFS test to support both the "opfs" and "opfs-wl" VFSes. FossilOrigin-Name: 17ac8d7bdfaf96510abea8c11019045c1703b7040655d9c4c8d7001636260b50 --- ext/wasm/tester1.c-pp.js | 288 +++++++++++++++++++++++---------------- manifest | 12 +- manifest.uuid | 2 +- 3 files changed, 179 insertions(+), 123 deletions(-) diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 6ed66d7853..81bc37e26d 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -451,9 +451,131 @@ globalThis.sqlite3InitModule = sqlite3InitModule; T.assert( !initDb ); tryKey('hexkey', hexFoo, 6); dbUnlink(); - }, + }; //#endif enable-see + /* Tests common to "opfs" and "opfs-wl". These tests manipulate + "this" and must run in order. + */ + T.opfsCommon = { + sanityChecks: async function(vfsName, oo1Ctor, sqlite3){ + T.assert(capi.sqlite3_vfs_find(vfsName)); + const opfs = sqlite3.opfs; + const filename = this.opfsDbFile = '/dir/sqlite3-tester1.db'; + const fileUri = 'file://'+filename+'?delete-before-open=1'; + const initSql = [ + 'create table p(a);', + 'insert into p(a) values(1),(2),(3)' + ]; + let db = new oo1Ctor(fileUri); + try { + db.exec(initSql); + T.assert(3 === db.selectValue('select count(*) from p')); + db.close(); + db = new oo1Ctor(filename); + db.exec('insert into p(a) values(4),(5),(6)'); + T.assert(6 === db.selectValue('select count(*) from p')); + this.opfsDbExport = capi.sqlite3_js_db_export(db); + T.assert(this.opfsDbExport instanceof Uint8Array) + .assert(this.opfsDbExport.byteLength>0 + && 0===this.opfsDbExport.byteLength % 512); + }finally{ + db.close(); + db = null; + } + T.assert(await opfs.entryExists(filename)); + try { + db = new oo1Ctor(fileUri); + db.exec(initSql) /* will throw if delete-before-open did not work */; + T.assert(3 === db.selectValue('select count(*) from p')); + }finally{ + if(db) db.close(); + } + }, + + importer: async function(vfsName, oo1Ctor, sqlite3){ + let db; + const filename = this.opfsDbFile; + try { + const exp = this.opfsDbExport; + delete this.opfsDbExport; + this.opfsImportSize = await oo1Ctor.importDb(filename, exp); + db = new oo1Ctor(this.opfsDbFile); + T.assert(6 === db.selectValue('select count(*) from p')). + assert( this.opfsImportSize == exp.byteLength ); + db.close(); + db = null; + this.opfsUnlink = + (fn=filename)=>sqlite3.util.sqlite3__wasm_vfs_unlink(vfsName, fn); + this.opfsUnlink(filename); + T.assert(!(await sqlite3.opfs.entryExists(filename))); + // Try again with a function as an input source: + let cursor = 0; + const blockSize = 512, end = exp.byteLength; + const reader = async function(){ + if(cursor >= exp.byteLength){ + return undefined; + } + const rv = exp.subarray(cursor, cursor+blockSize>end ? end : cursor+blockSize); + cursor += blockSize; + return rv; + }; + this.opfsImportSize = await oo1Ctor.importDb(filename, reader); + db = new oo1Ctor(this.opfsDbFile); + T.assert(6 === db.selectValue('select count(*) from p')). + assert( this.opfsImportSize == exp.byteLength ); + }finally{ + if(db) db.close(); + } + }, + + opfsUtil: async function(vfsName, oo1Ctor, sqlite3){ + const filename = this.opfsDbFile; + const unlink = this.opfsUnlink; + T.assert(filename && !!unlink); + delete this.opfsDbFile; + delete this.opfsUnlink; + /************************************************************** + ATTENTION CLIENT-SIDE USERS: sqlite3.opfs is NOT intended + for client-side use. It is only for this project's own + internal use. Its APIs are subject to change or removal at + any time. The sqlite3.opfs namespace is REMOVED from the + sqlite3 namespace in non-test runs of the library. + ***************************************************************/ + const opfs = sqlite3.opfs; + const fSize = this.opfsImportSize; + delete this.opfsImportSize; + let sh; + try{ + T.assert(await opfs.entryExists(filename)); + const [dirHandle, filenamePart] = await opfs.getDirForFilename(filename, false); + const fh = await dirHandle.getFileHandle(filenamePart); + sh = await fh.createSyncAccessHandle(); + T.assert(fSize === await sh.getSize()); + await sh.close(); + sh = undefined; + unlink(); + T.assert(!(await opfs.entryExists(filename))); + }finally{ + if(sh) await sh.close(); + unlink(); + } + + // Some sanity checks of the opfs utility functions... + const testDir = '/sqlite3-opfs-'+opfs.randomFilename(12); + const aDir = testDir+'/test/dir'; + T.assert(await opfs.mkdir(aDir), "mkdir failed") + .assert(await opfs.mkdir(aDir), "mkdir must pass if the dir exists") + .assert(!(await opfs.unlink(testDir+'/test')), "delete 1 should have failed (dir not empty)") + .assert((await opfs.unlink(testDir+'/test/dir')), "delete 2 failed") + .assert(!(await opfs.unlink(testDir+'/test/dir')), + "delete 2b should have failed (dir already deleted)") + .assert((await opfs.unlink(testDir, true)), "delete 3 failed") + .assert(!(await opfs.entryExists(testDir)), + "entryExists(",testDir,") should have failed"); + } + }/*T.opfsCommon*/; + //////////////////////////////////////////////////////////////////////// // End of infrastructure setup. Now define the tests... //////////////////////////////////////////////////////////////////////// @@ -3767,130 +3889,29 @@ globalThis.sqlite3InitModule = sqlite3InitModule; //////////////////////////////////////////////////////////////////////// T.g('OPFS: Origin-Private File System', - (sqlite3)=>(hasOpfs() || 'requires "opfs" VFS')) + (sqlite3)=>(!!sqlite3.oo1.OpfsDb || 'requires "opfs" VFS')) .t({ name: 'OPFS db sanity checks', - test: async function(sqlite3){ - T.assert(capi.sqlite3_vfs_find('opfs')); - const opfs = sqlite3.opfs; - const filename = this.opfsDbFile = '/dir/sqlite3-tester1.db'; - const fileUri = 'file://'+filename+'?delete-before-open=1'; - const initSql = [ - 'create table p(a);', - 'insert into p(a) values(1),(2),(3)' - ]; - let db = new sqlite3.oo1.OpfsDb(fileUri); - try { - db.exec(initSql); - T.assert(3 === db.selectValue('select count(*) from p')); - db.close(); - db = new sqlite3.oo1.OpfsDb(filename); - db.exec('insert into p(a) values(4),(5),(6)'); - T.assert(6 === db.selectValue('select count(*) from p')); - this.opfsDbExport = capi.sqlite3_js_db_export(db); - T.assert(this.opfsDbExport instanceof Uint8Array) - .assert(this.opfsDbExport.byteLength>0 - && 0===this.opfsDbExport.byteLength % 512); - }finally{ - db.close(); - } - T.assert(await opfs.entryExists(filename)); - try { - db = new sqlite3.oo1.OpfsDb(fileUri); - db.exec(initSql) /* will throw if delete-before-open did not work */; - T.assert(3 === db.selectValue('select count(*) from p')); - }finally{ - if(db) db.close(); - } + test: async (sqlite3)=>{ + await T.opfsCommon.sanityChecks('opfs', sqlite3.oo1.OpfsDb, sqlite3); } - }/*OPFS db sanity checks*/) + }) .t({ - name: 'OPFS import', - test: async function(sqlite3){ - let db; - const filename = this.opfsDbFile; - try { - const exp = this.opfsDbExport; - delete this.opfsDbExport; - this.opfsImportSize = await sqlite3.oo1.OpfsDb.importDb(filename, exp); - db = new sqlite3.oo1.OpfsDb(this.opfsDbFile); - T.assert(6 === db.selectValue('select count(*) from p')). - assert( this.opfsImportSize == exp.byteLength ); - db.close(); - this.opfsUnlink = - (fn=filename)=>sqlite3.util.sqlite3__wasm_vfs_unlink("opfs",fn); - this.opfsUnlink(filename); - T.assert(!(await sqlite3.opfs.entryExists(filename))); - // Try again with a function as an input source: - let cursor = 0; - const blockSize = 512, end = exp.byteLength; - const reader = async function(){ - if(cursor >= exp.byteLength){ - return undefined; - } - const rv = exp.subarray(cursor, cursor+blockSize>end ? end : cursor+blockSize); - cursor += blockSize; - return rv; - }; - this.opfsImportSize = await sqlite3.oo1.OpfsDb.importDb(filename, reader); - db = new sqlite3.oo1.OpfsDb(this.opfsDbFile); - T.assert(6 === db.selectValue('select count(*) from p')). - assert( this.opfsImportSize == exp.byteLength ); - }finally{ - if(db) db.close(); - } + name: 'OPFS import/export', + test: async (sqlite3)=>{ + await T.opfsCommon.importer('opfs', sqlite3.oo1.OpfsDb, sqlite3); } - }/*OPFS export/import*/) + }) .t({ name: '(Internal-use) OPFS utility APIs', - test: async function(sqlite3){ - const filename = this.opfsDbFile; - const unlink = this.opfsUnlink; - T.assert(filename && !!unlink); - delete this.opfsDbFile; - delete this.opfsUnlink; - /************************************************************** - ATTENTION CLIENT-SIDE USERS: sqlite3.opfs is NOT intended - for client-side use. It is only for this project's own - internal use. Its APIs are subject to change or removal at - any time. - ***************************************************************/ - const opfs = sqlite3.opfs; - const fSize = this.opfsImportSize; - delete this.opfsImportSize; - let sh; - try{ - T.assert(await opfs.entryExists(filename)); - const [dirHandle, filenamePart] = await opfs.getDirForFilename(filename, false); - const fh = await dirHandle.getFileHandle(filenamePart); - sh = await fh.createSyncAccessHandle(); - T.assert(fSize === await sh.getSize()); - await sh.close(); - sh = undefined; - unlink(); - T.assert(!(await opfs.entryExists(filename))); - }finally{ - if(sh) await sh.close(); - unlink(); - } - - // Some sanity checks of the opfs utility functions... - const testDir = '/sqlite3-opfs-'+opfs.randomFilename(12); - const aDir = testDir+'/test/dir'; - T.assert(await opfs.mkdir(aDir), "mkdir failed") - .assert(await opfs.mkdir(aDir), "mkdir must pass if the dir exists") - .assert(!(await opfs.unlink(testDir+'/test')), "delete 1 should have failed (dir not empty)") - .assert((await opfs.unlink(testDir+'/test/dir')), "delete 2 failed") - .assert(!(await opfs.unlink(testDir+'/test/dir')), - "delete 2b should have failed (dir already deleted)") - .assert((await opfs.unlink(testDir, true)), "delete 3 failed") - .assert(!(await opfs.entryExists(testDir)), - "entryExists(",testDir,") should have failed"); + test: async (sqlite3)=>{ + await T.opfsCommon.opfsUtil("opfs", sqlite3.oo1.OpfsDb, sqlite3); } - }/*OPFS util sanity checks*/) + }) //#if enable-see .t({ name: 'OPFS with SEE encryption', + predicate: ()=>!!sqlite3.oo1.OpfsDb, test: function(sqlite3){ T.seeBaseCheck( sqlite3.oo1.OpfsDb, @@ -3899,9 +3920,44 @@ globalThis.sqlite3InitModule = sqlite3InitModule; if( isInit ) opt.filename += '?delete-before-open=1'; return opt; }, - ()=>{}); + ()=>{} + ); } - })/*OPFS with SEE*/ + }) +//#endif enable-see + ;/* end OPFS tests */ + + //////////////////////////////////////////////////////////////////////// + T.g('OPFS-WL: Origin-Private File System with Web Locks', + (sqlite3)=>(!!sqlite3.oo1.OpfsWlDb || 'requires "opfs-wl" VFS')) + .t({ + name: 'OPFS-WL db sanity checks', + test: async (sqlite3)=>{ + await T.opfsCommon.sanityChecks('opfs-wl', sqlite3.oo1.OpfsWlDb, sqlite3); + } + }) + .t({ + name: 'OPFS-WL import/export', + test: async (sqlite3)=>{ + await T.opfsCommon.importer('opfs-wl', sqlite3.oo1.OpfsWlDb, sqlite3); + } + }) +//#if enable-see + .t({ + name: 'OPFS-WL with SEE encryption', + predicate: ()=>!!sqlite3.oo1.OpfsWlDb, + test: function(sqlite3){ + T.seeBaseCheck( + sqlite3.oo1.OpfsWlDb, + function(isInit){ + const opt = {filename: 'file:///sqlite3-see.edb'}; + if( isInit ) opt.filename += '?delete-before-open=1'; + return opt; + }, + ()=>{} + ); + } + }) //#endif enable-see ;/* end OPFS tests */ diff --git a/manifest b/manifest index d2f8ed2331..852b2ca2e8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Extend\sthe\sJS\spre-bootstrapping\sconfiguration\sto\sinclude\san\soption\sto\sdisable\sinclusion\sof\sany\sgiven\sextension\sVFS\s(not\sthe\sdefault\sVFSes,\slike\smemdb).\sThe\sprimary\smotivation\sfor\sthis\sis\sto\sgive\speople\swho\sdon't\suse\sOPFS\sto\sa\sway\sto\skeep\sthe\sOPFS\sVFSes\sfrom\sloading\stheir\sproxy\sworkers,\swhich\sare\sexpensive. -D 2026-03-07T06:10:29.452 +C Refactor\stester1\sOPFS\stest\sto\ssupport\sboth\sthe\s"opfs"\sand\s"opfs-wl"\sVFSes. +D 2026-03-08T07:58:02.639 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -644,7 +644,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c986e48af7d3d720fcd244 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb -F ext/wasm/tester1.c-pp.js 31cde3c4db4b955d5554c21cb0aa6ec3a0743b03d7c5262a38bfa303e7955942 +F ext/wasm/tester1.c-pp.js bccc66cdb09477ef09bf7c871bdba85f2c8b936a32d5dc07dc8c882517f73b50 F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226 F ext/wasm/tests/opfs/concurrency/test.js 46c772bc18abb0fcbb058d57b5aaee9e7938f948ecdd802c6ca0850ad3519f92 F ext/wasm/tests/opfs/concurrency/worker.js fc985ec86b70b057224e8caaa9c5a11892ea9b980a5c5da21b1efdf5f12bc3f6 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P c1cb61f473a11a325ef421ba8edfb20257203688565f7db62309044be183af5f -R bd137899af2cd4094f0a4f5a1f4094af +P 9a07eb7a941479510891d1444aacbeb440efaad3e9a13f186833618d8b60a8da +R 2c796a522d5a1762226997586fbd0bf5 U stephan -Z 147d7dd643bc15130deceeb0e6d52d6f +Z 681d2e8fff944e3c89259f16f4209f56 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 06ded776dc..7e39b0e048 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9a07eb7a941479510891d1444aacbeb440efaad3e9a13f186833618d8b60a8da +17ac8d7bdfaf96510abea8c11019045c1703b7040655d9c4c8d7001636260b50 From 303fad1f91d63c05ff73e7f6ae9f225745eda731 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 8 Mar 2026 08:09:09 +0000 Subject: [PATCH 144/197] Update the tester1 SEE tests to account for opfs-wl. FossilOrigin-Name: 616d32c8380ef47c5a7c2eb765e7b6fbec9500d4e16c837f4ee11d71c239a55f --- ext/wasm/tester1.c-pp.js | 8 +++++--- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 81bc37e26d..c1fda13d76 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -3599,7 +3599,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule; test: function(sqlite3){ const JDb = sqlite3.oo1.JsStorageDb; T.seeBaseCheck(JDb, - (isInit)=>return {filename: "session"}, + (isInit)=>{ + return {filename: "session"}; + }, ()=>JDb.clearStorage('session')); } })/*kvvfs with SEE*/ @@ -3911,7 +3913,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule; //#if enable-see .t({ name: 'OPFS with SEE encryption', - predicate: ()=>!!sqlite3.oo1.OpfsDb, + predicate: (sqlite3)=>!!sqlite3.oo1.OpfsDb, test: function(sqlite3){ T.seeBaseCheck( sqlite3.oo1.OpfsDb, @@ -3945,7 +3947,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule; //#if enable-see .t({ name: 'OPFS-WL with SEE encryption', - predicate: ()=>!!sqlite3.oo1.OpfsWlDb, + predicate: (sqlite3)=>!!sqlite3.oo1.OpfsWlDb, test: function(sqlite3){ T.seeBaseCheck( sqlite3.oo1.OpfsWlDb, diff --git a/manifest b/manifest index 852b2ca2e8..7dd4119fca 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refactor\stester1\sOPFS\stest\sto\ssupport\sboth\sthe\s"opfs"\sand\s"opfs-wl"\sVFSes. -D 2026-03-08T07:58:02.639 +C Update\sthe\stester1\sSEE\stests\sto\saccount\sfor\sopfs-wl. +D 2026-03-08T08:09:09.808 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -644,7 +644,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c986e48af7d3d720fcd244 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb -F ext/wasm/tester1.c-pp.js bccc66cdb09477ef09bf7c871bdba85f2c8b936a32d5dc07dc8c882517f73b50 +F ext/wasm/tester1.c-pp.js a84541ec9cfedcb41279a0da6b34c052a2c7b397c696b8a8a8f85964c8d1e9ca F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226 F ext/wasm/tests/opfs/concurrency/test.js 46c772bc18abb0fcbb058d57b5aaee9e7938f948ecdd802c6ca0850ad3519f92 F ext/wasm/tests/opfs/concurrency/worker.js fc985ec86b70b057224e8caaa9c5a11892ea9b980a5c5da21b1efdf5f12bc3f6 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 9a07eb7a941479510891d1444aacbeb440efaad3e9a13f186833618d8b60a8da -R 2c796a522d5a1762226997586fbd0bf5 +P 17ac8d7bdfaf96510abea8c11019045c1703b7040655d9c4c8d7001636260b50 +R 20c127d6b469936bc976ef9124b5bb85 U stephan -Z 681d2e8fff944e3c89259f16f4209f56 +Z c738f3c585f3f955ad9c9cce49c18902 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7e39b0e048..4539686e52 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -17ac8d7bdfaf96510abea8c11019045c1703b7040655d9c4c8d7001636260b50 +616d32c8380ef47c5a7c2eb765e7b6fbec9500d4e16c837f4ee11d71c239a55f From 1eb335e31377a982d4acd525f18cf9456c403b7e Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 8 Mar 2026 10:51:47 +0000 Subject: [PATCH 145/197] Increase the version number on trunk to 3.53.0 FossilOrigin-Name: 0152b445ff0cdf560fc028938e1d43a56685d7c046fad84fa90166cd01d71279 --- VERSION | 2 +- manifest | 17 ++++++++--------- manifest.uuid | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/VERSION b/VERSION index 426d048447..c5c343b57a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.52.1 +3.53.0 diff --git a/manifest b/manifest index 7f650c37c3..7d3c2bdd6d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sopfs-wl\sinto\strunk,\snot\sso\smuch\sfor\sthe\s"opfs-wl"\sVFS,\swhich\sis\sstil\stentative\s(working\sfine\sbut\swith\slittle\sperceived\sbenefit),\sbut\sfor\sthe\s"opfs"\sVFS\scleanups\swhich\snecessarily\shappened\saround\sit. -D 2026-03-08T08:32:22.078 +C Increase\sthe\sversion\snumber\son\strunk\sto\s3.53.0 +D 2026-03-08T10:51:47.666 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -8,7 +8,7 @@ F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0 F Makefile.msc d6448b1066932640e0ab2b01376c4ee7615a2b978c3c92e010f8fe222183c201 F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec -F VERSION ed5325177122f86b7a25c21bee36fda8171a34ab86e4c72007798d7837a752be +F VERSION 31435e19ded2aae3c1c67dacf06a995a37fd1b253baec5899b78d64cd29db4f7 F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5 F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 @@ -594,7 +594,7 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c F ext/wasm/api/sqlite3-api-prologue.js db1ba33ca7092f12d5bb6cb615c78c457432be4a1d26785686993a8909950d72 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc -F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js c2236c9037ccac368be6eeed3e5f6ed3cefed0d20539c9092139f27a76aaf1ba w ext/wasm/api/sqlite3-opfs-async-proxy.js +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js c2236c9037ccac368be6eeed3e5f6ed3cefed0d20539c9092139f27a76aaf1ba F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js f907fa712d1c9d98a3c08393f3e97a664857782da11670e129d39e383f45f968 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js cf5fba74978d3e0983f68505d9695ee7836853855590a92ccc5a96e27db5350b @@ -2192,9 +2192,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P da3ad170aebf57f2202e56673ac149bc51077d126ab5928f1db16492e403d5b9 616d32c8380ef47c5a7c2eb765e7b6fbec9500d4e16c837f4ee11d71c239a55f -R 7fa9d9bc620afcdc086430a72b380676 -T +closed 616d32c8380ef47c5a7c2eb765e7b6fbec9500d4e16c837f4ee11d71c239a55f Closed\sby\sintegrate-merge. -U stephan -Z eb8fc8dc10da8c389057ea48d94a3dd6 +P bcaa876c6dafee0995d239f59b6ce7810b6f5faa219b9c392966211ae3dec17a +R 5bb3db34ea0d888edcdd73b8c86f90de +U drh +Z 5075d03aea4dc83f8f3561051268639a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1542198500..5ab5aaa27c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bcaa876c6dafee0995d239f59b6ce7810b6f5faa219b9c392966211ae3dec17a +0152b445ff0cdf560fc028938e1d43a56685d7c046fad84fa90166cd01d71279 From 02cbc96d09e24e214523e58fb4bec0f4aeb005bf Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 8 Mar 2026 12:42:34 +0000 Subject: [PATCH 146/197] JS doc updates. FossilOrigin-Name: 699295f84ef2c4da363f13126abde6af07697d0959896cd868b14513d4278964 --- ext/wasm/api/sqlite3-api-prologue.js | 30 ++++++++++++----------- ext/wasm/tests/opfs/concurrency/worker.js | 3 ++- manifest | 16 ++++++------ manifest.uuid | 2 +- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 5e1c6ba54d..e7b775fe51 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -1955,7 +1955,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( Calls the given _synchronous_ callback function. If that function returns sqlite3.capi.SQLITE_BUSY _or_ throws an SQLite3Error - which a resultCode property of that value then it will suppress + with a resultCode property of that value then it will suppress that error and try again, up to the given maximum number of times. If the callback returns any other value than that, it is returned. If the maximum number of retries has been @@ -1972,8 +1972,8 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( handled as described above. Its result value is ignored. To effectively retry "forever", pass a negative maxTimes value, - with the caveat that there is no recovery from that if the code - gets stuck in a deadlock situation. + with the caveat that there is no recovery from that unless the + beforeRetry() can figure out when to throw. TODO: an async variant of this. */ @@ -2088,13 +2088,15 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( return ff.isReady = p.catch(catcher); }.bind(sqlite3ApiBootstrap), /** - scriptInfo ideally gets injected into this object by the - infrastructure which assembles the JS/WASM module. It contains - state which must be collected before sqlite3ApiBootstrap() can - be declared. It is not necessarily available to any - sqlite3ApiBootstrap.initializers but "should" be in place (if - it's added at all) by the time that - sqlite3ApiBootstrap.initializersAsync is processed. + scriptInfo holds information about the currenty-loading script + so that we can locate the WASM file if it's somewhere other + than the build-time-defined directory. It ideally gets injected + into this object by the infrastructure which assembles the + JS/WASM module. It contains state which must be collected + before sqlite3ApiBootstrap() can be declared. It is not + necessarily available to any sqlite3ApiBootstrap.initializers + but "should" be in place (if it's added at all) by the time + that sqlite3ApiBootstrap.initializersAsync is processed. This state is not part of the public API, only intended for use with the sqlite3 API bootstrapping and wasm-loading process. @@ -2138,10 +2140,10 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( loader, and if we lose that capability for some reason then we'll lose access to this metadata. - These data are interesting for exploring how the wasm/JS - pieces connect, e.g. for exploring exactly what Emscripten - imports into WASM from its JS glue, but it's not - SQLite-related. + These data are interesting for exploring how the wasm/JS pieces + connect, e.g. for exploring exactly what Emscripten imports into + WASM from its JS glue, but it's not SQLite-related and is not + required for the library to work. */ const iw = sqlite3.scriptInfo?.instantiateWasm; if( iw ){ diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index fb603cf795..398e5b5a7f 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -10,7 +10,8 @@ const jsSqlite = urlArgs.get('sqlite3.dir') +options.workerName; importScripts(jsSqlite)/*Sigh - URL args are not propagated this way*/; //const sqlite3InitModule = (await import(jsSqlite)).default; -globalThis.sqlite3InitModule.__isUnderTest = true; +globalThis.sqlite3InitModule.__isUnderTest = + true /* causes sqlite3.opfs to be retained */; globalThis.sqlite3InitModule().then(async function(sqlite3){ const wPost = (type,...payload)=>{ postMessage({type, worker: options.workerName, payload}); diff --git a/manifest b/manifest index 7d3c2bdd6d..3f24be3130 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Increase\sthe\sversion\snumber\son\strunk\sto\s3.53.0 -D 2026-03-08T10:51:47.666 +C JS\sdoc\supdates. +D 2026-03-08T12:42:34.028 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -591,7 +591,7 @@ F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f F ext/wasm/api/sqlite3-api-glue.c-pp.js 7afb3da3510facafd94ce31133ec847d0d4db5b2b5e4325941803fd3bca07c16 F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c41db98a22b534c15e543cfa -F ext/wasm/api/sqlite3-api-prologue.js db1ba33ca7092f12d5bb6cb615c78c457432be4a1d26785686993a8909950d72 +F ext/wasm/api/sqlite3-api-prologue.js 4336f02ac24ba58e68e355adb9da2804a1eef15a4aee961fa813c7d812a56b54 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js c2236c9037ccac368be6eeed3e5f6ed3cefed0d20539c9092139f27a76aaf1ba @@ -647,7 +647,7 @@ F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3 F ext/wasm/tester1.c-pp.js e26e78fe450375b43a88a5da41946b8997612201a592770f19ec827b2bf96cc0 F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226 F ext/wasm/tests/opfs/concurrency/test.js 46c772bc18abb0fcbb058d57b5aaee9e7938f948ecdd802c6ca0850ad3519f92 -F ext/wasm/tests/opfs/concurrency/worker.js 4edeec8d88f14c9603c9d4e32ce379ce1d5394f3c5e820776e26a603d600b3e3 +F ext/wasm/tests/opfs/concurrency/worker.js 704d82c5e287e47f612349e027765943a58ad967dcf178fb5a1c3a8eaafb09af F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79 F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8 F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328 @@ -2192,8 +2192,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P bcaa876c6dafee0995d239f59b6ce7810b6f5faa219b9c392966211ae3dec17a -R 5bb3db34ea0d888edcdd73b8c86f90de -U drh -Z 5075d03aea4dc83f8f3561051268639a +P 0152b445ff0cdf560fc028938e1d43a56685d7c046fad84fa90166cd01d71279 +R c2a756d084a38515683f88a003d1705b +U stephan +Z d7173eb7134af12db84591911d0c0ce4 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5ab5aaa27c..6eb4e7d576 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0152b445ff0cdf560fc028938e1d43a56685d7c046fad84fa90166cd01d71279 +699295f84ef2c4da363f13126abde6af07697d0959896cd868b14513d4278964 From 46a692c08ba568248d79b19d810610346f2c41b0 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 8 Mar 2026 16:03:08 +0000 Subject: [PATCH 147/197] Upgrade ext/wasm/c-pp-lite.c to its newer sibling because we've reached the older one's limits. This renames c-pp-lite.c to libcmpp.c to maintain both the SCM- and code lineage but that may end up looking a bit weird because the diff between the two is vast. FossilOrigin-Name: 2e2339bd9e4293bad04ece7673a3048b99c2143cf9573ade2ec082d95744b981 --- ext/wasm/GNUmakefile | 10 +- ext/wasm/api/EXPORTED_FUNCTIONS.c-pp | 6 +- ext/wasm/api/extern-post-js.c-pp.js | 8 +- ext/wasm/api/opfs-common-inline.c-pp.js | 16 +- ext/wasm/api/opfs-common-shared.c-pp.js | 8 +- ext/wasm/api/pre-js.c-pp.js | 15 +- ext/wasm/api/sqlite3-api-glue.c-pp.js | 10 +- ext/wasm/api/sqlite3-api-oo1.c-pp.js | 12 +- ext/wasm/api/sqlite3-api-worker1.c-pp.js | 2 +- ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js | 8 +- ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js | 38 +- ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js | 2 +- ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js | 2 +- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 2 +- ext/wasm/api/sqlite3-worker1-promiser.c-pp.js | 10 +- ext/wasm/api/sqlite3-worker1.c-pp.js | 4 +- ext/wasm/c-pp-lite.c | 2804 --- ext/wasm/demo-worker1-promiser.c-pp.html | 4 +- ext/wasm/demo-worker1-promiser.c-pp.js | 4 +- ext/wasm/fiddle/index.c-pp.html | 2 +- ext/wasm/libcmpp.c | 16877 ++++++++++++++++ ext/wasm/tester1-worker.c-pp.html | 2 +- ext/wasm/tester1.c-pp.html | 4 +- ext/wasm/tester1.c-pp.js | 16 +- manifest | 56 +- manifest.uuid | 2 +- 26 files changed, 17000 insertions(+), 2924 deletions(-) delete mode 100644 ext/wasm/c-pp-lite.c create mode 100644 ext/wasm/libcmpp.c diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index 1b7c5269e8..05375d42bd 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -566,12 +566,14 @@ WASM_CUSTOM_INSTANTIATE = 1 # -D... flags which should be included in all invocations should be # appended to $(b.c-pp.target.flags). # -bin.c-pp = ./c-pp-lite -$(bin.c-pp): c-pp-lite.c $(sqlite3.c) $(MAKEFILE) - $(CC) -O0 -o $@ c-pp-lite.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top) \ +bin.c-pp = ./c-pp +$(bin.c-pp): libcmpp.c $(sqlite3.c) $(MAKEFILE) + $(CC) -O0 -o $@ libcmpp.c $(dir.top)/sqlite3.c -I$(dir.top) \ -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_UTF16 \ -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_WAL -DSQLITE_THREADSAFE=0 \ - -DSQLITE_TEMP_STORE=3 + -DSQLITE_TEMP_STORE=3 \ + '-DCMPP_DEFAULT_DELIM="//#"' -DCMPP_MAIN -DCMPP_OMIT_D_MODULE \ + -DCMPP_OMIT_D_PIPE DISTCLEAN_FILES += $(bin.c-pp) b.c-pp.target.flags ?= ifeq (1,$(SQLITE_C_IS_SEE)) diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.c-pp b/ext/wasm/api/EXPORTED_FUNCTIONS.c-pp index a43a7b0253..2b8397a6d7 100644 --- a/ext/wasm/api/EXPORTED_FUNCTIONS.c-pp +++ b/ext/wasm/api/EXPORTED_FUNCTIONS.c-pp @@ -226,14 +226,14 @@ _sqlite3session_object_config _sqlite3session_patchset _sqlite3session_patchset_strm _sqlite3session_table_filter -//#endif not bare-bones +//#/if not bare-bones //#if enable-see _sqlite3_key _sqlite3_key_v2 _sqlite3_rekey _sqlite3_rekey_v2 _sqlite3_activate_see -//#endif enable-see +//#/if enable-see //#if fiddle _fiddle_db_arg _fiddle_db_filename @@ -245,4 +245,4 @@ _fiddle_reset_db _fiddle_db_handle _fiddle_db_vfs _fiddle_export_db -//#endif fiddle +//#/if fiddle diff --git a/ext/wasm/api/extern-post-js.c-pp.js b/ext/wasm/api/extern-post-js.c-pp.js index cac6e4ab4f..b2e760d6a0 100644 --- a/ext/wasm/api/extern-post-js.c-pp.js +++ b/ext/wasm/api/extern-post-js.c-pp.js @@ -14,7 +14,7 @@ */ //#if target:es6-module const toExportForESM = -//#endif +//#/if (function(){ //console.warn("this is extern-post-js"); /** @@ -97,7 +97,7 @@ const toExportForESM = //console.warn("sqlite3InitModule() returning E-module.",EmscriptenModule); return EmscriptenModule; } -//#endif +//#/if return s; }).catch((e)=>{ console.error("Exception loading sqlite3 module:",e); @@ -128,10 +128,10 @@ const toExportForESM = } /* AMD modules get injected in a way we cannot override, so we can't handle those here. */ -//#endif // !target:es6-module +//#/if // !target:es6-module return sIM; })(); //#if target:es6-module sqlite3InitModule = toExportForESM; export default sqlite3InitModule; -//#endif +//#/if diff --git a/ext/wasm/api/opfs-common-inline.c-pp.js b/ext/wasm/api/opfs-common-inline.c-pp.js index 04ae17d555..74e911e56d 100644 --- a/ext/wasm/api/opfs-common-inline.c-pp.js +++ b/ext/wasm/api/opfs-common-inline.c-pp.js @@ -1,4 +1,4 @@ -//#if nope +//#if 0 /** This file is for preprocessor #include into the "opfs" and "opfs-wl" impls, as well as their async-proxy part. It must be @@ -7,9 +7,9 @@ (B) it references an object which is local to each of those files but which has a 99% identical structure for each. */ -//#endif +//#/if //#// vfs.metrics.enable is a refactoring crutch. -//#define vfs.metrics.enable=0 +//#define vfs.metrics.enable 0 const initS11n = function(){ /** This proxy de/serializes cross-thread function arguments and @@ -92,7 +92,7 @@ const initS11n = function(){ state.s11n.deserialize = function(clear=false){ //#if vfs.metrics.enable ++metrics.s11n.deserialize.count; -//#endif +//#/if const t = performance.now(); const argc = viewU8[0]; const rc = argc ? [] : null; @@ -120,7 +120,7 @@ const initS11n = function(){ //log("deserialize:",argc, rc); //#if vfs.metrics.enable metrics.s11n.deserialize.time += performance.now() - t; -//#endif +//#/if return rc; }; @@ -140,7 +140,7 @@ const initS11n = function(){ const t = performance.now(); //#if vfs.metrics.enable ++metrics.s11n.serialize.count; -//#endif +//#/if if(args.length){ //log("serialize():",args); const typeIds = []; @@ -173,7 +173,7 @@ const initS11n = function(){ } //#if vfs.metrics.enable metrics.s11n.serialize.time += performance.now() - t; -//#endif +//#/if }; //#if defined opfs-async-proxy @@ -184,7 +184,7 @@ const initS11n = function(){ } }) : ()=>{}; -//#endif +//#/if return state.s11n; //#undef vfs.metrics.enable diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 11acf40bdc..24ae2632fb 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -1118,7 +1118,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ new Worker(new URL(proxyUri, import.meta.url)); //#else new Worker(proxyUri); -//#endif +//#/if let zombieTimer = setTimeout(()=>{ /* At attempt to work around a browser-specific quirk in which the Worker load is failing in such a way that we neither @@ -1140,7 +1140,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }; const opRun = opfsVfs.opRun; -//#if nope +//#if 0 /** Not part of the public API. Only for test/development use. */ @@ -1154,7 +1154,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ W.postMessage({type: 'opfs-async-restart'}); } }; -//#endif +//#/if const sanityCheck = function(){ const scope = wasm.scopedAllocPush(); @@ -1298,4 +1298,4 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }/*createVfsState()*/; }/*sqlite3ApiBootstrap.initializers*/); -//#endif target:node +//#/if target:node diff --git a/ext/wasm/api/pre-js.c-pp.js b/ext/wasm/api/pre-js.c-pp.js index 3910cb000b..fbb48f9eac 100644 --- a/ext/wasm/api/pre-js.c-pp.js +++ b/ext/wasm/api/pre-js.c-pp.js @@ -17,9 +17,9 @@ /** This file was preprocessed using: -//#@policy error +//#@ policy error @c-pp::argv@ -//#@policy off +//#@ policy off */ //#if unsupported-build /** @@ -30,9 +30,10 @@ load. It may not work properly. Only builds _directly_ targeting browser environments ("vanilla" JS and ESM modules) are supported and tested. Builds which _indirectly_ target browsers (namely - bundler-friendly builds) are not supported deliverables. + bundler-friendly builds and any node builds) are not supported + deliverables. */ -//#endif +//#/if //#if not target:es6-bundler-friendly (function(Module){ const sIMS = @@ -101,7 +102,7 @@ "result =", theFile ); return theFile; -//#endif target:es6-module +//#/if target:es6-module }.bind(sIMS); //#if Module.instantiateWasm and not wasmfs and not target:node @@ -147,7 +148,7 @@ .then(finalThen) return loadWasm(); }.bind(sIMS); -//#endif Module.instantiateWasm and not wasmfs +//#/if Module.instantiateWasm and not wasmfs })(Module); -//#endif not target:es6-bundler-friendly +//#/if not target:es6-bundler-friendly /* END FILE: api/pre-js.js. */ diff --git a/ext/wasm/api/sqlite3-api-glue.c-pp.js b/ext/wasm/api/sqlite3-api-glue.c-pp.js index a51176e9e4..9c525bd4c7 100644 --- a/ext/wasm/api/sqlite3-api-glue.c-pp.js +++ b/ext/wasm/api/sqlite3-api-glue.c-pp.js @@ -122,11 +122,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"], ["sqlite3_column_int","int", "sqlite3_stmt*", "int"], ["sqlite3_column_name","string", "sqlite3_stmt*", "int"], -//#define proxy-text-apis=1 +//#define proxy-text-apis 1 //#if not proxy-text-apis /* Search this file for tag:proxy-text-apis to see what this is about. */ ["sqlite3_column_text","string", "sqlite3_stmt*", "int"], -//#endif +//#/if ["sqlite3_column_type","int", "sqlite3_stmt*", "int"], ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"], ["sqlite3_commit_hook", "void*", [ @@ -326,7 +326,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ ["sqlite3_value_subtype", "int", "sqlite3_value*"], //#if not proxy-text-apis ["sqlite3_value_text", "string", "sqlite3_value*"], -//#endif +//#/if ["sqlite3_value_type", "int", "sqlite3_value*"], ["sqlite3_vfs_find", "*", "string"], ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], @@ -502,7 +502,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ ["sqlite3_activate_see", undefined, "string"] ); } -//#endif enable-see +//#/if enable-see if( wasm.bigIntEnabled && !!wasm.exports.sqlite3_declare_vtab ){ bindingSignatures.int64.push( @@ -1696,7 +1696,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ : null; }; }/*text-return-related bindings*/ -//#endif proxy-text-apis +//#/if proxy-text-apis {/* sqlite3_config() */ /** diff --git a/ext/wasm/api/sqlite3-api-oo1.c-pp.js b/ext/wasm/api/sqlite3-api-oo1.c-pp.js index 9338eef336..13aa427194 100644 --- a/ext/wasm/api/sqlite3-api-oo1.c-pp.js +++ b/ext/wasm/api/sqlite3-api-oo1.c-pp.js @@ -215,7 +215,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ if(stmt) stmt.finalize(); } }; -//#endif enable-see +//#/if enable-see /** A proxy for DB class constructors. It must be called with the @@ -301,7 +301,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ try{ //#if enable-see dbCtorApplySEEKey(this,opt); -//#endif +//#/if // Check for per-VFS post-open SQL/callback... const pVfs = capi.sqlite3_js_db_vfs(pDb) || toss3("Internal error: cannot get VFS for new db handle."); @@ -453,7 +453,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ is supplied and the database is encrypted, execution of the post-initialization SQL will fail, causing the constructor to throw. -//#endif enable-see +//#/if enable-see The `filename` and `vfs` arguments may be either JS strings or C-strings allocated via WASM. `flags` is required to be a JS @@ -1141,7 +1141,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return arg.returnVal(); }/*exec()*/, -//#if nope +//#if 0 /** Experimental and untested - do not use. @@ -1265,7 +1265,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } return this; }/*forEachStmt()*/, -//#endif nope +//#/if nope /** Creates a new UDF (User-Defined Function) which is accessible @@ -2426,4 +2426,4 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }); //#else /* Built with the omit-oo1 flag. */ -//#endif if not omit-oo1 +//#/if if not omit-oo1 diff --git a/ext/wasm/api/sqlite3-api-worker1.c-pp.js b/ext/wasm/api/sqlite3-api-worker1.c-pp.js index 25262abf85..d2103ca850 100644 --- a/ext/wasm/api/sqlite3-api-worker1.c-pp.js +++ b/ext/wasm/api/sqlite3-api-worker1.c-pp.js @@ -677,4 +677,4 @@ sqlite3.initWorker1API = function(){ }); //#else /* Built with the omit-oo1 flag. */ -//#endif if not omit-oo1 +//#/if if not omit-oo1 diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js index 9aed973e26..a3a86067d4 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -811,11 +811,11 @@ const installAsyncProxy = function(){ const slotWhichOp = opIds.whichOp; const idleWaitTime = state.asyncIdleWaitTime; const hasWaitAsync = !!Atomics.waitAsync; -//#if nope +//#if 0 error("waitLoop init: isWebLocker",isWebLocker, "idleWaitTime",idleWaitTime, "hasWaitAsync",hasWaitAsync); -//#endif +//#/if while(!flagAsyncShutdown){ try { let opId; @@ -882,7 +882,7 @@ const installAsyncProxy = function(){ operation */ ) || []; //error("waitLoop() whichOp =",opId, f.opHandlers[opId].key, args); -//#if nope +//#if 0 if( isWebLocker && (opId==opIds.xLock || opIds==opIds.xUnlock) ){ /* An expert suggests that this introduces a race condition, but my eyes aren't seeing it. The hope was that this @@ -891,7 +891,7 @@ const installAsyncProxy = function(){ hnd(...args); continue; } -//#endif +//#/if await hnd(...args); }catch(e){ error('in waitLoop():', e); diff --git a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js index 88f81226a6..0db303bc46 100644 --- a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js @@ -25,9 +25,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ delete sqlite3.capi.KVVfsFile; } //#else -//#@policy error +//#@ policy error //#savepoint begin -//#define kvvfs-v2-added-in=3.52.0 +//#define kvvfs-v2-added-in "3.52.0" /** kvvfs - the Key/Value VFS - is an SQLite3 VFS which delegates @@ -581,7 +581,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ ? cache.storagePool[zClass] : cache.storagePool[wasm.cstrToJs(zClass)]; -//#if nope +//#if 0 // fileForDb() works but we don't have a current need for it. /** Expects an (sqlite3*). Uses sqlite3_file_control() to extract its @@ -624,7 +624,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ throw e; } }; -//#endif nope +//#/if const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKey; /** @@ -968,7 +968,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return 0; } -//#if nope +//#if 0 // these impls work but there's currently no pressing need _not_ use // the native impls. xCurrentTime: function(pVfs,pOut){ @@ -980,7 +980,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ wasm.poke64(pOut, (2440587.5 * 86400000) + Date.now()); return 0; } -//#endif +//#/if }/*.vfs*/, /** @@ -1076,7 +1076,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } }, -//#if not nope +//#if 0 // We override xRead/xWrite only for logging/debugging. They // should otherwise be disabled (it's faster that way). xRead: function(pFile,pTgt,n,iOff64){ @@ -1107,9 +1107,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return cache.setError(e); } }, -//#endif nope +//#/if -//#if nope +//#if 0 xTruncate: function(pFile,i64){}, xFileSize: function(pFile,pi64Out){}, xLock: function(pFile,iLock){}, @@ -1117,7 +1117,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ xCheckReservedLock: function(pFile,piOut){}, xSectorSize: function(pFile){}, xDeviceCharacteristics: function(pFile){} -//#endif +//#/if }/*.ioDb*/, ioJrnl:{ @@ -1125,7 +1125,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ are copied as-is from the ioDb objects. Others are specific to journal files. */ xClose: true, -//#if nope +//#if 0 xRead: function(pFile,pTgt,n,iOff64){}, xWrite: function(pFile,pSrc,n,iOff64){}, xTruncate: function(pFile,i64){}, @@ -1137,15 +1137,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ xCheckReservedLock: true, xSectorSize: true, xDeviceCharacteristics: true -//#endif +//#/if }/*.ioJrnl*/ }/*methodOverrides*/; -//#if nope +//#if 0 debug("pVfs and friends", pVfs, pIoDb, pIoJrnl, kvvfsMethods, capi.sqlite3_file.structInfo, KVVfsFile.structInfo); -//#endif +//#/if try { util.assert( cache.buffer.n>1024*129, "Heap buffer is not large enough" @@ -1235,7 +1235,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ limitation which has since been overcome, but removal of JsStorageDb.prototype.clearStorage() would be a backwards compatibility break, so this function permits wiping the storage for those two - cases even if they are opened. Use with case. + cases even if they are opened. Use with care. */ const sqlite3_js_kvvfs_clear = function callee(which){ if( ''===which ){ @@ -1844,7 +1844,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return jdb.storageSize(this.affirmOpen().dbFilename(), true); }; }/*sqlite3.oo1.JsStorageDb*/ -//#endif not omit-oo1 +//#/if not omit-oo1 if( sqlite3.__isUnderTest && sqlite3.vtab ){ /** @@ -2008,7 +2008,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }/* virtual table */ -//#if nope +//#if 0 /** The idea here is a simpler wrapper for listening to kvvfs changes. Clients would override its onXyz() event methods @@ -2095,8 +2095,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ async onOpen(count){} async onClose(count){} }/*KvvfsListener*/; -//#endif nope +//#/if nope })/*globalThis.sqlite3ApiBootstrap.initializers*/; //#savepoint rollback -//#endif not omit-kvvfs +//#/if not omit-kvvfs diff --git a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js index 689f53d4a7..2990fb1470 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js @@ -1471,4 +1471,4 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ The OPFS SAH Pool VFS parts are elided from builds targeting node.js. */ -//#endif target:node +//#/if target:node diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index dbd786410a..30b24869d6 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -130,4 +130,4 @@ globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ }); }); }/*sqlite3ApiBootstrap.initializers.push()*/); -//#endif target:node +//#/if target:node diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 53619bfc92..8edfab4dab 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -177,4 +177,4 @@ globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ }) }); }/*sqlite3ApiBootstrap.initializers.push()*/); -//#endif target:node +//#/if target:node diff --git a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js index b282c5e6e1..bcbf3fa9f8 100644 --- a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js +++ b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js @@ -24,7 +24,7 @@ */ //#if not defined target:es6-module 'use strict'; -//#endif +//#/if /** Configures an sqlite3 Worker API #1 Worker such that it can be manipulated via a Promise-based interface and returns a factory @@ -278,13 +278,13 @@ globalThis.sqlite3Worker1Promiser.defaultConfig = { } } return new Worker(theJs + globalThis.location.search); -//#endif +//#/if } //#if not target:es6-module .bind({ currentScript: globalThis?.document?.currentScript }) -//#endif +//#/if , onerror: (...args)=>console.error('sqlite3Worker1Promiser():',...args) }/*defaultConfig*/; @@ -349,7 +349,7 @@ globalThis.sqlite3Worker1Promiser.v2.defaultConfig = */ export default sqlite3Worker1Promiser.v2; delete globalThis.sqlite3Worker1Promiser; -//#endif /* target:es6-module */ +//#/if /* target:es6-module */ //#else /* Built with the omit-oo1 flag. */ -//#endif if not omit-oo1 +//#/if if not omit-oo1 diff --git a/ext/wasm/api/sqlite3-worker1.c-pp.js b/ext/wasm/api/sqlite3-worker1.c-pp.js index db27c8fc0e..046243baa5 100644 --- a/ext/wasm/api/sqlite3-worker1.c-pp.js +++ b/ext/wasm/api/sqlite3-worker1.c-pp.js @@ -49,8 +49,8 @@ import sqlite3InitModule from './sqlite3.mjs'; //console.warn("worker1 theJs =",theJs); importScripts(theJs); } -//#endif +//#/if sqlite3InitModule().then(sqlite3 => sqlite3.initWorker1API()); //#else /* Built with the omit-oo1 flag. */ -//#endif if not omit-oo1 +//#/if if not omit-oo1 diff --git a/ext/wasm/c-pp-lite.c b/ext/wasm/c-pp-lite.c deleted file mode 100644 index b8d67f6a39..0000000000 --- a/ext/wasm/c-pp-lite.c +++ /dev/null @@ -1,2804 +0,0 @@ -/* -** 2022-11-12: -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** * May you do good and not evil. -** * May you find forgiveness for yourself and forgive others. -** * May you share freely, never taking more than you give. -** -************************************************************************ -** -** The C-minus Preprocessor: a truly minimal C-like preprocessor. -** Why? Because C preprocessors _can_ process non-C code but generally make -** quite a mess of it. The purpose of this application is an extremely -** minimal preprocessor with only the most basic functionality of a C -** preprocessor, namely. -** -** The supported preprocessor directives are documented in the -** README.md hosted with this file. -** -** Any mention of "#" in the docs, e.g. "#if", is symbolic. The -** directive delimiter is configurable and defaults to "##". Define -** CMPP_DEFAULT_DELIM to a string when compiling to define the default -** at build-time. -** -** This preprocessor has only minimal support for replacement of tokens -** which live in the "content" blocks of inputs (that is, the pieces -** which are not prepocessor lines). -** -** See this file's README.md for details. -** -** Design note: this code makes use of sqlite3. Though not _strictly_ -** needed in order to implement it, this tool was specifically created -** for use with the sqlite3 project's own JavaScript code, so there's -** no reason not to make use of it to do some of the heavy lifting. It -** does not require any cutting-edge sqlite3 features and should be -** usable with any version which supports `WITHOUT ROWID`. -** -** Author(s): -** -** - Stephan Beal -** -** Canonical homes: -** -** - https://fossil.wanderinghorse.net/r/c-pp -** - https://sqlite.org/src/file/ext/wasm/c-pp.c -** -** With the former hosting this app's SCM and the latter being the -** single known deployment of c-pp.c, where much of its development -** happens. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "sqlite3.h" - -#if defined(_WIN32) || defined(WIN32) -# include -# include -# ifndef access -# define access(f,m) _access((f),(m)) -# endif -#else -# include -#endif - -#ifndef CMPP_DEFAULT_DELIM -#define CMPP_DEFAULT_DELIM "##" -#endif - -#ifndef CMPP_ATSIGN -#define CMPP_ATSIGN (unsigned char)'@' -#endif - -#if 1 -# define CMPP_NORETURN __attribute__((noreturn)) -#else -# define CMPP_NORETURN -#endif - -/* Fatally exits the app with the given printf-style message. */ -static CMPP_NORETURN void fatalv__base(char const *zFile, int line, - char const *zFmt, va_list); -static CMPP_NORETURN void fatal__base(char const *zFile, int line, - char const *zFmt, ...); -#define fatalv(...) fatalv__base(__FILE__,__LINE__,__VA_ARGS__) -#define fatal(...) fatal__base(__FILE__,__LINE__,__VA_ARGS__) - -/** Proxy for free(), for symmetry with cmpp_realloc(). */ -static void cmpp_free(void *p); -/** A realloc() proxy which dies fatally on allocation error. */ -static void * cmpp_realloc(void * p, unsigned n); -#if 0 -/** A malloc() proxy which dies fatally on allocation error. */ -static void * cmpp_malloc(unsigned n); -#endif - -static void check__oom2(void const *p, char const *zFile, int line){ - if(!p) fatal("Alloc failed at %s:%d", zFile, line); -} -#define check__oom(P) check__oom2((P), __FILE__, __LINE__) - -/* -** If p is stdin or stderr then this is a no-op, else it is a -** proxy for fclose(). This is a no-op if p is NULL. -*/ -static void FILE_close(FILE *p); -/* -** Works like fopen() but accepts the special name "-" to mean either -** stdin (if zMode indicates a real-only mode) or stdout. Fails -** fatally on error. -*/ -static FILE * FILE_open(char const *zName, const char * zMode); -/* -** Reads the entire contents of the given file, allocating it in a -** buffer which gets assigned to `*pOut`. `*nOut` gets assigned the -** length of the output buffer. Fails fatally on error. -*/ -static void FILE_slurp(FILE *pFile, unsigned char **pOut, - unsigned * nOut); - -/* -** Intended to be passed an sqlite3 result code. If it's a non-0 value -** other than SQLITE_ROW or SQLITE_DONE then it emits a fatal error -** message which contains both the given string and the -** sqlite3_errmsg() from the application's database instance. -*/ -static void db_affirm_rc(int rc, const char * zMsg); - -/* -** Proxy for sqlite3_str_finish() which fails fatally if that -** routine returns NULL. -*/ -static char * db_str_finish(sqlite3_str *s, int * n); -/* -** Proxy for sqlite3_str_new() which fails fatally if that -** routine returns NULL. -*/ -static sqlite3_str * db_str_new(void); - -/* -** Proxy for sqlite3_step() which fails fatally if the result -** is anything other than SQLITE_ROW or SQLITE_DONE. -*/ -static int db_step(sqlite3_stmt *pStmt); -/* -** Proxy for sqlite3_bind_int() which fails fatally on error. -*/ -static void db_bind_int(sqlite3_stmt *pStmt, int col, int val); -/* -** Proxy for sqlite3_bind_null() which fails fatally on error. -*/ -static void db_bind_null(sqlite3_stmt *pStmt, int col); -/* -** Proxy for sqlite3_bind_text() which fails fatally on error. -*/ -static void db_bind_text(sqlite3_stmt *pStmt, int col, const char * zStr); -/* -** Proxy for sqlite3_bind_text() which fails fatally on error. -*/ -static void db_bind_textn(sqlite3_stmt *pStmt, int col, const char * zStr, int len); -#if 0 -/* -** Proxy for sqlite3_bind_text() which fails fatally on error. It uses -** sqlite3_str_vappendf() so supports all of its formatting options. -*/ -static void db_bind_textv(sqlite3_stmt *pStmt, int col, const char * zFmt, ...); -#endif -/* -** Proxy for sqlite3_free(), to be passed any memory which is allocated -** by sqlite3_malloc(). -*/ -static void db_free(void *m); - -/* -** Returns true if the first nKey bytes of zKey are a legal string. If -** it returns false and zErrPos is not null, *zErrPos is set to the -** position of the illegal character. If nKey is negative, strlen() is -** used to calculate it. -*/ -static int cmpp_is_legal_key(char const *zKey, int nKey, char const **zErrPos); - -/* -** Fails fatally if !cmpp_is_legal_key(zKey). -*/ -static void cmpp_affirm_legal_key(char const *zKey, int nKey); - -/* -** Adds the given `#define` macro name to the list of macros, ignoring -** any duplicates. Fails fatally on error. -** -** If zVal is NULL then zKey may contain an '=', from which the value -** will be extracted. If zVal is not NULL then zKey may _not_ contain -** an '='. -*/ -static void db_define_add(const char * zKey, char const *zVal); - -/* -** Returns true if the given key is already in the `#define` list, -** else false. Fails fatally on db error. -** -** nName is the length of the key part of zName (which might have -** a following =y part. If it's negative, strlen() is used to -** calculate it. -*/ -static int db_define_has(const char * zName, int nName); - -/* -** Returns true if the given key is already in the `#define` list, and -** it has a truthy value (is not empty and not equal to '0'), else -** false. Fails fatally on db error. -** -** nName is the length of zName, or <0 to use strlen() to figure -** it out. -*/ -static int db_define_get_bool(const char * zName, int nName); - -/* -** Searches for a define where (k GLOB zName). If one is found, a copy -** of it is assigned to *zVal (the caller must eventually db_free() -** it)), *nVal (if nVal is not NULL) is assigned its strlen, and -** returns non-0. If no match is found, 0 is returned and neither -** *zVal nor *nVal are modified. If more than one result matches, a -** fatal error is triggered. -** -** It is legal for *zVal to be NULL (and *nVal to be 0) if it returns -** non-0. That just means that the key was defined with no value part. -*/ -static int db_define_get(const char * zName, int nName, char **zVal, unsigned int *nVal); - -/* -** Removes the given `#define` macro name from the list of -** macros. Fails fatally on error. -*/ -static void db_define_rm(const char * zKey); -/* -** Adds the given filename to the list of being-`#include`d files, -** using the given source file name and line number of error reporting -** purposes. If recursion is later detected. -*/ -static void db_including_add(const char * zKey, const char * zSrc, int srcLine); -/* -** Adds the given dir to the list of includes. They are checked in the -** order they are added. -*/ -static void db_include_dir_add(const char * zKey); -/* -** Returns a resolved path of PREFIX+'/'+zKey, where PREFIX is one of -** the `#include` dirs (db_include_dir_add()). If no file match is -** found, NULL is returned. Memory must eventually be passed to -** db_free() to free it. -*/ -static char * db_include_search(const char * zKey); -/* -** Removes the given key from the `#include` list. -*/ -static void db_include_rm(const char * zKey); -/* -** A proxy for sqlite3_prepare() which fails fatally on error. -*/ -static void db_prepare(sqlite3_stmt **pStmt, const char * zSql, ...); - -/* -** Opens the given file and processes its contents as c-pp, sending -** all output to the global c-pp output channel. Fails fatally on -** error. If bRaw is true then the file's contents are passed through -** verbatim, rather than being preprocessed. -*/ -static void cmpp_process_file(const char * zName, int bRaw); - -/* -** Operator policy for cmpp_kvp_parse(). -*/ -enum cmpp_key_op_e { - /* Fail if the key contains an operator. */ - cmpp_key_op_none, - /* Accept only '='. */ - cmpp_key_op_eq1 -}; -typedef enum cmpp_key_op_e cmpp_key_op_e; - -/* -** Operators and operator policies for use with X=Y-format keys. -*/ -#define cmpp_kvp_op_map(E) \ - E(none,"") \ - E(eq1,"=") \ - E(eq2,"==") \ - E(lt,"<") \ - E(le,"<=") \ - E(gt,">") \ - E(ge,">=") - -enum cmpp_kvp_op_e { -#define E(N,S) cmpp_kvp_op_ ## N, - cmpp_kvp_op_map(E) -#undef E -}; -typedef enum cmpp_kvp_op_e cmpp_kvp_op_e; - -/* -** A snippet from a string. -*/ -struct cmpp_snippet { - char const *z; - unsigned int n; -}; -typedef struct cmpp_snippet cmpp_snippet; -#define cmpp_snippet_empty_m {0,0} - -/* -** Result type for cmpp_kvp_parse(). -*/ -struct cmpp_kvp { - cmpp_snippet k; - cmpp_snippet v; - cmpp_kvp_op_e op; -}; - -typedef struct cmpp_kvp cmpp_kvp; -#define cmpp_kvp_empty_m \ - {cmpp_snippet_empty_m,cmpp_snippet_empty_m,cmpp_kvp_op_none} -static const cmpp_kvp cmpp_kvp_empty = cmpp_kvp_empty_m; - -/* -** Parses X or X=Y into p. Fails fatally on error. -** -** If nKey is negative then strlen() is used to calculate it. -** -** The third argument specifies whether/how to permit/treat the '=' -** part of X=Y. -*/ -static void cmpp_kvp_parse(cmpp_kvp * p, - char const *zKey, int nKey, - cmpp_kvp_op_e opPolicy); - -/* -** Wrapper around a FILE handle. -*/ -typedef struct FileWrapper FileWrapper; -struct FileWrapper { - /* File's name. */ - char const *zName; - /* FILE handle. */ - FILE * pFile; - /* Where FileWrapper_slurp() stores the file's contents. */ - unsigned char * zContent; - /* Size of this->zContent, as set by FileWrapper_slurp(). */ - unsigned nContent; - /* See Global::pFiles. */ - FileWrapper * pTail; -}; -#define FileWrapper_empty_m {0,0,0,0,0} -static const FileWrapper FileWrapper_empty = FileWrapper_empty_m; - -/* -** Proxy for FILE_close() and frees all memory owned by p. A no-op if -** p is already closed. -*/ -static void FileWrapper_close(FileWrapper * p); -/* Proxy for FILE_open(). Closes p first if it's currently opened. */ -static void FileWrapper_open(FileWrapper * p, const char * zName, const char *zMode); -/* Proxy for FILE_slurp(). */ -static void FileWrapper_slurp(FileWrapper * p); -/* -** If p->zContent ends in \n or \r\n, that part is replaced with 0 and -** p->nContent is adjusted. Returns true if it chomps, else false. -*/ -int FileWrapper_chomp(FileWrapper * p); - -/* -** Outputs a printf()-formatted message to stderr. -*/ -static void g_stderr(char const *zFmt, ...); -/* -** Outputs a printf()-formatted message to stderr. -*/ -static void g_stderrv(char const *zFmt, va_list); -#define g_debug(lvl,pfexpr) \ - if(lvl<=g.flags.doDebug) g_stderr("%s @ %s():%d: ",g.zArgv0,__func__,__LINE__); \ - if(lvl<=g.flags.doDebug) g_stderr pfexpr - -#define g_warn(zFmt,...) g_stderr("%s:%d %s() " zFmt "\n", __FILE__, __LINE__, __func__, __VA_ARGS__) -#define g_warn0(zMsg) g_stderr("%s:%d %s() %s\n", __FILE__, __LINE__, __func__, zMsg) - -void cmpp_free(void *p){ - sqlite3_free(p); -} - -void * cmpp_realloc(void * p, unsigned n){ - void * const rc = sqlite3_realloc(p, n); - if(!rc) fatal("realloc(P,%u) failed", n); - return rc; -} - -#if 0 -void * cmpp_malloc(unsigned n){ - void * const rc = sqlite3_alloc(n); - if(!rc) fatal("malloc(%u) failed", n); - return rc; -} -#endif - -FILE * FILE_open(char const *zName, const char * zMode){ - FILE * p; - if('-'==zName[0] && 0==zName[1]){ - p = strstr(zMode,"w") ? stdout : stdin; - }else{ - p = fopen(zName, zMode); - if(!p) fatal("Cannot open file [%s] with mode [%s]", zName, zMode); - } - return p; -} - -void FILE_close(FILE *p){ - if(p && p!=stdout && p!=stderr){ - fclose(p); - } -} - -void FILE_slurp(FILE *pFile, unsigned char **pOut, - unsigned * nOut){ - unsigned char zBuf[1024 * 8]; - unsigned char * pDest = 0; - unsigned nAlloc = 0; - unsigned nOff = 0; - /* Note that this needs to be able to work on non-seekable streams, - ** thus we read in chunks instead of doing a single alloc and - ** filling it in one go. */ - while( !feof(pFile) ){ - size_t const n = fread(zBuf, 1, sizeof(zBuf), pFile); - if(n>0){ - if(nAlloc < nOff + n + 1){ - nAlloc = nOff + n + 1; - pDest = cmpp_realloc(pDest, nAlloc); - } - memcpy(pDest + nOff, zBuf, n); - nOff += n; - } - } - if(pDest) pDest[nOff] = 0; - *pOut = pDest; - *nOut = nOff; -} - -void FileWrapper_close(FileWrapper * p){ - if(p->pFile) FILE_close(p->pFile); - if(p->zContent) cmpp_free(p->zContent); - *p = FileWrapper_empty; -} - -void FileWrapper_open(FileWrapper * p, const char * zName, - const char * zMode){ - FileWrapper_close(p); - p->pFile = FILE_open(zName, zMode); - p->zName = zName; -} - -void FileWrapper_slurp(FileWrapper * p){ - assert(!p->zContent); - assert(p->pFile); - FILE_slurp(p->pFile, &p->zContent, &p->nContent); -} - -int FileWrapper_chomp(FileWrapper * p){ - if( p->nContent && '\n'==p->zContent[p->nContent-1] ){ - p->zContent[--p->nContent] = 0; - if( p->nContent && '\r'==p->zContent[p->nContent-1] ){ - p->zContent[--p->nContent] = 0; - } - return 1; - } - return 0; -} - -enum CmppParseState { -TS_Start = 1, -TS_If, -TS_IfPassed, -TS_Else, -TS_Error -}; -typedef enum CmppParseState CmppParseState; -enum CmppTokenType { - -#define CmppToken_map(E) \ - E(Invalid,0) \ - E(Assert,"assert") \ - E(AtPolicy,"@policy") \ - E(Comment,"//") \ - E(Define,"define") \ - E(Elif,"elif") \ - E(Else,"else") \ - E(Endif,"endif") \ - E(Error,"error") \ - E(If,"if") \ - E(Include,"include") \ - E(Line,0) \ - E(Opaque,0) \ - E(Pragma,"pragma") \ - E(Savepoint,"savepoint") \ - E(Stderr,"stderr") \ - E(Undef,"undef") - -#define E(N,TOK) TT_ ## N, - CmppToken_map(E) -#undef E -}; -typedef enum CmppTokenType CmppTokenType; - -/* -** Map of directive (formerly keyword) names and their token types. -*/ -static const struct { -#define E(N,TOK) struct cmpp_snippet N; - CmppToken_map(E) -#undef E -} DStrings = { -#define E(N,TOK) .N = {TOK,sizeof(TOK)-1}, - CmppToken_map(E) -#undef E -}; - -//static -char const * TT_cstr(int tt){ - switch(tt){ -#define E(N,TOK) case TT_ ## N: return DStrings.N.z; - CmppToken_map(E) -#undef E - } - return NULL; -} - -struct CmppToken { - CmppTokenType ttype; - /* Line number of this token in the source file. */ - unsigned lineNo; - /* Start of the token. */ - unsigned char const * zBegin; - /* One-past-the-end byte of the token. */ - unsigned char const * zEnd; -}; -typedef struct CmppToken CmppToken; -#define CmppToken_empty_m {TT_Invalid,0,0,0} -static const CmppToken CmppToken_empty = CmppToken_empty_m; - -/* -** CmppLevel represents one "level" of tokenization, starting at the -** top of the main input, incrementing once for each level of `#if`, -** and decrementing for each `#endif`. -** pushes a level. -*/ -typedef struct CmppLevel CmppLevel; -struct CmppLevel { - unsigned short flags; - /* - ** Used for controlling which parts of an if/elif/...endif chain - ** should get output. - */ - unsigned short skipLevel; - /* The token which started this level (an 'if' or 'include'). */ - CmppToken token; - CmppParseState pstate; -}; -#define CmppLevel_empty_m {0U,0U,CmppToken_empty_m,TS_Start} -static const CmppLevel CmppLevel_empty = CmppLevel_empty_m; -enum CmppLevel_Flags { -/* Max depth of nested `#if` constructs in a single tokenizer. */ -CmppLevel_Max = 10, -/* Max number of keyword arguments. */ -CmppArgs_Max = 15, -/* Directive line buffer size */ -CmppArgs_BufSize = 1024, -/* Flag indicating that output for a CmpLevel should be elided. */ -CmppLevel_F_ELIDE = 0x01, -/* -** Mask of CmppLevel::flags which are inherited when CmppLevel_push() -** is used. -*/ -CmppLevel_F_INHERIT_MASK = CmppLevel_F_ELIDE -}; - -typedef struct CmppTokenizer CmppTokenizer; -typedef struct CmppKeyword CmppKeyword; -typedef void (*cmpp_keyword_f)(CmppKeyword const * pKw, CmppTokenizer * t); -struct CmppKeyword { - const char *zName; - unsigned nName; - int bTokenize; - CmppTokenType ttype; - cmpp_keyword_f xCall; -}; - -static CmppKeyword const * CmppKeyword_search(const char *zName); -static void cmpp_process_keyword(CmppTokenizer * const t); - -/* -** Tokenizer for c-pp input files. -*/ -struct CmppTokenizer { - const char * zName; /* Input (file) name for error reporting */ - unsigned const char * zBegin; /* start of input */ - unsigned const char * zEnd; /* one-after-the-end of input */ - unsigned const char * zPos; /* current position */ - unsigned int lineNo; /* line # of current pos */ - unsigned nSavepoint; - CmppParseState pstate; - CmppToken token; /* current token result */ - struct { - unsigned ndx; - CmppLevel stack[CmppLevel_Max]; - } level; - /* Args for use in cmpp_keyword_f() impls. */ - struct { - CmppKeyword const * pKw; - int argc; - const unsigned char * argv[CmppArgs_Max]; - unsigned char lineBuf[CmppArgs_BufSize]; - } args; -}; -#define CT_level(t) (t)->level.stack[(t)->level.ndx] -#define CT_pstate(t) CT_level(t).pstate -#define CT_skipLevel(t) CT_level(t).skipLevel -#define CLvl_skip(lvl) ((lvl)->skipLevel || ((lvl)->flags & CmppLevel_F_ELIDE)) -#define CT_skip(t) CLvl_skip(&CT_level(t)) -#define CmppTokenizer_empty_m { \ - .zName=0, .zBegin=0, .zEnd=0, \ - .zPos=0, \ - .lineNo=1U, \ - .pstate = TS_Start, \ - .token = CmppToken_empty_m, \ - .level = {0U,{CmppLevel_empty_m}}, \ - .args = {0,0,{0},{0}} \ - } -static const CmppTokenizer CmppTokenizer_empty = CmppTokenizer_empty_m; - -static void CmppTokenizer_cleanup(CmppTokenizer * const t); - -static void cmpp_t_out(CmppTokenizer * t, void const *z, unsigned int n); -/*static void cmpp_t_outf(CmppTokenizer * t, char const *zFmt, ...);*/ - -/* -** Pushes a new level into the given tokenizer. Fails fatally if -** it's too deep. -*/ -static void CmppLevel_push(CmppTokenizer * const t); -/* -** Pops a level from the tokenizer. Fails fatally if the top -** level is popped. -*/ -static void CmppLevel_pop(CmppTokenizer * const t); -/* -** Returns the current level object. -*/ -static CmppLevel * CmppLevel_get(CmppTokenizer * const t); - -/* -** Policies for how to handle undefined @tokens@ when performing -** content filtering. -*/ -enum AtPolicy { - AT_invalid = -1, - /** Turn off @foo@ parsing. */ - AT_OFF = 0, - /** Retain undefined @foo@ - emit it as-is. */ - AT_RETAIN, - /** Elide undefined @foo@. */ - AT_ELIDE, - /** Error for undefined @foo@. */ - AT_ERROR, - AT_DEFAULT = AT_ERROR -}; -typedef enum AtPolicy AtPolicy; - -static AtPolicy AtPolicy_fromStr(char const *z, int bEnforce){ - if( 0==strcmp(z, "retain") ) return AT_RETAIN; - if( 0==strcmp(z, "elide") ) return AT_ELIDE; - if( 0==strcmp(z, "error") ) return AT_ERROR; - if( 0==strcmp(z, "off") ) return AT_OFF; - if( bEnforce ){ - fatal("Invalid @ policy value: %s. " - "Try one of retain|elide|error|off.", z); - } - return AT_invalid; -} - -/* -** Global app state singleton. -*/ -static struct Global { - /* main()'s argv[0]. */ - const char * zArgv0; - /* App's db instance. */ - sqlite3 * db; - /* Current tokenizer (for error reporting purposes). */ - CmppTokenizer const * tok; - /* - ** We use a linked-list of these to keep track of our opened - ** files so that we can clean then up via atexit() in the case of - ** fatal error (to please valgrind). - */ - FileWrapper * pFiles; - /* Output channel. */ - FileWrapper out; - struct { - /* - ** Bytes of the keyword delimiter/prefix. Owned - ** elsewhere. - */ - const char * z; - /* Byte length of this->zDelim. */ - unsigned short n; - /* - ** The @token@ delimiter. - ** - ** Potential TODO is replace this with a pair of opener/closer - ** strings, e.g. "{{" and "}}". - */ - const unsigned char chAt; - } delim; - struct { -#define CMPP_SAVEPOINT_NAME "_cmpp_" -#define GStmt_map(E) \ - E(defIns,"INSERT OR REPLACE INTO def(k,v) VALUES(?,?)") \ - E(defDel,"DELETE FROM def WHERE k GLOB ?") \ - E(defHas,"SELECT 1 FROM def WHERE k GLOB ?") \ - E(defGet,"SELECT k,v FROM def WHERE k GLOB ?") \ - E(defGetBool, \ - "SELECT 1 FROM def WHERE k = ?1" \ - " AND v IS NOT NULL" \ - " AND '0'!=v AND ''!=v") \ - E(defSelAll,"SELECT k,v FROM def ORDER BY k") \ - E(inclIns,"INSERT OR FAIL INTO incl(file,srcFile," \ - "srcLine) VALUES(?,?,?)") \ - E(inclDel,"DELETE FROM incl WHERE file=?") \ - E(inclHas,"SELECT 1 FROM incl WHERE file=?") \ - E(inclPathAdd,"INSERT OR FAIL INTO " \ - "inclpath(seq,dir) VALUES(?,?)") \ - E(inclSearch, \ - "SELECT ?1 fn WHERE fileExists(fn) " \ - "UNION ALL SELECT * FROM (" \ - "SELECT replace(dir||'/'||?1, '//','/') AS fn " \ - "FROM inclpath WHERE fileExists(fn) ORDER BY seq"\ - ")") \ - E(spBegin,"SAVEPOINT " CMPP_SAVEPOINT_NAME) \ - E(spRollback,"ROLLBACK TO SAVEPOINT " \ - CMPP_SAVEPOINT_NAME) \ - E(spRelease,"RELEASE SAVEPOINT " CMPP_SAVEPOINT_NAME) - -#define E(N,S) sqlite3_stmt * N; - GStmt_map(E) -#undef E - } stmt; - struct { - FILE * pFile; - int expandSql; - } sqlTrace; - struct { - AtPolicy atPolicy; - /* If true, enables certain debugging output. */ - char doDebug; - /* If true, chomp() files read via -Fx=file. */ - char chompF; - } flags; -} g = { - .zArgv0 = "?", - .db = 0, - .tok = 0, - .pFiles = 0, - .out = FileWrapper_empty_m, - .delim = { - .z = CMPP_DEFAULT_DELIM, - .n = (unsigned short) sizeof(CMPP_DEFAULT_DELIM)-1, - .chAt = '@' - }, - .stmt = { - .defIns = 0, - .defDel = 0, - .defHas = 0, - .defGet = 0, - .defGetBool = 0, - .inclIns = 0, - .inclDel = 0, - .inclHas = 0, - .inclPathAdd = 0, - .inclSearch = 0 - }, - .sqlTrace = { - .pFile = 0, - .expandSql = 0 - }, - .flags = { - .atPolicy = AT_OFF, - .doDebug = 0, - .chompF = 0 - } -}; - -/** Distinct IDs for each g.stmt member. */ -enum GStmt_e { - GStmt_none = 0, -#define E(N,S) GStmt_ ## N, - GStmt_map(E) -#undef E -}; - -/* -** Returns the g.stmt.X corresponding to `which`, initializing it if -** needed. It does not return NULL - it fails fatally on error. -*/ -static sqlite3_stmt * g_stmt(enum GStmt_e which){ - sqlite3_stmt ** q = 0; - char const * zSql = 0; - switch(which){ - case GStmt_none: - fatal("GStmt_none is not a valid statement handle"); - return NULL; -#define E(N,S) case GStmt_ ## N: zSql = S; q = &g.stmt.N; break; - GStmt_map(E) -#undef E - } - assert( q ); - assert( zSql && *zSql ); - if( !*q ){ - db_prepare(q, "%s", zSql); - assert( *q ); - } - return *q; -} -static void g_stmt_reset(sqlite3_stmt * const q){ - sqlite3_clear_bindings(q); - sqlite3_reset(q); -} - -#if 0 -/* -** Outputs a printf()-formatted message to c-pp's global output -** channel. -*/ -static void g_outf(char const *zFmt, ...); -void g_outf(char const *zFmt, ...){ - va_list va; - va_start(va, zFmt); - vfprintf(g.out.pFile, zFmt, va); - va_end(va); -} -#endif - -/* Outputs n bytes from z to c-pp's global output channel. */ -static void g_out(void const *z, unsigned int n); -void g_out(void const *z, unsigned int n){ - if(g.out.pFile && 1!=fwrite(z, n, 1, g.out.pFile)){ - int const err = errno; - fatal("fwrite() output failed with errno #%d", err); - } -} - -void g_stderrv(char const *zFmt, va_list va){ - if( g.out.pFile==stdout ){ - fflush(g.out.pFile); - } - vfprintf(stderr, zFmt, va); -} - -void g_stderr(char const *zFmt, ...){ - va_list va; - va_start(va, zFmt); - g_stderrv(zFmt, va); - va_end(va); -} - -/* -** Emits n bytes of z if CT_skip(t) is false. -*/ -void cmpp_t_out(CmppTokenizer * t, void const *z, unsigned int n){ - g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t))); - g_debug(3,("CT_skip() ?= %d\n",CT_skip(t))); - if(!CT_skip(t)) g_out(z, n); -} - -void CmppLevel_push(CmppTokenizer * const t){ - CmppLevel * pPrev; - CmppLevel * p; - if(t->level.ndx+1 == (unsigned)CmppLevel_Max){ - fatal("%sif nesting level is too deep. Max=%d\n", - g.delim.z, CmppLevel_Max); - } - pPrev = &CT_level(t); - g_debug(3,("push from tokenizer level=%u flags=%04x\n", - t->level.ndx, pPrev->flags)); - p = &t->level.stack[++t->level.ndx]; - *p = CmppLevel_empty; - p->token = t->token; - p->flags = (CmppLevel_F_INHERIT_MASK & pPrev->flags); - if(CLvl_skip(pPrev)) p->flags |= CmppLevel_F_ELIDE; - g_debug(3,("push to tokenizer level=%u flags=%04x\n", - t->level.ndx, p->flags)); -} - -void CmppLevel_pop(CmppTokenizer * const t){ - if(!t->level.ndx){ - fatal("Internal error: CmppLevel_pop() at the top of the stack"); - } - g_debug(3,("pop from tokenizer level=%u, flags=%04x skipLevel?=%d\n", - t->level.ndx, - t->level.stack[t->level.ndx].flags, CT_skipLevel(t))); - g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t))); - g_debug(3,("CT_skip() ?= %d\n",CT_skip(t))); - t->level.stack[t->level.ndx--] = CmppLevel_empty; - g_debug(3,("pop to tokenizer level=%u, flags=%04x\n", t->level.ndx, - t->level.stack[t->level.ndx].flags)); - g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t))); - g_debug(3,("CT_skip() ?= %d\n",CT_skip(t))); -} - -CmppLevel * CmppLevel_get(CmppTokenizer * const t){ - return &t->level.stack[t->level.ndx]; -} - - -void db_affirm_rc(int rc, const char * zMsg){ - switch(rc){ - case 0: - case SQLITE_DONE: - case SQLITE_ROW: - break; - default: - assert( g.db ); - fatal("Db error #%d %s: %s", rc, zMsg, - sqlite3_errmsg(g.db)); - } -} - -int db_step(sqlite3_stmt *pStmt){ - int const rc = sqlite3_step(pStmt); - switch( rc ){ - case SQLITE_ROW: - case SQLITE_DONE: - break; - default: - db_affirm_rc(rc, "from db_step()"); - } - return rc; -} - -static sqlite3_str * db_str_new(void){ - sqlite3_str * rc = sqlite3_str_new(g.db); - if(!rc) fatal("Alloc failed for sqlite3_str_new()"); - return rc; -} - -static char * db_str_finish(sqlite3_str *s, int * n){ - int const rc = sqlite3_str_errcode(s); - if(rc) fatal("Error #%d from sqlite3_str_errcode()", rc); - if(n) *n = sqlite3_str_length(s); - char * z = sqlite3_str_finish(s); - if(!z) fatal("Alloc failed for sqlite3_str_new()"); - return z; -} - -void db_prepare(sqlite3_stmt **pStmt, const char * zSql, ...){ - int rc; - sqlite3_str * str = db_str_new(); - char * z = 0; - int n = 0; - va_list va; - va_start(va, zSql); - sqlite3_str_vappendf(str, zSql, va); - va_end(va); - rc = sqlite3_str_errcode(str); - if(rc) fatal("sqlite3_str_errcode() = %d", rc); - z = db_str_finish(str, &n); - rc = sqlite3_prepare_v2(g.db, z, n, pStmt, 0); - if(rc) fatal("Error #%d (%s) preparing: %s", - rc, sqlite3_errmsg(g.db), z); - sqlite3_free(z); -} - -void db_bind_int(sqlite3_stmt *pStmt, int col, int val){ - db_affirm_rc(sqlite3_bind_int(pStmt, col, val), - "from db_bind_int()"); -} - -void db_bind_null(sqlite3_stmt *pStmt, int col){ - db_affirm_rc(sqlite3_bind_null(pStmt, col), - "from db_bind_null()"); -} - -void db_bind_textn(sqlite3_stmt *pStmt, int col, - const char * zStr, int n){ - db_affirm_rc( - (zStr && n) - ? sqlite3_bind_text(pStmt, col, zStr, n, SQLITE_TRANSIENT) - : sqlite3_bind_null(pStmt, col), - "from db_bind_textn()" - ); -} - -void db_bind_text(sqlite3_stmt *pStmt, int col, - const char * zStr){ - db_bind_textn(pStmt, col, zStr, -1); -} - -#if 0 -void db_bind_textv(sqlite3_stmt *pStmt, int col, - const char * zFmt, ...){ - int rc; - sqlite3_str * str = db_str_new(); - int n = 0; - char * z; - va_list va; - va_start(va,zFmt); - sqlite3_str_vappendf(str, zFmt, va); - va_end(va); - z = db_str_finish(str, &n); - rc = sqlite3_bind_text(pStmt, col, z, n, sqlite3_free); - db_affirm_rc(rc,"from db_bind_textv()"); -} -#endif - -void db_free(void *m){ - sqlite3_free(m); -} - -void db_define_add(const char * zKey, char const *zVal){ - cmpp_kvp kvp = cmpp_kvp_empty; - cmpp_kvp_parse(&kvp, zKey, -1, - zVal - ? cmpp_key_op_none - : cmpp_key_op_eq1 - ); - if( kvp.v.z ){ - if( zVal ){ - assert(!"cannot happen - cmpp_key_op_none will prevent it"); - fatal("Cannot assign two values to [%.*s] [%.*s] [%s]", - kvp.k.n, kvp.k.z, kvp.v.n, kvp.v.z, zVal); - } - }else{ - kvp.v.z = zVal; - kvp.v.n = zVal ? (int)strlen(zVal) : 0; - } - sqlite3_stmt * const q = g_stmt(GStmt_defIns); - //g_stderr("zKey=%s\nzVal=%s\nzEq=%s\n", zKey, zVal, zEq); - db_bind_textn(q, 1, kvp.k.z, kvp.k.n); - if( kvp.v.z ){ - if( kvp.v.n ){ - db_bind_textn(q, 2, kvp.v.z, (int)kvp.v.n); - }else{ - db_bind_null(q, 2); - } - }else{ - db_bind_int(q, 2, 1); - } - db_step(q); - g_debug(2,("define: %s%s%s\n", - zKey, - zVal ? " with value " : "", - zVal ? zVal : "")); - sqlite3_reset(q); -} - -static void db_define_add_file(const char * zKey){ - cmpp_kvp kvp = cmpp_kvp_empty; - cmpp_kvp_parse(&kvp, zKey, -1, cmpp_kvp_op_eq1); - if( !kvp.v.z || !kvp.v.n ){ - fatal("Invalid filename: %s", zKey); - } - sqlite3_stmt * q = 0; - FileWrapper fw = FileWrapper_empty; - FileWrapper_open(&fw, kvp.v.z, "r"); - FileWrapper_slurp(&fw); - q = g_stmt(GStmt_defIns); - //g_stderr("zKey=%s\nzVal=%s\nzEq=%s\n", zKey, zVal, zEq); - db_bind_textn(q, 1, kvp.k.z, (int)kvp.k.n); - if( g.flags.chompF ){ - FileWrapper_chomp(&fw); - } - if( fw.nContent ){ - db_affirm_rc( - sqlite3_bind_text(q, 2, - (char const *)fw.zContent, - (int)fw.nContent, sqlite3_free), - "binding file content"); - fw.zContent = 0 /* transfered ownership */; - fw.nContent = 0; - }else{ - db_affirm_rc( sqlite3_bind_null(q, 2), - "binding empty file content"); - } - FileWrapper_close(&fw); - db_step(q); - g_stmt_reset(q); - g_debug(2,("define: %s%s%s\n", - kvp.k.z, - kvp.v.z ? " with value " : "", - kvp.v.z ? kvp.v.z : "")); -} - -#define ustr_c(X) ((unsigned char const *)X) - -static inline unsigned int cmpp_strlen(char const *z, int n){ - return n<0 ? (int)strlen(z) : (unsigned)n; -} - - -int db_define_has(const char * zName, int nName){ - int rc; - sqlite3_stmt * const q = g_stmt(GStmt_defHas); - nName = cmpp_strlen(zName, nName); - db_bind_textn(q, 1, zName, nName); - rc = db_step(q); - if(SQLITE_ROW == rc){ - rc = 1; - }else{ - assert(SQLITE_DONE==rc); - rc = 0; - } - g_debug(1,("defined [%s] ?= %d\n",zName, rc)); - g_stmt_reset(q); - return rc; -} - -int db_define_get_bool(const char * zName, int nName){ - sqlite3_stmt * const q = g_stmt(GStmt_defGetBool); - int rc = 0; - nName = cmpp_strlen(zName, nName); - db_bind_textn(q, 1, zName, nName); - rc = db_step(q); - if(SQLITE_ROW == rc){ - if( SQLITE_ROW==sqlite3_step(q) ){ - fatal("Key is ambiguous: %s", zName); - } - rc = 1; - }else{ - assert(SQLITE_DONE==rc); - rc = 0; - } - g_stmt_reset(q); - return rc; -} - -int db_define_get(const char * zName, int nName, - char **zVal, unsigned int *nVal){ - sqlite3_stmt * q = g_stmt(GStmt_defGet); - nName = cmpp_strlen(zName, nName); - db_bind_textn(q, 1, zName, nName); - int n = 0; - int rc = db_step(q); - if(SQLITE_ROW == rc){ - const unsigned char * z = sqlite3_column_text(q, 1); - n = sqlite3_column_bytes(q,1); - if( nVal ) *nVal = (unsigned)n; - *zVal = sqlite3_mprintf("%.*s", n, z); - if( n && z ) check__oom(*zVal); - if( SQLITE_ROW==sqlite3_step(q) ){ - db_free(*zVal); - *zVal = 0; - fatal("Key is ambiguous: %.*s\n", - nName, zName); - } - rc = 1; - }else{ - assert(SQLITE_DONE==rc); - rc = 0; - } - g_debug(1,("define [%.*s] ?= %d %.*s\n", - nName, zName, rc, - *zVal ? n : 0, - *zVal ? *zVal : "")); - g_stmt_reset(q); - return rc; -} - -void db_define_rm(const char * zKey){ - int rc; - int n = 0; - sqlite3_stmt * const q = g_stmt(GStmt_defDel); - db_bind_text(q, 1, zKey); - rc = db_step(q); - if(SQLITE_DONE != rc){ - db_affirm_rc(rc, "Stepping DELETE on def"); - } - g_debug(2,("undefine: %.*s\n",n, zKey)); - g_stmt_reset(q); -} - -void db_including_add(const char * zKey, const char * zSrc, int srcLine){ - int rc; - sqlite3_stmt * const q = g_stmt(GStmt_inclIns); - db_bind_text(q, 1, zKey); - db_bind_text(q, 2, zSrc); - db_bind_int(q, 3, srcLine); - rc = db_step(q); - if(SQLITE_DONE != rc){ - db_affirm_rc(rc, "Stepping INSERT on incl"); - } - g_debug(2,("is-including-file add [%s] from [%s]:%d\n", zKey, zSrc, srcLine)); - g_stmt_reset(q); -} - -void db_include_rm(const char * zKey){ - int rc; - sqlite3_stmt * const q = g_stmt(GStmt_inclDel); - db_bind_text(q, 1, zKey); - rc = db_step(q); - if(SQLITE_DONE != rc){ - db_affirm_rc(rc, "Stepping DELETE on incl"); - } - g_debug(2,("inclpath rm [%s]\n", zKey)); - g_stmt_reset(q); -} - -char * db_include_search(const char * zKey){ - char * zName = 0; - sqlite3_stmt * const q = g_stmt(GStmt_inclSearch); - db_bind_text(q, 1, zKey); - if(SQLITE_ROW==db_step(q)){ - const unsigned char * z = sqlite3_column_text(q, 0); - zName = z ? sqlite3_mprintf("%s", z) : 0; - if(!zName) fatal("Alloc failed"); - } - g_stmt_reset(q); - return zName; -} - -static int db_including_has(const char * zName){ - int rc; - sqlite3_stmt * const q = g_stmt(GStmt_inclHas); - db_bind_text(q, 1, zName); - rc = db_step(q); - if(SQLITE_ROW == rc){ - rc = 1; - }else{ - assert(SQLITE_DONE==rc); - rc = 0; - } - g_debug(2,("inclpath has [%s] = %d\n",zName, rc)); - g_stmt_reset(q); - return rc; -} - -#if 0 -/* -** Fails fatally if the `#include` list contains the given key. -*/ -static void db_including_check(const char * zKey); -void db_including_check(const char * zName){ - if(db_including_has(zName)){ - fatal("Recursive include detected: %s\n", zName); - } -} -#endif - -void db_include_dir_add(const char * zDir){ - static int seq = 0; - int rc; - sqlite3_stmt * const q = g_stmt(GStmt_inclPathAdd); - db_bind_int(q, 1, ++seq); - db_bind_text(q, 2, zDir); - rc = db_step(q); - if(SQLITE_DONE != rc){ - db_affirm_rc(rc, "Stepping INSERT on inclpath"); - } - g_debug(2,("inclpath add #%d: %s\n",seq, zDir)); - g_stmt_reset(q); -} - -void g_FileWrapper_link(FileWrapper *fp){ - assert(!fp->pTail); - fp->pTail = g.pFiles; - g.pFiles = fp; -} - -void g_FileWrapper_close(FileWrapper *fp){ - assert(fp); - assert(fp->pTail || g.pFiles==fp); - g.pFiles = fp->pTail; - fp->pTail = 0; - FileWrapper_close(fp); -} - -static void g_cleanup(int bCloseFileChain){ - if( g.db ){ -#define E(N,S) sqlite3_finalize(g.stmt.N); g.stmt.N = 0; - GStmt_map(E) -#undef E - } - if( bCloseFileChain ){ - FileWrapper * fpNext = 0; - for( FileWrapper * fp=g.pFiles; fp; fp=fpNext ){ - fpNext = fp->pTail; - fp->pTail = 0; - FileWrapper_close(fp); - } - } - FileWrapper_close(&g.out); - if(g.db){ - sqlite3_close(g.db); - g.db = 0; - } -} - -static void cmpp_atexit(void){ - g_cleanup(1); -} - -int cmpp_is_legal_key(char const *zKey, int nKey, char const **zAt){ - char const * z = zKey; - nKey = cmpp_strlen(zKey, nKey); - if( !nKey ){ - if( zAt ) *zAt = z; - return 0; - } - char const * const zEnd = z ? z + nKey : NULL; - for( ; z < zEnd; ++z ){ - switch( (0x80 & *z) ? 0 : *z ){ - case 0: - case '_': - continue; - case '-': - case '.': - case '/': - case ':': - case '=': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if( z==zKey ) break; - continue; - default: - if( isalpha((int)*z) ) continue; - } - if( zAt ) *zAt = z; - return 0; - } - assert( z==zEnd ); - return 1; -} - -void cmpp_affirm_legal_key(char const *zKey, int nKey){ - char const *zAt = 0; - nKey = cmpp_strlen(zKey, nKey); - if( !cmpp_is_legal_key(zKey, nKey, &zAt) ){ - assert( zAt ); - fatal("Illegal character 0x%02x in key [%.*s]\n", - (int)*zAt, nKey, zKey); - } -} - -/* -** sqlite3 UDF which returns true if its argument refers to an -** accessible file, else false. -*/ -static void udf_file_exists( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const char *zName; - (void)(argc); /* Unused parameter */ - zName = (const char*)sqlite3_value_text(argv[0]); - if( zName==0 ) return; - sqlite3_result_int(context, 0==access(zName, 0)); -} - -/** - ** This sqlite3_trace_v2() callback outputs tracing info using - ** g.sqlTrace.pFile. -*/ -static int cmpp__db_sq3TraceV2(unsigned t,void*c,void*p,void*x){ - static unsigned int counter = 0; - switch(t){ - case SQLITE_TRACE_STMT:{ - FILE * const fp = g.sqlTrace.pFile; - if( fp ){ - char const * const zSql = (char const *)x; - char * const zExp = g.sqlTrace.expandSql - ? sqlite3_expanded_sql((sqlite3_stmt*)p) - : 0; - fprintf(fp, "SQL TRACE #%u: %s\n", - ++counter, zExp ? zExp : zSql); - sqlite3_free(zExp); - } - break; - } - } - return 0; -} - -/* Initialize g.db, failing fatally on error. */ -static void cmpp_initdb(void){ - int rc; - char * zErr = 0; - const char * zSchema = - "CREATE TABLE def(" - /* ^^^ defines */ - "k TEXT PRIMARY KEY NOT NULL," - "v TEXT DEFAULT NULL" - ") WITHOUT ROWID;" - "CREATE TABLE incl(" - /* ^^^ files currently being included */ - "file TEXT PRIMARY KEY NOT NULL," - "srcFile TEXT DEFAULT NULL," - "srcLine INTEGER DEFAULT 0" - ") WITHOUT ROWID;" - "CREATE TABLE inclpath(" - /* ^^^ include path */ - "seq INTEGER UNIQUE ON CONFLICT IGNORE, " - "dir TEXT PRIMARY KEY NOT NULL ON CONFLICT IGNORE" - ");" - "BEGIN;" - ; - assert(0==g.db); - if(g.db) return; - rc = sqlite3_open_v2(":memory:", &g.db, SQLITE_OPEN_READWRITE, 0); - if(rc) fatal("Error opening :memory: db."); - sqlite3_trace_v2(g.db, SQLITE_TRACE_STMT, cmpp__db_sq3TraceV2, 0); - rc = sqlite3_exec(g.db, zSchema, 0, 0, &zErr); - if(rc) fatal("Error initializing database: %s", zErr); - rc = sqlite3_create_function(g.db, "fileExists", 1, - SQLITE_UTF8|SQLITE_DIRECTONLY, 0, - udf_file_exists, 0, 0); - db_affirm_rc(rc, "UDF registration failed."); -} - -/* -** For position zPos, which must be in the half-open range -** [zBegin,zEnd), returns g.delim.n if it is at the start of a line and -** starts with g.delim.z, else returns 0. -*/ -//static -unsigned short cmpp_is_delim(unsigned char const *zBegin, - unsigned char const *zEnd, - unsigned char const *zPos){ - assert(zEnd>zBegin); - assert(zPos=zBegin); - if(zPos>zBegin && - ('\n'!=*(zPos - 1) - || ((unsigned)(zEnd - zPos) <= g.delim.n))){ - return 0; - }else if(0==memcmp(zPos, g.delim.z, g.delim.n)){ - return g.delim.n; - }else{ - return 0; - } -} - -static void cmpp_t_out_expand(CmppTokenizer * const t, - unsigned char const * zFrom, - unsigned int n); - -static inline int cmpp__isspace(int ch){ - return ' '==ch || '\t'==ch; -} - -static inline unsigned cmpp__strlenu(unsigned char const *z, int n){ - return n<0 ? (unsigned)strlen((char const *)z) : (unsigned)n; -} - -static inline void cmpp__skip_space_c( unsigned char const **p, - unsigned char const *zEnd ){ - unsigned char const * z = *p; - while( zzPos,t->zEnd) for a derective delimiter. Emits any - non-delimiter output found along the way. - - This updtes t->zPos and t->lineNo as it goes. - - If a delimiter is found, it updates t->token and returns 0. - On no match returns 0. -*/ -static -int CmppTokenizer__delim_search(CmppTokenizer * const t){ - if(!t->zPos) t->zPos = t->zBegin; - if( t->zPos>=t->zEnd ){ - return 0; - } - assert( (t->zPos==t->zBegin || t->zPos[-1]=='\n') - && "Else we've mismanaged something."); - char const * const zD = g.delim.z; - unsigned short const nD = g.delim.n; - unsigned char const * const zEnd = t->zEnd; - unsigned char const * zLeft = t->zPos; - unsigned char const * z = zLeft; - - assert( 0==*zEnd && "Else we'll misinteract with strcspn()" ); - if( *zEnd ){ - fatal("Input must be NUL-terminated."); - return 0; - } -#define tflush \ - if(z>zEnd) z=zEnd; \ - if( z>zLeft ) { \ - cmpp_t_out_expand(t, zLeft, (unsigned)(z-zLeft)); \ - } zLeft = z - while(z < zEnd){ - size_t nNlTotal = 0; - unsigned char const * zNl; - size_t nNl2 = strcspn((char const *)z, "\n"); - zNl = (z + nNl2 >= zEnd ? zEnd : z + nNl2); - if( nNl2 >= CmppArgs_BufSize /* too long */ - //|| '\n'!=(char)*zNl /* end of input */ - /* ^^^ we have to accept a missing trailing EOL for the - sake of -e scripts. */ - ){ - /* we'd like to error out here, but only if we know we're - reading reading a directive line. */ - ++t->lineNo; - z = zNl + 1; - tflush; - continue; - } - nNlTotal += nNl2; - assert( '\n'==*zNl || !*zNl ); - assert( '\n'==*zNl || zNl==zEnd ); - //g_stderr("input: zNl=%d z=<<<%.*s>>>", (int)*zNl, (zNl-z), z); - unsigned char const * const zBOL = z; - cmpp__skip_space_c(&z, zNl); - if( z+nD < zNl && 0==memcmp(z, zD, nD) ){ - /* Found a directive delimiter. */ - if( zBOL!=z ){ - /* Do not emit space from the same line which preceeds a - delimiter */ - zLeft = z; - } - while( zNl>z && zNllineNo; - ++zNl; - nNl2 = strcspn((char const *)zNl, "\n"); - if( !nNl2 ) break; - nNlTotal += nNl2; - zNl += nNl2; - } - assert( zNl<=zEnd && "Else our input was not NUL-terminated"); - if( nNlTotal >= CmppArgs_BufSize ){ - fatal("Directive line is too long (%u)", - (unsigned)(zNl-z)); - break; - } - tflush; - t->token.zBegin = z + nD; - t->token.zEnd = zNl; - cmpp__skip_space_c(&t->token.zBegin, t->token.zEnd); - t->token.ttype = TT_Line; - t->token.lineNo = t->lineNo++; - t->zPos = t->token.zEnd + 1; - if( 0 ){ - g_stderr("token=<<%.*s>>", (t->token.zEnd - t->token.zBegin), - t->token.zBegin); - } - return 1; - } - z = zNl+1; - ++t->lineNo; - tflush; - //g_stderr("line #%d no match\n",(int)t->lineNo); - } - tflush; - t->zPos = z; - return 0; -#undef tflush -} - -void cmpp_kvp_parse(cmpp_kvp * p, char const *zKey, int nKey, - cmpp_kvp_op_e opPolicy){ - char chEq = 0; - char opLen = 0; - *p = cmpp_kvp_empty; - p->k.z = zKey; - p->k.n = cmpp_strlen(zKey, nKey); - switch( opPolicy ){ - case cmpp_kvp_op_none: break; - case cmpp_kvp_op_eq1: - chEq = '='; - opLen = 1; - break; - default: - assert(!"don't use these yet"); - /* todo: ==, !=, <=, <, >, >= */ - chEq = '='; - opLen = 1; - break; - } - assert( chEq ); - p->op = cmpp_kvp_op_none; - const char * const zEnd = p->k.z + p->k.n; - for(const char * zPos = p->k.z ; *zPos && zPosop = cmpp_kvp_op_eq1; - p->k.n = (unsigned)(zPos - zKey); - zPos += opLen; - assert( zPos <= zEnd ); - p->v.z = zPos; - p->v.n = (unsigned)(zEnd - zPos); - break; - } - } - cmpp_affirm_legal_key(p->k.z, p->k.n); -} - -static void cmpp_t_out_expand(CmppTokenizer * const t, - unsigned char const * zFrom, - unsigned int n){ - unsigned char const *zLeft = zFrom; - unsigned char const * const zEnd = zFrom + n; - unsigned char const *z = AT_OFF==g.flags.atPolicy ? zEnd : zLeft; - unsigned char const chEol = (unsigned char)'\n'; - int state = 0 /* 0==looking for opening @ - ** 1==looking for closing @ */; - if( 0 ){ - g_warn("zLeft=%d %c", (int)*zLeft, *zLeft); - } -#define tflush \ - if(z>zEnd) z=zEnd; \ - if(zLefttoken; - - assert(t->zBegin); - assert(t->zEnd > t->zBegin); - if(!t->zPos) t->zPos = t->zBegin; - t->args.pKw = 0; - t->args.argc = 0; - *tok = CmppToken_empty; - if( !CmppTokenizer__delim_search(t) ){ - return 0; - } - /* Split t->token into arguments for the line's keyword */ - int i, argc = 0, prevChar = 0; - const unsigned tokLen = (unsigned)(tok->zEnd - tok->zBegin); - unsigned char * zKwd; - unsigned char * zEsc; - unsigned char * zz; - - assert(TT_Line==tok->ttype); - g_debug(2,("token @ line %u len=%u [[[%.*s]]]\n", - tok->lineNo, tokLen, tokLen, tok->zBegin)); - zKwd = &t->args.lineBuf[0]; - memcpy(zKwd, tok->zBegin, tokLen); - memset(zKwd + tokLen, 0, sizeof(t->args.lineBuf) - tokLen); - for( zEsc = 0, zz = zKwd; *zz; ++zz ){ - /* Convert backslash-escaped newlines to whitespace */ - switch((int)*zz){ - case (int)'\\': - if(zEsc) zEsc = 0; - else zEsc = zz; - break; - case (int)'\n': - assert(zEsc && "Should not have an unescaped newline?"); - if(zEsc==zz-1){ - *zEsc = (unsigned char)' '; - /* FIXME?: memmove() lnBuf content one byte to the left here - ** to collapse backslash and newline into a single - ** byte. Also consider collapsing all leading space on the - ** next line. (Much later: or just collapse the output as we go, - ** effectively shrinking the line.) */ - } - zEsc = 0; - *zz = (unsigned char)' '; - break; - default: - zEsc = 0; - break; - } - } - t->args.argv[argc++] = zKwd; - for( zz = zKwd; *zz; ++zz ){ - if(isspace(*zz)){ - *zz = 0; - break; - } - } - t->args.pKw = CmppKeyword_search((char const *)zKwd); - if(!t->args.pKw){ - fatal("Unknown keyword '%s' at line %u\n", (char const *)zKwd, - tok->lineNo); - } - for( ++zz ; *zz && isspace(*zz); ++zz ){} - if(t->args.pKw->bTokenize){ - for( ; *zz; prevChar = *zz, ++zz ){ - /* Split string into word-shaped tokens. - ** TODO ?= quoted strings, for the sake of the - ** #error keyword. */ - if(isspace(*zz)){ - assert(zz!=zKwd && "Leading space was stripped earlier."); - *zz = 0; - }else{ - if(argc == (int)CmppArgs_Max){ - fatal("Too many arguments @ line %u: %.*s", - tok->lineNo, tokLen, tok->zBegin); - }else if(zz>zKwd && !prevChar){ - t->args.argv[argc++] = zz; - } - } - } - }else{ - /* Treat rest of line as one token */ - if(*zz) t->args.argv[argc++] = zz; - } - tok->ttype = t->args.pKw->ttype; - if(g.flags.doDebug>1){ - for(i = 0; i < argc; ++i){ - g_debug(0,("line %u arg #%d=%s\n", - tok->lineNo, i, - (char const *)t->args.argv[i])); - } - } - t->args.argc = argc; - return 1; -} - -/* Internal error reporting helper for cmpp_keyword_f() impls. */ -static CMPP_NORETURN void cmpp_kwd__err_(char const *zFile, int line, - CmppKeyword const * pKw, - CmppTokenizer const *t, - char const *zFmt, ...){ - va_list va; - g_stderr("%s @ %s line %u:", - pKw->zName, t->zName, t->token.lineNo); - va_start(va, zFmt); - g.tok = 0 /* stop fatalv__base() from duplicating the file info */; - fatalv__base(zFile, line, zFmt, va); - /* not reached */ - va_end(va); -} -#define cmpp_kwd__err(...) cmpp_kwd__err_(__FILE__,__LINE__, __VA_ARGS__) -#define cmpp_t__err(T,...) cmpp_kwd__err_(__FILE__,__LINE__, (T)->args.pKw, (T), __VA_ARGS__) - -/* No-op cmpp_keyword_f() impl. */ -static void cmpp_kwd_noop(CmppKeyword const * pKw, CmppTokenizer *t){ - (void)pKw; - (void)t; -} - -/* #error impl. */ -static void cmpp_kwd_error(CmppKeyword const * pKw, CmppTokenizer *t){ - if(CT_skip(t)) return; - else{ - assert(t->args.argc < 3); - const char *zBegin = t->args.argc>1 - ? (const char *)t->args.argv[1] : 0; - cmpp_t__err(t, "%s", zBegin ? zBegin : "(no additional info)"); - } -} - -/* Impl. for #define, #undef */ -static void cmpp_kwd_define(CmppKeyword const * pKw, CmppTokenizer *t){ - if(CT_skip(t)) return; - if(t->args.argc<2){ - cmpp_kwd__err(pKw, t, "Expecting one or more arguments"); - }else{ - int i = 1; - for( ; i < t->args.argc; ++i){ - char const * const zArg = (char const *)t->args.argv[i]; - cmpp_affirm_legal_key(zArg, -1); - if( TT_Define==pKw->ttype ){ - db_define_add( zArg, NULL ); - }else{ - db_define_rm( zArg ); - } - } - } -} - -static int cmpp_val_matches(char const *zGlob, char const *zRhs){ - return 0==sqlite3_strglob(zGlob, zRhs); -} - -typedef int (*cmpp_vcmp_f)(char const *zLhs, char const *zRhs); - -/* -** Accepts a key in the form X or X=Y. In the former case, it uses -** db_define_get_bool(kvp->k) to determine its truthiness, else it -** compares the kvp->v part to kvp->k's defined value to determine -** truthiness. -** -** Unless... -** -** If bCheckDefined is true is true then (A) it returns true if the -** value is defined and (B) fails fatally if given an X=Y-format key. -** -** Returns true if zKey evals to true, else false. -*/ -//static -int cmpp_kvp_truth(CmppKeyword const * const pKw, - CmppTokenizer const * const t, - cmpp_kvp const * const kvp, - int bCheckDefined){ - int buul = 0; - if( kvp->v.z ){ - if( bCheckDefined ){ - cmpp_kwd__err(pKw, t, "Value part is not legal for " - "is-defined checks: %.s", - kvp->k.n, kvp->k.z); - } - char * zVal = 0; - unsigned int nVal = 0; - buul = db_define_get(kvp->k.z, (int)kvp->k.n, &zVal, &nVal); - //g_debug(0,("checking key[%.*s]=%.*s\n", (zEq-zKey), zKey, nVal, zVal)); - if( kvp->v.n && nVal ){ - /* FIXME? do this with a query */ - /*g_debug(0,("if get-define [%.*s]=[%.*s] zValPart=%s\n", - (zEq-zKey), zKey, - nVal, zVal, zValPart));*/ - buul = cmpp_val_matches(kvp->v.z, zVal); - //g_debug(0,("buul=%d\n", buul)); - }else{ - assert( 0==kvp->v.n || 0==nVal ); - buul = kvp->v.n == nVal; - } - db_free(zVal); - }else{ - if( bCheckDefined ){ - buul = db_define_has(kvp->k.z, kvp->k.n); - }else{ - buul = db_define_get_bool(kvp->k.z, kvp->k.n); - } - } - return buul; -} - -#if 0 -/* -** A thin proxy for cmpp_kvp_truth(). -*/ -static int cmpp_key_truth(CmppKeyword const * pKw, - CmppTokenizer const * t, - char const *zKey, int bCheckDefined){ - cmpp_kvp kvp = cmpp_kvp_empty; - cmpp_kvp_parse(&kvp, zKey, -1, cmpp_kvp_op_eq1); - return cmpp_kvp_truth(pKw, t, &kvp, bCheckDefined); -} -#endif - -//static -cmpp_kvp_op_e cmpp_t_is_op(CmppTokenizer const * t, int arg){ - if( t->args.argc > arg ){ - char const * const z = (char const *)t->args.argv[arg]; -#define E(N,S) if( strcmp(S,z) ) return cmpp_kvp_op_ ## N; else - cmpp_kvp_op_map(E) -#undef E - if(0) {} - } - return cmpp_kvp_op_none; -} - -/* -** A single part of an #if-type expression. They are parsed from -** CmppTokenizer::args in this form: -** -** not* defined{0,1} key[=[value]] -*/ -struct CmppExprDef { - /* The key part of the input. */ - cmpp_kvp kvp; - struct { - int ndx; - int next; - } arg; - CmppTokenizer const * tizer; - /* Set to 0 or 1 depending how many "not" are parsed. */ - unsigned char bNegated; - /* Set to 1 if "defined" is parsed. */ - unsigned char bCheckDefined; -}; -typedef struct CmppExprDef CmppExprDef; -#define CmppExprDef_empty_m {cmpp_kvp_empty_m,{0,0},0,0,0} -static const CmppExprDef CmppExprDef_empty = CmppExprDef_empty_m; - -/* -** Evaluate cep to true or false and return that value: -** -** If cep->bCheckDefined, return the result of db_define_has(). -** -** Else if cep->kvp.v.z is not NULL then fetch the define's value -** and return the result of cmpp_val_matches(cep->kvp.v.z,thatValue). -** -** Else return the result of db_define_get_bool(). -** -** The returned result accounts for cep->bNegated. -*/ -static int CmppExprDef_eval(CmppExprDef const * cep){ - int buul = 0; - - if( cep->bCheckDefined ){ - assert( !cep->kvp.v.n ); - buul = db_define_has(cep->kvp.k.z, (int)cep->kvp.k.n); - }else if( cep->kvp.v.z ){ - unsigned nVal = 0; - char * zVal = 0; - buul = db_define_get(cep->kvp.k.z, cep->kvp.k.n, &zVal, &nVal); - if( nVal ){ - buul = cmpp_val_matches(cep->kvp.v.z, zVal); - } - db_free(zVal); - }else{ - buul = db_define_get_bool(cep->kvp.k.z, cep->kvp.k.n); - } - return cep->bNegated ? !buul : buul; -} - -/* -** Expects t->args, starting at t->args.argv[startArg], to parse to -** one CmmpExprDef. It clears cep and repopulates it with info about -** the parse. Fails fatally on a parse error. -** -** Returns true if it reads one, false if it doesn't, and fails fatally -** if what it tries to parse is not empty but is not a CmppExprDef. -** -** Specifically, it parses: -** -** not+ defined? Word[=value] -** -*/ -static int CmppExprDef_read_one(CmppKeyword const * pKw, - CmppTokenizer const * t, - int startArg, CmppExprDef * cep){ - char const *zKey = 0; - *cep = CmppExprDef_empty; - cep->arg.ndx = startArg; - assert( t->args.pKw ); - assert( t->args.pKw==pKw ); - cep->tizer = t; - for(int i = startArg; !zKey && iargs.argc; ++i ){ - char const * z = (char const *)t->args.argv[i]; - if( 0==strcmp(z, "not") ){ - cep->bNegated = !cep->bNegated; - }else if( 0==strcmp(z,"defined") ){ - if( cep->bCheckDefined ){ - cmpp_kwd__err(pKw, t, - "Cannot use 'defined' more than once"); - } - cep->bCheckDefined = 1; - }else{ - assert( !zKey ); - cmpp_kvp_parse(&cep->kvp, z, -1, cmpp_kvp_op_eq1); - if( cep->bCheckDefined && cep->kvp.v.z ){ - cmpp_kwd__err(pKw, t, "Cannot use X=Y keys with 'defined'"); - cep->arg.next = ++i; - } - return 1; - } - } - return 0; -} - -/* -** Evals pStart and then proceeds to process any remaining arguments -** in t->args as RHS expressions. Returns the result of the expression -** as a bool. -** -** Specifically, it parses: -** -** and|or CmppExprDef -** -** Where CmppExprDef is the result of CmppExprDef_read_one(). -*/ -static int CmppExprDef_parse_cond(CmppKeyword const *pKw, - CmppTokenizer *t, - CmppExprDef const * pStart){ - enum { Op_none = 0, Op_And, Op_Or }; - int lhs = CmppExprDef_eval(pStart); - int op = Op_none; - int i = pStart->arg.next; - for( ; i < t->args.argc; ++i ){ - CmppExprDef eNext = CmppExprDef_empty; - char const *z = (char const *)t->args.argv[i]; - if( 0==strcmp("and",z) ){ - if( Op_none!=op ) goto multiple_ops; - op = Op_And; - continue; - }else if( 0==strcmp("or",z) ){ - if( Op_none!=op ) goto multiple_ops; - op = Op_Or; - continue; - }else if( !CmppExprDef_read_one(pKw, t, i, &eNext) ){ - if( Op_none!=op ){ - cmpp_t__err(t, "Stray operator: %s",z); - } - } - assert( eNext.kvp.k.z ); - int const rhs = CmppExprDef_eval(&eNext); - switch( op ){ - case Op_none: break; - case Op_And: lhs = lhs && rhs; break; - case Op_Or: lhs = lhs || rhs; break; - default: - assert(!"cannot happen"); - fatal("this cannot happen"); - } - op = Op_none; - } - if( Op_none!=op ){ - cmpp_t__err(t, "Extra operator at end of expression"); - }else if( i < t->args.argc ){ - assert(!"cannot happen"); - cmpp_kwd__err(t->args.pKw, t, "Unhandled extra arguments"); - }else{ - return lhs; - } - assert(!"not reached"); -multiple_ops: - cmpp_t__err(t,"Cannot have multiple operators"); - return 0 /* not reached */; -} - -/* Impl. for #if, #elif, #assert. */ -static void cmpp_kwd_if(CmppKeyword const * pKw, CmppTokenizer *t){ - CmppParseState tmpState = TS_Start; - CmppExprDef cep = CmppExprDef_empty; - //int buul = 0; - assert( TT_If==pKw->ttype - || TT_Elif==pKw->ttype - || TT_Assert==pKw->ttype); - if(t->args.argc<2){ - cmpp_kwd__err(pKw, t, "Expecting an argument"); - } - CmppExprDef_read_one(pKw, t, 1, &cep); - if( !cep.kvp.k.z ){ - cmpp_kwd__err(pKw, t, "Missing key argument"); - } - /*g_debug(0,("%s %s level %u pstate=%d bNot=%d bCheckDefined=%d\n", - pKw->zName, zKey, t->level.ndx, (int)CT_pstate(t), - bNot, bCheckDefined));*/ - switch(pKw->ttype){ - case TT_Assert: - break; - case TT_Elif: - switch(CT_pstate(t)){ - case TS_If: break; - case TS_IfPassed: CT_level(t).flags |= CmppLevel_F_ELIDE; return; - default: - cmpp_kwd__err(pKw, t, "'%s' used out of context", - pKw->zName); - } - break; - case TT_If: - CmppLevel_push(t); - break; - default: - assert(!"cannot happen"); - cmpp_kwd__err(pKw, t, "Unexpected keyword token type"); - break; - } - if( CmppExprDef_parse_cond( pKw, t, &cep ) ){ - CT_pstate(t) = tmpState = TS_IfPassed; - CT_skipLevel(t) = 0; - }else{ - if( TT_Assert==pKw->ttype ){ - cmpp_kwd__err(pKw, t, "Assertion failed: %s", - /* fixme: emit the whole line. We don't have it - handy in a readily-printable form. */ - cep.kvp.k.z); - } - CT_pstate(t) = TS_If /* also for TT_Elif */; - CT_skipLevel(t) = 1; - g_debug(3,("setting CT_skipLevel = 1 @ level %d\n", t->level.ndx)); - } - if( TT_If==pKw->ttype ){ - unsigned const lvlIf = t->level.ndx; - CmppToken const lvlToken = CT_level(t).token; - while(cmpp_next_keyword_line(t)){ - cmpp_process_keyword(t); - if(lvlIf > t->level.ndx){ - assert(TT_Endif == t->token.ttype); - break; - } -#if 0 - if(TS_IfPassed==tmpState){ - tmpState = TS_Start; - t->level.stack[lvlIf].flags |= CmppLevel_F_ELIDE; - g_debug(1,("Setting ELIDE for TS_IfPassed @ lv %d (lvlIf=%d)\n", t->level.ndx, lvlIf)); - } -#endif - } - if(lvlIf <= t->level.ndx){ - cmpp_kwd__err(pKw, t, - "Input ended inside an unterminated %sif " - "opened at [%s] line %u", - g.delim.z, t->zName, lvlToken.lineNo); - } - } -} - -/* Impl. for #else. */ -static void cmpp_kwd_else(CmppKeyword const * pKw, CmppTokenizer *t){ - if(t->args.argc>1){ - cmpp_kwd__err(pKw, t, "Expecting no arguments"); - } - switch(CT_pstate(t)){ - case TS_IfPassed: CT_skipLevel(t) = 1; break; - case TS_If: CT_skipLevel(t) = 0; break; - default: - cmpp_kwd__err(pKw, t, "'%s' with no matching 'if'", - pKw->zName); - } - /*g_debug(0,("else flags=0x%02x skipLevel=%u\n", - CT_level(t).flags, CT_level(t).skipLevel));*/ - CT_pstate(t) = TS_Else; -} - -/* Impl. for #endif. */ -static void cmpp_kwd_endif(CmppKeyword const * pKw, CmppTokenizer *t){ - /* Maintenance reminder: we ignore all arguments after the endif - ** to allow for constructs like: - ** - ** #endif // foo - ** - ** in a manner which does not require a specific comment style */ - switch(CT_pstate(t)){ - case TS_Else: - case TS_If: - case TS_IfPassed: - break; - default: - cmpp_kwd__err(pKw, t, "'%s' with no matching 'if'", - pKw->zName); - } - CmppLevel_pop(t); -} - -/* Impl. for #include. */ -static void cmpp_kwd_include(CmppKeyword const * pKw, CmppTokenizer *t){ - char const * zFile; - char * zResolved; - int bRaw = 0 /* -raw flag */; - if(CT_skip(t)) return; - else if(t->args.argc<2 || t->args.argc>3){ - cmpp_kwd__err(pKw, t, "Expected args: ?-raw? filename"); - } - if(t->args.argc==2){ - zFile = (const char *)t->args.argv[1]; - }else{ - if( 0==strcmp("-raw", (char*)t->args.argv[1]) ){ - bRaw = 1; - }else{ - cmpp_kwd__err(pKw, t, "Unhandled argument: %s", - t->args.argv[1]); - } - zFile = (const char *)t->args.argv[2]; - } - if(!bRaw && db_including_has(zFile)){ - /* Note that different spellings of the same filename - ** will elude this check, but that seems okay, as different - ** spellings means that we're not re-running the exact same - ** invocation. We might want some other form of multi-include - ** protection, rather than this, however. There may well be - ** sensible uses for recursion. */ - cmpp_t__err(t, "Recursive include of file: %s", zFile); - } - zResolved = db_include_search(zFile); - if(zResolved){ - if( bRaw ) db_including_add(zFile, t->zName, t->token.lineNo); - cmpp_process_file(zResolved, bRaw); - if( bRaw ) db_include_rm(zFile); - db_free(zResolved); - }else{ - cmpp_t__err(t, "file not found: %s", zFile); - } -} - -static void cmpp_dump_defines( FILE * fp, int bIndent ){ - sqlite3_stmt * const q = g_stmt(GStmt_defSelAll); - while( SQLITE_ROW==sqlite3_step(q) ){ - unsigned char const * zK = sqlite3_column_text(q, 0); - unsigned char const * zV = sqlite3_column_text(q, 1); - int const nK = sqlite3_column_bytes(q, 0); - int const nV = sqlite3_column_bytes(q, 1); - fprintf(fp, "%s%.*s = %.*s\n", - bIndent ? "\t" : "", nK, zK, nV, zV); - } - g_stmt_reset(q); -} - -/* Impl. for #pragma. */ -static void cmpp_kwd_pragma(CmppKeyword const * pKw, CmppTokenizer *t){ - const char * zArg; - if(CT_skip(t)) return; - else if(t->args.argc<2){ - cmpp_kwd__err(pKw, t, "Expecting an argument"); - } - zArg = (const char *)t->args.argv[1]; -#define M(X) 0==strcmp(zArg,X) - if(M("defines")){ - cmpp_dump_defines(stderr, 1); - } - else if(M("chomp-F")){ - g.flags.chompF = 1; - }else if(M("no-chomp-F")){ - g.flags.chompF = 0; - } -#if 0 - /* now done by cmpp_kwd_at_policy() */ - else if(M("@")){ - if(t->args.argc>2){ - g.flags.atPolicy = - AtPolicy_fromStr((char const *)t->args.argv[2], 1); - }else{ - g.flags.atPolicy = AT_DEFAULT; - } - }else if(M("no-@")){ - g.flags.atPolicy = AT_OFF; - } -#endif - else{ - cmpp_kwd__err(pKw, t, "Unknown pragma: %s", zArg); - } -#undef M -} - -static void db_step_reset(sqlite3_stmt * const q, char const * zErrTip){ - db_affirm_rc(sqlite3_step(q), zErrTip); - g_stmt_reset(q); -} - -static void cmpp_sp_begin(CmppTokenizer * const t){ - db_step_reset(g_stmt(GStmt_spBegin), "Starting savepoint"); - ++t->nSavepoint; -} - -static void cmpp_sp_rollback(CmppTokenizer * const t){ - if( !t->nSavepoint ){ - cmpp_t__err(t, "Cannot roll back: no active savepoint"); - } - db_step_reset(g_stmt(GStmt_spRollback), - "Rolling back savepoint"); - db_step_reset(g_stmt(GStmt_spRelease), - "Releasing rolled-back savepoint"); - --t->nSavepoint; -} - -static void cmpp_sp_commit(CmppTokenizer * const t){ - if( !t->nSavepoint ){ - cmpp_t__err(t, "Cannot commit: no active savepoint"); - } - db_step_reset(g_stmt(GStmt_spRelease), "Rolling back savepoint"); - --t->nSavepoint; -} - -void CmppTokenizer_cleanup(CmppTokenizer * const t){ - while( t->nSavepoint ){ - cmpp_sp_rollback(t); - } -} - -/* Impl. for #savepoint. */ -static void cmpp_kwd_savepoint(CmppKeyword const * pKw, CmppTokenizer *t){ - const char * zArg; - if(CT_skip(t)) return; - else if(t->args.argc!=2){ - cmpp_kwd__err(pKw, t, "Expecting one argument"); - } - zArg = (const char *)t->args.argv[1]; -#define M(X) 0==strcmp(zArg,X) - if(M("begin")){ - cmpp_sp_begin(t); - }else if(M("rollback")){ - cmpp_sp_rollback(t); - }else if(M("commit")){ - cmpp_sp_commit(t); - }else{ - cmpp_kwd__err(pKw, t, "Unknown savepoint option: %s", zArg); - } -#undef SP_NAME -#undef M -} - -/* #stder impl. */ -static void cmpp_kwd_stderr(CmppKeyword const * pKw, CmppTokenizer *t){ - if(CT_skip(t)) return; - else{ - const char *zBegin = t->args.argc>1 - ? (const char *)t->args.argv[1] : 0; - if(zBegin){ - g_stderr("%s:%u: %s\n", t->zName, t->token.lineNo, zBegin); - }else{ - g_stderr("%s:%u: (no %.*s%s argument)\n", - t->zName, t->token.lineNo, - g.delim.n, g.delim.z, pKw->zName); - } - } -} - -/* Impl. for the @ policy. */ -static void cmpp_kwd_at_policy(CmppKeyword const * pKw, CmppTokenizer *t){ - if(CT_skip(t)) return; - else if(t->args.argc<2){ - g.flags.atPolicy = AT_DEFAULT; - }else{ - g.flags.atPolicy = AtPolicy_fromStr((char const*)t->args.argv[1], 1); - } -} - - -#if 0 -/* Impl. for dummy placeholder. */ -static void cmpp_kwd_todo(CmppKeyword const * pKw, CmppTokenizer *t){ - (void)t; - g_debug(0,("TODO: keyword handler for %s\n", pKw->zName)); -} -#endif - -CmppKeyword aKeywords[] = { -/* Keep these sorted by zName */ -#define S(NAME) DStrings.NAME.z, DStrings.NAME.n - {S(Comment), 0, TT_Comment, cmpp_kwd_noop}, - {S(AtPolicy), 1, TT_AtPolicy, cmpp_kwd_at_policy}, - {S(Assert),1, TT_Assert, cmpp_kwd_if}, - {S(Define), 1, TT_Define, cmpp_kwd_define}, - {S(Elif), 1, TT_Elif, cmpp_kwd_if}, - {S(Else), 1, TT_Else, cmpp_kwd_else}, - {S(Endif), 0, TT_Endif, cmpp_kwd_endif}, - {S(Error), 0, TT_Error, cmpp_kwd_error}, - {S(If), 1, TT_If, cmpp_kwd_if}, - {S(Include), 1, TT_Include, cmpp_kwd_include}, - {S(Pragma), 1, TT_Pragma, cmpp_kwd_pragma}, - {S(Savepoint), 1, TT_Savepoint, cmpp_kwd_savepoint}, - {S(Stderr), 0, TT_Stderr, cmpp_kwd_stderr}, - {S(Undef), 1, TT_Undef, cmpp_kwd_define}, -#undef S - {0,0,TT_Invalid, 0} -}; - -static int cmpp_CmppKeyword(const void *p1, const void *p2){ - char const * zName = (const char *)p1; - CmppKeyword const * kw = (CmppKeyword const *)p2; - return strcmp(zName, kw->zName); -} - -CmppKeyword const * CmppKeyword_search(const char *zName){ - return (CmppKeyword const *)bsearch(zName, &aKeywords[0], - sizeof(aKeywords)/sizeof(aKeywords[0]) - 1, - sizeof(aKeywords[0]), - cmpp_CmppKeyword); -} - -void cmpp_process_keyword(CmppTokenizer * const t){ - assert(t->args.pKw); - assert(t->args.argc); - t->args.pKw->xCall(t->args.pKw, t); - t->args.pKw = 0; - t->args.argc = 0; -} - -void cmpp_process_string(const char * zName, - unsigned char const * zIn, - int nIn){ - nIn = cmpp__strlenu(zIn, nIn); - if( !nIn ) return; - CmppTokenizer const * const oldTok = g.tok; - CmppTokenizer ct = CmppTokenizer_empty; - ct.zName = zName; - ct.zBegin = zIn; - ct.zEnd = zIn + nIn; - while(cmpp_next_keyword_line(&ct)){ - cmpp_process_keyword(&ct); - } - if(0!=ct.level.ndx){ - CmppLevel const * const lv = CmppLevel_get(&ct); - fatal("Input ended inside an unterminated nested construct " - "opened at [%s] line %u", zName, lv->token.lineNo); - } - CmppTokenizer_cleanup(&ct); - g.tok = oldTok; -} - -void cmpp_process_file(const char * zName, int bRaw){ - FileWrapper fw = FileWrapper_empty; - FileWrapper_open(&fw, zName, "r"); - g_FileWrapper_link(&fw); - FileWrapper_slurp(&fw); - g_debug(1,("Read %u byte(s) from [%s]\n", fw.nContent, fw.zName)); - if( fw.zContent ){ - if( bRaw ){ - FileWrapper fw = FileWrapper_empty; - FileWrapper_open(&fw, zName, "rb"); - g_FileWrapper_link(&fw); - FileWrapper_slurp(&fw); - if( 1!=fwrite(fw.zContent, fw.nContent, 1, g.out.pFile) ){ - fatal("fwrite() failed with errno %d\n", errno); - } - g_FileWrapper_close(&fw); - }else{ - cmpp_process_string(zName, fw.zContent, fw.nContent); - } - } - g_FileWrapper_close(&fw); -} - - -void fatalv__base(char const *zFile, int line, - char const *zFmt, va_list va){ - FILE * const fp = stderr; - fflush(stdout); - fputc('\n', fp); - if( g.flags.doDebug ){ - fprintf(fp, "%s: ", g.zArgv0); - if( zFile ){ - fprintf(fp, "%s:%d ",zFile, line); - } - } - if( g.tok ){ - fprintf(fp,"@%s:%d: ", - (g.tok->zName && 0==strcmp("-",g.tok->zName)) - ? "" - : g.tok->zName, - g.tok->lineNo); - } - if(zFmt && *zFmt){ - vfprintf(fp, zFmt, va); - } - fputc('\n', fp); - fflush(fp); - exit(1); -} - -void fatal__base(char const *zFile, int line, - char const *zFmt, ...){ - va_list va; - va_start(va, zFmt); - fatalv__base(zFile, line, zFmt, va); - va_end(va); -} - -#undef CT_level -#undef CT_pstate -#undef CT_skipLevel -#undef CT_skip -#undef CLvl_skip - -static void usage(int isErr){ - FILE * const fOut = isErr ? stderr : stdout; - fprintf(fOut, "Usage: %s [flags] [infile...]\n", g.zArgv0); - fprintf(fOut, - "Flags and filenames may be in any order and " - "they are processed in that order.\n" - "\nFlags:\n"); -#define GAP " " -#define arg(F,D) fprintf(fOut,"\n %s\n" GAP "%s\n",F, D) - arg("-o|--outfile FILE","Send output to FILE (default=- (stdout)).\n" - GAP "Because arguments are processed in order, this should\n" - GAP "normally be given before -f."); - arg("-f|--file FILE","Process FILE (default=- (stdin)).\n" - GAP "All non-flag arguments are assumed to be the input files."); - arg("-DXYZ[=value]","Define XYZ to the given value (default=1)."); - arg("-UXYZ","Undefine all defines matching glob XYZ."); - arg("-IXYZ","Add dir XYZ to the " CMPP_DEFAULT_DELIM "include path."); - arg("-FXYZ=filename", - "Define XYZ to the raw contents of the given file.\n" - GAP "The file is not processed as by " CMPP_DEFAULT_DELIM"include\n" - GAP "Maybe it should be. Or maybe we need a new flag for that."); - arg("-d|--delimiter VALUE", "Set keyword delimiter to VALUE " - "(default=" CMPP_DEFAULT_DELIM ")."); - arg("--@policy retain|elide|error|off", - "Specifies how to handle @tokens@ (default=off).\n" - GAP "off = do not look for @tokens@\n" - GAP "retain = parse @tokens@ and retain any undefined ones\n" - GAP "elide = parse @tokens@ and elide any undefined ones\n" - GAP "error = parse @tokens@ and error out for any undefined ones" - ); - arg("-@", "Equivalent to --@policy=error."); - arg("-no-@", "Equivalent to --@policy=off (the default)."); - arg("--sql-trace", "Send a trace of all SQL to stderr."); - arg("--sql-trace-x", - "Like --sql-trace but expand all bound values in the SQL."); - arg("--no-sql-trace", "Disable SQL tracing (default)."); - arg("--chomp-F", "One trailing newline is trimmed from files " - "read via -FXYZ=filename."); - arg("--no-chomp-F", "Disable --chomp-F (default)."); -#undef arg -#undef GAP - fputs("\nFlags which require a value accept either " - "--flag=value or --flag value.\n\n",fOut); -} - -/* -** Expects that *ndx points to the current argv entry and that it is a -** flag which expects a value. This function checks for --flag=val and -** (--flag val) forms. If a value is found then *ndx is adjusted (if -** needed) to point to the next argument after the value and *zVal is -** pointed to the value. If no value is found then it fails fatally. -*/ -static void get_flag_val(int argc, char const * const * argv, int * ndx, - char const **zVal){ - char const * zEq = strchr(argv[*ndx], '='); - if( zEq ){ - *zVal = zEq+1; - return; - } - if(*ndx+1>=argc){ - fatal("Missing value for flag '%s'", argv[*ndx]); - } - *zVal = argv[++*ndx]; -} - -static int arg_is_flag( char const *zFlag, char const *zArg, - char const **zValIfEqX ){ - *zValIfEqX = 0; - if( 0==strcmp(zFlag, zArg) ) return 1; - char const * z = strchr(zArg,'='); - if( z && z>zArg ){ - /* compare the part before the '=' */ - if( 0==strncmp(zFlag, zArg, z-zArg) ){ - if( !zFlag[z-zArg] ){ - *zValIfEqX = z+1; - return 1; - } - /* Else it was a prefix match. */ - } - } - return 0; -} - -static void define_argv(int argc, char const * const * argv){ - sqlite3_str * const s = sqlite3_str_new(g.db); - sqlite3_str_append(s, "c-pp::argv=", 11); - for( int i = 0; i < argc; ++i ){ - if( i ) sqlite3_str_appendchar(s, 1, ' '); - sqlite3_str_appendf(s, "%s", argv[i]); - } - char * const z = sqlite3_str_finish(s); - assert(z); - if(z){ - db_define_add(z, NULL); - sqlite3_free(z); - } -} - -int main(int argc, char const * const * argv){ - int rc = 0; - int inclCount = 0; - int nFile = 0; - int ndxTrace = 0; - int expandMode = 0; - char const * zVal = 0; -#define ARGVAL if( !zVal ) get_flag_val(argc, argv, &i, &zVal) -#define M(X) arg_is_flag(X, zArg, &zVal) -#define ISFLAG(X) else if(M(X)) -#define ISFLAG2(X,Y) else if(M(X) || M(Y)) -#define NOVAL if( zVal ) fatal("Unexpected value for %s", zArg) -#define g_out_open \ - if(!g.out.pFile) FileWrapper_open(&g.out, "-", "w"); \ - if(!inclCount){ db_include_dir_add("."); ++inclCount; } (void)0 - - g.zArgv0 = argv[0]; -#define DOIT if(doIt) - for(int doIt = 0; doIt<2; ++doIt){ - /** - Loop through the flags twice. The first time we just validate - and look for --help/-?. The second time we process the flags. - This approach allows us to easily chain multiple files and - flags: - - ./c-pp -Dfoo -o foo x.y -Ufoo -Dbar -o bar x.y - */ - DOIT{ - atexit(cmpp_atexit); - if( 1==ndxTrace ){ - /* Ensure that we start with tracing in the early stage if - --sql-trace is the first arg, in order to log schema - setup. */ - g.sqlTrace.pFile = stderr; - g.sqlTrace.expandSql = expandMode; - } - cmpp_initdb(); - define_argv(argc, argv); - } - for(int i = 1; i < argc; ++i){ - int negate = 0; - char const * zArg = argv[i]; - //g_stderr("i=%d zArg=%s\n", i, zArg); - zVal = 0; - while('-'==*zArg) ++zArg; - if(zArg==argv[i]/*not a flag*/){ - zVal = zArg; - goto do_infile; - } - if( 0==strncmp(zArg,"no-",3) ){ - zArg += 3; - negate = 1; - } - ISFLAG2("?","help"){ - NOVAL; - usage(0); - goto end; - }else if('D'==*zArg){ - ++zArg; - if(!*zArg) fatal("Missing key for -D"); - DOIT { - db_define_add(zArg, 0); - } - }else if('F'==*zArg){ - ++zArg; - if(!*zArg) fatal("Missing key for -F"); - DOIT { - db_define_add_file(zArg); - } - }else if('U'==*zArg){ - ++zArg; - if(!*zArg) fatal("Missing key for -U"); - DOIT { - db_define_rm(zArg); - } - }else if('I'==*zArg){ - ++zArg; - if(!*zArg) fatal("Missing directory for -I"); - DOIT { - db_include_dir_add(zArg); - ++inclCount; - } - } - ISFLAG2("o","outfile"){ - ARGVAL; - DOIT { - FileWrapper_open(&g.out, zVal, "w"); - } - } - ISFLAG2("f","file"){ - ARGVAL; - do_infile: - DOIT { - ++nFile; - g_out_open; - cmpp_process_file(zVal, 0); - } - } - ISFLAG("e"){ - ARGVAL; - DOIT { - ++nFile; - g_out_open; - cmpp_process_string("-e script", ustr_c(zVal), -1); - } - } - ISFLAG("@"){ - NOVAL; - DOIT { - assert( AT_DEFAULT!=AT_OFF ); - g.flags.atPolicy = negate ? AT_OFF : AT_DEFAULT; - } - } - ISFLAG("@policy"){ - AtPolicy aup; - ARGVAL; - aup = AtPolicy_fromStr(zVal, 1); - DOIT { - g.flags.atPolicy = aup; - } - } - ISFLAG("debug"){ - NOVAL; - g.flags.doDebug += negate ? -1 : 1; - } - ISFLAG("sql-trace"){ - NOVAL; - /* Needs to be set before the start of the second pass, when - the db is inited. */ - g.sqlTrace.expandSql = 0; - DOIT { - g.sqlTrace.pFile = negate ? (FILE*)0 : stderr; - }else if( !ndxTrace && !negate ){ - ndxTrace = i; - expandMode = 0; - } - } - ISFLAG("sql-trace-x"){ - NOVAL; - g.sqlTrace.expandSql = 1; - DOIT { - g.sqlTrace.pFile = negate ? (FILE*)0 : stderr; - }else if( !ndxTrace && !negate ){ - ndxTrace = i; - expandMode = 1; - } - } - ISFLAG("chomp-F"){ - NOVAL; - DOIT g.flags.chompF = !negate; - } - ISFLAG2("d","delimiter"){ - ARGVAL; - if( !doIt ){ - g.delim.z = zVal; - g.delim.n = (unsigned short)strlen(zVal); - if(!g.delim.n) fatal("Keyword delimiter may not be empty."); - } - } - ISFLAG2("dd", "dump-defines"){ - DOIT { - FILE * const fp = stderr; - fprintf(fp, "All %sdefine entries:\n", g.delim.z); - cmpp_dump_defines(fp, 1); - } - } - else{ - fatal("Unhandled flag: %s", argv[i]); - } - } - DOIT { - if(!nFile){ - if(!g.out.zName) g.out.zName = "-"; - if(!inclCount){ - db_include_dir_add("."); - ++inclCount; - } - FileWrapper_open(&g.out, g.out.zName, "w"); - cmpp_process_file("-", 0); - } - } - } - end: - g_cleanup(1); - return rc ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/ext/wasm/demo-worker1-promiser.c-pp.html b/ext/wasm/demo-worker1-promiser.c-pp.html index a1005beb93..c54b46aadb 100644 --- a/ext/wasm/demo-worker1-promiser.c-pp.html +++ b/ext/wasm/demo-worker1-promiser.c-pp.html @@ -10,7 +10,7 @@ Worker1-promiser (ESM) tests //#else Worker1-promiser tests -//#endif +//#/if
    worker-promise tests
    @@ -37,6 +37,6 @@ //#else -//#endif +//#/if diff --git a/ext/wasm/demo-worker1-promiser.c-pp.js b/ext/wasm/demo-worker1-promiser.c-pp.js index c129e21281..1521edfc17 100644 --- a/ext/wasm/demo-worker1-promiser.c-pp.js +++ b/ext/wasm/demo-worker1-promiser.c-pp.js @@ -19,7 +19,7 @@ import {default as promiserFactory} from "./jswasm/sqlite3-worker1-promiser.mjs" "use strict"; const promiserFactory = globalThis.sqlite3Worker1Promiser.v2; delete globalThis.sqlite3Worker1Promiser; -//#endif +//#/if (async function(){ const T = globalThis.SqliteTestUtil; const eOutput = document.querySelector('#test-output'); @@ -53,7 +53,7 @@ delete globalThis.sqlite3Worker1Promiser; before workerPromise is set. */ console.warn("This is the v2 interface - you don't need an onready() function."); }, -//#endif +//#/if debug: 1 ? undefined : (...args)=>console.debug('worker debug',...args), onunhandled: function(ev){ error("Unhandled worker message:",ev.data); diff --git a/ext/wasm/fiddle/index.c-pp.html b/ext/wasm/fiddle/index.c-pp.html index 1f818286b5..7fe9a12a77 100644 --- a/ext/wasm/fiddle/index.c-pp.html +++ b/ext/wasm/fiddle/index.c-pp.html @@ -27,7 +27,7 @@ --> -//#endif +//#/if