Compare commits

..

38 Commits

Author SHA1 Message Date
drh 0cb576f306 Fix harmless compiler warnings about unused variable assignments.
FossilOrigin-Name: afe7e9fd1c476c7cdcefab0adf0191a8dc3283811f72a685fff3eb6539b72dcc
2026-03-29 22:41:12 +00:00
drh 6d27844bbe Merge trunk performance enhancements and fixes into the direct-printf branch.
FossilOrigin-Name: 9fa9cd11f8f5f7591168870c6e41121221b58a4a3094e708e3fa5bab1502f190
2026-03-29 19:23:47 +00:00
drh 03f13d77a5 Avoid using unsigned 64-bit integer division on platforms that do not support
it in hardware.

FossilOrigin-Name: 2197677491dfc5ec87b57bbf807776875248a250f80ce9a5ce94ae385bb1d2bc
2026-03-29 19:06:36 +00:00
drh 445fbc61c8 The _umulh() intrinsic function is not available on 32-bit windows. So don't
use it there.

FossilOrigin-Name: e75f30c7e66e725a2f3f46c7d4d69a2ff925e2de9a86c3a6ec38897545b43a58
2026-03-29 10:32:25 +00:00
drh eb0cb3f53b In sqlite3_str_vappendf(), write floating-point renderings directly into
the output buffer, saving a memcpy().

FossilOrigin-Name: e4e040e7aaaf5bfccbf0414fee3d08c5fdc24e03d1118dce92d2dd16c614ce63
2026-03-28 20:24:47 +00:00
drh 5239e69fb1 Remove a harmless unused variable from the fp-speed-2.c benchmark.
FossilOrigin-Name: ff9008e7615d877e6cc852c60097777006b274971646d368eaa56b99a7acf6c7
2026-03-28 14:21:53 +00:00
drh 20d93e16d7 Enhancements to the fp-speed-N.c programs, suggested by Andreas Kupries.
FossilOrigin-Name: 7d81ff4c509d4039ef9e2f1066284ec560131422db0cbffa7e1826d71bb8f8e1
2026-03-28 14:17:53 +00:00
drh c409eaaf14 Reduce the compiled size of the quote() SQL function.
FossilOrigin-Name: 9ea980a35628f7d0741ab6c65840ab9dab8abb576c6c60109147336452f9637a
2026-03-28 13:59:34 +00:00
drh 2e01416762 Turn an sqlite3VMPrintf() into an sqlite3DbStrDup().
FossilOrigin-Name: 75e8703664ae94244284819d9021877a5fc33a268fb86f3e70de20875a766d80
2026-03-28 13:30:47 +00:00
drh ff8a0895d6 Fix up the floating-point speed tests so that they only need to be run once
to get a performance comparision.  Provide the fp-speed-test makefile target
to build and run them both.

FossilOrigin-Name: 09e0e78a8265c2e2bc36fef1fa88bd5bf414f9b776966c1c91a4ed4b7866331d
2026-03-27 20:18:06 +00:00
drh a2f78f665c Add a comment to test/fptest01.sql to remind us that failures in that
script might not be the fault of SQLite.

FossilOrigin-Name: 65efcb0a2ed49fa2fd747b5f034d976ed3cb4a01a185bcada70bf8a5208f3841
2026-03-27 19:25:25 +00:00
drh c4cedd7ffe New test cases for text→float conversions.
FossilOrigin-Name: bbf2d648376a965605d5c641a889ab7ef365bc53788d984c054468e9889deee6
2026-03-27 18:58:50 +00:00
drh 00c6eca32c Enable the use of intrinsic high-precision multiplies on Windows ARM.
Make the SQLITE_DISABLE_INTRINSIC option effective on high-precision
multiple subroutines, for testing purposes.

FossilOrigin-Name: efb6212de4ca998546329b06b43122f0fffa3759e4615ca3357ef9fa13606d44
2026-03-27 16:09:10 +00:00
drh be2242d2ee Change the print resolution the fp-speed-1.c test to 17 digits.
FossilOrigin-Name: c687b32a956315ddf4336df42deb4037c37d51b536b8a24c5cef4c5a0bc4c79b
2026-03-27 14:54:01 +00:00
drh 2dd3b4a646 Update fp-speed-1.c and fp-speed-2.c to include its own timers, so that it
works on platforms that lack the "time" command.

FossilOrigin-Name: 9b083070de2d782fe1db62652af8f3cd48abe16b55b974f3927b738e3d914887
2026-03-27 14:19:01 +00:00
drh 4570aeb7bc Add the fp-speed-2.c performance test program.
FossilOrigin-Name: b788256f1980531e7abb15c5fbcdd40ae166f091aea28f449c0407105ddf1aa4
2026-03-27 14:03:41 +00:00
drh 1283969f26 Add a comment showing reserved file-control numbers to sqlite3.h
FossilOrigin-Name: cd472d7c85f3fda54bba5166eae72b5f9b86861c4a1160583e8ee902ba992255
2026-03-27 11:46:11 +00:00
stephan 772ea2f01c Add SQLITE_STRICT_SUBTYPE to PRAGMA compile_options, an omission reported in [forum:3906a71526|forum post 3906a71526].
FossilOrigin-Name: c5af6a10245b6b847d30002806c1577b020c36ab27f7b1cf202ade136aa4779c
2026-03-26 19:11:57 +00:00
drh d4af925e34 Enhance the return value from sqlite3AtoF() so that it reports if the input
includes more than 19.25 significant digits.

FossilOrigin-Name: 1721c8da769816ca16104cd636299d84f682fc004938a50056b76b269e49e915
2026-03-26 18:19:47 +00:00
drh 61d3bc8ddc Revamp the return code from sqlite3AtoF() for additional information and
for small speed improvement and size reduction.

FossilOrigin-Name: f10a431eade20ecd4c4d501fc534e2dae6ab2fe67302ea7bb3cd6eba127848fc
2026-03-26 16:33:03 +00:00
drh f9a3b78561 Improvements to the sqlite3AtoF() interface. Add a test-control for
direct testing of sqlite3AtoF().

FossilOrigin-Name: 97ee48b6ef65fb55633196282c9e75b3b0a3b81ba9755f63493a38e3f1a5610c
2026-03-26 14:19:34 +00:00
drh f855727e45 Back out the sqlite3_atof() API, for now.
FossilOrigin-Name: 7568d264be3988df195401158d8d07105b8e9e018eccf98ac948219bee9388ac
2026-03-26 12:09:37 +00:00
drh 3d58f022a8 Fix an off-by-one error that cause a loop to (harmlessly) run more times
than necessary.  Performance optimization, not a bug fix.

FossilOrigin-Name: 58f4e058f1cbb798b8a48208c6310fd10ca9cd1fc7c550f3ed283cf38ae45c2f
2026-03-25 21:23:23 +00:00
drh 7e9eaf3c1f Performance optimization when zero-padding in printf().
FossilOrigin-Name: dbd81abdc6633124e72999321db6fc8640851fa5eb063e6317a4c3e57b48dbaa
2026-03-25 21:05:18 +00:00
drh 0944b3efad Small size reduction and performance increase in sqlite3Atoi64().
FossilOrigin-Name: c818165fd709b813ab07788662bf69205ece2dcea41346609b3439950f900057
2026-03-25 19:36:16 +00:00
drh f3f194c385 Signification optimizations to layout of text for floating point
conversions in sqlite3_str_vappendf().

FossilOrigin-Name: 6a74df6d6ecfda8e0ff72ca0f4167190e989973ad124412892f7d36f1666ccfc
2026-03-25 17:59:22 +00:00
dan 183a73c352 Handle the case where the compile-time default page-size is greater than 8192 bytes.
FossilOrigin-Name: 3aea251f238277c68d7a80a4fa643bb0f80b274cef77ef32c4eb833cfaf46740
2026-03-25 11:19:38 +00:00
drh 53197b7940 Prevent overly long JSON paths from using too much stack space.
FossilOrigin-Name: 82a0794814bbc095235f8158a4129a5d83f6af1b0c27cb56449ea32feb44faf5
2026-03-24 19:26:05 +00:00
drh f1f1784f4b Limit JSONB recursion depth in the json_patch() function.
FossilOrigin-Name: f8659b700c0088abe19ce65fec032c1005a1f750566488f4578256d41558770c
2026-03-24 12:39:05 +00:00
drh 814f592cf0 Improved error messages for JSONB nested too deep.
FossilOrigin-Name: 82036fafa175e798fd32b3dc4ad043fc2bbe2bb2af17781f12dcb4d23a233865
2026-03-24 11:54:55 +00:00
stephan 9b805c6248 Remove a stale reference to the long-removed SQLITE_MUTEX_APPDEF, as pointed out in [forum:348453389b|forum post 348453389b].
FossilOrigin-Name: cb8e55b59113d0102c50db0a43b1b59d531cdcb12a7cce4c4c9a428c7c6e1adf
2026-03-24 11:33:22 +00:00
drh 3c2ccd2903 Minor simplification to JSON path error reporting.
FossilOrigin-Name: 1cd30c4827e382861cf12af48579eedc9685b9612dedb6a2844f20355b910e7e
2026-03-24 11:25:44 +00:00
drh 7bf4d708dc Recognize artifical JSONB blobs with deep recursion as being ill-formed.
FossilOrigin-Name: adac4ed1f13a9a1c4a34c8f59438eac68867981748629ca3957055ad9f940299
2026-03-24 00:31:28 +00:00
drh 5239e821e8 Move datatype and structure definitions up near the top in the CLI source code,
to facilitate future changes.  No changes to the actual logic (yet).

FossilOrigin-Name: 6b3d84d34d1a84eb8ddff08cd85d9dff6e71099e7a4b2c19db8774d942d3a040
2026-03-23 21:03:34 +00:00
stephan a217a4af09 Require a button click to start the OPFS concurrency tester, rather than simply launching all N workers immediately on page load.
FossilOrigin-Name: 3342d6786e07d3d8dd4b1f2291edea9f8354d384ff21242cc513c218ce6f1630
2026-03-23 13:17:13 +00:00
drh 3e3c31ff0e Use sqlite3_atof() instead of atof() in the CLI. Dogfooding.
FossilOrigin-Name: 276c350313a1ac2ebc70c1e8e50ed4baecd4be4d4c93ba04cf5e0078da18700e
2026-03-23 13:00:56 +00:00
drh dc32016ee0 Move the definition of the new sqlite3_atof() function in sqlite3.h so
that it is adjacent to sqlite3_mprintf().

FossilOrigin-Name: 1553a60506fa29b5f00535ae0f7aeb8cc94ebe84015386b3248fd8491108fc60
2026-03-23 12:25:52 +00:00
drh 5700f8c471 Add the sqlite3_atof() interface.
FossilOrigin-Name: 52f76c59f27152dd62069bd833e2409d57d0cd36ccaa568b2ec4ec823e98cb44
2026-03-23 10:58:29 +00:00
27 changed files with 1690 additions and 1056 deletions
+15
View File
@@ -2627,6 +2627,12 @@ smoketest: $(TESTPROGS)
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
# Measure the performance of floating-point conversions.
#
fp-speed-test: fp-speed-1.exe fp-speed-2.exe
fp-speed-1 1000000
fp-speed-2 1000000
shelltest:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl release shell
@@ -2719,6 +2725,14 @@ speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
$(TOP)\test\speedtest1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
fp-speed-1.exe: $(TOP)\test\fp-speed-1.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
$(TOP)\test\fp-speed-1.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
fp-speed-2.exe: $(TOP)\test\fp-speed-2.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(ST_COMPILE_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION \
$(TOP)\test\fp-speed-2.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
kvtest.exe: $(TOP)\test\kvtest.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(KV_COMPILE_OPTS) \
$(TOP)\test\kvtest.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -2908,6 +2922,7 @@ clean:
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL
del /Q changeset.exe 2>NUL
del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL
del /Q fp-speed-1.exe fp-speed-2.exe 2>NUL
del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL
del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL
del /Q sqlite3rc.h 2>NUL
+2 -2
View File
@@ -38,8 +38,8 @@
Links for various testing options: <ul id='testlinks'></ul>
</p>
<div class='input-wrapper'>
<input type='checkbox' id='cb-log-reverse'>
<label for='cb-log-reverse'>Reverse log order?</label>
<button id='gogogo'><strong>Start test</strong></button>
<label><input type='checkbox' id='cb-log-reverse'>Reverse log order?</label>
</div>
<div id='test-output'></div>
<script>(function(){
+26 -21
View File
@@ -1,4 +1,5 @@
(async function(self){
const btnGo = document.querySelector('#gogogo');
const logCss = (function(){
const mapToString = (v)=>{
@@ -92,6 +93,7 @@
logCss('tests-pass',"All",workers.length,"workers finished in",
calcTime(new Date()),"ms");
}
logCss("Reload page to run the test again.");
};
workers.onmessage = function(msg){
@@ -158,25 +160,28 @@
a.innerText = args;
}
stdout("Launching",options.workerCount,"workers. Options:",options);
workers.uri = (
'worker.js?'
+ 'sqlite3.dir='+options.sqlite3Dir
+ '&vfs='+options.vfs
+ '&interval='+options.interval
+ '&iterations='+options.iterations
+ '&opfs-verbose='+options.opfsVerbose
+ '&opfs-unlock-asap='+options.unlockAsap
);
for(let i = 0; i < options.workerCount; ++i){
stdout("Launching worker...", i, );
workers.push(new Worker(
workers.uri+'&workerId='+(i+1)+(
(i || options.noUnlink) ? '' : '&unlink-db'
)
));
}
// 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);
btnGo.addEventListener('click', ()=>{
btnGo.remove();
stdout("Launching",options.workerCount,"workers. Options:",options);
workers.uri = (
'worker.js?'
+ 'sqlite3.dir='+options.sqlite3Dir
+ '&vfs='+options.vfs
+ '&interval='+options.interval
+ '&iterations='+options.iterations
+ '&opfs-verbose='+options.opfsVerbose
+ '&opfs-unlock-asap='+options.unlockAsap
);
for(let i = 0; i < options.workerCount; ++i){
stdout("Launching worker...", i, );
workers.push(new Worker(
workers.uri+'&workerId='+(i+1)+(
(i || options.noUnlink) ? '' : '&unlink-db'
)
));
}
// 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);
});
})(globalThis);
+15
View File
@@ -1920,6 +1920,12 @@ smoketest: $(TESTPROGS) fuzzcheck$(T.exe)
shelltest:
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl release shell
# Test performance of floating-point conversions.
#
fp-speed-test: fp-speed-1$(T.exe) fp-speed-2$(T.exe)
./fp-speed-1 1000000
./fp-speed-2 1000000
#
# sqlite3_analyzer.c build depends on $(LINK_TOOLS_DYNAMICALLY).
#
@@ -2037,6 +2043,14 @@ speedtest1$(T.exe): $(TOP)/test/speedtest1.c sqlite3.c Makefile
$(LDFLAGS.libsqlite3)
xbin: speedtest1$(T.exe)
fp-speed-1$(T.exe): $(TOP)/test/fp-speed-1.c sqlite3.o Makefile
$(T.link) $(ST_OPT) -o $@ $(TOP)/test/fp-speed-1.c sqlite3.o \
$(LDFLAGS.libsqlite3)
fp-speed-2$(T.exe): $(TOP)/test/fp-speed-2.c sqlite3.o Makefile
$(T.link) $(ST_OPT) -o $@ $(TOP)/test/fp-speed-2.c sqlite3.o \
$(LDFLAGS.libsqlite3)
startup$(T.exe): $(TOP)/test/startup.c sqlite3.c
$(T.link) -Os -g -USQLITE_THREADSAFE -DSQLITE_THREADSAFE=0 \
-o $@ $(TOP)/test/startup.c sqlite3.c $(LDFLAGS.libsqlite3)
@@ -2482,6 +2496,7 @@ tidy:
rm -f tclsqlite3$(T.exe) $(TESTPROGS)
rm -f LogEst$(T.exe) fts3view$(T.exe) rollback-test$(T.exe) showdb$(T.exe)
rm -f showjournal$(T.exe) showstat4$(T.exe) showwal$(T.exe) speedtest1$(T.exe)
rm -f fp-speed-1$(T.exe) fp-speed-2$(T.exe)
rm -f wordcount$(T.exe) changeset$(T.exe) version-info$(T.exe)
rm -f *.exp *.vsix pkgIndex.tcl
rm -f sqlite3_analyzer$(T.exe) sqlite3_rsync$(T.exe) sqlite3_expert$(T.exe)
+29 -31
View File
@@ -1,12 +1,12 @@
C Proposed\snew\sAPI\sroutine:\ssqlite3_atof().
D 2026-03-22T20:52:23.836
C Fix\sharmless\scompiler\swarnings\sabout\sunused\svariable\sassignments.
D 2026-03-29T22:41:12.963
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 bee487191dcc9394d0e38854aa311b79d4488e0b877cc1a1a61ba5ad8ef225a6
F Makefile.msc 92391304cf70f4c178b127aa83b88637abd28d1b83ede451616144037ea1d3dd
F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec
F VERSION 31435e19ded2aae3c1c67dacf06a995a37fd1b253baec5899b78d64cd29db4f7
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
@@ -646,8 +646,8 @@ F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f80
F ext/wasm/tester1-worker.c-pp.html 7171022e7f4da8f46e5f50ea81dd6ce840b9235c47653a5deeb3764ccc2fe472
F ext/wasm/tester1.c-pp.html bd927ccf51ddd65e924660a0487add99e1b044afe03950e49d87ccf44efdddb6
F ext/wasm/tester1.c-pp.js 581be6f3228351bc77512ba743912d1ad52f40dde1fef1a943fd568b0cfc51b1
F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226
F ext/wasm/tests/opfs/concurrency/test.js 46c772bc18abb0fcbb058d57b5aaee9e7938f948ecdd802c6ca0850ad3519f92
F ext/wasm/tests/opfs/concurrency/index.html 706eab6308343c04ac2360aba6001af4ffaf46d8f33a0ccd02c64d93e3216a43
F ext/wasm/tests/opfs/concurrency/test.js 6919778fceaac1b7cc78caf41d796f545d2c4433b31188aa9689f05b5ad28828
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
@@ -655,7 +655,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 64479b612d66a3f1a3ab498a3a40607937f614168987d8cda8320fa8be517fac
F main.mk 0ed98e9faa3a8e2ce40ec5b55781101048c13c6970bc50d456d4c2834e74f4ea
F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -684,20 +684,20 @@ F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde
F src/expr.c b135746c5aaa80ec13225bfe3e5e46ad74377a7cea46630c1dab6b0409729fab
F src/expr.c 51e9c77ff5d9a21439e611fe6571a3cd50387e526e13c5614fd407e5b8571930
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08
F src/func.c 6e7de3551ae0f8205006e5109f025223246edd20186d54d90746dee7c1c5c093
F src/func.c 706ac012bf87d8ad7416a56a1d2b1f19e5dea03506a4606a01aa9d3bacf392c7
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 7401618493219bb605408be48d2ea5ed5c9055f1c3b733268331eb0174048746
F src/json.c 5027b856cd9b621dc9ba66b211e21a440ccdc63cefdefb44c51e7d3ac550d1a4
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 187929338d21f43cbdea359a3c1ec61294f39b7f9032e824c1dbb79f9994c838
F src/main.c 31a13302193fbd51279c7e69cdfa0320d0de7629f9151e0964c1d320e8bdd7a4
F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9
F src/main.c 387bb9d0216d6d35b221481ba8e661d94ad043060cd89581b6422c269ce680a0
F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -729,17 +729,17 @@ F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
F src/pragma.c 789ef67117b74b5be0a2db6681f7f0c55e6913791b9da309aefd280de2c8a74d
F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d
F src/printf.c 9cff219dba73b1aa9a8113e83e962f03f7bea8b6eb51cefb25bc468d5a69fb2d
F src/printf.c 9abec48ffb0fc1aac72a461e2ca456b5284a39c84cddc932c86822311e059882
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c f0834917f2b1719d545a0d7eaad693283788f68ecd99871a81c7ff3b12b26209
F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576
F src/shell.c.in 4a9217005b76017bc90a08f87c45ea273d796273e0b0a3e4c621a5051a4ae95d
F src/sqlite.h.in ad873c7d97fdc13538f2b75f57a706b118df7026e49fe0f350e82c38c7892d11
F src/shell.c.in 91ee40ec3f75192362cbaa0ad85316140b8dde00a184113d73a837fb6173dbcc
F src/sqlite.h.in e7acbb01518f05c5a342149ec1eeb1afcdccf9b90a6e9770a4893ae9a3c756ae
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 5d48df11327acaabc45690a1957f0f4643e07afd9f77c5f2326115239fe5a3bc
F src/sqliteInt.h 9716721fb57e32938a1d30a84560ce7633c63860a2209e188c87afad15d4b464
F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
F src/sqliteInt.h bc1cbc0c23dba35b324ae85a7dbb5fb182321bbd30857fb21f3d0cba049001a5
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 7401c73c917a4d1b380c896a324c8d8eb533a999559d9e339d479596553bebfd
@@ -792,21 +792,21 @@ F src/test_vfs.c b4135c1308516adf0dfd494e6d6c33114e03732be899eace0502919b674586b
F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8ea72
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 85d8b9f05f78211c61e3739ab5db761d7118766d1916ae7f2764735106bc4e13
F src/tokenize.c 2bbf16801d8c59aaf5435b066364da9e39ec3a379084b8a697881e7e52733c63
F src/tokenize.c e9d52d9f7374d82dadcd11726bea8a597d43709d6672704f3f0375bf1d726912
F src/treeview.c feaa59f14db4f7b5aacca9c5ad5aeb562c1f98262c1ffd74371f4186ade91fc5
F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
F src/util.c 32e5aed34f20508356a297f4a28762ecd1db0c81bfcbe5aa9d9ebcc6a52b6a85
F src/util.c f264a84eda716ae009089f1d788b55718062810792b0bfa331e7899f2add39c6
F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82
F src/vdbe.c dbafc6f5762f9ae90d9dc9ed065a31743a8ceafbdbfb1a0a3a228921fb3cc36a
F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3
F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
F src/vdbeaux.c 81687c55682b9f4d942186695f4f7fa4743c564a985e0889def52eded9076d61
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
F src/vdbemem.c 05610ea8423c4c852a9039e47fb6a2706d4d848758602ebf30da6c3212344695
F src/vdbemem.c 5af6cf1253ac2aed0612b85138a1faf43f30ad38777d554db6c85b7281fa79fb
F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
@@ -1126,9 +1126,10 @@ F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958fdde5c
F test/fork-test.c 9ac2e6423a1d38df3d6be0e8ac15608b545de21e2b19d9d876254c5931b63edb
F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4
F test/fp-speed-1.c b37de94eba034e1703668816225f54510ec60fb0685406608cc707afe6b8234d
F test/fp-speed-1.c 34a2fe8dc30d0b24bb3e7c16efca0a30452287da6caff7dde86eef882db155a4
F test/fp-speed-2.c 15830b061832bb51f68f0985cf7a06f4f5d49eb25cc399854f1ff60d6a878ee9
F test/fpconv1.test 63f352682fa65601a326563ad633086df6ab194e6ed5e7366786f38a525a7fd7
F test/fptest01.sql 210562ad8d5a7895f26273dd3be56561a41bcb51d78a28a337af0f1ceaa3bb8d
F test/fptest01.sql 3d84f10bb1cc220b59207354c887d720289903adeb9972a29d6bfcb3fec0df95
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654
F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a
@@ -2137,7 +2138,7 @@ F tool/mkamalzip.tcl 8aa5ebe7973c8b8774062d34e15fea9815c4cc2ceea3a9b184695f00591
F tool/mkautoconfamal.sh 06fbe090b81c24e592c1f22b404334f805ba74d482a9260f2ac81e6f3d3386d8
F tool/mkccode.tcl c42a8f8cf78f92e83795d5447460dbce7aaf78a3bbf9082f1507dc71a3665f3c x
F tool/mkcombo.tcl 2a5189b219c4a495e1ff7fc980bd568d3cfb82ae9d50c84e77f7a161e96fc132
F tool/mkctimec.tcl 3fb5cad05922f5da61262cb6bcd5868a34e94a49ca8833ae2d7796e7df075576 x
F tool/mkctimec.tcl 68f3ee9e2e6a06524b25d79b5b61a883053466080a39da59e0a0697f0c4d9a3b x
F tool/mkfptab.c 24ea40113f96584caca3f6dd06b4ad5adffa0f39023910cb83fa7ef2ffa9b0ba
F tool/mkkeywordhash.c 82d5af1d0e677900739fba59155cddac172d8c712c2d91ab73d6e6bcb30060f0
F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14ebb7a
@@ -2195,11 +2196,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
P 62f011509600ab8cda28888ebd32e5faa4e865702755bc32dee7a12bf2f4425d
R ecbe134231e80d18c47a828b4727e394
T *branch * atof
T *sym-atof *
T -sym-trunk *
P 9fa9cd11f8f5f7591168870c6e41121221b58a4a3094e708e3fa5bab1502f190
R 3d9d1b868f679fc05545d2cf5aa8e36a
U drh
Z f810f3325e6bad43a83315df84a7d9cd
Z e2629b4a210900f82e89295566df240e
# Remove this line to create a well-formed Fossil manifest.
+2 -2
View File
@@ -1,2 +1,2 @@
branch atof
tag atof
branch direct-printf
tag direct-printf
+1 -1
View File
@@ -1 +1 @@
db370f0f628895279a1c1db79ba7428cb4e31b56cafc191859c2f1a5a924435b
afe7e9fd1c476c7cdcefab0adf0191a8dc3283811f72a685fff3eb6539b72dcc
+2 -1
View File
@@ -4302,7 +4302,8 @@ sqlite3ExprCodeIN_oom_error:
*/
static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
if( ALWAYS(z!=0) ){
double value = sqlite3_atof(z);
double value;
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);
+5 -12
View File
@@ -1098,18 +1098,11 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){
switch( sqlite3_value_type(pValue) ){
case SQLITE_FLOAT: {
double r1, r2;
const char *zVal;
r1 = sqlite3_value_double(pValue);
sqlite3_str_appendf(pStr, "%!0.15g", r1);
zVal = sqlite3_str_value(pStr);
if( zVal ){
sqlite3AtoF(zVal, &r2);
if( r1!=r2 ){
sqlite3_str_reset(pStr);
sqlite3_str_appendf(pStr, "%!0.20e", r1);
}
}
/* ,--- Show infinity as 9.0e+999
** |
** | ,--- 17 precision guarantees round-trip
** v v */
sqlite3_str_appendf(pStr, "%!0.17g", sqlite3_value_double(pValue));
break;
}
case SQLITE_INTEGER: {
+76 -28
View File
@@ -313,7 +313,8 @@ struct JsonString {
/* Allowed values for JsonString.eErr */
#define JSTRING_OOM 0x01 /* Out of memory */
#define JSTRING_MALFORMED 0x02 /* Malformed JSONB */
#define JSTRING_ERR 0x04 /* Error already sent to sqlite3_result */
#define JSTRING_TOODEEP 0x04 /* JSON nested too deep */
#define JSTRING_ERR 0x08 /* Error already sent to sqlite3_result */
/* The "subtype" set for text JSON values passed through using
** sqlite3_result_subtype() and sqlite3_value_subtype().
@@ -403,7 +404,7 @@ struct JsonParse {
**************************************************************************/
static void jsonReturnStringAsBlob(JsonString*);
static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p);
static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*);
static u32 jsonTranslateBlobToText(JsonParse*,u32,JsonString*);
static void jsonReturnParse(sqlite3_context*,JsonParse*);
static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32);
static void jsonParseFree(JsonParse*);
@@ -561,6 +562,15 @@ static void jsonStringOom(JsonString *p){
jsonStringReset(p);
}
/* Report JSON nested too deep
*/
static void jsonStringTooDeep(JsonString *p){
p->eErr |= JSTRING_TOODEEP;
assert( p->pCtx!=0 );
sqlite3_result_error(p->pCtx, "JSON nested too deep", -1);
jsonStringReset(p);
}
/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
** Return zero on success. Return non-zero on an OOM error
*/
@@ -877,6 +887,8 @@ static void jsonReturnString(
}
}else if( p->eErr & JSTRING_OOM ){
sqlite3_result_error_nomem(p->pCtx);
}else if( p->eErr & JSTRING_TOODEEP ){
/* error already in p->pCtx */
}else if( p->eErr & JSTRING_MALFORMED ){
sqlite3_result_error(p->pCtx, "malformed JSON", -1);
}
@@ -2178,7 +2190,7 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
** The pOut->eErr JSTRING_OOM flag is set on a OOM.
*/
static u32 jsonTranslateBlobToText(
const JsonParse *pParse, /* the complete parse of the JSON */
JsonParse *pParse, /* the complete parse of the JSON */
u32 i, /* Start rendering at this index */
JsonString *pOut /* Write JSON here */
){
@@ -2360,10 +2372,14 @@ static u32 jsonTranslateBlobToText(
jsonAppendChar(pOut, '[');
j = i+n;
iEnd = j+sz;
if( ++pParse->iDepth > JSON_MAX_DEPTH ){
jsonStringTooDeep(pOut);
}
while( j<iEnd && pOut->eErr==0 ){
j = jsonTranslateBlobToText(pParse, j, pOut);
jsonAppendChar(pOut, ',');
}
pParse->iDepth--;
if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
if( sz>0 ) jsonStringTrimOneChar(pOut);
jsonAppendChar(pOut, ']');
@@ -2374,10 +2390,14 @@ static u32 jsonTranslateBlobToText(
jsonAppendChar(pOut, '{');
j = i+n;
iEnd = j+sz;
if( ++pParse->iDepth > JSON_MAX_DEPTH ){
jsonStringTooDeep(pOut);
}
while( j<iEnd && pOut->eErr==0 ){
j = jsonTranslateBlobToText(pParse, j, pOut);
jsonAppendChar(pOut, (x++ & 1) ? ',' : ':');
}
pParse->iDepth--;
if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
if( sz>0 ) jsonStringTrimOneChar(pOut);
jsonAppendChar(pOut, '}');
@@ -2434,7 +2454,7 @@ static u32 jsonTranslateBlobToPrettyText(
u32 i /* Start rendering at this index */
){
u32 sz, n, j, iEnd;
const JsonParse *pParse = pPretty->pParse;
JsonParse *pParse = pPretty->pParse;
JsonString *pOut = pPretty->pOut;
n = jsonbPayloadSize(pParse, i, &sz);
if( n==0 ){
@@ -2449,6 +2469,9 @@ static u32 jsonTranslateBlobToPrettyText(
if( j<iEnd ){
jsonAppendChar(pOut, '\n');
pPretty->nIndent++;
if( pPretty->nIndent >= JSON_MAX_DEPTH ){
jsonStringTooDeep(pOut);
}
while( pOut->eErr==0 ){
jsonPrettyIndent(pPretty);
j = jsonTranslateBlobToPrettyText(pPretty, j);
@@ -2470,6 +2493,10 @@ static u32 jsonTranslateBlobToPrettyText(
if( j<iEnd ){
jsonAppendChar(pOut, '\n');
pPretty->nIndent++;
if( pPretty->nIndent >= JSON_MAX_DEPTH ){
jsonStringTooDeep(pOut);
}
pParse->iDepth = pPretty->nIndent;
while( pOut->eErr==0 ){
jsonPrettyIndent(pPretty);
j = jsonTranslateBlobToText(pParse, j, pOut);
@@ -2871,7 +2898,8 @@ static int jsonLabelCompare(
#define JSON_LOOKUP_ERROR 0xffffffff
#define JSON_LOOKUP_NOTFOUND 0xfffffffe
#define JSON_LOOKUP_NOTARRAY 0xfffffffd
#define JSON_LOOKUP_PATHERROR 0xfffffffc
#define JSON_LOOKUP_TOODEEP 0xfffffffc
#define JSON_LOOKUP_PATHERROR 0xfffffffb
#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
/* Forward declaration */
@@ -2918,7 +2946,12 @@ static u32 jsonCreateEditSubstructure(
pIns->eEdit = pParse->eEdit;
pIns->nIns = pParse->nIns;
pIns->aIns = pParse->aIns;
pIns->iDepth = pParse->iDepth+1;
if( pIns->iDepth >= JSON_MAX_DEPTH ){
return JSON_LOOKUP_TOODEEP;
}
rc = jsonLookupStep(pIns, 0, zTail, 0);
pParse->iDepth--;
pParse->oom |= pIns->oom;
}
return rc; /* Error code only */
@@ -3024,7 +3057,11 @@ static u32 jsonLookupStep(
n = jsonbPayloadSize(pParse, v, &sz);
if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR;
assert( j>0 );
if( ++pParse->iDepth >= JSON_MAX_DEPTH ){
return JSON_LOOKUP_TOODEEP;
}
rc = jsonLookupStep(pParse, v, &zPath[i], j);
pParse->iDepth--;
if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
return rc;
}
@@ -3110,7 +3147,11 @@ static u32 jsonLookupStep(
iEnd = j+sz;
while( j<iEnd ){
if( kk==0 ){
if( ++pParse->iDepth >= JSON_MAX_DEPTH ){
return JSON_LOOKUP_TOODEEP;
}
rc = jsonLookupStep(pParse, j, &zPath[i+1], 0);
pParse->iDepth--;
if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
return rc;
}
@@ -3442,7 +3483,16 @@ static int jsonFunctionArgToBlob(
}
/*
** Generate a bad path error.
** Generate a path error.
**
** The specifics of the error are determined by the rc argument.
**
** rc error
** ----------------- ----------------------
** JSON_LOOKUP_ARRAY "not an array"
** JSON_LOOKUP_TOODEEP "JSON nested too deep"
** JSON_LOOKUP_ERROR "malformed JSON"
** otherwise... "bad JSON path"
**
** If ctx is not NULL then push the error message into ctx and return NULL.
** If ctx is NULL, then return the text of the error message.
@@ -3455,6 +3505,10 @@ static char *jsonBadPathError(
char *zMsg;
if( rc==(int)JSON_LOOKUP_NOTARRAY ){
zMsg = sqlite3_mprintf("not an array element: %Q", zPath);
}else if( rc==(int)JSON_LOOKUP_ERROR ){
zMsg = sqlite3_mprintf("malformed JSON");
}else if( rc==(int)JSON_LOOKUP_TOODEEP ){
zMsg = sqlite3_mprintf("JSON path too deep");
}else{
zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath);
}
@@ -3517,6 +3571,7 @@ static void jsonInsertIntoBlob(
p->nIns = ax.nBlob;
p->aIns = ax.aBlob;
p->delta = 0;
p->iDepth = 0;
rc = jsonLookupStep(p, 0, zPath+1, 0);
}
jsonParseReset(&ax);
@@ -3529,11 +3584,7 @@ static void jsonInsertIntoBlob(
jsonInsertIntoBlob_patherror:
jsonParseFree(p);
if( rc==JSON_LOOKUP_ERROR ){
sqlite3_result_error(ctx, "malformed JSON", -1);
}else{
jsonBadPathError(ctx, zPath, rc);
}
jsonBadPathError(ctx, zPath, rc);
return;
}
@@ -3973,10 +4024,8 @@ static void jsonArrayLengthFunc(
if( JSON_LOOKUP_ISERROR(i) ){
if( i==JSON_LOOKUP_NOTFOUND ){
/* no-op */
}else if( i==JSON_LOOKUP_PATHERROR ){
jsonBadPathError(ctx, zPath, 0);
}else{
sqlite3_result_error(ctx, "malformed JSON", -1);
jsonBadPathError(ctx, zPath, i);
}
eErr = 1;
i = 0;
@@ -4110,11 +4159,8 @@ static void jsonExtractFunc(
jsonAppendSeparator(&jx);
jsonAppendRawNZ(&jx, "null", 4);
}
}else if( j==JSON_LOOKUP_ERROR ){
sqlite3_result_error(ctx, "malformed JSON", -1);
goto json_extract_error;
}else{
jsonBadPathError(ctx, zPath, 0);
jsonBadPathError(ctx, zPath, j);
goto json_extract_error;
}
}
@@ -4138,6 +4184,7 @@ json_extract_error:
#define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */
#define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */
#define JSON_MERGE_OOM 3 /* Out-of-memory condition */
#define JSON_MERGE_TOODEEP 4 /* Nested too deep */
/*
** RFC-7396 MergePatch for two JSONB blobs.
@@ -4189,7 +4236,8 @@ static int jsonMergePatch(
JsonParse *pTarget, /* The JSON parser that contains the TARGET */
u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */
const JsonParse *pPatch, /* The PATCH */
u32 iPatch /* Index of PATCH in pPatch->aBlob[] */
u32 iPatch, /* Index of PATCH in pPatch->aBlob[] */
u32 iDepth /* Nesting depth */
){
u8 x; /* Type of a single node */
u32 n, sz=0; /* Return values from jsonbPayloadSize() */
@@ -4298,7 +4346,8 @@ static int jsonMergePatch(
/* Algorithm line 12 */
int rc, savedDelta = pTarget->delta;
pTarget->delta = 0;
rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue);
if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP;
rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue, iDepth+1);
if( rc ) return rc;
pTarget->delta += savedDelta;
}
@@ -4319,7 +4368,8 @@ static int jsonMergePatch(
pTarget->aBlob[iTEnd+szNew] = 0x00;
savedDelta = pTarget->delta;
pTarget->delta = 0;
rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue);
if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP;
rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue,iDepth+1);
if( rc ) return rc;
pTarget->delta += savedDelta;
}
@@ -4350,11 +4400,13 @@ static void jsonPatchFunc(
if( pTarget==0 ) return;
pPatch = jsonParseFuncArg(ctx, argv[1], 0);
if( pPatch ){
rc = jsonMergePatch(pTarget, 0, pPatch, 0);
rc = jsonMergePatch(pTarget, 0, pPatch, 0, 0);
if( rc==JSON_MERGE_OK ){
jsonReturnParse(ctx, pTarget);
}else if( rc==JSON_MERGE_OOM ){
sqlite3_result_error_nomem(ctx);
}else if( rc==JSON_MERGE_TOODEEP ){
sqlite3_result_error(ctx, "JSON nested too deep", -1);
}else{
sqlite3_result_error(ctx, "malformed JSON", -1);
}
@@ -4442,10 +4494,8 @@ static void jsonRemoveFunc(
if( JSON_LOOKUP_ISERROR(rc) ){
if( rc==JSON_LOOKUP_NOTFOUND ){
continue; /* No-op */
}else if( rc==JSON_LOOKUP_PATHERROR ){
jsonBadPathError(ctx, zPath, rc);
}else{
sqlite3_result_error(ctx, "malformed JSON", -1);
jsonBadPathError(ctx, zPath, rc);
}
goto json_remove_done;
}
@@ -4542,10 +4592,8 @@ static void jsonTypeFunc(
if( JSON_LOOKUP_ISERROR(i) ){
if( i==JSON_LOOKUP_NOTFOUND ){
/* no-op */
}else if( i==JSON_LOOKUP_PATHERROR ){
jsonBadPathError(ctx, zPath, 0);
}else{
sqlite3_result_error(ctx, "malformed JSON", -1);
jsonBadPathError(ctx, zPath, i);
}
goto json_type_done;
}
+2 -3
View File
@@ -528,12 +528,11 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_str_free,
#ifdef SQLITE_ENABLE_CARRAY
sqlite3_carray_bind,
sqlite3_carray_bind_v2,
sqlite3_carray_bind_v2
#else
0,
0,
0
#endif
sqlite3_atof
};
/* True if x is the directory separator character
+11
View File
@@ -4716,6 +4716,17 @@ int sqlite3_test_control(int op, ...){
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_ATOF, const char *z, double *p);
**
** Test access to the sqlite3AtoF() routine.
*/
case SQLITE_TESTCTRL_ATOF: {
const char *z = va_arg(ap,const char*);
double *pR = va_arg(ap,double*);
rc = sqlite3AtoF(z,pR);
break;
}
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
**
+76 -39
View File
@@ -496,9 +496,11 @@ void sqlite3_str_vappendf(
}while( longvalue>0 );
}
length = (int)(&zOut[nOut-1]-bufpt);
while( precision>length ){
*(--bufpt) = '0'; /* Zero pad */
length++;
if( precision>length ){ /* zero pad */
int nn = precision-length;
bufpt -= nn;
memset(bufpt,'0',nn);
length = precision;
}
if( cThousand ){
int nn = (length - 1)/3; /* Number of "," to insert */
@@ -529,6 +531,7 @@ void sqlite3_str_vappendf(
FpDecode s;
int iRound;
int j;
i64 szBufNeeded; /* Size needed to hold the output */
if( bArgList ){
realvalue = getDoubleArg(pArgList);
@@ -617,17 +620,15 @@ void sqlite3_str_vappendf(
}else{
e2 = s.iDP - 1;
}
bufpt = buf;
{
i64 szBufNeeded; /* Size of a temporary buffer needed */
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
if( szBufNeeded > etBUFSIZE ){
bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
if( bufpt==0 ) return;
}
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+8;
if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
if( sqlite3StrAccumEnlargeIfNeeded(pAccum, szBufNeeded) ){
width = length = 0;
break;
}
zOut = bufpt;
bufpt = zOut = pAccum->zText + pAccum->nChar;
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */
if( prefix ){
@@ -635,12 +636,24 @@ void sqlite3_str_vappendf(
}
/* Digits prior to the decimal point */
j = 0;
assert( s.n>0 );
if( e2<0 ){
*(bufpt++) = '0';
}else{
}else if( cThousand ){
for(; e2>=0; e2--){
*(bufpt++) = j<s.n ? s.z[j++] : '0';
if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
if( (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
}
}else{
j = e2+1;
if( j>s.n ) j = s.n;
memcpy(bufpt, s.z, j);
bufpt += j;
e2 -= j;
if( e2>=0 ){
memset(bufpt, '0', e2+1);
bufpt += e2+1;
e2 = -1;
}
}
/* The decimal point */
@@ -649,12 +662,26 @@ void sqlite3_str_vappendf(
}
/* "0" digits after the decimal point but before the first
** significant digit of the number */
for(e2++; e2<0 && precision>0; precision--, e2++){
*(bufpt++) = '0';
if( e2<(-1) && precision>0 ){
int nn = -1-e2;
if( nn>precision ) nn = precision;
memset(bufpt, '0', nn);
bufpt += nn;
precision -= nn;
}
/* Significant digits after the decimal point */
while( (precision--)>0 ){
*(bufpt++) = j<s.n ? s.z[j++] : '0';
if( precision>0 ){
int nn = s.n - j;
if( NEVER(nn>precision) ) nn = precision;
if( nn>0 ){
memcpy(bufpt, s.z+j, nn);
bufpt += nn;
precision -= nn;
}
if( precision>0 && !flag_rtz ){
memset(bufpt, '0', precision);
bufpt += precision;
}
}
/* Remove trailing zeros and the "." if no digits follow the "." */
if( flag_rtz && flag_dp ){
@@ -684,27 +711,31 @@ void sqlite3_str_vappendf(
*(bufpt++) = (char)(exp/10+'0'); /* 10's digit */
*(bufpt++) = (char)(exp%10+'0'); /* 1's digit */
}
*bufpt = 0;
/* The converted number is in buf[] and zero terminated. Output it.
** Note that the number is in the usual order, not reversed as with
** integer conversions. */
length = (int)(bufpt-zOut);
bufpt = zOut;
/* Special case: Add leading zeros if the flag_zeropad flag is
** set and we are not left justified */
if( flag_zeropad && !flag_leftjustify && length < width){
int i;
int nPad = width - length;
for(i=width; i>=nPad; i--){
bufpt[i] = bufpt[i-nPad];
assert( length <= szBufNeeded );
if( length<width ){
i64 nPad = width - length;
if( flag_leftjustify ){
memset(bufpt, ' ', nPad);
}else if( !flag_zeropad ){
memmove(zOut+nPad, zOut, length);
memset(zOut, ' ', nPad);
}else{
int adj = prefix!=0;
memmove(zOut+nPad+adj, zOut+adj, length-adj);
memset(zOut+adj, '0', nPad);
}
i = prefix!=0;
while( nPad-- ) bufpt[i++] = '0';
length = width;
}
break;
pAccum->nChar += length;
zOut[length] = 0;
/* Floating point conversions render directly into the output
** buffer. Hence, don't just break out of the switch(). Bypass the
** output buffer writing that occurs after the switch() by continuing
** to the next character in the format string. */
continue;
}
case etSIZE:
if( !bArgList ){
@@ -748,11 +779,10 @@ void sqlite3_str_vappendf(
i64 nCopyBytes;
if( nPrior > precision-1 ) nPrior = precision - 1;
nCopyBytes = length*nPrior;
if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){
sqlite3StrAccumEnlarge(pAccum, nCopyBytes);
if( sqlite3StrAccumEnlargeIfNeeded(pAccum, nCopyBytes) ){
break;
}
if( pAccum->accError ) break;
sqlite3_str_append(pAccum,
sqlite3_str_append(pAccum,
&pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes);
precision -= nPrior;
nPrior *= 2;
@@ -1098,6 +1128,13 @@ int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){
return (int)N;
}
int sqlite3StrAccumEnlargeIfNeeded(StrAccum *p, i64 N){
if( N + p->nChar >= p->nAlloc ){
sqlite3StrAccumEnlarge(p, N);
}
return p->accError;
}
/*
** Append N copies of character c to the given string buffer.
*/
+1 -1
View File
@@ -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) );
r = sqlite3_atof(p->u.zToken);
sqlite3AtoF(p->u.zToken, &r);
assert( r>=0.0 );
if( r>1.0 ) return -1;
return (int)(r*134217728.0);
+772 -769
View File
File diff suppressed because it is too large Load Diff
+7 -29
View File
@@ -1290,6 +1290,12 @@ struct sqlite3_io_methods {
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
/* reserved file-control numbers:
** 101
** 102
** 103
*/
/*
** CAPI3REF: Mutex Handle
@@ -8357,13 +8363,6 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix
** and Windows.
**
** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
** implementation is included with the library. In this case the
** application must supply a custom mutex implementation using the
** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
** before calling sqlite3_initialize() or any other public sqlite3_
** function that calls sqlite3_initialize().
**
** ^The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
@@ -8718,6 +8717,7 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
#define SQLITE_TESTCTRL_ATOF 34
#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/*
@@ -10925,28 +10925,6 @@ int sqlite3_preupdate_blobwrite(sqlite3 *);
*/
int sqlite3_system_errno(sqlite3*);
/*
** CAPI3REF: Text-to-float conversion
**
** The sqlite3_atof(X) interface returns a "double" derived from the
** text representation of a floating point value in X.
** This interface provides applications with access to the
** same text&rarr;float conversion routine used by SQLite for SQL parsing
** and type coercion. The sqlite3_atof(X) routine works like the standard
** C-library atof(X) routine with the following exceptions:
**
** <ul>
** <li> Parsing of the input X is strict. If anything about X
** is not well-formed, 0.0 is returned.
** <li> Special values such like "INF", "INFINITY", and "NAN" are not
** recognized.
** <li> Hexadecimal floating point literals are not recognized.
** <li> The current locale is ignored. The radix character is always ".".
** <li> The sqlite3_atof() interface does not set errno.
** </ul>
*/
double sqlite3_atof(const char*);
/*
** CAPI3REF: Database Snapshot
** KEYWORDS: {snapshot} {sqlite3_snapshot}
-4
View File
@@ -376,8 +376,6 @@ struct sqlite3_api_routines {
void (*str_free)(sqlite3_str*);
int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*));
int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*);
/* Version 3.53.0 and later */
double (*atof)(const char*);
};
/*
@@ -721,8 +719,6 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_str_free sqlite3_api->str_free
#define sqlite3_carray_bind sqlite3_api->carray_bind
#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2
/* Version 3.53.0 and later */
#define sqlite3_atof sqlite3_api->atof
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+12 -6
View File
@@ -4828,17 +4828,22 @@ struct PrintfArguments {
sqlite3_value **apArg; /* The argument values */
};
/*
** Maxium number of base-10 digits in an unsigned 64-bit integer
*/
#define SQLITE_U64_DIGITS 20
/*
** An instance of this object receives the decoding of a floating point
** value into an approximate decimal representation.
*/
struct FpDecode {
int n; /* Significant digits in the decode */
int iDP; /* Location of the decimal point */
char *z; /* Start of significant digits */
char zBuf[20]; /* Storage for significant digits */
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[SQLITE_U64_DIGITS+1]; /* Storage for significant digits */
char sign; /* '+' or '-' */
char isSpecial; /* 1: Infinity 2: NaN */
};
void sqlite3FpDecode(FpDecode*,double,int,int);
@@ -5526,6 +5531,7 @@ char *sqlite3RCStrResize(char*,u64);
void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
int sqlite3StrAccumEnlarge(StrAccum*, i64);
int sqlite3StrAccumEnlargeIfNeeded(StrAccum*, i64);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumSetError(StrAccum*, u8);
void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
+4
View File
@@ -232,6 +232,10 @@
# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
#endif
#if SQLITE_MAX_DEFAULT_PAGE_SIZE<SQLITE_DEFAULT_PAGE_SIZE
# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_DEFAULT_PAGE_SIZE
#endif
/*
+1 -1
View File
@@ -734,7 +734,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
}
if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){
if( pParse->zErrMsg==0 ){
pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
pParse->zErrMsg = sqlite3DbStrDup(db, sqlite3ErrStr(pParse->rc));
}
if( (pParse->prepFlags & SQLITE_PREPARE_DONT_LOG)==0 ){
sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
+150 -71
View File
@@ -465,11 +465,12 @@ u8 sqlite3StrIHash(const char *z){
*/
static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
#if (defined(__GNUC__) || defined(__clang__)) \
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv))
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
&& !defined(SQLITE_DISABLE_INTRINSIC)
__uint128_t r = (__uint128_t)a * b;
*pLo = (u64)r;
return (u64)(r>>64);
#elif defined(_MSC_VER) && defined(_M_X64)
#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC)
*pLo = a*b;
return __umulh(a, b);
#else
@@ -500,17 +501,19 @@ static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
*/
static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
#if (defined(__GNUC__) || defined(__clang__)) \
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv))
&& (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
&& !defined(SQLITE_DISABLE_INTRINSIC)
__uint128_t r = (__uint128_t)a * b;
r += ((__uint128_t)aLo * b) >> 32;
*pLo = (r>>32)&0xffffffff;
return r>>64;
#elif defined(_MSC_VER) && defined(_M_X64)
#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC)
u64 r1_hi = __umulh(a,b);
u64 r1_lo = a*b;
u64 r2 = (__umulh((u64)aLo,b)<<32) + ((aLo*b)>>32);
r1_hi += _addcarry_u64(0, r1_lo, r2, &r1_lo);
*pLo = r1_lo>>32;
u64 t = r1_lo + r2;
if( t<r1_lo ) r1_hi++;
*pLo = t>>32;
return r1_hi;
#else
u64 x2 = a>>32;
@@ -722,7 +725,8 @@ static int pwr2to10(int p){ return (p*78913) >> 18; }
** Count leading zeros for a 64-bit unsigned integer.
*/
static int countLeadingZeros(u64 m){
#if defined(__GNUC__) || defined(__clang__)
#if (defined(__GNUC__) || defined(__clang__)) \
&& !defined(SQLITE_DISABLE_INTRINSIC)
return __builtin_clzll(m);
#else
int n = 0;
@@ -820,25 +824,28 @@ static double sqlite3Fp10Convert2(u64 d, int p){
**
** Return positive if the result is a valid real number (or integer) and
** zero or negative if the string is empty or contains extraneous text.
** More specifically:
** Lower bits of the return value contain addition information about the
** parse:
**
** 1 => The input string is a pure integer
** 2 or more => The input has a decimal point or eNNN clause
** 0 or less => The input string is not well-formed
** -1 => The input is not well-formed, but it does begin
** with a well-formed floating-point literal (with
** a "." or a "eNNN" suffix or both) followed by
** other extraneous text.
** bit 0 => Set for any valid input
** bit 1 => Input contains a decimal point or eNNN clause
** This bit is zero if the input is an integer
** bit 2 => The input is exactly 0.0, not an underflow from
** some value near zero
** bit 3 => More than 19 significant digits in the input
**
** Valid numbers are in one of these formats:
** If the input contains a syntax error but begins with text that might
** be a valid number of some kind, then the result is negative. The
** result is only zero if no prefix of the input could be interpreted as
** a number.
**
** Leading and trailing whitespace is ignored. Valid numbers are in
** one of the formats below:
**
** [+-]digits[E[+-]digits]
** [+-]digits.[digits][E[+-]digits]
** [+-].digits[E[+-]digits]
**
** Leading and trailing whitespace is ignored for the purpose of determining
** validity.
**
** Algorithm sketch: Compute an unsigned 64-bit integer s and a base-10
** exponent d such that the value encoding by the input is s*pow(10,d).
** Then invoke sqlite3Fp10Convert2() to calculated the closest possible
@@ -859,20 +866,20 @@ int sqlite3AtoF(const char *zIn, double *pResult){
int neg = 0; /* True for a negative value */
u64 s = 0; /* mantissa */
int d = 0; /* Value is s * pow(10,d) */
int seenDigit = 0; /* true if any digits seen */
int seenFP = 0; /* True if we've seen a "." or a "e" */
int mState = 0; /* 1: digit seen 2: fp 4: hard-zero */
unsigned v; /* Value of a single digit */
start_of_text:
if( (v = (unsigned)z[0] - '0')<10 ){
parse_integer_part:
seenDigit = 1;
mState = 1;
s = v;
z++;
while( (v = (unsigned)z[0] - '0')<10 ){
s = s*10 + v;
z++;
if( s>=(LARGEST_INT64-9)/10 ){
if( s>=(LARGEST_UINT64-9)/10 ){
mState = 9;
while( sqlite3Isdigit(z[0]) ){ z++; d++; }
break;
}
@@ -894,20 +901,22 @@ int sqlite3AtoF(const char *zIn, double *pResult){
/* if decimal point is present */
if( *z=='.' ){
z++;
seenFP = 1;
if( sqlite3Isdigit(z[0]) ){
seenDigit = 1;
mState |= 1;
do{
if( s<((LARGEST_INT64-9)/10) ){
if( s<(LARGEST_UINT64-9)/10 ){
s = s*10 + z[0] - '0';
d--;
}else{
mState = 11;
}
z++;
}while( sqlite3Isdigit(z[0]) );
}while( sqlite3Isdigit(*++z) );
}else if( mState==0 ){
*pResult = 0.0;
return 0;
}
}
if( !seenDigit ){
mState |= 2;
}else if( mState==0 ){
*pResult = 0.0;
return 0;
}
@@ -931,7 +940,7 @@ int sqlite3AtoF(const char *zIn, double *pResult){
if( (v = (unsigned)z[0] - '0')<10 ){
int exp = v;
z++;
seenFP = 1;
mState |= 2;
while( (v = (unsigned)z[0] - '0')<10 ){
exp = exp<10000 ? (exp*10 + v) : 10000;
z++;
@@ -943,35 +952,32 @@ int sqlite3AtoF(const char *zIn, double *pResult){
}
}
/* skip trailing spaces */
while( sqlite3Isspace(*z) ) z++;
/* Convert s*pow(10,d) into real */
*pResult = s ? sqlite3Fp10Convert2(s,d) : 0.0;
if( s==0 ){
*pResult = 0.0;
mState |= 4;
}else{
*pResult = sqlite3Fp10Convert2(s,d);
}
if( neg ) *pResult = -*pResult;
assert( !sqlite3IsNaN(*pResult) );
/* return true if number and no extra non-whitespace characters after */
if( z[0]==0 ){
return seenFP+1;
}else if( seenFP ){
return -1; /* Prefix is a floating point number */
}else{
return 0; /* Prefix is just an integer */
return mState;
}
if( sqlite3Isspace(z[0]) ){
do{ z++; }while( sqlite3Isspace(*z) );
if( z[0]==0 ){
return mState;
}
}
return 0xfffffff0 | mState;
#else
return !sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8);
return sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8)==0;
#endif /* SQLITE_OMIT_FLOATING_POINT */
}
/*
** Access to sqlite3AtoF()
*/
double sqlite3_atof(const char *z){
double r;
return sqlite3AtoF(z,&r)>0 ? r : 0.0;
}
/*
** Digit pairs used to convert a U64 or I64 into text, two digits
** at a time.
@@ -992,6 +998,69 @@ static const union {
"90919293949596979899"
};
/*
** ARMv6, ARMv7, PPC32 are known to not support hardware u64 division.
*/
#if (defined(__arm__) && !defined(__aarch64__)) || \
(defined(__ppc__) && !defined(__ppc64__))
# define SQLITE_AVOID_U64_DIVIDE 1
#endif
#ifdef SQLITE_AVOID_U64_DIVIDE
/*
** Render an unsigned 64-bit integer as text onto the end of a 2-byte
** aligned buffer that is SQLITE_U64_DIGIT+1 bytes long. The last byte
** of the buffer will be filled with a \000 byte.
**
** Return the index into the buffer of the first byte.
**
** This routine is used on platforms where u64-division is slow because
** it is not available in hardware and has to be emulated in software.
** It seeks to minimize the number of u64 divisions and use u32 divisions
** instead. It is slower on platforms that have hardware u64 division,
** but much faster on platforms that do not.
*/
static int sqlite3UInt64ToText(u64 v, char *zOut){
u32 x32, kk;
int i;
zOut[SQLITE_U64_DIGITS] = 0;
i = SQLITE_U64_DIGITS;
assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[0]) );
assert( TWO_BYTE_ALIGNMENT(zOut) );
while( (v>>32)!=0 ){
u32 y, x0, x1, y0, y1;
x32 = v % 100000000;
v = v / 100000000;
y = x32 % 10000;
x32 /= 10000;
x1 = x32 / 100;
x0 = x32 % 100;
y1 = y / 100;
y0 = y % 100;
assert( i>=8 );
i -= 8;
*(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[x1*2];
*(u16*)(&zOut[i+2]) = *(u16*)&sqlite3DigitPairs.a[x0*2];
*(u16*)(&zOut[i+4]) = *(u16*)&sqlite3DigitPairs.a[y1*2];
*(u16*)(&zOut[i+6]) = *(u16*)&sqlite3DigitPairs.a[y0*2];
}
x32 = v;
while( x32>=10 ){
kk = x32 % 100;
x32 = x32 / 100;
assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk*2]) );
assert( i>=2 );
i -= 2;
assert( TWO_BYTE_ALIGNMENT(&zOut[i]) );
*(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[kk*2];
}
if( x32 ){
assert( i>0 );
zOut[--i] = x32 + '0';
}
return i;
}
#endif /* defined(SQLITE_AVOID_U64_DIVIDE) */
/*
** Render an signed 64-bit integer as text. Store the result in zOut[] and
@@ -1005,7 +1074,7 @@ int sqlite3Int64ToText(i64 v, char *zOut){
int i;
u64 x;
union {
char a[23];
char a[SQLITE_U64_DIGITS+1];
u16 forceAlignment;
} u;
if( v>0 ){
@@ -1017,6 +1086,9 @@ int sqlite3Int64ToText(i64 v, char *zOut){
}else{
x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v;
}
#ifdef SQLITE_AVOID_U64_DIVIDE
i = sqlite3UInt64ToText(x, u.a);
#else
i = sizeof(u.a)-1;
u.a[i] = 0;
while( x>=10 ){
@@ -1030,6 +1102,7 @@ int sqlite3Int64ToText(i64 v, char *zOut){
if( x ){
u.a[--i] = x + '0';
}
#endif /* SQLITE_AVOID_U64_DIVIDE */
if( v<0 ) u.a[--i] = '-';
memcpy(zOut, &u.a[i], sizeof(u.a)-i);
return sizeof(u.a)-1-i;
@@ -1086,8 +1159,8 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
int incr;
u64 u = 0;
int neg = 0; /* assume positive */
int i;
int c = 0;
int i, j;
unsigned int c = 0;
int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
int rc; /* Baseline return code */
const char *zStart;
@@ -1115,8 +1188,8 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
}
zStart = zNum;
while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
u = u*10 + c - '0';
for(i=0; &zNum[i]<zEnd && (c=(unsigned)zNum[i]-'0')<=9; i+=incr){
u = u*10 + c;
}
testcase( i==18*incr );
testcase( i==19*incr );
@@ -1153,14 +1226,14 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
return rc;
}else{
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
c = i>19*incr ? 1 : compare2pow63(zNum, incr);
if( c<0 ){
j = i>19*incr ? 1 : compare2pow63(zNum, incr);
if( j<0 ){
/* zNum is less than 9223372036854775808 so it fits */
assert( u<=LARGEST_INT64 );
return rc;
}else{
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
if( c>0 ){
if( j>0 ){
/* zNum is greater than 9223372036854775808 so it overflows */
return 2;
}else{
@@ -1349,37 +1422,43 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
/* 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( sizeof(p->zBuf)==SQLITE_U64_DIGITS+1 );
assert( v>0 );
zBuf = p->zBuf;
#ifdef SQLITE_AVOID_U64_DIVIDE
i = sqlite3UInt64ToText(v, zBuf);
#else
i = SQLITE_U64_DIGITS;
while( v>=10 ){
int kk = (v%100)*2;
assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) );
assert( TWO_BYTE_ALIGNMENT(&zBuf[i-1]) );
*(u16*)(&zBuf[i-1]) = *(u16*)&sqlite3DigitPairs.a[kk];
assert( TWO_BYTE_ALIGNMENT(&zBuf[i]) );
assert( i-2>=0 );
*(u16*)(&zBuf[i-2]) = *(u16*)&sqlite3DigitPairs.a[kk];
i -= 2;
v /= 100;
}
if( v ){
assert( v<10 );
zBuf[i--] = v + '0';
assert( i>0 );
zBuf[--i] = v + '0';
}
assert( i>=0 && i<sizeof(p->zBuf)-1 );
n = sizeof(p->zBuf) - 1 - i; /* Total number of digits extracted */
#endif /* SQLITE_AVOID_U64_DIVIDE */
assert( i>=0 && i<SQLITE_U64_DIGITS );
n = SQLITE_U64_DIGITS - i; /* Total number of digits extracted */
assert( n>0 );
assert( n<sizeof(p->zBuf) );
testcase( n==sizeof(p->zBuf)-1 );
assert( n<=SQLITE_U64_DIGITS );
p->iDP = n + exp;
if( iRound<=0 ){
iRound = p->iDP - iRound;
if( iRound==0 && zBuf[i+1]>='5' ){
if( iRound==0 && zBuf[i]>='5' ){
iRound = 1;
zBuf[i--] = '0';
zBuf[--i] = '0';
n++;
p->iDP++;
}
}
z = &zBuf[i+1]; /* z points to the first digit */
z = &zBuf[i]; /* z points to the first digit */
if( iRound>0 && (iRound<n || n>mxRound) ){
if( iRound>mxRound ) iRound = mxRound;
if( iRound==17 ){
@@ -1406,7 +1485,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
int jj, kk;
u64 v2;
assert( z[0]!='0' );
for(jj=14; z[jj-1]=='0'; jj--){}
for(jj=13; z[jj-1]=='0'; jj--){}
v2 = z[0] - '0';
for(kk=1; kk<jj; kk++) v2 = (v2*10) + z[kk] - '0';
if( r==sqlite3Fp10Convert2(v2, exp + n - jj) ){
+3 -3
View File
@@ -357,7 +357,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str );
rc = sqlite3MemRealValueRC(pRec, &rValue);
if( rc<=0 ) return;
if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){
if( (rc&2)==0 && alsoAnInt(pRec, rValue, &pRec->u.i) ){
pRec->flags |= MEM_Int;
}else{
pRec->u.r = rValue;
@@ -475,13 +475,13 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
}
rc = sqlite3MemRealValueRC(pMem, &pMem->u.r);
if( rc<=0 ){
if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){
if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){
pMem->u.i = ix;
return MEM_Int;
}else{
return MEM_Real;
}
}else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){
}else if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){
pMem->u.i = ix;
return MEM_Int;
}
+25 -6
View File
@@ -658,9 +658,21 @@ i64 sqlite3VdbeIntValue(const Mem *pMem){
/*
** This routine implements the uncommon and slower path for
** sqlite3MemValueRC(). It is broken out into a separate
** no-inline routine so that the main routine can avoid unnecessary
** sqlite3MemRealValueRC() that has to deal with input strings
** that are not UTF8 or that are not zero-terminated. It is
** broken out into a separate no-inline routine so that the
** main sqlite3MemRealValueRC() routine can avoid unnecessary
** stack pushes.
**
** A text->float translation of pMem->z is written into *pValue.
**
** Result code invariants:
**
** rc==0 => ERROR: Input string not well-formed, or OOM
** rc<0 => Some prefix of the input is well-formed
** rc>0 => All of the input is well-formed
** (rc&2)==0 => The number is expressed as an integer, with no
** decimal point or eNNN suffix.
*/
static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath(
Mem *pMem,
@@ -706,12 +718,19 @@ static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath(
}
/*
** 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.
** Invoke sqlite3AtoF() on the text value of pMem. Write the
** translation of the text input into *pValue.
**
** The caller must ensure that pMem->db!=0 and that pMem is in
** mode MEM_Str or MEM_Blob.
**
** Result code invariants:
**
** rc==0 => ERROR: Input string not well-formed, or OOM
** rc<0 => Some prefix of the input is well-formed
** rc>0 => All of the input is well-formed
** (rc&2)==0 => The number is expressed as an integer, with no
** decimal point or eNNN suffix.
*/
int sqlite3MemRealValueRC(Mem *pMem, double *pValue){
assert( pMem->db!=0 );
@@ -883,7 +902,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
rc = sqlite3MemRealValueRC(pMem, &pMem->u.r);
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
if( ((rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<2)
|| sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r)))
){
pMem->u.i = ix;
+78 -25
View File
@@ -2,6 +2,9 @@
** Performance testing of floating-point binary-to-decimal conversion for
** SQLite versus the standard library.
**
** This module compares library sprintf() against SQLite's sqlite3_snprintf().
** To go the other direction (decimal-to-binary) see fp-speed-2.c.
**
** To compile:
**
** make sqlite3.c
@@ -10,9 +13,17 @@
**
** To run the test:
**
** time ./a.out 0 10000000 <-- standard library
** time ./a.out 1 10000000 <-- SQLite
** ./a.out 10000000
*/
#include "sqlite3.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/time.h>
#endif
static double aVal[] = {
-1.0163830486285643089e+063,
+0.0049243807391586981e-019,
@@ -117,38 +128,80 @@ static double aVal[] = {
};
#define NN (sizeof(aVal)/sizeof(aVal[0]))
#include "sqlite3.h"
#include <stdio.h>
#include <stdlib.h>
/* Return the current wall-clock time in microseconds since the
** Unix epoch (1970-01-01T00:00:00Z)
*/
static sqlite3_int64 timeOfDay(void){
#if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
sqlite3_uint64 t;
FILETIME tm;
GetSystemTimePreciseAsFileTime(&tm);
t = ((sqlite3_uint64)tm.dwHighDateTime<<32) |
(sqlite3_uint64)tm.dwLowDateTime;
t += 116444736000000000LL;
t /= 10;
return t;
#elif defined(_WIN32)
static sqlite3_vfs *clockVfs = 0;
sqlite3_int64 t;
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
if( clockVfs==0 ) return 0; /* Never actually happens */
if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
clockVfs->xCurrentTimeInt64(clockVfs, &t);
}else{
double r;
clockVfs->xCurrentTime(clockVfs, &r);
t = (sqlite3_int64)(r*86400000.0);
}
return t*1000;
#else
struct timeval sNow;
(void)gettimeofday(&sNow,0);
return ((sqlite3_int64)sNow.tv_sec)*1000000 + sNow.tv_usec;
#endif
}
int main(int argc, char **argv){
int i;
int cnt;
int fg;
static const char *zFmt = "%.17g";
sqlite3_int64 tm1, tm2;
char zBuf[1000];
if( argc!=3 ){
fprintf(stderr, "Usage: %s FLAG COUNT\n", argv[0]);
if( argc!=2 ){
printf("Usage: %s COUNT\n", argv[0]);
printf("Suggested value for COUNT is 10 million\n");
return 1;
}
cnt = atoi(argv[1]);
if( cnt<100 ){
printf("Minimum COUNT value is 100");
return 1;
}
cnt = atoi(argv[2]);
fg = atoi(argv[1]);
switch( fg % 3 ){
case 0: {
printf("Doing %d calls to C-lib sprintf()\n", cnt);
for(i=0; i<cnt; i++){
sprintf(zBuf, "%.26g", aVal[i%NN]);
}
break;
}
case 1: {
printf("Doing %d calls to sqlite3_snprintf()\n", cnt);
for(i=0; i<cnt; i++){
sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.26g", aVal[i%NN]);
}
break;
}
printf("C-library sprintf(\"%s\"): ", zFmt);
fflush(stdout);
tm1 = timeOfDay();
for(i=0; i<cnt; i++){
sprintf(zBuf, zFmt, aVal[i%NN]);
}
tm1 = timeOfDay() - tm1;
printf("%6.1f ns/call, %9.6f sec total\n", tm1*1.0e+3/(double)cnt,tm1*1.0e-6);
printf("sqlite3_snprintf(\"%s\"): ", zFmt);
tm2 = timeOfDay();
for(i=0; i<cnt; i++){
sqlite3_snprintf(sizeof(zBuf), zBuf, zFmt, aVal[i%NN]);
}
tm2 = timeOfDay() - tm2;
printf("%6.1f ns/call, %9.6f sec total\n", tm2*1.0e+3/(double)cnt,tm2*1.0e-6);
if( tm1 < tm2 ){
printf("sprintf() is about %g times faster than sqlite3_snprintf()\n",
(double)tm2/(double)tm1);
}else{
printf("sqlite3_snprintf() is about %g times faster than sprintf()\n",
(double)tm1/(double)tm2);
}
return 0;
}
+263
View File
@@ -0,0 +1,263 @@
/*
** Performance testing of floating-point decimal-to-binary conversion for
** SQLite versus the standard library.
**
** This module compares library atof() against SQLite's sqlite3AtoF().
** To go the other direction (binary-to-decimal) see fp-speed-1.c.
**
** To compile:
**
** make sqlite3.c
** gcc -Os -c sqlite3.c
** gcc -I. -Os test/fp-speed-2.c sqlite3.o -ldl -lm -lpthread
**
** To run the test:
**
** ./a.out 10000000
**
** Notes:
**
** * A first loop is run to measure the testing overhead. This
** overhead is then subtracted from the times of subsequent loops
** so that the estimates are for the calls to atof() or
** sqlite3AtoF() only.
*/
#include "sqlite3.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/time.h>
#endif
static const char *aVal[] = {
"-1.01638304862856430",
"+0.00492438073915869",
"+7.38187324073439948",
"+7.06785952192257171",
"+9.28072663198500256",
"+5.88710508619333946",
"-2.29980236212596628",
"-1.59035819249108474",
"+2.43134418168449782",
"-3.82909873289453990",
"+1.87879140627440013",
"+0.72706535604871466",
"+0.06395776979131836",
"+5.22923388793158619",
"+6.37476826728722313",
"+8.69723395383291069",
"-9.50744860515976919",
"-8.64802578453687530",
"-3.56575957757974703",
"-7.83231061797317613",
"+7.78138752741208003",
"-1.87397189283601965",
"+8.68981459155933572",
"+6.05667663598778378",
"+4.17033792171481606",
"+2.12838712887466515",
"-6.83952360838918106",
"-6.21142997639395291",
"-2.07535257426146373",
"+5.87274598039442902",
"+8.58889910620021018",
"+6.86244610313559176",
"-3.30539867566709051",
"-4.35968431527634449",
"+0.08341395201040996",
"-8.85819865489042224",
"-3.66220954287276982",
"-6.69658522970250632",
"+1.82041693474064884",
"+6.52345080386490003",
"+1.59230060182190114",
"+1.73625552916563894",
"+7.28754319768547858",
"+1.28358801059589267",
"+8.05162533203208194",
"+6.63246333993811454",
"-1.71265000702800620",
"+1.69957383415837123",
"+7.60487669237386637",
"+0.61591172354494550",
"+5.75448943554159432",
"+8.29702285926905818",
"-6.55319253601630674",
"+5.83213346061870300",
"+5.65571665095718917",
"+0.33227897084384087",
"-7.12106487766986866",
"-9.67212625267063433",
"-3.45839165713773950",
"+4.78960943232147507",
"-9.69260280400041378",
"+7.06838482753813854",
"-5.29701141821629619",
"-4.42870212009053932",
"+0.07288911557328087",
"-9.18554620258794474",
"+3.72941262341310077",
"+2.68574218827927192",
"-4.70706073336246853",
"+7.21758207682793342",
"-8.36784125342611634",
"+2.21748443042418221",
"+0.19498245886068610",
"-9.73340529556720719",
"-9.77938877669369998",
"-5.15611645874169315",
"-7.50489935777651747",
"+7.35560765686877845",
"-5.06816285755335998",
"+1.52097056420277478",
"-7.59897825350482960",
"+1.36541372033897758",
"-1.64417205546513720",
"-4.90424331961411259",
"-7.70636119616491307",
"+0.16994274609307662",
"+8.33743178495722168",
"-5.23553304804695800",
"-3.85100459421941479",
"-6.35136225443263398",
"+2.38693034844544289",
"+3.83527158716203602",
"-3.12631204931368879",
"-5.57947970025564908",
"-8.81098744795956043",
"-4.37273601202032169",
"-3.11099511896685399",
"-9.48418780317042682",
"-3.73984516683044072",
"+4.89840420089159599",
};
#define NN (sizeof(aVal)/sizeof(aVal[0]))
/* Return the current wall-clock time in microseconds since the
** Unix epoch (1970-01-01T00:00:00Z)
*/
static sqlite3_int64 timeOfDay(void){
#if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
sqlite3_uint64 t;
FILETIME tm;
GetSystemTimePreciseAsFileTime(&tm);
t = ((sqlite3_uint64)tm.dwHighDateTime<<32) |
(sqlite3_uint64)tm.dwLowDateTime;
t += 116444736000000000LL;
t /= 10;
return t;
#elif defined(_WIN32)
static sqlite3_vfs *clockVfs = 0;
sqlite3_int64 t;
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
if( clockVfs==0 ) return 0; /* Never actually happens */
if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
clockVfs->xCurrentTimeInt64(clockVfs, &t);
}else{
double r;
clockVfs->xCurrentTime(clockVfs, &r);
t = (sqlite3_int64)(r*86400000.0);
}
return t*1000;
#else
struct timeval sNow;
(void)gettimeofday(&sNow,0);
return ((sqlite3_int64)sNow.tv_sec)*1000000 + sNow.tv_usec;
#endif
}
/*
** Generate text of the i-th test floating-point literal.
*/
static int fpLiteral(int i, char *z){
int e, ex, len, ix;
ex = i%401;
e = ex - 200;
len = (i/401)%16 + 4;
ix = (i/(401*16))%NN;
memcpy(z, aVal[ix], len);
z[len++] = 'e';
if( e<0 ){
z[len++] = '-';
e = -e;
}else{
z[len++] = '+';
}
z[len++] = e/100 + '0';
z[len++] = (e/10)%10 + '0';
z[len++] = e%10 + '0';
z[len] = 0;
return ex;
}
int main(int argc, char **argv){
int i;
int cnt;
sqlite3_int64 tm[3];
double arSum[401];
char z[1000];
if( argc!=2 ){
printf("Usage: %s COUNT\n", argv[0]);
printf("Suggested value for COUNT is 10 million\n");
return 1;
}
cnt = atoi(argv[1]);
if( cnt<100 ){
printf("Minimum COUNT value is 100");
return 1;
}
printf("test-overhead: ");
fflush(stdout);
memset(arSum, 0, sizeof(arSum));
tm[2] = timeOfDay();
for(i=0; i<cnt; i++){
double r = (double)i;
int ex = fpLiteral(i,z);
arSum[ex] += r;
}
tm[2] = timeOfDay() - tm[2];
for(i=1; i<=400; i++) arSum[0] += arSum[i];
printf("%6.1f ns/test, %9.6f sec total\n", tm[2]*1e3/cnt, tm[2]*1e-6);
printf("C-lib atof(): ");
fflush(stdout);
memset(arSum, 0, sizeof(arSum));
tm[0] = timeOfDay();
for(i=0; i<cnt; i++){
int ex = fpLiteral(i,z);
arSum[ex] += atof(z);
}
tm[0] = timeOfDay() - tm[0] - tm[2];
for(i=1; i<=400; i++) arSum[0] += arSum[i];
printf("%6.1f ns/test, %9.6f sec net", tm[0]*1e3/cnt, tm[0]*1e-6);
printf(", cksum: %g\n", arSum[0]);
printf("sqlite3AtoF(): ");
fflush(stdout);
memset(arSum, 0, sizeof(arSum));
tm[1] = timeOfDay();
for(i=0; i<cnt; i++){
double r = 0.0;
int ex = fpLiteral(i,z);
sqlite3_test_control(SQLITE_TESTCTRL_ATOF, z, &r);
arSum[ex] += r;
}
tm[1] = timeOfDay() - tm[1] - tm[2];
for(i=1; i<=400; i++) arSum[0] += arSum[i];
printf("%6.1f ns/test, %9.6f sec net", tm[1]*1e3/cnt, tm[1]*1e-6);
printf(", cksum: %g\n", arSum[0]);
if( tm[0] < tm[1] ){
printf("atof() is about %g times faster than sqlite3AtoF()\n",
(double)tm[1]/(double)tm[0]);
}else{
printf("sqlite3AtoF() is about %g times faster than atof()\n",
(double)tm[0]/(double)tm[1]);
}
return 0;
}
+111 -1
View File
@@ -11,7 +11,21 @@
#
#***********************************************************************
#
# Floating-point to text conversions
# Floating-point <-> text conversions
#
# FAILURES IN THIS SCRIPT ARE NOT NECESSARILY THE FAULT OF SQLITE.
#
# Some of the tests below use the system strtod() function as
# an oracle of truth. These tests assume that the system strtod()
# is always correct. That is the case for Win11, Macs, most Linux
# boxes and so forth. But it possible to find a machine for which
# is not true. (One example, is Macs from around 2005.) On such
# machines, some of these tests might fail.
#
# So, in other words, a failure in any of the tests below does not
# necessarily mean that SQLite is wrong. It might mean that the
# strtod() function in the standard library of the machine on which
# the test is running is wrong.
#
# Verify that binary64 -> text -> binary64 conversions round-trip
@@ -74,3 +88,99 @@ WITH
fp(r) AS (SELECT ieee754_from_int(n) FROM fpint)
SELECT r FROM fp WHERE r<>strtod(r||'');
.check ''
# Comparing SQLite's text-to-double conversion against strtod()
# for 200,000 random floating-point literals.
#
.param set $N 50_000
.testcase 300
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
VALUES(1,'1234.5789')
UNION ALL
SELECT n+1, format('%.*s.%.*se%+d',
(n%3)+1,
random()%1000,
abs(random()%16)+1,
abs(random()),
random()%308)
FROM fp WHERE n<$N
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
.check ''
.testcase 301
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
VALUES(1,'1234.5789')
UNION ALL
SELECT n+1, format('%.*s.%.*s',
(n%3)+1,
random()%1000,
abs(random()%16)+1,
abs(random()))
FROM fp WHERE n<$N
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
.check ''
.testcase 302
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
VALUES(1,'1234.5789')
UNION ALL
SELECT n+1, format('%.*s.%.*s',
abs(random()%7)+1,
random(),
abs(random()%10)+1,
abs(random()))
FROM fp WHERE n<$N
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
.check ''
.testcase 303
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
VALUES(1,'1234.5789')
UNION ALL
SELECT n+1, format('%de%+03d',
random(),
random()%308)
FROM fp WHERE n<$N
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
.check ''
# Another 500,000 comparisions between SQLite and strtod() from completely
# random floating point literals.
#
.testcase 310
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
UNION ALL
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
FROM fp WHERE n<$N*2
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
.check ''
.testcase 311
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
UNION ALL
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
FROM fp WHERE n<$N*2
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
.check ''
.testcase 312
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
UNION ALL
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
FROM fp WHERE n<$N*2
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
.check ''
.testcase 313
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
UNION ALL
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
FROM fp WHERE n<$N*2
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
.check ''
.testcase 314
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
UNION ALL
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
FROM fp WHERE n<$N*2
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
.check ''
+1
View File
@@ -276,6 +276,7 @@ set boolean_defnil_options {
SQLITE_SECURE_DELETE
SQLITE_SMALL_STACK
SQLITE_SOUNDEX
SQLITE_STRICT_SUBTYPE
SQLITE_SUBSTR_COMPATIBILITY
SQLITE_TCL
SQLITE_TEST