Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0cb576f306 | |||
| 6d27844bbe | |||
| 03f13d77a5 | |||
| 445fbc61c8 | |||
| eb0cb3f53b | |||
| 5239e69fb1 | |||
| 20d93e16d7 | |||
| c409eaaf14 | |||
| 2e01416762 | |||
| ff8a0895d6 | |||
| a2f78f665c | |||
| c4cedd7ffe | |||
| 00c6eca32c | |||
| be2242d2ee | |||
| 2dd3b4a646 | |||
| 4570aeb7bc | |||
| 1283969f26 | |||
| 772ea2f01c | |||
| d4af925e34 | |||
| 61d3bc8ddc | |||
| f9a3b78561 | |||
| f855727e45 | |||
| 3d58f022a8 | |||
| 7e9eaf3c1f | |||
| 0944b3efad | |||
| f3f194c385 | |||
| 183a73c352 | |||
| 53197b7940 | |||
| f1f1784f4b | |||
| 814f592cf0 | |||
| 9b805c6248 | |||
| 3c2ccd2903 | |||
| 7bf4d708dc | |||
| 5239e821e8 | |||
| a217a4af09 | |||
| 3e3c31ff0e | |||
| dc32016ee0 | |||
| 5700f8c471 |
@@ -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
|
||||
|
||||
@@ -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(){
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -1,2 +1,2 @@
|
||||
branch atof
|
||||
tag atof
|
||||
branch direct-printf
|
||||
tag direct-printf
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
db370f0f628895279a1c1db79ba7428cb4e31b56cafc191859c2f1a5a924435b
|
||||
afe7e9fd1c476c7cdcefab0adf0191a8dc3283811f72a685fff3eb6539b72dcc
|
||||
|
||||
+2
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+7
-29
@@ -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→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}
|
||||
|
||||
@@ -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
@@ -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*);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 ''
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user