Compare commits

..

90 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
drh 80b88b2482 Proposed new API routine: sqlite3_atof().
FossilOrigin-Name: db370f0f628895279a1c1db79ba7428cb4e31b56cafc191859c2f1a5a924435b
2026-03-22 20:52:23 +00:00
drh 8e7f122c7d Performance enhancements and improved documentation for sqlite3AtoF().
FossilOrigin-Name: 62f011509600ab8cda28888ebd32e5faa4e865702755bc32dee7a12bf2f4425d
2026-03-22 18:26:43 +00:00
drh dfd31e158c Additional performance improvements in sqlite3AtoF(). Also update the
header comments.

FossilOrigin-Name: 8c3a1b450d6d5778004b9fb0e92b4f3f90d3e06ff87276370d01a45b7d607d23
2026-03-22 17:50:48 +00:00
drh cc19c1dafd Further simplification and performance improvement
FossilOrigin-Name: 6c3dc2430adef061b458b6d9159628bb8debfd4d63876d5d5e7493afb799d97f
2026-03-22 02:51:18 +00:00
drh 99571bf3c3 Performance improvements in the floating-point number parser.
FossilOrigin-Name: aea648f3668219a2539160eb68c77ddd06aa8eac235c1326fe7b1547288b11ee
2026-03-22 02:26:38 +00:00
drh 3c1f727603 Because version 3.52.0 was withdrawn, that means QRF has never been
officially released.  Hence the new nMultiInsert field of the spec
can be moved out of the extensions area and into the main part of the
spec, and the version number can drop back from 2 to 1.

FossilOrigin-Name: cf19982241afb17e3db4148b8257f6737141935a291c340ab085c42ed946af1a
2026-03-21 19:49:38 +00:00
drh d9e70f2b90 Try to fix harmless compiler warnings from legacy C compilers in the CLI.
FossilOrigin-Name: 8e1d0c4eac303cd0834449f4792605c0ed983db1f360af42300f0048dadbbef8
2026-03-21 13:21:41 +00:00
drh 4c78799bb0 Add support for REINDEX EXPRESSIONS
FossilOrigin-Name: d56954146ce5eccd63b65242abe2e6556dbceda39a58eab39f5884884afea337
2026-03-21 13:05:54 +00:00
drh 958b6a52e5 Undo "indices"→"indexes" changes in comments, to avoid diff clutter.
Fix a couple of unreachable branches.

FossilOrigin-Name: 0042ff9afd00eca0a837e9bbe57540ff2810fcd58b4f7e3f4e3b83aad5699757
2026-03-21 12:55:57 +00:00
drh f62cff6a9e Fix harmless compiler warnings in the csv.c.
FossilOrigin-Name: 6ac701f89e2ac8dfd18d041eb8c36a0c2b9fedc5618d3a95be794aecce5c59cf
2026-03-20 20:35:21 +00:00
drh f163bfba4e If the argument to REINDEX is EXPRESSIONS (with no schema prefix) then it
updates both expression indexes, and any indexes named "expressions" or
all indexes of any tables name "expressions".

FossilOrigin-Name: 72650dc152279a6da1937f377b1e16b79f4cd664841e12222dc5459838408d22
2026-03-20 19:30:58 +00:00
drh b0a4b69b95 If there are not collating sequences, tables, or indexes named "EXPRESSIONS"
then the "REINDEX EXPRESSIONS" command rebuilds all expression indexes.

FossilOrigin-Name: df5c5aa26758e0dc00a9ccba29eac83071176d257e121207e0a13c54833b18c0
2026-03-20 14:37:39 +00:00
dan bd580270a5 Ensure that collation sequences on non-PK columns of a WITHOUT ROWID table are used correctly when they are part of a row value comparison. Fix for forum post [forum:7a308e933d | 7a308e933d].
FossilOrigin-Name: 078b3162d0d3d3035f4d3ad88664066d99c218a731ac481b9f1172529e26e4eb
2026-03-20 11:35:15 +00:00
drh de4ef2dc70 Ensure that sqlite3RCStr values returned by json_group_array() and
json_group_object() are zero-terminated.

FossilOrigin-Name: 88a931ea2ae734478928c2a6021b00b0f2be490328260630e176cf3cc7111472
2026-03-19 23:49:29 +00:00
dan 0cb7603d4c Update fts5 scan costs to take into account that a prefix query combined with a rowid equality constraint is still quite expensive.
FossilOrigin-Name: 539769b63e4044018be2993894b1962df6a6ae58636682b7fb7a2dd5aaf4075c
2026-03-19 17:56:10 +00:00
drh 28cfb1e4a7 Restructure some internal subroutine signatures for improved
performance of affinity type conversions.

FossilOrigin-Name: 2bc6ce87b39c6ae324c3641c5af60e000df7d7c6d5fd2dd1a318c94cbb4aef84
2026-03-19 17:08:08 +00:00
drh 915a55444b Use compiler intrinsics to improve the performance of
sqlite3Multiply160().

FossilOrigin-Name: 3c64f31392328f51e205fde52f19cf70c193e90897ccb7e93c685bad4f342cac
2026-03-19 13:40:40 +00:00
dan 58012b85b0 Do not assume that a recursive CTE emits rows in ORDER BY order. Fix for forum post [forum:deb1eadf4d677bd5 | deb1eadf4d677bd5].
FossilOrigin-Name: cadb6cdd32c3c9abd7e063f25acd39dddc9ff764a16019ffd5aa11063175326f
2026-03-19 10:51:40 +00:00
dan a2d80200b1 Reverse the if() condition added by this branch.
FossilOrigin-Name: a9a0dd521c7c24b0c8b22abf2a131028f4dc9cd233678dc1f658da81a4a70e4b
2026-03-19 10:39:24 +00:00
drh 08eb5e9e51 Continue enforcing the legacy declaration-before-statement C-language rule,
since some downstream still uses it.

FossilOrigin-Name: 5c237f1f863a32cf229010d2024d0d1e76a07a4d8b9492b26503b959f1c32485
2026-03-18 22:31:56 +00:00
drh b425ebdd4f Add logic to silently and transparently deal with stale expression index
values when deleting or update a table row, instead of reporting a corrupt
database.  Enhance PRAGMA integrity_check to identify non-serious
stale expression index entries as such, rather than proclaiming that the
indexes is broken.

FossilOrigin-Name: 0ed040128b7ebb5be438b1841607ed9c525b271cac81021bc356cf573d1cd516
2026-03-18 20:17:48 +00:00
drh ac53ce155a Minor optimization to error message generation in integrity_check.
FossilOrigin-Name: e0fa7c500052af9d36cb2d232131ef93361403187f4a60f53279b102c7a95860
2026-03-18 18:14:14 +00:00
drh 5a6772eaa5 Comment improvements. Ensure that tests in shellB.test that require
virtual tables do not run when compiling without virtual table support.

FossilOrigin-Name: a270c6cc0eea8a8a2cf1ce30d724b2f12b11a1c343cd8520bd7843f4e62878f8
2026-03-18 17:16:18 +00:00
drh acc213b42f Improve the integrity-check error message when floating point index values
are off by one or two ULPs.  Change the name of the eiib1.test test module
to expridx1.test.

FossilOrigin-Name: 4e996c183ea8d270b4448b471d4d032e13cef89f537674599d1e7c367cc2d0f8
2026-03-18 15:51:15 +00:00
dan 345bc91673 Do not assume that a recursive CTE emits rows in ORDER BY order. Forum [forum:deb1eadf4d677bd5 | deb1eadf4d677bd5].
FossilOrigin-Name: 971aa34b3fd86ba30fe170886d9f83c17159b1638c4bd4fb6cdef79b1c9a88e2
2026-03-18 15:40:26 +00:00
drh 1539575e05 Take care not to overread the record header when decoding the record
in vdbeIsMatchingIndexKey().

FossilOrigin-Name: 3a275b5848767b61011b9d1d3d1a62328a80906386375d1b1e13fd92b6983e05
2026-03-18 14:47:20 +00:00
dan f0648f6924 Pad the allocation in vdbeIsMatchingKey() a little to avoid undefined behaviour if the record is corrupt and getVarint32() reads past the end of it.
FossilOrigin-Name: 9b0671a4f58098948d530f5e238b483a0e9f1309021aff0d6b5ea90e6c8f4e7b
2026-03-18 14:01:21 +00:00
drh 15a3b2d4e1 Adjust the fix at [f7389cdb129d3386] so that integrity_check output still
appears prior to the SQLITE_CORRUPT return.

FossilOrigin-Name: efd9a7a6c862f778da9cd74e38f674e5d1094aa1c566ea3e68553e83f59502d3
2026-03-18 13:49:06 +00:00
drh 765ff2189a Simplification to the logic that decides whether or not an index
field matches when floating point values are close but not exact.

FossilOrigin-Name: 3897017c0e871c676d44786a6f11205fd4b7a947d9d1359109037a123eda6b9b
2026-03-18 12:36:01 +00:00
drh 3ca448dee5 Fix harmless signed/unsigned compiler warnings.
FossilOrigin-Name: aa211fa1d49b6734913e957f9e4b9825709a1493d275f7dfaf9123dc8c7232dc
2026-03-18 11:15:57 +00:00
dan 3f2d7d4aaa Fix some cases where integrity-check would fail to identify real values in indexed expressions that are with 2 ULPs of each other.
FossilOrigin-Name: 40c5966f7b784f181365c81fc559aee9463c374ee56677cf6e0aecaed39d2b28
2026-03-18 11:06:10 +00:00
drh 00989bcd9f Fix harmless "unused variable" compiler warning.
FossilOrigin-Name: 3380eb1ea71d6bf8325dbe49f4bac7623b3b6193f3b36dedd9411188cfc80b89
2026-03-18 11:04:15 +00:00
dan 362b9cecdb Modify integrity-check so that it is only tolerant of very small distortions of real values in indexed expression fields.
FossilOrigin-Name: 82e6de835bde306778425d18ab1a15ae80fdf01af7f577ead89c09f9d53b5b2f
2026-03-17 21:17:42 +00:00
drh f4e6483cda Improved error handling in OP_IFindKey and in vdbeIsMatchingIndexKey().
FossilOrigin-Name: f7389cdb129d3386b7dfb8acacf84816cf10864c6800a9bd9a61c6364b850a31
2026-03-17 18:55:24 +00:00
dan ae2820ab28 When integrity-check finds a missing index entry, search a small range (currently 10) of entries around the missing key for an entry that matches all non-virtual and non-expression fields.
FossilOrigin-Name: 978cedcbd33165dadc7dffc118bde359eff6751ec9842230880cb827d9f7845f
2026-03-17 17:05:45 +00:00
drh bdbad43f33 Do not run index healing on an invalid cursor.
FossilOrigin-Name: eb6403f02c113f58030c0b4143d91b6327ee21dcb324d3f235c2bf6bf3d6577c
2026-03-17 13:13:02 +00:00
drh d6965b1dab Merge recent trunk enhancements into the idxdelete-tolerance branch
FossilOrigin-Name: 9d84fdb7819a9850919e2c1977811bcf514b3baad29eb8cc9fc78451d500c8b6
2026-03-17 12:16:47 +00:00
drh ccf2babd42 Fix an assertion fault that could occur in RTree when given a corrupt
database.

FossilOrigin-Name: ed29fe973e6cbf291eff6fc582aeb34556ea4f8df105ec61b361e4cdda017e62
2026-03-17 12:07:49 +00:00
dan 2953e950c8 Fix display of P4_INDEX values in EXPLAIN output.
FossilOrigin-Name: e717017f0213441da2ef8a9e1f1e88ebfdefa26fc4773711968417c0bd6ebe5f
2026-03-17 11:26:57 +00:00
dan 8736da94bc Fix compiler warning an inefficiency introduced by previous commit.
FossilOrigin-Name: 03058d73d3a88ab30e874b4231cc5b263b874a577f8bf5189a452d7376e25a47
2026-03-17 11:22:51 +00:00
drh b302c4d39c Typo fix in sqlite3Multiply128(): The datatype should be *unsigned*.
FossilOrigin-Name: b459f6ff63325f71d4056dad2ebb536e0d414c973f3c6e167e8f67e94e6f0e2d
2026-03-17 11:19:16 +00:00
dan 022f2f96bc Change the sqlite3VdbeFindDeleteKey() routine so that all index fields that are not expressions or virtual columns must match the table for the delete to succeed.
FossilOrigin-Name: eccd9fcfa7e34ddcdeb671544c6afac7aa0d4665c5e1df7c8e53c41387ed0386
2026-03-17 11:17:54 +00:00
drh 5a73386511 Fix a harmless compiler warning.
FossilOrigin-Name: aa23d6cc69471eacb3fb0d789c34169e047e4a09a50beb430eb8e8e63b5bce78
2026-03-17 10:19:11 +00:00
drh 1c1f7c259e Merge trunk enhancements into the idxdelete-tolerance branch
FossilOrigin-Name: 5f5ab3eb3618b6a2799355df50bfdf94121161f7cadba6253963036d9f284f08
2026-03-17 09:53:02 +00:00
drh cf93c51790 Enhance text→float conversions for exact rounding in all cases.
FossilOrigin-Name: 704ddfd0df57c2b137af88264df20a540e3f8f114a58ae5e31b40ab8259bb63e
2026-03-17 09:49:07 +00:00
dan 4cc023bd01 Remove a couple of unused variables.
FossilOrigin-Name: f66cb3dc275d3f31e57576466e697a6c7c5179144babab08d75b624e9846ecc3
2026-03-16 19:14:07 +00:00
dan f6308e68ff Further tests for the code on this branch.
FossilOrigin-Name: f928a38091977268aa6a096104797158883ed89b9e026b4e4b98b9b5da967de1
2026-03-16 16:44:14 +00:00
dan 066a5bcdd7 If OP_IdxDelete cannot find an index entry to delete, first search 10 entries in either direction of where the entry should be in the index. If that fails, search the entire index for an entry with matching PK fields.
FossilOrigin-Name: 2cb9f4e4178549144acd82e317a1646e71c9281ac9fc4aa26bf129f1068ded45
2026-03-16 16:21:43 +00:00
dan b2006499c7 Fix a problem with the find-delete-key method on this branch.
FossilOrigin-Name: 6f49b5ecad5d924999d045a1ade93d95e731182be1781aefa5bc763b6202e9c3
2026-03-16 15:49:58 +00:00
drh bf057073c3 Rework the ".indexes" command of the CLI. (1) The PATTERN now matches
the name of the index itself, not the name of the table containing
the index, thus making the pattern actually useful.  (2)  System-generated
indexes (for UNIQUE constraints and similar) are omitted unless
the -a|-all or --sys options are added.  (3) The --expr option causes
only expression indexes to be shown.

FossilOrigin-Name: 13e2cad810bfd59a9e18eb38bda1241715b76756ffec7d617e9ce99b89f19284
2026-03-16 15:35:41 +00:00
dan d21413adcb Make OP_IdxDelete tolerant of small variations in index key values.
FossilOrigin-Name: c4b0081f08bd0458dbcf269b43a4051941eec8067393aa8e6810d4b8422ce44a
2026-03-16 15:16:13 +00:00
dan 061459bf76 Properly fix temp triggers created as part of FK processing to their schemas. Otherwise they may become confused by similarly named child tables in other attached databases. Fix for forum post [forum:636bd0180a | 636bd0180a].
FossilOrigin-Name: 80bc5bc07e221f837c28066f0a438f11c8ab6be4c8ba93615439eb1667967003
2026-03-16 11:14:26 +00:00
49 changed files with 3013 additions and 1342 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
+45 -20
View File
@@ -517,7 +517,7 @@ static void fts5SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
if( sqlite3_libversion_number()>=3008002 )
#endif
{
pIdxInfo->estimatedRows = nRow;
pIdxInfo->estimatedRows = MAX(1, nRow);
}
#endif
}
@@ -586,19 +586,30 @@ static int fts5UsePatternMatch(
** a) If a MATCH operator is present, the cost depends on the other
** constraints also present. As follows:
**
** * No other constraints: cost=1000.0
** * One rowid range constraint: cost=750.0
** * Both rowid range constraints: cost=500.0
** * An == rowid constraint: cost=100.0
** * No other constraints: cost=50000.0
** * One rowid range constraint: cost=37500.0
** * Both rowid range constraints: cost=30000.0
** * An == rowid constraint: cost=25000.0
**
** b) Otherwise, if there is no MATCH:
**
** * No other constraints: cost=1000000.0
** * One rowid range constraint: cost=750000.0
** * Both rowid range constraints: cost=250000.0
** * An == rowid constraint: cost=10.0
** * No other constraints: cost=3000000.0
** * One rowid range constraints: cost=2250000.0
** * Both rowid range constraint: cost=750000.0
** * An == rowid constraint: cost=25.0
**
** Costs are not modified by the ORDER BY clause.
**
** The ratios used in case (a) are based on informal results obtained from
** the tool/fts5cost.tcl script. The "MATCH and ==" combination has the
** cost set quite high because the query may be a prefix query. Unless
** there is a prefix index, prefix queries with rowid constraints are much
** more expensive than non-prefix queries with rowid constraints.
**
** The estimated rows returned is set to the cost/40. For simple queries,
** experimental results show that cost/4 might be about right. But for
** more complex queries that use multiple terms the number of rows might
** be far fewer than this. So we compromise and use cost/40.
*/
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
Fts5Table *pTab = (Fts5Table*)pVTab;
@@ -724,21 +735,35 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
/* Calculate the estimated cost based on the flags set in idxFlags. */
if( bSeenEq ){
pInfo->estimatedCost = nSeenMatch ? 1000.0 : 25.0;
fts5SetUniqueFlag(pInfo);
pInfo->estimatedCost = nSeenMatch ? 25000.0 : 25.0;
fts5SetEstimatedRows(pInfo, 1);
fts5SetUniqueFlag(pInfo);
}else{
if( bSeenLt && bSeenGt ){
pInfo->estimatedCost = nSeenMatch ? 5000.0 : 750000.0;
}else if( bSeenLt || bSeenGt ){
pInfo->estimatedCost = nSeenMatch ? 7500.0 : 2250000.0;
i64 nEstRows;
if( nSeenMatch ){
if( bSeenLt && bSeenGt ){
pInfo->estimatedCost = 50000.0;
}else if( bSeenLt || bSeenGt ){
pInfo->estimatedCost = 37500.0;
}else{
pInfo->estimatedCost = 50000.0;
}
nEstRows = (i64)(pInfo->estimatedCost / 40.0);
for(i=1; i<nSeenMatch; i++){
pInfo->estimatedCost *= 2.5;
nEstRows = nEstRows / 2;
}
}else{
pInfo->estimatedCost = nSeenMatch ? 10000.0 : 3000000.0;
if( bSeenLt && bSeenGt ){
pInfo->estimatedCost = 750000.0;
}else if( bSeenLt || bSeenGt ){
pInfo->estimatedCost = 2250000.0;
}else{
pInfo->estimatedCost = 3000000.0;
}
nEstRows = (i64)(pInfo->estimatedCost / 4.0);
}
for(i=1; i<nSeenMatch; i++){
pInfo->estimatedCost *= 0.4;
}
fts5SetEstimatedRows(pInfo, (i64)(pInfo->estimatedCost / 4.0));
fts5SetEstimatedRows(pInfo, nEstRows);
}
pInfo->idxNum = idxFlags;
+9
View File
@@ -65,5 +65,14 @@ do_eqp_test 1.4 {
`--SCAN vt VIRTUAL TABLE INDEX 0:=
}
do_eqp_test 1.5 {
SELECT * FROM vt, t1
WHERE vt.rowid = t1.rowid AND vt MATCH ? AND b = ?
} {
QUERY PLAN
|--SCAN vt VIRTUAL TABLE INDEX 0:M1
`--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?)
}
finish_test
+153
View File
@@ -0,0 +1,153 @@
#
# 2026 March 20
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#--------------------------------------------------------------------------
#
# This script extracts the documentation for the API used by fts5 auxiliary
# functions from header file fts5.h. It outputs html text on stdout that
# is included in the documentation on the web.
#
sqlite3 db fts5cost.db
# Create an IPK table with 1,000,000 entries. Short records.
#
set res [list [catch { db eval {SELECT count(*) FROM t1} } msg] $msg]
if {$res!="0 1000000"} {
db eval {
PRAGMA mmap_size = 1000000000; -- 1GB
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
)
INSERT INTO t1 SELECT i, hex(randomblob(8)) FROM s;
}
}
# Create an FTS5 table with 1,000,000 entries. Each row contains a single
# column containing a document of 100 terms chosen pseudo-randomly from
# a vocabularly of 2000.
set res [list [catch { db eval {SELECT count(*) FROM f1} } msg] $msg]
if {$res!="0 1000000"} {
set nVocab 2000
set nTerm 100
db eval {
BEGIN;
DROP TABLE IF EXISTS vocab1;
CREATE TABLE vocab1(w);
}
for {set ii 0} {$ii<$nVocab} {incr ii} {
set word [format %06x [expr {int(abs(rand()) * 0xFFFFFF)}]]
db eval { INSERT INTO vocab1 VALUES($word) }
lappend lVocab $word
}
db func doc doc
proc doc {} {
for {set ii 0} {$ii<$::nTerm} {incr ii} {
lappend ret [lindex $::lVocab [expr int(abs(rand())*$::nVocab)]]
}
set ret
}
db eval {
DROP TABLE IF EXISTS f1;
CREATE VIRTUAL TABLE f1 USING fts5(x);
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1_000_000
)
INSERT INTO f1(rowid, x) SELECT i, doc() FROM s;
COMMIT;
}
} else {
set lVocab [db eval { SELECT * FROM vocab1 }]
set nVocab [llength $lVocab]
}
proc rowid_query {n} {
set rowid 654
for {set ii 0} {$ii<$n} {incr ii} {
db eval { SELECT b FROM t1 WHERE a = $rowid }
set rowid [expr {($rowid + 7717) % 1000000}]
}
}
proc rowid_query_fts {n} {
set rowid 654
for {set ii 0} {$ii<$n} {incr ii} {
db eval { SELECT * FROM f1 WHERE rowid = $rowid }
set rowid [expr {($rowid + 7717) % 1000000}]
}
}
proc match_query_fts {n} {
set idx 654
for {set ii 0} {$ii<$n} {incr ii} {
set match [lrange $::lVocab $idx $idx+1]
db eval { SELECT * FROM f1($match) }
set idx [expr {($idx + 7717) % $::nVocab}]
}
}
proc prefix_query_fts {n} {
set idx 654
for {set ii 0} {$ii<$n} {incr ii} {
set match "[lindex $::lVocab $idx]*"
db eval { SELECT * FROM f1($match) }
set idx [expr {($idx + 7717) % $::nVocab}]
}
}
proc match_rowid_query_fts {n} {
set idx 654
for {set ii 0} {$ii<$n} {incr ii} {
set match "[lindex $::lVocab $idx]"
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
set idx [expr {($idx + 7717) % $::nVocab}]
}
}
proc prefix_rowid_query_fts {n} {
set idx 654
for {set ii 0} {$ii<$n} {incr ii} {
set match "[lindex $::lVocab $idx]*"
db eval { SELECT * FROM f1($match) WHERE rowid=500000 }
set idx [expr {($idx + 7717) % $::nVocab}]
}
}
proc mytime {cmd div} {
set tm [time $cmd]
expr {[lindex $tm 0] / $div}
}
#set us [mytime { match_rowid_query_fts 1000 } 1000]
#puts "1000 match/rowid queries on fts5 table: ${us} per query"
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
set us [mytime { match_query_fts 10 } 10]
puts "10 match queries on fts5 table: ${us} per query"
set us [mytime { prefix_query_fts 10 } 10]
puts "10 prefix queries on fts5 table: ${us} per query"
set us [mytime { prefix_rowid_query_fts 1000 } 1000]
puts "1000 prefix/rowid queries on fts5 table: ${us} per query"
set us [mytime { rowid_query 10000 } 10000]
puts "10000 by-rowid queries on normal table: ${us} per query"
set us [mytime { rowid_query_fts 10000 } 10000]
puts "10000 by-rowid queries on fts5 table: ${us} per query"
+7 -6
View File
@@ -64,6 +64,7 @@ SQLITE_EXTENSION_INIT1
#ifndef SQLITEINT_H
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
#endif
/* Max size of the error message in a CsvReader */
@@ -221,7 +222,7 @@ static char *csv_read_one_field(CsvReader *p){
}
if( c=='"' ){
int pc, ppc;
int startLine = p->nLine;
i64 startLine = p->nLine;
pc = ppc = 0;
while( 1 ){
c = csv_getc(p);
@@ -325,7 +326,7 @@ typedef struct CsvCursor {
sqlite3_vtab_cursor base; /* Base class. Must be first */
CsvReader rdr; /* The CsvReader object */
char **azVal; /* Value of the current row */
int *aLen; /* Length of each entry */
i64 *aLen; /* Length of each entry */
sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */
} CsvCursor;
@@ -497,7 +498,7 @@ static int csvtabConnect(
CsvTable *pNew = 0; /* The CsvTable object to construct */
int bHeader = -1; /* header= flags. -1 means not seen yet */
int rc = SQLITE_OK; /* Result code from this routine */
int i, j; /* Loop counters */
u64 i, j; /* Loop counters */
#ifdef SQLITE_TEST
int tstFlags = 0; /* Value for testflags=N parameter */
#endif
@@ -516,7 +517,7 @@ static int csvtabConnect(
assert( sizeof(azPValue)==sizeof(azParam) );
memset(&sRdr, 0, sizeof(sRdr));
memset(azPValue, 0, sizeof(azPValue));
for(i=3; i<argc; i++){
for(i=3; i<(u64)argc; i++){
const char *z = argv[i];
const char *zValue;
for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){
@@ -709,12 +710,12 @@ static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
CsvTable *pTab = (CsvTable*)p;
CsvCursor *pCur;
size_t nByte;
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol;
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(i64))*pTab->nCol;
pCur = sqlite3_malloc64( nByte );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, nByte);
pCur->azVal = (char**)&pCur[1];
pCur->aLen = (int*)&pCur->azVal[pTab->nCol];
pCur->aLen = (i64*)&pCur->azVal[pTab->nCol];
*ppCursor = &pCur->base;
if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){
csv_xfer_error(pTab, &pCur->rdr);
+1 -1
View File
@@ -828,7 +828,6 @@ static void re_bytecode_func(
int i;
int n;
char *z;
(void)argc;
static const char *ReOpName[] = {
"EOF",
"MATCH",
@@ -851,6 +850,7 @@ static void re_bytecode_func(
"ATSTART",
};
(void)argc;
zPattern = (const char*)sqlite3_value_text(argv[0]);
if( zPattern==0 ) return;
zErr = re_compile(&pRe, zPattern, re_maxnfa(re_maxlen(context)),
+22 -9
View File
@@ -115,6 +115,7 @@ struct sqlite3_qrf_spec {
short int nScreenWidth; /* Maximum overall table width */
short int nLineLimit; /* Maximum number of lines for any row */
short int nTitleLimit; /* Maximum number of characters in a title */
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
int nCharLimit; /* Maximum number of characters in a cell */
int nWidth; /* Number of entries in aWidth[] */
int nAlign; /* Number of entries in aAlignment[] */
@@ -381,7 +382,16 @@ can improve readability. The nTitleLimit setting currently only
works for **Box**, **Column**, **Line**, **Markdown**, and **Table**
styles, though that limitation might change in future releases.
### 2.9 Word Wrapping In Columnar Styles (nWrap, bWordWrap)
### 2.9 Multiple Tuples Per INSERT In QRF_STYLE_Insert (nMultiInsert)
If the sqlite3_qrf_spec.nMultiInsert value is positive, then the
QRF_STYLE_Insert output mode will generate multiple tuples in
each INSERT statement until the total number of bytes in the
statement exceeds nMultiInsert. A value of a few thousand is
recommended here, in order to generate SQL output that is parsed
and inserted at maximum speed by SQLite.
### 2.10 Word Wrapping In Columnar Styles (nWrap, bWordWrap)
When using columnar formatting modes (QRF_STYLE_Box, QRF_STYLE_Column,
QRF_STYLE_Markdown, or QRF_STYLE_Table), the formatter attempts to limit
@@ -400,7 +410,7 @@ anywhere, including in the middle of a word.
For narrow columns and wide words, it might sometimes be necessary to split
a column in the middle of a word, even when bWordWrap is QRF_Yes.
### 2.10 Helping The Output To Fit On The Terminal (nScreenWidth)
### 2.11 Helping The Output To Fit On The Terminal (nScreenWidth)
The sqlite3_qrf_spec.nScreenWidth field can be set the number of
characters that will fit on one line on the viewer output device.
@@ -420,7 +430,7 @@ The nScreenWidth field currently only makes a difference in
columnar styles (**Box**, **Column**, **Markdown**, and **Table**)
and in the **Line** style.
### 2.11 Individual Column Width (nWidth and aWidth)
### 2.12 Individual Column Width (nWidth and aWidth)
The sqlite3_qrf_spec.aWidth field is a pointer to an array of
signed 16-bit integers that control the width of individual columns
@@ -458,7 +468,7 @@ Again, negative values for aWidth\[\] entries are supported for
backwards compatibility only, and are not recommended for new
applications.
### 2.12 Alignment (nAlignment, aAlignment, eDfltAlign, eTitleAlign)
### 2.13 Alignment (nAlignment, aAlignment, eDfltAlign, eTitleAlign)
Some cells in a display table might contain a lot of text and thus
be wide, or they might contain newline characters or be wrapped by
@@ -537,7 +547,7 @@ specify a vertical alignment, then values are top-aligned
The vertical alignment settings are currently ignored and
the vertical alignment is always QRF_ALIGN_Top.*
### 2.13 Row and Column Separator Strings
### 2.14 Row and Column Separator Strings
The sqlite3_qrf_spec.zColumnSep and sqlite3_qrf_spec.zRowSep strings
are alternative column and row separator character sequences. If not
@@ -545,18 +555,18 @@ specified (if these pointers are left as NULL) then appropriate defaults
are used. Some output styles have hard-coded column and row separators
and these settings are ignored for those styles.
### 2.14 The Output Table Name
### 2.15 The Output Table Name
The sqlite3_qrf_spec.zTableName value is the name of the output table
when eStyle is QRF_STYLE_Insert.
### 2.15 The Rendering Of NULL (zNull)
### 2.16 The Rendering Of NULL (zNull)
If a value is NULL then show the NULL using the string
found in sqlite3_qrf_spec.zNull. If zNull is itself a NULL pointer
then NULL values are rendered as an empty string.
### 2.16 Optional Value Rendering Callback
### 2.17 Optional Value Rendering Callback
If the sqlite3_qrf_spec.xRender field is not NULL, then each
sqlite3_value coming out of the query is first passed to the
@@ -709,7 +719,10 @@ the `<TABLE>..</TABLE>` around the outside.
The **Insert** style generates a series of SQL "INSERT" statements
that will inserts the data that is output into a table whose name is defined
by the zTableName field of `sqlite3_qrf_spec`. If zTableName is NULL,
then a substitute name is used.
then a substitute name is used. If nMultiInsert is positive, then the
output will add multiple rows to each INSERT statement until the size
of the INSERT statement exceeds nMultiInsert bytes before starting
a new INSERT statement.
The **Json** and **JObject** styles generates JSON text for the query result.
The **Json** style produces a JSON array of structures with one
+2 -2
View File
@@ -2564,7 +2564,7 @@ static void qrfOneSimpleRow(Qrf *p){
break;
}
case QRF_STYLE_Insert: {
unsigned int mxIns = p->spec.iVersion>=2 ? p->spec.nMultiInsert : 0;
unsigned int mxIns = p->spec.nMultiInsert;
int szStart = sqlite3_str_length(p->pOut);
if( p->u.nIns==0 || p->u.nIns>=mxIns ){
if( p->u.nIns ){
@@ -2712,7 +2712,7 @@ static void qrfInitialize(
size_t sz; /* Size of pSpec[], based on pSpec->iVersion */
memset(p, 0, sizeof(*p));
p->pzErr = pzErr;
if( pSpec->iVersion>2 ){
if( pSpec->iVersion>1 ){
qrfError(p, SQLITE_ERROR,
"unusable sqlite3_qrf_spec.iVersion (%d)",
pSpec->iVersion);
+1 -2
View File
@@ -42,6 +42,7 @@ struct sqlite3_qrf_spec {
short int nScreenWidth; /* Maximum overall table width */
short int nLineLimit; /* Maximum number of lines for any row */
short int nTitleLimit; /* Maximum number of characters in a title */
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
int nCharLimit; /* Maximum number of characters in a cell */
int nWidth; /* Number of entries in aWidth[] */
int nAlign; /* Number of entries in aAlignment[] */
@@ -56,8 +57,6 @@ struct sqlite3_qrf_spec {
void *pRenderArg; /* First argument to the xRender callback */
void *pWriteArg; /* First argument to the xWrite callback */
char **pzOutput; /* Storage location for output string */
/* Fields below are only available if iVersion>=2 */
unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
/* Additional fields may be added in the future */
};
+13 -12
View File
@@ -1037,7 +1037,17 @@ static void rtreeRelease(Rtree *pRtree){
pRtree->inWrTrans = 0;
assert( pRtree->nCursor==0 );
nodeBlobReset(pRtree);
assert( pRtree->nNodeRef==0 || pRtree->bCorrupt );
if( pRtree->nNodeRef ){
int i;
assert( pRtree->bCorrupt );
for(i=0; i<HASHSIZE; i++){
while( pRtree->aHash[i] ){
RtreeNode *pNext = pRtree->aHash[i]->pNext;
sqlite3_free(pRtree->aHash[i]);
pRtree->aHash[i] = pNext;
}
}
}
sqlite3_finalize(pRtree->pWriteNode);
sqlite3_finalize(pRtree->pDeleteNode);
sqlite3_finalize(pRtree->pReadRowid);
@@ -2329,7 +2339,7 @@ static int AdjustTree(
int iCell;
cnt++;
if( NEVER(cnt>100) ){
if( cnt>100 ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
@@ -2687,15 +2697,6 @@ static int SplitNode(
rc = updateMapping(pRtree, pCell->iRowid, pLeft, iHeight);
}
if( rc==SQLITE_OK ){
rc = nodeRelease(pRtree, pRight);
pRight = 0;
}
if( rc==SQLITE_OK ){
rc = nodeRelease(pRtree, pLeft);
pLeft = 0;
}
splitnode_out:
nodeRelease(pRtree, pRight);
nodeRelease(pRtree, pLeft);
@@ -2880,7 +2881,7 @@ static int rtreeInsertCell(
rc = SplitNode(pRtree, pNode, pCell, iHeight);
}else{
rc = AdjustTree(pRtree, pNode, pCell);
if( ALWAYS(rc==SQLITE_OK) ){
if( rc==SQLITE_OK ){
if( iHeight==0 ){
rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
}else{
+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)
+51 -48
View File
@@ -1,12 +1,12 @@
C Include\sthe\sfloat-point\stable\sgenerator\sutility\sin\sthe\stools\sdirectory.
D 2026-03-17T09:45:47.412
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
@@ -114,7 +114,7 @@ F ext/fts5/fts5_config.c bfba970fe1e4eed18ee57c8d51458e226db9a960ddf775c5e50e3d7
F ext/fts5/fts5_expr.c 71d48e8cf0358deace4949276647d317ff7665db6db09f40b81e2e7fe6664c7c
F ext/fts5/fts5_hash.c d5871df92ce3fa210a650cf419ee916b87c29977e86084d06612edf772bff6f5
F ext/fts5/fts5_index.c f8cfa37bb7397e5ede20242e4c9cb030bc8b4584ce3f23a5e2495038c0ae64bd
F ext/fts5/fts5_main.c 6889f1373c469d515e792fb3d783c2218e63c560433ebd66edc0f740ab086c1b
F ext/fts5/fts5_main.c b0fed47b3b4420ba6810373480a75bc28a9c0b7d16478d19a396436fb3ff17d7
F ext/fts5/fts5_storage.c 19bc7c4cbe1e6a2dd9849ef7d84b5ca1fcbf194cefc3e386b901e00e08bf05c2
F ext/fts5/fts5_tcl.c 2be6cc14f9448f720fd4418339cd202961a0801ea9424cb3d9de946f8f5a051c
F ext/fts5/fts5_test_mi.c 4308d5658cb1f5eee5998dcbaac7d5bdf7a2ef43c8192ca6e0c843f856ccee26
@@ -202,7 +202,7 @@ F ext/fts5/test/fts5hash.test fd3e0367fbf0b0944d6936fdb22696350f57b9871069c67662
F ext/fts5/test/fts5integrity.test 613efcebe16b2d7a4096f03bcfb164f79a000b3354420ceda4a6f3e035090789
F ext/fts5/test/fts5integrity2.test 4c3636615c0201232c44a8105d5cb14fd5499fd0ee3014d7ffd7e83aac76ece8
F ext/fts5/test/fts5interrupt.test af7834ac6c2e71c05aea42d92f272eef3655e89b7a14a5620a2cd9de35e2e8ea
F ext/fts5/test/fts5join.test 48b7ed36956948c5b8456c8bcaa5b087808d99000675918a43c4f51a925f1514
F ext/fts5/test/fts5join.test 3791e30d034050281191cd8141d969849f6c060135f1e3938fea3eea955f9da9
F ext/fts5/test/fts5lastrowid.test f36298a1fb9f988bde060a274a7ce638faa9c38a31400f8d2d27ea9373e0c4a1
F ext/fts5/test/fts5leftjoin.test 1c14b51f4d1344a89e488160882f05a2246dd7e70c5cf077c8fb473e03c66338
F ext/fts5/test/fts5limits.test 8ab67cf5d311c124b6ceb0062d0297767176df4572d955fce79fa43004dff01c
@@ -271,6 +271,7 @@ F ext/fts5/test/fts5update2.test c5baa76799ac605ebb8e5e21035db2014b396cef25c903e
F ext/fts5/test/fts5version.test 44ab35566267b7618c090443de2d9ad84f633df5d20bf72e9bad199ae5fced84
F ext/fts5/test/fts5vocab.test 2a2bdb60d0998fa3124d541b6d30b019504918dc43a6584645b63a24be72f992
F ext/fts5/test/fts5vocab2.test 4265137a3747b27deb1e2e2bde5654120c6de72bfed3238e67806d85af60fc4c
F ext/fts5/tool/fts5cost.tcl 188a802e69422619c526698b92f0e5935f7d00b964e155bf4d5b4d4094989f60
F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85
F ext/fts5/tool/fts5txt2db.tcl c0d43c8590656f8240e622b00957b3a0facc49482411a9fdc2870b45c0c82f9f
F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
@@ -368,7 +369,7 @@ F ext/misc/cksumvfs.c 9d7d0cf1a8893ac5d48922bfe9f3f217b4a61a6265f559263a02bb2001
F ext/misc/closure.c 5559daf1daf742228431db929d1aa86dd535a4224cc634a81d2fd0d1e6ad7839
F ext/misc/completion.c fd94e8231bb286a2eef7225368938565162daa72a8e8d06f946cc30ce15bf600
F ext/misc/compress.c 8191118b9b73e7796c961790db62d35d9b0fb724b045e005a5713dc9e0795565
F ext/misc/csv.c e82124eabee0e692d7b90ab8b2c34fadbf7b375279f102567fa06e4da4b771bf
F ext/misc/csv.c 256ee522fcf505d6eeaee0a891be9decd8df53c7d8d6a3629c52e6e803adf5f7
F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a06680
F ext/misc/decimal.c b64911bcc77ed86e40075a6a51a9efb48520720f289b9be544adf6e2587094d5
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
@@ -388,7 +389,7 @@ F ext/misc/percentile.c 72e05a21db20a2fa85264b99515941f00ae698824c9db82d7edfbb16
F ext/misc/prefixes.c 82645f79229877afab08c8b08ca1e7fa31921280906b90a61c294e4f540cd2a6
F ext/misc/qpvtab.c fc189e127f68f791af90a487f4460ec91539a716daf45a0c357e963fd47cc06c
F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
F ext/misc/regexp.c 69bd45f6931bdc6801c1059b65a3e8b15ba88255e6abe387a34b653ce17e8908
F ext/misc/regexp.c fa2d4c479e8bfe8c228d57dd4dde8e4aecb5b0abee70713853dcaa3c52d3fd8a
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
@@ -418,10 +419,10 @@ F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f6
F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
F ext/misc/zipfile.c c8ee04e1b349270b5df401ad732f5d7c387146e69b33c02fa90322760cc6fee0
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
F ext/qrf/README.md e6e0ce2700acf6fd06312b42726a8f08ca240f30e1b122bff87c71c602046352
F ext/qrf/README.md 9e644615d7d7b77ef7e9db798765679e50c5ed12eda48bce21c9ef9eb4715e9d
F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430
F ext/qrf/qrf.c 668456bdcfa1ad7914f21ee3846404494efbdfc8b6b6557a2ec27a17e1f92b29
F ext/qrf/qrf.h 2b27cb8079131ac3af2134e9e2ee9621b41d97bcb546fead41b9e1a12a3567a7
F ext/qrf/qrf.c 7334c688296f818f99c0cf37318b279ef62982a4860762096158237981fecb06
F ext/qrf/qrf.h 751fc5b102fa7e19aa4f1e2e75012fdc477bf6af7409dff36f9de5a9f3f6cf22
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
@@ -490,7 +491,7 @@ F ext/recover/sqlite3recover.h 011c799f02deb70ab685916f6f538e6bb32c4e0025e79bfd0
F ext/recover/test_recover.c 3d0fb1df7823f5bc22a0b93955034d16a2dfa2eb1e443e9a0123a77f120599a3
F ext/rtree/README 734aa36238bcd2dee91db5dba107d5fcbdb02396612811377a8ad50f1272b1c1
F ext/rtree/geopoly.c bd1971479184d559499ff3087c37f2823977d7b0ec80916141ae66f70345c88d
F ext/rtree/rtree.c 9331997a76b88a9bc04e156bdfd6e2fe35c0aa93bc338ebc6aa0ae470fe4a852
F ext/rtree/rtree.c 44abdd5df278ca1901daf29c82cce6785f0ee82ce59e28160ee988c17a9a185b
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test e0608db762b2aadca0ecb6f97396cf66244490adc3ba88f2a292b27be3e1da3e
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
@@ -645,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
@@ -654,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
@@ -675,28 +676,28 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
F src/btree.c fb350c445316c1cc0529703c0b76450770a1de0ab0440641a56b19f05d6fefbe
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
F src/build.c b993e4adef4c4cdfd7abf62e2676c467bb1923f25f40c3c7ab2a7bfbace3de7f
F src/build.c f370ed7458c1c3258bf8d83abf4af7130b2ba3a76536022e2b4d42973c53f70e
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
F src/delete.c 901499bed747c3b4b2be45be1abe912ba50a3f6a40ba88cc006ccf279f2d0e97
F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde
F src/expr.c 51e9c77ff5d9a21439e611fe6571a3cd50387e526e13c5614fd407e5b8571930
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c fb0f74c57d19a2d3f113f3476826919d68feda7ff334abfdb479a9a6353b9fcd
F src/func.c 6e7de3551ae0f8205006e5109f025223246edd20186d54d90746dee7c1c5c093
F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08
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 06cc944d51ecbdde04f465ea220034cab76dcce4e20b95d2201f6f3e2c89a854
F src/json.c 5027b856cd9b621dc9ba66b211e21a440ccdc63cefdefb44c51e7d3ac550d1a4
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9
F src/main.c 31a13302193fbd51279c7e69cdfa0320d0de7629f9151e0964c1d320e8bdd7a4
F src/main.c 387bb9d0216d6d35b221481ba8e661d94ad043060cd89581b6422c269ce680a0
F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -726,22 +727,22 @@ F src/parse.y 3b784d6083380a950e3b1b32ce5ddd303e8c7c209d8ab788df2c62aaf9ee8eb3
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f
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 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576
F src/shell.c.in 5bfc926b756d5816fcaf56a30c3a363ba09ac09a9f6a5a7eef1b27c8bac8f6c4
F src/sqlite.h.in 4d657846d68a58b028f0c4c331b9d3b4a79306f25c3b0d04fb56060343f73d85
F src/shell.c.in 91ee40ec3f75192362cbaa0ad85316140b8dde00a184113d73a837fb6173dbcc
F src/sqlite.h.in e7acbb01518f05c5a342149ec1eeb1afcdccf9b90a6e9770a4893ae9a3c756ae
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
F src/sqliteInt.h 9716721fb57e32938a1d30a84560ce7633c63860a2209e188c87afad15d4b464
F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e
F src/sqliteInt.h bc1cbc0c23dba35b324ae85a7dbb5fb182321bbd30857fb21f3d0cba049001a5
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 71230da35d81b7234c5e4dc3747ca2302390884b051052956deb3dbf680a6ed4
F src/tclsqlite.c 7401c73c917a4d1b380c896a324c8d8eb533a999559d9e339d479596553bebfd
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
F src/test1.c 3e3b013f59ffcb57dce00c90d55907072d71d4e970cb0a590cb261efe11bae9c
F src/test2.c 2b9ab96bba63a1c369d5769390475259ad210f144a877805f2e32e563f9e93c1
@@ -791,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 cf91389b58590edfb5978199ef59488ef8e3723e1ba1aa0ff15c62f8a658b95f
F src/util.c f264a84eda716ae009089f1d788b55718062810792b0bfa331e7899f2add39c6
F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82
F src/vdbe.c 5328c99dd256ee8132383565a86e253543a85daccfd7477c52f20bac6b385a7f
F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9
F src/vdbeInt.h 42488247a80cd9d300627833c6c85ace067ae5011a99e7614e2358130d62feea
F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3
F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
F src/vdbeaux.c 396d38a62a357b807eabae0cae441fc89d2767a57ab08026b7072bf7aa2dd00c
F src/vdbeaux.c 81687c55682b9f4d942186695f4f7fa4743c564a985e0889def52eded9076d61
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
F src/vdbemem.c 317ec5e870ddb16951b606c9fe8be22baef22ecbe46f58fdefc259662238afb7
F src/vdbemem.c 5af6cf1253ac2aed0612b85138a1faf43f30ad38777d554db6c85b7281fa79fb
F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
@@ -814,7 +815,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab
F src/wal.c 88d94fd15a75f6eda831fa32d1148a267ea37bf0a4b69829a73dfde06244b08f
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
F src/where.c 406d9ec8d12f646c28c4b4a645ea20329eb343b19cfa3dcd8aab938066c4ae66
F src/where.c bffca5e4ef20d0bfbdc24f1dc13fd3f955284225a8ad25a4454635f6be39aad0
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
F src/wherecode.c 676cb6cb02878643e817d9917a2d3522b83a3736b2cedd3dc8a01d7bb92af6c2
F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6
@@ -875,7 +876,7 @@ F test/attach2.test 6d1e3a457ce260d6fc8e5945c07fba6c76dc2aa90e1c701f067b50ee88f7
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
F test/attach4.test 00e754484859998d124d144de6d114d920f2ed6ca2f961e6a7f4183c714f885e
F test/attachmalloc.test 67309af95c6b765c13e7d2279d7fccbef78e6eb0565d75d51cefd5dc88784549
F test/auth.test 5b8558a40571ebc55c1581cb7cec3b2348a699542a0a51b83ef21c6a953d95e3
F test/auth.test 2a01bf5bf3a0f10adf8ae3a3fd2c05af8a8c1b7a52fae227adb4ccd931915b5c
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
@@ -1102,6 +1103,7 @@ F test/expr.test db981f8a85520e99ae20aab7ad2e9b5b0437ed09159b57ced434c672075d2e6
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
F test/exprfault.test da33606d799718e2f8e34efd0e5858884a1ad87f608774c552a7f5517cc27181
F test/exprfault2.test c49e84273898969af5dbc4fe6a3f4335f14639799f343590336c9ddf84425965
F test/expridx1.test b464520126e1d781a7800f8540621c82e8bbc526f089ff8b0b57ffc51feea6b7
F test/extension01.test 5de412c66276105901c370770175003381fdcb0c4da7054fa43cf4a31e0bfa3a
F test/external_reader.test 6fdec43eeca23eb32faad1e95a4d1abc402bc8b3db70df12d6fc08a637f4a2b5
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
@@ -1119,14 +1121,15 @@ F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
F test/fkey5.test 6727452e163a427147e84e739da18713da553d79f9783559b04fdcd36d5c7421
F test/fkey6.test 668a7299e75899b0a3342c36df655be57f76a05aca3544bda939a6e676e2f000
F test/fkey7.test 64fb28da03da5dfe3cdef5967aa7e832c2507bf7fb8f0780cacbca1f2338d031
F test/fkey8.test 51deda7f1a1448bca95875e4a6e1a3a75b4bd7215e924e845bd60de60e4d84bf
F test/fkey8.test 00ecfcaba529d4d9ef608551714e6a4d1e9d7083406f65e2f108c539aff6e8e3
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
@@ -1559,7 +1562,7 @@ F test/rowvalue6.test d19b54feb604d5601f8614b15e214e0774c01087
F test/rowvalue7.test 06ec0aca725bf683313d03793aa2943bc7f45a901848c7056a9665b769c8fc38
F test/rowvalue8.test 5900eddad9e2c3c2e26f1a95f74aafc1232ee5e0
F test/rowvalue9.test 7499a8fd7ca3a3f0e19d94e135355439aa2b596f86b775ca8de79672da2ca378
F test/rowvalueA.test 1c5ed13f3b0641452ae35e6488d6ecc16cefce99f2adf7c07c513530e2aac6b7
F test/rowvalueA.test 7d28bf6c2f8a2af8adbba2c4eda9136a4dd36250b8966ba05b34c0954f78efd7
F test/rowvaluefault.test 963ae9cdaed30a85a29668dd514e639f3556cae903ee9f172ea972d511c54fff
F test/rowvaluevtab.test cd9747bb3f308086944c07968f547ad6b05022e698d80b9ffbdfe09ce0b8da6f
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
@@ -1615,7 +1618,7 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test d714be78c063cfb5f0933dcf2b5d9df62ef57f8eaf8848bbd0026a9d252d4db5
F test/shell1.test eda2e527435f139224dda67db6bbd2466597408d4fe5883d647d67fa32d88f7c
F test/shell2.test dc541d2681503e55466a24d35a4cbf8ca5b90b8fcdef37fc4db07373a67d31d3
F test/shell3.test 91efdd545097a61a1f72cf79c9ad5b49da080f3f10282eaf4c3c272cd1012db2
F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
@@ -1625,7 +1628,7 @@ F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d
F test/shell8.test 38c9e4d7e85d2a3ecfacaa9f6cda4f7a81bf4fffb5f3f37f9cd76827c6883192
F test/shell9.test c0e8871061a92151450b3332279a893b516fa73a6c46d4f51a0998407cbf8c89
F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480
F test/shellB.test 7123d231158588401f332bf278754687b83ba5fc5b352ec8679fb19edfb4cc0a
F test/shellB.test 31df04230f6062069bb7c5d0e5c5439ca44448fa9da1a55aa461a4b872fe6bd9
F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
@@ -2081,7 +2084,7 @@ F test/with1.test 31db84788e0429885b63995149fab57d32e26196b752a3a926249ae74c0add
F test/with2.test 181674a6cc86a601ca2ac052741cdfad5b529e07e870435d2f6cdb92d589ff17
F test/with3.test e30369ea27aa27eb1bda4c5e510c8a9f782c8afd2ab99d1a02b8a7f25a5d3e65
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
F test/with5.test 0e5e141fee75aa170289467542a2ffd71933d4fb006bfb135275b1787bdc8fbe
F test/with6.test 281e4861b5e517f6c3c2f08517a520c1e2ee7c11966545d3901f258a4fe8ef76
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
F test/without_rowid1.test f6e75e32821eb423ac3812434d12bdd8098f17e3b2206da61575e1db77f82428
@@ -2135,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
@@ -2190,11 +2193,11 @@ F tool/vdbe-compress.tcl fa2f37ab39b2a0087fafb6a7f3ce19503e25e624ffa8ed9951717ab
F tool/vdbe_profile.tcl 3ac5a4a9449f4baf77059358ea050db3e34395ccf59c5464d29b91746d5b961e
F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6ddf2700c
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
P 23ad656edb3a63e7e6602770e1f2c4a5ef1f3d41565e7f13408b5305619dfa3d
R 0212d90b78d20068a702d7e70e4b68de
P 9fa9cd11f8f5f7591168870c6e41121221b58a4a3094e708e3fa5bab1502f190
R 3d9d1b868f679fc05545d2cf5aa8e36a
U drh
Z a52753c1b6f0991d0a121a4d3cb8bc3e
Z e2629b4a210900f82e89295566df240e
# Remove this line to create a well-formed Fossil manifest.
+2 -2
View File
@@ -1,2 +1,2 @@
branch fp-accuracy
tag fp-accuracy
branch direct-printf
tag direct-printf
+1 -1
View File
@@ -1 +1 @@
4ab10b251d870af8297b9e505452393f6000f83784c822ff128e7aec06f8c72f
afe7e9fd1c476c7cdcefab0adf0191a8dc3283811f72a685fff3eb6539b72dcc
+80 -88
View File
@@ -2494,9 +2494,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
if( !hasColumn(pPk->aiColumn, j, i)
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0
){
const char *zColl = sqlite3ColumnColl(&pTab->aCol[i]);
assert( j<pPk->nColumn );
pPk->aiColumn[j] = i;
pPk->azColl[j] = sqlite3StrBINARY;
pPk->azColl[j] = zColl ? zColl : sqlite3StrBINARY;
j++;
}
}
@@ -5522,8 +5523,7 @@ void sqlite3RowidConstraint(
}
/*
** Check to see if pIndex uses the collating sequence pColl. Return
** true if it does and false if it does not.
** Return true if any column of pIndex uses the zColl collation
*/
#ifndef SQLITE_OMIT_REINDEX
static int collationMatch(const char *zColl, Index *pIndex){
@@ -5531,8 +5531,8 @@ static int collationMatch(const char *zColl, Index *pIndex){
assert( zColl!=0 );
for(i=0; i<pIndex->nColumn; i++){
const char *z = pIndex->azColl[i];
assert( z!=0 || pIndex->aiColumn[i]<0 );
if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){
assert( z!=0 );
if( 0==sqlite3StrICmp(z, zColl) ){
return 1;
}
}
@@ -5540,73 +5540,40 @@ static int collationMatch(const char *zColl, Index *pIndex){
}
#endif
/*
** Recompute all indices of pTab that use the collating sequence pColl.
** If pColl==0 then recompute all indices of pTab.
*/
#ifndef SQLITE_OMIT_REINDEX
static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
if( !IsVirtual(pTab) ){
Index *pIndex; /* An index associated with pTab */
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
if( zColl==0 || collationMatch(zColl, pIndex) ){
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIndex, -1);
}
}
}
}
#endif
/*
** Recompute all indices of all tables in all databases where the
** indices use the collating sequence pColl. If pColl==0 then recompute
** all indices everywhere.
*/
#ifndef SQLITE_OMIT_REINDEX
static void reindexDatabases(Parse *pParse, char const *zColl){
Db *pDb; /* A single database */
int iDb; /* The database index number */
sqlite3 *db = pParse->db; /* The database connection */
HashElem *k; /* For looping over tables in pDb */
Table *pTab; /* A table in the database */
assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
assert( pDb!=0 );
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
reindexTable(pParse, pTab, zColl);
}
}
}
#endif
/*
** Generate code for the REINDEX command.
**
** REINDEX -- 1
** REINDEX <collation> -- 2
** REINDEX ?<database>.?<tablename> -- 3
** REINDEX ?<database>.?<indexname> -- 4
** REINDEX ?<database>.?<indexname> -- 3
** REINDEX ?<database>.?<tablename> -- 4
** REINDEX EXPRESSIONS -- 5
**
** Form 1 causes all indices in all attached databases to be rebuilt.
** Form 2 rebuilds all indices in all databases that use the named
** Form 1 causes all indexes in all attached databases to be rebuilt.
** Form 2 rebuilds all indexes in all databases that use the named
** collating function. Forms 3 and 4 rebuild the named index or all
** indices associated with the named table.
** indexes associated with the named table, respectively. Form 5
** rebuilds all expression indexes in addition to all collations,
** indexes, or tables named "EXPRESSIONS".
**
** If the name is ambiguous such that it matches two or more of
** forms 2 through 5, then rebuild the union of all matching indexes,
** taken care to avoid rebuilding the same index more than once.
*/
#ifndef SQLITE_OMIT_REINDEX
void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */
char *z; /* Name of a table or index */
const char *zDb; /* Name of the database */
Table *pTab; /* A table in the database */
Index *pIndex; /* An index associated with pTab */
int iDb; /* The database index number */
char *z = 0; /* Name of a table or index or collation */
const char *zDb = 0; /* Name of the database */
int iReDb = -1; /* The database index number */
sqlite3 *db = pParse->db; /* The database connection */
Token *pObjName; /* Name of the table or index to be reindexed */
int bMatch = 0; /* At least one name match */
const char *zColl = 0; /* Rebuild indexes using this collation */
Table *pReTab = 0; /* Rebuild all indexes of this table */
Index *pReIndex = 0; /* Rebuild this index */
int isExprIdx = 0; /* Rebuild all expression indexes */
int bAll = 0; /* Rebuild all indexes */
/* Read the database schema. If an error occurs, leave an error message
** and code in pParse and return NULL. */
@@ -5615,41 +5582,66 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
}
if( pName1==0 ){
reindexDatabases(pParse, 0);
return;
/* rebuild all indexes */
bMatch = 1;
bAll = 1;
}else if( NEVER(pName2==0) || pName2->z==0 ){
char *zColl;
assert( pName1->z );
zColl = sqlite3NameFromToken(pParse->db, pName1);
if( !zColl ) return;
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
if( pColl ){
reindexDatabases(pParse, zColl);
sqlite3DbFree(db, zColl);
return;
z = sqlite3NameFromToken(pParse->db, pName1);
if( z==0 ) return;
}else{
iReDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
if( iReDb<0 ) return;
z = sqlite3NameFromToken(db, pObjName);
if( z==0 ) return;
zDb = db->aDb[iReDb].zDbSName;
}
if( !bAll ){
if( zDb==0 && sqlite3StrICmp(z, "expressions")==0 ){
isExprIdx = 1;
bMatch = 1;
}
if( zDb==0 && (pColl = sqlite3FindCollSeq(db, ENC(db), z, 0))!=0 ){
zColl = z;
bMatch = 1;
}
if( zColl==0 && (pReTab = sqlite3FindTable(db, z, zDb))!=0 ){
bMatch = 1;
}
if( zColl==0 && (pReIndex = sqlite3FindIndex(db, z, zDb))!=0 ){
bMatch = 1;
}
sqlite3DbFree(db, zColl);
}
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
if( iDb<0 ) return;
z = sqlite3NameFromToken(db, pObjName);
if( z==0 ) return;
zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
pTab = sqlite3FindTable(db, z, zDb);
if( pTab ){
reindexTable(pParse, pTab, 0);
sqlite3DbFree(db, z);
return;
if( bMatch ){
int iDb;
HashElem *k;
Table *pTab;
Index *pIdx;
Db *pDb;
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
assert( pDb!=0 );
if( iReDb>=0 && iReDb!=iDb ) continue;
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
if( IsVirtual(pTab) ) continue;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( bAll
|| pTab==pReTab
|| pIdx==pReIndex
|| (isExprIdx && pIdx->bHasExpr)
|| (zColl!=0 && collationMatch(zColl,pIdx))
){
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIdx, -1);
}
} /* End loop over indexes of pTab */
} /* End loop over tables of iDb */
} /* End loop over databases */
}else{
sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
}
pIndex = sqlite3FindIndex(db, z, zDb);
sqlite3DbFree(db, z);
if( pIndex ){
iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema);
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIndex, -1);
return;
}
sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
return;
}
#endif
+3 -1
View File
@@ -923,7 +923,9 @@ void sqlite3GenerateRowIndexDelete(
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
&iPartIdxLabel, pPrior, r1);
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn
);
sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX);
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
pPrior = pIdx;
}
+8 -6
View File
@@ -1326,7 +1326,6 @@ static Trigger *fkActionTrigger(
nFrom = sqlite3Strlen30(zFrom);
if( action==OE_Restrict ){
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
SrcList *pSrc;
Expr *pRaise;
@@ -1337,10 +1336,10 @@ static Trigger *fkActionTrigger(
}
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pSrc ){
assert( pSrc->nSrc==1 );
pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 );
pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
SrcItem *pItem = &pSrc->a[0];
pItem->zName = sqlite3DbStrDup(db, zFrom);
pItem->fg.fixedSchema = 1;
pItem->u4.pSchema = pTab->pSchema;
}
pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise),
@@ -1362,7 +1361,10 @@ static Trigger *fkActionTrigger(
pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
pStep->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pStep->pSrc ){
pStep->pSrc->a[0].zName = sqlite3DbStrNDup(db, zFrom, nFrom);
SrcItem *pItem = &pStep->pSrc->a[0];
pItem->zName = sqlite3DbStrNDup(db, zFrom, nFrom);
pItem->u4.pSchema = pTab->pSchema;
pItem->fg.fixedSchema = 1;
}
pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
+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: {
+83 -38
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
*/
@@ -850,6 +860,7 @@ static void jsonReturnString(
){
assert( (pParse!=0)==(ctx!=0) );
assert( ctx==0 || ctx==p->pCtx );
jsonStringTerminate(p);
if( p->eErr==0 ){
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx));
if( flags & JSON_BLOB ){
@@ -857,7 +868,7 @@ static void jsonReturnString(
}else if( p->bStatic ){
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
SQLITE_TRANSIENT, SQLITE_UTF8);
}else if( jsonStringTerminate(p) ){
}else{
if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){
int rc;
pParse->zJson = sqlite3RCStrRef(p->zBuf);
@@ -873,11 +884,11 @@ static void jsonReturnString(
sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed,
sqlite3RCStrUnref,
SQLITE_UTF8);
}else{
sqlite3_result_error_nomem(p->pCtx);
}
}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);
}
@@ -2088,12 +2099,8 @@ static int jsonConvertTextToBlob(
*/
static void jsonReturnStringAsBlob(JsonString *pStr){
JsonParse px;
assert( pStr->eErr==0 );
memset(&px, 0, sizeof(px));
jsonStringTerminate(pStr);
if( pStr->eErr ){
sqlite3_result_error_nomem(pStr->pCtx);
return;
}
px.zJson = pStr->zBuf;
px.nJson = pStr->nUsed;
px.db = sqlite3_context_db_handle(pStr->pCtx);
@@ -2183,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 */
){
@@ -2365,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, ']');
@@ -2379,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, '}');
@@ -2439,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 ){
@@ -2454,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);
@@ -2475,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);
@@ -2876,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 */
@@ -2923,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 */
@@ -3029,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;
}
@@ -3115,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;
}
@@ -3447,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.
@@ -3460,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);
}
@@ -3522,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);
@@ -3534,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;
}
@@ -3978,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;
@@ -4115,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;
}
}
@@ -4143,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.
@@ -4194,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() */
@@ -4303,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;
}
@@ -4324,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;
}
@@ -4355,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);
}
@@ -4447,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;
}
@@ -4547,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;
}
@@ -4808,7 +4851,8 @@ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
if( pStr ){
pStr->pCtx = ctx;
jsonAppendChar(pStr, ']');
jsonAppendRawNZ(pStr, "]", 2);
jsonStringTrimOneChar(pStr);
if( pStr->eErr ){
jsonReturnString(pStr, 0, 0);
return;
@@ -4931,7 +4975,8 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
if( pStr ){
jsonAppendChar(pStr, '}');
jsonAppendRawNZ(pStr, "}", 2);
jsonStringTrimOneChar(pStr);
pStr->pCtx = ctx;
if( pStr->eErr ){
jsonReturnString(pStr, 0, 0);
+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)
**
+14 -2
View File
@@ -2067,8 +2067,20 @@ void sqlite3Pragma(
pPrior = pIdx;
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */
/* Verify that an index entry exists for the current table row */
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
pIdx->nColumn); VdbeCoverage(v);
jmp2 = sqlite3VdbeAddOp3(v, OP_IFindKey, iIdxCur+j, ckUniq, r1);
VdbeCoverage(v);
sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "index %s stores an imprecise floating-point "
"value for row ", pIdx->zName),
P4_DYNAMIC);
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
integrityCheckResultRow(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, ckUniq);
sqlite3VdbeJumpHere(v, jmp2);
sqlite3VdbeLoadString(v, 3, "row ");
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
sqlite3VdbeLoadString(v, 4, " missing from index ");
@@ -2076,7 +2088,7 @@ void sqlite3Pragma(
jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
jmp4 = integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, jmp2);
sqlite3VdbeResolveLabel(v, ckUniq);
/* The OP_IdxRowid opcode is an optimized version of OP_Column
** that extracts the rowid off the end of the index record.
+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.
*/
+879 -805
View File
File diff suppressed because it is too large Load Diff
+7 -7
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 */
/*
+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
@@ -2136,7 +2136,7 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
};
memset(&qrf, 0, sizeof(qrf));
qrf.iVersion = 2;
qrf.iVersion = 1;
qrf.pzOutput = &zResult;
for(i=2; i<objc; i++){
const char *zArg = Tcl_GetString(objv[i]);
+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);
+244 -121
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))
__uint128_t r = (__int128_t)a * b;
&& (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
@@ -499,6 +500,22 @@ static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
** The lower 64 bits of A*B are discarded.
*/
static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
#if (defined(__GNUC__) || defined(__clang__)) \
&& (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(_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);
u64 t = r1_lo + r2;
if( t<r1_lo ) r1_hi++;
*pLo = t>>32;
return r1_hi;
#else
u64 x2 = a>>32;
u64 x1 = a&0xffffffff;
u64 x0 = aLo;
@@ -520,6 +537,7 @@ static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
r3 += r2>>32;
*pLo = r2&0xffffffff;
return (r4<<32) + r3;
#endif
}
/*
@@ -707,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;
@@ -749,46 +768,50 @@ static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){
/*
** Return an IEEE754 floating point value that approximates d*pow(10,p).
**
** The (current) algorithm is adapted from the work of Ross Cox at
** https://github.com/rsc/fpfmt
*/
static double sqlite3Fp10Convert2(u64 d, int p){
int b, lp, e, adj, s;
u32 pwr10l, mid1;
u64 pwr10h, x, hi, lo, sticky, u, m;
double r;
if( p<POWERSOF10_FIRST ) return 0.0;
if( p>POWERSOF10_LAST ) return INFINITY;
int b = 64 - countLeadingZeros(d);
int lp = pwr10to2(p);
int e = 53 - b - lp;
b = 64 - countLeadingZeros(d);
lp = pwr10to2(p);
e = 53 - b - lp;
if( e > 1074 ){
if( e>=1130 ) return 0.0;
e = 1074;
}
int s = -(e-(64-b) + lp + 3);
u32 pwr10l;
u64 pwr10h = powerOfTen(p, &pwr10l);
s = -(e-(64-b) + lp + 3);
pwr10h = powerOfTen(p, &pwr10l);
if( pwr10l!=0 ){
pwr10h++;
pwr10l = ~pwr10l;
}
u64 x = d<<(64-b);
u64 lo;
u64 hi = sqlite3Multiply128(x,pwr10h,&lo);
u32 mid1 = lo>>32;
u64 sticky = 1;
x = d<<(64-b);
hi = sqlite3Multiply128(x,pwr10h,&lo);
mid1 = lo>>32;
sticky = 1;
if( (hi & (U64_BIT(s)-1))==0 ) {
u32 mid2 = sqlite3Multiply128(x,((u64)pwr10l)<<32,&lo)>>32;
sticky = (mid1-mid2 > 1);
hi -= mid1 < mid2;
}
u64 u = (hi>>s) | sticky;
int adj = (u >= U64_BIT(55)-2);
u = (hi>>s) | sticky;
adj = (u >= U64_BIT(55)-2);
if( adj ){
u = (u>>adj) | (u&1);
e -= adj;
}
u64 m = (u + 1 + ((u>>2)&1)) >> 2;
m = (u + 1 + ((u>>2)&1)) >> 2;
if( e<=(-972) ) return INFINITY;
if((m & U64_BIT(52)) != 0){
m = (m & ~U64_BIT(52)) | ((u64)(1075-e)<<52);
}
double r;
memcpy(&r,&m,8);
return r;
}
@@ -799,134 +822,161 @@ static double sqlite3Fp10Convert2(u64 d, int p){
**
** z[] must be UTF-8 and zero-terminated.
**
** Return TRUE if the result is a valid real number (or integer) and FALSE
** if the string is empty or contains extraneous text. More specifically
** return
** 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 a valid number
** -1 => Not a valid number, but has a valid prefix which
** includes a decimal point and/or an eNNN clause
** 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.
** Lower bits of the return value contain addition information about the
** parse:
**
** Valid numbers are in one of these formats:
** 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
**
** 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.
**
** If some prefix of the input string is a valid number, this routine
** returns FALSE but it still converts the prefix and writes the result
** into *pResult.
** 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
** IEEE754 double. The sign is added back afterwards, if the input string
** starts with a "-". The use of an unsigned 64-bit s mantissa means that
** only about the first 19 significant digits of the input can contribute
** to the result. This can result in suboptimal rounding decisions when
** correct rounding requires more than 19 input digits. For example,
** this routine renders "3500000000000000.2500001" as
** 3500000000000000.0 instead of 3500000000000000.5 because the decision
** to round up instead of using banker's rounding to round down is determined
** by the 23rd significant digit, which this routine ignores. It is not
** possible to do better without some kind of BigNum.
*/
#if defined(_MSC_VER)
#pragma warning(disable : 4756)
#endif
int sqlite3AtoF(const char *z, double *pResult){
int sqlite3AtoF(const char *zIn, double *pResult){
#ifndef SQLITE_OMIT_FLOATING_POINT
/* sign * significand * (10 ^ (esign * exponent)) */
int neg = 0; /* True for a negative value */
u64 s = 0; /* mantissa */
int d = 0; /* Value is s * pow(10,d) */
int nDigit = 0; /* Number of digits processed */
int eType = 1; /* 1: pure integer, 2+: fractional */
const unsigned char *z = (const unsigned char*)zIn;
int neg = 0; /* True for a negative value */
u64 s = 0; /* mantissa */
int d = 0; /* Value is s * pow(10,d) */
int mState = 0; /* 1: digit seen 2: fp 4: hard-zero */
unsigned v; /* Value of a single digit */
*pResult = 0.0; /* Default return value, in case of an error */
/* skip leading spaces */
while( sqlite3Isspace(*z) ) z++;
/* get sign of significand */
if( *z=='-' ){
start_of_text:
if( (v = (unsigned)z[0] - '0')<10 ){
parse_integer_part:
mState = 1;
s = v;
z++;
while( (v = (unsigned)z[0] - '0')<10 ){
s = s*10 + v;
z++;
if( s>=(LARGEST_UINT64-9)/10 ){
mState = 9;
while( sqlite3Isdigit(z[0]) ){ z++; d++; }
break;
}
}
}else if( z[0]=='-' ){
neg = 1;
z++;
}else if( *z=='+' ){
if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part;
}else if( z[0]=='+' ){
z++;
}
/* copy max significant digits to significand */
while( sqlite3Isdigit(*z) ){
s = s*10 + (*z - '0');
z++; nDigit++;
if( s>=((LARGEST_INT64-9)/10) ){
/* skip non-significant significand digits
** (increase exponent by d to shift decimal left) */
while( sqlite3Isdigit(*z) ){ z++; d++; }
}
if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part;
}else if( sqlite3Isspace(z[0]) ){
do{ z++; }while( sqlite3Isspace(z[0]) );
goto start_of_text;
}else{
s = 0;
}
/* if decimal point is present */
if( *z=='.' ){
z++;
eType++;
/* copy digits from after decimal to significand
** (decrease exponent by d to shift decimal right) */
while( sqlite3Isdigit(*z) ){
if( s<((LARGEST_INT64-9)/10) ){
s = s*10 + (*z - '0');
d--;
nDigit++;
}
z++;
if( sqlite3Isdigit(z[0]) ){
mState |= 1;
do{
if( s<(LARGEST_UINT64-9)/10 ){
s = s*10 + z[0] - '0';
d--;
}else{
mState = 11;
}
}while( sqlite3Isdigit(*++z) );
}else if( mState==0 ){
*pResult = 0.0;
return 0;
}
mState |= 2;
}else if( mState==0 ){
*pResult = 0.0;
return 0;
}
/* if exponent is present */
if( *z=='e' || *z=='E' ){
int esign = 1; /* sign of exponent */
int esign;
z++;
eType++;
/* get sign of exponent */
if( *z=='-' ){
esign = -1;
z++;
}else if( *z=='+' ){
z++;
}else{
esign = +1;
if( *z=='+' ){
z++;
}
}
/* copy digits to exponent */
if( sqlite3Isdigit(*z) ){
int exp = *z - '0';
if( (v = (unsigned)z[0] - '0')<10 ){
int exp = v;
z++;
while( sqlite3Isdigit(*z) ){
exp = exp<10000 ? (exp*10 + (*z - '0')) : 10000;
mState |= 2;
while( (v = (unsigned)z[0] - '0')<10 ){
exp = exp<10000 ? (exp*10 + v) : 10000;
z++;
}
d += esign*exp;
}else{
eType = -1;
z--; /* Leave z[0] at 'e' or '+' or '-',
** so that the return is 0 or -1 */
}
}
/* skip trailing spaces */
while( sqlite3Isspace(*z) ) z++;
/* Zero is a special case */
/* Convert s*pow(10,d) into real */
if( s==0 ){
*pResult = neg ? -0.0 : +0.0;
*pResult = 0.0;
mState |= 4;
}else{
*pResult = sqlite3Fp10Convert2(s,d);
if( neg ) *pResult = -*pResult;
assert( !sqlite3IsNaN(*pResult) );
}
if( neg ) *pResult = -*pResult;
assert( !sqlite3IsNaN(*pResult) );
/* return true if number and no extra non-whitespace characters after */
if( z[0]==0 && nDigit>0 ){
return eType;
}else if( eType>=2 && nDigit>0 ){
return -1;
}else{
return 0;
if( z[0]==0 ){
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 */
}
#if defined(_MSC_VER)
#pragma warning(default : 4756)
#endif
/*
** Digit pairs used to convert a U64 or I64 into text, two digits
@@ -948,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
@@ -961,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 ){
@@ -973,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 ){
@@ -986,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;
@@ -1042,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;
@@ -1071,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 );
@@ -1109,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{
@@ -1305,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 ){
@@ -1362,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) ){
+75 -12
View File
@@ -355,9 +355,9 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
double rValue;
int rc;
assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str );
rValue = sqlite3MemRealValueRC(pRec, &rc);
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;
@@ -473,15 +473,15 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
pMem->u.i = 0;
return MEM_Int;
}
pMem->u.r = sqlite3MemRealValueRC(pMem, &rc);
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;
}
@@ -6622,13 +6622,15 @@ case OP_SorterInsert: { /* in2 */
break;
}
/* Opcode: IdxDelete P1 P2 P3 * *
/* Opcode: IdxDelete P1 P2 P3 P4 *
** Synopsis: key=r[P2@P3]
**
** The content of P3 registers starting at register P2 form
** an unpacked index key. This opcode removes that entry from the
** index opened by cursor P1.
**
** P4 is a pointer to an Index structure.
**
** Raise an SQLITE_CORRUPT_INDEX error if no matching index entry is found
** and not in writable_schema mode.
*/
@@ -6653,13 +6655,22 @@ case OP_IdxDelete: {
r.aMem = &aMem[pOp->p2];
rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res);
if( rc ) goto abort_due_to_error;
if( res==0 ){
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
if( rc ) goto abort_due_to_error;
}else if( !sqlite3WritableSchema(db) ){
rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption");
goto abort_due_to_error;
if( res!=0 ){
rc = sqlite3VdbeFindIndexKey(pCrsr, pOp->p4.pIdx, &r, &res, 0);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( res!=0 ){
if( !sqlite3WritableSchema(db) ){
rc = sqlite3ReportError(
SQLITE_CORRUPT_INDEX, __LINE__, "index corruption");
goto abort_due_to_error;
}
pC->cacheStatus = CACHE_STALE;
pC->seekResult = 0;
break;
}
}
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
if( rc ) goto abort_due_to_error;
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
pC->seekResult = 0;
@@ -7286,6 +7297,58 @@ case OP_IntegrityCk: {
sqlite3VdbeChangeEncoding(pIn1, encoding);
goto check_for_interrupt;
}
/* Opcode: IFindKey P1 P2 P3 P4 *
**
** This instruction always follows an OP_Found with the same P1, P2 and P3
** values as this instruction and a non-zero P4 value. The P4 value to
** this opcode is of type P4_INDEX and contains a pointer to the Index
** object of for the index being searched.
**
** This opcode uses sqlite3VdbeFindIndexKey() to search around the current
** cursor location for an index key that exactly matches all fields that
** are not indexed expressions or references to VIRTUAL generated columns,
** and either exactly match or are real numbers that are within 2 ULPs of
** each other if the don't match.
**
** To put it another way, this opcode looks for nearby index entries that
** are very close to the search key, but which might have small differences
** in floating-point values that come via an expression.
**
** If no nearby alternative entry is found in cursor P1, then jump to P2.
** But if a close match is found, fall through.
**
** This opcode is used by PRAGMA integrity_check to help distinguish
** between truely corrupt indexes and expression indexes that are holding
** floating-point values that are off by one or two ULPs.
*/
case OP_IFindKey: { /* jump, in3 */
VdbeCursor *pC;
int res;
UnpackedRecord r;
assert( pOp[-1].opcode==OP_Found );
assert( pOp[-1].p1==pOp->p1 );
assert( pOp[-1].p3==pOp->p3 );
pC = p->apCsr[pOp->p1];
assert( pOp->p4type==P4_INDEX );
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
assert( pC->isTable==0 );
memset(&r, 0, sizeof(r));
r.aMem = &aMem[pOp->p3];
r.nField = pOp->p4.pIdx->nColumn;
r.pKeyInfo = pC->pKeyInfo;
rc = sqlite3VdbeFindIndexKey(pC->uc.pCursor, pOp->p4.pIdx, &r, &res, 1);
if( rc || res!=0 ){
rc = SQLITE_OK;
goto jump_to_p2;
}
pC->nullRow = 0;
break;
};
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
/* Opcode: RowSetAdd P1 P2 * * *
+15 -13
View File
@@ -75,6 +75,7 @@ struct VdbeOp {
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
Table *pTab; /* Used when p4type is P4_TABLE */
SubrtnSig *pSubrtnSig; /* Used when p4type is P4_SUBRTNSIG */
Index *pIdx; /* Used when p4type is P4_INDEX */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
@@ -129,20 +130,21 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INT32 (-3) /* P4 is a 32-bit signed integer */
#define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */
#define P4_TABLE (-5) /* P4 is a pointer to a Table structure */
#define P4_INDEX (-6) /* P4 is a pointer to an Index structure */
/* Above do not own any resources. Must free those below */
#define P4_FREE_IF_LE (-6)
#define P4_DYNAMIC (-6) /* Pointer to memory from sqliteMalloc() */
#define P4_FUNCDEF (-7) /* P4 is a pointer to a FuncDef structure */
#define P4_KEYINFO (-8) /* P4 is a pointer to a KeyInfo structure */
#define P4_EXPR (-9) /* P4 is a pointer to an Expr tree */
#define P4_MEM (-10) /* P4 is a pointer to a Mem* structure */
#define P4_VTAB (-11) /* P4 is a pointer to an sqlite3_vtab structure */
#define P4_REAL (-12) /* P4 is a 64-bit floating point value */
#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */
#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */
#define P4_SUBRTNSIG (-17) /* P4 is a SubrtnSig pointer */
#define P4_FREE_IF_LE (-7)
#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */
#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */
#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */
#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */
#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */
#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */
#define P4_REAL (-13) /* P4 is a 64-bit floating point value */
#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */
#define P4_TABLEREF (-17) /* Like P4_TABLE, but reference counted */
#define P4_SUBRTNSIG (-18) /* P4 is a SubrtnSig pointer */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
+2 -1
View File
@@ -656,7 +656,7 @@ int sqlite3IntFloatCompare(i64,double);
i64 sqlite3VdbeIntValue(const Mem*);
int sqlite3VdbeMemIntegerify(Mem*);
double sqlite3VdbeRealValue(Mem*);
SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem*, int*);
int sqlite3MemRealValueRC(Mem*, double*);
int sqlite3VdbeBooleanValue(Mem*, int ifNull);
void sqlite3VdbeIntegerAffinity(Mem*);
int sqlite3VdbeMemRealify(Mem*);
@@ -687,6 +687,7 @@ void sqlite3VdbePreUpdateHook(
Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int,int);
#endif
int sqlite3VdbeTransferError(Vdbe *p);
int sqlite3VdbeFindIndexKey(BtCursor*, Index*, UnpackedRecord*, int*, int);
int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
+221
View File
@@ -2003,6 +2003,10 @@ char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
zP4 = pOp->p4.pTab->zName;
break;
}
case P4_INDEX: {
zP4 = pOp->p4.pIdx->zName;
break;
}
case P4_SUBRTNSIG: {
SubrtnSig *pSig = pOp->p4.pSubrtnSig;
sqlite3_str_appendf(&x, "subrtnsig:%d,%s", pSig->selId, pSig->zAff);
@@ -5393,6 +5397,223 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
}
}
/*
** Helper function for vdbeIsMatchingIndexKey(). Return true if column
** iCol should be ignored when comparing a record with a record from
** an index on disk. The field should be ignored if:
**
** * the corresponding bit in mask is set, and
** * either:
** - bIntegrity is false, or
** - the two Mem values are both real values that differ by
** BTREE_ULPDISTORTION or fewer ULPs.
*/
static int vdbeSkipField(
Bitmask mask, /* Mask of indexed expression fields */
int iCol, /* Column of index being considered */
Mem *pMem1, /* Expected index value */
Mem *pMem2, /* Actual indexed value */
int bIntegrity /* True if running PRAGMA integrity_check */
){
#define BTREE_ULPDISTORTION 2
if( iCol>=BMS || (mask & MASKBIT(iCol))==0 ) return 0;
if( bIntegrity==0 ) return 1;
if( (pMem1->flags & MEM_Real) && (pMem2->flags & MEM_Real) ){
u64 m1, m2;
memcpy(&m1,&pMem1->u.r,8);
memcpy(&m2,&pMem2->u.r,8);
if( (m1<m2 ? m2-m1 : m1-m2) <= BTREE_ULPDISTORTION ){
return 1;
}
}
return 0;
}
/*
** This function compares the unpacked record with the current key that
** cursor pCur points to. If bInt is false, all fields for which the
** corresponding bit in parameter "mask" is set are ignored. Or, if
** bInt is true, then a difference of BTREE_ULPDISTORTION or fewer ULPs
** in real values is overlooked for fields with the corresponding bit
** set in mask.
**
** Return the usual less than zero, zero, or greater than zero if the
** remaining fields of the cursor cursor key are less than, equal to or
** greater than those in (*p).
*/
static int vdbeIsMatchingIndexKey(
BtCursor *pCur, /* Cursor open on index */
int bInt, /* True for integrity_check-style search */
Bitmask mask, /* Mask of columns to skip */
UnpackedRecord *p, /* Index key being deleted */
int *piRes /* 0 for a match, non-zero for not a match */
){
u8 *aRec = 0;
u32 nRec = 0;
Mem mem;
int rc = SQLITE_OK;
memset(&mem, 0, sizeof(mem));
mem.enc = p->pKeyInfo->enc;
mem.db = p->pKeyInfo->db;
nRec = sqlite3BtreePayloadSize(pCur);
if( nRec>0x7fffffff ){
return SQLITE_CORRUPT_BKPT;
}
/* Allocate 5 extra bytes at the end of the buffer. This allows the
** getVarint32() call below to read slightly past the end of the buffer
** if the record is corrupt. */
aRec = sqlite3MallocZero(nRec+5);
if( aRec==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
rc = sqlite3BtreePayload(pCur, 0, nRec, aRec);
}
if( rc==SQLITE_OK ){
u32 szHdr = 0; /* Size of record header in bytes */
u32 idxHdr = 0; /* Current index in header */
idxHdr = getVarint32(aRec, szHdr);
if( szHdr>98307 ){
rc = SQLITE_CORRUPT;
}else{
int res = 0; /* Result of this function call */
u32 idxRec = szHdr; /* Index of next field in record body */
int ii = 0; /* Iterator variable */
int nCol = p->pKeyInfo->nAllField;
for(ii=0; ii<nCol && rc==SQLITE_OK; ii++){
u32 iSerial = 0;
int nSerial = 0;
if( idxHdr>=szHdr ){
rc = SQLITE_CORRUPT_BKPT;
break;
}
idxHdr += getVarint32(&aRec[idxHdr], iSerial);
nSerial = sqlite3VdbeSerialTypeLen(iSerial);
if( (idxRec+nSerial)>nRec ){
rc = SQLITE_CORRUPT_BKPT;
}else{
sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &mem);
if( vdbeSkipField(mask, ii, &p->aMem[ii], &mem, bInt)==0 ){
res = sqlite3MemCompare(&mem, &p->aMem[ii], p->pKeyInfo->aColl[ii]);
if( res!=0 ) break;
}
}
idxRec += sqlite3VdbeSerialTypeLen(iSerial);
}
*piRes = res;
}
}
sqlite3_free(aRec);
return rc;
}
/*
** This is called when the record in (*p) should be found in the index
** opened by cursor pCur, but was not. This may happen as part of a DELETE
** operation or an integrity check.
**
** One reason that an exact match was not found may be the EIIB bug - that
** a text-to-float conversion may have caused a real value in record (*p)
** to be slightly different from its counterpart on disk. This function
** attempts to find the right index record. If it does find the right
** record, it leaves *pCur pointing to it and sets (*pRes) to 0 before
** returning. Otherwise, (*pRes) is set to non-zero and an SQLite error
** code returned.
**
** The algorithm used to find the correct record is:
**
** * Scan up to BTREE_FDK_RANGE entries either side of the current entry.
** If parameter bIntegrity is false, then all fields that are indexed
** expressions or virtual table columns are omitted from the comparison.
** If bIntegrity is true, then small differences in real values in
** such fields are overlooked, but they are not omitted from the comparison
** altogether.
**
** * If the above fails to find an entry and bIntegrity is false, search
** the entire index.
*/
int sqlite3VdbeFindIndexKey(
BtCursor *pCur,
Index *pIdx,
UnpackedRecord *p,
int *pRes,
int bIntegrity
){
#define BTREE_FDK_RANGE 10
int nStep = 0;
int res = 1;
int rc = SQLITE_OK;
int ii = 0;
/* Calculate a mask based on the first 64 columns of the index. The mask
** bit is set if the corresponding index field is either an expression
** or a virtual column of the table. */
Bitmask mask = 0;
for(ii=0; ii<MIN(pIdx->nColumn, BMS); ii++){
int iCol = pIdx->aiColumn[ii];
if( (iCol==XN_EXPR)
|| (iCol>=0 && (pIdx->pTable->aCol[iCol].colFlags & COLFLAG_VIRTUAL))
){
mask |= MASKBIT(ii);
}
}
/* If the mask is 0 at this point, then the index contains no expressions
** or virtual columns. So do not search for a match - return so that the
** caller may declare the db corrupt immediately. Or, if mask is non-zero,
** proceed. */
if( mask!=0 ){
/* Move the cursor back BTREE_FDK_RANGE entries. If this hits an EOF,
** position the cursor at the first entry in the index and set nStep
** to -1 so that the first loop below scans the entire index. Otherwise,
** set nStep to BTREE_FDK_RANGE*2 so that the first loop below scans
** just that many entries. */
for(ii=0; sqlite3BtreeEof(pCur)==0 && ii<BTREE_FDK_RANGE; ii++){
rc = sqlite3BtreePrevious(pCur, 0);
}
if( rc==SQLITE_DONE ){
rc = sqlite3BtreeFirst(pCur, &res);
nStep = -1;
}else{
nStep = BTREE_FDK_RANGE*2;
}
/* This loop runs at most twice to search for a key with matching PK
** fields in the index. The second iteration always searches the entire
** index. The first iteration searches nStep entries starting with the
** current cursor entry if (nStep>=0), or the entire index if (nStep<0). */
while( sqlite3BtreeCursorIsValidNN(pCur) ){
for(ii=0; rc==SQLITE_OK && (ii<nStep || nStep<0); ii++){
rc = vdbeIsMatchingIndexKey(pCur, bIntegrity, mask, p, &res);
if( res==0 || rc!=SQLITE_OK ) break;
rc = sqlite3BtreeNext(pCur, 0);
}
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
assert( res!=0 );
}
if( nStep<0 || rc!=SQLITE_OK || res==0 || bIntegrity ) break;
/* The first, non-exhaustive, search failed to find an entry with
** matching PK fields. So restart for an exhaustive search of the
** entire index. */
nStep = -1;
rc = sqlite3BtreeFirst(pCur, &res);
}
}
*pRes = res;
return rc;
}
#ifndef SQLITE_OMIT_DATETIME_FUNCS
/*
** Cause a function to throw an error if it was call from OP_PureFunc
+73 -26
View File
@@ -657,32 +657,36 @@ i64 sqlite3VdbeIntValue(const Mem *pMem){
}
/*
** Invoke sqlite3AtoF() on the text value of pMem and return the
** double result. If sqlite3AtoF() returns an error code, write
** that code into *pRC if (*pRC)!=NULL.
** This routine implements the uncommon and slower path for
** 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.
**
** The caller must ensure that pMem->db!=0 and that pMem is in
** mode MEM_Str or MEM_Blob.
** 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.
*/
SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem *pMem, int *pRC){
double val = (double)0;
int rc = 0;
assert( pMem->db!=0 );
assert( pMem->flags & (MEM_Str|MEM_Blob) );
if( pMem->z==0 ){
/* no-op */
}else if( pMem->enc==SQLITE_UTF8
&& ((pMem->flags & MEM_Term)!=0 || sqlite3VdbeMemZeroTerminateIfAble(pMem))
){
rc = sqlite3AtoF(pMem->z, &val);
}else if( pMem->n==0 ){
/* no-op */
}else if( pMem->enc==SQLITE_UTF8 ){
static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath(
Mem *pMem,
double *pValue
){
int rc = SQLITE_OK;
*pValue = 0.0;
if( pMem->enc==SQLITE_UTF8 ){
char *zCopy = sqlite3DbStrNDup(pMem->db, pMem->z, pMem->n);
if( zCopy ){
rc = sqlite3AtoF(zCopy, &val);
rc = sqlite3AtoF(zCopy, pValue);
sqlite3DbFree(pMem->db, zCopy);
}
return rc;
}else{
int n, i, j;
char *zCopy;
@@ -705,13 +709,56 @@ SQLITE_NOINLINE double sqlite3MemRealValueRC(Mem *pMem, int *pRC){
}
assert( j<=n/2 );
zCopy[j] = 0;
rc = sqlite3AtoF(zCopy, &val);
rc = sqlite3AtoF(zCopy, pValue);
if( i<n ) rc = -100;
sqlite3DbFree(pMem->db, zCopy);
}
return rc;
}
if( pRC ) *pRC = rc;
return val;
}
/*
** 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 );
assert( pMem->flags & (MEM_Str|MEM_Blob) );
if( pMem->z==0 ){
*pValue = 0.0;
return 0;
}else if( pMem->enc==SQLITE_UTF8
&& ((pMem->flags & MEM_Term)!=0 || sqlite3VdbeMemZeroTerminateIfAble(pMem))
){
return sqlite3AtoF(pMem->z, pValue);
}else if( pMem->n==0 ){
*pValue = 0.0;
return 0;
}else{
return sqlite3MemRealValueRCSlowPath(pMem, pValue);
}
}
/*
** This routine acts as a bridge from sqlite3VdbeRealValue() to
** sqlite3VdbeRealValueRC, allowing sqlite3VdbeRealValue() to avoid
** stuffing values onto the stack.
*/
static SQLITE_NOINLINE double sqlite3MemRealValueNoRC(Mem *pMem){
double r;
(void)sqlite3MemRealValueRC(pMem, &r);
return r;
}
/*
@@ -730,7 +777,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
testcase( pMem->flags & MEM_IntReal );
return (double)pMem->u.i;
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
return sqlite3MemRealValueRC(pMem, 0);
return sqlite3MemRealValueNoRC(pMem);
}else{
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
return (double)0;
@@ -854,8 +901,8 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
sqlite3_int64 ix;
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
pMem->u.r = sqlite3MemRealValueRC(pMem, &rc);
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
rc = sqlite3MemRealValueRC(pMem, &pMem->u.r);
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;
+15 -5
View File
@@ -2449,11 +2449,16 @@ void sqlite3WhereClausePrint(WhereClause *pWC){
void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
WhereInfo *pWInfo;
if( pWC ){
int nb;
SrcItem *pItem;
Table *pTab;
Bitmask mAll;
pWInfo = pWC->pWInfo;
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
Table *pTab = pItem->pSTab;
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
nb = 1+(pWInfo->pTabList->nSrc+3)/4;
pItem = pWInfo->pTabList->a + p->iTab;
pTab = pItem->pSTab;
mAll = (((Bitmask)1)<<(nb*4)) - 1;
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
sqlite3DebugPrintf(" %12s",
@@ -4167,7 +4172,12 @@ static int whereLoopAddBtree(
whereLoopOutputAdjust(pWC, pNew, rSize);
if( pSrc->fg.isSubquery ){
if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
/* Do not set btree.pOrderBy for a recursive CTE. In this case
** the ORDER BY clause does not determine the overall order that
** rows are emitted from the CTE in. */
if( (pSrc->u4.pSubq->pSelect->selFlags & SF_Recursive)==0 ){
pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
}
}else if( pSrc->fg.fromExists ){
pNew->nOut = 0;
}
+4 -4
View File
@@ -1922,8 +1922,8 @@ do_test auth-1.283 {
execsql {
REINDEX BINARY;
}
set ::authargs
} {t3_idx1 {} main {} sqlite_autoindex_t3_1 {} main {}}
lsort -unique $::authargs
} {{} main sqlite_autoindex_t3_1 t3_idx1 t3_idx2}
do_test auth-1.284 {
set ::authargs {}
execsql {
@@ -1963,8 +1963,8 @@ ifcapable tempdb {
execsql {
REINDEX BINARY;
}
set ::authargs
} {t3_idx1 {} temp {} sqlite_autoindex_t3_1 {} temp {}}
lsort -unique $::authargs
} {{} sqlite_autoindex_t3_1 t3_idx1 t3_idx2 temp}
do_test auth-1.290 {
set ::authargs {}
execsql {
+273
View File
@@ -0,0 +1,273 @@
# 2026-03-16
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains test cases for handling stale expression indexes -
# expression indexes for which the value of the expression is different
# from (though usually very close to) the value stored on disk.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix expridx1
# Check that OP_IdxDelete works when:
#
# 1.1.* The real value in the index is greater than that in the table,
# 1.2.* The real value in the index is smaller than that in the table,
# 1.3.* Duplicate distorted real values.
#
do_execsql_test 1.0.1 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b REAL);
INSERT INTO t1 VALUES(10, 10.0);
INSERT INTO t1 VALUES(15, 15.0);
INSERT INTO t1 VALUES(20, 20.0);
INSERT INTO t1 VALUES(25, 25.0);
INSERT INTO t1 VALUES(30, 30.0);
CREATE INDEX i1 ON t1((b+0.0));
}
# Return a list of rowids from table t1 for which there is no exact
# match in the index.
set idxcheck {
SELECT rowid FROM t1 AS o NOT INDEXED
WHERE NOT EXISTS (SELECT 1 FROM t1 WHERE +a=o.a AND b+0.0=o.b+0.0)
}
set root [db one {SELECT rootpage FROM sqlite_schema WHERE name='i1'}]
do_test 1.0.2 {
# Create an imposter table for index i1
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $root
db eval {
CREATE TABLE x1(b, rowid, PRIMARY KEY(b, rowid)) WITHOUT ROWID;
}
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
db one { PRAGMA integrity_check }
} ok
do_execsql_test 1.1.1 {
UPDATE x1 SET b=21.0 WHERE rowid=20;
}
do_execsql_test 1.1.1b {
PRAGMA integrity_check;
} {{row 3 missing from index i1}}
do_execsql_test 1.1.1c $idxcheck {20}
do_execsql_test 1.1.2 {
DELETE FROM t1 WHERE a=20;
} {}
do_execsql_test 1.1.3 {
PRAGMA integrity_check;
} {ok}
do_execsql_test 1.1.4 $idxcheck {}
do_execsql_test 1.2.1 {
UPDATE x1 SET b=26.0 WHERE rowid=25;
PRAGMA integrity_check;
} {
{row 3 missing from index i1}
}
do_execsql_test 1.2.2 $idxcheck {25}
do_execsql_test 1.2.3 {
DELETE FROM t1 WHERE a=25;
} {}
do_execsql_test 1.2.4 {
PRAGMA integrity_check;
} {ok}
do_execsql_test 1.2.5 $idxcheck {}
do_execsql_test 1.3.1 {
DELETE FROM t1;
INSERT INTO t1 VALUES(5, 15.0);
INSERT INTO t1 VALUES(10, 20.0);
INSERT INTO t1 VALUES(15, 20.0);
INSERT INTO t1 VALUES(20, 20.0);
INSERT INTO t1 VALUES(25, 20.0);
INSERT INTO t1 VALUES(30, 20.0);
INSERT INTO t1 VALUES(35, 25.0);
UPDATE x1 SET b=19.0 WHERE b=20.0;
PRAGMA integrity_check;
} {
{row 2 missing from index i1}
{row 3 missing from index i1}
{row 4 missing from index i1}
{row 5 missing from index i1}
{row 6 missing from index i1}
}
do_execsql_test 1.3.2 $idxcheck {10 15 20 25 30}
foreach {tn a} {
1 15 2 30 3 20 4 10 5 25
} {
do_execsql_test 1.3.3.$tn {
DELETE FROM t1 WHERE a=$a
}
}
do_execsql_test 1.3.4 {
PRAGMA integrity_check
} {ok}
do_execsql_test 1.3.5 $idxcheck {}
#-------------------------------------------------------------------------
reset_db
set nRow [expr 1000]
do_execsql_test 2.0 {
CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID;
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$nRow
)
INSERT INTO t1 SELECT i, random(), hex(randomblob(50)) FROM s;
CREATE INDEX t1c ON t1(+c);
}
set idxcheck {
SELECT a, b FROM t1 AS o NOT INDEXED
WHERE NOT EXISTS (SELECT 1 FROM t1 WHERE +a=o.a AND +b=o.b AND +c=o.c)
}
set root [db one {SELECT rootpage FROM sqlite_schema WHERE name='t1c'}]
do_test 2.1 {
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $root
db eval {
CREATE TABLE x1(a, b, c, PRIMARY KEY(c, a, b)) WITHOUT ROWID;
}
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
} {}
do_execsql_test 2.2 {
UPDATE x1 SET c=hex(randomblob(50)) WHERE (a%2)!=0
}
do_execsql_test 2.3 "
SELECT count(*) FROM ( $idxcheck )
" [expr $nRow/2]
do_test 2.4 {
for {set ii 1} {$ii<$nRow} {incr ii 2} {
execsql { DELETE FROM t1 WHERE a=$ii }
}
execsql {PRAGMA integrity_check}
} {ok}
do_execsql_test 2.5 "
SELECT count(*) FROM ( $idxcheck )
" 0
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE TABLE y1(a, b, c GENERATED ALWAYS AS (a*b) VIRTUAL);
CREATE INDEX i1 ON y1(c);
INSERT INTO y1 VALUES(2, 3);
INSERT INTO y1 VALUES(4, 5);
}
set idxcheck {
SELECT rowid FROM y1 AS o NOT INDEXED
WHERE NOT EXISTS (SELECT 1 FROM y1 WHERE +rowid=o.rowid AND c=o.c)
}
set root [db one {SELECT rootpage FROM sqlite_schema WHERE name='i1'}]
do_test 3.1 {
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $root
db eval { CREATE TABLE x1(c, rowid, PRIMARY KEY(c, rowid)) WITHOUT ROWID; }
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
} {}
do_execsql_test 3.2 {
UPDATE x1 SET c=19 WHERE rowid=2;
}
do_execsql_test 3.3 $idxcheck 2
do_execsql_test 3.4 {
DELETE FROM y1 WHERE a=4;
}
do_execsql_test 3.5 $idxcheck {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
CREATE TABLE z1(a INTEGER PRIMARY KEY, b);
CREATE INDEX z1b ON z1(b+0.0);
INSERT INTO z1 VALUES(1, 1.0);
INSERT INTO z1 VALUES(2, 4.0);
INSERT INTO z1 VALUES(3, 4.0);
INSERT INTO z1 VALUES(4, 4.0);
INSERT INTO z1 VALUES(5, 4.0);
INSERT INTO z1 VALUES(6, 4.0);
INSERT INTO z1 VALUES(7, 4.0);
INSERT INTO z1 VALUES(8, 1.0);
}
set root [db one {SELECT rootpage FROM sqlite_schema WHERE name='z1b'}]
do_test 4.1 {
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $root
db eval { CREATE TABLE x1(b, a, PRIMARY KEY(b, a)) WITHOUT ROWID; }
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
} {}
do_execsql_test 4.2 {
UPDATE x1 SET b=4.000000000000001 WHERE a=2; -- 1 ULP
UPDATE x1 SET b=4.000000000000002 WHERE a=3; -- 2 ULP
UPDATE x1 SET b=4.000000000000003 WHERE a=4; -- 3 ULP
UPDATE x1 SET b=3.9999999999999996 WHERE a=5; -- -1 ULP
UPDATE x1 SET b=3.9999999999999992 WHERE a=6; -- -2 ULP
UPDATE x1 SET b=3.9999999999999988 WHERE a=7; -- -3 ULP
}
do_execsql_test 4.3 {
PRAGMA integrity_check
} {
{index z1b stores an imprecise floating-point value for row 2}
{index z1b stores an imprecise floating-point value for row 3}
{row 4 missing from index z1b}
{index z1b stores an imprecise floating-point value for row 5}
{index z1b stores an imprecise floating-point value for row 6}
{row 7 missing from index z1b}
}
do_execsql_test 4.4 {
UPDATE z1 SET b=-4.0 WHERE b=4.0;
PRAGMA integrity_check;
} {ok}
do_execsql_test 4.5 {
UPDATE x1 SET b=-4.000000000000001 WHERE a=2; -- -1 ULP
UPDATE x1 SET b=-4.000000000000002 WHERE a=3; -- -2 ULP
UPDATE x1 SET b=-4.000000000000003 WHERE a=4; -- -3 ULP
UPDATE x1 SET b=-3.9999999999999996 WHERE a=5; -- 1 ULP
UPDATE x1 SET b=-3.9999999999999992 WHERE a=6; -- 2 ULP
UPDATE x1 SET b=-3.9999999999999988 WHERE a=7; -- 3 ULP
}
do_execsql_test 4.6 {
PRAGMA integrity_check
} {
{index z1b stores an imprecise floating-point value for row 2}
{index z1b stores an imprecise floating-point value for row 3}
{row 4 missing from index z1b}
{index z1b stores an imprecise floating-point value for row 5}
{index z1b stores an imprecise floating-point value for row 6}
{row 7 missing from index z1b}
}
finish_test
+40
View File
@@ -249,5 +249,45 @@ do_execsql_test 6.3 {
DELETE FROM aux.p1 WHERE a=123;
}
#-------------------------------------------------------------------------
# Forum: https://sqlite.org/forum/forumpost/636bd0180a
#
reset_db
do_execsql_test 7.0 {
PRAGMA foreign_keys = ON;
CREATE TABLE p1 (pid PRIMARY KEY);
CREATE TABLE c1 (cid PRIMARY KEY,
pid REFERENCES p1(pid) ON UPDATE CASCADE
);
}
do_execsql_test 7.1 {
ATTACH ':memory:' AS aux;
CREATE TABLE aux.p1 (pid PRIMARY KEY);
CREATE TABLE aux.c1 (cid PRIMARY KEY,
pid REFERENCES p1(pid) ON UPDATE CASCADE);
INSERT INTO aux.p1 VALUES (10);
INSERT INTO aux.p1 VALUES (20);
INSERT INTO aux.c1 VALUES(11, 10);
INSERT INTO aux.c1 VALUES(12, 10);
INSERT INTO aux.c1 VALUES(21, 20);
INSERT INTO aux.c1 VALUES(22, 20);
}
do_catchsql_test 7.2 {
UPDATE aux.p1 SET pid = pid * 10;
} {0 {}}
do_execsql_test 7.3 {
SELECT * FROM aux.p1;
} {100 200}
do_execsql_test 7.4 {
SELECT * FROM aux.c1;
} {11 100 12 100 21 200 22 200}
finish_test
+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 ''
+24
View File
@@ -96,6 +96,30 @@ do_execsql_test 3.3 {
SELECT * FROM x2 CROSS JOIN x1 WHERE (1234, x2.y) > (x1.a, x1.b);
} {1234 abc 1234 ABCD}
#-------------------------------------------------------------------------
# Test the fix for forum post https://sqlite.org/forum/forumpost/7a308e933d
#
do_execsql_test 4.0 {
CREATE TABLE t1 (a PRIMARY KEY, b COLLATE NOCASE) WITHOUT ROWID;
INSERT INTO t1 VALUES ('BBB', 'a');
}
do_execsql_test 4.1 {
SELECT * FROM t1 WHERE (t1.a, t1.b) <= ('BBB', 'CCC');
} {BBB a}
do_execsql_test 4.2 {
DROP TABLE t1;
CREATE TABLE t0 (c0);
INSERT INTO t0 VALUES ('True');
CREATE TABLE t1 (c0 COLLATE NOCASE, c1 PRIMARY KEY) WITHOUT ROWID;
INSERT INTO t1 VALUES ('a', 1);
INSERT INTO t1 VALUES ('a', 'True');
}
do_execsql_test 4.3 {
SELECT * FROM t0, t1 WHERE (t1.c1, t1.c0) <= (t0.c0, t0.c0);
} {True a 1 True a True}
finish_test
+2 -1
View File
@@ -445,7 +445,8 @@ do_test shell1-3.12.2-legacy {
do_test shell1-3.12.3 {
# too many arguments
catchcmd "test.db" ".indexes FOO BAD"
} {1 {Usage: .indexes ?LIKE-PATTERN?}}
} {1 {line 1: .indexes FOO BAD
line 1: ^--- unknown argument}}
# .mode MODE ?TABLE? Set output mode where MODE is one of:
# ascii Columns/rows delimited by 0x1F and 0x1E
+1 -1
View File
@@ -43,8 +43,8 @@ do_clitest dblwidth-a.sql
do_clitest vt100-a.sql
do_clitest regexp1.sql
do_clitest imposter1.sql
do_clitest dotcmd01.sql
ifcapable vtab {
do_clitest dotcmd01.sql
do_clitest import01.sql
do_clitest intck01.sql
}
+21
View File
@@ -190,5 +190,26 @@ do_execsql_test 220 {
SELECT x FROM closure ORDER BY +x;
} {1 2 3 4 5 6 7 8 9 11 13}
#-------------------------------------------------------------------------
# Forum: https://sqlite.org/forum/forumpost/deb1eadf4d677bd5
#
# For a recursive CTE, do not assume rows are delivered in the order
# specified by the ORDER BY clause. In this case ORDER BY governs the
# order in which the queue is processed, not the overall order in which
# rows are emitted by the CTE.
#
reset_db
do_execsql_test 300 {
CREATE TABLE tree(id INTEGER PRIMARY KEY, parent INTEGER);
INSERT INTO tree VALUES(3, 1);
INSERT INTO tree VALUES(2, 3);
}
do_execsql_test 310 {
WITH RECURSIVE tt(ii) AS (
VALUES(1) UNION ALL SELECT id FROM tree, tt WHERE parent=ii ORDER BY id
)
SELECT * FROM tt ORDER BY ii;
} {1 2 3}
finish_test
+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
+1
View File
@@ -68,6 +68,7 @@ gcc -c $WARNING_OPTS -std=c99 \
echo '**** Optimized -O3. Includes FTS4/5, GEOPOLY, JSON1 ******'
echo '****' $WARNING_OPTS
gcc -O3 -c $WARNING_OPTS -std=c99 \
-Wdeclaration-after-statement \
-DHAVE_STDINT_H \
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_FTS5 \