Compare commits

...

109 Commits

Author SHA1 Message Date
drh 4760a0655f The ability to DROP multiple tables (or views or indexes or triggers) at once,
as implemented by this branch, appears to work.  However, this branch adds over
1000 bytes to the code footprint.  And the changes is significant, adding risk.
The benefit of being able to drop multiple tables in a single statement is not
seen to be enough to overcome those downsides, and so there are no immediate
plans to merge this branch.

FossilOrigin-Name: 1a49788afd90fa4415c6aae4b6bbad68f9306c1df1026762a9d88bcb40e4cd8f
2024-03-04 18:02:36 +00:00
drh 313aaff7cd Remove an unused line of code.
FossilOrigin-Name: 26272590691aee8569a1ea9c233f9b0e55ece63ed167696cc1ecfe3ca2548ba1
2024-03-02 12:17:08 +00:00
drh 4859e9c642 Simplifications to multi-DROP logic.
FossilOrigin-Name: e70d6be7511837ff11deac10b335e0f613dfa6dedcab269df9ce61c8d8495d2a
2024-03-02 11:02:04 +00:00
drh 3ffea6bc31 Improved rebustness against OOM and corruption.
FossilOrigin-Name: 3992f45033d7c1eb7b2bf7790fbf301c495f3e6ef1610a8d66d7357270a227e4
2024-03-02 00:29:11 +00:00
drh c5c3cde0e3 When doing DROP TABLE or DROP INDEX, use a heap to ensure that the various
btrees are dropped in the right order for autovacuum.

FossilOrigin-Name: e5bf9556ffd1d0880cc982d389e229246d0f3ddce4264905c6a7dd9c55d735e8
2024-03-01 22:42:16 +00:00
drh 29962f9194 RTREE uses multi-DROP to erase shadow tables.
FossilOrigin-Name: cf8a58d679d0cd30bf7c9208780855f0567b5e086422d59e3254b907923e0dd1
2024-03-01 19:08:45 +00:00
drh 0809210f9d Omit unreachable branches in the parser.
FossilOrigin-Name: 90de1f73f9aaab321c0f94b41b6d76ea966d8413d5ad864311d462780e1eadcc
2024-03-01 18:05:57 +00:00
drh b3e1f4cc3c Fix harmless compiler warning.
FossilOrigin-Name: 33d3bb848b578d8e7d1029c6603785d90c399d6bc5075d306561fc3c1ab8f202
2024-03-01 15:56:51 +00:00
drh b0f9538628 Improved handling of foreign-key constraints on a multi-drop of tables.
FossilOrigin-Name: 144e332f44b266a0e594f990088faccd1f0f08fe8e84f2efc9467d99fc14e84b
2024-03-01 14:47:01 +00:00
drh 19fb027eb5 When doing a multi-drop, delete btrees beginning with the largest root page
first and working toward smaller root pages, to avoid problems with root page
renumbering due to autovacuum.

FossilOrigin-Name: 37d4c5e207888b49c224275b05abfc1f63a2d8d2133bcc8970188b15387926ef
2024-03-01 12:21:45 +00:00
drh c3004fc223 Attempt to fix multi-object DROP. Working better, but still not perfect.
FossilOrigin-Name: 02f9fc73eef80f528097581580977aae46942baac2d7fb205c52f7f25472f2a8
2024-02-29 19:40:38 +00:00
drh 6b4c974bec Add the ability to DROP one or more objects of the same class
in a single statement by listing the objects as multiple arguments to the
DROP command.

FossilOrigin-Name: 2266086cf08ee710338667d1cf0b1e81ce7380101707db272ce27124404068a0
2024-02-29 13:44:15 +00:00
stephan 91d7bd8ec7 Fix two -Werror=lto-type-mismatch warnings reported in [forum:ef62b57bd5|forum post ef62b57bd5].
FossilOrigin-Name: 803481f25020f3c25941f1e7d1a8071937820dea951e8798198b0b0fa3fb48ce
2024-02-29 10:55:02 +00:00
stephan 087e6c9ada Fix two -Werror=lto-type-mismatch warnings reported in [forum:ef62b57bd5|forum post ef62b57bd5].
FossilOrigin-Name: 29f94610dc8319709b8d3726a60e2a7a33ffbf4998c681f772da26c9701cc0b0
2024-02-29 03:45:18 +00:00
drh 09a71d8d44 Add in a VdbeCoverage() macro needed by STAT4 that should have been part of
check-in [63ef234e88857a65].

FossilOrigin-Name: d51c699ae413215d534f954c129691ef5d95d540dc5d4304cbba576c976d931c
2024-02-28 15:32:32 +00:00
drh 8597eee119 Always convert 32-bit integer literals into EP_IntValue notation, even if
they contain "_" separators.

FossilOrigin-Name: 2dfc427f676255cbe189a26bfec2405d41d31ccc4512c55b31e6e633261d7a23
2024-02-28 01:12:21 +00:00
drh b542933cba Fix an eputf() macro without its argument in the CLI.
FossilOrigin-Name: c2f5e257d2cfb91341f5261ed3924dc4ec2a6f854f3692fb416043f5c654a963
2024-02-27 20:19:32 +00:00
drh 6324cdfdcd Add an assert() to help scan-build recognize that a variable is initialized.
FossilOrigin-Name: 10d26f1ee8e7624cbb957332b4397d2f1fcdaf916acec93077f2ddd33e01f1d8
2024-02-27 19:57:31 +00:00
drh 2aea6083bd Adjust a VdbeCoverage() macro in PRAGMA integrity_check to account for the
fact that arguments to the OP_Eq opcode used are never NULL.

FossilOrigin-Name: 759ccea3f6e21493c0153f884b601988efd59e409b113b28f8cf23f59a74e418
2024-02-27 16:36:40 +00:00
drh 39670a5345 Remove unreachable branches from the PRAGMA integrity_check enhancement of
[b736519d3d2e93c7].

FossilOrigin-Name: 6d02fb233fb86f9907cc374d06a7ed71a638091d6e75abc199001c42eab51e5c
2024-02-27 15:33:54 +00:00
dan 8732fce985 Ensure memory cells are properly freed before they are overwritten by OP_IntegrityCk.
FossilOrigin-Name: e50acaf934f44f8833bc588e0ae1abd59df907b9a42d4cafd5518427a8c7b627
2024-02-27 14:31:31 +00:00
dan f8dc7d20f7 Have "PRAGMA quick_check" compare the number of entries in tables and indexes.
FossilOrigin-Name: b736519d3d2e93c76fa36253143f2664b9dd12e26acba555f0bf9c4d44705499
2024-02-27 11:03:10 +00:00
stephan 5b985fee64 Extend sqlite3.c makefile rule to support EXTRA_SRC=list-of-c-files to append to the generated sqlite3.c, as discussed in/around [forum:ccda88cf6f1754c5|forum post ccda88cf6f1754c5].
FossilOrigin-Name: 61676f1e18a405e4f3b6007488f2e68f3f55b312c107359ae5e52929f0c104c8
2024-02-27 11:02:31 +00:00
dan 1ffaa03adc Allow "_" characters to appear between any two digits in an integer, real or hexadecimal SQL literal.
FossilOrigin-Name: 0e6700f43f133510c8049b2c5a2610cb3be29da7ed4d39b1fa65dc22c4cf529b
2024-02-27 10:52:41 +00:00
stephan 32888c2b30 Bring the extra-src branch up to date with the trunk.
FossilOrigin-Name: 12ff5c5c4162951a29b638a5bc6cffa50e057c5a5e8f5e9c627af5f4ab1e4cdb
2024-02-27 00:58:51 +00:00
drh f79b0bdcbf The quote() SQL function should convert +Inf into 9.0e+999 and -Inf into
-9.0e+999.  See [forum:/forumpost/6675b25108|forum post 6675b25108].

FossilOrigin-Name: 85dd79a6edecfc8c6307c6d215998f76dab086aa14528ddc64eb9955501becfd
2024-02-26 22:28:21 +00:00
drh 7c6433cfff When inserting a 3-byte cell into a btree, ensure that the extra padding byte
is 0x00.  This is not necessary for security, as far as I can tell, but it
seems like a reasonable precaution.

FossilOrigin-Name: 5766f1279dab91e030d4dcf5133659e5cedf914a1628ccf00d67d8e50a9957fd
2024-02-26 15:27:33 +00:00
dan 09e1900cdc Add the intck extension. For performing incremental integrity-check on a database.
FossilOrigin-Name: 141d8bb059f8987d05d18327b97c4d36e98258f657b41a3d4d8877fe8b4e72e3
2024-02-26 12:16:02 +00:00
drh 1103eb423e Fix header comments on test scripts.
FossilOrigin-Name: 9fe9670c977ce7ad2c19657783a63998769dbb7741a587889c72ecc04d895793
2024-02-26 11:51:21 +00:00
drh f286ad9211 Remove a local variable from sqlite3IntFloatCompare() that was being optimized
out anyhow, in order to get back to 100% MC/DC.

FossilOrigin-Name: 52b13d6acbb738b9281f7dd44edd6c3c9585d22d98b1951b7059534fbd16fac0
2024-02-26 11:43:44 +00:00
dan afeec79847 Merge latest trunk changes into this branch.
FossilOrigin-Name: b6371ff9f5c3d4e87a5b1127a82970202f74c790b828dda20df88dd727bcc9b4
2024-02-26 10:56:54 +00:00
drh dfd991c3b9 Make sure key comprisons are done correctly if the index key contains NaN
values that have not been shifted into NULLs.  That can only happen due to
database corruption, but we need to deal with it nevertheless.

FossilOrigin-Name: 7e4c743f9e6ef33500795543e6db9a77c533025bf00c2ee97abd433a3871b5a1
2024-02-25 21:30:33 +00:00
drh 7598e7d70e Add two GIFs that contain the feather logo.
FossilOrigin-Name: 5f21e6a8ee709d8c5ec12c45e8dc702a7d0bb041f31b5715e28cd904dfd566b0
2024-02-24 19:58:15 +00:00
dan 9c59c87448 Add further tests for the intck module.
FossilOrigin-Name: c253e276b29de28a18270d01b60d95157ce3fc4b37e246d991f9119d26e718d7
2024-02-24 16:26:15 +00:00
dan ee299cc7d4 Add tests for the new code on this branch.
FossilOrigin-Name: 351d46b2373f08bc8033d0902d9f67cd6c8bcc16c0d9f787e4fb279c0a76da87
2024-02-23 20:51:06 +00:00
dan 645f21f15b Add the ".intck ?STEPS_PER_UNLOCK?" command to the shell tool.
FossilOrigin-Name: cfd051836b72f7d4e38cc9614f6ae5c003de4ce377359fd391adf06fe1ddf6b9
2024-02-23 18:21:51 +00:00
stephan b088e892a0 Typo fixes [forum:c19bbf245d|reported in the forum]. No code changes.
FossilOrigin-Name: 67d8bae0f695c0839e724c1aadea0a22f736fdd9664d40a29b4d82c91fb89ab3
2024-02-23 18:02:31 +00:00
dan 5956d1d942 Fix detection of surplus index entries when all indexed fields are NULL.
FossilOrigin-Name: 5f310fb7be450c96f01c21e6fd1377d4a274784377d0bd811922ab63e612bd11
2024-02-23 17:10:39 +00:00
dan 1545243368 Fix problems with resuming integrity-check operations on indexes with mixed ASC and DESC columns, and on indexes that contain NULL values.
FossilOrigin-Name: 0f68b35a000ef9f4691c59797c66ed6c3435fc5c503e9d24f891afec6aceeada
2024-02-23 15:13:53 +00:00
mistachkin f7ad684c5a Fix harmless compiler warning seen with MSVC.
FossilOrigin-Name: e5db08993127dfc18cc2b621a13cbfef52974f0f504f4d8208093bfad1ffdcc5
2024-02-22 18:15:08 +00:00
drh 0b8c3126f4 Fix debugging code so that it compiles on MSVC.
FossilOrigin-Name: ce5df19dc4aff3fde03ef62261a5e095a16a8f4e46e2924becea4fed56ce49e3
2024-02-22 00:50:54 +00:00
dan 639db50a02 Fix various issues in sqlite3intck.c.
FossilOrigin-Name: 8a7bfa74525a495f45b1ea212b1718633b637295090d514dd777f9263477d514
2024-02-21 20:58:48 +00:00
drh 9591a9f069 Fix typo in comment. [https://fossil-scm.org/forum/forumpost/cc20266bf2|Fossil forum post cc20266bf2].
FossilOrigin-Name: 7e3c46eed1290964a3e25662686c6ba1149bf8687d05719b684772e65d660c09
2024-02-21 20:21:46 +00:00
dan 6a00f707e8 Simplify the way the restart key is saved internally by the intck extension.
FossilOrigin-Name: 0e39962baae8a82a3021077676b792ac30c79426bcd8c075b5e92bee55e8c3a5
2024-02-21 19:31:00 +00:00
dan b783f56c58 Add documentation to ext/intck/sqlite3intck.h.
FossilOrigin-Name: 4cc19bd74f05fe92658cc392a1d1afa173d93181a77303af6bc5684436ae832e
2024-02-21 19:17:45 +00:00
dan b2897c221d Ensure intck tests are run by testrunner.tcl.
FossilOrigin-Name: 11d6816c060b6edb9cd61f29297ab95e75e2b46f29c0a796820d94fc13586f6d
2024-02-21 16:15:50 +00:00
dan ebd99d5708 Merge trunk changes into this branch.
FossilOrigin-Name: 63e8846ac1dc1cf1f7071c4634ccbfec3c13560db6afec376cd91515b62430d3
2024-02-21 16:12:23 +00:00
dan eb715f022f Have the intck extension better handle corruption at the b-tree layer.
FossilOrigin-Name: ecd775d108f77d39a1303316c1e0f0b0ae3ffc5218222e1ebfe2ef6783829b85
2024-02-20 20:18:02 +00:00
dan cfcb3b9208 Use fewer cycles to generate the "next key" value used by sqlite3_intck_suspend() function in the intck extension.
FossilOrigin-Name: 95f01426f948cf435d0b400dc7ae06fa699eee32cff498fe77e74a1257a4e09b
2024-02-20 18:17:06 +00:00
dan 626d619218 Consider using "=" and IS operators with even low-quality indexes in cases where they are selected explicitly using an INDEXED BY clause.
FossilOrigin-Name: 43cbbea82132db2d0ddb4f34cc2b6910b3a1243ae6d4e837b1b27bfe91b84834
2024-02-20 16:04:27 +00:00
drh 21eda699d7 Fixes to comments associated with the recent PRAGMA optimize enhancements.
No changes to code.

FossilOrigin-Name: 27a2113d78b35e324e9aedda7403c96c56ad0bed8c6b139fc5a179e8800b9109
2024-02-20 15:38:36 +00:00
drh b468e68322 Remove an unreachable branch from printf(). Change it into an assert().
FossilOrigin-Name: 4c9886b692706723f4b68f58dfef07ab19b192fd19b953917f23b55655af3e02
2024-02-20 13:11:27 +00:00
drh 4b2eeb289b Remove an unused variable from the merge in the previous check-in.
FossilOrigin-Name: 5c26bf379e18e28d800525bd03e2d5597e2f37674979302f351b99abfc064749
2024-02-20 13:10:46 +00:00
drh 68d92c4ad3 Enhancements to PRAGMA optimize and ANALYZE. Add the 0x10000 flag to
PRAGMA optimize.  ANALYZE now records zero-size partial indexes in the
sqlite_stat1 table.  PRAGMA optimize looks for both growth and shrinkage
in table sizes, and uses tighter bounds (10x rather than 25x) to trigger
a re-analyze.  PRAGMA optimize automatically uses are reasonable
analysis_limit to prevent excessive runtimes.

FossilOrigin-Name: 63ef234e88857a653fa3541e80d59802ceccb806ac8296e8bae79a385b7086f7
2024-02-20 12:48:00 +00:00
drh 4189c44cff Another simplification of the PRAGMA optimize logic for improved coverage.
FossilOrigin-Name: 6c5a0c85454e3c658e51fab611c169c034447174022eebc52fd8619b528a4765
2024-02-20 12:14:07 +00:00
drh ae71fa5d59 Minor fixes.
FossilOrigin-Name: ed5afebc410e3d430e2428d35f027bffb218e5f11036a42f97b080153e89016e
2024-02-19 23:58:26 +00:00
drh a1507a3fa0 Fix a minor hiccup in the computation of the number of btrees to be scanned.
FossilOrigin-Name: 91302d9b2720d6b5184e1c24db55d351544adfde4b3d2ddcdc1561f79f11985a
2024-02-19 20:47:59 +00:00
dan ebea8458e2 Use more efficient SQL to verify that indexes contain entries that match their tables.
FossilOrigin-Name: c01e008c28895e50b14531b2a1f3f1110aab3b54df41ebdbd416fbac7b1bba94
2024-02-19 20:15:44 +00:00
drh 9a28311b6a If there is no mention of a table in sqlite_stat1, use OP_Rewind to see if
the table is empty prior to invoking ANALYZE.

FossilOrigin-Name: 0cc93b19de597866292e0696f89fbd0e22a6cbb374678f5cc096fb889210fe3c
2024-02-19 20:12:30 +00:00
drh 74b0aad09f In PRAGMA optimize, scale back the analysis_limit when many different tables
and indexes must be scanned.

FossilOrigin-Name: 636615358aebfef80a657d09f15f608df9e64882b2aaa5574ce31a4f1c71fd70
2024-02-19 19:56:40 +00:00
drh f40da9226d Merge trunk fixes into the better-optimize branch.
FossilOrigin-Name: 2cf78a5b5fce7f2d49ce185d27f50722c91a1d6c91bbcecebd4bb5244a76769f
2024-02-19 18:55:32 +00:00
dan cfc62ceefd Add implementation of sqlite3_intck_suspend().
FossilOrigin-Name: c36ada868da74e030ff5002de1f3b31b639b0c43714b91c2e5ca0eda16bb6bc2
2024-02-19 18:03:53 +00:00
drh e7bdb2172c If a table has one or more rows and it has a partial index has zero rows,
still make an entry in the sqlite_stat1 table for the partial index, so that
we know that "PRAGMA optimize" does not need to redo the whole table.

FossilOrigin-Name: e147b18991dd462fff367442acb0504fdf193a31843ed34ec8c1ced30747bf8a
2024-02-19 16:22:58 +00:00
drh 6c6356f7f2 Simplifications to PRAGMA optimize to make it easier to use. It always
tries to ANALYZE unanalyzed indexes.  The 0x10000 flag just makes it check
for size changes in all tables.

FossilOrigin-Name: 44ed7f4cd07a88a2fdd303a2c78e6babe01d7344b399bd2b80ed68d75a77aaa2
2024-02-19 13:50:09 +00:00
drh 9f34a05e98 Change the 0x20000 bit (use analysis limit) to 0x10, meaning that this feature
is on by default.  The default analysis limit is changed to 2000 which is
almost always sufficient for accurate analysis results.

FossilOrigin-Name: 4abd47b5917099a2f74e53e12c987da0722304a5e9a93b6d43015c1f45c48444
2024-02-19 13:06:27 +00:00
stephan e0a9935be1 Extend the strerror_r() result type discrepancy check in os_unix.c to include the Android NDK, as reported in [forum post 3f13857fa4062301|forum:3f13857fa4062301]. The NDK's strerror_r() signature is version-dependent, whereas this change assumes int return (POSIX semantic) across all versions.
FossilOrigin-Name: f18b2524da6bbbcf372b292df52fbe6efa49fd6e1f1f13ef2447279d559f7a08
2024-02-19 12:20:46 +00:00
drh d43e7adca7 Hold a transaction during PRAGMA optimize, for performance.
FossilOrigin-Name: d13b79eae6df7f9d1f3b8062ddc75a12ff038196b3d752d2672a9925fa45ca56
2024-02-18 01:12:22 +00:00
dan 99a94a124c Add start of extension for incremental integrity-checks to ext/intck/.
FossilOrigin-Name: 444e3c9210026da7eae1ed98850722e002433aa2cc77dbc6b6f80327a6b7a390
2024-02-17 20:55:01 +00:00
drh 42eb6a91cd Add new MASK bits to PRAGMA optimize: 0x70000.
FossilOrigin-Name: dd4497062569eec9ddfdaa7d6394c83ff40a7a59c6697a161bc4ff6d8af3bb29
2024-02-17 16:39:52 +00:00
drh 6161cdd446 Fix rounding in zero-precision %f and %g printf conversions.
[forum:/info/393708f4a8|Forum post 393708f4a8].  This bug was
introduced by check-in [32befb224b254639] and first appeared in version 3.43.0.

FossilOrigin-Name: 7fca1bc482fc2456d75392eb42f768fda72631c9070de46b8123b1126e78306f
2024-02-17 03:32:31 +00:00
drh 837efb4cbe The PRAGMA optimize command invokes ANALYZE if a table shrinks by 25 times
in addition to if it grows by 25 times.

FossilOrigin-Name: 40532ffba91cf332c1ea4add80184031a9d6e10514d2d9b9a6cfd613091b81f7
2024-02-17 01:12:58 +00:00
drh 4dd59fd997 Fix the subtype on the value column from json_each/json_tree for cases
when the value is an array or object.  Fix for the bug reported by
[forum:/forumpost/ecb94cd210|forum post ecb94cd210].

FossilOrigin-Name: 1c33c5db2e05019d1a375109f79ad8588a3c17f81e4f4b8d66c880c3c860e87e
2024-02-16 21:30:08 +00:00
larrybr fd2500f98b Retweak last check-in to retain compile-time checking of xprintf() arguments.
FossilOrigin-Name: 670174916c660b24ba70e96a42984eb65ee52da50e9828bdeca4c9ff4bf92e20
2024-02-16 18:34:21 +00:00
stephan 816f677c1c Work around a __VA_ARGS__ complaint in fiddle builds.
FossilOrigin-Name: 7d750248c58ccbf87036ea7db053def1c83c7a8ed428a5c47895756302b36200
2024-02-16 16:04:31 +00:00
drh 9d00aba895 Rename the TF_StatsUsed flag to TF_MaybeReanalyze, to more accurately
reflect its usage.  No logic changes.

FossilOrigin-Name: b4790da5e0d6f0f617e6c3a17fc2606842e41cab14339392abd335410fec0aa3
2024-02-16 12:57:04 +00:00
dan 5e5831a760 Handle an OOM case in fts5 code to query tokendata=1 tables.
FossilOrigin-Name: 01222d96b9ab24c7013a2587544304ba32c1f039b08c06a04d8d58ec9c790db0
2024-02-16 11:41:47 +00:00
drh 95b5295f52 Fix a bug in PRAGMA integrity_check introduced by enhancement (8a) in
[https://sqlite.org/releaselog/3_42_0.html|release 3.42.0] and first reported by
[forum:/forumpost/ee4f6fa5ab|forum post ee4f6fa5ab].

FossilOrigin-Name: 460353dfff8f2fb03f9c8666d0c367ec7be4cfa96dfcb0cea10f144d043223bb
2024-02-13 18:41:46 +00:00
drh 54eb54c7de Changes to vtabCallConstructor() to avoid a harmless static analyzer warning
and to help prove that the UAF reported by
[forum:/forumpost/cafbe582e8|forum post cafbe582e8] is a false-positive.

FossilOrigin-Name: 4892440b93306e5a245f18c0d3d295d851e6712260e420016c0d70e12abf8901
2024-02-13 17:11:19 +00:00
drh 8e821c251d Replace the assert() that was removed by [f023cb541b5dd72c] because
[1cd5d4623f44af25] made it true again.

FossilOrigin-Name: 189a49f165dfc348a8730ad2b2288b9b2b2089b1de99fa2d515f2a90c9e7bd4e
2024-02-12 19:12:30 +00:00
dan 98a8ffb3b3 Have rtree avoid keeping a blob handle open following an error.
FossilOrigin-Name: 1cd5d4623f44af25ab4f5af580354b3ae22cf5de4109e008ca41055125bb708d
2024-02-12 16:12:25 +00:00
drh 38e0492b91 Add a new sqlite3FaultSim() to btree for better fault analysis.
FossilOrigin-Name: 2c675bd30568d3c530300beb3fcfaa17c9f063cdcb9a39ac68b9902100f641a6
2024-02-12 14:44:35 +00:00
drh 84dea8264b Add a new sqlite3FaultSim() call in the btree logic, for testing.
FossilOrigin-Name: e0558f79b8184ea6741fb20b710dab854f5bdb71aa47d5a6701eeb7389540c8c
2024-02-12 13:51:08 +00:00
drh b29047838d Add support for the ".testctrl fault_install" dot-command in the CLI when
launched with the --unsafe-testing option.

FossilOrigin-Name: 5ba7fee1a9b49df82387e355d2ab7de58663d3fa824e50717608b27e0f7ac874
2024-02-12 13:28:10 +00:00
drh 18b6019cdd In the RTREE extension, allow the xBeginTransaction() entry point to be
invoked multiple times without intervening calls to xEndTransaction().

FossilOrigin-Name: f023cb541b5dd72c996f0574210344179217666a2229bc8d3fe057fdbc5c2245
2024-02-11 22:56:12 +00:00
drh 3c5a810646 If a term of an ORDER BY or GROUP BY contains an aggregate function or column,
then it is not an alias that needs to be resolved, so don't try to.  This fixes
a harmless assertion found by dbsqlfuzz.  This yet another problem that
orginated at check-in [6e6b3729e0549de0].

FossilOrigin-Name: d4ec2a5d2297cd9ead0a8768dcf003ea76c74d8d68d88c40f62363f484a4a4d3
2024-02-11 20:53:14 +00:00
drh ece3567aec Improved AggInfo tracing in debug builds. No changes to deliverable code.
FossilOrigin-Name: bb31f9c44794e02a46ed3edbcc96eb48c5870d3f82cb404586ded9a3efa7a859
2024-02-11 18:53:48 +00:00
larrybr 589c407f12 Further clarify sqlite3_exec() callback parameter lifetime.
FossilOrigin-Name: 993a1a843177b19a9cb5598f57d1e05c01e1695f164faaa9ae22810ad4533eba
2024-02-10 03:11:42 +00:00
larrybr 25e172d429 Mention limited lifetime of string arrays passed to sqlite3_exec() callback.
FossilOrigin-Name: 717f67f3189a59842f5c17a25e8db0e24ec4405886fc22ab6eeb3954fba5a964
2024-02-08 01:19:46 +00:00
drh 0f777cd622 Fix an #endif (added in the wrong place by [8f4b1ceafe4a271b]) so that
the build works with SQLITE_OMIT_VIRTUAL_TABLE.

FossilOrigin-Name: 7070924eebce1d089fde911dc0427ab8f3764d57ace24caff2b79954b42d1b51
2024-02-07 20:45:38 +00:00
drh 722bd1fe89 Bring test cases into alignment with the latest enhancements.
FossilOrigin-Name: cd017c28d516399e25b5ee9e8fcd7390ca2be9128c7c41f1007f37bc01a35717
2024-02-07 19:52:03 +00:00
drh 204b41955e Turns out the branch is reachable, so back out the NEVER().
FossilOrigin-Name: 0af36a3223d2dabda887830390a603ab4781baca7e2f1698ec6c5f2cf03faf04
2024-02-07 19:17:44 +00:00
drh 71cdea8f5f Detect and respond to an OOM on the jsonStringTerminate() call of
jsonReturnStringAsBlob() routine.

FossilOrigin-Name: 881f814c09b6896a448a2360b0b43dc99592ea3a1d72ac359770cbb0a2c7d38a
2024-02-07 14:05:38 +00:00
drh 8babc01892 Slight change to OOM handling in JSON to catch a corner case found by
dbsqlfuzz.

FossilOrigin-Name: 6a2b3266c586d12b51e11fe63cda5881be9373207aa16671ab77f547830eb790
2024-02-06 18:33:01 +00:00
stephan 72c7bb3e1a Correct docs about the first OFPS VFS's importDb() method being synchronous (it's not, whereas the second VFS's importDb() is).
FossilOrigin-Name: ae7505fa5e112f39a329befb35eff6ddf46a53f5deb610906550bf67f56fc157
2024-02-06 08:59:59 +00:00
stephan db9cc74c9c Make explicit that using the importDb() methods of the OPFS VFSes has undefined results if the being-imported db is currently open. Doc changes only.
FossilOrigin-Name: f28b9924b401b359e59a73918a34b29cde719164a6b4ac5a9d23da6294b701bd
2024-02-06 08:25:23 +00:00
dan 5e922865aa Return SQLITE_ABORT if the underlying shadow tables change in the middle of an rtree query in such a way as to invalidate an rtree internal priority queue entry. This replaces the SQLITE_ABORT_ROLLBACK mechanism added in [af5c4251].
FossilOrigin-Name: 32f85a5ce8e32506ad0cf309c86589958f38d924b4b3de532bec8bdb8e385fad
2024-02-05 17:54:03 +00:00
dan d90ecb5d6e Have "PRAGMA quick_check" compare the number of entries in tables and indexes.
FossilOrigin-Name: cc294c041b4c7a044ff344989f872415ced5263a0b654112371b2da7c852a688
2024-02-02 16:51:24 +00:00
dan 406eb5a146 Add extra checks for the validity of a numeric literal to sqlite3DequoteNumber().
FossilOrigin-Name: d57407ef59baf699b72c8c4859abfaa7977dd41f6f16eb8fe1d53a68806eb966
2024-01-23 11:20:58 +00:00
dan a545de6827 Fix a problem in the previous commit with hex literals that start with "0X" instead of "0x".
FossilOrigin-Name: c063c89b11487e6e712b97de604db316fa97bcf91ed810bb2dcbbcb54c68dbf4
2024-01-22 19:42:56 +00:00
dan 8374f7dfaf Allow underscores to occur in hex literals.
FossilOrigin-Name: 81a56229460cc5b6acfd3c3729fcf89ea3cccb546ca2b4f4035b140c60911e18
2024-01-22 19:38:55 +00:00
dan fbb72fae8f Add extra tests for the code on this branch.
FossilOrigin-Name: b15bbb201a7727806b9fd6c02f2579b01e0e38155a8f9e24c5d6f487fe3e8b6c
2024-01-22 19:00:50 +00:00
drh 87ad06ed99 Do not allow digit separators that are not surrounded on both sides by digits.
FossilOrigin-Name: 5bbc378a3022e2013048c8e296d95de21d15a8d7c1b62e8ffb64782f952cfe12
2024-01-22 17:18:41 +00:00
dan 17589f7811 Fix test script literal.test so that it works with SQLITE_OMIT_ALTER_TABLE builds.
FossilOrigin-Name: b57327be4be9638f5ee834a6c9e06135aaef9e499516f8b53f927ffe81033f61
2024-01-22 11:12:38 +00:00
dan b75dc61a53 Merge trunk changes into this branch.
FossilOrigin-Name: 03ade4a810516ff84bc5c1a716b0e454cc8a89374100415ff21a82449112811b
2024-01-20 18:45:30 +00:00
dan 95295a7e9b Add test cases for the new code on this branch.
FossilOrigin-Name: 49f29a7b4f44f691ecf7a57b26477971e6ffaf2a0b1690b4926ffbb43fa3929b
2024-01-20 16:46:25 +00:00
dan 3eae6664a0 Allow "_" characters to appear following any digit in an integer or real SQL literal.
FossilOrigin-Name: 401650aaccbc99246bd4e1ff37a28b78f528178aee2f294d87b9f7fecd7432bb
2024-01-20 16:18:04 +00:00
stephan 45cf8ad02a In mksqlite3c.tcl, pass EXTRA_SRC files through verbatim instead of applying the post-processing needed for sqlite's own source files.
FossilOrigin-Name: 44f3d7d054055fab4cca0ba753e75e237ca159ae868ffd1d13ed45a874a772f2
2023-09-03 15:01:11 +00:00
mistachkin 2065a9b730 Also add support for EXTRA_SRC in the Makefile for MSVC.
FossilOrigin-Name: bfc18ef4323cd73fc63cb93f18bdd9c3add41bea83c1cbc1c20de5c1e4296a60
2023-09-02 21:55:10 +00:00
stephan 87ac2b043a Add EXTRA_SRC build var. If set, it is treated like a list of files, each of which gets appended verbatim to sqlite3.c. The intent is to enable easily extending the amalgamation. Requested in/around [forum:3fcc655f0ac0efe8|forum post 3fcc655f0ac0efe8].
FossilOrigin-Name: 934b84339860fa84a6faa3507bdd3cc58199e2636a394fc93176c80da0ba6f1c
2023-09-02 05:37:58 +00:00
81 changed files with 4018 additions and 590 deletions
+6 -2
View File
@@ -418,6 +418,8 @@ TESTSRC = \
$(TOP)/ext/recover/sqlite3recover.c \
$(TOP)/ext/recover/dbdata.c \
$(TOP)/ext/recover/test_recover.c \
$(TOP)/ext/intck/test_intck.c \
$(TOP)/ext/intck/sqlite3intck.c \
$(TOP)/ext/rbu/test_rbu.c
# Statically linked extensions
@@ -815,7 +817,8 @@ has_tclsh85:
touch .target_source
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl src-verify has_tclsh84
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS)
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS) \
$(EXTRA_SRC)
cp tsrc/sqlite3ext.h .
cp $(TOP)/ext/session/sqlite3session.h .
@@ -826,7 +829,8 @@ sqlite3r.c: sqlite3.c sqlite3r.h has_tclsh84
cp $(TOP)/ext/recover/sqlite3recover.c tsrc/
cp $(TOP)/ext/recover/sqlite3recover.h tsrc/
cp $(TOP)/ext/recover/dbdata.c tsrc/
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl --enable-recover $(AMALGAMATION_LINE_MACROS)
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl --enable-recover \
$(AMALGAMATION_LINE_MACROS) $(EXTRA_SRC)
sqlite3ext.h: .target_source
cp tsrc/sqlite3ext.h .
+10 -1
View File
@@ -18,6 +18,13 @@ USE_AMALGAMATION = 1
!ENDIF
# <</mark>>
# Optionally set EXTRA_SRC to a list of C files to append to
# the generated sqlite3.c.
#
!IFNDEF EXTRA_SRC
EXTRA_SRC =
!ENDIF
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
#
!IFNDEF USE_FULLWARN
@@ -1595,6 +1602,8 @@ TESTEXT = \
$(TOP)\ext\rtree\test_rtreedoc.c \
$(TOP)\ext\recover\sqlite3recover.c \
$(TOP)\ext\recover\test_recover.c \
$(TOP)\ext\intck\test_intck.c \
$(TOP)\ext\intck\sqlite3intck.c \
$(TOP)\ext\recover\dbdata.c
# If use of zlib is enabled, add the "zipfile.c" source file.
@@ -1913,7 +1922,7 @@ mptest: mptester.exe
echo > .target_source
sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) src-verify.exe
$(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS)
$(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS) $(EXTRA_SRC)
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl
$(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

+7
View File
@@ -18,6 +18,13 @@
TOP = .
# Optionally set EXTRA_SRC to a list of C files to append to
# the generated sqlite3.c.
#
!IFNDEF EXTRA_SRC
EXTRA_SRC =
!ENDIF
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
#
!IFNDEF USE_FULLWARN
+7 -4
View File
@@ -6837,23 +6837,26 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){
int ii;
Fts5TokenDataIter *pT = pIter->pTokenDataIter;
Fts5Index *pIndex = pIter->pIndex;
for(ii=0; ii<pT->nIter; ii++){
Fts5Iter *p = pT->apIter[ii];
if( p->base.bEof==0
&& (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom))
){
fts5MultiIterNext(p->pIndex, p, bFrom, iFrom);
fts5MultiIterNext(pIndex, p, bFrom, iFrom);
while( bFrom && p->base.bEof==0
&& p->base.iRowid<iFrom
&& p->pIndex->rc==SQLITE_OK
&& pIndex->rc==SQLITE_OK
){
fts5MultiIterNext(p->pIndex, p, 0, 0);
fts5MultiIterNext(pIndex, p, 0, 0);
}
}
}
fts5IterSetOutputsTokendata(pIter);
if( pIndex->rc==SQLITE_OK ){
fts5IterSetOutputsTokendata(pIter);
}
}
/*
+10 -1
View File
@@ -127,7 +127,7 @@ do_execsql_test 3.0 {
COMMIT;
}
do_faultsim_test 3 -faults oom* -prep {
do_faultsim_test 3.1 -faults oom* -prep {
} -body {
execsql {
SELECT rowid FROM t1('BBB AND AAA');
@@ -136,6 +136,15 @@ do_faultsim_test 3 -faults oom* -prep {
faultsim_integrity_check
faultsim_test_result {0 {10 35}}
}
do_faultsim_test 3.2 -faults oom* -prep {
} -body {
execsql {
SELECT count(*) FROM t1('BBB');
}
} -test {
faultsim_integrity_check
faultsim_test_result {0 27}
}
finish_test
+331
View File
@@ -0,0 +1,331 @@
# 2008 Feb 19
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# The focus of this file is testing the incremental integrity check
# (intck) extension.
#
source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intck1
foreach {tn sql} {
1 "CREATE TABLE t1(a PRIMARY KEY, b)"
2 "CREATE TABLE t2(a PRIMARY KEY, b) WITHOUT ROWID "
3 "CREATE TABLE t3(a PRIMARY KEY, b) WITHOUT rowID;"
4 "CREATE TABLE t4(a PRIMARY KEY, ROWID)"
5 {CREATE TABLE t5(a PRIMARY KEY, ROWID) WITHOUT ROWID
}
} {
do_test 1.1.$tn {
db eval $sql
set {} {}
} {}
}
set space " \n\v\t\r\f"
do_execsql_test 1.2 {
SELECT name, (rtrim(sql, $space) LIKE '%rowid')
FROM sqlite_schema WHERE type='table'
ORDER BY 1
} {
t1 0
t2 1
t3 1
t4 0
t5 1
}
do_execsql_test 1.3 {
CREATE TABLE x1(a COLLATE nocase, b INTEGER, c BLOB);
INSERT INTO x1 VALUES('lEtTeRs', 1234, 1234);
}
do_execsql_test 1.3.1 {
WITH wrapper(c1, c2, c3) AS (
SELECT a, b, c FROM x1
)
SELECT * FROM wrapper WHERE c1='letters';
} {lEtTeRs 1234 1234}
do_execsql_test 1.3.2 {
WITH wrapper(c1, c2, c3) AS (
SELECT a, b, c FROM x1
)
SELECT * FROM wrapper WHERE c2='1234';
} {lEtTeRs 1234 1234}
do_execsql_test 1.3.2 {
WITH wrapper(c1, c2, c3) AS (
SELECT a, b, c FROM x1
)
SELECT * FROM wrapper WHERE c3='1234';
} {}
do_execsql_test 1.4 {
CREATE TABLE z1(a, b);
CREATE INDEX z1ab ON z1(a+b COLLATE nocase);
}
do_execsql_test 1.4.1 {
SELECT * FROM z1 INDEXED BY z1ab
}
do_catchsql_test 1.5.1 {
CREATE INDEX z1b ON z1(b ASC NULLS LAST);
} {1 {unsupported use of NULLS LAST}}
do_catchsql_test 1.5.2 {
CREATE INDEX z1b ON z1(b DESC NULLS LAST);
} {1 {unsupported use of NULLS LAST}}
do_catchsql_test 1.5.3 {
CREATE INDEX z1b ON z1(b ASC NULLS FIRST);
} {1 {unsupported use of NULLS FIRST}}
do_catchsql_test 1.5.4 {
CREATE INDEX z1b ON z1(b DESC NULLS FIRST);
} {1 {unsupported use of NULLS FIRST}}
reset_db
do_execsql_test 1.6.1 {
CREATE TABLE t1(i INTEGER PRIMARY KEY, b, c);
CREATE INDEX i1 ON t1(b);
ANALYZE;
INSERT INTO sqlite_stat1 VALUES('t1', 'i1', '10000 10000');
ANALYZE sqlite_schema;
} {}
do_eqp_test 1.6.2 {
SELECT 1 FROM t1 INDEXED BY i1 WHERE (b, i) IS (?, ?);
} {SEARCH}
#-------------------------------------------------------------------------
reset_db
do_test 2.0 {
set ic [sqlite3_intck db main]
$ic close
} {}
do_execsql_test 2.1 {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
CREATE INDEX i1 ON t1(a COLLATE nocase);
CREATE INDEX i2 ON t1(b, a);
CREATE INDEX i3 ON t1(b + a COLLATE nocase) WHERE a!=1;
}
do_intck_test 2.2 {
}
# Delete a row from each of the i1 and i2 indexes using the imposter
# table interface.
#
do_test 2.3 {
db eval {SELECT name, rootpage FROM sqlite_schema} {
set R($name) $rootpage
}
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $R(i1)
db eval { CREATE TABLE imp1(a PRIMARY KEY, rowid) WITHOUT ROWID; }
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $R(i2)
db eval { CREATE TABLE imp2(b, a, rowid, PRIMARY KEY(b, a)) WITHOUT ROWID; }
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
db eval {
DELETE FROM imp1 WHERE rowid=1;
DELETE FROM imp2 WHERE rowid=2;
}
db close
sqlite3 db test.db
} {}
do_intck_test 2.4 {
{entry (1,1) missing from index i1}
{entry (4,3,2) missing from index i2}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE TABLE x1(a, b, c, PRIMARY KEY(c, b)) WITHOUT ROWID;
CREATE INDEX x1a ON x1(a COLLATE nocase);
INSERT INTO x1 VALUES(1, 2, 'three');
INSERT INTO x1 VALUES(4, 5, 'six');
INSERT INTO x1 VALUES(7, 8, 'nine');
}
do_intck_test 3.1 { }
do_test 3.2 {
db eval {SELECT name, rootpage FROM sqlite_schema} {
set R($name) $rootpage
}
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $R(x1a)
db eval { CREATE TABLE imp1(c, b, a, PRIMARY KEY(c, b)) WITHOUT ROWID }
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
db eval {
DELETE FROM imp1 WHERE a=5;
}
execsql_pp {
}
db close
sqlite3 db test.db
} {}
do_intck_test 3.3 {
{entry (4,'six',5) missing from index x1a}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
CREATE TABLE www(x, y, z);
CREATE INDEX w1 ON www( (x+1), z );
INSERT INTO www VALUES(1, 1, 1), (2, 2, 2);
}
do_intck_test 4.1 { }
#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a COLLATE NOCASE);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t1 VALUES(2, 2);
}
do_test 5.1 {
set ic [sqlite3_intck db nosuchdb]
$ic step
} {SQLITE_ERROR}
do_test 5.2 {
$ic close
set ic [sqlite3_intck db {}]
while {[$ic step]=="SQLITE_OK"} {}
set res [$ic error]
$ic close
set res
} {SQLITE_OK {}}
do_test 5.3 { test_do_intck db "main" } {}
do_test 5.4 {
set ret {}
set ic [sqlite3_intck db main]
db eval [$ic test_sql t1] {
if {$error_message!=""} { lappend ret $error_message }
}
$ic close
set ret
} {}
do_test 5.5 {
set ret {}
set ic [sqlite3_intck db main]
db eval [$ic test_sql {}] {
if {$error_message!=""} { lappend ret $error_message }
}
$ic close
set ret
} {}
db cache flush
do_test 5.6 {
set ret {}
set ic [sqlite3_intck db main]
$ic step
db eval [$ic test_sql {}] {
if {$error_message!=""} { lappend ret $error_message }
}
$ic close
set ret
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
CREATE TABLE t1(x, y, PRIMARY KEY(x)) WITHOUT ROWID;
CREATE INDEX i1 ON t1(y, x);
INSERT INTO t1 VALUES(X'0000', X'1111');
}
do_intck_test 6.1 {}
do_execsql_test 6.2.1 {
PRAGMA writable_schema = 1;
UPDATE sqlite_schema SET sql = 'CREATE INDEX i1' WHERE name='i1';
} {}
do_intck_test 6.2.2 {}
do_execsql_test 6.3.1 {
UPDATE sqlite_schema SET sql = 'CREATE INDEX i1(y' WHERE name='i1';
} {}
do_intck_test 6.3.2 {}
do_execsql_test 6.4.1 {
UPDATE sqlite_schema
SET sql = 'CREATE INDEX i1(y) hello world'
WHERE name='i1';
} {}
do_intck_test 6.4.2 {}
do_execsql_test 6.5.1 {
UPDATE sqlite_schema
SET sql = 'CREATE INDEX i1(y, x) WHERE 1 '
WHERE name='i1';
} {}
do_intck_test 6.5.2 {}
do_execsql_test 6.6.1 {
UPDATE sqlite_schema
SET sql = 'CREATE INDEX i1( , ) WHERE 1 '
WHERE name='i1';
} {}
do_test 6.7.2 {
set ic [sqlite3_intck db main]
$ic step
} {SQLITE_ERROR}
do_test 6.5.3 {
$ic error
} {SQLITE_ERROR {near "AS": syntax error}}
$ic close
do_execsql_test 6.6.1 {
UPDATE sqlite_schema
SET sql = 'CREATE INDEX i1([y'
WHERE name='i1';
} {}
do_intck_test 6.6.2 {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 7.0 {
CREATE TABLE x1("1", "22", "3333", four);
CREATE INDEX i1 ON x1( "1" , "22", NULL);
INSERT INTO x1 VALUES(1, 22, 3333, NULL);
INSERT INTO x1 VALUES(1, 22, 3333, NULL);
}
do_execsql_test 7.1 " CREATE INDEX i2 ON x1( \"1\"\r\n\t ) "
do_execsql_test 7.2 { CREATE INDEX i3 ON x1( "22" || 'abc''def' || `1` ) }
do_execsql_test 7.3 { CREATE INDEX i4 ON x1( [22] + [1] ) }
do_execsql_test 7.4 { CREATE INDEX i5 ON x1( four||'hello' ) }
do_intck_test 7.5 {}
finish_test
+176
View File
@@ -0,0 +1,176 @@
# 2024 Feb 19
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# The focus of this file is testing the incremental integrity check
# (intck) extension.
#
source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intck2
do_execsql_test 1.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
INSERT INTO t1 VALUES(3, 'three');
CREATE INDEX i1 ON t1(b);
}
proc imposter_edit {obj create sql} {
sqlite3 xdb test.db
set pgno [xdb one {SELECT rootpage FROM sqlite_schema WHERE name=$obj}]
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER xdb main 1 $pgno
xdb eval $create
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER xdb main 0 0
xdb eval $sql
xdb close
}
imposter_edit i1 {
CREATE TABLE imp(b, a, PRIMARY KEY(b)) WITHOUT ROWID;
} {
DELETE FROM imp WHERE b='two';
INSERT INTO imp(b, a) VALUES('four', 4);
}
do_intck_test 1.1 {
{surplus entry ('four',4) in index i1}
{entry ('two',2) missing from index i1}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE TABLE x1(a, b, "c d");
CREATE INDEX x1a ON x1(a COLLATE nocase DESC , b ASC);
CREATE INDEX x1b ON x1( a || b || ' "''" ' COLLATE binary ASC );
CREATE INDEX x1c ON x1( format('%s', a)ASC, format('%d', "c d" ) );
INSERT INTO x1 VALUES('one', 2, 3);
INSERT INTO x1 VALUES('One', 4, 5);
INSERT INTO x1 VALUES('ONE', 6, 7);
INSERT INTO x1 VALUES(NULL, NULL, NULL);
}
do_intck_test 2.1 {}
imposter_edit x1 {
CREATE TABLE imp(a, b, c);
} {
DELETE FROM imp WHERE c=7;
}
do_intck_test 2.2 {
{surplus entry ('ONE',6,3) in index x1a}
{surplus entry ('ONE6 "''" ',3) in index x1b}
{surplus entry ('ONE','7',3) in index x1c}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE TABLE x1(a, b, c);
CREATE INDEX x1all ON x1(a DESC, b ASC, c DESC);
INSERT INTO x1 VALUES(2, 1, 2);
INSERT INTO x1 VALUES(2, 1, 1);
INSERT INTO x1 VALUES(2, 2, 2);
INSERT INTO x1 VALUES(2, 2, 1);
INSERT INTO x1 VALUES(1, 1, 2);
INSERT INTO x1 VALUES(1, 1, 1);
INSERT INTO x1 VALUES(1, 2, 2);
INSERT INTO x1 VALUES(1, 2, 1);
}
do_intck_test 3.1 {
}
imposter_edit x1 {
CREATE TABLE imp(a, b, c);
} {
DELETE FROM imp WHERE 1;
}
db close
sqlite3 db test.db
do_intck_test 3.2 {
{surplus entry (2,1,2,1) in index x1all}
{surplus entry (2,1,1,2) in index x1all}
{surplus entry (2,2,2,3) in index x1all}
{surplus entry (2,2,1,4) in index x1all}
{surplus entry (1,1,2,5) in index x1all}
{surplus entry (1,1,1,6) in index x1all}
{surplus entry (1,2,2,7) in index x1all}
{surplus entry (1,2,1,8) in index x1all}
}
do_execsql_test 3.3 {
DELETE FROM x1;
INSERT INTO x1 VALUES(NULL, NULL, NULL);
INSERT INTO x1 VALUES(NULL, NULL, NULL);
INSERT INTO x1 VALUES(NULL, NULL, NULL);
INSERT INTO x1 VALUES(NULL, NULL, NULL);
}
do_intck_test 3.4 {
}
imposter_edit x1 {
CREATE TABLE imp(a, b, c);
} {
DELETE FROM imp WHERE 1;
INSERT INTO imp(rowid) VALUES(-123);
INSERT INTO imp(rowid) VALUES(456);
}
db close
sqlite3 db test.db
do_intck_test 3.5 {
{entry (NULL,NULL,NULL,-123) missing from index x1all}
{entry (NULL,NULL,NULL,456) missing from index x1all}
{surplus entry (NULL,NULL,NULL,1) in index x1all}
{surplus entry (NULL,NULL,NULL,2) in index x1all}
{surplus entry (NULL,NULL,NULL,3) in index x1all}
{surplus entry (NULL,NULL,NULL,4) in index x1all}
}
reset_db
do_execsql_test 3.6 {
CREATE TABLE w1(a PRIMARY KEY, b, c);
INSERT INTO w1 VALUES(1.0, NULL, NULL);
INSERT INTO w1 VALUES(33.0, NULL, NULL);
INSERT INTO w1 VALUES(100.0, NULL, NULL);
CREATE INDEX w1bc ON w1(b, c);
}
do_intck_test 3.7 {
}
imposter_edit w1 {
CREATE TABLE imp(a, b, c);
} {
DELETE FROM imp WHERE a=33;
INSERT INTO imp(a) VALUES(1234.5);
INSERT INTO imp(a) VALUES(-1234.5);
}
do_intck_test 3.8 {
{surplus entry (33.0,2) in index sqlite_autoindex_w1_1}
{entry (1234.5,4) missing from index sqlite_autoindex_w1_1}
{entry (NULL,NULL,4) missing from index w1bc}
{entry (-1234.5,5) missing from index sqlite_autoindex_w1_1}
{entry (NULL,NULL,5) missing from index w1bc}
{surplus entry (NULL,NULL,2) in index w1bc}
}
finish_test
+56
View File
@@ -0,0 +1,56 @@
# 2024 Feb 18
#
# 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.
#
#***********************************************************************
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source $testdir/tester.tcl
proc do_intck {db {bSuspend 0}} {
set ic [sqlite3_intck $db main]
set ret [list]
while {"SQLITE_OK"==[$ic step]} {
set msg [$ic message]
if {$msg!=""} {
lappend ret $msg
}
if {$bSuspend} {
$ic unlock
#puts "SQL: [$ic test_sql {}]"
#execsql_pp "EXPLAIN query plan [$ic test_sql {}]"
#explain_i [$ic test_sql {}]
}
}
set err [$ic error]
if {[lindex $err 0]!="SQLITE_OK"} {
error $err
}
$ic close
return $ret
}
proc intck_sql {db tbl} {
set ic [sqlite3_intck $db main]
set sql [$ic test_sql $tbl]
$ic close
return $sql
}
proc do_intck_test {tn expect} {
uplevel [list do_test $tn.a [list do_intck db] [list {*}$expect]]
uplevel [list do_test $tn.b [list do_intck db 1] [list {*}$expect]]
}
+48
View File
@@ -0,0 +1,48 @@
# 2024 February 24
#
# 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.
#
#***********************************************************************
#
source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intckbusy
do_execsql_test 1.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES(2, 'two', 'three');
INSERT INTO t1 VALUES(3, NULL, NULL);
CREATE INDEX i1 ON t1(b, c);
}
sqlite3 db2 test.db
do_execsql_test -db db2 1.1 {
BEGIN EXCLUSIVE;
INSERT INTO t1 VALUES(4, 5, 6);
}
do_test 1.2 {
set ic [sqlite3_intck db main]
$ic step
} {SQLITE_BUSY}
do_test 1.3 {
$ic unlock
} {SQLITE_BUSY}
do_test 1.4 {
$ic error
} {SQLITE_BUSY {database is locked}}
do_test 1.4 {
$ic close
} {}
finish_test
+235
View File
@@ -0,0 +1,235 @@
# 2024 Feb 21
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# The focus of this file is testing the intck extensions response
# to corruption at the b-tree level.
#
source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intckcorrupt
#-------------------------------------------------------------------------
reset_db
do_test 1.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
| size 356352 pagesize 4096 filename crash-acaae0347204ae.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 d0 00 00 00 .....@ ........
| 32: 40 00 ea 00 00 00 00 00 00 40 00 00 00 40 00 00 @........@...@..
| 96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ...............O
| 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^...
| 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par
| 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE
| 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa
| 3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rent.(nodeno INT
| 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
| 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q...
| 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node
| 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T
| 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n
| 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR
| 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data).
| 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_
| 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR
| 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r
| 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE
| 3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY,
| 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q..
| 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C
| 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA
| 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr
| 4064: 65 65 28 69 64 2c 78 30 20 50 52 49 4d 41 52 59 ee(id,x0 PRIMARY
| 4080: 20 4b 45 59 2c 70 61 72 65 6e 74 6e 6f 64 65 29 KEY,parentnode)
| page 2 offset 4096
| 0: 51 03 06 17 1b 1b 01 7b 74 61 62 6c 65 74 31 5f Q.......tablet1_
| 16: 6e 6f 64 65 74 31 5f 6e 6f 64 65 03 43 52 45 41 nodet1_node.CREA
| 32: 54 45 20 54 41 42 4c 45 20 22 74 31 5f 6e 6f 64 TE TABLE .t1_nod
| 48: 65 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 45 47 45 e.(nodeno INTEGE
| 64: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 64 61 R PRIMARY KEY,da
| 80: 74 61 29 5c 02 07 17 1d 1d 01 81 0b 74 61 62 6c ta).........tabl
| 96: 65 74 31 5f 72 6f 77 69 64 74 31 5f 72 6f 77 69 et1_rowidt1_rowi
| 112: 64 02 43 52 45 41 54 45 20 54 41 42 4c 45 00 00 d.CREATE TABLE..
| 128: 01 0a 02 00 00 00 01 0e 0d 00 00 00 00 24 0e 0d .............$..
| 144: 0c 1a 06 85 50 46 60 27 70 08 00 00 00 00 00 00 ....PF`'p.......
| 3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f ..............to
| 3840: 79 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 y half.....#.bot
| 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72 tom half.....!.r
| 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half.......
| 3888: 6c 65 66 74 20 43 15 f6 e6 f6 46 50 34 35 24 54 left C....FP45$T
| 3904: 15 44 52 05 44 14 24 c4 52 02 27 43 15 f6 e6 f6 .DR.D.$.R.'C....
| 3920: 46 52 22 8e 6f 64 65 6e 6f 20 49 4e 54 45 47 45 FR..odeno INTEGE
| 3936: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 64 61 R PRIMARY KEY,da
| 3952: 74 61 29 5c 02 07 17 1d 1d 01 81 0b 74 61 62 6c ta).........tabl
| 3968: 65 74 31 5f 72 6f 74 74 6f 6d 20 65 64 67 65 0f et1_rottom edge.
| 3984: 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 65 ....!.right edge
| 4000: 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 65 .......left edge
| 4016: 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 05 .......center...
| 4032: 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 20 ..1.upper-right
| 4048: 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f 77 corner.....1.low
| 4064: 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 16 er-right corner.
| 4080: 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 74 ..../.upper-left
| page 3 offset 8192
| 0: 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 01 8c 6f corner...../..o
| 16: 77 65 72 2d 6c 53 51 4c 69 74 65 20 66 6f 72 6d wer-lSQLite form
| 32: 61 74 20 33 00 10 00 01 01 00 40 20 20 00 00 00 at 3......@ ...
| 48: 00 00 00 00 2f 00 00 0d eb 13 00 00 00 03 00 00 ..../...........
| 64: 00 04 00 00 00 00 00 00 00 06 00 00 00 01 00 00 ................
| 80: 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
| page 6 offset 20480
| 128: 00 00 00 00 00 00 00 00 97 3d 04 ae 7c 01 00 00 .........=..|...
| 624: 00 00 00 00 00 00 21 97 3d 04 ae 7c 01 00 00 00 ......!.=..|....
| 1120: 00 00 00 00 00 20 97 3d 04 ae 7c 01 00 00 00 00 ..... .=..|.....
| 1616: 00 00 00 00 1f 97 3d 04 ae 7c 01 00 00 00 00 00 ......=..|......
| 2112: 00 00 00 1e 97 3d 04 ae 7c 01 00 00 00 00 00 00 .....=..|.......
| 2608: 00 00 1d 97 d3 d0 4a e7 c0 00 00 00 00 00 00 00 ......J.........
| 3088: 00 00 00 00 00 00 00 00 00 00 00 00 01 f3 00 00 ................
| 3600: 23 97 3d 04 ae 7c 01 00 00 00 00 00 00 00 00 00 #.=..|..........
| 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 26 ...............&
| page 8 offset 28672
| 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0......
| 1072: 97 4d 1e 14 00 ae 7c 00 00 00 00 00 00 00 00 00 .M....|.........
| 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................
| page 10 offset 36864
| 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0......
| 1072: 9a ee c1 80 fd 78 1f ce 1b ae eb b4 00 00 00 00 .....x..........
| 1088: 13 20 ff 20 00 70 00 00 00 60 50 00 00 00 11 e0 . . .p...`P.....
| 1104: 00 00 00 70 00 00 00 60 50 05 35 14 c6 97 46 52 ...p...`P.5...FR
| 1120: 06 66 f7 26 d6 17 42 03 30 01 00 00 10 10 04 02 .f.&..B.0.......
| 1136: 02 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 .........@......
| 1152: 00 00 00 00 00 40 00 00 00 40 00 00 00 00 00 00 .....@...@......
| 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................
| page 12 offset 45056
| 0: 0d 00 00 00 01 04 30 00 04 30 e1 b4 30 97 4d 46 ......0..0..0.MF
| 16: 14 00 ae 7c 00 00 00 00 00 00 00 03 00 00 43 00 ...|..........C.
| page 47 offset 188416
| 2512: 00 00 00 00 00 00 00 00 be 00 00 00 00 00 00 00 ................
| page 87 offset 352256
| 2512: 00 00 00 00 00 00 00 00 aa 00 00 00 00 00 00 00 ................
| end crash-acaae0347204ae.db
}]} {}
do_intck_test 1.1 {
{corruption found while reading database schema}
}
#-------------------------------------------------------------------------
reset_db
do_test 2.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
| size 28672 pagesize 4096 filename crash-3afa1ca9e9c1bd.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
| 96: 00 00 00 00 0d 00 00 00 06 0e 88 00 0f b8 0f 6d ...............m
| 112: 0f 3a 0f 0b 0e d5 0e 88 01 00 00 00 00 00 00 00 .:..............
| 3712: 00 00 00 00 00 00 00 00 4b 06 06 17 25 25 01 5b ........K...%%.[
| 3728: 74 61 62 6c 65 73 71 6c 69 74 65 5f 73 74 61 74 tablesqlite_stat
| 3744: 31 73 71 6c 69 74 65 5f 73 74 61 74 31 07 43 52 1sqlite_stat1.CR
| 3760: 45 41 54 45 20 54 41 42 4c 45 20 73 71 6c 69 74 EATE TABLE sqlit
| 3776: 65 5f 73 74 61 74 31 28 74 62 6c 2c 69 64 78 2c e_stat1(tbl,idx,
| 3792: 73 74 61 74 29 34 05 06 17 13 11 01 53 69 6e 64 stat)4......Sind
| 3808: 65 78 63 31 63 63 31 06 43 52 45 41 54 45 20 55 exc1cc1.CREATE U
| 3824: 4e 49 51 55 45 20 49 4e 44 45 58 20 63 31 63 20 NIQUE INDEX c1c
| 3840: 4f 4e 20 63 31 28 63 2c 20 62 29 2d 04 06 17 13 ON c1(c, b)-....
| 3856: 11 01 45 69 6e 64 65 78 63 31 64 63 31 05 43 52 ..Eindexc1dc1.CR
| 3872: 45 41 54 45 20 49 4e 44 45 58 20 63 31 64 20 4f EATE INDEX c1d O
| 3888: 4e 20 63 31 28 64 2c 20 62 29 31 03 06 17 13 11 N c1(d, b)1.....
| 3904: 01 4d 69 6e 64 65 78 62 31 63 62 31 05 43 52 45 .Mindexb1cb1.CRE
| 3920: 41 54 45 20 55 4e 49 51 55 45 20 49 4e 44 45 58 ATE UNIQUE INDEX
| 3936: 20 62 31 63 20 4f 4e 20 62 31 28 63 29 49 02 06 b1c ON b1(c)I..
| 3952: 17 11 11 0f 7f 74 61 62 6c 65 63 31 63 31 03 43 .....tablec1c1.C
| 3968: 52 45 41 54 45 20 54 41 42 4c 45 20 63 31 28 61 REATE TABLE c1(a
| 3984: 20 49 4e 54 20 50 52 49 4d 41 52 59 20 4b 45 59 INT PRIMARY KEY
| 4000: 2c 20 62 2c 20 63 2c 20 64 29 20 57 49 54 48 4f , b, c, d) WITHO
| 4016: 55 54 20 52 4f 57 49 44 46 01 06 17 11 11 01 79 UT ROWIDF......y
| 4032: 74 61 62 6c 65 62 31 62 31 02 43 52 45 41 54 45 tableb1b1.CREATE
| 4048: 20 54 41 42 4c 45 20 62 31 28 61 20 49 4e 54 20 TABLE b1(a INT
| 4064: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 2c 20 PRIMARY KEY, b,
| 4080: 63 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 c) WITHOUT ROWID
| page 2 offset 4096
| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f e2 ................
| 16: 0f da 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 06 ................
| 4048: 67 07 07 04 01 0f 01 06 66 06 07 04 01 0f 01 05 g.......f.......
| 4064: 65 05 07 04 01 0f 01 04 64 04 07 04 01 0f 01 03 e.......d.......
| 4080: 63 03 07 04 01 0f 01 02 62 0f 05 04 09 0f 09 61 c.......b......a
| page 3 offset 8192
| 0: 0a 00 00 00 07 0f bd 00 0f f9 0f ef 0f e5 0f db ................
| 16: 0f d1 0f c7 0f bd 00 00 00 00 01 00 00 00 00 00 ................
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 09 05 01 ................
| 4032: 0f 01 01 07 61 07 07 09 05 01 0f 01 01 06 61 06 ....a.........a.
| 4048: 06 09 05 01 0f 01 01 05 61 05 05 09 05 01 0f 01 ........a.......
| 4064: 01 04 61 04 04 09 05 01 0f 01 01 03 61 03 03 09 ..a.........a...
| 4080: 05 01 0f 01 01 02 61 0f 02 06 05 09 0f 09 09 61 ......a........a
| page 4 offset 12288
| 0: 0a 00 00 00 07 0f d8 00 0f fc 0f f0 0f ea 0f e4 ................
| 16: 0f de 0f d8 0f f6 00 00 00 00 00 00 00 00 00 00 ................
| 4048: 00 00 00 00 00 00 00 00 05 03 01 01 07 07 05 03 ................
| 4064: 01 01 06 06 05 03 01 01 05 05 05 03 01 01 04 04 ................
| 4080: 05 03 01 01 03 03 05 03 01 01 0f 02 03 03 09 09 ................
| page 5 offset 16384
| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f 00 ................
| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................
| 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a.......
| 4064: 61 05 07 04 01 1f 01 04 61 04 07 04 01 0f 01 03 a.......a.......
| 4080: 61 03 07 04 01 0f 01 02 61 02 05 04 09 0f 09 61 a.......a......a
| page 6 offset 20480
| 0: 0a 00 00 00 07 0f ca 00 0f fa 0f ea 0f e2 00 00 ................
| 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................
| 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a.......
| 4064: 61 05 07 04 01 0f 01 04 61 04 07 04 01 0f 01 03 a.......a.......
| 4080: 61 03 07 04 01 0f 01 0f 61 02 05 04 09 0f 09 61 a.......a......a
| page 7 offset 24576
| 0: 0d 00 00 00 05 0f 1c 00 0f f0 0f e0 0f d3 0f c5 ................
| 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4016: 00 00 00 00 00 00 00 00 0b 05 04 11 11 13 62 31 ..............b1
| 4032: 62 31 37 20 31 0c 04 04 11 13 13 62 31 62 31 63 b17 1......b1b1c
| 4048: 37 20 31 0b 03 04 11 11 13 63 31 63 31 37 20 31 7 1......c1c17 1
| 4064: 0e 02 04 11 13 07 63 31 63 31 64 37 20 31 20 31 ......c1c1d7 1 1
| 4080: 0e 01 04 11 13 17 63 31 63 31 63 37 20 31 00 00 ......c1c1c7 1..
| end crash-3afa1ca9e9c1bd.db
}]} {}
do_intck_test 2.1 {
{corruption found while reading database schema}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
PRAGMA page_size = 1024;
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a);
INSERT INTO t1 VALUES(1, 1), (2, 2), (3, 3);
}
do_test 3.1 {
set pgno [db one {SELECT rootpage FROM sqlite_schema WHERE name='t1'}]
db close
hexio_write test.db [expr ($pgno-1)*1024] 0000
} {2}
sqlite3 db test.db
do_intck_test 3.2 {
{corruption found while scanning database object i1}
{corruption found while scanning database object t1}
}
finish_test
+45
View File
@@ -0,0 +1,45 @@
# 2024 February 24
#
# 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.
#
#***********************************************************************
#
source [file join [file dirname [info script]] intck_common.tcl]
set testprefix intckfault
do_execsql_test 1.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES(2, 'two', 'three');
INSERT INTO t1 VALUES(3, NULL, NULL);
CREATE INDEX i1 ON t1(b, c);
}
do_faultsim_test 1 -faults oom-t* -prep {
} -body {
set ::ic [sqlite3_intck db main]
set nStep 0
while {"SQLITE_OK"==[$::ic step]} {
incr nStep
if {$nStep==3} { $::ic unlock }
}
set res [$::ic error]
$::ic close
set res
} -test {
catch { $::ic close }
puts $testresult
puts $testnfail
faultsim_test_result {0 {SQLITE_OK {}}} {0 {SQLITE_NOMEM {}}} {0 {SQLITE_NOMEM {out of memory}}}
}
finish_test
+941
View File
@@ -0,0 +1,941 @@
/*
** 2024-02-08
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
*/
#include "sqlite3intck.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
/*
** nKeyVal:
** The number of values that make up the 'key' for the current pCheck
** statement.
**
** rc:
** Error code returned by most recent sqlite3_intck_step() or
** sqlite3_intck_unlock() call. This is set to SQLITE_DONE when
** the integrity-check operation is finished.
**
** zErr:
** If the object has entered the error state, this is the error message.
** Is freed using sqlite3_free() when the object is deleted.
**
** zTestSql:
** The value returned by the most recent call to sqlite3_intck_testsql().
** Each call to testsql() frees the previous zTestSql value (using
** sqlite3_free()) and replaces it with the new value it will return.
*/
struct sqlite3_intck {
sqlite3 *db;
const char *zDb; /* Copy of zDb parameter to _open() */
char *zObj; /* Current object. Or NULL. */
sqlite3_stmt *pCheck; /* Current check statement */
char *zKey;
int nKeyVal;
char *zMessage;
int bCorruptSchema;
int rc; /* Error code */
char *zErr; /* Error message */
char *zTestSql; /* Returned by sqlite3_intck_test_sql() */
};
/*
** Some error has occurred while using database p->db. Save the error message
** and error code currently held by the database handle in p->rc and p->zErr.
*/
static void intckSaveErrmsg(sqlite3_intck *p){
p->rc = sqlite3_errcode(p->db);
sqlite3_free(p->zErr);
p->zErr = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
}
/*
** If the handle passed as the first argument is already in the error state,
** then this function is a no-op (returns NULL immediately). Otherwise, if an
** error occurs within this function, it leaves an error in said handle.
**
** Otherwise, this function attempts to prepare SQL statement zSql and
** return the resulting statement handle to the user.
*/
static sqlite3_stmt *intckPrepare(sqlite3_intck *p, const char *zSql){
sqlite3_stmt *pRet = 0;
if( p->rc==SQLITE_OK ){
p->rc = sqlite3_prepare_v2(p->db, zSql, -1, &pRet, 0);
if( p->rc!=SQLITE_OK ){
intckSaveErrmsg(p);
assert( pRet==0 );
}
}
return pRet;
}
/*
** If the handle passed as the first argument is already in the error state,
** then this function is a no-op (returns NULL immediately). Otherwise, if an
** error occurs within this function, it leaves an error in said handle.
**
** Otherwise, this function treats argument zFmt as a printf() style format
** string. It formats it according to the trailing arguments and then
** attempts to prepare the results and return the resulting prepared
** statement.
*/
static sqlite3_stmt *intckPrepareFmt(sqlite3_intck *p, const char *zFmt, ...){
sqlite3_stmt *pRet = 0;
va_list ap;
char *zSql = 0;
va_start(ap, zFmt);
zSql = sqlite3_vmprintf(zFmt, ap);
if( p->rc==SQLITE_OK && zSql==0 ){
p->rc = SQLITE_NOMEM;
}
pRet = intckPrepare(p, zSql);
sqlite3_free(zSql);
va_end(ap);
return pRet;
}
/*
** Finalize SQL statement pStmt. If an error occurs and the handle passed
** as the first argument does not already contain an error, store the
** error in the handle.
*/
static void intckFinalize(sqlite3_intck *p, sqlite3_stmt *pStmt){
int rc = sqlite3_finalize(pStmt);
if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){
intckSaveErrmsg(p);
}
}
/*
** If there is already an error in handle p, return it. Otherwise, call
** sqlite3_step() on the statement handle and return that value.
*/
static int intckStep(sqlite3_intck *p, sqlite3_stmt *pStmt){
if( p->rc ) return p->rc;
return sqlite3_step(pStmt);
}
/*
** Execute SQL statement zSql. There is no way to obtain any results
** returned by the statement. This function uses the sqlite3_intck error
** code convention.
*/
static void intckExec(sqlite3_intck *p, const char *zSql){
sqlite3_stmt *pStmt = 0;
pStmt = intckPrepare(p, zSql);
intckStep(p, pStmt);
intckFinalize(p, pStmt);
}
/*
** A wrapper around sqlite3_mprintf() that uses the sqlite3_intck error
** code convention.
*/
static char *intckMprintf(sqlite3_intck *p, const char *zFmt, ...){
va_list ap;
char *zRet = 0;
va_start(ap, zFmt);
zRet = sqlite3_vmprintf(zFmt, ap);
if( p->rc==SQLITE_OK ){
if( zRet==0 ){
p->rc = SQLITE_NOMEM;
}
}else{
sqlite3_free(zRet);
zRet = 0;
}
return zRet;
}
/*
** This is used by sqlite3_intck_unlock() to save the vector key value
** required to restart the current pCheck query as a nul-terminated string
** in p->zKey.
*/
static void intckSaveKey(sqlite3_intck *p){
int ii;
char *zSql = 0;
sqlite3_stmt *pStmt = 0;
sqlite3_stmt *pXinfo = 0;
const char *zDir = 0;
assert( p->pCheck );
assert( p->zKey==0 );
pXinfo = intckPrepareFmt(p,
"SELECT group_concat(desc, '') FROM %Q.sqlite_schema s, "
"pragma_index_xinfo(%Q, %Q) "
"WHERE s.type='index' AND s.name=%Q",
p->zDb, p->zObj, p->zDb, p->zObj
);
if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXinfo) ){
zDir = (const char*)sqlite3_column_text(pXinfo, 0);
}
if( zDir==0 ){
/* Object is a table, not an index. This is the easy case,as there are
** no DESC columns or NULL values in a primary key. */
const char *zSep = "SELECT '(' || ";
for(ii=0; ii<p->nKeyVal; ii++){
zSql = intckMprintf(p, "%z%squote(?)", zSql, zSep);
zSep = " || ', ' || ";
}
zSql = intckMprintf(p, "%z || ')'", zSql);
}else{
/* Object is an index. */
assert( p->nKeyVal>1 );
for(ii=p->nKeyVal; ii>0; ii--){
int bLastIsDesc = zDir[ii-1]=='1';
int bLastIsNull = sqlite3_column_type(p->pCheck, ii)==SQLITE_NULL;
const char *zLast = sqlite3_column_name(p->pCheck, ii);
char *zLhs = 0;
char *zRhs = 0;
char *zWhere = 0;
if( bLastIsNull ){
if( bLastIsDesc ) continue;
zWhere = intckMprintf(p, "'%s IS NOT NULL'", zLast);
}else{
const char *zOp = bLastIsDesc ? "<" : ">";
zWhere = intckMprintf(p, "'%s %s ' || quote(?%d)", zLast, zOp, ii);
}
if( ii>1 ){
const char *zLhsSep = "";
const char *zRhsSep = "";
int jj;
for(jj=0; jj<ii-1; jj++){
const char *zAlias = (const char*)sqlite3_column_name(p->pCheck,jj+1);
zLhs = intckMprintf(p, "%z%s%s", zLhs, zLhsSep, zAlias);
zRhs = intckMprintf(p, "%z%squote(?%d)", zRhs, zRhsSep, jj+1);
zLhsSep = ",";
zRhsSep = " || ',' || ";
}
zWhere = intckMprintf(p,
"'(%z) IS (' || %z || ') AND ' || %z",
zLhs, zRhs, zWhere);
}
zWhere = intckMprintf(p, "'WHERE ' || %z", zWhere);
zSql = intckMprintf(p, "%z%s(quote( %z ) )",
zSql,
(zSql==0 ? "VALUES" : ",\n "),
zWhere
);
}
zSql = intckMprintf(p,
"WITH wc(q) AS (\n%z\n)"
"SELECT 'VALUES' || group_concat('(' || q || ')', ',\n ') FROM wc"
, zSql
);
}
pStmt = intckPrepare(p, zSql);
if( p->rc==SQLITE_OK ){
for(ii=0; ii<p->nKeyVal; ii++){
sqlite3_bind_value(pStmt, ii+1, sqlite3_column_value(p->pCheck, ii+1));
}
if( SQLITE_ROW==sqlite3_step(pStmt) ){
p->zKey = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0));
}
intckFinalize(p, pStmt);
}
sqlite3_free(zSql);
intckFinalize(p, pXinfo);
}
/*
** Find the next database object (table or index) to check. If successful,
** set sqlite3_intck.zObj to point to a nul-terminated buffer containing
** the object's name before returning.
*/
static void intckFindObject(sqlite3_intck *p){
sqlite3_stmt *pStmt = 0;
char *zPrev = p->zObj;
p->zObj = 0;
assert( p->rc==SQLITE_OK );
assert( p->pCheck==0 );
pStmt = intckPrepareFmt(p,
"WITH tables(table_name) AS ("
" SELECT name"
" FROM %Q.sqlite_schema WHERE (type='table' OR type='index') AND rootpage"
" UNION ALL "
" SELECT 'sqlite_schema'"
")"
"SELECT table_name FROM tables "
"WHERE ?1 IS NULL OR table_name%s?1 "
"ORDER BY 1"
, p->zDb, (p->zKey ? ">=" : ">")
);
if( p->rc==SQLITE_OK ){
sqlite3_bind_text(pStmt, 1, zPrev, -1, SQLITE_TRANSIENT);
if( sqlite3_step(pStmt)==SQLITE_ROW ){
p->zObj = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0));
}
}
intckFinalize(p, pStmt);
/* If this is a new object, ensure the previous key value is cleared. */
if( sqlite3_stricmp(p->zObj, zPrev) ){
sqlite3_free(p->zKey);
p->zKey = 0;
}
sqlite3_free(zPrev);
}
/*
** Return the size in bytes of the first token in nul-terminated buffer z.
** For the purposes of this call, a token is either:
**
** * a quoted SQL string,
* * a contiguous series of ascii alphabet characters, or
* * any other single byte.
*/
static int intckGetToken(const char *z){
char c = z[0];
int iRet = 1;
if( c=='\'' || c=='"' || c=='`' ){
while( 1 ){
if( z[iRet]==c ){
iRet++;
if( z[iRet]!=c ) break;
}
iRet++;
}
}
else if( c=='[' ){
while( z[iRet++]!=']' && z[iRet] );
}
else if( (c>='A' && c<='Z') || (c>='a' && c<='z') ){
while( (z[iRet]>='A' && z[iRet]<='Z') || (z[iRet]>='a' && z[iRet]<='z') ){
iRet++;
}
}
return iRet;
}
/*
** Return true if argument c is an ascii whitespace character.
*/
static int intckIsSpace(char c){
return (c==' ' || c=='\t' || c=='\n' || c=='\r');
}
/*
** Argument z points to the text of a CREATE INDEX statement. This function
** identifies the part of the text that contains either the index WHERE
** clause (if iCol<0) or the iCol'th column of the index.
**
** If (iCol<0), the identified fragment does not include the "WHERE" keyword,
** only the expression that follows it. If (iCol>=0) then the identified
** fragment does not include any trailing sort-order keywords - "ASC" or
** "DESC".
**
** If the CREATE INDEX statement does not contain the requested field or
** clause, NULL is returned and (*pnByte) is set to 0. Otherwise, a pointer to
** the identified fragment is returned and output parameter (*pnByte) set
** to its size in bytes.
*/
static const char *intckParseCreateIndex(const char *z, int iCol, int *pnByte){
int iOff = 0;
int iThisCol = 0;
int iStart = 0;
int nOpen = 0;
const char *zRet = 0;
int nRet = 0;
int iEndOfCol = 0;
/* Skip forward until the first "(" token */
while( z[iOff]!='(' ){
iOff += intckGetToken(&z[iOff]);
if( z[iOff]=='\0' ) return 0;
}
assert( z[iOff]=='(' );
nOpen = 1;
iOff++;
iStart = iOff;
while( z[iOff] ){
const char *zToken = &z[iOff];
int nToken = 0;
/* Check if this is the end of the current column - either a "," or ")"
** when nOpen==1. */
if( nOpen==1 ){
if( z[iOff]==',' || z[iOff]==')' ){
if( iCol==iThisCol ){
int iEnd = iEndOfCol ? iEndOfCol : iOff;
nRet = (iEnd - iStart);
zRet = &z[iStart];
break;
}
iStart = iOff+1;
while( intckIsSpace(z[iStart]) ) iStart++;
iThisCol++;
}
if( z[iOff]==')' ) break;
}
if( z[iOff]=='(' ) nOpen++;
if( z[iOff]==')' ) nOpen--;
nToken = intckGetToken(zToken);
if( (nToken==3 && 0==sqlite3_strnicmp(zToken, "ASC", nToken))
|| (nToken==4 && 0==sqlite3_strnicmp(zToken, "DESC", nToken))
){
iEndOfCol = iOff;
}else if( 0==intckIsSpace(zToken[0]) ){
iEndOfCol = 0;
}
iOff += nToken;
}
/* iStart is now the byte offset of 1 byte passed the final ')' in the
** CREATE INDEX statement. Try to find a WHERE clause to return. */
while( zRet==0 && z[iOff] ){
int n = intckGetToken(&z[iOff]);
if( n==5 && 0==sqlite3_strnicmp(&z[iOff], "where", 5) ){
zRet = &z[iOff+5];
nRet = strlen(zRet);
}
iOff += n;
}
/* Trim any whitespace from the start and end of the returned string. */
if( zRet ){
while( intckIsSpace(zRet[0]) ){
nRet--;
zRet++;
}
while( nRet>0 && intckIsSpace(zRet[nRet-1]) ) nRet--;
}
*pnByte = nRet;
return zRet;
}
/*
** User-defined SQL function wrapper for intckParseCreateIndex():
**
** SELECT parse_create_index(<sql>, <icol>);
*/
static void intckParseCreateIndexFunc(
sqlite3_context *pCtx,
int nVal,
sqlite3_value **apVal
){
const char *zSql = (const char*)sqlite3_value_text(apVal[0]);
int idx = sqlite3_value_int(apVal[1]);
const char *zRes = 0;
int nRes = 0;
assert( nVal==2 );
if( zSql ){
zRes = intckParseCreateIndex(zSql, idx, &nRes);
}
sqlite3_result_text(pCtx, zRes, nRes, SQLITE_TRANSIENT);
}
/*
** Return true if sqlite3_intck.db has automatic indexes enabled, false
** otherwise.
*/
static int intckGetAutoIndex(sqlite3_intck *p){
int bRet = 0;
sqlite3_stmt *pStmt = 0;
pStmt = intckPrepare(p, "PRAGMA automatic_index");
if( SQLITE_ROW==intckStep(p, pStmt) ){
bRet = sqlite3_column_int(pStmt, 0);
}
intckFinalize(p, pStmt);
return bRet;
}
/*
** Return true if zObj is an index, or false otherwise.
*/
static int intckIsIndex(sqlite3_intck *p, const char *zObj){
int bRet = 0;
sqlite3_stmt *pStmt = 0;
pStmt = intckPrepareFmt(p,
"SELECT 1 FROM %Q.sqlite_schema WHERE name=%Q AND type='index'",
p->zDb, zObj
);
if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
bRet = 1;
}
intckFinalize(p, pStmt);
return bRet;
}
/*
** Return a pointer to a nul-terminated buffer containing the SQL statement
** used to check database object zObj (a table or index) for corruption.
** If parameter zPrev is not NULL, then it must be a string containing the
** vector key required to restart the check where it left off last time.
** If pnKeyVal is not NULL, then (*pnKeyVal) is set to the number of
** columns in the vector key value for the specified object.
**
** This function uses the sqlite3_intck error code convention.
*/
static char *intckCheckObjectSql(
sqlite3_intck *p, /* Integrity check object */
const char *zObj, /* Object (table or index) to scan */
const char *zPrev, /* Restart key vector, if any */
int *pnKeyVal /* OUT: Number of key-values for this scan */
){
char *zRet = 0;
sqlite3_stmt *pStmt = 0;
int bAutoIndex = 0;
int bIsIndex = 0;
const char *zCommon =
/* Relation without_rowid also contains just one row. Column "b" is
** set to true if the table being examined is a WITHOUT ROWID table,
** or false otherwise. */
", without_rowid(b) AS ("
" SELECT EXISTS ("
" SELECT 1 FROM tabname, pragma_index_list(tab, db) AS l"
" WHERE origin='pk' "
" AND NOT EXISTS (SELECT 1 FROM sqlite_schema WHERE name=l.name)"
" )"
")"
""
/* Table idx_cols contains 1 row for each column in each index on the
** table being checked. Columns are:
**
** idx_name: Name of the index.
** idx_ispk: True if this index is the PK of a WITHOUT ROWID table.
** col_name: Name of indexed column, or NULL for index on expression.
** col_expr: Indexed expression, including COLLATE clause.
** col_alias: Alias used for column in 'intck_wrapper' table.
*/
", idx_cols(idx_name, idx_ispk, col_name, col_expr, col_alias) AS ("
" SELECT l.name, (l.origin=='pk' AND w.b), i.name, COALESCE(("
" SELECT parse_create_index(sql, i.seqno) FROM "
" sqlite_schema WHERE name = l.name"
" ), format('\"%w\"', i.name) || ' COLLATE ' || quote(i.coll)),"
" 'c' || row_number() OVER ()"
" FROM "
" tabname t,"
" without_rowid w,"
" pragma_index_list(t.tab, t.db) l,"
" pragma_index_xinfo(l.name) i"
" WHERE i.key"
" UNION ALL"
" SELECT '', 1, '_rowid_', '_rowid_', 'r1' FROM without_rowid WHERE b=0"
")"
""
""
/*
** For a PK declared as "PRIMARY KEY(a, b) ... WITHOUT ROWID", where
** the intck_wrapper aliases of "a" and "b" are "c1" and "c2":
**
** o_pk: "o.c1, o.c2"
** i_pk: "i.'a', i.'b'"
** ...
** n_pk: 2
*/
", tabpk(db, tab, idx, o_pk, i_pk, q_pk, eq_pk, ps_pk, pk_pk, n_pk) AS ("
" WITH pkfields(f, a) AS ("
" SELECT i.col_name, i.col_alias FROM idx_cols i WHERE i.idx_ispk"
" )"
" SELECT t.db, t.tab, t.idx, "
" group_concat(a, ', '), "
" group_concat('i.'||quote(f), ', '), "
" group_concat('quote(o.'||a||')', ' || '','' || '), "
" format('(%s)==(%s)',"
" group_concat('o.'||a, ', '), "
" group_concat(format('\"%w\"', f), ', ')"
" ),"
" group_concat('%s', ','),"
" group_concat('quote('||a||')', ', '), "
" count(*)"
" FROM tabname t, pkfields"
")"
""
", idx(name, match_expr, partial, partial_alias, idx_ps, idx_idx) AS ("
" SELECT idx_name,"
" format('(%s,%s) IS (%s,%s)', "
" group_concat(i.col_expr, ', '), i_pk,"
" group_concat('o.'||i.col_alias, ', '), o_pk"
" ), "
" parse_create_index("
" (SELECT sql FROM sqlite_schema WHERE name=idx_name), -1"
" ),"
" 'cond' || row_number() OVER ()"
" , group_concat('%s', ',')"
" , group_concat('quote('||i.col_alias||')', ', ')"
" FROM tabpk t, "
" without_rowid w,"
" idx_cols i"
" WHERE i.idx_ispk==0 "
" GROUP BY idx_name"
")"
""
", wrapper_with(s) AS ("
" SELECT 'intck_wrapper AS (\n SELECT\n ' || ("
" WITH f(a, b) AS ("
" SELECT col_expr, col_alias FROM idx_cols"
" UNION ALL "
" SELECT partial, partial_alias FROM idx WHERE partial IS NOT NULL"
" )"
" SELECT group_concat(format('%s AS %s', a, b), ',\n ') FROM f"
" )"
" || format('\n FROM %Q.%Q ', t.db, t.tab)"
/* If the object being checked is a table, append "NOT INDEXED".
** Otherwise, append "INDEXED BY <index>", and then, if the index
** is a partial index " WHERE <condition>". */
" || CASE WHEN t.idx IS NULL THEN "
" 'NOT INDEXED'"
" ELSE"
" format('INDEXED BY %Q%s', t.idx, ' WHERE '||i.partial)"
" END"
" || '\n)'"
" FROM tabname t LEFT JOIN idx i ON (i.name=t.idx)"
")"
""
;
bAutoIndex = intckGetAutoIndex(p);
if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 0");
bIsIndex = intckIsIndex(p, zObj);
if( bIsIndex ){
pStmt = intckPrepareFmt(p,
/* Table idxname contains a single row. The first column, "db", contains
** the name of the db containing the table (e.g. "main") and the second,
** "tab", the name of the table itself. */
"WITH tabname(db, tab, idx) AS ("
" SELECT %Q, (SELECT tbl_name FROM %Q.sqlite_schema WHERE name=%Q), %Q "
")"
""
", whereclause(w_c) AS (%s)"
""
"%s" /* zCommon */
""
", case_statement(c) AS ("
" SELECT "
" 'CASE WHEN (' || group_concat(col_alias, ', ') || ', 1) IS (\n' "
" || ' SELECT ' || group_concat(col_expr, ', ') || ', 1 FROM '"
" || format('%%Q.%%Q NOT INDEXED WHERE %%s\n', t.db, t.tab, p.eq_pk)"
" || ' )\n THEN NULL\n '"
" || 'ELSE format(''surplus entry ('"
" || group_concat('%%s', ',') || ',' || p.ps_pk"
" || ') in index ' || t.idx || ''', ' "
" || group_concat('quote('||i.col_alias||')', ', ') || ', ' || p.pk_pk"
" || ')'"
" || '\n END AS error_message'"
" FROM tabname t, tabpk p, idx_cols i WHERE i.idx_name=t.idx"
")"
""
", thiskey(k, n) AS ("
" SELECT group_concat(i.col_alias, ', ') || ', ' || p.o_pk, "
" count(*) + p.n_pk "
" FROM tabpk p, idx_cols i WHERE i.idx_name=p.idx"
")"
""
", main_select(m, n) AS ("
" SELECT format("
" 'WITH %%s\n' ||"
" ', idx_checker AS (\n' ||"
" ' SELECT %%s,\n' ||"
" ' %%s\n' || "
" ' FROM intck_wrapper AS o\n' ||"
" ')\n',"
" ww.s, c, t.k"
" ), t.n"
" FROM case_statement, wrapper_with ww, thiskey t"
")"
"SELECT m || "
" group_concat('SELECT * FROM idx_checker ' || w_c, ' UNION ALL '), n"
" FROM "
"main_select, whereclause "
, p->zDb, p->zDb, zObj, zObj
, zPrev ? zPrev : "VALUES('')", zCommon
);
}else{
pStmt = intckPrepareFmt(p,
/* Table tabname contains a single row. The first column, "db", contains
** the name of the db containing the table (e.g. "main") and the second,
** "tab", the name of the table itself. */
"WITH tabname(db, tab, idx, prev) AS (SELECT %Q, %Q, NULL, %Q)"
""
"%s" /* zCommon */
/* expr(e) contains one row for each index on table zObj. Value e
** is set to an expression that evaluates to NULL if the required
** entry is present in the index, or an error message otherwise. */
", expr(e, p) AS ("
" SELECT format('CASE WHEN EXISTS \n"
" (SELECT 1 FROM %%Q.%%Q AS i INDEXED BY %%Q WHERE %%s%%s)\n"
" THEN NULL\n"
" ELSE format(''entry (%%s,%%s) missing from index %%s'', %%s, %%s)\n"
" END\n'"
" , t.db, t.tab, i.name, i.match_expr, ' AND (' || partial || ')',"
" i.idx_ps, t.ps_pk, i.name, i.idx_idx, t.pk_pk),"
" CASE WHEN partial IS NULL THEN NULL ELSE i.partial_alias END"
" FROM tabpk t, idx i"
")"
", numbered(ii, cond, e) AS ("
" SELECT 0, 'n.ii=0', 'NULL'"
" UNION ALL "
" SELECT row_number() OVER (),"
" '(n.ii='||row_number() OVER ()||COALESCE(' AND '||p||')', ')'), e"
" FROM expr"
")"
", counter_with(w) AS ("
" SELECT 'WITH intck_counter(ii) AS (\n ' || "
" group_concat('SELECT '||ii, ' UNION ALL\n ') "
" || '\n)' FROM numbered"
")"
""
", case_statement(c) AS ("
" SELECT 'CASE ' || "
" group_concat(format('\n WHEN %%s THEN (%%s)', cond, e), '') ||"
" '\nEND AS error_message'"
" FROM numbered"
")"
""
/* This table contains a single row consisting of a single value -
** the text of an SQL expression that may be used by the main SQL
** statement to output an SQL literal that can be used to resume
** the scan if it is suspended. e.g. for a rowid table, an expression
** like:
**
** format('(%d,%d)', _rowid_, n.ii)
*/
", thiskey(k, n) AS ("
" SELECT o_pk || ', ii', n_pk+1 FROM tabpk"
")"
""
", whereclause(w_c) AS ("
" SELECT CASE WHEN prev!='' THEN "
" '\nWHERE (' || o_pk ||', n.ii) > ' || prev"
" ELSE ''"
" END"
" FROM tabpk, tabname"
")"
""
", main_select(m, n) AS ("
" SELECT format("
" '%%s, %%s\nSELECT %%s,\n%%s\nFROM intck_wrapper AS o"
", intck_counter AS n%%s\nORDER BY %%s', "
" w, ww.s, c, thiskey.k, whereclause.w_c, t.o_pk"
" ), thiskey.n"
" FROM case_statement, tabpk t, counter_with, "
" wrapper_with ww, thiskey, whereclause"
")"
"SELECT m, n FROM main_select",
p->zDb, zObj, zPrev, zCommon
);
}
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
zRet = intckMprintf(p, "%s", (const char*)sqlite3_column_text(pStmt, 0));
if( pnKeyVal ){
*pnKeyVal = sqlite3_column_int(pStmt, 1);
}
}
intckFinalize(p, pStmt);
if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 1");
return zRet;
}
/*
** Open a new integrity-check object.
*/
int sqlite3_intck_open(
sqlite3 *db, /* Database handle to operate on */
const char *zDbArg, /* "main", "temp" etc. */
sqlite3_intck **ppOut /* OUT: New integrity-check handle */
){
sqlite3_intck *pNew = 0;
int rc = SQLITE_OK;
const char *zDb = zDbArg ? zDbArg : "main";
int nDb = strlen(zDb);
pNew = (sqlite3_intck*)sqlite3_malloc(sizeof(*pNew) + nDb + 1);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
memset(pNew, 0, sizeof(*pNew));
pNew->db = db;
pNew->zDb = (const char*)&pNew[1];
memcpy(&pNew[1], zDb, nDb+1);
rc = sqlite3_create_function(db, "parse_create_index",
2, SQLITE_UTF8, 0, intckParseCreateIndexFunc, 0, 0
);
if( rc!=SQLITE_OK ){
sqlite3_intck_close(pNew);
pNew = 0;
}
}
*ppOut = pNew;
return rc;
}
/*
** Free the integrity-check object.
*/
void sqlite3_intck_close(sqlite3_intck *p){
if( p ){
sqlite3_finalize(p->pCheck);
sqlite3_create_function(
p->db, "parse_create_index", 1, SQLITE_UTF8, 0, 0, 0, 0
);
sqlite3_free(p->zObj);
sqlite3_free(p->zKey);
sqlite3_free(p->zTestSql);
sqlite3_free(p->zErr);
sqlite3_free(p->zMessage);
sqlite3_free(p);
}
}
/*
** Step the integrity-check object.
*/
int sqlite3_intck_step(sqlite3_intck *p){
if( p->rc==SQLITE_OK ){
if( p->zMessage ){
sqlite3_free(p->zMessage);
p->zMessage = 0;
}
if( p->bCorruptSchema ){
p->rc = SQLITE_DONE;
}else
if( p->pCheck==0 ){
intckFindObject(p);
if( p->rc==SQLITE_OK ){
if( p->zObj ){
char *zSql = 0;
zSql = intckCheckObjectSql(p, p->zObj, p->zKey, &p->nKeyVal);
p->pCheck = intckPrepare(p, zSql);
sqlite3_free(zSql);
sqlite3_free(p->zKey);
p->zKey = 0;
}else{
p->rc = SQLITE_DONE;
}
}else if( p->rc==SQLITE_CORRUPT ){
p->rc = SQLITE_OK;
p->zMessage = intckMprintf(p, "%s",
"corruption found while reading database schema"
);
p->bCorruptSchema = 1;
}
}
if( p->pCheck ){
assert( p->rc==SQLITE_OK );
if( sqlite3_step(p->pCheck)==SQLITE_ROW ){
/* Normal case, do nothing. */
}else{
intckFinalize(p, p->pCheck);
p->pCheck = 0;
p->nKeyVal = 0;
if( p->rc==SQLITE_CORRUPT ){
p->rc = SQLITE_OK;
p->zMessage = intckMprintf(p,
"corruption found while scanning database object %s", p->zObj
);
}
}
}
}
return p->rc;
}
/*
** Return a message describing the corruption encountered by the most recent
** call to sqlite3_intck_step(), or NULL if no corruption was encountered.
*/
const char *sqlite3_intck_message(sqlite3_intck *p){
assert( p->pCheck==0 || p->zMessage==0 );
if( p->zMessage ){
return p->zMessage;
}
if( p->pCheck ){
return (const char*)sqlite3_column_text(p->pCheck, 0);
}
return 0;
}
/*
** Return the error code and message.
*/
int sqlite3_intck_error(sqlite3_intck *p, const char **pzErr){
if( pzErr ) *pzErr = p->zErr;
return (p->rc==SQLITE_DONE ? SQLITE_OK : p->rc);
}
/*
** Close any read transaction the integrity-check object is holding open
** on the database.
*/
int sqlite3_intck_unlock(sqlite3_intck *p){
if( p->rc==SQLITE_OK && p->pCheck ){
assert( p->zKey==0 && p->nKeyVal>0 );
intckSaveKey(p);
intckFinalize(p, p->pCheck);
p->pCheck = 0;
}
return p->rc;
}
/*
** Return the SQL statement used to check object zObj. Or, if zObj is
** NULL, the current SQL statement.
*/
const char *sqlite3_intck_test_sql(sqlite3_intck *p, const char *zObj){
sqlite3_free(p->zTestSql);
if( zObj ){
p->zTestSql = intckCheckObjectSql(p, zObj, 0, 0);
}else{
if( p->zObj ){
p->zTestSql = intckCheckObjectSql(p, p->zObj, p->zKey, 0);
}else{
sqlite3_free(p->zTestSql);
p->zTestSql = 0;
}
}
return p->zTestSql;
}
+171
View File
@@ -0,0 +1,171 @@
/*
** 2024-02-08
**
** 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.
**
*************************************************************************
*/
/*
** Incremental Integrity-Check Extension
** -------------------------------------
**
** This module contains code to check whether or not an SQLite database
** is well-formed or corrupt. This is the same task as performed by SQLite's
** built-in "PRAGMA integrity_check" command. This module differs from
** "PRAGMA integrity_check" in that:
**
** + It is less thorough - this module does not detect certain types
** of corruption that are detected by the PRAGMA command. However,
** it does detect all kinds of corruption that are likely to cause
** errors in SQLite applications.
**
** + It is slower. Sometimes up to three times slower.
**
** + It allows integrity-check operations to be split into multiple
** transactions, so that the database does not need to be read-locked
** for the duration of the integrity-check.
**
** One way to use the API to run integrity-check on the "main" database
** of handle db is:
**
** int rc = SQLITE_OK;
** sqlite3_intck *p = 0;
**
** sqlite3_intck_open(db, "main", &p);
** while( SQLITE_OK==sqlite3_intck_step(p) ){
** const char *zMsg = sqlite3_intck_message(p);
** if( zMsg ) printf("corruption: %s\n", zMsg);
** }
** rc = sqlite3_intck_error(p, &zErr);
** if( rc!=SQLITE_OK ){
** printf("error occured (rc=%d), (errmsg=%s)\n", rc, zErr);
** }
** sqlite3_intck_close(p);
**
** Usually, the sqlite3_intck object opens a read transaction within the
** first call to sqlite3_intck_step() and holds it open until the
** integrity-check is complete. However, if sqlite3_intck_unlock() is
** called, the read transaction is ended and a new read transaction opened
** by the subsequent call to sqlite3_intck_step().
*/
#ifndef _SQLITE_INTCK_H
#define _SQLITE_INTCK_H
#include "sqlite3.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
** An ongoing incremental integrity-check operation is represented by an
** opaque pointer of the following type.
*/
typedef struct sqlite3_intck sqlite3_intck;
/*
** Open a new incremental integrity-check object. If successful, populate
** output variable (*ppOut) with the new object handle and return SQLITE_OK.
** Or, if an error occurs, set (*ppOut) to NULL and return an SQLite error
** code (e.g. SQLITE_NOMEM).
**
** The integrity-check will be conducted on database zDb (which must be "main",
** "temp", or the name of an attached database) of database handle db. Once
** this function has been called successfully, the caller should not use
** database handle db until the integrity-check object has been destroyed
** using sqlite3_intck_close().
*/
int sqlite3_intck_open(
sqlite3 *db, /* Database handle */
const char *zDb, /* Database name ("main", "temp" etc.) */
sqlite3_intck **ppOut /* OUT: New sqlite3_intck handle */
);
/*
** Close and release all resources associated with a handle opened by an
** earlier call to sqlite3_intck_open(). The results of using an
** integrity-check handle after it has been passed to this function are
** undefined.
*/
void sqlite3_intck_close(sqlite3_intck *pCk);
/*
** Do the next step of the integrity-check operation specified by the handle
** passed as the only argument. This function returns SQLITE_DONE if the
** integrity-check operation is finished, or an SQLite error code if
** an error occurs, or SQLITE_OK if no error occurs but the integrity-check
** is not finished. It is not considered an error if database corruption
** is encountered.
**
** Following a successful call to sqlite3_intck_step() (one that returns
** SQLITE_OK), sqlite3_intck_message() returns a non-NULL value if
** corruption was detected in the db.
**
** If an error occurs and a value other than SQLITE_OK or SQLITE_DONE is
** returned, then the integrity-check handle is placed in an error state.
** In this state all subsequent calls to sqlite3_intck_step() or
** sqlite3_intck_unlock() will immediately return the same error. The
** sqlite3_intck_error() method may be used to obtain an English language
** error message in this case.
*/
int sqlite3_intck_step(sqlite3_intck *pCk);
/*
** If the previous call to sqlite3_intck_step() encountered corruption
** within the database, then this function returns a pointer to a buffer
** containing a nul-terminated string describing the corruption in
** English. If the previous call to sqlite3_intck_step() did not encounter
** corruption, or if there was no previous call, this function returns
** NULL.
*/
const char *sqlite3_intck_message(sqlite3_intck *pCk);
/*
** Close any read-transaction opened by an earlier call to
** sqlite3_intck_step(). Any subsequent call to sqlite3_intck_step() will
** open a new transaction. Return SQLITE_OK if successful, or an SQLite error
** code otherwise.
**
** If an error occurs, then the integrity-check handle is placed in an error
** state. In this state all subsequent calls to sqlite3_intck_step() or
** sqlite3_intck_unlock() will immediately return the same error. The
** sqlite3_intck_error() method may be used to obtain an English language
** error message in this case.
*/
int sqlite3_intck_unlock(sqlite3_intck *pCk);
/*
** If an error has occurred in an earlier call to sqlite3_intck_step()
** or sqlite3_intck_unlock(), then this method returns the associated
** SQLite error code. Additionally, if pzErr is not NULL, then (*pzErr)
** may be set to point to a nul-terminated string containing an English
** language error message. Or, if no error message is available, to
** NULL.
**
** If no error has occurred within sqlite3_intck_step() or
** sqlite_intck_unlock() calls on the handle passed as the first argument,
** then SQLITE_OK is returned and (*pzErr) set to NULL.
*/
int sqlite3_intck_error(sqlite3_intck *pCk, const char **pzErr);
/*
** This API is used for testing only. It returns the full-text of an SQL
** statement used to test object zObj, which may be a table or index.
** The returned buffer is valid until the next call to either this function
** or sqlite3_intck_close() on the same sqlite3_intck handle.
*/
const char *sqlite3_intck_test_sql(sqlite3_intck *pCk, const char *zObj);
#ifdef __cplusplus
} /* end of the 'extern "C"' block */
#endif
#endif /* ifndef _SQLITE_INTCK_H */
+238
View File
@@ -0,0 +1,238 @@
/*
** 2010 August 28
**
** 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.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library.
*/
#include "sqlite3.h"
#include "sqlite3intck.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <string.h>
#include <assert.h>
/* In test1.c */
int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
const char *sqlite3ErrName(int);
typedef struct TestIntck TestIntck;
struct TestIntck {
sqlite3_intck *intck;
};
static int testIntckCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
struct Subcmd {
const char *zName;
int nArg;
const char *zExpect;
} aCmd[] = {
{"close", 0, ""}, /* 0 */
{"step", 0, ""}, /* 1 */
{"message", 0, ""}, /* 2 */
{"error", 0, ""}, /* 3 */
{"unlock", 0, ""}, /* 4 */
{"test_sql", 1, ""}, /* 5 */
{0 , 0}
};
int rc = TCL_OK;
int iIdx = -1;
TestIntck *p = (TestIntck*)clientData;
if( objc<2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
return TCL_ERROR;
}
rc = Tcl_GetIndexFromObjStruct(
interp, objv[1], aCmd, sizeof(aCmd[0]), "SUB-COMMAND", 0, &iIdx
);
if( rc ) return rc;
if( objc!=2+aCmd[iIdx].nArg ){
Tcl_WrongNumArgs(interp, 2, objv, aCmd[iIdx].zExpect);
return TCL_ERROR;
}
switch( iIdx ){
case 0: assert( 0==strcmp("close", aCmd[iIdx].zName) ); {
Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
break;
}
case 1: assert( 0==strcmp("step", aCmd[iIdx].zName) ); {
int rc = sqlite3_intck_step(p->intck);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
break;
}
case 2: assert( 0==strcmp("message", aCmd[iIdx].zName) ); {
const char *z = sqlite3_intck_message(p->intck);
Tcl_SetObjResult(interp, Tcl_NewStringObj(z ? z : "", -1));
break;
}
case 3: assert( 0==strcmp("error", aCmd[iIdx].zName) ); {
const char *zErr = 0;
int rc = sqlite3_intck_error(p->intck, 0);
Tcl_Obj *pRes = Tcl_NewObj();
Tcl_ListObjAppendElement(
interp, pRes, Tcl_NewStringObj(sqlite3ErrName(rc), -1)
);
sqlite3_intck_error(p->intck, &zErr);
Tcl_ListObjAppendElement(
interp, pRes, Tcl_NewStringObj(zErr ? zErr : 0, -1)
);
Tcl_SetObjResult(interp, pRes);
break;
}
case 4: assert( 0==strcmp("unlock", aCmd[iIdx].zName) ); {
int rc = sqlite3_intck_unlock(p->intck);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
break;
}
case 5: assert( 0==strcmp("test_sql", aCmd[iIdx].zName) ); {
const char *zObj = Tcl_GetString(objv[2]);
const char *zSql = sqlite3_intck_test_sql(p->intck, zObj[0] ? zObj : 0);
Tcl_SetObjResult(interp, Tcl_NewStringObj(zSql, -1));
break;
}
}
return TCL_OK;
}
/*
** Destructor for commands created by test_sqlite3_intck().
*/
static void testIntckFree(void *clientData){
TestIntck *p = (TestIntck*)clientData;
sqlite3_intck_close(p->intck);
ckfree(p);
}
/*
** tclcmd: sqlite3_intck DB DBNAME
*/
static int test_sqlite3_intck(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
char zName[64];
int iName = 0;
Tcl_CmdInfo info;
TestIntck *p = 0;
sqlite3 *db = 0;
const char *zDb = 0;
int rc = SQLITE_OK;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
return TCL_ERROR;
}
p = (TestIntck*)ckalloc(sizeof(TestIntck));
memset(p, 0, sizeof(TestIntck));
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
return TCL_ERROR;
}
zDb = Tcl_GetString(objv[2]);
if( zDb[0]=='\0' ) zDb = 0;
rc = sqlite3_intck_open(db, zDb, &p->intck);
if( rc!=SQLITE_OK ){
ckfree(p);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errstr(rc), -1));
return TCL_ERROR;
}
do {
sprintf(zName, "intck%d", iName++);
}while( Tcl_GetCommandInfo(interp, zName, &info)!=0 );
Tcl_CreateObjCommand(interp, zName, testIntckCmd, (void*)p, testIntckFree);
Tcl_SetObjResult(interp, Tcl_NewStringObj(zName, -1));
return TCL_OK;
}
/*
** tclcmd: test_do_intck DB DBNAME
*/
static int test_do_intck(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db = 0;
const char *zDb = 0;
int rc = SQLITE_OK;
sqlite3_intck *pCk = 0;
Tcl_Obj *pRet = 0;
const char *zErr = 0;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
return TCL_ERROR;
}
zDb = Tcl_GetString(objv[2]);
pRet = Tcl_NewObj();
Tcl_IncrRefCount(pRet);
rc = sqlite3_intck_open(db, zDb, &pCk);
if( rc==SQLITE_OK ){
while( sqlite3_intck_step(pCk)==SQLITE_OK ){
const char *zMsg = sqlite3_intck_message(pCk);
if( zMsg ){
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zMsg, -1));
}
}
rc = sqlite3_intck_error(pCk, &zErr);
}
if( rc!=SQLITE_OK ){
if( zErr ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
}else{
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
}
}else{
Tcl_SetObjResult(interp, pRet);
}
Tcl_DecrRefCount(pRet);
sqlite3_intck_close(pCk);
sqlite3_intck_close(0);
return rc ? TCL_ERROR : TCL_OK;
}
int Sqlitetestintck_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "sqlite3_intck", test_sqlite3_intck, 0, 0);
Tcl_CreateObjCommand(interp, "test_do_intck", test_do_intck, 0, 0);
return TCL_OK;
}
+11 -12
View File
@@ -694,11 +694,9 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
** Clear the Rtree.pNodeBlob object
*/
static void nodeBlobReset(Rtree *pRtree){
if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
sqlite3_blob *pBlob = pRtree->pNodeBlob;
pRtree->pNodeBlob = 0;
sqlite3_blob_close(pBlob);
}
sqlite3_blob *pBlob = pRtree->pNodeBlob;
pRtree->pNodeBlob = 0;
sqlite3_blob_close(pBlob);
}
/*
@@ -742,7 +740,6 @@ static int nodeAcquire(
&pRtree->pNodeBlob);
}
if( rc ){
nodeBlobReset(pRtree);
*ppNode = 0;
/* If unable to open an sqlite3_blob on the desired row, that can only
** be because the shadow tables hold erroneous data. */
@@ -802,6 +799,7 @@ static int nodeAcquire(
}
*ppNode = pNode;
}else{
nodeBlobReset(pRtree);
if( pNode ){
pRtree->nNodeRef--;
sqlite3_free(pNode);
@@ -1055,9 +1053,9 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
Rtree *pRtree = (Rtree *)pVtab;
int rc;
char *zCreate = sqlite3_mprintf(
"DROP TABLE '%q'.'%q_node';"
"DROP TABLE '%q'.'%q_rowid';"
"DROP TABLE '%q'.'%q_parent';",
"DROP TABLE '%q'.'%q_node',"
"'%q'.'%q_rowid',"
"'%q'.'%q_parent';",
pRtree->zDb, pRtree->zName,
pRtree->zDb, pRtree->zName,
pRtree->zDb, pRtree->zName
@@ -1136,7 +1134,9 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
sqlite3_finalize(pCsr->pReadAux);
sqlite3_free(pCsr);
pRtree->nCursor--;
nodeBlobReset(pRtree);
if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){
nodeBlobReset(pRtree);
}
return SQLITE_OK;
}
@@ -3226,7 +3226,7 @@ constraint:
static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
Rtree *pRtree = (Rtree *)pVtab;
assert( pRtree->inWrTrans==0 );
pRtree->inWrTrans++;
pRtree->inWrTrans = 1;
return SQLITE_OK;
}
@@ -3241,7 +3241,6 @@ static int rtreeEndTransaction(sqlite3_vtab *pVtab){
return SQLITE_OK;
}
static int rtreeRollback(sqlite3_vtab *pVtab){
Rtree *pRtree = (Rtree *)pVtab;
return rtreeEndTransaction(pVtab);
}
+1
View File
@@ -16,6 +16,7 @@ if {![info exists testdir]} {
}
source $testdir/tester.tcl
set testprefix rtreeJ
ifcapable !rtree { finish_test ; return }
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2);
+2 -2
View File
@@ -92,7 +92,7 @@ do_test 2.1 {
} {}
do_execsql_test -db db2 2.2 {
SELECT * FROM sqlite_stat1
SELECT * FROM sqlite_stat1 ORDER BY tbl, idx
} {
t1 sqlite_autoindex_t1_1 {32 1}
t1 t1b {32 4}
@@ -104,7 +104,7 @@ do_test 2.3 {
} {}
do_execsql_test -db db2 2.4 {
SELECT * FROM sqlite_stat1
SELECT * FROM sqlite_stat1 ORDER BY tbl, idx;
} {
t1 sqlite_autoindex_t1_1 {32 1}
t1 t1b {32 4}
@@ -1137,8 +1137,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
existing content. Throws if the pool has no available file slots,
on I/O error, or if the input does not appear to be a
database. In the latter case, only a cursory examination is made.
Note that this routine is _only_ for importing database files,
not arbitrary files, the reason being that this VFS will
Results are undefined if the given db name refers to an opened
db. Note that this routine is _only_ for importing database
files, not arbitrary files, the reason being that this VFS will
automatically clean up any non-database files so importing them
is pointless.
+11 -9
View File
@@ -1193,16 +1193,18 @@ const installOpfsVfs = function callee(options){
Asynchronously imports the given bytes (a byte array or
ArrayBuffer) into the given database file.
Results are undefined if the given db name refers to an opened
db.
If passed a function for its second argument, its behaviour
changes to async and it imports its data in chunks fed to it by
the given callback function. It calls the callback (which may
be async) repeatedly, expecting either a Uint8Array or
ArrayBuffer (to denote new input) or undefined (to denote
EOF). For so long as the callback continues to return
non-undefined, it will append incoming data to the given
VFS-hosted database file. When called this way, the resolved
value of the returned Promise is the number of bytes written to
the target file.
changes: imports its data in chunks fed to it by the given
callback function. It calls the callback (which may be async)
repeatedly, expecting either a Uint8Array or ArrayBuffer (to
denote new input) or undefined (to denote EOF). For so long as
the callback continues to return non-undefined, it will append
incoming data to the given VFS-hosted database file. When
called this way, the resolved value of the returned Promise is
the number of bytes written to the target file.
It very specifically requires the input to be an SQLite3
database and throws if that's not the case. It does so in
+5 -4
View File
@@ -230,7 +230,6 @@ SRC += \
SRC += \
$(TOP)/ext/misc/stmt.c
# FTS5 things
#
FTS5_HDR = \
@@ -375,7 +374,9 @@ TESTSRC += \
$(TOP)/ext/rtree/test_rtreedoc.c \
$(TOP)/ext/recover/sqlite3recover.c \
$(TOP)/ext/recover/dbdata.c \
$(TOP)/ext/recover/test_recover.c
$(TOP)/ext/recover/test_recover.c \
$(TOP)/ext/intck/test_intck.c \
$(TOP)/ext/intck/sqlite3intck.c
#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c
@@ -659,7 +660,7 @@ target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl fts5.c
touch target_source
sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl src-verify
tclsh $(TOP)/tool/mksqlite3c.tcl
tclsh $(TOP)/tool/mksqlite3c.tcl $(EXTRA_SRC)
cp tsrc/sqlite3ext.h .
cp $(TOP)/ext/session/sqlite3session.h .
echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c
@@ -671,7 +672,7 @@ sqlite3ext.h: target_source
cp tsrc/sqlite3ext.h .
sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl src-verify
tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros=1
tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros=1 $(EXTRA_SRC)
echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c
cat sqlite3.c >>tclsqlite3.c
echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c
+85 -73
View File
@@ -1,21 +1,23 @@
C Return\sSQLITE_ABORT\sif\sthe\sunderlying\sshadow\stables\schange\sin\sthe\smiddle\sof\san\srtree\squery\sin\ssuch\sa\sway\sas\sto\sinvalidate\san\srtree\sinternal\spriority\squeue\sentry.
D 2024-02-05T17:35:36.153
C The\sability\sto\sDROP\smultiple\stables\s(or\sviews\sor\sindexes\sor\striggers)\sat\sonce,\nas\simplemented\sby\sthis\sbranch,\sappears\sto\swork.\s\sHowever,\sthis\sbranch\sadds\sover\n1000\sbytes\sto\sthe\scode\sfootprint.\s\sAnd\sthe\schanges\sis\ssignificant,\sadding\srisk.\nThe\sbenefit\sof\sbeing\sable\sto\sdrop\smultiple\stables\sin\sa\ssingle\sstatement\sis\snot\nseen\sto\sbe\senough\sto\sovercome\sthose\sdownsides,\sand\sso\sthere\sare\sno\simmediate\nplans\sto\smerge\sthis\sbranch.
D 2024-03-04T18:02:36.966
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F Makefile.in 24be65ae641c5727bbc247d60286a15ecc24fb80f14f8fb2d32533bf0ec96e79
F Makefile.in 3c4f4879b2301e5486939f68cc64f84430861d246ac11430ff1a1d7347ed5b8c
F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
F Makefile.msc df56c06ef05add5ebcdcc9d4823fb2ec66ac16b06acb6971a7420859025886fa
F Makefile.msc 15a875f6016c4200e7093db92365fabb8b32eb09f9e40e1aadeedeecad4050d5
F README.md 6358805260a03ebead84e168bbf3740ddf3f683b477e478567186aa7afb490d3
F VERSION c84541c6a9e8426462176fbb1f9ecb5cfd7d1bb56228053ff7eeba8841673eb6
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
F autoconf/Makefile.am adedc1324b6a87fdd1265ddd336d2fb7d4f36a0e77b86ea553ae7cc4ea239347
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
F autoconf/Makefile.msc ac338c36a338f6b49475da71930f45145a181d6b551578d5a7a64f113ef27b2c
F autoconf/Makefile.msc 7ac6c331fc3b8aa57b6782db995b8c0e49230352decd4e2662fd07c06a9ed623
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
F autoconf/README.txt 42cfd21d0b19dc7d5d85fb5c405c5f3c6a4c923021c39128f6ba685355d8fd56
F autoconf/configure.ac ec7fa914c5e74ff212fe879f9bb6918e1234497e05facfb641f30c4d5893b277
@@ -97,7 +99,7 @@ F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70
F ext/fts5/fts5_config.c 8072a207034b51ae9b7694121d1b5715c794e94b275e088f70ae532378ca5cdf
F ext/fts5/fts5_expr.c e91156ebdcc08d837f4f324168f69f3c0d7fdef0e521fd561efb48ef3297b696
F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a0ec91b1
F ext/fts5/fts5_index.c bb1965c3965f6fe5f64160bf1c0694a9684a790a783f293a76da1d38d319b258
F ext/fts5/fts5_index.c ee0f4d50bc0c58a7c5ef7d645e7e38e1e59315b8ea9d722ae00c5f949ee65379
F ext/fts5/fts5_main.c d68bd9533d5a638b7f6fae61c3cb0a15257dcdcccedaf3d0b3c9f55940c85048
F ext/fts5/fts5_storage.c f9e31b0d155e9b2c92d5d3a09ad7a56b937fbf1c7f962e10f4ca6281349f3934
F ext/fts5/fts5_tcl.c fdf7e2bb9a9186cfcaf2d2ce11d338309342b7a7593c2812bc54455db53da5d2
@@ -171,7 +173,7 @@ F ext/fts5/test/fts5faultD.test e7ed7895abfe6bc98a5e853826f6b74956e7ba7f594f1860
F ext/fts5/test/fts5faultE.test 844586ce71dab4be85bb86880e87b624d089f851654cd22e4710c77eb8ce7075
F ext/fts5/test/fts5faultF.test 4abef99f86e99d9f0c6460dd68c586a766b6b9f1f660ada55bf2e8266bd1bbc1
F ext/fts5/test/fts5faultG.test d2e5a4d9a34e08dcaadcaeafef74d10cbc2abdd11aa2659a18af0294bf2812d3
F ext/fts5/test/fts5faultH.test 57f53c87ffd59be0265840f2b54a16811f9cb9012db86aad9b41d0d14d85dfe3
F ext/fts5/test/fts5faultH.test b5c3b62642b7d321504a0a4f424eb80b4f6927969173334c8ca20df388557622
F ext/fts5/test/fts5first.test 3fcf2365c00a15fc9704233674789a3b95131d12de18a9b996159f6909dc8079
F ext/fts5/test/fts5full.test e1701a112354e0ff9a1fdffb0c940c576530c33732ee20ac5e8361777070d717
F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e
@@ -248,6 +250,15 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/intck/intck1.test 8a879640c90fdff5e91e6c2c41d509485ee634e8077fe0ca9f76be4cbd441fa3
F ext/intck/intck2.test 47afb44681d13d11072cd8906e6aa877c967e65be788b01f6139922fd91474ef
F ext/intck/intck_common.tcl 9e51458126576783f11051ac0fd25bea3f6b17f570a55884223737f3200b214b
F ext/intck/intckbusy.test 0732fe3efbb9e0a53ffdcc240073f6ff2777ea82c3e08812b16494f650763fe1
F ext/intck/intckcorrupt.test 3211ef68ac53e83951b6c8f6a8d2396506d123fe5898f97f848a25837744ec56
F ext/intck/intckfault.test ba0213c9c8dce08d519d5251268a3bab076a184b4d07acdea23b65e89c9ae03c
F ext/intck/sqlite3intck.c 52381a627637504a49e93400814b36e99afa0b972a9a24ef1732b8268bb27fa8
F ext/intck/sqlite3intck.h 2b40c38e7063ab822c974c0bd4aed97dabb579ccfe2e180a4639bb3bbef0f1c9
F ext/intck/test_intck.c d63f1707432802f5db125ee40b794923af77d4686869bd8d3a7eb43332344267
F ext/jni/GNUmakefile 59eb05f2a363bdfac8d15d66bed624bfe1ff289229184f3861b95f98a19cf4b2
F ext/jni/README.md d899789a9082a07b99bf30b1bbb6204ae57c060efcaa634536fa669323918f42
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
@@ -495,7 +506,7 @@ F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c3350
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/geopoly.c 0dd4775e896cee6067979d67aff7c998e75c2c9d9cd8d62a1a790c09cde7adca
F ext/rtree/rtree.c d96c5d34eafcd46bc4b7645c26a4bcc3169d9e70e9df707ef91c2e90870d00d9
F ext/rtree/rtree.c c65a133bb697d20c0ac60ac09dc3a1cbf55500bfd6e9e730d2469aa6113480ed
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test 2b5b8c719c6a4abe377f57766f428a49af36a93061cb146cccfdc3b30000c0a4
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
@@ -515,7 +526,7 @@ F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd
F ext/rtree/rtreeG.test 1b9ca6e3effb48f4161edaa463ddeaa8fca4b2526d084f9cbf5dbe4e0184939c
F ext/rtree/rtreeH.test 0885151ee8429242625600ae47142cca935332c70a06737f35af53a7bd7aaf90
F ext/rtree/rtreeI.test 608e77f7fde9be5a12eae316baef640fffaafcfa90a3d67443e78123e19c4ca4
F ext/rtree/rtreeJ.test ba4e25c409ebed4b96bf1270e72760c1344d0a464478d221dbe91e8471ac9ac6
F ext/rtree/rtreeJ.test 93227ccd4d6c328f5ac46a902b8880041509dd2d68f6ce71560f0d8ab5bb507a
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl 202ca70df1f0645ef9d5a2170e62d378a28098d9407f0569e85c9c1cf1bd020a
F ext/rtree/rtreecheck.test 934546ad9b563e090ee0c5cbdc69ad014189ad76e5df7320526797a9a345661f
@@ -567,7 +578,7 @@ F ext/session/sessionnoop2.test de4672dce88464396ec9f30ed08c6c01643a69c53ae540fa
F ext/session/sessionrebase.test 702378bdcb5062f1106e74457beca8797d09c113a81768734a58b197b5b334e2
F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a80600a44396f7363
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c
F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
F ext/session/sqlite3session.c 829d468f0f3d2710aace56b0116a7ca3f414683ce78e3125ae5e21547a895078
F ext/session/sqlite3session.h 4cf19a51975746d7cff2fdd74db8b769c570958e1c3639ac150d824ac1553b3e
@@ -601,8 +612,8 @@ F ext/wasm/api/sqlite3-api-worker1.js 8d9c0562831f62218170a3373468d8a0b7a6503b59
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 595953994aa3ae2287c889c4da39ab3d6f17b6461ecf4bec334b7a3faafddb02
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js ebf6c7e997cd8948b35b3afc550b0503dd53febd9d2b56354efd11d985e5f0f2
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 5a430874906ff3f4a6ca69aadf0c2aaedc1bb45489b8365bff7e955a83a8d42a
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js fe427645e1499618f5fa7bc670af850577d8bcc132df982078690c9bf8400baa
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js a2fcbc3fecdd0eea229283584ebc122f29d98194083675dbe5cb2cf3a17fe309
F ext/wasm/api/sqlite3-wasm.c d33a16495ca871781e78812d3a18fed78b797468fffee657b8d7199b277ff359
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js e8135b44a568badfe197e2379f6b42899f2240b5c3a77fa044331110f7ce8e50
@@ -659,7 +670,7 @@ F ext/wasm/wasmfs.make 8a4955882aaa0783b3f60a9484a1f0f3d8b6f775c0fcd17c082f31966
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
F main.mk ef8d6b0e76b27d2b32d7b71ea30a2b2626b668f998a4f32f6171c9623a310a53
F main.mk 2c8b556ba7a4a15f5440663f7b05da221355d1921d5c75298bb50e2bb8081d79
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
@@ -672,16 +683,16 @@ F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
F src/alter.c 30c2333b8bb3af71e4eb9adeadee8aa20edb15917ed44b8422e5cd15f3dfcddc
F src/analyze.c 0f15753308c3bca7674f31fa7e0807ffcb8b120c36eef7d00b62b33079ddc854
F src/analyze.c a3df28274e2565ba5656577d7e3fd262169a213e6eb0bd47890e0f0729a4031c
F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39
F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
F src/btree.c bf659f4b1622c120ec6a863ba96c63f1861595ca21124950d977cec1477dd922
F src/btree.h 03e3356f5208bcab8eed4e094240fdac4a7f9f5ddf5e91045ce589f67d47c240
F src/btreeInt.h 3e2589726c4f105e653461814f65857465da68be1fac688de340c43b873f4062
F src/build.c 05c9eb387638982092988d2ef4c00a91b0c29baa1b85923f082ce0cf2903ea7e
F src/btree.c 285b493d843e7ba8ef78b6ae7d31238e904901dbc0c484f7904de4cf18fd8802
F src/btree.h 55066f513eb095db935169dab1dc2f7c7a747ef223c533f5d4ad4dfed346cbd0
F src/btreeInt.h 98aadb6dcb77b012cab2574d6a728fad56b337fc946839b9898c4b4c969e30b6
F src/build.c 7ee3616b8a25577f2fb715d91eaa27f62a34e6ee6d0130cc8b9644c07875b759
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
@@ -689,21 +700,21 @@ F src/date.c 90df32c2d8b2a38dd2e83d32e47802629305c4882fb2ec75c9ecdcd75b68bcb2
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
F src/expr.c 3381ee4c9aa7ccde22a2a7f35ce343925a7a25d96bdc943649131f9decdebad2
F src/expr.c 2803f5e7e3458ced24c0de48ec3640cd7a68ec61350d99c9f30b1bcd6640bd61
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
F src/func.c c71b81223e165722cd81fa71fb869a235de5998c4c5142a5dfa2725d6331f539
F src/fkey.c 0592046ed7598625234298211cc1fe611efb3fe7870a3f1938038fd9092c82f9
F src/func.c 4204c56196847faefef57fa14e43b8e4d65eb8d7e65318abe463472e3fd148cb
F src/global.c 765a0656d6cbf043cb272ff0ae38f39cc46713539ffe6793258ed3eb4b188b52
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c ae8847ccf8e212650d8a79277750f2123a03ae040d21d96ff5010114bd5b1040
F src/json.c 3b4e2778d95d923d6d77e8a5efd51a6265017b466782d597303f5f094fcd68af
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
F src/main.c 438b95162acfa17b7d218f586f5bde11d6ae82bcf030c9611fc537556870ad6b
F src/malloc.c c31472af77e3421d993b69c93f07890277afd94247da4290e1b290ffc0d1f404
F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75
@@ -723,28 +734,28 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
F src/os_unix.c fa9b81b642e60e77ffaf98bd1a2e5fde16c1c2317614ec178bf3bd5864772356
F src/os_unix.c 8d7533b3b4d0d2d6ddd34d1ebc92f50a91f04e722a3a9295a000bc3c25128e2f
F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c ff60e98138d2499082ac6230f01ac508aba545315debccfca2fd6042f5f10fcd
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
F src/parse.y bfd6da46fc895cd8237400ff485d04ab0b32e47eb56de20982bb7f53e56c1f42
F src/parse.y 9a77520c83950ced6e8b981c7826ebfd8e4a5c6e4b5d9743639e357910180c94
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
F src/pragma.c f9b6bb9a044a0dfda1f31c2d1523c7970f850688b450f06e61e23672d70adac0
F src/pragma.c e8221d6310c9923c80f6fa6d09b7ea7c5263a671f53db8d0894df23efcdb617b
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
F src/prepare.c 371f6115cb69286ebc12c6f2d7511279c2e47d9f54f475d46a554d687a3b312c
F src/printf.c 18fbdf028345c8fbe6044f5f5bfda5a10d48d6287afef088cc21b0ca57985640
F src/printf.c 10e8bad30042f8bd6114a013b4afc229ec8ad255ab27518d7d9f52e8cbc5cd0a
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 0ed10ebb70d15dcf3f1882051931ccfaf9c3f4debe67dbd114047d9e2adb9523
F src/resolve.c d77c6160bc8f249c2196fdd3e75f66a1dd70e37aa25c39aedc7b1f93c42b7c6d
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c f1a81ff4f8e9e76c224e2ab3a4baa799add0db22158c7fcede65d8cc4a6fa2da
F src/shell.c.in c6cb773b7703d76677529de19d1c40584520701966422c33da3e9334498a7099
F src/sqlite.h.in 61a60b4ea04db8ead15e1579b20b64cb56e9f55d52c5f9f9694de630110593a3
F src/select.c 43fabfc01bf87addd15e39f112f1e2ade15b19594835ab8a9e5bd50839d4e1b1
F src/shell.c.in 2ec564ed3ff0147036be313efeb47b3dbfb8753d5eb5ea0e90636427c6b3a365
F src/sqlite.h.in 19a2db3995a699bd7f6dfb423856242bfceb7ec849a93c91d241d19fc28d9f0f
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
F src/sqliteInt.h 5013ac1f5642df4c0b76314f507f4c7b6f8efee0e1d7c2e93bf8b445ceea29bb
F src/sqliteInt.h 532224eec9f53245c8450c662c2a9d06a1aec22cb28e5fc4cdfd0f67239e9049
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -790,7 +801,7 @@ F src/test_schema.c cbfd7a9a9b6b40d4377d0c76a6c5b2a58387385977f26edab4e77eb5f90a
F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 9fdb13b1df05e639808d44fcb8f6064aaded32b6565c00b215cfd05a060d1aca
F src/test_tclsh.c 3ff5d188a72f00807425954ea3b493dfd3a4b890ecc6700ea83bad2fd1332ecf
F src/test_tclsh.c aaf0d1de4a518a8db5ad38e5262be3e48b4a74ad1909f2dba753cecb30979d5d
F src/test_tclvar.c 3273f9d59395b336e381b53cfc68ec6ebdaada4e93106a2e976ffb0550504e1c
F src/test_thread.c 7ddcf0c8b79fa3c1d172f82f322302c963d923cdb503c6171f3c8081586d0b01
F src/test_vdbecov.c f60c6f135ec42c0de013a1d5136777aa328a776d33277f92abac648930453d43
@@ -801,30 +812,30 @@ F src/test_windirent.h da2e5b73c32d09905fbdd00f27cd802212a32a58ead882736fe4f5eb7
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 23d9f4539880b40226254ad9072f4ecf12eb1902e62aea47aac29928afafcfd5
F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68
F src/treeview.c c6fc972683fd00f975d8b32a81c1f25d2fb7d4035366bf45c9f5622d3ccd70ee
F src/trigger.c 0905b96b04bb6658509f711a8207287f1315cdbc3df1a1b13ba6483c8e341c81
F src/trigger.c 15ca35f491c03197c3ccd5a0b3c5b926719cbe4e185b73da0507dbeb84a52d0e
F src/update.c 6904814dd62a7a93bbb86d9f1419c7f134a9119582645854ab02b36b676d9f92
F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242
F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
F src/util.c 078f040366d5bd5f47658d045f901c768c1c636c6eaea121f3a1cbd63c3edb5b
F src/util.c 0765014847e2a06c952dd64aef0bea5144cd5b335a161eb0768ebe4f63dfe216
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
F src/vdbe.c dd340f5add924a8397401f7fe4faf2304ffd49ab5853d32ffc1736093b9c5080
F src/vdbe.h 88e19a982df9027ec1c177c793d1a5d34dc23d8f06e3b2d997f43688b05ee0eb
F src/vdbe.c 523a88b3df328810fbcbb407738c352dd9d5163b7af4c953e6e9887a4b582859
F src/vdbe.h c2d78d15112c3fc5ab87f5e8e0b75d2db1c624409de2e858c3d1aafb1650bb4f
F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
F src/vdbeapi.c 8f57d60c89da0b60e6d4e272358c511f6bae4e24330bdb11f8b42f986d1bf21b
F src/vdbeaux.c c5a471b34e9c4cfc0295a3e10734fd197670ffaebcb742f284c8e17e8026ceea
F src/vdbeaux.c 66161ba75c4a2d86aab124fe3cbcc2a752d8e4b1fc8c1fc6e00625db4798168c
F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5
F src/vdbemem.c 3e37dab421b74e9ce55c1e88fbc7bc6fead590b5ab258bc684f8b70abb1d6e71
F src/vdbesort.c 00c1fb15171205063556c2f1cf454e24c0b41c1effb0c876b850dce91f21bc64
F src/vdbemem.c 213bf303826c0ef702e3a2a69dab2309d84b8381b822c6787885859fd7cd4c4e
F src/vdbesort.c 237840ca1947511fa59bd4e18b9eeae93f2af2468c34d2427b059f896230a547
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
F src/vdbevtab.c 2143db7db0ceed69b21422581f434baffc507a08d831565193a7a02882a1b6a7
F src/vtab.c 11948e105f56e84099ca17f1f434b1944539ea84de26d0d767eadfbc670ce1ea
F src/vtab.c 38fcf63832f7e606755fa47b028c2eb6d6cd5facb40e280d66fbda4ed9a52188
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
F src/where.c 0a6492afeb75f8d2a50e26b993eb78e9623b142e637cd3f2cdb85e896931d51d
F src/where.c 33eaaeef3aef10c2b9e82096e70a174d6636e35cb0b180321b8ddf804590e5cd
F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
@@ -834,14 +845,14 @@ F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867d
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
F test/aggnested.test 610b0ce2c3e8f3daee25f9752800ee8d785db10da4aa1fbeea0ea1aabaf1d704
F test/aggorderby.test cc3abf5de64d46ff66395ca8c2346b66c2576d5aedb7bffc5b0742508856e3bf
F test/aggnested.test 4dfdbfab105cec5750a1eeb59284ffffc3b37a32aaaf09143df3f549e28e2081
F test/aggorderby.test af1e07766e8f752d54dd317aa1d956e8e896671a70ddb20228e8cdf9391023b1
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
F test/alter.test 3c00eff1e2036b9f93e9cd0f3d3e63750ac87ecb5bc71b9d7bd07cbf2ac4c494
F test/alter2.test 7e3d26ab409df52df887b366a63902c3429b935c41cb962fd58ffc25784f2f19
F test/alter3.test ffc4ab29ce78a3517a66afd69b2730667e3471622509c283b2bd4c46f680fba3
F test/alter4.test 716caa071dd8a3c6d57225778d15d3c3cbf5e34b2e84ae44199aeb2bbf50a707
F test/alter3.test 0663df0cb3b9558ccc21abe642b792d4e2e747164156208e2a44ce88c09fe09b
F test/alter4.test 0ef8e62259bbc17495456d19e33a97b14cc2f634ef67bfdfb6a3f826eb9cfbc1
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
F test/alterauth2.test 48967abae0494d9a300d1c92473d99fcb66edfcc23579c89322f033f49410adc
F test/altercol.test 29fed774747777fbbaacdd865b4413ed2d0844a4c824f8af531b5c7d4a832087
@@ -859,7 +870,7 @@ F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5
F test/altertab3.test 6c432fbb9963e0bd6549bf1422f6861d744ee5a80cb3298564e81e556481df16
F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b
F test/analyze.test e8ab7a3fa8b0294dd72c6d0acd822c3b69fd4ab9392789b29dd29daaa8601b4c
F test/analyze3.test 03f4b3d794760cf15da2d85a52df9bae300e51c8fefe9c36cfae1f86dc10d23f
F test/analyze4.test 68bd069f3ac7ac1e652ddd9f04f57d5606ddb4208450f5297005db7aa0dd707d
F test/analyze5.test fa5131952303ac4146aba101b116b9c8cb89e2637531c334a6df7f7d19dddc0d
@@ -887,7 +898,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 8d4152a8dca10e6dbe15b0c6dfcc183d5e9a7f6f983d9ae6e05f70e947aed7c3
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
@@ -947,7 +958,7 @@ F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
F test/btree01.test fef17d9e999ac4f04095948e3438fbe674f4e07bb2c63bb1cad41d87baee077f
F test/btree02.test 7555a5440453d900410160a52554fe6478af4faf53098f7235f1f443d5a1d6cc
F test/btreefault.test a82a23b0578bc587afbf9a622c8f54a54f63762f062ba8a35613cfee38ab42f9
F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb7834727
F test/busy.test caff7164c16ce06a53af51f9e4c2753d4cc64250e00790a5e48b9c4f4be37597
F test/busy2.test 20823a5d7c42fb257d9f108c66312d90b1bb4ec3d80ba6b4e371073727560f98
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
@@ -999,7 +1010,7 @@ F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85
F test/corruptA.test 112f4b2ae0b95ebf3ea63718642fb969a93acea557ace3a307234d19c245989b
F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec
F test/corruptC.test 9cf32275dae3ca33f645afe5d1d3f5ba5ac2af2b0833dfb5282f9dccb6fb81bb
F test/corruptD.test a828c788535946a372a56a750b242cd96287cd823657abe5a73c5e51b91bdd28
F test/corruptD.test 614320aa519f6bf6c7dd2f581f9513ff7b6826954180cca1a606d0e25ea084a3
F test/corruptE.test 4143791f2dfb443aec5b7fabfa5821e6063eccc3b49b06f212c2f014715fd476
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51
@@ -1058,6 +1069,7 @@ F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
F test/distinct.test 691c9e850b0d0b56b66e7e235453198cb4cf0760e324b7403d3c5abbeab0a014
F test/distinct2.test bb71cc7b5e58e895787f9910a788c254f679928d324732d063fe9bc202ecbe71
F test/distinctagg.test 40d7169ae5846caaf62c6e307d2ca3c333daf9b6f7cde888956a339a97afe85f
F test/drop-many.test 30dd091a4fd0a04b1a38e70c93f69c55749e62a3d895ac5e09277cd97caa5bbf
F test/e_blobbytes.test 4c01dfe4f12087b92b20705a3fdfded45dc4ed16d5a211fed4e1d2786ba68a52
F test/e_blobclose.test 692fc02a058476c2222a63d97e3f3b2b809c1842e5525ded7f854d540ac2e075
F test/e_blobopen.test 29f6055ee453b8e679fe9570c4d3acfedbef821622c5dad16875148c5952ef50
@@ -1071,7 +1083,7 @@ F test/e_expr.test b950818a48269506d75a41c819003bd77a0893bc4a4f2fdee191bc74109c1
F test/e_fkey.test feeba6238aeff9d809fb6236b351da8df4ae9bda89e088e54526b31a0cbfeec5
F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
F test/e_reindex.test 027bb13d2c7e9e865886eed6349f126a273f8037899b636bf5fb53c7fc815921
F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
F test/e_select.test 327a15f14068bbd6f647cedc67210f8680fcb2f05e481a0a855fccd2abfa1292
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
@@ -1108,7 +1120,7 @@ F test/filter1.test 590f8ba9a0cd0823b80d89ac75c5ce72276189cef9225d2436adaf1ee87f
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
F test/filter2.test 3cc20eaea2ea1ab245197cc4a62468deb460b78f5aa9bd7d5d3353c2fe569bae
F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b
F test/fkey1.test e563bcb4cb108ce3f40363cda4f84009dc89a39e2973076e5057ba99fca35378
F test/fkey1.test 6cf3fb520def0950799499b5bd0c6f22517cf7b6aee07523cbb52c1496aa8d00
F test/fkey2.test 1063d65e5923c054cfb8f0555a92a3ae0fa8c067275a33ee1715bd856cdb304c
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
@@ -1217,7 +1229,7 @@ F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f75
F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9
F test/fts4upfrom.test f25835162c989dffd5e2ef91ec24c4848cc9973093e2d492d1c7b32afac1b49d
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test da1332f6ab70338b83f5e2d594e72c7aa438c9b68406915e5a54618d601c09ee
F test/func.test 504d202650c7940b5aa98364dd68f242df87f39f829e51074a55d79fc7bc7414
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a
F test/func4.test e8ef9b2bd6a192a213cbd5cf31a3b35e25cd6ff2fdaeea0b58d63be31b03d220
@@ -1233,7 +1245,7 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
F test/fuzzcheck.c 7e1bcc242dc4b42e43e4708c8140fe268db83a6901fbc681d150c77aa185e328
F test/fuzzcheck.c e6a40f53ac5624aa5b7c4f31c385f09ba088d524cecc4512fd3057caeed8f530
F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
@@ -1337,7 +1349,7 @@ F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd286
F test/json/json-q1.txt 65f9d1cdcc4cffa9823fb73ed936aae5658700cd001fde448f68bfb91c807307
F test/json/json-speed-check.sh 912ee03e700a65c827ee0c7b4752c21ec5ef69cf7679d2f482ca817042bead52 x
F test/json/jsonb-q1.txt 1e180fe6491efab307e318b22879e3a736ac9a96539bbde7911a13ee5b33abc7
F test/json101.test 70587d7d35ef9e2126364ba70f0c951f70827cfbd28649d779ff3df7e8f87547
F test/json101.test 30db5b055b103ccabc53a29cfe6cda3345d07e171aeb25403dafa04f19e98b19
F test/json102.test 557a46e16df1aa9bdbc4076a71a45814ea0e7503d6621d87d42a8c04cbc2b0ef
F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
F test/json104.test 1b844a70cddcfa2e4cd81a5db0657b2e61e7f00868310f24f56a9ba0114348c1
@@ -1357,7 +1369,9 @@ F test/like2.test d3be15fefee3e02fc88942a9b98f26c5339bbdef7783c90023c092c4955fe3
F test/like3.test a76e5938fadbe6d32807284c796bafd869974a961057bc5fc5a28e06de98745c
F test/limit.test 350f5d03c29e7dff9a2cde016f84f8d368d40bcd02fa2b2a52fa10c4bf3cbfaf
F test/limit2.test 9409b033284642a859fafc95f29a5a6a557bd57c1f0d7c3f554bd64ed69df77e
F test/literal.test d0a72ab5afe525da7b5f0d2e11df7a369e8021f98de90da4352b8634dba9ccaf
F test/literal.test a65dca9fef86e51b8e45544268e37abbd4bb94ba35fd65f6fdcab2f288cd8f79
F test/literal2.tcl 1499037beaf661aeecdbe48801220a181d805372a64c6128d5f26bb6a4a8f0ce
F test/literal2.test b149e16b5fc9ee6249069a8858ed41052f222014fe0ba7ad43c2fb989c2dada2
F test/loadext.test faa4f6eed07a5aac35d57fdd7bc07f8fc82464cfd327567c10cf0ba3c86cde04
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
F test/lock.test be4fe08118fb988fed741f429b7dd5d65e1c90db
@@ -1410,7 +1424,7 @@ F test/minmax.test fe638b55d77d2375531a8f549b338eafcd9adfbd2f72df37ed77d9b26ca0a
F test/minmax2.test cf9311babb6f0518d04e42fd6a42c619531c4309a9dd790a2c4e9b3bc595e0de
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 272ca395257f05937dc96441c9dde4bc9fbf116a8d4fa02baeb0d13d50e36c87
F test/misc1.test 8d138a4926ab90617c1aa29ce26e7785ae2b83a4d3a195d543b7374e05589dd1
F test/misc1.test e3e36262aff1bd9b8b9bf1eeb3af04adb3fc1e23f0a92dbff708bba9e939ace1
F test/misc2.test 71e746af479119386ac2ed7ab7d81d99970e75b49ffd3e8efffee100b4b5f350
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
F test/misc4.test 10cd6addb2fa9093df4751a1b92b50440175dd5468a6ec84d0386e78f087db0e
@@ -1480,16 +1494,17 @@ F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/pendingrace.test 6aa33756b950c4529f79c4f3817a9a1e4025bd0d9961571a05c0279bd183d9c6
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test f7caf8dd5c7b1da74842a48df116f7f193399c656d4ffc805cd0d9658568c675
F test/permutations.test 405542f1d659942994a6b38a9e024cf5cfd23eaa68c806aeb24a72d7c9186e80
F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f
F test/pragma.test 57a36226218c03cfb381019fe43234b2cefbd8a1f12825514f906a17ccf7991e
F test/pragma.test 8bb6d3992c1c31ff6d5553d1e0693d642f7e19015648c6ae7034cb497d26bbd4
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 92a46bbea12322dd94a404f49edcfbfc913a2c98115f0d030a7459bb4712ef31
F test/pragma4.test ca5e4dfc46adfe490f75d73734f70349d95a199e6510973899e502eef2c8b1f8
F test/pragma4.test 9559cf5173864bf47c0431873d158fbeb72f920a59905b1f46069d8543eccdab
F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d9102
F test/pragma6.test fc3b670ab8ed985b2e5faa870f0f81aba1bfd5c3877ef3214e2df88592ccd3e5
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9
F test/printf.test 512152dca7f2f578f045a5a732e7bee08e4f47a8a212f83ce46791b518eba70f
F test/printf.test 685fec5a0c5af2490ab0632775a301554361d674211d690f5bee0a97b05333de
F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
@@ -1627,13 +1642,13 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
F test/speedtest1.c f9505ad6f9c2c3c488a370a2d193e9603a030e51126ef3ecfeb056d21f0e7ad5
F test/speedtest1.c 19c9b60908d25502d2831f97efee8b81006c356ab8c08327e25d24a4144f2131
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae6a41fb
F test/sqldiff1.test 1b7ab4f312442c5cc6b3a5f299fa8ca051416d1dd173cb1126fd51bf64f2c3fb
F test/sqllimits1.test b28e5cc8d337aaf290614d96a47e8fbfb720bb7ad35620c9d5432996fd413ac4
F test/sqllimits1.test 5880a2f107185744ba4d93637f44c78d17706a9899a38b694d50f209735c81cc
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
F test/startup.c 1beb5ca66fcc0fce95c3444db9d1674f90fc605499a574ae2434dcfc10d22805
F test/stat.test 123212a20ceb496893d5254a5f6c76442ce549fdc08d1702d8288a2bbaac8408
@@ -2093,7 +2108,7 @@ F tool/mkshellc.tcl b7adf08b82de60811d2cb6af05ff59fc17e5cd6f3e98743c14eaaa3f8971
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
F tool/mksqlite3c.tcl 2c760ab786cb509b47f00c96fea82994866cb99f5e046df81c768288f57897b4
F tool/mksqlite3c.tcl c6acfdf4e4ef93478ff3ce3cd593e17abb03f446036ce710c3156bcfa18665e0
F tool/mksqlite3h.tcl d391cff7cad0a372ee1406faee9ccc7dad9cb80a0c95cae0f73d10dd26e06762
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mktoolzip.tcl c7a9b685f5131d755e7d941cec50cee7f34178b9e34c9a89811eeb08617f8423
@@ -2115,7 +2130,7 @@ F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c
F tool/showwal.c 11eca547980a066b081f512636151233350ac679f29ecf4ebfce7f4530230b3d
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
F tool/spaceanal.tcl 70c87c04cfd2e77b3e6f21c33ca768296aa8f67d4ab4874786ac8fbb28433477
F tool/speed-check.sh 72dc85b2c0484af971ee3e7d10775f72b4e771e27e162c2099b3bf25517c25fb
F tool/speed-check.sh e8d20cc2eb9c85ec1ba562226de144435456dcdff4ee618de49603c6958f6116
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
@@ -2162,11 +2177,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 26f848e5e0ac34e545d2f27cf33abc46eac13e04ed9cd71084b0f7d47136ff97
R ac07ea666046dd35038bc77784e8d419
T *branch * rtree-fix
T *sym-rtree-fix *
T -sym-trunk *
U dan
Z 6f11e0396699443c7473bed77f9c3651
P 26272590691aee8569a1ea9c233f9b0e55ece63ed167696cc1ecfe3ca2548ba1
R ffcb677589cb061417252fbc7f9600de
U drh
Z 148d8810a6ba162cbd3b9cd95d027cbb
# Remove this line to create a well-formed Fossil manifest.
+1 -1
View File
@@ -1 +1 @@
478280ef67efed854988ab4f740a38ae1937204c0434ad8da11f1869a12a6d06
1a49788afd90fa4415c6aae4b6bbad68f9306c1df1026762a9d88bcb40e4cd8f
+44 -31
View File
@@ -872,7 +872,7 @@ static void statGet(
if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
sqlite3_str_appendf(&sStat, " %llu", iVal);
#ifdef SQLITE_ENABLE_STAT4
assert( p->current.anEq[i] );
assert( p->current.anEq[i] || p->nRow==0 );
#endif
}
sqlite3ResultStrAccum(context, &sStat);
@@ -1057,7 +1057,7 @@ static void analyzeOneTable(
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int nCol; /* Number of columns in pIdx. "N" */
int addrRewind; /* Address of "OP_Rewind iIdxCur" */
int addrGotoEnd; /* Address of "OP_Rewind iIdxCur" */
int addrNextRow; /* Address of "next_row:" */
const char *zIdxName; /* Name of the index */
int nColTest; /* Number of columns to test for changes */
@@ -1081,9 +1081,14 @@ static void analyzeOneTable(
/*
** Pseudo-code for loop that calls stat_push():
**
** Rewind csr
** if eof(csr) goto end_of_scan;
** regChng = 0
** Rewind csr
** if eof(csr){
** stat_init() with count = 0;
** goto end_of_scan;
** }
** count()
** stat_init()
** goto chng_addr_0;
**
** next_row:
@@ -1122,41 +1127,36 @@ static void analyzeOneTable(
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
/* Invoke the stat_init() function. The arguments are:
**
/* Implementation of the following:
**
** regChng = 0
** Rewind csr
** if eof(csr){
** stat_init() with count = 0;
** goto end_of_scan;
** }
** count()
** stat_init()
** goto chng_addr_0;
*/
assert( regTemp2==regStat+4 );
sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
/* Arguments to stat_init():
** (1) the number of columns in the index including the rowid
** (or for a WITHOUT ROWID table, the number of PK columns),
** (2) the number of columns in the key without the rowid/pk
** (3) estimated number of rows in the index,
*/
** (3) estimated number of rows in the index. */
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
assert( regRowid==regStat+2 );
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
#ifdef SQLITE_ENABLE_STAT4
if( OptimizationEnabled(db, SQLITE_Stat4) ){
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
VdbeCoverage(v);
}else
#endif
{
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
}
assert( regTemp2==regStat+4 );
sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp,
OptimizationDisabled(db, SQLITE_Stat4));
sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4,
&statInitFuncdef, 0);
addrGotoEnd = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
VdbeCoverage(v);
/* Implementation of the following:
**
** Rewind csr
** if eof(csr) goto end_of_scan;
** regChng = 0
** goto next_push_0;
**
*/
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
addrNextRow = sqlite3VdbeCurrentAddr(v);
@@ -1263,6 +1263,12 @@ static void analyzeOneTable(
}
/* Add the entry to the stat1 table. */
if( pIdx->pPartIdxWhere ){
/* Partial indexes might get a zero-entry in sqlite_stat1. But
** an empty table is omitted from sqlite_stat1. */
sqlite3VdbeJumpHere(v, addrGotoEnd);
addrGotoEnd = 0;
}
callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
assert( "BBB"[0]==SQLITE_AFF_TEXT );
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
@@ -1286,6 +1292,13 @@ static void analyzeOneTable(
int addrIsNull;
u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
/* No STAT4 data is generated if the number of rows is zero */
if( addrGotoEnd==0 ){
sqlite3VdbeAddOp2(v, OP_Cast, regStat1, SQLITE_AFF_INTEGER);
addrGotoEnd = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1);
VdbeCoverage(v);
}
if( doOnce ){
int mxCol = nCol;
Index *pX;
@@ -1338,7 +1351,7 @@ static void analyzeOneTable(
#endif /* SQLITE_ENABLE_STAT4 */
/* End of analysis */
sqlite3VdbeJumpHere(v, addrRewind);
if( addrGotoEnd ) sqlite3VdbeJumpHere(v, addrGotoEnd);
}
+35 -16
View File
@@ -5128,9 +5128,12 @@ static int accessPayload(
if( pCur->aOverflow==0
|| nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow)
){
Pgno *aNew = (Pgno*)sqlite3Realloc(
pCur->aOverflow, nOvfl*2*sizeof(Pgno)
);
Pgno *aNew;
if( sqlite3FaultSim(413) ){
aNew = 0;
}else{
aNew = (Pgno*)sqlite3Realloc(pCur->aOverflow, nOvfl*2*sizeof(Pgno));
}
if( aNew==0 ){
return SQLITE_NOMEM_BKPT;
}else{
@@ -6179,10 +6182,10 @@ i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
assert( cursorOwnsBtShared(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
/* Currently this interface is only called by the OP_IfSmaller
** opcode, and it that case the cursor will always be valid and
** will always point to a leaf node. */
if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
/* Currently this interface is only called by the OP_IfSizeBetween
** opcode and the OP_Count opcode with P3=1. In either case,
** the cursor will always be valid unless the btree is empty. */
if( pCur->eState!=CURSOR_VALID ) return 0;
if( NEVER(pCur->pPage->leaf==0) ) return -1;
n = pCur->pPage->nCell;
@@ -7004,7 +7007,10 @@ static int fillInCell(
n = nHeader + nPayload;
testcase( n==3 );
testcase( n==4 );
if( n<4 ) n = 4;
if( n<4 ){
n = 4;
pPayload[nPayload] = 0;
}
*pnSize = n;
assert( nSrc<=nPayload );
testcase( nSrc<nPayload );
@@ -9450,7 +9456,10 @@ int sqlite3BtreeInsert(
if( flags & BTREE_PREFORMAT ){
rc = SQLITE_OK;
szNew = p->pBt->nPreformatSize;
if( szNew<4 ) szNew = 4;
if( szNew<4 ){
szNew = 4;
newCell[3] = 0;
}
if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
CellInfo info;
pPage->xParseCell(pPage, newCell, &info);
@@ -10791,6 +10800,9 @@ static int checkTreePage(
** number of cells on the page. */
nCell = get2byte(&data[hdr+3]);
assert( pPage->nCell==nCell );
if( pPage->leaf || pPage->intKey==0 ){
pCheck->nRow += nCell;
}
/* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
** immediately follows the b-tree page header. */
@@ -10902,6 +10914,7 @@ static int checkTreePage(
btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
}
}
assert( heap!=0 );
/* Add the freeblocks to the min-heap
**
** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
@@ -11001,6 +11014,7 @@ int sqlite3BtreeIntegrityCheck(
sqlite3 *db, /* Database connection that is running the check */
Btree *p, /* The btree to be checked */
Pgno *aRoot, /* An array of root pages numbers for individual trees */
Mem *aCnt, /* Memory cells to write counts for each tree to */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
int *pnErr, /* OUT: Write number of errors seen to this variable */
@@ -11014,7 +11028,9 @@ int sqlite3BtreeIntegrityCheck(
int bPartial = 0; /* True if not checking all btrees */
int bCkFreelist = 1; /* True to scan the freelist */
VVA_ONLY( int nRef );
assert( nRoot>0 );
assert( aCnt!=0 );
/* aRoot[0]==0 means this is a partial check */
if( aRoot[0]==0 ){
@@ -11087,15 +11103,18 @@ int sqlite3BtreeIntegrityCheck(
testcase( pBt->db->flags & SQLITE_CellSizeCk );
pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
i64 notUsed;
if( aRoot[i]==0 ) continue;
sCheck.nRow = 0;
if( aRoot[i] ){
i64 notUsed;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
}
if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
}
#endif
sCheck.v0 = aRoot[i];
checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
sCheck.v0 = aRoot[i];
checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
}
sqlite3MemSetArrayInt64(aCnt, i, sCheck.nRow);
}
pBt->db->flags = savedDbFlags;
+1
View File
@@ -331,6 +331,7 @@ int sqlite3BtreeIntegrityCheck(
sqlite3 *db, /* Database connection that is running the check */
Btree *p, /* The btree to be checked */
Pgno *aRoot, /* An array of root pages numbers for individual trees */
sqlite3_value *aCnt, /* OUT: entry counts for each btree in aRoot[] */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
int *pnErr, /* OUT: Write number of errors seen to this variable */
+1
View File
@@ -707,6 +707,7 @@ struct IntegrityCk {
StrAccum errMsg; /* Accumulate the error message text here */
u32 *heap; /* Min-heap used for analyzing cell coverage */
sqlite3 *db; /* Database connection running the check */
i64 nRow; /* Number of rows visited in current tree */
};
/*
+294 -196
View File
@@ -2923,11 +2923,11 @@ void sqlite3EndTable(
/* Test for cycles in generated columns and illegal expressions
** in CHECK constraints and in DEFAULT clauses. */
if( p->tabFlags & TF_HasGenerated ){
sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0,
sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"",
db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
}
sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0,
sqlite3MPrintf(db, "PRAGMA \"%w\".integrity_check(%Q)",
db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
}
@@ -3260,84 +3260,129 @@ void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){
#endif
/*
** Write code to erase the table with root-page iTable from database iDb.
** Also write code to modify the sqlite_schema table and internal schema
** if a root-page of another table is moved by the btree-layer whilst
** erasing iTable (this can happen with an auto-vacuum database).
** The RootStack object holds a list (really a Heap) of btree root pages
** and schema numbers that need to be deleted using OP_Destroy.
**
** OP_Destroy opcodes must be issued in order of decreasing root page
** numbers in order to avoid having auto-vacuum disrupt subsequent
** OP_Destroy opcodes. For that reason, all pending OP_Destroy calls
** are accumulated in an instance of this object. Then at the end of
** code generation, this object is used to generate the OP_Destroy opcodes
** in decreasing order.
**
** The data structure is a max-heap. Each rootpage/schema-number combo
** is stored as a 64-bit integer, with the schema-number in the upper 32
** bits and the page number in the lower 32-bits. The root of the heap
** (RootStack.a[0]) is the largest entry in the heap. The children of
** heap entry i are i*2+1 and i*2+2. The heap always stays balanced by
** ensuring that a parent entry is larger than both children.
**
*/
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse);
int r1 = sqlite3GetTempReg(pParse);
if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema");
sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
sqlite3MayAbort(pParse);
#ifndef SQLITE_OMIT_AUTOVACUUM
/* OP_Destroy stores an in integer r1. If this integer
** is non-zero, then it is the root page number of a table moved to
** location iTable. The following code modifies the sqlite_schema table to
** reflect this.
**
** The "#NNN" in the SQL is a special constant that means whatever value
** is in register NNN. See grammar rules associated with the TK_REGISTER
** token for additional information.
*/
sqlite3NestedParse(pParse,
"UPDATE %Q." LEGACY_SCHEMA_TABLE
" SET rootpage=%d WHERE #%d AND rootpage=#%d",
pParse->db->aDb[iDb].zDbSName, iTable, r1, r1);
#endif
sqlite3ReleaseTempReg(pParse, r1);
typedef struct RootStack RootStack;
struct RootStack {
u32 nAlloc; /* Slots allocated for a[] */
u32 nUsed; /* Slots used for in a[] */
u64 *a; /* Sorting heap. Each entry has iDb in the upper 32 bits and
** a page number in the lower 32 bits */
};
/*
** Add a new Pgno and iDb to the RootStack in question.
**
** The new entry is inserted at the of the heap (most distant child)
** and then the heap is rebalanced.
*/
static void rootStackPush(Parse *pParse, RootStack *p, Pgno pgno, int iDb){
u64 iNew;
int i, j;
if( p->nAlloc<p->nUsed+1 ){
p->nAlloc = p->nAlloc*2 + 12;
p->a = sqlite3DbRealloc(pParse->db, p->a, sizeof(Pgno)*p->nAlloc);
if( p->a==0 ){
p->nAlloc = p->nUsed = 0;
return;
}
}
assert( pgno>0 || CORRUPT_DB );
assert( iDb>=0 && iDb<pParse->db->nDb );
iNew = (((u64)iDb)<<32) | pgno;
i = p->nUsed++;
p->a[i] = iNew;
while( i>=1 && p->a[j = (i-1)/2]<p->a[i] ){
u64 tmp = p->a[i];
p->a[i] = p->a[j];
p->a[j] = tmp;
i = j;
}
}
/*
** Write VDBE code to erase table pTab and all associated indices on disk.
** Code to update the sqlite_schema tables and internal schema definitions
** in case a root-page belonging to another table is moved by the btree layer
** is also added (this can happen with an auto-vacuum database).
** Remove the largest entry from the RootStack heap. Rebalance the
** heap and then return that largest entry.
*/
static void destroyTable(Parse *pParse, Table *pTab){
/* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
** is not defined), then it is important to call OP_Destroy on the
** table and index root-pages in order, starting with the numerically
** largest root-page number. This guarantees that none of the root-pages
** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the
** following were coded:
**
** OP_Destroy 4 0
** ...
** OP_Destroy 5 0
**
** and root page 5 happened to be the largest root-page number in the
** database, then root page 5 would be moved to page 4 by the
** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
** a free-list page.
*/
Pgno iTab = pTab->tnum;
Pgno iDestroyed = 0;
while( 1 ){
Index *pIdx;
Pgno iLargest = 0;
if( iDestroyed==0 || iTab<iDestroyed ){
iLargest = iTab;
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
Pgno iIdx = pIdx->tnum;
assert( pIdx->pSchema==pTab->pSchema );
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
iLargest = iIdx;
}
}
if( iLargest==0 ){
return;
}else{
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
assert( iDb>=0 && iDb<pParse->db->nDb );
destroyRootPage(pParse, iLargest, iDb);
iDestroyed = iLargest;
}
static u64 rootStackPop(RootStack *p){
u64 iMax;
int i, j;
assert( p->nUsed>0 );
assert( p->a!=0 );
iMax = p->a[0];
p->a[0] = p->a[--p->nUsed];
i = 0;
while( (j = i*2+1)<p->nUsed ){
u64 tmp;
if( j+1<p->nUsed && p->a[j+1]>p->a[j] ) j++;
if( p->a[i]>p->a[j] ) break;
tmp = p->a[i];
p->a[i] = p->a[j];
p->a[j] = tmp;
i = j;
}
return iMax;
}
/*
** Generate OP_Destroy opcodes for every btree named in the given
** RootStack object. Issue these OP_Destroy opcodes in order of decreasing
** root page number. Then clean up any memory used by the RootStack.
*/
static void rootStackCode(Parse *pParse, RootStack *p){
int iLastDb = -1;
int r1 = sqlite3GetTempReg(pParse);
int r2 = sqlite3GetTempReg(pParse);
int regReturn = sqlite3GetTempReg(pParse);
Vdbe *v = pParse->pVdbe;
int addrSub = 0;
while( pParse->nErr==0 && p->nUsed>0 ){
u64 iNext = rootStackPop(p);
Pgno pgno = iNext & 0xffffffff;
int iDb = (iNext>>32)&0xffff;
if( pgno<2 ) sqlite3ErrorMsg(pParse, "corrupt schema");
sqlite3MayAbort(pParse);
if( iDb!=iLastDb ){
/* Code a subroutine to that will update the schema table when
** a root page number changes. The old root page is in register r1.
** Root page is moved to the value in register r2. */
iLastDb = iDb;
sqlite3VdbeAddOp0(v, OP_Goto);
addrSub = sqlite3VdbeCurrentAddr(v);
sqlite3NestedParse(pParse,
"UPDATE %Q." LEGACY_SCHEMA_TABLE
" SET rootpage=#%d WHERE rootpage=#%d",
pParse->db->aDb[iDb].zDbSName, r2, r1);
sqlite3VdbeAddOp1(v, OP_Return, regReturn);
sqlite3VdbeJumpHere(v, addrSub-1);
}
sqlite3VdbeAddOp3(v, OP_Destroy, pgno, r1, iDb);
sqlite3VdbeAddOp2(v, OP_IfNot, r1, sqlite3VdbeCurrentAddr(v)+3);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, pgno, r2);
sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, addrSub);
}
if( pParse->nErr==0 ){
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, regReturn);
}
sqlite3DbFree(pParse->db, p->a);
}
/*
@@ -3367,7 +3412,12 @@ static void sqlite3ClearStatTables(
/*
** Generate code to drop a table.
*/
void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
static void sqlite3CodeDropTable(
Parse *pParse, /* Parsing context */
RootStack *pStack, /* List of pending OP_Destroys */
Table *pTab, /* Table to be dropped */
int iDb /* Schema holding pTab */
){
Vdbe *v;
sqlite3 *db = pParse->db;
Trigger *pTrigger;
@@ -3420,8 +3470,13 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE
" WHERE tbl_name=%Q and type!='trigger'",
pDb->zDbSName, pTab->zName);
if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab);
if( IsOrdinaryTable(pTab) ){
Index *pIdx;
rootStackPush(pParse, pStack, pTab->tnum, iDb);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->tnum==pTab->tnum ) continue;
rootStackPush(pParse, pStack, pIdx->tnum, iDb);
}
}
/* Remove the table entry from SQLite's internal schema and modify
@@ -3477,106 +3532,134 @@ static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){
*/
void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
Table *pTab;
Vdbe *v;
sqlite3 *db = pParse->db;
int iDb;
int ii, jj;
RootStack rootStack;
if( db->mallocFailed ){
goto exit_drop_table;
}
assert( pParse->nErr==0 );
assert( pName->nSrc==1 );
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
if( noErr ) db->suppressErr++;
assert( isView==0 || isView==LOCATE_VIEW );
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
if( noErr ) db->suppressErr--;
memset(&rootStack, 0, sizeof(rootStack));
(void)sqlite3GetVdbe(pParse);
sqlite3ReadSchema(pParse);
assert( pName!=0 || pParse->nErr!=0 );
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
if( noErr ) db->suppressErr++;
assert( isView==0 || isView==LOCATE_VIEW );
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[ii]);
if( noErr ) db->suppressErr--;
if( pTab==0 ){
if( noErr ){
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
sqlite3ForceNotReadOnly(pParse);
if( pTab==0 ){
if( noErr ){
sqlite3CodeVerifyNamedSchema(pParse, pName->a[ii].zDatabase);
sqlite3ForceNotReadOnly(pParse);
}
testcase( ii+1<pName->nSrc );
continue;
}
goto exit_drop_table;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb>=0 && iDb<db->nDb );
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb>=0 && iDb<db->nDb );
/* If pTab is a virtual table, call ViewGetColumnNames() to ensure
** it is initialized.
*/
if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
goto exit_drop_table;
}
/* If pTab is a virtual table, call ViewGetColumnNames() to ensure
** it is initialized.
*/
if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
break;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code;
const char *zTab = SCHEMA_TABLE(iDb);
const char *zDb = db->aDb[iDb].zDbSName;
const char *zArg2 = 0;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
goto exit_drop_table;
}
if( isView ){
if( !OMIT_TEMPDB && iDb==1 ){
code = SQLITE_DROP_TEMP_VIEW;
}else{
code = SQLITE_DROP_VIEW;
{
int code;
const char *zTab = SCHEMA_TABLE(iDb);
const char *zDb = db->aDb[iDb].zDbSName;
const char *zArg2 = 0;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
break;
}
if( isView ){
if( !OMIT_TEMPDB && iDb==1 ){
code = SQLITE_DROP_TEMP_VIEW;
}else{
code = SQLITE_DROP_VIEW;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
}else if( IsVirtual(pTab) ){
code = SQLITE_DROP_VTABLE;
zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
}else if( IsVirtual(pTab) ){
code = SQLITE_DROP_VTABLE;
zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
#endif
}else{
if( !OMIT_TEMPDB && iDb==1 ){
code = SQLITE_DROP_TEMP_TABLE;
}else{
code = SQLITE_DROP_TABLE;
if( !OMIT_TEMPDB && iDb==1 ){
code = SQLITE_DROP_TEMP_TABLE;
}else{
code = SQLITE_DROP_TABLE;
}
}
if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
break;
}
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
break;
}
}
if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
goto exit_drop_table;
}
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
goto exit_drop_table;
}
}
#endif
if( tableMayNotBeDropped(db, pTab) ){
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
goto exit_drop_table;
}
if( tableMayNotBeDropped(db, pTab) ){
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
break;
}
#ifndef SQLITE_OMIT_VIEW
/* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
** on a table.
*/
if( isView && !IsView(pTab) ){
sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);
goto exit_drop_table;
}
if( !isView && IsView(pTab) ){
sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);
goto exit_drop_table;
}
/* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
** on a table.
*/
if( isView && !IsView(pTab) ){
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);
break;
}
if( !isView && IsView(pTab) ){
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);
break;
}
#endif
/* If this table or view has appeared previously in the list of tables
** or views to be dropped, then the prior appearance is sufficient so
** skip this one. */
for(jj=ii-1; jj>=0 && pName->a[jj].pTab!=pTab; jj--){}
if( jj>=0 ) continue;
/* Generate code to remove the table from the schema table
** on disk.
*/
v = sqlite3GetVdbe(pParse);
if( v ){
/* Remember the table for use in the second pass */
pName->a[ii].pTab = pTab;
pTab->nTabRef++;
/* Generate code to clear this table from sqlite_statN and to
** cascade foreign key constraints.
*/
sqlite3BeginWriteOperation(pParse, 1, iDb);
if( !isView ){
if( IsOrdinaryTable(pTab) ){
sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
sqlite3FkDropTable(pParse, pName, pTab);
}
sqlite3CodeDropTable(pParse, pTab, iDb, isView);
}
exit_drop_table:
/* Generate code to actually delete the tables/views in a second pass.
** Btrees must be deleted largest root page first, to avoid problems
** caused by autovacuum page reordering. */
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
pTab = pName->a[ii].pTab;
if( pTab==0 ) continue;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3CodeDropTable(pParse, &rootStack, pTab, iDb);
}
sqlite3SrcListDelete(db, pName);
rootStackCode(pParse, &rootStack);
}
/*
@@ -4576,67 +4659,82 @@ void sqlite3DefaultRowEst(Index *pIdx){
*/
void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
Index *pIndex;
Vdbe *v;
sqlite3 *db = pParse->db;
Vdbe *v;
int iDb;
int ii, jj;
RootStack rootStack;
if( db->mallocFailed ){
goto exit_drop_index;
}
assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
assert( pName->nSrc==1 );
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto exit_drop_index;
}
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
if( pIndex==0 ){
if( !ifExists ){
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
}else{
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
sqlite3ForceNotReadOnly(pParse);
memset(&rootStack, 0, sizeof(rootStack));
v = sqlite3GetVdbe(pParse);
sqlite3ReadSchema(pParse);
assert( pName!=0 || pParse->nErr!=0 );
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
pName->a[ii].regReturn = 0;
pIndex = sqlite3FindIndex(db, pName->a[ii].zName, pName->a[ii].zDatabase);
if( pIndex==0 ){
if( !ifExists ){
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a+ii);
}else{
sqlite3CodeVerifyNamedSchema(pParse, pName->a[ii].zDatabase);
sqlite3ForceNotReadOnly(pParse);
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
}
pParse->checkSchema = 1;
continue;
}
pParse->checkSchema = 1;
goto exit_drop_index;
}
if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
"or PRIMARY KEY constraint cannot be dropped", 0);
goto exit_drop_index;
}
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
"or PRIMARY KEY constraint cannot be dropped", 0);
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
break;
}
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_DROP_INDEX;
Table *pTab = pIndex->pTable;
const char *zDb = db->aDb[iDb].zDbSName;
const char *zTab = SCHEMA_TABLE(iDb);
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
goto exit_drop_index;
{
int code = SQLITE_DROP_INDEX;
Table *pTab = pIndex->pTable;
const char *zDb = db->aDb[iDb].zDbSName;
const char *zTab = SCHEMA_TABLE(iDb);
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
break;
}
if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
break;
}
}
if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
goto exit_drop_index;
}
}
#endif
/* Generate code to remove the index and from the schema table */
v = sqlite3GetVdbe(pParse);
if( v ){
/* Skip over redundant DROP INDEXes */
for(jj=ii-1; jj>=0 && pName->a[jj].u2.pIdx!=pIndex; jj--){}
if( jj>=0 ) continue;
/* Record that this index needs to be dropped. */
pName->a[ii].u2.pIdx = pIndex;
/* Generate code to remove the index and from the schema table and
** from sqlite_statN tables */
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3NestedParse(pParse,
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'",
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE
" WHERE name=%Q AND type='index'",
db->aDb[iDb].zDbSName, pIndex->zName
);
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
rootStackPush(pParse, &rootStack, pIndex->tnum, iDb);
sqlite3ChangeCookie(pParse, iDb);
destroyRootPage(pParse, pIndex->tnum, iDb);
sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0);
}
exit_drop_index:
sqlite3SrcListDelete(db, pName);
rootStackCode(pParse, &rootStack);
}
/*
+6 -5
View File
@@ -914,11 +914,12 @@ void sqlite3ExprSetErrorOffset(Expr *pExpr, int iOfst){
** appear to be quoted. If the quotes were of the form "..." (double-quotes)
** then the EP_DblQuoted flag is set on the expression node.
**
** Special case: If op==TK_INTEGER and pToken points to a string that
** can be translated into a 32-bit integer, then the token is not
** stored in u.zToken. Instead, the integer values is written
** into u.iValue and the EP_IntValue flag is set. No extra storage
** Special case (tag-20240227-a): If op==TK_INTEGER and pToken points to
** a string that can be translated into a 32-bit integer, then the token is
** not stored in u.zToken. Instead, the integer values is written
** into u.iValue and the EP_IntValue flag is set. No extra storage
** is allocated to hold the integer text and the dequote flag is ignored.
** See also tag-20240227-b.
*/
Expr *sqlite3ExprAlloc(
sqlite3 *db, /* Handle for sqlite3DbMallocRawNN() */
@@ -934,7 +935,7 @@ Expr *sqlite3ExprAlloc(
if( pToken ){
if( op!=TK_INTEGER || pToken->z==0
|| sqlite3GetInt32(pToken->z, &iValue)==0 ){
nExtra = pToken->n+1;
nExtra = pToken->n+1; /* tag-20240227-a */
assert( iValue>=0 );
}
}
+25 -6
View File
@@ -718,8 +718,9 @@ void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){
/*
** This function is called to generate code that runs when table pTab is
** being dropped from the database. The SrcList passed as the second argument
** to this function contains a single entry guaranteed to resolve to
** table pTab.
** to this function contains entries for every table that is being dropped,
** with the SrcItem.pTab line being set to the table being dropped. pTab
** will be one of those tables.
**
** Normally, no code is required. However, if either
**
@@ -728,15 +729,23 @@ void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){
** determined at runtime that there are outstanding deferred FK
** constraint violations in the database,
**
** then the equivalent of "DELETE FROM <tbl>" is executed before dropping
** the table from the database. Triggers are disabled while running this
** DELETE, but foreign key actions are not.
** then the equivalent of "DELETE FROM <tbl>" is executed for every table
** being dropped, in the order specified in the DROP TABLE statement, which
** is the same as the order in which these tables appear in pName.
** Triggers are disabled while running these DELETEs, but foreign key
** actions are not.
**
** This routine sets the SrcList.addrFillSub value for all pName entries
** for which DELETE FROM has been run. This prevents the DELETE FROM
** from being run multiple times.
*/
void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
sqlite3 *db = pParse->db;
if( (db->flags&SQLITE_ForeignKeys) && IsOrdinaryTable(pTab) ){
int iSkip = 0;
Vdbe *v = sqlite3GetVdbe(pParse);
SrcList *pSrc;
int ii;
assert( v ); /* VDBE has already been allocated */
assert( IsOrdinaryTable(pTab) );
@@ -756,7 +765,17 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
}
pParse->disableTriggers = 1;
sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0);
for(ii=0; ii<pName->nSrc; ii++){
if( pName->a[ii].pTab==0 ) continue;
if( pName->a[ii].addrFillSub ) continue;
pName->a[ii].addrFillSub = 1;
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pSrc ){
pSrc->a[0].zDatabase = sqlite3DbStrDup(db, pName->a[ii].zDatabase);
pSrc->a[0].zName = sqlite3DbStrDup(db, pName->a[ii].zName);
sqlite3DeleteFrom(pParse, pSrc, 0, 0, 0);
}
}
pParse->disableTriggers = 0;
/* If the DELETE has generated immediate foreign key constraint
+2 -2
View File
@@ -1101,13 +1101,13 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
double r1, r2;
const char *zVal;
r1 = sqlite3_value_double(pValue);
sqlite3_str_appendf(pStr, "%!.15g", r1);
sqlite3_str_appendf(pStr, "%!0.15g", r1);
zVal = sqlite3_str_value(pStr);
if( zVal ){
sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
if( r1!=r2 ){
sqlite3_str_reset(pStr);
sqlite3_str_appendf(pStr, "%!.20e", r1);
sqlite3_str_appendf(pStr, "%!0.20e", r1);
}
}
break;
+10 -1
View File
@@ -1623,6 +1623,7 @@ json_parse_restart:
case '[': {
/* Parse array */
iThis = pParse->nBlob;
assert( i<=(u32)pParse->nJson );
jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0);
iStart = pParse->nBlob;
if( pParse->oom ) return -1;
@@ -2027,6 +2028,10 @@ static void jsonReturnStringAsBlob(JsonString *pStr){
JsonParse px;
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);
@@ -3359,8 +3364,9 @@ rebuild_from_cache:
}
p->zJson = (char*)sqlite3_value_text(pArg);
p->nJson = sqlite3_value_bytes(pArg);
if( db->mallocFailed ) goto json_pfa_oom;
if( p->nJson==0 ) goto json_pfa_malformed;
if( NEVER(p->zJson==0) ) goto json_pfa_oom;
assert( p->zJson!=0 );
if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){
if( flgs & JSON_KEEPERROR ){
p->nErr = 1;
@@ -4938,6 +4944,9 @@ static int jsonEachColumn(
case JEACH_VALUE: {
u32 i = jsonSkipLabel(p);
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
break;
}
case JEACH_TYPE: {
+4 -4
View File
@@ -228,9 +228,9 @@ static void sqlite3MallocAlarm(int nByte){
** code debuggers when working on out-of-memory conditions, for example
** caused by PRAGMA hard_heap_limit=N.
*/
static SQLITE_NOINLINE void test_oom_breakpoint(void){
static SQLITE_NOINLINE void test_oom_breakpoint(u64 n){
static u64 nOomFault = 0;
nOomFault++;
nOomFault += n;
/* The assert() is never reached in a human lifetime. It is here mostly
** to prevent code optimizers from optimizing out this function. */
assert( (nOomFault>>32) < 0xffffffff );
@@ -265,7 +265,7 @@ static void mallocWithAlarm(int n, void **pp){
if( mem0.hardLimit ){
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.hardLimit - nFull ){
test_oom_breakpoint();
test_oom_breakpoint(1);
*pp = 0;
return;
}
@@ -554,7 +554,7 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
sqlite3MallocAlarm(nDiff);
if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){
sqlite3_mutex_leave(mem0.mutex);
test_oom_breakpoint();
test_oom_breakpoint(1);
return 0;
}
}
+5 -1
View File
@@ -1295,8 +1295,12 @@ static int unixLogErrorAtLine(
** available, the error message will often be an empty string. Not a
** huge problem. Incorrectly concluding that the GNU version is available
** could lead to a segfault though.
**
** Forum post 3f13857fa4062301 reports that the Android SDK may use
** int-type return, depending on its version.
*/
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
#if (defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)) \
&& !defined(ANDROID) && !defined(__ANDROID__)
zErr =
# endif
strerror_r(iErrno, aErr, sizeof(aErr)-1);
+22 -4
View File
@@ -471,7 +471,7 @@ resolvetype(A) ::= REPLACE. {A = OE_Replace;}
////////////////////////// The DROP TABLE /////////////////////////////////////
//
cmd ::= DROP TABLE ifexists(E) fullname(X). {
cmd ::= DROP TABLE ifexists(E) fullnamelist(X). {
sqlite3DropTable(pParse, X, 0, E);
}
%type ifexists {int}
@@ -485,7 +485,7 @@ cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) eidlist_opt(C)
AS select(S). {
sqlite3CreateView(pParse, &X, &Y, &Z, C, S, T, E);
}
cmd ::= DROP VIEW ifexists(E) fullname(X). {
cmd ::= DROP VIEW ifexists(E) fullnamelist(X). {
sqlite3DropTable(pParse, X, 1, E);
}
%endif SQLITE_OMIT_VIEW
@@ -774,6 +774,18 @@ fullname(A) ::= nm(X) DOT nm(Y). {
if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &Y);
}
%type fullnamelist {SrcList*}
%destructor fullnamelist {sqlite3SrcListDelete(pParse->db, $$);}
fullnamelist(A) ::= fullname(A).
fullnamelist(A) ::= fullnamelist(L) COMMA nm(X). {
A = sqlite3SrcListAppend(pParse,L,&X,0);
assert( !IN_RENAME_OBJECT ); /* Used only by DROP, which cannot be part of schema */
}
fullnamelist(A) ::= fullnamelist(L) COMMA nm(X) DOT nm(Y). {
A = sqlite3SrcListAppend(pParse,L,&X,&Y);
assert( !IN_RENAME_OBJECT ); /* Used only by DROP, which cannot be part of schema */
}
%type xfullname {SrcList*}
%destructor xfullname {sqlite3SrcListDelete(pParse->db, $$);}
xfullname(A) ::= nm(X).
@@ -1504,7 +1516,7 @@ collate(C) ::= COLLATE ids. {C = 1;}
///////////////////////////// The DROP INDEX command /////////////////////////
//
cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
cmd ::= DROP INDEX ifexists(E) fullnamelist(X). {sqlite3DropIndex(pParse, X, E);}
///////////////////////////// The VACUUM command /////////////////////////////
//
@@ -1661,7 +1673,7 @@ raisetype(A) ::= FAIL. {A = OE_Fail;}
//////////////////////// DROP TRIGGER statement //////////////////////////////
%ifndef SQLITE_OMIT_TRIGGER
cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
cmd ::= DROP TRIGGER ifexists(NOERR) fullnamelist(X). {
sqlite3DropTrigger(pParse,X,NOERR);
}
%endif !SQLITE_OMIT_TRIGGER
@@ -1935,6 +1947,12 @@ filter_clause(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
SPAN /* The span operator */
ERROR /* An expression containing an error */
.
term(A) ::= QNUMBER(X). {
A=tokenExpr(pParse,@X,X);
sqlite3DequoteNumber(pParse, A);
}
/* There must be no more than 255 tokens defined above. If this grammar
** is extended with new rules and tokens, they must either be so few in
** number that TK_SPAN is no more than 255, or else the new tokens must
+187 -58
View File
@@ -30,6 +30,34 @@
** ../tool/mkpragmatab.tcl. */
#include "pragma.h"
/*
** When the 0x10 bit of PRAGMA optimize is set, any ANALYZE commands
** will be run with an analysis_limit set to the lessor of the value of
** the following macro or to the actual analysis_limit if it is non-zero,
** in order to prevent PRAGMA optimize from running for too long.
**
** The value of 2000 is chosen emperically so that the worst-case run-time
** for PRAGMA optimize does not exceed 100 milliseconds against a variety
** of test databases on a RaspberryPI-4 compiled using -Os and without
** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of
** this paragraph, "worst-case" means that ANALYZE ends up being
** run on every table in the database. The worst case typically only
** happens if PRAGMA optimize is run on a database file for which ANALYZE
** has not been previously run and the 0x10000 flag is included so that
** all tables are analyzed. The usual case for PRAGMA optimize is that
** no ANALYZE commands will be run at all, or if any ANALYZE happens it
** will be against a single table, so that expected timing for PRAGMA
** optimize on a PI-4 is more like 1 millisecond or less with the 0x10000
** flag or less than 100 microseconds without the 0x10000 flag.
**
** An analysis limit of 2000 is almost always sufficient for the query
** planner to fully characterize an index. The additional accuracy from
** a larger analysis is not usually helpful.
*/
#ifndef SQLITE_DEFAULT_OPTIMIZE_LIMIT
# define SQLITE_DEFAULT_OPTIMIZE_LIMIT 2000
#endif
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
@@ -1692,7 +1720,6 @@ void sqlite3Pragma(
Hash *pTbls; /* Set of all tables in the schema */
int *aRoot; /* Array of root page numbers of all btrees */
int cnt = 0; /* Number of entries in aRoot[] */
int mxIdx = 0; /* Maximum number of indexes for any table */
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
@@ -1714,7 +1741,6 @@ void sqlite3Pragma(
if( pObjTab && pObjTab!=pTab ) continue;
if( HasRowid(pTab) ) cnt++;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
if( nIdx>mxIdx ) mxIdx = nIdx;
}
if( cnt==0 ) continue;
if( pObjTab ) cnt++;
@@ -1734,11 +1760,11 @@ void sqlite3Pragma(
aRoot[0] = cnt;
/* Make sure sufficient number of registers have been allocated */
sqlite3TouchRegister(pParse, 8+mxIdx);
sqlite3TouchRegister(pParse, 8+cnt);
sqlite3ClearTempRegCache(pParse);
/* Do the b-tree integrity checks */
sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY);
sqlite3VdbeChangeP5(v, (u8)i);
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
@@ -1748,6 +1774,36 @@ void sqlite3Pragma(
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
/* Check that the indexes all have the right number of rows */
cnt = pObjTab ? 1 : 0;
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
int iTab = 0;
Table *pTab = sqliteHashData(x);
Index *pIdx;
if( pObjTab && pObjTab!=pTab ) continue;
if( HasRowid(pTab) ){
iTab = cnt++;
}else{
iTab = cnt;
for(pIdx=pTab->pIndex; ALWAYS(pIdx); pIdx=pIdx->pNext){
if( IsPrimaryKeyIndex(pIdx) ) break;
iTab++;
}
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->pPartIdxWhere==0 ){
addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+cnt, 0, 8+iTab);
VdbeCoverageNeverNull(v);
sqlite3VdbeLoadString(v, 4, pIdx->zName);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
}
cnt++;
}
}
/* Make sure all the indices are constructed correctly.
*/
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
@@ -1897,6 +1953,7 @@ void sqlite3Pragma(
** is REAL, we have to load the actual data using OP_Column
** to reliably determine if the value is a NULL. */
sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
sqlite3ColumnDefault(v, pTab, j, 3);
jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
VdbeCoverage(v);
}
@@ -2070,21 +2127,9 @@ void sqlite3Pragma(
}
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
if( !isQuick ){
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
if( pPk==pIdx ) continue;
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
sqlite3VdbeLoadString(v, 4, pIdx->zName);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
}
if( pPk ){
sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
}
if( pPk ){
assert( !isQuick );
sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
}
}
@@ -2116,10 +2161,9 @@ void sqlite3Pragma(
a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, a1);
#endif
continue;
}
#endif
}
{
static const int iLn = VDBE_OFFSET_LINENO(2);
@@ -2383,44 +2427,63 @@ void sqlite3Pragma(
**
** The optional argument is a bitmask of optimizations to perform:
**
** 0x0001 Debugging mode. Do not actually perform any optimizations
** but instead return one line of text for each optimization
** that would have been done. Off by default.
** 0x00001 Debugging mode. Do not actually perform any optimizations
** but instead return one line of text for each optimization
** that would have been done. Off by default.
**
** 0x0002 Run ANALYZE on tables that might benefit. On by default.
** See below for additional information.
** 0x00002 Run ANALYZE on tables that might benefit. On by default.
** See below for additional information.
**
** 0x0004 (Not yet implemented) Record usage and performance
** information from the current session in the
** database file so that it will be available to "optimize"
** pragmas run by future database connections.
** 0x00010 Run all ANALYZE operations using an analysis_limit that
** is the lessor of the current analysis_limit and the
** SQLITE_DEFAULT_OPTIMIZE_LIMIT compile-time option.
** The default value of SQLITE_DEFAULT_OPTIMIZE_LIMIT is
** currently (2024-02-19) set to 2000, which is such that
** the worst case run-time for PRAGMA optimize on a 100MB
** database will usually be less than 100 milliseconds on
** a RaspberryPI-4 class machine. On by default.
**
** 0x0008 (Not yet implemented) Create indexes that might have
** been helpful to recent queries
** 0x10000 Look at tables to see if they need to be reanalyzed
** due to growth or shrinkage even if they have not been
** queried during the current connection. Off by default.
**
** The default MASK is and always shall be 0xfffe. 0xfffe means perform all
** of the optimizations listed above except Debug Mode, including new
** optimizations that have not yet been invented. If new optimizations are
** ever added that should be off by default, those off-by-default
** optimizations will have bitmasks of 0x10000 or larger.
** The default MASK is and always shall be 0x0fffe. In the current
** implementation, the default mask only covers the 0x00002 optimization,
** though additional optimizations that are covered by 0x0fffe might be
** added in the future. Optimizations that are off by default and must
** be explicitly requested have masks of 0x10000 or greater.
**
** DETERMINATION OF WHEN TO RUN ANALYZE
**
** In the current implementation, a table is analyzed if only if all of
** the following are true:
**
** (1) MASK bit 0x02 is set.
** (1) MASK bit 0x00002 is set.
**
** (2) The query planner used sqlite_stat1-style statistics for one or
** more indexes of the table at some point during the lifetime of
** the current connection.
** (2) The table is an ordinary table, not a virtual table or view.
**
** (3) One or more indexes of the table are currently unanalyzed OR
** the number of rows in the table has increased by 25 times or more
** since the last time ANALYZE was run.
** (3) The table name does not begin with "sqlite_".
**
** (4) One or more of the following is true:
** (4a) The 0x10000 MASK bit is set.
** (4b) One or more indexes on the table lacks an entry
** in the sqlite_stat1 table.
** (4c) The query planner used sqlite_stat1-style statistics for one
** or more indexes of the table at some point during the lifetime
** of the current connection.
**
** (5) One or more of the following is true:
** (5a) One or more indexes on the table lacks an entry
** in the sqlite_stat1 table. (Same as 4a)
** (5b) The number of rows in the table has increased or decreased by
** 10-fold. In other words, the current size of the table is
** 10 times larger than the size in sqlite_stat1 or else the
** current size is less than 1/10th the size in sqlite_stat1.
**
** The rules for when tables are analyzed are likely to change in
** future releases.
** future releases. Future versions of SQLite might accept a string
** literal argument to this pragma that contains a mnemonic description
** of the options rather than a bitmap.
*/
case PragTyp_OPTIMIZE: {
int iDbLast; /* Loop termination point for the schema loop */
@@ -2432,6 +2495,10 @@ void sqlite3Pragma(
LogEst szThreshold; /* Size threshold above which reanalysis needed */
char *zSubSql; /* SQL statement for the OP_SqlExec opcode */
u32 opMask; /* Mask of operations to perform */
int nLimit; /* Analysis limit to use */
int nCheck = 0; /* Number of tables to be optimized */
int nBtree = 0; /* Number of btrees to scan */
int nIndex; /* Number of indexes on the current table */
if( zRight ){
opMask = (u32)sqlite3Atoi(zRight);
@@ -2439,6 +2506,14 @@ void sqlite3Pragma(
}else{
opMask = 0xfffe;
}
if( (opMask & 0x10)==0 ){
nLimit = 0;
}else if( db->nAnalysisLimit>0
&& db->nAnalysisLimit<SQLITE_DEFAULT_OPTIMIZE_LIMIT ){
nLimit = 0;
}else{
nLimit = SQLITE_DEFAULT_OPTIMIZE_LIMIT;
}
iTabCur = pParse->nTab++;
for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){
if( iDb==1 ) continue;
@@ -2447,23 +2522,61 @@ void sqlite3Pragma(
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
/* If table pTab has not been used in a way that would benefit from
** having analysis statistics during the current session, then skip it.
** This also has the effect of skipping virtual tables and views */
if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue;
/* This only works for ordinary tables */
if( !IsOrdinaryTable(pTab) ) continue;
/* Reanalyze if the table is 25 times larger than the last analysis */
szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 );
/* Do not scan system tables */
if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ) continue;
/* Find the size of the table as last recorded in sqlite_stat1.
** If any index is unanalyzed, then the threshold is -1 to
** indicate a new, unanalyzed index
*/
szThreshold = pTab->nRowLogEst;
nIndex = 0;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
nIndex++;
if( !pIdx->hasStat1 ){
szThreshold = 0; /* Always analyze if any index lacks statistics */
break;
szThreshold = -1; /* Always analyze if any index lacks statistics */
}
}
if( szThreshold ){
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur,
sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
/* If table pTab has not been used in a way that would benefit from
** having analysis statistics during the current session, then skip it,
** unless the 0x10000 MASK bit is set. */
if( (pTab->tabFlags & TF_MaybeReanalyze)!=0 ){
/* Check for size change if stat1 has been used for a query */
}else if( opMask & 0x10000 ){
/* Check for size change if 0x10000 is set */
}else if( pTab->pIndex!=0 && szThreshold<0 ){
/* Do analysis if unanalyzed indexes exists */
}else{
/* Otherwise, we can skip this table */
continue;
}
nCheck++;
if( nCheck==2 ){
/* If ANALYZE might be invoked two or more times, hold a write
** transaction for efficiency */
sqlite3BeginWriteOperation(pParse, 0, iDb);
}
nBtree += nIndex+1;
/* Reanalyze if the table is 10 times larger or smaller than
** the last analysis. Unconditional reanalysis if there are
** unanalyzed indexes. */
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
if( szThreshold>=0 ){
const LogEst iRange = 33; /* 10x size change */
sqlite3VdbeAddOp4Int(v, OP_IfSizeBetween, iTabCur,
sqlite3VdbeCurrentAddr(v)+2+(opMask&1),
szThreshold>=iRange ? szThreshold-iRange : -1,
szThreshold+iRange);
VdbeCoverage(v);
}else{
sqlite3VdbeAddOp2(v, OP_Rewind, iTabCur,
sqlite3VdbeCurrentAddr(v)+2+(opMask&1));
VdbeCoverage(v);
}
zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"",
@@ -2473,11 +2586,27 @@ void sqlite3Pragma(
sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC);
sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1);
}else{
sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC);
sqlite3VdbeAddOp4(v, OP_SqlExec, nLimit ? 0x02 : 00, nLimit, 0,
zSubSql, P4_DYNAMIC);
}
}
}
sqlite3VdbeAddOp0(v, OP_Expire);
/* In a schema with a large number of tables and indexes, scale back
** the analysis_limit to avoid excess run-time in the worst case.
*/
if( !db->mallocFailed && nLimit>0 && nBtree>100 ){
int iAddr, iEnd;
VdbeOp *aOp;
nLimit = 100*nLimit/nBtree;
if( nLimit<100 ) nLimit = 100;
aOp = sqlite3VdbeGetOp(v, 0);
iEnd = sqlite3VdbeCurrentAddr(v);
for(iAddr=0; iAddr<iEnd; iAddr++){
if( aOp[iAddr].opcode==OP_SqlExec ) aOp[iAddr].p2 = nLimit;
}
}
break;
}
+3 -1
View File
@@ -498,6 +498,7 @@ void sqlite3_str_vappendf(
if( xtype==etFLOAT ){
iRound = -precision;
}else if( xtype==etGENERIC ){
if( precision==0 ) precision = 1;
iRound = precision;
}else{
iRound = precision+1;
@@ -533,13 +534,14 @@ void sqlite3_str_vappendf(
}
exp = s.iDP-1;
if( xtype==etGENERIC && precision>0 ) precision--;
/*
** If the field type is etGENERIC, then convert to either etEXP
** or etFLOAT, as appropriate.
*/
if( xtype==etGENERIC ){
assert( precision>0 );
precision--;
flag_rtz = !flag_alternateform;
if( exp<-4 || exp>precision ){
xtype = etEXP;
+2
View File
@@ -79,6 +79,8 @@ static void resolveAlias(
assert( iCol>=0 && iCol<pEList->nExpr );
pOrig = pEList->a[iCol].pExpr;
assert( pOrig!=0 );
assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) );
if( pExpr->pAggInfo ) return;
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig, 0);
if( db->mallocFailed ){
+8
View File
@@ -6444,6 +6444,8 @@ void sqlite3SelectPrep(
*/
static void printAggInfo(AggInfo *pAggInfo){
int ii;
sqlite3DebugPrintf("AggInfo %d/%p:\n",
pAggInfo->selId, pAggInfo);
for(ii=0; ii<pAggInfo->nColumn; ii++){
struct AggInfo_col *pCol = &pAggInfo->aCol[ii];
sqlite3DebugPrintf(
@@ -8546,6 +8548,12 @@ select_end:
sqlite3ExprListDelete(db, pMinMaxOrderBy);
#ifdef SQLITE_DEBUG
if( pAggInfo && !db->mallocFailed ){
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x20 ){
TREETRACE(0x20,pParse,p,("Finished with AggInfo\n"));
printAggInfo(pAggInfo);
}
#endif
for(i=0; i<pAggInfo->nColumn; i++){
Expr *pExpr = pAggInfo->aCol[i].pCExpr;
if( pExpr==0 ) continue;
+157 -5
View File
@@ -268,6 +268,9 @@ INCLUDE ../ext/consio/console_io.c
* setOutputStream(FILE *pf)
* This is normally the stream that CLI normal output goes to.
* For the stand-alone CLI, it is stdout with no .output redirect.
*
* The ?putz(z) forms are required for the Fiddle builds for string literal
* output, in aid of enforcing format string to argument correspondence.
*/
# define sputz(s,z) fPutsUtf8(z,s)
# define sputf fPrintfUtf8
@@ -279,12 +282,18 @@ INCLUDE ../ext/consio/console_io.c
#else
/* For Fiddle, all console handling and emit redirection is omitted. */
# define sputz(fp,z) fputs(z,fp)
# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__)
# define oputz(z) fputs(z,stdout)
/* These next 3 macros are for emitting formatted output. When complaints
* from the WASM build are issued for non-formatted output, (when a mere
* string literal is to be emitted, the ?putz(z) forms should be used.
* (This permits compile-time checking of format string / argument mismatch.)
*/
# define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
# define eputz(z) fputs(z,stderr)
# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__)
/* These next 3 macros are for emitting simple string literals. */
# define oputz(z) fputs(z,stdout)
# define eputz(z) fputs(z,stderr)
# define sputz(fp,z) fputs(z,fp)
# define oputb(buf,na) fwrite(buf,1,na,stdout)
#endif
@@ -1213,6 +1222,9 @@ INCLUDE ../ext/misc/sqlar.c
INCLUDE ../ext/expert/sqlite3expert.h
INCLUDE ../ext/expert/sqlite3expert.c
INCLUDE ../ext/intck/sqlite3intck.h
INCLUDE ../ext/intck/sqlite3intck.c
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
#define SQLITE_SHELL_HAVE_RECOVER 1
#else
@@ -4732,6 +4744,7 @@ static const char *(azHelp[]) = {
".indexes ?TABLE? Show names of indexes",
" If TABLE is specified, only show indexes for",
" tables matching TABLE using the LIKE operator.",
".intck ?STEPS_PER_UNLOCK? Run an incremental integrity check on the db",
#ifdef SQLITE_ENABLE_IOTRACE
",iotrace FILE Enable I/O diagnostic logging to FILE",
#endif
@@ -7641,6 +7654,40 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
}
#endif /* SQLITE_SHELL_HAVE_RECOVER */
/*
** Implementation of ".intck STEPS_PER_UNLOCK" command.
*/
static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){
sqlite3_intck *p = 0;
int rc = SQLITE_OK;
rc = sqlite3_intck_open(pState->db, "main", &p);
if( rc==SQLITE_OK ){
i64 nStep = 0;
i64 nError = 0;
const char *zErr = 0;
while( SQLITE_OK==sqlite3_intck_step(p) ){
const char *zMsg = sqlite3_intck_message(p);
if( zMsg ){
oputf("%s\n", zMsg);
nError++;
}
nStep++;
if( nStepPerUnlock && (nStep % nStepPerUnlock)==0 ){
sqlite3_intck_unlock(p);
}
}
rc = sqlite3_intck_error(p, &zErr);
if( zErr ){
eputf("%s\n", zErr);
}
sqlite3_intck_close(p);
oputf("%lld steps, %lld errors\n", nStep, nError);
}
return rc;
}
/*
* zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it.
@@ -7884,6 +7931,38 @@ static int outputDumpWarning(ShellState *p, const char *zLike){
return rc;
}
/*
** Fault-Simulator state and logic.
*/
static struct {
int iId; /* ID that triggers a simulated fault. -1 means "any" */
int iErr; /* The error code to return on a fault */
int iCnt; /* Trigger the fault only if iCnt is already zero */
int iInterval; /* Reset iCnt to this value after each fault */
int eVerbose; /* When to print output */
} faultsim_state = {-1, 0, 0, 0, 0};
/*
** This is the fault-sim callback
*/
static int faultsim_callback(int iArg){
if( faultsim_state.iId>0 && faultsim_state.iId!=iArg ){
return SQLITE_OK;
}
if( faultsim_state.iCnt>0 ){
faultsim_state.iCnt--;
if( faultsim_state.eVerbose>=2 ){
oputf("FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
}
return SQLITE_OK;
}
if( faultsim_state.eVerbose>=1 ){
oputf("FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
}
faultsim_state.iCnt = faultsim_state.iInterval;
return faultsim_state.iErr;
}
/*
** If an input line begins with "." then invoke this routine to
** process that line.
@@ -9099,6 +9178,21 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
if( c=='i' && cli_strncmp(azArg[0], "intck", n)==0 ){
i64 iArg = 0;
if( nArg==2 ){
iArg = integerValue(azArg[1]);
if( iArg==0 ) iArg = -1;
}
if( (nArg!=1 && nArg!=2) || iArg<0 ){
eputf("%s","Usage: .intck STEPS_PER_UNLOCK\n");
rc = 1;
goto meta_command_exit;
}
open_db(p, 0);
rc = intckDatabaseCmd(p, iArg);
}else
#ifdef SQLITE_ENABLE_IOTRACE
if( c=='i' && cli_strncmp(azArg[0], "iotrace", n)==0 ){
SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
@@ -10772,7 +10866,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/*{"bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/
{"byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" },
{"extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" },
/*{"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"" },*/
{"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"args..." },
{"fk_no_action", SQLITE_TESTCTRL_FK_NO_ACTION, 0, "BOOLEAN" },
{"imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"},
{"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" },
@@ -11005,6 +11099,64 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_test_control(testctrl, &rc2);
break;
case SQLITE_TESTCTRL_FAULT_INSTALL: {
int kk;
int bShowHelp = nArg<=2;
isOk = 3;
for(kk=2; kk<nArg; kk++){
const char *z = azArg[kk];
if( z[0]=='-' && z[1]=='-' ) z++;
if( cli_strcmp(z,"off")==0 ){
sqlite3_test_control(testctrl, 0);
}else if( cli_strcmp(z,"on")==0 ){
faultsim_state.iCnt = faultsim_state.iInterval;
if( faultsim_state.iErr==0 ) faultsim_state.iErr = 1;
sqlite3_test_control(testctrl, faultsim_callback);
}else if( cli_strcmp(z,"reset")==0 ){
faultsim_state.iCnt = faultsim_state.iInterval;
}else if( cli_strcmp(z,"status")==0 ){
oputf("faultsim.iId: %d\n", faultsim_state.iId);
oputf("faultsim.iErr: %d\n", faultsim_state.iErr);
oputf("faultsim.iCnt: %d\n", faultsim_state.iCnt);
oputf("faultsim.iInterval: %d\n", faultsim_state.iInterval);
oputf("faultsim.eVerbose: %d\n", faultsim_state.eVerbose);
}else if( cli_strcmp(z,"-v")==0 ){
if( faultsim_state.eVerbose<2 ) faultsim_state.eVerbose++;
}else if( cli_strcmp(z,"-q")==0 ){
if( faultsim_state.eVerbose>0 ) faultsim_state.eVerbose--;
}else if( cli_strcmp(z,"-id")==0 && kk+1<nArg ){
faultsim_state.iId = atoi(azArg[++kk]);
}else if( cli_strcmp(z,"-errcode")==0 && kk+1<nArg ){
faultsim_state.iErr = atoi(azArg[++kk]);
}else if( cli_strcmp(z,"-interval")==0 && kk+1<nArg ){
faultsim_state.iInterval = atoi(azArg[++kk]);
}else if( cli_strcmp(z,"-?")==0 || sqlite3_strglob("*help*",z)==0){
bShowHelp = 1;
}else{
eputf("Unrecognized fault_install argument: \"%s\"\n",
azArg[kk]);
rc = 1;
bShowHelp = 1;
break;
}
}
if( bShowHelp ){
oputz(
"Usage: .testctrl fault_install ARGS\n"
"Possible arguments:\n"
" off Disable faultsim\n"
" on Activate faultsim\n"
" reset Reset the trigger counter\n"
" status Show current status\n"
" -v Increase verbosity\n"
" -q Decrease verbosity\n"
" --errcode N When triggered, return N as error code\n"
" --id ID Trigger only for the ID specified\n"
" --interval N Trigger only after every N-th call\n"
);
}
break;
}
}
}
if( isOk==0 && iCtrl>=0 ){
+4 -2
View File
@@ -420,6 +420,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not dereference the arrays or string pointers
** passed as the 3rd and 4th callback parameters after it returns.
** </ul>
*/
int sqlite3_exec(
@@ -762,11 +764,11 @@ struct sqlite3_file {
** </ul>
** xLock() upgrades the database file lock. In other words, xLock() moves the
** database file lock in the direction NONE toward EXCLUSIVE. The argument to
** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
** SQLITE_LOCK_NONE. If the database file lock is already at or above the
** requested lock, then the call to xLock() is a no-op.
** xUnlock() downgrades the database file lock to either SHARED or NONE.
* If the lock is already at or below the requested lock state, then the call
** If the lock is already at or below the requested lock state, then the call
** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
+7 -4
View File
@@ -609,6 +609,8 @@
# define SQLITE_OMIT_ALTERTABLE
#endif
#define SQLITE_DIGIT_SEPARATOR '_'
/*
** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits. This macro is used inside of various testcase()
@@ -2476,8 +2478,7 @@ struct Table {
#define TF_HasStored 0x00000040 /* Has one or more STORED columns */
#define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */
#define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */
#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by
** Index.aiRowLogEst[] values */
#define TF_MaybeReanalyze 0x00000100 /* Maybe run ANALYZE on this table */
#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */
#define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */
#define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */
@@ -3313,6 +3314,8 @@ struct SrcItem {
union {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
Trigger *pTrig; /* Trigger in argument list of DROP TRIGGER */
Index *pIdx; /* Index in argument list to DROP INDEX */
} u2;
};
@@ -4796,6 +4799,7 @@ int sqlite3ErrorToParser(sqlite3*,int);
void sqlite3Dequote(char*);
void sqlite3DequoteExpr(Expr*);
void sqlite3DequoteToken(Token*);
void sqlite3DequoteNumber(Parse*, Expr*);
void sqlite3TokenInit(Token*,char*);
int sqlite3KeywordCode(const unsigned char*, int);
int sqlite3RunParser(Parse*, const char*);
@@ -4924,7 +4928,6 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
int sqlite3DbMaskAllZero(yDbMask);
#endif
void sqlite3DropTable(Parse*, SrcList*, int, int);
void sqlite3CodeDropTable(Parse*, Table*, int, int);
void sqlite3DeleteTable(sqlite3*, Table*);
void sqlite3DeleteTableGeneric(sqlite3*, void*);
void sqlite3FreeIndex(sqlite3*, Index*);
@@ -5572,7 +5575,7 @@ const char *sqlite3JournalModename(int);
*/
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
void sqlite3FkCheck(Parse*, Table*, int, int, int*, int);
void sqlite3FkDropTable(Parse*, SrcList *, Table*);
void sqlite3FkDropTable(Parse*, SrcList*, Table*);
void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int);
int sqlite3FkRequired(Parse*, Table*, int*, int);
u32 sqlite3FkOldmask(Parse*, Table*);
+2
View File
@@ -108,6 +108,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
extern int Sqlitetest_window_Init(Tcl_Interp *);
extern int Sqlitetestvdbecov_Init(Tcl_Interp *);
extern int TestRecover_Init(Tcl_Interp*);
extern int Sqlitetestintck_Init(Tcl_Interp*);
Tcl_CmdInfo cmdInfo;
@@ -175,6 +176,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
Sqlitetest_window_Init(interp);
Sqlitetestvdbecov_Init(interp);
TestRecover_Init(interp);
Sqlitetestintck_Init(interp);
Tcl_CreateObjCommand(
interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
+54 -20
View File
@@ -437,27 +437,58 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
*tokenType = TK_INTEGER;
#ifndef SQLITE_OMIT_HEX_INTEGER
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
for(i=3; sqlite3Isxdigit(z[i]); i++){}
return i;
}
for(i=3; 1; i++){
if( sqlite3Isxdigit(z[i])==0 ){
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
*tokenType = TK_QNUMBER;
}else{
break;
}
}
}
}else
#endif
for(i=0; sqlite3Isdigit(z[i]); i++){}
{
for(i=0; 1; i++){
if( sqlite3Isdigit(z[i])==0 ){
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
*tokenType = TK_QNUMBER;
}else{
break;
}
}
}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( z[i]=='.' ){
i++;
while( sqlite3Isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
if( (z[i]=='e' || z[i]=='E') &&
( sqlite3Isdigit(z[i+1])
|| ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
)
){
i += 2;
while( sqlite3Isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
if( z[i]=='.' ){
if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
for(i++; 1; i++){
if( sqlite3Isdigit(z[i])==0 ){
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
*tokenType = TK_QNUMBER;
}else{
break;
}
}
}
}
if( (z[i]=='e' || z[i]=='E') &&
( sqlite3Isdigit(z[i+1])
|| ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
)
){
if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
for(i+=2; 1; i++){
if( sqlite3Isdigit(z[i])==0 ){
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
*tokenType = TK_QNUMBER;
}else{
break;
}
}
}
}
#endif
}
while( IdChar(z[i]) ){
*tokenType = TK_ILLEGAL;
i++;
@@ -622,10 +653,13 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
if( tokenType>=TK_WINDOW ){
assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
|| tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
|| tokenType==TK_QNUMBER
);
#else
if( tokenType>=TK_SPACE ){
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL
|| tokenType==TK_QNUMBER
);
#endif /* SQLITE_OMIT_WINDOWFUNC */
if( AtomicLoad(&db->u1.isInterrupted) ){
pParse->rc = SQLITE_INTERRUPT;
@@ -658,7 +692,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
assert( n==6 );
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif /* SQLITE_OMIT_WINDOWFUNC */
}else{
}else if( tokenType!=TK_QNUMBER ){
Token x;
x.z = zSql;
x.n = n;
+30 -26
View File
@@ -624,35 +624,39 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
const char *zDb;
const char *zName;
sqlite3 *db = pParse->db;
int ii, jj;
if( db->mallocFailed ) goto drop_trigger_cleanup;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto drop_trigger_cleanup;
}
assert( pName->nSrc==1 );
zDb = pName->a[0].zDatabase;
zName = pName->a[0].zName;
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
if( pTrigger ) break;
}
if( !pTrigger ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a);
}else{
sqlite3CodeVerifyNamedSchema(pParse, zDb);
sqlite3ReadSchema(pParse);
assert( pName!=0 || pParse->nErr!=0 );
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
zDb = pName->a[ii].zDatabase;
zName = pName->a[ii].zName;
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
if( pTrigger ) break;
}
pParse->checkSchema = 1;
goto drop_trigger_cleanup;
pName->a[ii].u2.pTrig = pTrigger;
if( !pTrigger ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a+ii);
}else{
sqlite3CodeVerifyNamedSchema(pParse, zDb);
}
testcase( ii>0 );
testcase( ii+1<pName->nSrc );
pParse->checkSchema = 1;
continue;
}
for(jj=ii-1; jj>=0; jj--){
if( pName->a[jj].u2.pTrig==pTrigger ) break;
}
if( jj>=0 ) continue;
sqlite3DropTriggerPtr(pParse, pTrigger);
}
sqlite3DropTriggerPtr(pParse, pTrigger);
drop_trigger_cleanup:
sqlite3SrcListDelete(db, pName);
}
+39 -1
View File
@@ -311,6 +311,44 @@ void sqlite3DequoteExpr(Expr *p){
sqlite3Dequote(p->u.zToken);
}
/*
** Expression p is a QNUMBER (quoted number). Dequote the value in p->u.zToken
** and set the type to INTEGER or FLOAT. "Quoted" integers or floats are those
** that contain '_' characters that must be removed before further processing.
*/
void sqlite3DequoteNumber(Parse *pParse, Expr *p){
assert( p!=0 || pParse->db->mallocFailed );
if( p ){
const char *pIn = p->u.zToken;
char *pOut = p->u.zToken;
int bHex = (pIn[0]=='0' && (pIn[1]=='x' || pIn[1]=='X'));
int iValue;
assert( p->op==TK_QNUMBER );
p->op = TK_INTEGER;
do {
if( *pIn!=SQLITE_DIGIT_SEPARATOR ){
*pOut++ = *pIn;
if( *pIn=='e' || *pIn=='E' || *pIn=='.' ) p->op = TK_FLOAT;
}else{
if( (bHex==0 && (!sqlite3Isdigit(pIn[-1]) || !sqlite3Isdigit(pIn[1])))
|| (bHex==1 && (!sqlite3Isxdigit(pIn[-1]) || !sqlite3Isxdigit(pIn[1])))
){
sqlite3ErrorMsg(pParse, "unrecognized token: \"%s\"", p->u.zToken);
}
}
}while( *pIn++ );
if( bHex ) p->op = TK_INTEGER;
/* tag-20240227-a: If after dequoting, the number is an integer that
** fits in 32 bits, then it must be converted into EP_IntValue. Other
** parts of the code expect this. See also tag-20240227-b. */
if( p->op==TK_INTEGER && sqlite3GetInt32(p->u.zToken, &iValue) ){
p->u.iValue = iValue;
p->flags |= EP_IntValue;
}
}
}
/*
** If the input token p is quoted, try to adjust the token to remove
** the quotes. This is not always possible:
@@ -1069,7 +1107,7 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
assert( p->n>0 );
assert( p->n<sizeof(p->zBuf) );
p->iDP = p->n + exp;
if( iRound<0 ){
if( iRound<=0 ){
iRound = p->iDP - iRound;
if( iRound==0 && p->zBuf[i+1]>='5' ){
iRound = 1;
+46 -22
View File
@@ -2086,7 +2086,7 @@ case OP_RealAffinity: { /* in1 */
}
#endif
#ifndef SQLITE_OMIT_CAST
#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE)
/* Opcode: Cast P1 P2 * * *
** Synopsis: affinity(r[P1])
**
@@ -6192,28 +6192,37 @@ case OP_Last: { /* jump, ncycle */
break;
}
/* Opcode: IfSmaller P1 P2 P3 * *
/* Opcode: IfSizeBetween P1 P2 P3 P4 *
**
** Estimate the number of rows in the table P1. Jump to P2 if that
** estimate is less than approximately 2**(0.1*P3).
** Let N be the approximate number of rows in the table or index
** with cursor P1 and let X be 10*log2(N) if N is positive or -1
** if N is zero. Thus X will be within the range of -1 to 640, inclusive
** Jump to P2 if X is in between P3 and P4, inclusive.
*/
case OP_IfSmaller: { /* jump */
case OP_IfSizeBetween: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
i64 sz;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p4type==P4_INT32 );
assert( pOp->p3>=-1 && pOp->p3<=640 );
assert( pOp->p4.i>=-1 && pOp->p4.i<=640 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
pCrsr = pC->uc.pCursor;
assert( pCrsr );
rc = sqlite3BtreeFirst(pCrsr, &res);
if( rc ) goto abort_due_to_error;
if( res==0 ){
if( res!=0 ){
sz = -1; /* -Infinity encoding */
}else{
sz = sqlite3BtreeRowCountEst(pCrsr);
if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)<pOp->p3 ) res = 1;
assert( sz>0 );
sz = sqlite3LogEst((u64)sz);
}
res = sz>=pOp->p3 && sz<=pOp->p4.i;
VdbeBranchTaken(res!=0,2);
if( res ) goto jump_to_p2;
break;
@@ -6913,11 +6922,18 @@ case OP_CreateBtree: { /* out2 */
break;
}
/* Opcode: SqlExec * * * P4 *
/* Opcode: SqlExec P1 P2 * P4 *
**
** Run the SQL statement or statements specified in the P4 string.
** Disable Auth and Trace callbacks while those statements are running if
** P1 is true.
**
** The P1 parameter is a bitmask of options:
**
** 0x0001 Disable Auth and Trace callbacks while the statements
** in P4 are running.
**
** 0x0002 Set db->nAnalysisLimit to P2 while the statements in
** P4 are running.
**
*/
case OP_SqlExec: {
char *zErr;
@@ -6925,6 +6941,7 @@ case OP_SqlExec: {
sqlite3_xauth xAuth;
#endif
u8 mTrace;
int savedAnalysisLimit;
sqlite3VdbeIncrWriteCounter(p, 0);
db->nSqlExec++;
@@ -6933,18 +6950,23 @@ case OP_SqlExec: {
xAuth = db->xAuth;
#endif
mTrace = db->mTrace;
if( pOp->p1 ){
savedAnalysisLimit = db->nAnalysisLimit;
if( pOp->p1 & 0x0001 ){
#ifndef SQLITE_OMIT_AUTHORIZATION
db->xAuth = 0;
#endif
db->mTrace = 0;
}
if( pOp->p1 & 0x0002 ){
db->nAnalysisLimit = pOp->p2;
}
rc = sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr);
db->nSqlExec--;
#ifndef SQLITE_OMIT_AUTHORIZATION
db->xAuth = xAuth;
#endif
db->mTrace = mTrace;
db->nAnalysisLimit = savedAnalysisLimit;
if( zErr || rc ){
sqlite3VdbeError(p, "%s", zErr);
sqlite3_free(zErr);
@@ -7096,13 +7118,13 @@ case OP_DropTrigger: {
/* Opcode: IntegrityCk P1 P2 P3 P4 P5
**
** Do an analysis of the currently open database. Store in
** register P1 the text of an error message describing any problems.
** If no problems are found, store a NULL in register P1.
** register (P1+1) the text of an error message describing any problems.
** If no problems are found, store a NULL in register (P1+1).
**
** The register P3 contains one less than the maximum number of allowed errors.
** At most reg(P3) errors will be reported.
** In other words, the analysis stops as soon as reg(P3) errors are
** seen. Reg(P3) is updated with the number of errors remaining.
** The register (P1) contains one less than the maximum number of allowed
** errors. At most reg(P1) errors will be reported.
** In other words, the analysis stops as soon as reg(P1) errors are
** seen. Reg(P1) is updated with the number of errors remaining.
**
** The root page numbers of all tables in the database are integers
** stored in P4_INTARRAY argument.
@@ -7120,19 +7142,21 @@ case OP_IntegrityCk: {
Mem *pnErr; /* Register keeping track of errors remaining */
assert( p->bIsReader );
assert( pOp->p4type==P4_INTARRAY );
nRoot = pOp->p2;
aRoot = pOp->p4.ai;
assert( nRoot>0 );
assert( aRoot!=0 );
assert( aRoot[0]==(Pgno)nRoot );
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pnErr = &aMem[pOp->p3];
assert( pOp->p1>0 && (pOp->p1+1)<=(p->nMem+1 - p->nCursor) );
pnErr = &aMem[pOp->p1];
assert( (pnErr->flags & MEM_Int)!=0 );
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
pIn1 = &aMem[pOp->p1];
pIn1 = &aMem[pOp->p1+1];
assert( pOp->p5<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
(int)pnErr->u.i+1, &nErr, &z);
rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1],
&aMem[pOp->p3], nRoot, (int)pnErr->u.i+1, &nErr, &z);
sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
assert( z==0 );
+2
View File
@@ -296,6 +296,8 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
int sqlite3VdbeHasSubProgram(Vdbe*);
void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val);
int sqlite3NotPureFunc(sqlite3_context*);
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
int sqlite3VdbeBytecodeVtabInit(sqlite3*);
+36 -10
View File
@@ -4060,6 +4060,23 @@ static void serialGet(
pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
}
}
static int serialGet7(
const unsigned char *buf, /* Buffer to deserialize from */
Mem *pMem /* Memory cell to write value into */
){
u64 x = FOUR_BYTE_UINT(buf);
u32 y = FOUR_BYTE_UINT(buf+4);
x = (x<<32) + y;
assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
swapMixedEndianFloat(x);
memcpy(&pMem->u.r, &x, sizeof(x));
if( IsNaN(x) ){
pMem->flags = MEM_Null;
return 1;
}
pMem->flags = MEM_Real;
return 0;
}
void sqlite3VdbeSerialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
@@ -4499,17 +4516,15 @@ int sqlite3IntFloatCompare(i64 i, double r){
return (x<r) ? -1 : (x>r);
}else{
i64 y;
double s;
if( r<-9223372036854775808.0 ) return +1;
if( r>=9223372036854775808.0 ) return -1;
y = (i64)r;
if( i<y ) return -1;
if( i>y ) return +1;
s = (double)i;
testcase( doubleLt(s,r) );
testcase( doubleLt(r,s) );
testcase( doubleEq(r,s) );
return (s<r) ? -1 : (s>r);
testcase( doubleLt(((double)i),r) );
testcase( doubleLt(r,((double)i)) );
testcase( doubleEq(r,((double)i)) );
return (((double)i)<r) ? -1 : (((double)i)>r);
}
}
@@ -4739,7 +4754,7 @@ int sqlite3VdbeRecordCompareWithSkip(
}else if( serial_type==0 ){
rc = -1;
}else if( serial_type==7 ){
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
serialGet7(&aKey1[d1], &mem1);
rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
}else{
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
@@ -4764,14 +4779,18 @@ int sqlite3VdbeRecordCompareWithSkip(
}else if( serial_type==0 ){
rc = -1;
}else{
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
if( serial_type==7 ){
if( mem1.u.r<pRhs->u.r ){
if( serialGet7(&aKey1[d1], &mem1) ){
rc = -1; /* mem1 is a NaN */
}else if( mem1.u.r<pRhs->u.r ){
rc = -1;
}else if( mem1.u.r>pRhs->u.r ){
rc = +1;
}else{
assert( rc==0 );
}
}else{
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
}
}
@@ -4841,7 +4860,14 @@ int sqlite3VdbeRecordCompareWithSkip(
/* RHS is null */
else{
serial_type = aKey1[idx1];
rc = (serial_type!=0 && serial_type!=10);
if( serial_type==0
|| serial_type==10
|| (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0)
){
assert( rc==0 );
}else{
rc = 1;
}
}
if( rc!=0 ){
+7
View File
@@ -943,6 +943,13 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
}
}
/*
** Set the iIdx'th entry of array aMem[] to contain integer value val.
*/
void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val){
sqlite3VdbeMemSetInt64(&aMem[iIdx], val);
}
/* A no-op destructor */
void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
+1 -1
View File
@@ -1290,7 +1290,7 @@ static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize);
sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte);
sqlite3OsFetch(pFd, 0, (int)nByte, &p);
if( NEVER(p) ) sqlite3OsUnfetch(pFd, 0, p);
if( p ) sqlite3OsUnfetch(pFd, 0, p);
}
}
#else
+3 -1
View File
@@ -611,6 +611,8 @@ static int vtabCallConstructor(
db->pVtabCtx = &sCtx;
pTab->nTabRef++;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
assert( pTab!=0 );
assert( pTab->nTabRef>1 || rc!=SQLITE_OK );
sqlite3DeleteTable(db, pTab);
db->pVtabCtx = sCtx.pPrior;
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
@@ -633,7 +635,7 @@ static int vtabCallConstructor(
pVTable->nRef = 1;
if( sCtx.bDeclared==0 ){
const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
*pzErr = sqlite3MPrintf(db, zFormat, zModuleName);
sqlite3VtabUnlock(pVTable);
rc = SQLITE_ERROR;
}else{
+5 -3
View File
@@ -2975,7 +2975,9 @@ static int whereLoopAddBtreeIndex(
}
if( pProbe->bUnordered || pProbe->bLowQual ){
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
if( pProbe->bLowQual ) opMask &= ~(WO_EQ|WO_IN|WO_IS);
if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){
opMask &= ~(WO_EQ|WO_IN|WO_IS);
}
}
assert( pNew->u.btree.nEq<pProbe->nColumn );
@@ -3970,7 +3972,7 @@ static int whereLoopAddBtree(
** unique index is used (making the index functionally non-unique)
** then the sqlite_stat1 data becomes important for scoring the
** plan */
pTab->tabFlags |= TF_StatsUsed;
pTab->tabFlags |= TF_MaybeReanalyze;
}
#ifdef SQLITE_ENABLE_STAT4
sqlite3Stat4ProbeFree(pBuilder->pRec);
@@ -5805,7 +5807,7 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
Table *pTab = pItem->pTab;
if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
pTab->tabFlags |= TF_StatsUsed;
pTab->tabFlags |= TF_MaybeReanalyze;
if( i>=1
&& (pLoop->wsFlags & reqFlags)==reqFlags
/* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
+6 -12
View File
@@ -117,8 +117,7 @@ do_test aggnested-3.0 {
#
do_test aggnested-3.1 {
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1 (
id1 INTEGER PRIMARY KEY AUTOINCREMENT,
value1 INTEGER
@@ -150,8 +149,7 @@ do_test aggnested-3.1-rj {
do_test aggnested-3.2 {
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1 (
id1 INTEGER,
value1 INTEGER,
@@ -178,8 +176,7 @@ do_test aggnested-3.2 {
} {1 0}
do_test aggnested-3.3 {
db eval {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1(id1, value1);
INSERT INTO t1 VALUES(4469,2),(4469,1);
CREATE TABLE t2 (value2);
@@ -249,8 +246,7 @@ do_test aggnested-3.16 {
# Problem found by dbsqlfuzz
#
do_execsql_test aggnested-4.1 {
DROP TABLE IF EXISTS aa;
DROP TABLE IF EXISTS bb;
DROP TABLE IF EXISTS aa, bb;
CREATE TABLE aa(x INT); INSERT INTO aa(x) VALUES(123);
CREATE TABLE bb(y INT); INSERT INTO bb(y) VALUES(456);
SELECT (SELECT sum(x+(SELECT y)) FROM bb) FROM aa;
@@ -259,8 +255,7 @@ do_execsql_test aggnested-4.2 {
SELECT (SELECT sum(x+y) FROM bb) FROM aa;
} {579}
do_execsql_test aggnested-4.3 {
DROP TABLE IF EXISTS tx;
DROP TABLE IF EXISTS ty;
DROP TABLE IF EXISTS tx, ty;
CREATE TABLE tx(x INT);
INSERT INTO tx VALUES(1),(2),(3),(4),(5);
CREATE TABLE ty(y INT);
@@ -477,8 +472,7 @@ do_execsql_test 9.5 {
# https://bugs.chromium.org/p/chromium/issues/detail?id=1511689
#
do_execsql_test 10.1 {
DROP TABLE IF EXISTS t0;
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t0, t1;
CREATE TABLE t0(c1, c2); INSERT INTO t0 VALUES(1,2);
CREATE TABLE t1(c3, c4); INSERT INTO t1 VALUES(3,4);
SELECT * FROM t0 WHERE EXISTS (SELECT 1 FROM t1 GROUP BY c3 HAVING ( SELECT count(*) FROM (SELECT 1 UNION ALL SELECT sum(DISTINCT c1) ) ) ) BETWEEN 1 AND 1;
+1 -2
View File
@@ -60,8 +60,7 @@ do_execsql_test aggorderby-4.1 {
do_execsql_test aggorderby-5.0 {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t3;
DROP TABLE IF EXISTS t1, t3;
CREATE TABLE t1(a TEXT); INSERT INTO t1 VALUES('aaa'),('bbb');
CREATE TABLE t3(d TEXT); INSERT INTO t3 VALUES('/'),('-');
SELECT (SELECT string_agg(a,d) FROM t3) FROM t1;
+2 -5
View File
@@ -105,9 +105,7 @@ do_test alter3-1.99 {
DROP TABLE t2;
}
execsql {
DROP TABLE abc;
DROP TABLE t1;
DROP TABLE t3;
DROP TABLE abc, t1, t3;
}
} {}
@@ -296,8 +294,7 @@ ifcapable attach {
} {1 one 2 two}
do_test alter3-5.99 {
execsql {
DROP TABLE aux.t1;
DROP TABLE t1;
DROP TABLE aux.t1, main.t1;
}
} {}
}
+1 -3
View File
@@ -114,9 +114,7 @@ do_test alter4-1.99 {
DROP TABLE t2;
}
execsql {
DROP TABLE abc;
DROP TABLE t1;
DROP TABLE t3;
DROP TABLE abc, t1, t3;
}
} {}
+1 -2
View File
@@ -195,8 +195,7 @@ do_test analyze-3.8 {
CREATE INDEX t3i1 ON t3(a);
CREATE INDEX t3i2 ON t3(a,b,c,d);
CREATE INDEX t3i3 ON t3(d,b,c,a);
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t1, t2;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {}
+5 -5
View File
@@ -216,7 +216,7 @@ do_test auth-1.21.1 {
}
return SQLITE_OK
}
catchsql {DROP TABLE t2}
catchsql {DROP TABLE IF EXISTS none1, none2, t2, none3}
} {1 {not authorized}}
do_test auth-1.21.2 {
set ::authargs
@@ -483,7 +483,7 @@ do_test auth-1.63 {
}
return SQLITE_OK
}
catchsql {DROP TABLE t2}
catchsql {DROP TABLE IF EXISTS none1, t2, none2}
} {1 {not authorized}}
do_test auth-1.64 {
execsql {SELECT name FROM sqlite_master}
@@ -726,7 +726,7 @@ do_test auth-1.101 {
}
return SQLITE_OK
}
catchsql {DROP VIEW v2}
catchsql {DROP VIEW IF EXISTS none1, v2, none2}
} {1 {not authorized}}
do_test auth-1.102 {
set ::authargs
@@ -1090,7 +1090,7 @@ do_test auth-1.153 {
}
return SQLITE_OK
}
catchsql {DROP TRIGGER r2}
catchsql {DROP TRIGGER IF EXISTS none1, r2, none2}
} {1 {not authorized}}
do_test auth-1.154 {
set ::authargs
@@ -1389,7 +1389,7 @@ do_test auth-1.205 {
}
return SQLITE_OK
}
catchsql {DROP INDEX i2}
catchsql {DROP INDEX IF EXISTS none1, i2, none2}
} {1 {not authorized}}
do_test auth-1.205a {
set ::authargs
+1 -1
View File
@@ -106,7 +106,7 @@ do_test 3.4 {
proc busy_handler {n} { return 1 }
do_test 3.5 {
catchsql { PRAGMA optimize }
} {0 {}}
} {1 {database is locked}}
do_test 3.6 {
execsql { COMMIT } db2
+1 -1
View File
@@ -113,7 +113,7 @@ do_test corruptD-1.1.1 {
hexio_write test.db [expr 1024+1] FFFF
catchsql { PRAGMA quick_check }
} {0 {{*** in database main ***
Tree 2 page 2: free space corruption}}}
Tree 2 page 2: free space corruption} {wrong # of entries in index i1}}}
do_test corruptD-1.1.2 {
incr_change_counter
hexio_write test.db [expr 1024+1] [hexio_render_int32 1021]
+161
View File
@@ -0,0 +1,161 @@
# 2024-02-29
#
# 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.
#
#***********************************************************************
#
# Test cases for DROP TABLE, DROP INDEX, DROP TRIGGER, and DROP VIEW that
# list multiple objects to be dropped.
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix drop-many
do_execsql_test 1.1 {
CREATE TABLE t1(a);
CREATE TABLE t2(b, c UNIQUE);
CREATE TABLE t3(d TEXT PRIMARY KEY, e);
CREATE INDEX t3e ON t3(e);
ATTACH ':memory:' AS aux1;
CREATE TABLE aux1.t4(f INT, g INT, h INT PRIMARY KEY) WITHOUT ROWID;
CREATE INDEX aux1.t4g ON t4(g);
CREATE INDEX t2b ON t2(b);
CREATE VIEW v5 AS SELECT 1,2,3;
CREATE VIEW v6 AS SELECT * FROM t3;
CREATE VIEW aux1.v7 AS SELECT 'hello';
CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN SELECT 'this is trigger r1'; END;
CREATE TRIGGER r2 BEFORE DELETE ON t2 BEGIN INSERT INTO t1 VALUES(old.b); END;
CREATE TRIGGER aux1.r3 AFTER UPDATE ON t4 BEGIN SELECT 'trigger r3'; END;
CREATE TRIGGER aux1.r4 INSTEAD OF UPDATE ON v7 BEGIN SELECT NULL; END;
} {}
do_execsql_test 1.2 {
BEGIN;
DROP TABLE t2, t4, t3, t1;
SELECT name FROM sqlite_schema WHERE type='table'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='table'
ORDER BY name;
ROLLBACK;
} {}
do_catchsql_test 1.3.1 {
DROP TABLE t2, t4, t3, t05, t1;
} {1 {no such table: t05}}
do_execsql_test 1.3.2 {
SELECT name FROM sqlite_schema WHERE type='table'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='table'
ORDER BY name;
} {t1 t2 t3 t4}
do_execsql_test 1.4 {
BEGIN;
DROP TABLE IF EXISTS t01, t2, t02, t4, t03, t3, t04, t1, t05;
SELECT name FROM sqlite_schema WHERE type='table'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='table'
ORDER BY name;
ROLLBACK;
} {}
do_catchsql_test 1.5.1 {
DROP TABLE IF EXISTS t2, t4, t3, v7, t1;
} {1 {use DROP VIEW to delete view v7}}
do_execsql_test 1.5.2 {
SELECT name FROM sqlite_schema WHERE type='table'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='table'
ORDER BY name;
} {t1 t2 t3 t4}
do_execsql_test 2.1 {
BEGIN;
DROP VIEW v5, v6, v7;
SELECT name FROM sqlite_schema WHERE type='view'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='view'
ORDER BY name;
ROLLBACK;
} {}
do_catchsql_test 2.2.1 {
DROP VIEW v5, v6, v8, v7;
} {1 {no such view: v8}}
do_execsql_test 2.2.2 {
SELECT name FROM sqlite_schema WHERE type='view'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='view'
ORDER BY name;
} {v5 v6 v7}
do_catchsql_test 2.3.1 {
DROP VIEW v5, v6, t1, v7;
} {1 {use DROP TABLE to delete table t1}}
do_execsql_test 2.3.2 {
SELECT name FROM sqlite_schema WHERE type='view'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='view'
ORDER BY name;
} {v5 v6 v7}
do_execsql_test 3.1 {
BEGIN;
DROP INDEX t2b, aux1.t4g, main.t3e;
SELECT name FROM sqlite_schema WHERE type='index' AND name NOT LIKE 'sqlite%'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='index'
ORDER BY name;
ROLLBACK;
} {}
do_catchsql_test 3.2.1 {
DROP INDEX t2b, aux1.t4g, t1, main.t3e;
} {1 {no such index: t1}}
do_execsql_test 3.2.2 {
SELECT name FROM sqlite_schema WHERE type='index' AND name NOT LIKE 'sqlite%'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='index'
ORDER BY name;
} {t2b t3e t4g}
do_execsql_test 3.3 {
BEGIN;
DROP INDEX IF EXISTS aux1.none, t2b, none2, aux1.t4g, main.t3e, none3;
SELECT name FROM sqlite_schema WHERE type='index' AND name NOT LIKE 'sqlite%'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='index'
ORDER BY name;
ROLLBACK;
} {}
do_execsql_test 4.1 {
BEGIN;
DROP TRIGGER main.r1, r2, r3, aux1.r4;
SELECT name FROM sqlite_schema WHERE type='trigger'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='trigger'
ORDER BY name;
ROLLBACK;
} {}
do_catchsql_test 4.2.1 {
DROP TRIGGER main.r1, r2, r3, main.t1, aux1.r4;
} {1 {no such trigger: main.t1}}
do_execsql_test 4.2.2 {
SELECT name FROM sqlite_schema WHERE type='trigger'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='trigger'
ORDER BY name;
} {r1 r2 r3 r4}
do_execsql_test 4.3 {
BEGIN;
DROP TRIGGER IF EXISTS none1, main.r1, r2, aux1.none2, r3, aux1.r4;
SELECT name FROM sqlite_schema WHERE type='trigger'
UNION ALL
SELECT name from aux1.sqlite_schema WHERE type='trigger'
ORDER BY name;
ROLLBACK;
} {}
finish_test
+3 -3
View File
@@ -73,12 +73,12 @@ sqlite3 db test.db
do_execsql_test e_reindex-1.3 {
PRAGMA integrity_check;
} [list \
{wrong # of entries in index i2} \
{wrong # of entries in index i1} \
{row 3 missing from index i2} \
{row 3 missing from index i1} \
{row 4 missing from index i2} \
{row 4 missing from index i1} \
{wrong # of entries in index i2} \
{wrong # of entries in index i1}
{row 4 missing from index i1}
]
do_execsql_test e_reindex-1.4 {
+11
View File
@@ -71,6 +71,17 @@ do_test fkey1-2.1 {
DROP TABLE t10;
}
} {}
do_test fkey1-2.2 {
execsql {
CREATE TABLE t5(x references t4);
CREATE TABLE t6(x references t4);
CREATE TABLE t7(x references t4);
CREATE TABLE t8(x references t4);
CREATE TABLE t9(x references t4);
CREATE TABLE t10(x references t4);
DROP TABLE t7, t9, t5, t8, t6, t10;
}
} {}
do_test fkey1-3.1 {
execsql {
+5
View File
@@ -786,6 +786,11 @@ do_test func-16.1 {
}
} {X'616263' NULL}
# Test the quote function for +Inf and -Inf
do_execsql_test func-16.2 {
SELECT quote(4.2e+859), quote(-7.8e+904);
} {9.0e+999 -9.0e+999}
# Correctly handle function error messages that include %. Ticket #1354
#
do_test func-17.1 {
+2 -2
View File
@@ -161,8 +161,8 @@ static struct GlobalVars {
/*
** Include the external vt02.c and randomjson.c modules.
*/
extern int sqlite3_vt02_init(sqlite3*,char***,void*);
extern int sqlite3_randomjson_init(sqlite3*,char***,void*);
extern int sqlite3_vt02_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_randomjson_init(sqlite3*,char**,const sqlite3_api_routines*);
/*
+14
View File
@@ -378,6 +378,20 @@ do_execsql_test json101-5.8 {
WHERE jx.value<>jx.atom AND type NOT IN ('array','object');
} {}
# 2024-02-16 https://sqlite.org/forum/forumpost/ecb94cd210
# Regression in json_tree()/json_each(). The value column
# should have the "J" subtype if the value is an array or
# object.
#
do_execsql_test json101-5.10 {
SELECT json_insert('{}','$.a',value) FROM json_tree('[1,2,3]') WHERE atom IS NULL;
} {{{"a":[1,2,3]}}}
# ^^^^^^^--- In double-quotes, a string literal, prior to bug fix
do_execsql_test json101-5.11 {
SELECT json_insert('{}','$.a',value) FROM json_tree('"[1,2,3]"');
} {{{"a":"[1,2,3]"}}}
do_execsql_test json101-6.1 {
SELECT json_valid('{"a":55,"b":72,}');
} {0}
+42 -1
View File
@@ -37,6 +37,10 @@ proc test_literal {tn lit type val} {
" [list $type $val]
}
proc test_literal_error {tn lit unrec} {
do_catchsql_test $tn "SELECT $lit" "1 {unrecognized token: \"$unrec\"}"
}
test_literal 1.0 45 integer 45
test_literal 1.1 0xFF integer 255
@@ -51,7 +55,6 @@ test_literal 1.10 -45 integer -45
test_literal 1.11 '0xFF' text 0xFF
test_literal 1.12 '-0xFF' text -0xFF
test_literal 1.13 -'0xFF' integer 0
test_literal 1.14 -9223372036854775808 integer -9223372036854775808
test_literal 2.1 1e12 real 1000000000000.0
@@ -59,4 +62,42 @@ test_literal 2.2 1.0 real 1.0
test_literal 2.3 1e1000 real Inf
test_literal 2.4 -1e1000 real -Inf
test_literal 3.1 1_000 integer 1000
test_literal 3.2 1.1_1 real 1.11
test_literal 3.3 1_0.1_1 real 10.11
test_literal 3.4 1e1_000 real Inf
test_literal 3.5 12_3_456.7_8_9 real 123456.789
test_literal 3.6 9_223_372_036_854_775_807 integer 9223372036854775807
test_literal 3.7 9_223_372_036_854_775_808 real 9.22337203685478e+18
test_literal 3.8 -9_223_372_036_854_775_808 integer -9223372036854775808
foreach {tn lit unrec} {
0 123a456 123a456
1 1_ 1_
2 1_.4 1_.4
3 1e_4 1e_4
4 1_e4 1_e4
5 1.4_e4 1.4_e4
6 1.4e+_4 1.4e
7 1.4e-_4 1.4e
8 1.4e4_ 1.4e4_
9 1.4_e4 1.4_e4
10 1.4e_4 1.4e_4
11 12__34 12__34
12 1234_ 1234_
13 12._34 12._34
14 12_.34 12_.34
15 12.34_ 12.34_
16 1.0e1_______2 1.0e1_______2
} {
test_literal_error 4.$tn $lit $unrec
}
# dbsqlfuzz e3186a9e7826e9cd7f4085aa4452f8696485f9e1
# See tag-20240224-a and -b
#
do_catchsql_test 5.1 {
SELECT 1 ORDER BY 2_3;
} {1 {1st ORDER BY term out of range - should be between 1 and 1}}
finish_test
+40
View File
@@ -0,0 +1,40 @@
# 2018 May 19
#
# 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.
#
#***********************************************************************
#
source [file join [file dirname $argv0] pg_common.tcl]
#=========================================================================
start_test literal2 "2024 Jan 23"
execsql_test 1.0 { SELECT 123_456 }
errorsql_test 1.1 { SELECT 123__456 }
execsql_float_test 2.1 { SELECT 1.0e1_2 }
execsql_test 3.0.0 { SELECT 0xFF_FF }
execsql_test 3.0.1 { SELECT 0xFF_EF }
errorsql_test 3.0.2 { SELECT 0xFF__EF }
# errorsql_test 3.0.3 { SELECT 0x_FFEF }
errorsql_test 3.0.4 { SELECT 0xFFEF_ }
execsql_test 3.1.0 { SELECT 0XFF_FF }
execsql_test 3.1.1 { SELECT 0XFF_EF }
errorsql_test 3.1.2 { SELECT 0XFF__EF }
# errorsql_test 3.1.3 { SELECT 0X_FFEF }
errorsql_test 3.1.4 { SELECT 0XFFEF_ }
finish_test
+84
View File
@@ -0,0 +1,84 @@
# 2024 Jan 23
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
####################################################
# DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED!
####################################################
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix literal2
do_execsql_test 1.0 {
SELECT 123_456
} {123456}
# PG says ERROR: trailing junk after numeric literal at or near "123_"
do_test 1.1 { catch { execsql {
SELECT 123__456
} } } 1
do_test 2.1 {
set myres {}
foreach r [db eval {SELECT 1.0e1_2}] {
lappend myres [format %.4f [set r]]
}
set res2 {1000000000000.0000}
set i 0
foreach r [set myres] r2 [set res2] {
if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} {
error "list element [set i] does not match: got=[set r] expected=[set r2]"
}
incr i
}
set {} {}
} {}
do_execsql_test 3.0.0 {
SELECT 0xFF_FF
} {65535}
do_execsql_test 3.0.1 {
SELECT 0xFF_EF
} {65519}
# PG says ERROR: trailing junk after numeric literal at or near "0xFF_"
do_test 3.0.2 { catch { execsql {
SELECT 0xFF__EF
} } } 1
# PG says ERROR: trailing junk after numeric literal at or near "0xFFEF_"
do_test 3.0.4 { catch { execsql {
SELECT 0xFFEF_
} } } 1
do_execsql_test 3.1.0 {
SELECT 0XFF_FF
} {65535}
do_execsql_test 3.1.1 {
SELECT 0XFF_EF
} {65519}
# PG says ERROR: trailing junk after numeric literal at or near "0XFF_"
do_test 3.1.2 { catch { execsql {
SELECT 0XFF__EF
} } } 1
# PG says ERROR: trailing junk after numeric literal at or near "0XFFEF_"
do_test 3.1.4 { catch { execsql {
SELECT 0XFFEF_
} } } 1
finish_test
+1 -1
View File
@@ -654,7 +654,7 @@ do_catchsql_test misc1-21.1 {
} {1 {near "#0": syntax error}}
do_catchsql_test misc1-21.2 {
VALUES(0,0x0MATCH#0;
} {1 {near ";": syntax error}}
} {1 {unrecognized token: "0x0MATCH"}}
# 2015-04-15
do_execsql_test misc1-22.1 {
+1
View File
@@ -95,6 +95,7 @@ foreach f [glob -nocomplain \
$testdir/../ext/lsm1/test/*.test \
$testdir/../ext/recover/*.test \
$testdir/../ext/rbu/*.test \
$testdir/../ext/intck/*.test \
] {
lappend alltests $f
}
+31 -16
View File
@@ -372,27 +372,27 @@ ifcapable attach {
db close
sqlite3 db test.db
execsql {PRAGMA integrity_check}
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
do_test pragma-3.3 {
execsql {PRAGMA integrity_check=1}
} {{row 1 missing from index i2}}
} {{wrong # of entries in index i2}}
do_test pragma-3.4 {
execsql {
ATTACH DATABASE 'test.db' AS t2;
PRAGMA integrity_check
}
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
do_test pragma-3.5 {
execsql {
PRAGMA integrity_check=4
}
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2}}
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
do_catchsql_test pragma-3.6 {
PRAGMA integrity_check=xyz
} {1 {no such table: xyz}}
do_catchsql_test pragma-3.6b {
PRAGMA integrity_check=t2
} {0 {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}}
} {0 {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}}
do_catchsql_test pragma-3.6c {
PRAGMA integrity_check=sqlite_schema
} {0 ok}
@@ -400,7 +400,7 @@ ifcapable attach {
execsql {
PRAGMA integrity_check=0
}
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
# Add additional corruption by appending unused pages to the end of
# the database file testerr.db
@@ -435,10 +435,10 @@ ifcapable attach {
} {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
do_execsql_test pragma-3.9b {
PRAGMA t2.integrity_check=t2;
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
} {{wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
do_execsql_test pragma-3.9c {
PRAGMA t2.integrity_check=sqlite_schema;
} {ok}
@@ -455,7 +455,7 @@ Page 4: never used}}
} {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2}}
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2}}
do_test pragma-3.12 {
execsql {
PRAGMA integrity_check=4
@@ -463,7 +463,7 @@ Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2}}
} {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2}}
Page 6: never used} {wrong # of entries in index i2}}
do_test pragma-3.13 {
execsql {
PRAGMA integrity_check=3
@@ -487,10 +487,10 @@ Page 5: never used}}
} {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {*** in database t3 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2}}
do_test pragma-3.16 {
execsql {
PRAGMA integrity_check(10)
@@ -498,10 +498,10 @@ Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2}
} {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {*** in database t3 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2}}
Page 6: never used} {wrong # of entries in index i2}}
do_test pragma-3.17 {
execsql {
PRAGMA integrity_check=8
@@ -509,7 +509,7 @@ Page 6: never used} {row 1 missing from index i2}}
} {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
Page 6: never used} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {*** in database t3 ***
Page 4: never used
Page 5: never used}}
do_test pragma-3.18 {
@@ -519,7 +519,7 @@ Page 5: never used}}
} {{*** in database t2 ***
Page 4: never used
Page 5: never used
Page 6: never used} {row 1 missing from index i2}}
Page 6: never used} {wrong # of entries in index i2}}
}
do_test pragma-3.19 {
catch {db close}
@@ -556,6 +556,21 @@ ifcapable altertable {
do_execsql_test pragma-3.23 {
PRAGMA integrity_check(1);
} {{non-unique entry in index t1a}}
# forum post https://sqlite.org/forum/forumpost/ee4f6fa5ab
do_execsql_test pragma-3.24 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a);
INSERT INTO t1 VALUES (1);
ALTER TABLE t1 ADD COLUMN b NOT NULL DEFAULT 0.25;
SELECT * FROM t1;
PRAGMA integrity_check(t1);
} {1 0.25 ok}
do_execsql_test pragma-3.25 {
ALTER TABLE t1 ADD COLUMN c CHECK (1);
SELECT * FROM t1;
PRAGMA integrity_check(t1);
} {1 0.25 {} ok}
}
# PRAGMA integrity check (or more specifically the sqlite3BtreeCount()
+1 -1
View File
@@ -97,7 +97,7 @@ do_test pragma4-2.100 {
}
string map {\[ x \] x \173 {} \175 {}} \
[db eval {EXPLAIN PRAGMA integrity_check}]
} {/ IntegrityCk 2 2 1 x[0-9]+,1x /}
} {/ IntegrityCk 1 2 8 x[0-9]+,1x /}
#--------------------------------------------------------------------------
+71
View File
@@ -0,0 +1,71 @@
# 2024 February 27
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements tests for PRAGMAs quick_check and integrity_check.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix pragma6
database_may_be_corrupt
#-------------------------------------------------------------------------
#
do_test 1.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 12288 pagesize 4096 filename crash-540f4c1eb1e7ac.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 03 .....@ ........
| 32: 00 bb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 96: 00 00 00 00 0d 00 00 00 02 0f 7f 00 0f c3 0f 7f ................
| 3952: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 ...............B
| 3968: 02 06 17 11 11 01 71 74 61 62 6c 65 74 32 74 32 ......qtablet2t2
| 3984: 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 32 .CREATE TABLE t2
| 4000: 28 61 20 49 4e 54 2c 20 62 20 41 53 20 28 61 2a (a INT, b AS (a*
| 4016: 32 29 20 53 54 4f 52 45 44 20 4e 4f 54 20 4e 55 2) STORED NOT NU
| 4032: 4c 4c 29 3b 01 06 17 11 11 01 63 74 61 62 6c 65 LL);......ctable
| 4048: 74 31 74 31 02 43 52 45 41 54 45 20 54 41 42 4c t1t1.CREATE TABL
| 4064: 45 20 74 31 28 61 20 49 4e 54 2c 20 62 20 41 53 E t1(a INT, b AS
| 4080: 20 28 61 2a 32 29 20 4e 4f 54 20 4e 55 4c 4c 29 (a*2) NOT NULL)
| page 2 offset 4096
| 0: 0d 00 00 00 05 0f e7 00 00 00 00 00 00 00 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 03 05 02 01 05 03 04 02 ................
| 4080: 01 04 03 03 02 01 03 03 02 02 01 02 02 01 02 09 ................
| page 3 offset 8192
| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 05 ................
| 4064: 03 01 01 05 0a 05 04 03 01 01 04 08 05 03 03 01 ................
| 4080: 01 03 06 05 02 03 00 00 00 00 00 00 00 00 00 00 ................
| end crash-540f4c1eb1e7ac.db
}]
} {}
do_execsql_test 1.1 {
CREATE TEMP TABLE t2(
a t1 PRIMARY KEY default 27,
b default(current_timestamp),
d TEXT UNIQUE DEFAULT 'ch`arlie',
c TEXT UNIQUE DEFAULT 084,
UNIQUE(c,b,b,a,b)
) WITHOUT ROWID;
INSERT INTO t1(a) VALUES(zeroblob(40000));
}
do_test 1.2 {
execsql { PRAGMA integrity_check; }
execsql { PRAGMA quick_check; }
set {} {}
} {}
finish_test
+17
View File
@@ -3833,4 +3833,21 @@ do_execsql_test printf-18.1 {
SELECT length( format('%,.249f', -5.0e-300) );
} {252}
# 2024-02-16
# https://sqlite.org/forum/info/393708f4a8
#
# The problem introduced by on 2023-07-03 by
# https://sqlite.org/src/info/32befb224b254639
#
do_execsql_test printf-19.1 {
SELECT format('%0.0f %0.0g %0.0g', 0.9, 0.09, 1.9);
} {{1 0.09 2}}
do_execsql_test printf-19.2 {
SELECT format('%0.0f %#0.0f',0.0, 0.0);
} {{0 0.}}
do_execsql_test printf-19.3 {
SELECT format('%,.0f %,.0f',12345e+10, 12345e+11);
} {{123,450,000,000,000 1,234,500,000,000,000}}
finish_test
+46
View File
@@ -2150,6 +2150,50 @@ void testset_debug1(void){
}
}
/*
** This testset focuses on the speed of parsing numeric literals (integers
** and real numbers). This was added to test the impact of allowing "_"
** characters to appear in numeric SQL literals to make them easier to read.
** For example, "SELECT 1_000_000;" instead of "SELECT 1000000;".
*/
void testset_parsenumber(void){
const char *zSql1 = "SELECT 1, 12, 123, 1234, 12345, 123456";
const char *zSql2 = "SELECT 8227256643844975616, 7932208612563860480, "
"2010730661871032832, 9138463067404021760, "
"2557616153664746496, 2557616153664746496";
const char *zSql3 = "SELECT 1.0, 1.2, 1.23, 123.4, 1.2345, 1.23456";
const char *zSql4 = "SELECT 8.227256643844975616, 7.932208612563860480, "
"2.010730661871032832, 9.138463067404021760, "
"2.557616153664746496, 2.557616153664746496";
const int NROW = 100*g.szTest;
int ii;
speedtest1_begin_test(100, "parsing small integers");
for(ii=0; ii<NROW; ii++){
sqlite3_exec(g.db, zSql1, 0, 0, 0);
}
speedtest1_end_test();
speedtest1_begin_test(110, "parsing large integers");
for(ii=0; ii<NROW; ii++){
sqlite3_exec(g.db, zSql2, 0, 0, 0);
}
speedtest1_end_test();
speedtest1_begin_test(200, "parsing small reals");
for(ii=0; ii<NROW; ii++){
sqlite3_exec(g.db, zSql3, 0, 0, 0);
}
speedtest1_end_test();
speedtest1_begin_test(210, "parsing large reals");
for(ii=0; ii<NROW; ii++){
sqlite3_exec(g.db, zSql4, 0, 0, 0);
}
speedtest1_end_test();
}
#ifdef __linux__
#include <sys/types.h>
#include <unistd.h>
@@ -2557,6 +2601,8 @@ int main(int argc, char **argv){
testset_fp();
}else if( strcmp(zThisTest,"trigger")==0 ){
testset_trigger();
}else if( strcmp(zThisTest,"parsenumber")==0 ){
testset_parsenumber();
}else if( strcmp(zThisTest,"rtree")==0 ){
#ifdef SQLITE_ENABLE_RTREE
testset_rtree(6, 147);
+1 -1
View File
@@ -707,6 +707,7 @@ if {$SQLITE_MAX_EXPR_DEPTH==0} {
}]
} "1 {Expression tree is too large (maximum depth $::SQLITE_MAX_EXPR_DEPTH)}"
if 0 {
# Attempting to beat the expression depth limit using nested SELECT
# queries causes a parser stack overflow.
do_test sqllimits1-9.2 {
@@ -718,7 +719,6 @@ if {$SQLITE_MAX_EXPR_DEPTH==0} {
catchsql [subst { $expr }]
} "1 {parser stack overflow}"
if 0 {
do_test sqllimits1-9.3 {
execsql {
PRAGMA max_page_count = 1000000; -- 1 GB
+24 -3
View File
@@ -17,7 +17,7 @@
# After the "tsrc" directory has been created and populated, run
# this script:
#
# tclsh mksqlite3c.tcl
# tclsh mksqlite3c.tcl [flags] [extra source files]
#
# The amalgamated SQLite code will be written into sqlite3.c
#
@@ -42,6 +42,7 @@ set linemacros 0
set useapicall 0
set enable_recover 0
set srcdir tsrc
set extrasrc [list]
for {set i 0} {$i<[llength $argv]} {incr i} {
set x [lindex $argv $i]
@@ -63,8 +64,10 @@ for {set i 0} {$i<[llength $argv]} {incr i} {
} elseif {[regexp {^-?-((help)|\?)$} $x]} {
puts $help
exit 0
} else {
} elseif {[regexp {^-?-} $x]} {
error "unknown command-line option: $x"
} else {
lappend extrasrc $x
}
}
set in [open $srcdir/sqlite3.h]
@@ -349,6 +352,21 @@ proc copy_file {filename} {
section_comment "End of $tail"
}
# Read the source file named $filename and write it into the
# sqlite3.c output file. The only transformation is the trimming
# of EOL whitespace.
#
proc copy_file_verbatim {filename} {
global out
set in [open $filename r]
set tail [file tail $filename]
section_comment "Begin EXTRA_SRC file $tail"
while {![eof $in]} {
set line [string trimright [gets $in]]
puts $out $line
}
section_comment "End of EXTRA_SRC $tail"
}
# Process the source files. Process files containing commonly
# used subroutines first in order to help the compiler find
@@ -470,13 +488,16 @@ set flist {
sqlite3session.c
fts5.c
stmt.c
}
}
if {$enable_recover} {
lappend flist sqlite3recover.c dbdata.c
}
foreach file $flist {
copy_file $srcdir/$file
}
foreach file $extrasrc {
copy_file_verbatim $file
}
puts $out \
"/* Return the source-id for this library */
+3
View File
@@ -161,6 +161,9 @@ while test "$1" != ""; do
--fp)
SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset fp"
;;
--parsenumber)
SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset parsenumber"
;;
--stmtscanstatus)
SPEEDTEST_OPTS="$SPEEDTEST_OPTS --stmtscanstatus"
;;