Compare commits

...

223 Commits

Author SHA1 Message Date
drh 0e464b5f51 Do not allow the push-down optimization on the right table of a RIGHT JOIN.
FossilOrigin-Name: 05917bfa02a7b6678c147d10fb53f55532ab15fd5d82d925ae921ae3759f0115
2022-04-25 20:47:58 +00:00
drh 5eb6e09795 The pushDownWhereTerms() routine should be using
sqlite3ExprIsTableConstraint(), not sqlite3ExprIsTableConstant().  This fixes
many problems, but still an error persists in join7.test.

FossilOrigin-Name: 10bf0e613809f71cc1a47ad40b517e2a66671212a6464e179c9d377e8b70d499
2022-04-25 20:38:42 +00:00
drh a9cdb90421 Fix a problem with automatic indexes introduced by
check-in [664b461bb5063d980] and reported by
[forum:/forumpost/0d3200f4f3bcd3a3|forum post 0d3200f4f3bcd3a3].

FossilOrigin-Name: 7ca3456c00998a429418ff29cf251b381586b330b88344c94a40c5df0b71da85
2022-04-25 19:40:33 +00:00
drh 95fe38f2fc Add a new optimizer disabling bit to disable just the UNION ALL branch of the
query flattener.

FossilOrigin-Name: c0f9ebab5455d8541a562122d3270b95ce571c3fd870b0048dda2b036c2b66c0
2022-04-25 14:59:59 +00:00
drh 7f417569f7 Avoid unintended side-effects on Parse.nSelect in the
sqlite3ViewGetColumnNames() routine.

FossilOrigin-Name: 59789fe1e745bb6f81898176e7e9c6064ac9f4bbefb4dc3c8f3e4c1379568f69
2022-04-25 14:49:48 +00:00
drh 1a6bac0d2f Remove NEVER() on branches formerly thought to unreachable
(see check-in [71272caff5874137]) in order to fix the first bug reported
by [forum:/forumpost/28821db852|forum post 28821db852].

FossilOrigin-Name: bd6811d8110d5f00596e2eff6d4b02af8b6d8557d41990e6f50518ead0fa01fb
2022-04-25 10:43:19 +00:00
drh ecb386b71f Prevent the ORDER BY LIMIT optimization from running if the innermost loop
is a right-join, as doing so will get an incorrect answer.

FossilOrigin-Name: 3aefc874d31885c64a5e02868edb2aa56a2b4429252d494e67e4088a9298ce5b
2022-04-23 19:21:47 +00:00
drh 30d2aab5fd In debug builds, add extra code to verify that there are no jumps that try to
escape from the right-join body subroutine.

FossilOrigin-Name: 45fe919266ba1843f3eeeb511ab43126069d4976c9fc64e57e0390c21f110b6e
2022-04-23 18:46:03 +00:00
drh 6c7e89b48a Fix false-positives in sqlite3VdbeNoJumpsOutsideSubrtn(). All tests pass now.
FossilOrigin-Name: 1300d978d5a072780e0f16722e42461dc983de9b4dfb2f5a7023c74c92ab9bc8
2022-04-23 18:34:55 +00:00
drh b77c312956 For debug builds, if the RIGHT JOIN body subroutine contains a jump that
escapes the subroutine, then abort the prepared statement with a descriptive
error and SQLITE_INTERNAL.  This extra sanity check causes many tests to
fail.

FossilOrigin-Name: 2c5bb2bff26cc70d8cac78ddd12d5ac37ab1472f5f88afbd975950a18ac2804d
2022-04-23 18:04:31 +00:00
drh d6bb6000ef Make use of the "%!S" format when running ExplainSubquery.
FossilOrigin-Name: 9425d79cb407dedc259655625369e023d22a04ef7db606ea3eefe7e4d662be1a
2022-04-22 18:07:38 +00:00
drh da653b897d Improve EXPLAIN QUERY PLAN output and comments on bytecode listings by
distinguishing between "subquery" and "join" and using consistent names
across EQP and bytecode.

FossilOrigin-Name: a2d3ee92420ec564e31eb0005367cf7ff3d00bfaed5a98ffdbe17c91c95d9d97
2022-04-22 17:36:10 +00:00
drh 67f70bea06 Honor the MATERIALIZED keyword on a common table expression by not flattening
the CTE into an outer query.

FossilOrigin-Name: 8d631a6b9eb06b54b10eda595a4c588ca38f909b4afa653b24d1f720b55d72f7
2022-04-22 16:15:48 +00:00
dan 9b843f0ce0 Add test cases to check the handling of SQLITE_BUSY in rbu.
FossilOrigin-Name: 6fccc733c6041a2946fb3d37e4737ae37defae5c110225dd746cdc038cc64957
2022-04-22 15:18:41 +00:00
drh 1ca14b74ed Simplification of data structures in the wildcard expander for
SF_NestedFrom queries.

FossilOrigin-Name: f7c18262347ff430879d5afc7a118d2b9b0050c845c6b1fe6c047062ea2ba8fe
2022-04-22 13:34:45 +00:00
drh 9c2d7aa7d0 Minor simplification to the result-set wildcard expander for SF_NestedFrom.
FossilOrigin-Name: d942530a6550a0cbe31790e462b0f0d57b9b4a896161878b7d45d11cbc1cb7a3
2022-04-22 12:46:46 +00:00
drh 8318b55d87 Merge the latest trunk fixes into the right-join branch.
FossilOrigin-Name: c74dc574c3b24a7d3533202f33b15341b043cfd89a80250563e6771ab6b6b8a7
2022-04-22 09:57:57 +00:00
drh 1c69bc912d Previous fix to join8.test needs a return.
FossilOrigin-Name: 7b4cd705a0339ddacad19564b07e50e4f68f54bf14dd2cd5d59b39314a4d2523
2022-04-21 23:34:35 +00:00
drh abb4e7598c Disable join8.test if the build lacks support for virtual tables.
FossilOrigin-Name: 94e1916a2f594e6b8a54734027deb99688244d05cefb3c78f23afab49af1e08f
2022-04-21 23:01:24 +00:00
drh 11140addbb Add support for RIGHT and FULL JOIN.
FossilOrigin-Name: f766dff012af0ea3c28a8ce4db850cd0205729a8283bce1e442992aded7c734b
2022-04-21 19:38:17 +00:00
drh 6dab33bf40 Fix harmless compiler warnings.
FossilOrigin-Name: 29255664127a975e5b0d5767cd4e56d93ff2ea1994702cdfbdca1b700952502e
2022-04-21 19:25:51 +00:00
drh a74b4c4d45 Fix a harmless uninitialized variable warning in MSVC.
FossilOrigin-Name: b870d2a2fa54ddab6ffc9b9d95f52420a5a6831aeb73dac75355ca1ab15a190e
2022-04-21 19:20:38 +00:00
drh 7e9a56f70f Fix harmless compiler warnings in the CLI.
FossilOrigin-Name: dfd2100bc4f316825fd199b347849d1a2b941837f9eedcf36f3c3d280692b991
2022-04-21 19:14:23 +00:00
drh 503ad9c72d Make sure the code generator knows to invoke row-value subroutines which
running the right-join post-processing loop.

FossilOrigin-Name: fd328e52aee1dace12b1c2f44b6f7e9d15d8f77c8e9d9e3d85840a129a4b1808
2022-04-21 14:48:40 +00:00
drh 825a6bffc4 Ensure correct fg.isNestedFrom values even on crazy parses.
FossilOrigin-Name: e611e8e62c948d28cd3f28452d3096bab06998a685ed9434061cc2054f5cac32
2022-04-21 14:08:29 +00:00
drh 18f8600fe6 Avoid materializing columns of SF_NestedFrom subqueries that are never used.
Other code improvements manually imported from the right-join-paren branch.

FossilOrigin-Name: cd8272fc2a34d1b245fd95208b9b601266ee7d2ff0f5ce52d03752f2c4e852a2
2022-04-21 13:11:26 +00:00
larrybr 6403e77d3b For CLI, fix how columnar mode fills in empty portions of wrapped row outputs.
FossilOrigin-Name: 77aed89192bdbad819ac17bf5d08728278a9b8cbbbef1d805df230caff79b417
2022-04-20 22:41:10 +00:00
drh 22b410d894 Small correction to the new bUsed logic of sqlite3ProcessJoin().
FossilOrigin-Name: ba04142e09bb1ccc86824760a2e11df47e070285a2d09c2f61b75255886597cd
2022-04-20 18:12:42 +00:00
drh e60ffa3350 Merge window function fix from trunk.
FossilOrigin-Name: b6b9e185f8c44b5f2f51111f7c5e4e2d77c8b853c5be271467ce138e8066340c
2022-04-20 16:54:47 +00:00
drh 910e57b9df Remove an unnecessary assignment operation.
FossilOrigin-Name: ed46527aca170ccbe9ed9ea4ae065db72c82dec17da7b99c928fae4495f05c2b
2022-04-20 16:53:23 +00:00
dan 41150bf35b Fix a problem with using multiple SQLITE_SUBTYPE function as window functions in a single query.
FossilOrigin-Name: 9430ead7ba433cbfce99f4f364a0c08499230e3a04f167326b0f131f098ffa09
2022-04-20 16:42:57 +00:00
drh bc656e220f Comment fixes and improvements in sqlite3ProcessJoin().
FossilOrigin-Name: 1118655f4d58da1273e83954c80d8bc17fa3bde7a39e81cb9947d59894d5ab93
2022-04-20 16:26:22 +00:00
drh 815b782e99 Improved tracking of nested SELECT objects used to implement
parenthensized FROM terms.

FossilOrigin-Name: 0da2232624571f4020c05d775ea518514d748fba8dacd4caba2e2e6ed1ae399f
2022-04-20 15:07:39 +00:00
drh b465a83353 Also show the ENAME_SPAN value in sqlite3TreeViewExprList(), if there is one.
FossilOrigin-Name: c1d42861778d65f7014c43fbaf09972a69ff0d81bfc2f4720160a989489cf2c8
2022-04-20 12:15:51 +00:00
drh d4e9caf987 Improved TreeView output for ExprList: Show the ENAME_TAB value, if there
is one.

FossilOrigin-Name: eb3f883b45f1bf3f388823360f4aec2d4b8776bfd96185b4fb44b7bc95c62318
2022-04-20 12:14:20 +00:00
drh 2627cbd4b5 Add a new comment to the body of lookupName(). No code changes.
FossilOrigin-Name: 22fa9b9b450fbbf7578597714eb1094f7d7433ac13497dc7d4a9affc4a2652ad
2022-04-20 12:02:52 +00:00
drh befbb40f44 Merge the ALTER TABLE fix from trunk.
FossilOrigin-Name: d5ceaef3fca8cb4791ead9cbfe00d0eafa1bdc2b0522c3599c68b40fe6a7efe2
2022-04-19 23:00:32 +00:00
dan cbde37d8e4 Fix a problem in ALTER TABLE with handling "table.*" expressions within SELECT statements in triggers.
FossilOrigin-Name: 24755fd0657252e49793bb1fe906973a2dd84a1bde03bea9a762de36cc96c2d2
2022-04-19 20:47:18 +00:00
drh 4d0d071a53 Improved comment on the JF_LTORJ constant definition.
FossilOrigin-Name: e0744da95fc010dc3a2e030ff491bcfa08a18691ee6ebc7d4e8aab3850f56eec
2022-04-19 19:51:51 +00:00
drh 3117b7b081 Fix a NULL-pointer dereference that can occur on an aggregate query that
uses FULL JOIN.  dbsqlfuzz 496a35dd4eefcd7935aaaeb0c69056bf49785d28.

FossilOrigin-Name: 63b8f8aec2a9ac3fbbd02715aa308eaf43c9ffde9d7c6db026d46edc575e7bdd
2022-04-19 18:23:01 +00:00
drh e32d6a0bbf Mark an unreachable "just-in-case" branch as unreachable.
FossilOrigin-Name: b966d52437f08a6759a83a45cafb0d706a8933a8e55dee38ae78166d1a5b3ba4
2022-04-19 15:56:03 +00:00
drh de75638b33 Add 512 new join test cases derived from PostgreSQL output.
FossilOrigin-Name: 78d58e461f99366d2749ccd6d02ab4cba0cab20bb80c097e7128da1e50303549
2022-04-19 15:01:57 +00:00
drh 2e61588931 Remove unnecessary cases for the resolver.
FossilOrigin-Name: 5bc9aa68e2f938f6a70dd4b08703fe52416d17efe461ec65d37332b57b827fdd
2022-04-19 09:39:39 +00:00
drh d737b16f92 Add the omitted "finish_test" to the end of joinA.test.
FossilOrigin-Name: 0907505cc9bb051280108fe5074211374b31836fae1ae6667a3de69f9d83fc01
2022-04-19 02:03:18 +00:00
drh 3b8c7545df New test cases for RIGHT and FULL JOIN.
FossilOrigin-Name: 5c2f670e0fb35648e1d6e1c48f4d8af815cd57d59eac6ba22e253511bb078870
2022-04-19 00:24:52 +00:00
drh 1c2bf41a12 Fix the query flattener so that it does not flatten a RIGHT or FULL JOIN into
any position of the outer query other than the first.

FossilOrigin-Name: 837322aa95b1c46201b7dd0c2e6c7b9915b4276d997949f1ecf961fb7f3514cf
2022-04-18 23:20:02 +00:00
drh ec39c96473 New test cases, including one that gets a different result than Postgres.
FossilOrigin-Name: 49ea11a4a5fd630db44f458304d4f45fa103529ed6b36d538c78074965e8d799
2022-04-18 22:51:24 +00:00
drh f80bb195b3 Disable the unused EU4_EXPR mode for the IdList object.
FossilOrigin-Name: 5bcf4aa3bf6b1b9f47142bc37683bb3bf0adeffd052d07449af7c9b415add052
2022-04-18 19:48:31 +00:00
drh 7466d5665a Even more test cases.
FossilOrigin-Name: 5f4310a104443ac3fc56f9d9cd2d428dd3e7a2a0285c8e74de6f499439fd6868
2022-04-18 19:34:41 +00:00
drh 23f240b325 New test cases for parenthesized NATURAL FULL JOINs.
FossilOrigin-Name: e34250efd34b526373bf072a43a7984ca19690836d7d2464dea8338066eaee8f
2022-04-18 19:28:08 +00:00
drh a20922cb20 New test case demonstrating the ability to invoke OP_NullRow on a cursor
that has never been opened.

FossilOrigin-Name: d173edc242f295f5812a58cad184695881d9b1b160cd5b25e303e22848e90ce1
2022-04-18 18:01:38 +00:00
drh 25f2ce6e71 Merge the btree bug-fix from trunk.
FossilOrigin-Name: a333c0b50c3af7cd818470a647d78c7c691ef15418ec7cffe80dd88405393069
2022-04-18 16:23:01 +00:00
drh 7348ca4e0b Ensure that left-hand side WITHOUT ROWID tables are set to OP_NullRow prior
to running the right-join loop.  This fixes a problem introduced by the
previous check-in.

FossilOrigin-Name: aab7665ce6c004df701a72aef1a5135f2c78f16c6ff728a00076afb66ba9d3a0
2022-04-18 16:20:59 +00:00
drh 2e1bcc9dd0 Fix problems with WHERE clauses that follow multiple FULL JOINs. This
introduces some new faults in the tests, probably due to something
unrelated.

FossilOrigin-Name: 95b242d4c2fed7c713299565ac1010f8a7534a5695589e87d5a0204c7bf5f3dc
2022-04-18 16:10:07 +00:00
dan 1942d1f236 Avoid an assert() failure in allocateSpace() triggered by a corrupt database. dbsqlfuzz f022eb0ce64d27808574d1dcde5cf7d002dabde8.
FossilOrigin-Name: 2de7f8cc7fe18f0828bb53f1fd11f5eb828faf4d6dfaf39693dff4f8926c1c7a
2022-04-18 15:56:58 +00:00
drh 41db500274 Merge the latest fixes from trunk.
FossilOrigin-Name: 1ba3b3ccf145d84fa75afabe2fa925f65e43f815b25b15bd60073a41aa97bf57
2022-04-18 14:41:24 +00:00
drh e98b71e65d Improved comment field in the bytecode generated for OP_Column and OP_Rowid.
FossilOrigin-Name: 1b2c5cef9560123344db391cd065090d1914724715ec6643d2d9b5fac2051a21
2022-04-18 14:15:07 +00:00
drh 088b615acd Improved comment field in the bytecode generated for OP_Column and OP_Rowid.
FossilOrigin-Name: 009bbf8026106c5a74cced06cced48badb870a4b6e6a2f8104a544d2a8d79e45
2022-04-18 13:57:57 +00:00
drh 01a6c16e0c New RIGHT JOIN test cases, one of which is currently failing.
FossilOrigin-Name: 9168cbbedd1c9d735279295a78212d830e24269f6d7e445e71faa2c06973223d
2022-04-18 13:08:17 +00:00
drh a1848a5d22 Change the row-value initialization subroutine call from within the
right-join body subroutine from an issue to an optimization opportunity.

FossilOrigin-Name: 829d49f27c041651ffeadc1397e4dd87a9994c9290e13b93542dbd2c514769cd
2022-04-18 11:22:46 +00:00
drh d875c7eefe Do not allow an empty table bypass to jump outside of a right-join body
subroutine.

FossilOrigin-Name: 1549dcd2353903b70abadd428eeef971ab940df04fb05a6b83b04ee30932db6d
2022-04-18 10:26:50 +00:00
drh d973268ccf Fix the sqlite3SrcListAppendList() routine so that it correctly adds
the JT_LTORJ attribute to the first SrcItem, if needed.

FossilOrigin-Name: 07ed0dca310d828f9fe152efa8ee2a89202771a8f661afa1dbeee34aaabef67a
2022-04-18 10:09:29 +00:00
drh abf86bd313 Leave sqlite3ProcessJoin() early if an OOM is encountered in the NATURAL
to USING converter.  This avoids NULL pointer dereferences further along in
the code.

FossilOrigin-Name: 0ccb224e13ad44c7e1a3aa186821a929faabc0075fe15799476c00d9a92e9d91
2022-04-18 09:59:33 +00:00
drh 79a25ee021 Fix to the coalesce() function generation in the resolver.
FossilOrigin-Name: 584bd55e20669d09b7efe3429ba847c42c32fb1eb960784c4e0dedcd96899313
2022-04-18 00:57:11 +00:00
drh d0453f7ec5 When converting a NATURAL JOIN into a JOIN USING, make sure to insert the
name correctly into the IdList even if it is a wierd quoted name.

FossilOrigin-Name: e62156b696f2496e2697cb3b46f136551b58644e2a5824aa3d759596694b2f4b
2022-04-18 00:04:15 +00:00
drh a3e2518bb3 Fix to the logic that computes coalesc() functions to resolve USING terms.
FossilOrigin-Name: 20388548d868511f8c8437718985d75fe9801835811fec716f1700727b9aa367
2022-04-17 23:46:18 +00:00
drh f68621fe83 Deal with OP_Return bypass in the RIGHT JOIN subroutine by adding extra
OP_Returns where needed.

FossilOrigin-Name: 71abe5641f599f27d1f0c800f6182e1168909f8aa99389b835b07d4b5f5483eb
2022-04-17 22:58:23 +00:00
drh 2bd9f44a18 Change OP_Return such that if P3 is 1, the Return is a no-op when the
P1 register contains a NULL.

FossilOrigin-Name: c90602328a4b26f06d76c5343d29ebb7a782186c86ea88f5965a41040cff5346
2022-04-17 20:30:52 +00:00
drh fe14699765 Further improvements to USING() processing for RIGHT and FULL JOINs. All
currently known issues are now resolved.  Performace is improved.

FossilOrigin-Name: 9fd3f22e2228dfba127f6ffe549109f3a4e910fa124adcc9c5483931bd6d5cd7
2022-04-17 18:46:17 +00:00
drh 6fda176ba6 New test cases, one of which is failing, indicating a bug that needs fixing.
FossilOrigin-Name: bd5fd68435ff068c18d7d46b33cf7591263a03c32a917a7df7c087b08c573cc8
2022-04-16 23:38:29 +00:00
drh 052953a4e6 Fix the USING to ON translation so that it works correctly for a sequence
of two or more joins where one of the joins to the right-hand side of the
list is a RIGHT or FULL JOIN.

FossilOrigin-Name: 9ffc2b231956cde1bc90519aa174b0e2dc30ef671ed745f4f3ffa9fbb7ffab4b
2022-04-16 22:57:41 +00:00
drh fdc621aece Since the query planner is unable to cope with a LEFT JOIN on the left-hand side
of a RIGHT JOIN, detect that situation early and raise a parsing error.
This is a temporary measure that needs to be fixed.

FossilOrigin-Name: 6d5d6e0403241c99ab4a47d7b6eedcd8ebc615a8ca8d66d7e81171f901b170d7
2022-04-16 19:13:16 +00:00
drh cebc8009ed Additional SELECT trace logic: Show the tree after result-set wildcard
expansion but before name resolution.

FossilOrigin-Name: a7babf75418adffa27dec7a9d382a60e1b9364fb51d72b0a10e2769b308b3c54
2022-04-16 18:33:22 +00:00
larrybr 2d27d36cba Make shell auto-column work with lots of columns when log() is missing.
FossilOrigin-Name: 82366436ef74838dae1f379f3e5b8ad187225a30ec58fb49f047ab7c08a263cf
2022-04-16 17:53:25 +00:00
dan b192970809 Fix a problem with "ON DELETE RESTRICT" and "ON UPDATE RESTRICT" foreign keys in attached databases scanning child tables in the wrong schema.
FossilOrigin-Name: 04d5b637f087520cd58211505f9b5c086ff96d864a1908f60464b6fe22c62b7d
2022-04-16 15:46:23 +00:00
drh 977eef6cdc New test cases. One of the new test cases shows a flaw in the base design
of RIGHT JOIN.

FossilOrigin-Name: 4c3ce6475a67b1e207a5b63d9e2d38ee5bc45c899ad00ee327f292bf59039b9c
2022-04-16 13:55:48 +00:00
drh bdbda1eb1f RIGHT JOIN USING now appears to work the same as PG-14. Legacy tests pass.
FossilOrigin-Name: 5bfb862419541de955dae35fc91f6e9fc70e2744bb786d49fa26bede80b9091d
2022-04-16 12:40:52 +00:00
drh be60896485 Revamp the USING clause processing so that it works (mostly) with RIGHT
and FULL JOIN.

FossilOrigin-Name: 719c8d920b435b0f234d47467a2abe2941ab7d55ecca886e211cfce577ae648c
2022-04-15 19:53:35 +00:00
drh e62d9149a6 Avoid deleting substructure of the Expr node in lookupName() until after
the error message is generated.

FossilOrigin-Name: b8e717663957dfd84e580bf21bc8e8881b33fdb94a2cc0c664a230e54d5e5076
2022-04-15 19:49:28 +00:00
drh bb3c62a758 Progress toward a working USING for FULL JOIN.
FossilOrigin-Name: fed2646adecb0a05dd674dc1cd2c0ae205078fe552ba93b8d68891c728c67637
2022-04-15 19:27:02 +00:00
drh 4ce7bf9156 When expanding "*" in the result set of a SELECT, do not attach a table name
to columns that are in subsequent USING clauses.

FossilOrigin-Name: 91530990e018580ec5322ace6f0c369a32a3529a0bfb4defb25ca20223a2a80f
2022-04-15 18:30:48 +00:00
drh 22c4bc8991 The sqlite3ProcessJoin() routine converts a NATURAL JOIN into a JOIN USING so
that henceforth the NATURAL keyword can be ignored.

FossilOrigin-Name: 8378e1e0d289627fb294ccd3f5865ef49df3a42b8a5aa211e21be1b42d9da753
2022-04-15 17:08:40 +00:00
drh a99e325468 Enhance the IdList object to exist in a single memory allocation (rather than
a separate allocate for the base object and the array of IDs).  Also permit
an IdList object to store an Expr pointer together with each name.

FossilOrigin-Name: 40f3c95871e6f40f287ef2756abafb8fc56dffdd0af69436e5c7d8e95022d94e
2022-04-15 15:47:14 +00:00
drh 358424aeff Add the "3" in the name of the sqlite3ProcessJoin() function.
FossilOrigin-Name: b925f72b6f679c61b0d6be16fabe64dc7605550b7bd86f35c586dcecd8217673
2022-04-15 15:15:01 +00:00
drh a51379ad78 Record the three known big issues with the current RIGHT JOIN design in
the join8 test module, with tests that deliberately fail in order to remind
us to fix the issues.

FossilOrigin-Name: 2c4ee723f4d0591d09776adfb82246bfa89153ab390b8b3f1878d1cdc43d68c8
2022-04-14 20:43:22 +00:00
drh b3ebf3043f Cherry pick subroutine indentation improvements and the hardening of
OP_Gosub from the right-join branch back into trunk.

FossilOrigin-Name: 12645f100d902690630a2925674aedbb01d41a53426a26a2f56de5b8fdec955f
2022-04-14 19:48:32 +00:00
drh 79f60034ee Another instance of indenting a subroutine.
FossilOrigin-Name: 73f4036b04798660b30e540cbab69420078df9fb62a6a39944e078c36272f905
2022-04-14 19:05:17 +00:00
drh d549a702b3 Check for interrupts and invoke the progress handler following a Gosub
opcode, to avoid and recover from infinite subroutine loops.

FossilOrigin-Name: 647211e044a5856ceb6bf3e7b78e650fe7d81f8b7bf34568b99b346405ba520c
2022-04-14 18:19:06 +00:00
drh 2c31c00bfa Rerun the subroutines that compute row-values if necessary from within
the RIGHT JOIN body subroutine.

FossilOrigin-Name: 9b9038bcd0ab5c4f01661456635526cef764f854ff24018a5e6e43825d07eb59
2022-04-14 16:34:07 +00:00
drh 37f5584a2f Adjust the output formatting of bytecode listings so that subroutines used
to implement subqueries are indented one level.

FossilOrigin-Name: 079b7b125206fb295720612f4853a5b786ec431ab595d35407195844779c149d
2022-04-14 15:55:34 +00:00
drh d345dcf39a Disable autoindexing for the RIGHT JOIN loop.
FossilOrigin-Name: 402a89e33e39b00352dc9fb3301d03c6f75d8bb5c2ad540cd22506bff10b4d85
2022-04-14 14:58:50 +00:00
drh 375f182b1d Adjust assert() statements to account for the new always-NULL cursor type
added by [4526c5d316508093].

FossilOrigin-Name: 7822faa48a058c0b0313b9241d290153fbe74ab84f58369a70014118a9085d1d
2022-04-14 14:40:29 +00:00
drh c504f677b6 Previous check-in accidentally inverted a test on an assert(). Fix that.
FossilOrigin-Name: 5ec4f806c569428851b6f0159451aa3ed66b3bc61a845fd7c543cffb694b882d
2022-04-14 14:19:23 +00:00
drh eab6c125bd Fix assert() statements associated with artifical null-value cursors
created by RIGHT JOIN.

FossilOrigin-Name: f5bce5f152259767497ae6826c558003822d976b3f35f4d74edee59a3490efb2
2022-04-14 12:59:25 +00:00
drh 95b1036e9a Fix a harmless (false-positive) unused variable compiler warning on MSVC.
FossilOrigin-Name: 63b04c63de680261a0d3eaf27154a1e8e77e3e166c3f2dbaea985603991c74f7
2022-04-13 19:00:57 +00:00
drh b60d1fbe8e Make the sqlite3TreeViewSrcList() routine a no-op if called with a
NULL SrcList object.

FossilOrigin-Name: 185d2720e7775e3060a1647353c10aada435244db53a0732ee786788a6ecae3f
2022-04-13 18:32:04 +00:00
drh 7c96039492 Fix an assert() in OP_Column so that it accounts for the new type of
pseudo-cursor that always returns NULL for any column.

FossilOrigin-Name: 371ddc97bef8e0d88ad965f00d27e010880174312ea36c4f1165dcf08441f40a
2022-04-13 18:20:23 +00:00
drh 3ac624344d If the OP_NullRow opcode is given a cursor that has not yet been opened,
then go automatically open it to a special pseudo-cursor that allows returns
NULL for every column.  Used by the new RIGHT JOIN implementation.

FossilOrigin-Name: 4526c5d316508093b7f3aeda1ce9d16ceb0be79842015a6d51f28c22b4473ca2
2022-04-13 17:41:03 +00:00
drh f7ecd956ce Move the explain comment for the RIGHT-JOIN post-processing loop to the
verify beginning of the loop - to make the start of the loop clearer to
human bytecode readers.

FossilOrigin-Name: 7ed2a271e6fcbb5e69a7f3a88d3f45fe6318819c0cc6a0dcc06c3dae5aa1503f
2022-04-13 16:46:35 +00:00
drh 94e615a6ac Add support for RIGHT and FULL OUTER JOINs.
FossilOrigin-Name: fa9d206f904280e3eafc6f4ba6c0c7325948364c62eeeb9f0fdc5825d622ec35
2022-04-13 12:34:54 +00:00
drh 12c35ec322 The rows of a RIGHT JOIN might come out in any arbitrary order. So disable
the ORDER-BY/GROUP-BY optimizations if a RIGHT JOIN is involved.

FossilOrigin-Name: d168f245ecf497368feea4697769930c00420ef47a584904dac85371b61fb78a
2022-04-13 12:12:01 +00:00
drh 3b79f7580a Fix an assert() in btree.c that might not be true for a corrupt database file.
FossilOrigin-Name: dbd8e2e46cfb2de0ebdbb62cda2fe669df3eda98f5d6112d541f581995b1361d
2022-04-13 10:49:50 +00:00
drh 146e64d2e4 Add missing VdbeCoverage() macros on new branch byte-code opcodes.
FossilOrigin-Name: 218c7167e562f5c327124f02a92de85079315320a221fb0508310d927596b14c
2022-04-13 01:52:32 +00:00
drh f7309bce10 Ensure that the JT_LTORJ bit in the SrcItem.fg.jointype is preserved during
query flattening.

FossilOrigin-Name: 61259050152321bc57dbdfdc3edcabb4f18c021b1ee0491c1e04ae24c7a59d89
2022-04-12 20:20:54 +00:00
drh 0879d5f9e0 For the bad join type error message "unknown or unsupported join type"
remove the "or unsupported" clause, because we now support all valid join
types.

FossilOrigin-Name: ab0a0562dd3594cf50ee56f6b3a5847fa5dcadf69146d560e3e7a95651b8f405
2022-04-12 18:40:14 +00:00
drh 949e2ab49a Factor out the RIGHT JOIN non-matched row loop from sqlite3WhereEnd(). This
reduces the register pressure on that routine and helps it to run faster
in the common case where there is no RIGHT JOIN.

FossilOrigin-Name: beeecf1604d4fb11e45058f48cb2289c6542e0bc218d63a245198113d8d5476b
2022-04-12 18:04:29 +00:00
drh 57d4b5bde1 Merge the latest enhancements from trunk into the right-join branch.
FossilOrigin-Name: b3e57ba120067c79e0398e39da9f00ecb11a5e18c36479da4c36a39e88a78a27
2022-04-12 17:43:30 +00:00
dan 6625d6d873 Earlier detection of corruption in balance_nonroot(). dbsqlfuzz 9191ade77ebd3b7a3356e074957aa85b0c669d14.
FossilOrigin-Name: bff4f083eb1c35544988493a5d73a42e646c4250b841f5aae38c2183f0867a0e
2022-04-12 17:02:27 +00:00
drh 61dac44eb9 The multi-index OR optimization does not work for RIGHT join, so disallow it.
FossilOrigin-Name: 34c2f7b237fa4e0e1cd94fb9c44ebe194b86b88dc575055cc46c7f3695d02756
2022-04-12 14:23:45 +00:00
drh a70782407d Always explicitly set each table cursor to NullRow before doing the RIGHT-JOIN
unmatched row pass.  This is a cheap opcode, and it adds an extra layer of
defense against incorrect results.

FossilOrigin-Name: a3d14e61ca22167296fee125a3e9aa63413408955e03bb3f9d85fa9f22df1b79
2022-04-12 13:46:21 +00:00
dan f7413d9acf Modify utility function sqlite3SetString() so that it may be used safely on Parse.zErrMsg. Fuzzer test case "crash-1604e5d76c92574e21e437049dab9b672e06b767.txt".
FossilOrigin-Name: 09c5a4ec13b02efd6207e26dab7beaf184f0d8ccea0bd0dfe94fc803fe5636ce
2022-04-12 11:02:06 +00:00
drh b087de063b Fix RIGHT JOIN for virtual tables.
FossilOrigin-Name: 75a9116e98b9ac5c1a4c62a01143a016d9ba6a0b495ff7af7468c11947a3e888
2022-04-11 21:00:38 +00:00
drh c133bab72a The query flattener must add TK_IF_NULL_ROW opcodes on substituted values
that land on the left operand of a RIGHT JOIN, just as it already does for
the right operand of a LEFT JOIN.

FossilOrigin-Name: 8e02cdf5b1128f5e5b82d93903063415ec312694e5ccdd19e99fa35433f1b68a
2022-04-11 20:15:52 +00:00
drh ec27077c4f New test cases added.
FossilOrigin-Name: bdd1499c0fa4f8aadf4857a0ccc0d839c250369f29766ebef80330964905e63b
2022-04-11 18:54:23 +00:00
drh 6134b2dff2 Fix handling of "continue" and "break" from inside the loop for the right
operand of a RIGHT JOIN.

FossilOrigin-Name: b6e773a26c2c6ee76ea61acb059b4e676d07ea62f6db9c513638f8986557cf04
2022-04-11 17:27:38 +00:00
drh ff02ac7f07 Do not attempt the LEFT JOIN strength reduction optimization on a FULL JOIN.
FossilOrigin-Name: 7ef3e99a73d70405a185d5d31f2d97d3bd99568fd6f10941e75d6c0baa27dc4f
2022-04-11 14:43:11 +00:00
drh c583719b65 Show LEFT and RIGHT JOIN processing in the EXPLAIN QUERY PLAN output.
FossilOrigin-Name: d91faeffea5cf0585fb71e5311fdcc6b8be85c7e9c732050b4448e617c970101
2022-04-11 14:26:37 +00:00
drh 37259f4e6b New test cases.
FossilOrigin-Name: d5f6791b86f946b348f5ddc9cedc0df4a86b17854a97554140799caf74c602f3
2022-04-11 13:13:57 +00:00
drh 3a6e4c59c4 Make a distinction between (1) WHERE clause constraints, (2) ON/USING
constraints on outer joins, and (3) ON/USING clause constraints on inner
joins.  Formerly, there was no distinctionb between 1 and 3, but RIGHT JOIN
needs to know the difference.  Make RIGHT JOIN aware of this difference and
add test cases.

FossilOrigin-Name: 0f6f61c3664cc87209c2a6f9b6df3a750d1510723fcde209c33db8feaf48bcf3
2022-04-11 12:38:06 +00:00
drh b77c07a715 Fix some comments that refer to LEFT JOIN that should refer to OUTER JOIN.
No changes to code.

FossilOrigin-Name: 5be5ede5cca1cd5ef863fe0feb2b4a990f4a42865281a6c2e4eb816f48847dc6
2022-04-11 11:59:25 +00:00
drh 189c065942 Merge the Expr.w.iJoin name change from trunk into the right-join branch.
FossilOrigin-Name: 29927926eb32acd963e2c496ad67d55177615ec4150fd218afaf2f9a730cabec
2022-04-11 11:48:17 +00:00
drh d198526289 Rename the Expr.w.iRightJoinTable to just Expr.w.iJoin, so that the words
"RightJoin" in the former name do not lead readers to believe that this has
something to do with RIGHT JOINs in particular.

FossilOrigin-Name: e8c00442d2daedec079748d13147bf73b0ec3c3cf432bce2cdccb706bdff2853
2022-04-11 11:25:28 +00:00
drh 79d2658671 Ensure that the JT_LTORJ flag is preserved when flattening a subquery that
is on the left side of a RIGHT JOIN.

FossilOrigin-Name: ccb61fb1f30e2741b19c1a0cbd2951715224852c86234a3c6a4bbd2e1187634a
2022-04-11 10:38:28 +00:00
drh 8a28ce7bc2 Show the JT_LTORJ flag in TreeView debugging output.
FossilOrigin-Name: 21eb44919f38abad30b75181ca8aec38b453b94dba2815caf7e946e07faa40d7
2022-04-11 00:54:30 +00:00
drh 41798d5bbc Do not allow query flattening nor the push-down optimization on the
right operand of a RIGHT JOIN.

FossilOrigin-Name: 5aa0c9ea9cf53c13bf266278b479b2e7af3aa5c6b144bd49ff155a4eb3c23c96
2022-04-11 00:21:53 +00:00
drh 529394e5c1 Cannot use an automatic index on the right table of a RIGHT JOIN because
automatic indexes must be WHERE_IDX_ONLY, but the RIGHT JOIN post-processing
does not know how to work with an index-only scan.

FossilOrigin-Name: beb4401dc09fb68e85ddcf3f99598527691535d0eb7693168f440e5a5a076e3f
2022-04-10 23:48:47 +00:00
drh 9debb58e48 Revisit [f84b2beca7197589]: disallow co-routine implementations of tables
that are to the left of a RIGHT JOIN, to avoid other complications.

FossilOrigin-Name: cf00ebfc4b77f45ec466b0d57d7c22c7f48acab19e4e55b168eb4b53f390d887
2022-04-10 23:01:20 +00:00
drh 62ed36bb5d Minor improvements to the sqlite3SrcListShiftJoinType() routine. This started
out to be an effort to convert RIGHT JOIN to LEFT JOIN if the join was on
the first pair of relations, but that messes up the "*" expansion and so won't
work.

FossilOrigin-Name: a48902c71ed30c83de7dbd26d1c7956136c35dc53b1076bc8b1ebcba568a3fd3
2022-04-10 20:28:41 +00:00
drh fcde633f7c When the left-most table of a RIGHT JOIN is implemented as a co-routine,
make sure all its columns are flushed to NULL when it finishes so that
they appear to be NULL during the RIGHT JOIN post-processing.

FossilOrigin-Name: f84b2beca719758979d7a5a63c3d16d5121a7518b3fbe5039af474a83dd569c2
2022-04-10 19:51:22 +00:00
drh e21e36dd2c More test cases and bug fixes.
FossilOrigin-Name: 140e97fde94fdc3babdd456ce1b22900ead0e40e2afe63d89d21ccdbf141b607
2022-04-10 17:14:48 +00:00
drh a20c71e9e8 More RIGHT JOIN test cases and a bug fix.
FossilOrigin-Name: 19e8ad690a140ca40838bf31a377c19010fcbbc2554a4f1746737543043e334b
2022-04-10 16:13:37 +00:00
drh ac8c438a79 Add a simple test case. (It is not difficult to create additional test
cases that assert, at this point.)

FossilOrigin-Name: f2201d5dcfc552bdddd0780b3f466bdaa886e557f147335c085395bfc001f6b0
2022-04-09 20:11:05 +00:00
larrybr 039132be20 Fix .import bug reported at https://sqlite.org/forum/forumpost/14db09d7e765b819 . zAutoColumn made to deliver characters, not bytes.
FossilOrigin-Name: 21e96600d90c1cda84777abe22a11058eba46c9faefeb05f8c31bc0e7fa84b19
2022-04-09 18:51:49 +00:00
drh de24dd706e Bug fixes. A basic FULL OUTER JOIN now works.
FossilOrigin-Name: 34bbeeb77bd530b2b1f0390e9e552f65ae35f09a74d80a09dd327e64f9be51a1
2022-04-09 18:48:11 +00:00
drh 86c1beb402 Add byte-code that computes unmatched rows on the right table of a RIGHT JOIN.
Compiles, and the code looks semi-reasonable, but still does not run.
Incremental check-in.

FossilOrigin-Name: 2db5a498e74241dd19ef51c601f1a2b3b687faed3e1be2d1e3ada737406ac8e9
2022-04-09 14:48:35 +00:00
drh 7c1734b09e The interior of the RIGHT JOIN loop is now a subroutine.
FossilOrigin-Name: 549f5a7ee639de80f049445002f58e93c805f9a3d3db1987ec9d139ccef4805e
2022-04-09 12:27:20 +00:00
drh c2308ad2a0 A few bits and bobs of code generation toward getting RIGHT JOIN to work.
Much more remains to do.

FossilOrigin-Name: 55b4543122646997d928598343bc467c993f971e86e9037c85430cc948750576
2022-04-09 03:16:26 +00:00
drh c187163090 Merge the sqlite3WhereMalloc() routine from trunk into the right-join branch.
FossilOrigin-Name: b1b3845aa38f469a27f07c8f6e8a98334f7967b19661ee4cf155d6997afd9d4c
2022-04-09 03:12:52 +00:00
drh f8bdcfa3f1 The sqlite3WhereMalloc() routine allocates memory that is automatically
deleted when the corresponding WhereInfo object is destroyed.

FossilOrigin-Name: f237e1d8cc41b937f34288daebfacf5f7b0990a807a805e0cb6b45bc730192d6
2022-04-09 03:06:01 +00:00
drh a76ac88af8 Preliminary code to support RIGHT JOIN. Everything seems to work, except that
the code to compute the unmatched rows for the RIGHT JOIN has not yet been
added, so the result of a RIGHT JOIN is currently the same as an INNER JOIN.

FossilOrigin-Name: 415abd6731b8e8a605adabfa6066c8a852a8531c300df41325d5f7e75cae5a70
2022-04-08 19:20:12 +00:00
drh 7d0ae00361 Enhance the sqlite_dbpage fix at [/info/642a0b4752743216|check-in 642a0b4752743]
from about a month ago such that it still takes a transaction on all attached
databases, but it only starts a read transaction for read-only operations,
rather than starting a write transaction for everything.

FossilOrigin-Name: 8efd61e8518594e3e9c84681fc35796a78fe8885a97ad4dd19f1573ee8065b18
2022-04-08 17:01:29 +00:00
drh 81a23623d8 Improved explanation and commentary on the sqlite3JoinType() routine. One
of the error messages changes slightly, but besides that everything works
the same.

FossilOrigin-Name: 48f2e5a1fbaa8ceb32e08066766be74233b0c67ab430bbf7adfdff42cdb7b8ec
2022-04-08 15:11:10 +00:00
drh ce5dd9e8d6 Fix two unreachable branches introduced by the recent
sqlite3TriggersExist() optimization.

FossilOrigin-Name: 1b5475d212cf9de0bff69eee8c607b4fcd8e04bf4df72171429e7609c4153951
2022-04-07 20:45:38 +00:00
drh e603ab00ee Enhance the EXPLAIN output formatting in the CLI so that the subroutine that
implements the loop body for the multi-index OR optimization is indented.

FossilOrigin-Name: c2965fea9df7076b235d3eadaf84f0a36242476d0329030b0e57557b66e2540c
2022-04-07 19:06:31 +00:00
drh da4c7ccc07 The ".testctrl optimizations 0x400000" command disables the generation of
OP_ReleaseReg opcodes.  OP_ReleaseReg opcodes are usually only generated for
SQLITE_DEBUG builds and are used to verify that registers are descoped
propertly.  But they can get in the way of code understanding when studying
bytecode dumps.  So this new optimization setting is provided to
temporarily turn OP_ReleaseReg opcodes off.

FossilOrigin-Name: fa5276725f246cef9d58b27c1e617ee3f873f7a9b88284a4e8fc453ebda338bc
2022-04-07 18:17:56 +00:00
drh db08a6d13c Fix the parsing of C-style comments in Lemon, as reported by
[forum:/forumpost/b6edc69548|forum post b6edc69548].  This has no affect
on SQLite itself.

FossilOrigin-Name: 201569e09b000919ccb463bd581fb2ecd5320e7f584fdb1bc2aaba111061d5c3
2022-04-07 14:13:32 +00:00
drh a744167956 Optimization to sqlite3TriggersExist() saves over 700K CPU cycles.
FossilOrigin-Name: 5043a3507e0781878e0e1bea5095a33273958820baead4af8fc2929e9d7c07ee
2022-04-07 14:03:07 +00:00
drh 4cd8296f39 Avoid compiler warnings about the new sqlite3Show() debugging routines
begin "defined but not used".

FossilOrigin-Name: 47ddc26974fbad8233c953d435e79d4f5dd5e09fbd684ea5f4ad32f4cae6cae6
2022-04-07 13:48:34 +00:00
drh 9c949b1c46 Omit an unnecessary initialization in tokenExpr().
FossilOrigin-Name: 8f6ae686019c61a03fe70eb78d2b529b1cf126215b45513a97cfdf7086f82f54
2022-04-07 12:10:00 +00:00
drh c381056e6d Fix harmless compiler warnings.
FossilOrigin-Name: 61095b5bcb5c30d29f03efa5b4809e3a0b780ed57e35227c292aab9dd1cfe3f6
2022-04-07 10:11:35 +00:00
drh d44f8b2385 Improved technique for parsing the ON and USING clauses of a join is faster
and uses less memory.

FossilOrigin-Name: 158156a3e3d50042cafc75dea3aaaa68b1f2efb9c3d178518ea6e68e32e0d21c
2022-04-07 01:11:13 +00:00
drh 200adc9e75 Faster parsing of the FROM clause in joins for the common case where there
is no INDEXED BY clause.

FossilOrigin-Name: 848b7a0ea99ddc52091b78313f018c07d00a0e28aa6da8c1cae709c1d03468fe
2022-04-06 19:46:20 +00:00
drh c2d0df95ba Improvements to the display of AST for DML statements.
FossilOrigin-Name: 84c239a071cfaf8af107646f01ef269e2915fd2384e95927d484f2e408ba6bbf
2022-04-06 18:30:17 +00:00
drh 2a7dcbfbb0 Attempt to show triggers in the TreeView output from DELETE, INSERT, and
UPDATE statements.

FossilOrigin-Name: b0939d6f4d94b45dce53ace6295508a67d574cc72bd6977623bf77065b3c4e64
2022-04-06 15:41:53 +00:00
drh c16a5686fe Corrections and updates to the header comment describing the
TriggerStep object.  No changes to code.

FossilOrigin-Name: abb34c0830a49d4f4e277ddd17e710529e87cba7061f3546079dbba2f82b020e
2022-04-06 12:54:41 +00:00
drh 8f1eb6f5e4 Add the sqlite3Show() family of debugging interfaces under SQLITE_DEBUG.
No changes to deliverable builds.  Rename SQLITE_ENABLE_SELECTTRACE to
SQLITE_ENABLE_TREETRACE in ctime.c.

FossilOrigin-Name: bc33168cf1f48caf848c2dc5c3ae15e4efff8c0378f944eb5398a245139a2b35
2022-04-06 12:25:04 +00:00
drh 5e431bead8 Rename debugging defines and variables from SELECTTRACE to TREETRACE (and
similar) since the functionality has how expanded to include data structures
beyond SELECT statements.  Should not affect deliverable builds.

FossilOrigin-Name: 393fa32e188a017f431372b54037cb31e885030542f00d0bfd59da9d9db5c014
2022-04-06 11:08:38 +00:00
drh f8ef2dbd7b Add additional tree display routines for DELETE and UPDATE. No changes
to deliverable code.

FossilOrigin-Name: fbd288ff3d4ea47cd324b5952e7754a465901844f2d950f0860d4488d5b6eb9f
2022-04-06 10:37:44 +00:00
drh 7d2c1d24b0 Add new diagnostic "sqlite3TreeView" routines for IdList, Upsert, and for
INSERT statements.  This is all debugging code.  There are no changes to
release builds.

FossilOrigin-Name: f3084122039bcb30c8617f5f432009a49be8b488235850a1f10ef862c91560b2
2022-04-06 00:29:21 +00:00
drh ec534e6a23 Small performance and size improvement to OP_Found.
FossilOrigin-Name: 81587a18b7c0516628453000172a0c58e74ee173c15f655d035799d84d4e2d81
2022-04-04 20:20:22 +00:00
drh 50f22d17a8 Tag an always-taken branch using ALWAYS().
FossilOrigin-Name: ad8bc3d7443ff57ce5a8756428e717ac42ec0295191a9b4d7ae44846d8fa03a2
2022-04-04 19:58:55 +00:00
drh b834e0de59 Optimizations to the OP_Found opcode save about 600K cycles in speedtest1.
FossilOrigin-Name: 5c3357ad62843fe982b9c2d31dbf02018f2948ceab2c85dac917cd9ce1e97dd6
2022-04-04 19:43:57 +00:00
drh 36d2d09023 Use unpacked keys for OP_Found in foreign key processing.
FossilOrigin-Name: 328dc76657eb5317f0201859d2b3abe6918103b894f7beaed0aca3058a9f2b64
2022-04-04 18:17:59 +00:00
drh 0de10ac11c When constructing the JSON Path for the "fullpath" column of the
json_tree() and json_each() table-valued functions, be sure to quote
object labels where necessary.

FossilOrigin-Name: 0fbbe7881cadf0b3c211653c7a0797e0a90c7c24da78ecc8a27140c05f89f2ed
2022-04-04 15:15:45 +00:00
drh b07fb4f1c2 Fix the JSON Path parser so that it will accept zero-length object labels.
[forum/forumpost/c082aeab43|Forum thread c082aeab43].

FossilOrigin-Name: 84fe95d2a5b4d232d657e3b8110027a698a9bcd597f205cc535cfa97bc299f21
2022-04-04 14:24:14 +00:00
drh a81a9f78fd Performance optimization and stronger assert()s in the comparison opcodes.
FossilOrigin-Name: e0305e640b9078c7eed9ab0bcc14f4515b54e7cd9ade3306bc2d1660f05b2725
2022-04-04 11:38:49 +00:00
drh 1c8486301f Only invoke sqlite3VdbeClearObject() from a single location, so that the
compiler is more likely to in-line the code.  Performance increase and
size reduction.

FossilOrigin-Name: c6947a96e61f71aa61ca3d70d9e2612d784ab04d60fa88852b03cfce86b1bf2b
2022-04-04 01:12:11 +00:00
drh 8703edd3e9 Performance optimization in the sqlite3VdbeHalt() routine.
FossilOrigin-Name: 9564d72a0820dbcb38f905fcd42ed4c858ea8fb5f648b189ceb65380a14a785b
2022-04-03 22:35:13 +00:00
drh 8bb93daca0 Performance optimization and size reduction in the OP_Halt opcode.
FossilOrigin-Name: 21948e6e1ccd2ce128742415d21759604ecb8902226ec4707dbd75585450f208
2022-04-03 20:39:48 +00:00
drh 18bcfb999a Omit the Vdbe.runOnlyOnce flag (simplifying the prepared statement
implementation) and accomplish the same result by adding an "OP_Expire 1 1"
opcode to prepared statements that would normally have runOnlyOnce set.

FossilOrigin-Name: 6e20e1c46d17ac6aba21e02b57649af51cfa415d83d0c001b30677d2fd1f1dc1
2022-04-03 19:13:40 +00:00
drh 8ee75f7c3a Performance optimization and slight size reduction in the OP_Transaction
opcode.

FossilOrigin-Name: 7bee8c195f3fc27aaab13e493ad446a4f19201de3ac064ed6d8a3cbda7c69ee1
2022-04-03 10:42:06 +00:00
drh c2808f39d1 Expand the getVarint32() macro in a few places, as the C-compiler seems to
be able to optimize better when that macro is expanded manually.

FossilOrigin-Name: cd4fe34b98bf5ce26f3596c717edb73932f3b46ad6e9b4934d06b7b3c176a0d6
2022-04-02 22:47:47 +00:00
drh 1f416db292 Fix harmless compiler warnings.
FossilOrigin-Name: 8a3a3486358d076c34e515ac92663a04f0c7ff10f405094cb5b6ada0d5f05cdc
2022-04-02 20:08:48 +00:00
drh d13527daed Ensure that a zero-blob does not cause in invocation of memcpy() with a
zero length and a NULL source pointer.

FossilOrigin-Name: 35441eb5e1447e01f2031837a4ede705bce34f87be27912278cc730abce6cf05
2022-04-02 19:21:58 +00:00
drh 2c144b0f63 Minor loop optimization in OP_MakeRecord.
FossilOrigin-Name: 4350983b37879d3280432d90fef04f5cc4be1b3110b5435123d897e31b34db8a
2022-04-02 15:19:02 +00:00
drh d859dc2b25 In-line the sqlite3VdbeSerialPut() routine into the OP_MakeRecord opcode.
This allows some duplicate comparisons to be omitted, resulting in a size
reduction and performance increase.

FossilOrigin-Name: 6f4d6f212a3558c27be6e9dcf71cec43c424d445e5889c6e91dde84a19c5a2c1
2022-04-02 14:30:58 +00:00
drh b47b1f67dc The putVarint32() macro does not optimize well. So expand it into in-line
code in places were performance is an issue.

FossilOrigin-Name: 390c239e53cf936a97b268dce8171f0b17050542ae64735ca8ef375fec2c9544
2022-04-01 21:01:37 +00:00
drh 759e507ce5 Loop optimization in the OP_MakeRecord opcode.
FossilOrigin-Name: 47a61fbd63928021098fbe492283f1afda7c293b3b2706c001192ae4ff1b2cbe
2022-04-01 20:39:40 +00:00
drh 3b8b5be3b7 It is not necessary to de-ephermeralize the output registers in the
OP_ResultRow opcode.  Omit that step for a size reduction and performance
increase.

FossilOrigin-Name: 8a07745aed1d0a4eead55d43f1923597b12371f307ecf5bc19c5a1db9a107a50
2022-04-01 20:19:36 +00:00
drh 35e9e350ca There is no need for sqlite3_step() to check for an OOM condition prior
to starting up.

FossilOrigin-Name: 44be7f46ba89289683ed0e123169ca9adb1018de03071d66de480c910a23d074
2022-04-01 19:13:39 +00:00
drh a24832b7b2 Omit the Vdbe.doingRerun field for a slight size reduction and performance gain.
FossilOrigin-Name: e93297a9d775688e6274c54ba75b19fc1fe8b29b73b9b5e7f94f3f2ca37f045f
2022-04-01 19:04:13 +00:00
drh cf6e3fd787 New macro ROUND8P() which works like ROUND8() but assumes that the input is
already a multiple of the size of a pointer.  It becomes a no-op for
64-bit machines, giving a small size reduction and speed boost.

FossilOrigin-Name: d126f304cde66ebfe21a4967c22dcba0bac27cbce56318b14bd50051e49c978c
2022-04-01 18:45:11 +00:00
drh 473571b083 Provide and use a version of sqlite3VdbeFreeCursor() that guarantees the
cursor pointer is not NULL.  This saves a few bytes of code space and a
few CPU cycles.

FossilOrigin-Name: cb5e6f8e265c91221227e5f15b95798c688773262407dd138d414103184702f6
2022-04-01 18:19:04 +00:00
drh 2fb448f2c8 Remove an unnecessary branch from sqlite3VdbeReset().
FossilOrigin-Name: a7d79560a0efd6221ba59ce84bcb4fa94024a901ac4a45e192ddecc6e1b5c78c
2022-04-01 17:23:17 +00:00
drh 17c4865b83 Refactor the Vdbe.iVdbeMagic field into Vdbe.eVdbeState. Split the RUNNING
state into separate RUNNING and READY.  This gives a size reduction and
performance increase.

FossilOrigin-Name: 5a50a42fde9477868fad31099f5fe976437825fac44f8b3a4cf6c739c7667bbb
2022-04-01 17:01:57 +00:00
drh 00946d7953 Avoid a harmless uninitialized variable warning in PRAGMA incremental_vacuum.
FossilOrigin-Name: 6d976f90dfe4886c3f4c062151af5c5ca7454d34b71172401b8c67acd2d663a0
2022-04-01 16:22:41 +00:00
drh 659fdb4da8 Have the sqlite3_context object carry the encoding for the prepared statement
that it represents, so that sqlite3_result() and similar can set the encoding
according to the prepared statement, even if the database encoding has
changed.
dbsqlfuzz c409b10d0a6bccf78ab00f47e1d29d42ee5b3565

FossilOrigin-Name: d4e19314f564126e180e091f9135c7bc55a10442edb46fbd3a4cfad21201dfa6
2022-04-01 15:31:58 +00:00
drh 99a218282c Split out the RUN state into separate READY and RUN states.
FossilOrigin-Name: d698826b08b88e227eb83f84b3cdb19f17306b532eccfa162090abccdf3c63d8
2022-03-31 21:15:09 +00:00
drh 66181ce2b8 Rename Vdbe.iVdbeMagic to eVdbeState. Remove unnecessary states. This is
a preliminary step toward splitting RUN_STATE out into several other states.

FossilOrigin-Name: ff91191d232305d44ae6c0fbca2542a749422dc716fa1fd5d54f58c7d6052c14
2022-03-31 20:04:49 +00:00
drh c4c0ff8664 Fix harmless compiler warnings.
FossilOrigin-Name: b916087aacba53530d2bd19eef2a4fd7a253bf7fa87b49e0df17f7987d7164ae
2022-03-31 16:09:13 +00:00
drh 89cf958c00 Refinement to [3f9887d4a58cbfdb]: The SQLITE_CONSTRAINT error should only
be returned if the prepared statement came from sqlite3_prepare_v2().  The
legacy sqlite3_prepare() is documented to return only SQLITE_ERROR.

FossilOrigin-Name: f2d9262e4427ab37ba26c004fc7a4790c86c1856d695a6b4ec3e72732ea54c09
2022-03-31 11:12:56 +00:00
drh 7e62146b13 Faster and slightly smaller implementation of sqlite3Step().
FossilOrigin-Name: c6901a8c78838228f8135c9346b214e638b72086fd85367b9ff482273e62ece6
2022-03-30 17:56:27 +00:00
drh 66f58bf38d Small size reduction and performance increase in sqlite3FinishCoding().
FossilOrigin-Name: 9248ce50f57fb9c4ba67949fdf9c9567c3e626cd9dd1b41b71c602d29c77c43e
2022-03-30 17:36:40 +00:00
drh c55b62d4cb In setResultStrOrError(), if the input string pointer is NULL and hence the
value gets set to an SQL NULL, then the Mem.enc field is uninitialized.  So
do not read it.  This is a harmless OSSFuzz/ASAN found problem.

FossilOrigin-Name: 47d0b1c4cfc3d2d8f57a02079276bb70a205ffd0f18007dd39c92f813d4c87f5
2022-03-29 22:57:00 +00:00
drh 4cb32b70ed Ensure that sqlite3VdbeMemSetStr() always leaves the value in a consistent
state even if there is an error.

FossilOrigin-Name: c86ab289ec31ce9ae0abaf103a829b8d1e5ed632f493456f1f40607aeb91b41c
2022-03-29 20:50:20 +00:00
drh 555db979f6 Reverse the order of two tests to stop a harmless initialized value
warning from MSAN - reported by OSSFuzz.

FossilOrigin-Name: 800b8fdad73b67105e416b4b5c6a5c5ded7d6a43b4eacd6b67d690cab7584b0b
2022-03-29 19:19:23 +00:00
drh de9484858e Avoid unnecessary calls to balance() from sqlite3BtreeDelete().
FossilOrigin-Name: d0966d1bdd474e27cb048884d340184f0e81a4fab65eb6b74682b20630caddf8
2022-03-29 13:16:32 +00:00
drh fb92e07186 Fix the sqlite3_result_xxxxx() routines so that they all check for and
perform any necessary text encoding conversions and check for oversize
strings and BLOBs.  Thus those checks can be done where they are most
efficient and avoided in cases like OP_Function where they are more
expensive.

FossilOrigin-Name: d50b162b2f2e320af0889b931351f9443580465a933f6657fa98f437b6579277
2022-03-29 01:43:09 +00:00
drh bcedbb2781 Further size and performance optimizations for sqlite3VdbeMemSetStr().
FossilOrigin-Name: 310a3e102d8eedf92ee63ffffb48621abfb1e2736b96bd2a676d63cca0f40598
2022-03-28 18:34:40 +00:00
drh f4dd18ea36 Slightly smaller and faster sqlite3VdbeMemSetStr().
FossilOrigin-Name: 06928e745c7bcb26ec46a17989f30efe3536fd48a74c8a1cd423cc9ff6feccb5
2022-03-28 17:34:46 +00:00
drh 60a512d923 Performance increase in the loop that frees an opcode array.
FossilOrigin-Name: 4ccebb86aae178dbce905d782f04d98211f8fce9aacd71c12b8694c92a4f5c40
2022-03-28 15:06:36 +00:00
drh cea170ec96 Another small performance gain by using sqlite3DbFreeNN().
FossilOrigin-Name: daa924af987253345bdb1c71b13378681bd252521e94d01f5d4629601232c352
2022-03-28 14:56:47 +00:00
drh da3ec15f3c Use sqlite3DbFreeNN() instead of sqlite3DbFree() in a few hot spots for
better performance.

FossilOrigin-Name: b12de0ecc78a4f654c8e7b2b17cc2201688808a4f516908e9563a216677e655c
2022-03-28 14:18:03 +00:00
drh f5a8386c32 Performance optimization in the memsys5 memory allocator.
FossilOrigin-Name: 949133231f8f751aa86518d0d3f6f03d7827fec085bfef3929fa3d57369d0216
2022-03-28 13:22:54 +00:00
drh be341502db Fix the Bloom-filter optimization so that it does not use IS NULL or
IS NOT NULL constraints from the WHERE clause when operating on a LEFT JOIN.
[forum:/forumpost/031e262a89b6a9d2|Forum thread 031e262a89b6a9d2].

FossilOrigin-Name: 1a6328f2a5b4973094e5f85787145d652119822c86ec01a61f3f985c9d2903f2
2022-03-25 01:23:37 +00:00
drh 5705b41fb8 The "PRAGMA writable_schema=ON" flag should not allow OOM errors to pass
while parsing the schema.
dbsqlfuzz 9cc49e1a53e1cef8e3a1496a88c683aa20483163.

FossilOrigin-Name: a7abb725c7c783331e73837597917e25e5ff692aac8ec97a0a8c0e30db62d68b
2022-03-24 14:01:55 +00:00
drh 8ad3c43257 Use trickery to code the UTF-8 BOM for the --bom option on .output, .once,
and .excel in the CLI, to work around a warning in some Microsoft compilers.
[https://fossil-scm.org/forum/forumpost/bd0844268f0fab71|Fossil forum post bd0844268f0fab71].

FossilOrigin-Name: 43143ad131f17734fd2eff849e0a1bc2e26daf6a28c7e07d697d38732e6af5fc
2022-03-23 10:04:52 +00:00
drh 500d7e542c Ensure that database corruption does not cause the cursor passed into
sqlite3BtreeDelete() to be invalid.
dbsqlfuzz 209bf3de9ee11ae440848ab9bc9c13858f9be2e4.

FossilOrigin-Name: a85126f96614c53b030c6e6c43ff239eae458048597a10e9a0361fcec8628ecf
2022-03-22 23:33:20 +00:00
drh 56d88aad29 Harden the xShmLock method of both the unix and Windows VFSes so that they
are robust against being invoked when the SHM file is not open.

FossilOrigin-Name: 67d8b434f628d44c4a90ce8ff5ab2e381f500bb42bdbfab9a17d21925a2ec6cd
2022-03-22 19:41:55 +00:00
drh 6fad5776c0 Make the sqlite3_serialize() and sqlite3_deserialize() interfaces accessible
to loadable extensions.

FossilOrigin-Name: 81f8746bc65828fb91e170393f22f1f4e9c587a8938e8c11b72315fcd6131403
2022-03-22 11:22:55 +00:00
larrybr b5bb769c27 expose sqlite3_{deserialize,serialize}() in sqlite3ext.h
FossilOrigin-Name: da874180d35aacdeb9c06f5b425e8909d833e2765179c4337854d56b8a624fd5
2022-03-22 03:03:13 +00:00
larrybr cb0854a380 Create new branch named "extapi-serializing"
FossilOrigin-Name: a1220a2170a09075a42d1d6c4b502ffa7cc92856779b9eb2ecb9e05c09ccedac
2022-03-22 02:53:34 +00:00
drh a753a3a2be Do not allow an #ifdef inside of an assert(), as gcc tells us that is
not portable.

FossilOrigin-Name: c7a2047e93df36c172be0be773f9a04150dafe7ba1773269d74016418d262fc4
2022-03-21 20:08:13 +00:00
drh c63e40956b Some branches are no longer reachable after the previous change. Mark them
accordingly.  Also improve comments.

FossilOrigin-Name: 88d69f60cceb22bde42cfe43c23259c7bad47b8e06f918a79bd089a77b480d46
2022-03-21 18:48:31 +00:00
drh bd5fb3a888 Strengthen the defenses against corrupt databases in the
sqlite3BtreeInsert() function of the btree module.
[forum:/forumpost/c7ec29905f|Forum post c7ec29905f].

FossilOrigin-Name: 4df301c8610c4c36b4eb360d49ccaef873c63ea719ccb14b357754ff0b3ea5ef
2022-03-21 18:17:09 +00:00
drh 67aa2318c1 The previous assert() fix was not correct when building with
-DSQLITE_ENABLE_OFFSET_SQL_FUNC.  This is the fix.

FossilOrigin-Name: c0a4767fef27cfe4fdc1d8a29342998095894769a63d84e37ec47ced7ce4e5f7
2022-03-21 15:42:42 +00:00
drh 75c493f767 Fix the assert() that attempts to verify that the table-reference to
index-reference translator finds all required translations.
[forum:/forumpost/929168fdd6|Forum post 929168fdd6].

FossilOrigin-Name: fa9bd1fce47e8db1cfc4cd8efd2c09f8711ea917ce7d116dc7226c575cb9a6d4
2022-03-21 13:47:15 +00:00
drh ef07f96faf Fix an assert() in sqlite3TableAffinity() that might have been false if there
was a prior syntax error in the query.

FossilOrigin-Name: 23fdb169ca1622369cd44fd641946c37fef09071625838b3b9c86c31244ed205
2022-03-21 11:32:45 +00:00
drh 9198f5afac In the CLI, disable the zipfile and sqlar extensions in --safe mode.
FossilOrigin-Name: d8b65a2dab97392ff81bcc33ff707b4e626a10d84a258c6452e45f90cd2c7f45
2022-03-19 15:19:35 +00:00
drh d5c35f6d69 Fix the zipfile extension so that it knows that a zero-length BLOB returns
a NULL pointer.
[forum:/forumpost/ae86934905|Forum post ae86934905].

FossilOrigin-Name: 5f6d56737caefa78e542a7af2f95646e3a818e0ecdd8e838f3c2978500ce960c
2022-03-19 12:48:14 +00:00
drh 389e056bfe Change a conditional into an assert() due to the change in
[387ab17b8a0a4b87].

FossilOrigin-Name: 13b584869f40ea6aa2190dbac64709695ee8d72b27bc5afb8b39ab3763b9c46a
2022-03-17 23:49:58 +00:00
drh b45e1d674a Add a 4th output code (value 3) from the sqlite3_vtab_distinct() interface
that indicates that SQLite wants distinct results that are sorted.

FossilOrigin-Name: 135d8b97b01f9b5204f486f828c274c2d779c17723e79171ca61f738746adf8e
2022-03-17 22:09:17 +00:00
drh 494317ad57 Another fix for a corner-case in sqlite_offset() - this one having to
do with computed virtual columns in a WITHOUT ROWID table.

FossilOrigin-Name: 84ddd19bcec99f04b43b1a823477457758a2d93ea9beda43598e1234ea07776c
2022-03-17 11:23:13 +00:00
88 changed files with 11865 additions and 1285 deletions
+3
View File
@@ -1627,6 +1627,9 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
}else{
if( pRet->nPhrase>0 ){
Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1];
assert( pParse!=0 );
assert( pParse->apPhrase!=0 );
assert( pParse->nPhrase>=2 );
assert( pLast==pParse->apPhrase[pParse->nPhrase-2] );
if( pPhrase->nTerm==0 ){
fts5ExprPhraseFree(pPhrase);
+5
View File
@@ -1262,9 +1262,14 @@ static int zipfileFilter(
zipfileCursorErr(pCsr, "zipfile() function requires an argument");
return SQLITE_ERROR;
}else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
static const u8 aEmptyBlob = 0;
const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
int nBlob = sqlite3_value_bytes(argv[0]);
assert( pTab->pFirstEntry==0 );
if( aBlob==0 ){
aBlob = &aEmptyBlob;
nBlob = 0;
}
rc = zipfileLoadDirectory(pTab, aBlob, nBlob);
pCsr->pFreeEntry = pTab->pFirstEntry;
pTab->pFirstEntry = pTab->pLastEntry = 0;
+82
View File
@@ -0,0 +1,82 @@
# 2014 August 30
#
# 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]] rbu_common.tcl]
set ::testprefix rbubusy
db close
sqlite3_shutdown
test_sqlite3_log xLog
reset_db
set db_sql {
CREATE TABLE t1(a PRIMARY KEY, b, c);
INSERT INTO t1 VALUES(1000, 2000, 3000);
}
set rbu_sql {
CREATE TABLE data_t1(a, b, c, rbu_control);
INSERT INTO data_t1 VALUES(1, 2, 3, 0);
INSERT INTO data_t1 VALUES(4, 5, 6, 0);
INSERT INTO data_t1 VALUES(7, 8, 9, 0);
}
do_test 1.1 {
forcedelete rbu.db
sqlite3 rbu rbu.db
rbu eval $rbu_sql
rbu close
db eval $db_sql
} {}
do_execsql_test 1.2 {
BEGIN;
SELECT * FROM t1
} {1000 2000 3000}
do_test 1.3 {
sqlite3rbu rbu test.db rbu.db
rbu step
} {SQLITE_OK}
do_test 1.4 {
while 1 {
set rc [rbu step]
if {$rc!="SQLITE_OK"} break
}
set rc
} {SQLITE_BUSY}
do_test 1.5 {
rbu step
} {SQLITE_BUSY}
do_test 1.6 {
db eval COMMIT
rbu step
} {SQLITE_BUSY}
catch { rbu close }
do_test 1.7 {
sqlite3rbu rbu test.db rbu.db
while 1 {
set rc [rbu step]
if {$rc!="SQLITE_OK"} break
}
set rc
} {SQLITE_DONE}
rbu close
finish_test
+1 -1
View File
@@ -342,7 +342,7 @@ do_eqp_execsql_test 7.2 {
QUERY PLAN
|--SCAN xdir
|--SCAN rt VIRTUAL TABLE INDEX 2:B0D1
`--SCAN ydir
`--SCAN ydir LEFT-JOIN
} {
5 1 2 7 12 14 {}
5 2 2 7 8 12 10
+91 -85
View File
@@ -1,5 +1,5 @@
C Updates\sa\scomment\sand\san\sassert().
D 2022-03-17T18:03:08.225
C Do\snot\sallow\sthe\spush-down\soptimization\son\sthe\sright\stable\sof\sa\sRIGHT\sJOIN.
D 2022-04-25T20:47:58.298
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -117,7 +117,7 @@ F ext/fts5/fts5Int.h 36fd4a05e6e6307e3bac359a589d5f090b903afe0e7ae15db84f0ff90c7
F ext/fts5/fts5_aux.c f558e1fb9f0f86a4f7489e258c162e1f947de5ff2709087fbb465fddb7092f98
F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b729225eeaf6a5
F ext/fts5/fts5_config.c 501e7d3566bc92766b0e11c0109a7c5a6146bc41144195459af5422f6c2078aa
F ext/fts5/fts5_expr.c fcd0770d53028c2b53a15d0f53bf6d0e01b1bf3dd97630b9fedf0801f03aa3ec
F ext/fts5/fts5_expr.c 40174a64829d30cc86e8266306ad24980f6911edd5ca0b8c1ce7821ea1341b88
F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982
F ext/fts5/fts5_index.c fdfbc8a62827ec1d1b6f207a1e59c1c4986c3ce245592b5128ffe738867cfcd1
F ext/fts5/fts5_main.c 6078ae86d3b813753a4f1201054550aff21a3f660e97b30f200d2b1472874151
@@ -339,7 +339,7 @@ F ext/misc/vfsstat.c 474d08efc697b8eba300082cb1eb74a5f0f3df31ed257db1cb07e72ab0e
F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
F ext/misc/wholenumber.c a838d1bea913c514ff316c69695efbb49ea3b8cb37d22afc57f73b6b010b4546
F ext/misc/zipfile.c c4e2d12b3544a380ce171a143dc2fdfe2fc76ae424ed4cf43ba4f74c6d0db444
F ext/misc/zipfile.c 22afe121d1a5e318453b7cdbc0f5492161d2fd4fce548ff3605da05e89be7140
F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
F ext/rbu/rbu1.test c62904bd9526dcdc3496a21199aaf14ae191bbadbf67f076bf16be6b3f2115c2
@@ -358,6 +358,7 @@ F ext/rbu/rbuA.test b34a90cb495682c25b5fc03a9d5e7a4fc99541c29256f25e2e2a4f6542b4
F ext/rbu/rbuB.test 52b07158824c6927b7e25554ace92a695cdebfc296ae3d308ac386984aded9bc
F ext/rbu/rbuC.test 80f1cc2fb74f44b1128fd0ed8eedab3a76fefeb72a947860e2869ef76fc8dc6b
F ext/rbu/rbu_common.tcl 60d904133ff843fe72cc0514e9dd2486707181e6e0fbab20979da28c48d21de9
F ext/rbu/rbubusy.test 35a6ad081b374281f728b26264ef4f0b0e7888ccb5ace1843aed30ed99c2e1ca
F ext/rbu/rbucollate.test cac528a9a46318cba42e61258bb42660bbbf4fdb9a8c863de5a54ad0c658d197
F ext/rbu/rbucrash.test 000981a1fe8a6e4d9a684232f6a129e66a3ef595f5ed74655e2f9c68ffa613b4
F ext/rbu/rbucrash2.test efa143cc94228eb0266d3f1abfbee60a5838a84cef7cc3fcb8c145b74d96fd41
@@ -409,7 +410,7 @@ F ext/rtree/rtree8.test 2d99006a1386663978c9e1df167554671e4f711c419175b39f332719
F ext/rtree/rtree9.test fd3c9384ef8aabbc127b3878764070398f136eebc551cd20484b570f2cc1956a
F ext/rtree/rtreeA.test a7fd235d8194115fa2e14d300337931eb2e960fe8a46cdfb66add2206412ea41
F ext/rtree/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9
F ext/rtree/rtreeC.test c4bfa9a61c6788c03e4a9ce40ab2cfc6100982559effd9842d1b658e1d47aa5f
F ext/rtree/rtreeC.test 2978b194d09b13e106bdb0e1c5b408b9d42eb338c1082bf43c87ef43bd626147
F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc
F ext/rtree/rtreeE.test e65d3fc625da1800b412fc8785817327d43ccfec5f5973912d8c9e471928caa9
F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd450ed331
@@ -485,44 +486,44 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 006325f8844c65d885b3ba469b4c08d9dd0cd3e9ec481d5bcff621f224cb2302
F src/alter.c 9395ece9850ad57c6fbb453aeb5185be4bae3b159c4b37611425c565124ee849
F src/analyze.c 3a119baeb03053c154029877454d41bb8fd79d4d1eb583392f2289b3554a75bc
F src/attach.c f26d400f3ffe2cdca01406bca70e5f58c5488bf165b4fc37c228136dfcf1b583
F src/attach.c 4431f82f0247bf3aaf91589acafdff77d1882235c95407b36da1585c765fbbc8
F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
F src/backup.c a2891172438e385fdbe97c11c9745676bec54f518d4447090af97189fd8e52d7
F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c ddc3cec12a39675e10066c008aac7925b26c74f78c46b849b2416ca45701a313
F src/btree.c df695e953c2ce78ce4878ee5016751df9bc9a921dc0500a0f53ab3bb3196e505
F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22
F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e
F src/build.c a0cc68fe8172c0a31b54576f9c6c0fe6f7c82b1b5e1387afdd6a5a13132bc131
F src/build.c e8e776b52bc145cbf4e9fb88b99830083880fc2b174c2f96518fff15cbc72396
F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1
F src/ctime.c 026dbdcdbd8c3cde98a88483ee88310ff43150ab164ad768f12cc700a11495ad
F src/date.c 15082566229d4b1e5f24fdb490bf9bcc68824b911d70e3573ef075a1b9e2d26f
F src/dbpage.c a70be9a4879ac5392673a1050d526a72b8b2f9938df7049f65348566a2637db3
F src/dbpage.c 90661a87e1db8bfbc8d2ebbdcd3749651ddb287c555c07a28fb17c7c591ffb68
F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
F src/delete.c b5f1716b4d723db48254ee0f896e362cd029e865e05414139ea7f539f3884e1d
F src/expr.c 3cdb00b6c15f815c94836e7b4474b675155d1279e64804f6ab5816188a9b05b6
F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce
F src/expr.c 5d4178f8462ca55a38cefcfcdf9635030607e3532649c96de471afafeca732c4
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 06e4ac33031b02dde7130c12e79cddf4dc5cfa72b23d8e63a3c26878fc9c1d3c
F src/fkey.c d965ede15d8360c09ed59348940649ee647b192e784466837d7aefa836d1d91e
F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761
F src/global.c 75deb064a71e1db60c8972a660a84f4e6d805c8f0463299a18e30ea527f4a650
F src/global.c e83ee571b79ee3adc32e380cf554cf1254bc43763d23786c71721fbcdfbbb965
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c d9fd15b2bd030cb9bd3119b301dbdb2912f16fff76c6e3797296cfd1500faaf4
F src/json.c 24fcd7f5f9080b04b89722c343010d390f85e55b2ab560046cb567c9dd640f62
F src/insert.c 173845e5a6bac96ae937409e4f876b631f26b31dabb9df8fd0eb3b130b2bb3a7
F src/json.c 7749b98c62f691697c7ee536b570c744c0583cab4a89200fdd0fc2aa8cc8cbd6
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c aa919a6a7884f8b34d7b791841b24d14b1b0ab43f45b3940f4851043b2855c0c
F src/main.c 89dfd569b4fbcab65281b3c6d636b887b2cb23cbaa16f8c6b67062862144c927
F src/malloc.c fec841aa0a0400a6f7d20706178a5d8e8219a6bf562b6fe712c17f6c26813266
F src/loadext.c 2ecb1441f9b1c22e9e022ee0776e67d259facf34b56ba892b206f0a294ee6f8c
F src/main.c 135858d2ede0b83d779e71b07ede9c1d6b6eaab7b77bc2a85729584152769faf
F src/malloc.c a9127efdcef92d6934c6339ea9813075b90edc0ce2e5c723556381a3828fb720
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75
F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
F src/mem5.c 5a3dbd8ac8a6501152a4fc1fcae9b0900c2d7eb0589c4ec7456fdde15725a26c
F src/memdb.c c2dc88f97c410eb68a24468344b65526685e18354ddfd15906750c1eaf9dc2dd
F src/memjournal.c 8bd50ae6d9c6d34b3a96cc3b4f567f9935dc358444d872ab48901a8c11ad82a6
F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8
@@ -536,33 +537,33 @@ F src/os.c b1c4f2d485961e9a5b6b648c36687d25047c252222e9660b7cc25a6e1ea436ab
F src/os.h 26890f540b475598cd9881dcc68931377b8d429d3ea3e2eeb64470cde64199f8
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c f0dc85d439ece53120c4071c98876758ec24e6f713b67af3711af033c897091e
F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
F src/os_unix.c 1f71ec8c87621f75c9c5ea973f5e8ce2f1d23fe760c01ed2814fe4b98b639825
F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356
F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3
F src/parse.y 0f02b27cdaa334441463153fff3ceb780fea006ab53ffd6ef566d4468f93e924
F src/pcache.c 0aab73936341fad83d107cf62c6a7bc2d2d5fb9aaec8c3ce61e19fc18e4560fc
F src/parse.y b86d56b446afb9c203d8354dc6c422818a62b4bbab52b76ab3da06d7b1d07e44
F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65
F src/pragma.c 9047ffb003d9434810ee81d7b1722d0093821622eb3217c962c3407bad949ce2
F src/pragma.c d1aead03e8418ff586c7cfca344c50a914b8eb06abd841e8e91a982d823671da
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
F src/prepare.c a187dade741c1f09ae118fcbbf0302511807bfc0355880927d7152eb75b8260d
F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32
F src/prepare.c fd940149c691684e7c1073c3787a7170e44852b02d1275d2e30a5b58e89cfcaf
F src/printf.c 512574910a45341c8ad244bd3d4939968ebdfde215645b676fff01cc46e90757
F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
F src/resolve.c ea935b87d6fb36c78b70cdc7b28561dc8f33f2ef37048389549c7b5ef9b0ba5e
F src/resolve.c f72bb13359dd5a74d440df25f320dc2c1baff5cde4fc9f0d1bc3feba90b8932a
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c c366c05e48e836ea04f8ecefb9c1225745dc250c3f01bdb39e9cbb0dc25e3610
F src/shell.c.in ec4b952f7d9c02919e8e8394be16bcbff55c105fd080895602d10fc8fa5328b8
F src/select.c cc1a7581403fc074eee85283ba8d81de50a831ae175cb65a5751be00f621c0d5
F src/shell.c.in ae0a6fae983caac6f8c824733f0599dfdf7b3a7e8efdef3cb5e3ab2e457ffc35
F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h a95cb9ed106e3d39e2118e4dcc15a14faec3fa50d0093425083d340d9dfd96e6
F src/sqliteInt.h 2ce7d868630ccd70ffd4b15d46b59ccf7daf89198993b62ed6e4a165d3511280
F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e
F src/sqliteInt.h 11cd60560cd14bb6eecd04d244faf4c1895417b97d89e2f50833f83c4611588d
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 1f6673991147bc2cecc08a40d22f9803b84c805b24b499fe727f392256f73474
F src/test1.c 87fda59eea3ac1eba1baef37c1967565cb1b8d6d264649f2e57f252ca5989914
F src/test1.c 1356984e97bff07e4a8cc3863e892f05b3348678a74783bb6f350b76316736f1
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
@@ -616,21 +617,21 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 6661a9fa660ecbd3ac0df1acd2ec788b3a8122b4316022bcdaf476ea6754a8de
F src/treeview.c 3fac35b0835998f34bc940cb07282c5c485caa1645135435fca07ba828c48463
F src/trigger.c 5fc3cde35cc4de510be68bb2db4dcff0ce0e1625f43e28a0920be9a6f010cd3f
F src/update.c f875b0d59da5c3055a0b2ac20560e1650229c6787e78de5e9836267b5cbb8359
F src/tokenize.c a38f52058b517929e264094abd0b5fd1e8e145a1aa43bc6f6a72ae5218f96c98
F src/treeview.c 396c21e21c853ebc1830c194fa13f1161dbc76adad0b0a605172ddb78b3b4cdb
F src/trigger.c 372ada38f667c6823a3db15749eb668338e65c793394e55a37e56a489f2d1b55
F src/update.c 2cfaded82ca80ff56afb8c3ae5e88284e0824bfd86119827cc22481959f96f92
F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23
F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
F src/vdbe.c b1830c6daf744473a732257652b6431ac18032f508a3e30ff3a1466fe5978559
F src/vdbe.h a1d0e3b934e835e73edd146f2e7c4eadb711b5c9875c18159a57483fd78e550e
F src/vdbeInt.h 8dd91427155a38ec06e9ecbde07e33f21bc02e101625191e7613f883e379a363
F src/vdbeapi.c bc3812dff7c9e6497c87ae86962818a51f66f8d7a873e7ec02a22aa115b84799
F src/vdbeaux.c 33c61dc3dbe920f262371ad2ba3e10277d27d8e35ee86075e2aef74113eae251
F src/vdbe.c 9527ab7f71c5b0291e5ed7727f213f4d7f6e0a82af019da5b365fd5a0f56bb96
F src/vdbe.h 07641758ca8b4f4c6d81ea667ea167c541e6ece21f5574da11e3d21ec37e2662
F src/vdbeInt.h ef43f7fdc5fde29fc3fd29c506c12830f366178fdb4edbbf0cbc3dfbd1278b5f
F src/vdbeapi.c 354c893f1500cf524cc45c32879b9c68893a28b77e3442c24668d6afe4236217
F src/vdbeaux.c f406d8d8b461f260aeaa69d265c5d175ff0a9f84d6153c87975cdfbf9d681922
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
F src/vdbemem.c 57fceb4ed6aac960e9517c963dc0668189e8b7c8e6216d257030a2f5e9a583df
F src/vdbemem.c 7189090b72baa025f945a1ac8c61ee420c645254476e8a191d555db76dfea5d4
F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
@@ -639,16 +640,16 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
F src/where.c bea45cd6ad295044fd2682ebc9c415acc9d83771809926cb0fa20f39df3376a4
F src/whereInt.h 15d2975c3b4c193c78c26674400a840da8647fe1777ae3b026e2d15937b38a03
F src/wherecode.c 555f598a9ddad81761f084710fdb4f8733fe31bc14cd6b19f8ca4274a7eaa04c
F src/whereexpr.c 2a71f5491798460c9590317329234d332d9eb1717cba4f3403122189a75c465e
F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f
F src/where.c 43085b3a4ce2e56315fabb0b240a56e76667d9e03c79f287695bcae7b76152d5
F src/whereInt.h 4db5a877a9d1f38b5c928c1c84297c07f30b9a3bc1f5f66214cf1a8ef90a0556
F src/wherecode.c 55a33d9db1759970c30220904bcc628ba66a1ccb63b5437ef4642f7ea6267b03
F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5
F src/window.c 924e04fd6e0e113d4dba18b78d43fcb8e42b8ebffc8fc728da52cf3ab014cf3c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7
F test/affinity3.test b5c19d504dec222c0dc66642673d23dce915d35737b68e74d9f237b80493eb53
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test cc47afa5e11e0d6771a85a4993fa6ff721480ddb53ea538ec3fdbafb720bd505
F test/aggnested.test 7269d07ac879fce161cb26c8fabe65cba5715742fac8a1fccac570dcdaf28f00
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
F test/alter.test 313073774ab5c3f2ef1d3f0d03757c9d3a81284ae7e1b4a6ca34db088f886896
@@ -669,7 +670,7 @@ F test/altermalloc3.test 55e606edf4b0acfbbd851ddfe93cfdddfae43d103644dcfd6008ae4
F test/alterqf.test ff6c6f881485c29ed699b8ef4774864ca1b0c01a6c08f5cdd624a008e4b40fca
F test/altertab.test 7273b8506eab46342be016af78028df49f3bd99037412f997a8f1011b37a6912
F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0
F test/altertab3.test 5929f522fd6fd708396ad9f317d4af9ff1a93e460df85bb1d54d4499eeb94960
F test/altertab3.test 8af5c6eb4a7dd2fc73235b865b53561bf07428d1d6a9cd59a067abf51141891e
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7
F test/analyze3.test 4440c4932247adb2b4e0c838f657c19dc7af4f56859255436dc4e855f39b9324
@@ -704,10 +705,10 @@ F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
F test/autoinc.test 997d6f185f138229dc4251583a1d04816423dddc2fc034871a01aeb1d728cb39
F test/autoindex1.test fe27af92eaf884bd9c38f94be3e8afa04ec494e5eefb189902026181a6175f5e
F test/autoindex1.test cdc336e80cfd586c0e09426d58bec412db7527ca22dfabe88eab690e3acbb406
F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df
F test/autoindex3.test 2d13958a5617e987624a428d7aed91bf51f322b49b476e3573fadec697ce6da5
F test/autoindex4.test 75cb1191a552b8201351f5a50d160fcb9387a0fbbfb820c77798bfee7da3f8cf
F test/autoindex4.test 5df39313526b6f22a26bd119bbd97ca69f28386ab3c671fc10568d921c41eb08
F test/autoindex5.test 2ee94f033b87ca0160e08d81034c507aff8e230df2627f0304fa309b2fee19a3
F test/autovacuum.test 00671369bbf96c6a49989a9425f5b78b94075d6a4b031e5e00000c2c32f365df
F test/autovacuum2.test 76f7eb4fe6a6bf6d33a196a7141dba98886d2fb53a268d7feca285d5da4759d7
@@ -752,7 +753,7 @@ F test/boundary3.tcl 23361e108a125dca9c4080c2feb884fe54d69243
F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45
F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
F test/btree01.test 8e1ba2f857608ad8fbf9fcc11f33b15b083711162f9566b0a21fb573f2008593
F test/btree01.test fef17d9e999ac4f04095948e3438fbe674f4e07bb2c63bb1cad41d87baee077f
F test/btree02.test 7555a5440453d900410160a52554fe6478af4faf53098f7235f1f443d5a1d6cc
F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb7834727
@@ -777,7 +778,7 @@ F test/close.test eccbad8ecd611d974cbf47278c3d4e5874faf02d811338d5d348af42d56d64
F test/closure01.test 9905883f1b171a4638f98fc764879f154e214a306d3d8daf412a15e7f3a9b1e0
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
F test/collate1.test 71a6f27fdc93a92f14d8ab80c05e1937656a5a03197e1a10157314554d630ce8
F test/collate2.test 9aaa410a00734e48bcb27f3872617d6f69b2a621
F test/collate2.test 471c6f74573382b89b0f8b88a05256faa52f7964f9e4799e76708a3b1ece6ba4
F test/collate3.test 89defc49983ddfbf0a0555aca8c0521a676f56a5
F test/collate4.test c953715fb498b87163e3e73dd94356bff1f317bd
F test/collate5.test 65d928034d30d2d263a80f6359f7549ee1598ec6
@@ -814,7 +815,7 @@ F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af
F test/corruptL.test 7d3440831ca24ba64305583c4d4506d417d3f89f5775c0b7cc8102db078f8ff5
F test/corruptL.test 21a951d1eb09120f3c1561af5bac30ed49be2d9dfcad039f71759c5d9e28a349
F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
F test/corruptN.test 60b5a62944b4f0029ba07edaa5fd8e670539d6b0a8d99db26c068d435675cbfe
F test/cost.test b11cdbf9f11ffe8ef99c9881bf390e61fe92baf2182bad1dbe6de59a7295c576
@@ -878,7 +879,7 @@ F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5e
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
F test/e_select.test c5425a423da06d0494119db8361ebfc6de302929f7546ca596d56224137e0360
F test/e_select.test 9b7ca08975c5444844b35ee60e09f973787a9f3317719715e8e6669abdf6aba2
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
F test/e_totalchanges.test c927f7499dc3aa28b9b556b7d6d115a2f0fe41f012b128d16bf1f3b30e9b41e4
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
@@ -893,7 +894,7 @@ F test/enc.test 9a7be5479da985381d740b15f432800f65e2c87029ee57a318f42cb2eb43763a
F test/enc2.test 848bf05f15b011719f478dddb7b5e9aea35e39e457493cba4c4eef75d849a5ec
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
F test/eqp.test bfe979eb1f4b8ab7a3bd7db6d16c2e6c6be0e5a3aada2227716f3fd3a9d76b69
F test/eqp.test 473aea9599b4b7af46614b55198cd78167e4eccd48e60812a40db47c5c41dea9
F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9
F test/eval.test 73969a2d43a511bf44080c44485a8c4d796b6a4f038d19e491867081155692c0
F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650bf0747
@@ -920,7 +921,7 @@ F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
F test/fkey5.test 6727452e163a427147e84e739da18713da553d79f9783559b04fdcd36d5c7421
F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0
F test/fkey7.test 64fb28da03da5dfe3cdef5967aa7e832c2507bf7fb8f0780cacbca1f2338d031
F test/fkey8.test 48ef829d63f5f7b37aabd4df9363ac05f65539d1da8c4a44251631769d920579
F test/fkey8.test 51deda7f1a1448bca95875e4a6e1a3a75b4bd7215e924e845bd60de60e4d84bf
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958fdde5c
F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4
@@ -1008,7 +1009,7 @@ F test/fts3fault.test 798e45af84be7978ca33d5bdc94246eb44724db24174b5d8e9b1ac46c5
F test/fts3fault2.test 6a17a11d8034b1c4eca9f3091649273d56c49ff049e2173df8060f94341e9da0
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
F test/fts3fuzz001.test e3c7b0ce9b04cc02281dcc96812a277f02df03cd7dc082055d87e11eb18aaf56
F test/fts3join.test b285c919559af5b093c51abb2c07ce7ec0156dbc9573f444b78dabd9f3040db2
F test/fts3join.test ee25def5e763ea8879c19e74f862d5191410ccc7259338887a3685e97f512662
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a
F test/fts3matchinfo2.test 00144e841704b8debfcdf6097969cd9f2a1cf759e2203cda42583648f2e6bf58
@@ -1110,7 +1111,7 @@ F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407
F test/index3.test 51685f39345462b84fcf77eb8537af847fdf438cc96b05c45d6aaca4e473ade0
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
F test/index6.test 5a7ab531c692ff3b3d139ef8ea6709fab40f9c6862ed418b4976752a5481da3a
F test/index6.test 6e5b6943f6a97a34898e48c4d0d4990caf55c12c00465a43a9c33d2fd9a3a820
F test/index7.test b238344318e0b4e42126717f6554f0e7dfd0b39cecad4b736039b43e1e3b6eb3
F test/index8.test caa097735c91dbc23d8a402f5e63a2a03c83840ba3928733ed7f9a03f8a912a3
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
@@ -1140,19 +1141,24 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9
F test/join.test 25cf0ac11c3b81fedfd166f9062166bdb39dea92f5a7c16cacbf6dc1f7f67020
F test/join2.test 9bdc615841b91c97a16d68bad9508aea11fa0c6b34e5689847bcc4dac70e4990
F test/join.test e5f165dfd84fd46406ddae6614b0122c3bfa23a26ef62966442e1503c40d96aa
F test/join2.test 466b07233820f5deee66a6c3bf6e4500c8bbf7b83649e67606f5f649c07928c0
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
F test/join5.test 3d51c4ae5f1f373a03164ca3c88d438f64bed7a2c01cf69810e2ca3d0e9071c8
F test/join5.test c4df54e2e204d7f1417bfbdd21ca324b4b07415c647595cc47798eacfddc96d3
F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c
F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0
F test/join8.test 8b1cc9592aa8f623fc2878353b16c81257591908de06d2a4916f7cbe3ca75ecd
F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05
F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a
F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9e1946
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json101.test d7c84854acafaf80f883e183ac4248ea2742615086c94a61a46ad7d7382ce123
F test/json101.test 9d46b8e254c4e23306da175dd226d5c4f164db6b294bcea98e5dcd891ba48c91
F test/json102.test 327e77275f338c028faefa2da5164daf6b142a165e3015ff2a6e4251ddc6a0ac
F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
F test/json104.test a502dc01853aada95d721b3b275afbe2dc18fffdac1fea6e96fb20c13586bbb5
@@ -1357,7 +1363,7 @@ F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce
F test/schemafault.test 1936bceca55ac82c5efbcc9fc91a1933e45c8d1e1d106b9a7e56c972a5a2a51e
F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2ff09384
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
F test/select1.test 3d23f66bf9ba77570acfe2ca5f1540ece17037cc64ab1a00efec9758ac29c268
F test/select1.test 692e84cfa29c405854c69e8a4027183d64c22952866a123fabbce741a379e889
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
F test/select3.test c49fbb758903f3718e2de5aa4655eda4838131cbea24a86db908f8b6889aa68c
F test/select4.test f0684d3da3bccacbe2a1ebadf6fb49d9df6f53acb4c6ebc228a88d0d6054cc7b
@@ -1389,11 +1395,11 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test b224e0793c5f48aa3749e65d8c64b93a30731bd206f2e41e6c5f1bee1bdb16c6
F test/shell1.test f7a2ef8260aa01f20be3185118213b1ae70518fdcd2105f3e25b021b5ca800ac
F test/shell2.test 7a3a23a9f57b99453f1679b1fe8072cb30e382a622874c0c4d97695fadb0a787
F test/shell3.test a50628ab1d78d90889d9d3f32fb2c084ee15674771e96afe954aaa0accd1de3c
F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759
F test/shell5.test 0a9920d81fae28c45cd5dbd1deb809487a23c5f4b422a49f9d31c85f926d4a9c
F test/shell5.test 78a7a8516b1e7de560748881424f621321549023d3e5f7ed2e1c56497f64c06c
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae
@@ -1474,7 +1480,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl f577d040078dd4fb56ea1ccaa71f6bfd0ebf0bd0ac373304db4269b5474f9cb7
F test/tester.tcl 18448c7801d44cc5f2690f54f803da49ed994b3968f73a393cff329e55926679
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1628,7 +1634,7 @@ F test/tkt3911.test 74cd324f3ba653040cc6d94cc4857b290d12d633
F test/tkt3918.test ea78bf164e4d55cbde0d83c671ef6fbe930a0032
F test/tkt3922.test f26be40ab4fe6c00795629bd2006d96e270d9b1a
F test/tkt3929.test cdf67acf5aa936ec4ffead81db87f8a71fe40e59
F test/tkt3935.test e15261fedb9e30a4305a311da614a5d8e693c767
F test/tkt3935.test 1ffcfffc148df51c8a01d1b3efae2d6c44cbeb0af1e0c5b88f4afe9a86d4ddb6
F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
F test/tkt4018.test 18dbc6617f7a4b90e938d1bd6d26ad18daafaf08
@@ -1681,7 +1687,7 @@ F test/update.test eb7f4eb172ce270e51bb67d7867521f33a63635bb671e261bbafccaef3bd6
F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3
F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9041
F test/upfrom1.test 8cb06689e99cd707d884faa16da0e8eb26ff658bb01c47ddf72fadade666e6e1
F test/upfrom2.test 88d39cb755db5789541e645d4e2764abc697a56958f28a3f8451a0e9342bbd6b
F test/upfrom2.test 66f3ebf721b3cebd922faee5c386bf244f816d416b57c000753ff51af62328a1
F test/upfrom3.test 6130f24ebf97f5ea865e5d2a14a2d543fe5428a62e87cc60f62d875e45c1f5f0
F test/upfromfault.test 3a10075a0043f0c4fad6614b2c371f88a8ba5a4acab68b907438413865d6a8d6
F test/upsert1.test b0ae2f58680c5205b4bc1cdeed3c3d444057c506f6c44494fa3eac60731d68a2
@@ -1711,7 +1717,7 @@ F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c840
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3
F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391
F test/vtab6.test 82d5bb8fd3c0643102c1209e9ea353b168b7eb9c8db4406ab2ee2cbbdaead62c
F test/vtab6.test fa609a4af96da30beceefa3cb624abe9be38c4747ab373d98179b24027d6b798
F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
@@ -1769,7 +1775,7 @@ F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2a
F test/walvfs.test bccb3e0d235ef85e276f491d34db32c9ada1ea67be8d9f10aabe7b30319ec656
F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec
F test/wapptest.tcl 899594e25684861d5b0c0880fb012364def50ef8097041b8ddf74be5ba7fa270 x
F test/where.test f114842c1851d257a26770f2ad55119b084001c0e1b8c214f886f45152d37cd8
F test/where.test 8c6bbd0cae8feae142a7946e3484a802fa566bacf38452b1c3e48cb77321f9a4
F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6
F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
@@ -1777,7 +1783,7 @@ F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
F test/where7.test 1c1bf436bf31b913d4764a2b62ac6e98b9681e5c7ae2b562605592a56b7e946b
F test/where8.test 461ca40265ed996a6305da99bb024b0e41602bb586acf544c08f95922358e49f
F test/where9.test 1ffb75edc50a8faa6e7bd77f8221d783febb00b44b0bdb32fb48cec6e38eca95
F test/where9.test 2db942671a002621eff4f713e347bb25243295f79d8990297cd160bebcfde3f7
F test/whereA.test 9d1077b117f1b68d5f739d94f36956c36cf995eb87bb19b77b2e81af020edd20
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
@@ -1814,18 +1820,18 @@ F test/window8.tcl 5e02e41d9d9a80f597063aed1a381eb19d1d0ef677a4f0df352c5365cf23f
F test/window8.test 4ab16817414af0c904abe2ebdf88eb6c2b00058b84f9748c6174ff11fc45f1ed
F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae4836
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
F test/windowB.test b67bda5645f3226790e1a360c4225241840b84adb5aa2e69bfb0b27eef3b84d9
F test/windowB.test f2fb42b864b0cf431c956407583e9478a74c3642bdf8737fdcb6ff4a40298b07
F test/windowC.test 6fd75f5bb2f1343d34e470e36e68f0ff638d8a42f6aa7d99471261b31a0d42f2
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b
F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c
F test/windowpushd.test d8895d08870b7226f7693665bd292eb177e62ca06799184957b3ca7dc03067df
F test/with1.test 7bc5abfe4c80c0cef8a90f5a66d60b9982e8ccd7350c8eb70611323a3b8e07ba
F test/with1.test 9ad67fdeb2bbd808a5763c9060e214ea232f9b18d846ea3a59756dc38bdc3880
F test/with2.test a1df41b987198383b9b70bf5e5fda390582e46398653858dbc6ceb24253b28df
F test/with3.test ad32d13ad50661e6fa305f62a0717649c348792e7b658bf2644976227a9e0373
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
F test/with6.test 661d7e416bef6c0a2556b2c9f0c8178a5b15932bed65246abed99723a8d4e7c0
F test/with6.test c18592592b5a1c5802fd4e933d506f7b34ebbe8fdd585229793e960ae58d433f
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
F test/without_rowid1.test a5210b8770dc4736bca4e74bc96588f43025ad03ad6a80f885afd36d9890e217
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
@@ -1863,7 +1869,7 @@ F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
F tool/lemon.c 1c5a14f6044193e42864c36de48359026fa2cdcf205a43cc1a31116101e27258
F tool/lemon.c ea5c8589c7749e9bd32ba10432aeeed3c16e215de72a12ada2bc707884837149
F tool/lempar.c 57478ea48420da05faa873c6d1616321caa5464644588c97fbe8e0ea04450748
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
@@ -1872,7 +1878,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
F tool/mkctimec.tcl 3147e9dfc4ad774e94f80084789ebaada9da9b6e66ddab16438cfc07999b6047 x
F tool/mkctimec.tcl ac96a74f5e6d9dac672d5229f79c583d3357a50e7d098e473e6b2ce2f8ae1704 x
F tool/mkkeywordhash.c 35bfc41adacc4aa6ef6fca7fd0c63e0ec0534b78daf4d0cfdebe398216bbffc3
F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
@@ -1883,7 +1889,7 @@ F tool/mkshellc.tcl df5d249617f9cc94d5c48eb0401673eb3f31f383ecbc54e8a13ca3dd97e8
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
F tool/mksqlite3c.tcl 6f9e05facb51e906a1a7ef9f95274ef2ec91bf88b96732a9aed40647c605f419
F tool/mksqlite3c.tcl eee7e9d9c58abb1045f6ed74ad95ad26e8d22be29fdc431deea5267fb3fa049c
F tool/mksqlite3h.tcl 1f5e4a1dbbbc43c83cc6e74fe32c6c620502240b66c7c0f33a51378e78fc4edf
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
@@ -1945,8 +1951,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 0a922d141749cf3ef672f56449001e03f1a7e31822b66dcaf8550bb6e1b88cd3
R 4575407b1b9d18654c677ea1217fbbaa
P 10bf0e613809f71cc1a47ad40b517e2a66671212a6464e179c9d377e8b70d499
R 8764866988e0da227134244ae6ff31d7
U drh
Z deec1c56a09d8f545a4f4b9f8cb9eb99
Z bf16933ceb0da28b71dd4050f0adc6a6
# Remove this line to create a well-formed Fossil manifest.
+1 -1
View File
@@ -1 +1 @@
0c5be14aac07222b9cd2404ae485b6587f8cb2899e776bc45f1f1117bdd7e9b7
05917bfa02a7b6678c147d10fb53f55532ab15fd5d82d925ae921ae3759f0115
+9 -7
View File
@@ -858,11 +858,10 @@ static void unmapColumnIdlistNames(
Parse *pParse,
const IdList *pIdList
){
if( pIdList ){
int ii;
for(ii=0; ii<pIdList->nId; ii++){
sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName);
}
int ii;
assert( pIdList!=0 );
for(ii=0; ii<pIdList->nId; ii++){
sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName);
}
}
@@ -890,8 +889,11 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
SrcList *pSrc = p->pSrc;
for(i=0; i<pSrc->nSrc; i++){
sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
sqlite3WalkExpr(pWalker, pSrc->a[i].pOn);
unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
if( pSrc->a[i].fg.isUsing==0 ){
sqlite3WalkExpr(pWalker, pSrc->a[i].u3.pOn);
}else{
unmapColumnIdlistNames(pParse, pSrc->a[i].u3.pUsing);
}
}
}
+5 -1
View File
@@ -480,7 +480,11 @@ static int fixSelectCb(Walker *p, Select *pSelect){
pItem->fg.fromDDL = 1;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3WalkExpr(&pFix->w, pList->a[i].pOn) ) return WRC_Abort;
if( pList->a[i].fg.isUsing==0
&& sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn)
){
return WRC_Abort;
}
#endif
}
if( pSelect->pWith ){
+60 -33
View File
@@ -1657,6 +1657,8 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** fragmented bytes within the page. */
memcpy(&aData[iAddr], &aData[pc], 2);
aData[hdr+7] += (u8)x;
testcase( pc+x>maxPC );
return &aData[pc];
}else if( x+pc > maxPC ){
/* This slot extends off the end of the usable part of the page */
*pRc = SQLITE_CORRUPT_PAGE(pPg);
@@ -5967,7 +5969,7 @@ bypass_moveto_root:
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
assert( pPage->isInit );
if( pPage->leaf ){
assert( pCur->ix<pCur->pPage->nCell );
assert( pCur->ix<pCur->pPage->nCell || CORRUPT_DB );
pCur->ix = (u16)idx;
*pRes = c;
rc = SQLITE_OK;
@@ -8491,7 +8493,7 @@ static int balance_nonroot(
iOvflSpace += sz;
assert( sz<=pBt->maxLocal+23 );
assert( iOvflSpace <= (int)pBt->pageSize );
for(k=0; b.ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
for(k=0; b.ixNx[k]<=j && ALWAYS(k<NB*2); k++){}
pSrcEnd = b.apEnd[k];
if( SQLITE_WITHIN(pSrcEnd, pCell, pCell+sz) ){
rc = SQLITE_CORRUPT_BKPT;
@@ -8742,7 +8744,6 @@ static int anotherValidCursor(BtCursor *pCur){
*/
static int balance(BtCursor *pCur){
int rc = SQLITE_OK;
const int nMin = pCur->pBt->usableSize * 2 / 3;
u8 aBalanceQuickSpace[13];
u8 *pFree = 0;
@@ -8754,7 +8755,11 @@ static int balance(BtCursor *pCur){
MemPage *pPage = pCur->pPage;
if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break;
if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
if( pPage->nOverflow==0 && pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){
/* No rebalance required as long as:
** (1) There are no overflow cells
** (2) The amount of free space on the page is less than 2/3rds of
** the total usable space on the page. */
break;
}else if( (iPage = pCur->iPage)==0 ){
if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){
@@ -9007,24 +9012,6 @@ int sqlite3BtreeInsert(
assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags );
assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 );
if( pCur->eState==CURSOR_FAULT ){
assert( pCur->skipNext!=SQLITE_OK );
return pCur->skipNext;
}
assert( cursorOwnsBtShared(pCur) );
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
&& pBt->inTransaction==TRANS_WRITE
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
/* Assert that the caller has been consistent. If this cursor was opened
** expecting an index b-tree, then the caller should be inserting blob
** keys with no associated data. If the cursor was opened expecting an
** intkey table, the caller should be inserting integer keys with a
** blob of associated data. */
assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) );
/* Save the positions of any other cursors open on this table.
**
** In some cases, the call to btreeMoveto() below is a no-op. For
@@ -9049,6 +9036,29 @@ int sqlite3BtreeInsert(
}
}
/* Ensure that the cursor is not in the CURSOR_FAULT state and that it
** points to a valid cell.
*/
if( pCur->eState>=CURSOR_REQUIRESEEK ){
testcase( pCur->eState==CURSOR_REQUIRESEEK );
testcase( pCur->eState==CURSOR_FAULT );
rc = moveToRoot(pCur);
if( rc && rc!=SQLITE_EMPTY ) return rc;
}
assert( cursorOwnsBtShared(pCur) );
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
&& pBt->inTransaction==TRANS_WRITE
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
/* Assert that the caller has been consistent. If this cursor was opened
** expecting an index b-tree, then the caller should be inserting blob
** keys with no associated data. If the cursor was opened expecting an
** intkey table, the caller should be inserting integer keys with a
** blob of associated data. */
assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) );
if( pCur->pKeyInfo==0 ){
assert( pX->pKey==0 );
/* If this is an insert into a table b-tree, invalidate any incrblob
@@ -9137,14 +9147,14 @@ int sqlite3BtreeInsert(
}
}
assert( pCur->eState==CURSOR_VALID
|| (pCur->eState==CURSOR_INVALID && loc)
|| CORRUPT_DB );
|| (pCur->eState==CURSOR_INVALID && loc) );
pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
assert( pPage->leaf || !pPage->intKey );
if( pPage->nFree<0 ){
if( pCur->eState>CURSOR_INVALID ){
if( NEVER(pCur->eState>CURSOR_INVALID) ){
/* ^^^^^--- due to the moveToRoot() call above */
rc = SQLITE_CORRUPT_BKPT;
}else{
rc = btreeComputeFreeSpace(pPage);
@@ -9306,7 +9316,11 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
u32 nRem; /* Bytes of data still to copy */
getCellInfo(pSrc);
aOut += putVarint32(aOut, pSrc->info.nPayload);
if( pSrc->info.nPayload<0x80 ){
*(aOut++) = pSrc->info.nPayload;
}else{
aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload);
}
if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey);
nIn = pSrc->info.nLocal;
aIn = pSrc->info.pPayload;
@@ -9425,12 +9439,16 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
if( pCur->eState==CURSOR_REQUIRESEEK ){
rc = btreeRestoreCursorPosition(pCur);
assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID );
if( rc || pCur->eState!=CURSOR_VALID ) return rc;
if( pCur->eState!=CURSOR_VALID ){
if( pCur->eState>=CURSOR_REQUIRESEEK ){
rc = btreeRestoreCursorPosition(pCur);
assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID );
if( rc || pCur->eState!=CURSOR_VALID ) return rc;
}else{
return SQLITE_CORRUPT_BKPT;
}
}
assert( CORRUPT_DB || pCur->eState==CURSOR_VALID );
assert( pCur->eState==CURSOR_VALID );
iCellDepth = pCur->iPage;
iCellIdx = pCur->ix;
@@ -9462,7 +9480,8 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
bPreserve = (flags & BTREE_SAVEPOSITION)!=0;
if( bPreserve ){
if( !pPage->leaf
|| (pPage->nFree+pPage->xCellSize(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
|| (pPage->nFree+pPage->xCellSize(pPage,pCell)+2) >
(int)(pBt->usableSize*2/3)
|| pPage->nCell==1 /* See dbfuzz001.test for a test case */
){
/* A b-tree rebalance will be required after deleting this entry.
@@ -9558,7 +9577,15 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** been corrected, so be it. Otherwise, after balancing the leaf node,
** walk the cursor up the tree to the internal node and balance it as
** well. */
rc = balance(pCur);
assert( pCur->pPage->nOverflow==0 );
assert( pCur->pPage->nFree>=0 );
if( pCur->pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){
/* Optimization: If the free space is less than 2/3rds of the page,
** then balance() will always be a no-op. No need to invoke it. */
rc = SQLITE_OK;
}else{
rc = balance(pCur);
}
if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
releasePageNotNull(pCur->pPage);
pCur->iPage--;
+74 -41
View File
@@ -172,9 +172,7 @@ void sqlite3FinishCoding(Parse *pParse){
int i;
int reg;
if( NEVER(pReturning->nRetCol==0) ){
assert( CORRUPT_DB );
}else{
if( pReturning->nRetCol ){
sqlite3VdbeAddOp0(v, OP_FkCheck);
addrRewind =
sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur);
@@ -214,7 +212,9 @@ void sqlite3FinishCoding(Parse *pParse){
int iDb, i;
assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
sqlite3VdbeJumpHere(v, 0);
for(iDb=0; iDb<db->nDb; iDb++){
assert( db->nDb>0 );
iDb = 0;
do{
Schema *pSchema;
if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
sqlite3VdbeUsesBtree(v, iDb);
@@ -229,7 +229,7 @@ void sqlite3FinishCoding(Parse *pParse){
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
VdbeComment((v,
"usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
}
}while( ++iDb<db->nDb );
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=0; i<pParse->nVtabLock; i++){
char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
@@ -268,9 +268,7 @@ void sqlite3FinishCoding(Parse *pParse){
if( pParse->bReturning ){
Returning *pRet = pParse->u1.pReturning;
if( NEVER(pRet->nRetCol==0) ){
assert( CORRUPT_DB );
}else{
if( pRet->nRetCol ){
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
}
}
@@ -3057,7 +3055,6 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
Table *pSelTab; /* A fake table from which we get the result set */
Select *pSel; /* Copy of the SELECT that implements the view */
int nErr = 0; /* Number of errors encountered */
int n; /* Temporarily holds the number of cursors assigned */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
#ifndef SQLITE_OMIT_VIRTUALTABLE
int rc;
@@ -3115,8 +3112,9 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pSel = sqlite3SelectDup(db, pTable->u.view.pSelect, 0);
if( pSel ){
u8 eParseMode = pParse->eParseMode;
int nTab = pParse->nTab;
int nSelect = pParse->nSelect;
pParse->eParseMode = PARSE_MODE_NORMAL;
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
DisableLookaside;
@@ -3128,7 +3126,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#else
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
#endif
pParse->nTab = n;
pParse->nTab = nTab;
pParse->nSelect = nSelect;
if( pSelTab==0 ){
pTable->nCol = 0;
nErr++;
@@ -4670,18 +4669,17 @@ IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
if( pList==0 ){
pList = sqlite3DbMallocZero(db, sizeof(IdList) );
if( pList==0 ) return 0;
}else{
IdList *pNew;
pNew = sqlite3DbRealloc(db, pList,
sizeof(IdList) + pList->nId*sizeof(pList->a));
if( pNew==0 ){
sqlite3IdListDelete(db, pList);
return 0;
}
pList = pNew;
}
pList->a = sqlite3ArrayAllocate(
db,
pList->a,
sizeof(pList->a[0]),
&pList->nId,
&i
);
if( i<0 ){
sqlite3IdListDelete(db, pList);
return 0;
}
i = pList->nId++;
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
if( IN_RENAME_OBJECT && pList->a[i].zName ){
sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken);
@@ -4695,10 +4693,10 @@ IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
int i;
if( pList==0 ) return;
assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
for(i=0; i<pList->nId; i++){
sqlite3DbFree(db, pList->a[i].zName);
}
sqlite3DbFree(db, pList->a);
sqlite3DbFreeNN(db, pList);
}
@@ -4708,7 +4706,7 @@ void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
*/
int sqlite3IdListIndex(IdList *pList, const char *zName){
int i;
if( pList==0 ) return -1;
assert( pList!=0 );
for(i=0; i<pList->nId; i++){
if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i;
}
@@ -4911,8 +4909,11 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
sqlite3DeleteTable(db, pItem->pTab);
if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
if( pItem->pOn ) sqlite3ExprDelete(db, pItem->pOn);
if( pItem->pUsing ) sqlite3IdListDelete(db, pItem->pUsing);
if( pItem->fg.isUsing ){
sqlite3IdListDelete(db, pItem->u3.pUsing);
}else if( pItem->u3.pOn ){
sqlite3ExprDelete(db, pItem->u3.pOn);
}
}
sqlite3DbFreeNN(db, pList);
}
@@ -4940,14 +4941,13 @@ SrcList *sqlite3SrcListAppendFromTerm(
Token *pDatabase, /* Name of the database containing pTable */
Token *pAlias, /* The right-hand side of the AS subexpression */
Select *pSubquery, /* A subquery used in place of a table name */
Expr *pOn, /* The ON clause of a join */
IdList *pUsing /* The USING clause of a join */
OnOrUsing *pOnUsing /* Either the ON clause or the USING clause */
){
SrcItem *pItem;
sqlite3 *db = pParse->db;
if( !p && (pOn || pUsing) ){
if( !p && pOnUsing!=0 && (pOnUsing->pOn || pOnUsing->pUsing) ){
sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s",
(pOn ? "ON" : "USING")
(pOnUsing->pOn ? "ON" : "USING")
);
goto append_from_error;
}
@@ -4967,15 +4967,27 @@ SrcList *sqlite3SrcListAppendFromTerm(
if( pAlias->n ){
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
}
pItem->pSelect = pSubquery;
pItem->pOn = pOn;
pItem->pUsing = pUsing;
if( pSubquery ){
pItem->pSelect = pSubquery;
if( pSubquery->selFlags & SF_NestedFrom ){
pItem->fg.isNestedFrom = 1;
}
}
assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
assert( pItem->fg.isUsing==0 );
if( pOnUsing==0 ){
pItem->u3.pOn = 0;
}else if( pOnUsing->pUsing ){
pItem->fg.isUsing = 1;
pItem->u3.pUsing = pOnUsing->pUsing;
}else{
pItem->u3.pOn = pOnUsing->pOn;
}
return p;
append_from_error:
assert( p==0 );
sqlite3ExprDelete(db, pOn);
sqlite3IdListDelete(db, pUsing);
sqlite3ClearOnOrUsing(db, pOnUsing);
sqlite3SelectDelete(db, pSubquery);
return 0;
}
@@ -5020,6 +5032,7 @@ SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){
p1 = pNew;
memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem));
sqlite3DbFree(pParse->db, p2);
p1->a[0].fg.jointype |= (JT_LTORJ & p1->a[1].fg.jointype);
}
}
return p1;
@@ -5056,14 +5069,34 @@ void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){
** The operator is "natural cross join". The A and B operands are stored
** in p->a[0] and p->a[1], respectively. The parser initially stores the
** operator with A. This routine shifts that operator over to B.
**
** Additional changes:
**
** * All tables to the left of the right-most RIGHT JOIN are tagged with
** JT_LTORJ (mnemonic: Left Table Of Right Join) so that the
** code generator can easily tell that the table is part of
** the left operand of at least one RIGHT JOIN.
*/
void sqlite3SrcListShiftJoinType(SrcList *p){
if( p ){
int i;
for(i=p->nSrc-1; i>0; i--){
p->a[i].fg.jointype = p->a[i-1].fg.jointype;
}
void sqlite3SrcListShiftJoinType(Parse *pParse, SrcList *p){
(void)pParse;
if( p && p->nSrc>1 ){
int i = p->nSrc-1;
u8 allFlags = 0;
do{
allFlags |= p->a[i].fg.jointype = p->a[i-1].fg.jointype;
}while( (--i)>0 );
p->a[0].fg.jointype = 0;
/* All terms to the left of a RIGHT JOIN should be tagged with the
** JT_LTORJ flags */
if( allFlags & JT_RIGHT ){
for(i=p->nSrc-1; ALWAYS(i>0) && (p->a[i].fg.jointype&JT_RIGHT)==0; i--){}
i--;
assert( i>=0 );
do{
p->a[i].fg.jointype |= JT_LTORJ;
}while( (--i)>=0 );
}
}
}
+3 -3
View File
@@ -307,9 +307,6 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_ENABLE_RTREE
"ENABLE_RTREE",
#endif
#ifdef SQLITE_ENABLE_SELECTTRACE
"ENABLE_SELECTTRACE",
#endif
#ifdef SQLITE_ENABLE_SESSION
"ENABLE_SESSION",
#endif
@@ -331,6 +328,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
"ENABLE_STMT_SCANSTATUS",
#endif
#ifdef SQLITE_ENABLE_TREETRACE
"ENABLE_TREETRACE",
#endif
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
"ENABLE_UNKNOWN_SQL_FUNCTION",
#endif
+1 -1
View File
@@ -156,7 +156,7 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
){
pIdxInfo->orderByConsumed = 1;
}
sqlite3VtabWriteAll(pIdxInfo);
sqlite3VtabUsesAllSchemas(pIdxInfo);
return SQLITE_OK;
}
+10 -3
View File
@@ -128,8 +128,8 @@ void sqlite3MaterializeView(
assert( pFrom->nSrc==1 );
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
assert( pFrom->a[0].pOn==0 );
assert( pFrom->a[0].pUsing==0 );
assert( pFrom->a[0].fg.isUsing==0 );
assert( pFrom->a[0].u3.pOn==0 );
}
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
SF_IncludeHidden, pLimit);
@@ -300,7 +300,6 @@ void sqlite3DeleteFrom(
assert( db->mallocFailed==0 );
assert( pTabList->nSrc==1 );
/* Locate the table which we want to delete. This table has to be
** put in an SrcList structure because some of the subroutines we
** will be calling are designed to work with multiple tables and expect
@@ -325,6 +324,14 @@ void sqlite3DeleteFrom(
# define isView 0
#endif
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x10000 ){
sqlite3TreeViewLine(0, "In sqlite3Delete() at %s:%d", __FILE__, __LINE__);
sqlite3TreeViewDelete(pParse->pWith, pTabList, pWhere,
pOrderBy, pLimit, pTrigger);
}
#endif
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
if( !isView ){
pWhere = sqlite3LimitWhere(
+77 -26
View File
@@ -1249,6 +1249,18 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
if( p ) sqlite3ExprDeleteNN(db, p);
}
/*
** Clear both elements of an OnOrUsing object
*/
void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
if( p==0 ){
/* Nothing to clear */
}else if( p->pOn ){
sqlite3ExprDeleteNN(db, p->pOn);
}else if( p->pUsing ){
sqlite3IdListDelete(db, p->pUsing);
}
}
/*
** Arrange to cause pExpr to be deleted when the pParse is deleted.
@@ -1515,6 +1527,7 @@ With *sqlite3WithDup(sqlite3 *db, With *p){
pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0);
pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0);
pRet->a[i].zName = sqlite3DbStrDup(db, p->a[i].zName);
pRet->a[i].eM10d = p->a[i].eM10d;
}
}
}
@@ -1619,6 +1632,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){
pItem->eEName = pOldItem->eEName;
pItem->done = 0;
pItem->bNulls = pOldItem->bNulls;
pItem->bUsed = pOldItem->bUsed;
pItem->bSorterRef = pOldItem->bSorterRef;
pItem->u = pOldItem->u;
}
@@ -1671,8 +1685,12 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
pTab->nTabRef++;
}
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
if( pOldItem->fg.isUsing ){
assert( pNewItem->fg.isUsing );
pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
}else{
pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags);
}
pNewItem->colUsed = pOldItem->colUsed;
}
return pNew;
@@ -1682,22 +1700,16 @@ IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){
int i;
assert( db!=0 );
if( p==0 ) return 0;
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
assert( p->eU4!=EU4_EXPR );
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) );
if( pNew==0 ) return 0;
pNew->nId = p->nId;
pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ){
sqlite3DbFreeNN(db, pNew);
return 0;
}
/* Note that because the size of the allocation for p->a[] is not
** necessarily a power of two, sqlite3IdListAppend() may not be called
** on the duplicate created by this function. */
pNew->eU4 = p->eU4;
for(i=0; i<p->nId; i++){
struct IdList_item *pNewItem = &pNew->a[i];
struct IdList_item *pOldItem = &p->a[i];
const struct IdList_item *pOldItem = &p->a[i];
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->idx = pOldItem->idx;
pNewItem->u4 = pOldItem->u4;
}
return pNew;
}
@@ -2163,7 +2175,7 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
/* If pWalker->eCode is 2 then any term of the expression that comes from
** the ON or USING clauses of a left join disqualifies the expression
** the ON or USING clauses of an outer join disqualifies the expression
** from being considered constant. */
if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
pWalker->eCode = 0;
@@ -2284,6 +2296,42 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
return exprIsConst(p, 3, iCur);
}
/*
** Check pExpr to see if it is an invariant constraint on data source pSrc.
** This is an optimization. False negatives will perhaps cause slower
** queries, but false positives will yield incorrect answers. So when in
** double, return 0.
**
** To be an invariant constraint, the following must be true:
**
** (1) pExpr cannot refer to any table other than pSrc->iCursor.
**
** (2) pExpr cannot use subqueries or non-deterministic functions.
**
** (3) pSrc cannot be part of the left operand for a RIGHT JOIN.
** (Is there some way to relax this constraint?)
**
** (4) If pSrc is the right operand of a LEFT JOIN, then...
** (4a) pExpr must come from an ON clause..
(4b) and specifically the ON clause associated with the LEFT JOIN.
**
** (5) If pSrc is not the right operand of a LEFT JOIN or the left
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
** clause, not an ON clause.
*/
int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
if( pSrc->fg.jointype & JT_LTORJ ){
return 0; /* rule (3) */
}
if( pSrc->fg.jointype & JT_LEFT ){
if( !ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (4a) */
if( pExpr->w.iJoin!=pSrc->iCursor ) return 0; /* rule (4b) */
}else{
if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (5) */
}
return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
}
/*
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
@@ -3165,9 +3213,9 @@ void sqlite3CodeRhsOfIN(
assert( ExprUseYSub(pExpr) );
assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|| pParse->nErr );
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn, 0,
pExpr->y.sub.iAddr-1);
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
pExpr->y.sub.iAddr, 1);
VdbeCoverage(v);
sqlite3ClearTempRegCache(pParse);
}
}
@@ -3296,9 +3344,9 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
assert( ExprUseYSub(pExpr) );
assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|| pParse->nErr );
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn, 0,
pExpr->y.sub.iAddr-1);
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
pExpr->y.sub.iAddr, 1);
VdbeCoverage(v);
sqlite3ClearTempRegCache(pParse);
return rReg;
}
@@ -3732,6 +3780,7 @@ void sqlite3ExprCodeGetColumnOfTable(
}
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
VdbeComment((v, "%s.rowid", pTab->zName));
}else{
int op;
int x;
@@ -4484,16 +4533,18 @@ expr_code_doover:
}
case TK_SELECT_COLUMN: {
int n;
if( pExpr->pLeft->iTable==0 ){
pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft);
Expr *pLeft = pExpr->pLeft;
if( pLeft->iTable==0 || pParse->withinRJSubrtn > pLeft->op2 ){
pLeft->iTable = sqlite3CodeSubselect(pParse, pLeft);
pLeft->op2 = pParse->withinRJSubrtn;
}
assert( pExpr->pLeft->op==TK_SELECT || pExpr->pLeft->op==TK_ERROR );
n = sqlite3ExprVectorSize(pExpr->pLeft);
assert( pLeft->op==TK_SELECT || pLeft->op==TK_ERROR );
n = sqlite3ExprVectorSize(pLeft);
if( pExpr->iTable!=n ){
sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
pExpr->iTable, n);
}
return pExpr->pLeft->iTable + pExpr->iColumn;
return pLeft->iTable + pExpr->iColumn;
}
case TK_IN: {
int destIfFalse = sqlite3VdbeMakeLabel(pParse);
@@ -5801,7 +5852,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
** in an incorrect answer.
**
** Terms of p that are marked with EP_FromJoin (and hence that come from
** the ON or USING clauses of LEFT JOINS) are excluded from the analysis.
** the ON or USING clauses of OUTER JOINS) are excluded from the analysis.
**
** This routine is used to check if a LEFT JOIN can be converted into
** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE
+13 -14
View File
@@ -390,7 +390,6 @@ static void fkLookupParent(
}else{
int nCol = pFKey->nCol;
int regTemp = sqlite3GetTempRange(pParse, nCol);
int regRec = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
@@ -429,12 +428,11 @@ static void fkLookupParent(
}
sqlite3VdbeGoto(v, iOk);
}
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec,
sqlite3VdbeAddOp4(v, OP_Affinity, regTemp, nCol, 0,
sqlite3IndexAffinityStr(pParse->db,pIdx), nCol);
sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, regRec);
sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regTemp, nCol);
VdbeCoverage(v);
sqlite3ReleaseTempRange(pParse, regTemp, nCol);
}
}
@@ -536,14 +534,10 @@ static Expr *exprTableColumn(
** Operation | FK type | Action taken
** --------------------------------------------------------------------------
** DELETE immediate Increment the "immediate constraint counter".
** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
** throw a "FOREIGN KEY constraint failed" exception.
**
** INSERT immediate Decrement the "immediate constraint counter".
**
** DELETE deferred Increment the "deferred constraint counter".
** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
** throw a "FOREIGN KEY constraint failed" exception.
**
** INSERT deferred Decrement the "deferred constraint counter".
**
@@ -1191,9 +1185,9 @@ int sqlite3FkRequired(
**
** It returns a pointer to a Trigger structure containing a trigger
** equivalent to the ON UPDATE or ON DELETE action specified by pFKey.
** If the action is "NO ACTION" or "RESTRICT", then a NULL pointer is
** returned (these actions require no special handling by the triggers
** sub-system, code for them is created by fkScanChildren()).
** If the action is "NO ACTION" then a NULL pointer is returned (these actions
** require no special handling by the triggers sub-system, code for them is
** created by fkScanChildren()).
**
** For example, if pFKey is the foreign key and pTab is table "p" in
** the following schema:
@@ -1322,18 +1316,23 @@ static Trigger *fkActionTrigger(
nFrom = sqlite3Strlen30(zFrom);
if( action==OE_Restrict ){
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
Token tFrom;
Token tDb;
Expr *pRaise;
tFrom.z = zFrom;
tFrom.n = nFrom;
tDb.z = db->aDb[iDb].zDbSName;
tDb.n = sqlite3Strlen30(tDb.z);
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
if( pRaise ){
pRaise->affExpr = OE_Abort;
}
pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise),
sqlite3SrcListAppend(pParse, 0, &tFrom, 0),
sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
pWhere,
0, 0, 0, 0, 0
);
+1 -1
View File
@@ -347,7 +347,7 @@ int sqlite3PendingByte = 0x40000000;
/*
** Tracing flags set by SQLITE_TESTCTRL_TRACEFLAGS.
*/
u32 sqlite3SelectTrace = 0;
u32 sqlite3TreeTrace = 0;
u32 sqlite3WhereTrace = 0;
#include "opcodes.h"
+15 -4
View File
@@ -181,7 +181,7 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
}
for(i=j=0; i<pTab->nCol; i++){
assert( pTab->aCol[i].affinity!=0 );
assert( pTab->aCol[i].affinity!=0 || sqlite3VdbeParser(v)->nErr>0 );
if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
zColAff[j++] = pTab->aCol[i].affinity;
}
@@ -765,6 +765,14 @@ void sqlite3Insert(
#endif
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x10000 ){
sqlite3TreeViewLine(0, "In sqlite3Insert() at %s:%d", __FILE__, __LINE__);
sqlite3TreeViewInsert(pParse->pWith, pTabList, pColumn, pSelect, pList,
onError, pUpsert, pTrigger);
}
#endif
/* If pTab is really a view, make sure it has been initialized.
** ViewGetColumnNames() is a no-op if pTab is not a view.
*/
@@ -843,13 +851,15 @@ void sqlite3Insert(
*/
bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
if( pColumn ){
assert( pColumn->eU4!=EU4_EXPR );
pColumn->eU4 = EU4_IDX;
for(i=0; i<pColumn->nId; i++){
pColumn->a[i].idx = -1;
pColumn->a[i].u4.idx = -1;
}
for(i=0; i<pColumn->nId; i++){
for(j=0; j<pTab->nCol; j++){
if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){
pColumn->a[i].idx = j;
pColumn->a[i].u4.idx = j;
if( i!=j ) bIdListInOrder = 0;
if( j==pTab->iPKey ){
ipkColumn = i; assert( !withoutRowid );
@@ -1151,7 +1161,8 @@ void sqlite3Insert(
}
}
if( pColumn ){
for(j=0; j<pColumn->nId && pColumn->a[j].idx!=i; j++){}
assert( pColumn->eU4==EU4_IDX );
for(j=0; j<pColumn->nId && pColumn->a[j].u4.idx!=i; j++){}
if( j>=pColumn->nId ){
/* A column not named in the insert column list gets its
** default value */
+34 -10
View File
@@ -1119,14 +1119,15 @@ static JsonNode *jsonLookupStep(
*pzErr = zPath;
return 0;
}
testcase( nKey==0 );
}else{
zKey = zPath;
for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
nKey = i;
}
if( nKey==0 ){
*pzErr = zPath;
return 0;
if( nKey==0 ){
*pzErr = zPath;
return 0;
}
}
j = 1;
for(;;){
@@ -2274,6 +2275,33 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
return SQLITE_OK;
}
/* Append an object label to the JSON Path being constructed
** in pStr.
*/
static void jsonAppendObjectPathElement(
JsonString *pStr,
JsonNode *pNode
){
int jj, nn;
const char *z;
assert( pNode->eType==JSON_STRING );
assert( pNode->jnFlags & JNODE_LABEL );
assert( pNode->eU==1 );
z = pNode->u.zJContent;
nn = pNode->n;
assert( nn>=2 );
assert( z[0]=='"' );
assert( z[nn-1]=='"' );
if( nn>2 && sqlite3Isalpha(z[1]) ){
for(jj=2; jj<nn-1 && sqlite3Isalnum(z[jj]); jj++){}
if( jj==nn-1 ){
z++;
nn -= 2;
}
}
jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
}
/* Append the name of the path for element i to pStr
*/
static void jsonEachComputePath(
@@ -2298,10 +2326,7 @@ static void jsonEachComputePath(
}else{
assert( pUp->eType==JSON_OBJECT );
if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
assert( pNode->eType==JSON_STRING );
assert( pNode->jnFlags & JNODE_LABEL );
assert( pNode->eU==1 );
jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1);
jsonAppendObjectPathElement(pStr, pNode);
}
}
@@ -2372,8 +2397,7 @@ static int jsonEachColumn(
if( p->eType==JSON_ARRAY ){
jsonPrintf(30, &x, "[%d]", p->iRowid);
}else if( p->eType==JSON_OBJECT ){
assert( pThis->eU==1 );
jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
jsonAppendObjectPathElement(&x, pThis);
}
}
jsonResult(&x);
+9 -1
View File
@@ -491,7 +491,15 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_vtab_distinct,
sqlite3_vtab_in,
sqlite3_vtab_in_first,
sqlite3_vtab_in_next
sqlite3_vtab_in_next,
/* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
sqlite3_deserialize,
sqlite3_serialize
#else
0,
0
#endif
};
/* True if x is the directory separator character
+25 -6
View File
@@ -4097,6 +4097,25 @@ int sqlite3_test_control(int op, ...){
volatile int x = 0;
assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 );
rc = x;
#if defined(SQLITE_DEBUG)
/* Invoke these debugging routines so that the compiler does not
** issue "defined but not used" warnings. */
if( x==9999 ){
sqlite3ShowExpr(0);
sqlite3ShowExpr(0);
sqlite3ShowExprList(0);
sqlite3ShowIdList(0);
sqlite3ShowSrcList(0);
sqlite3ShowWith(0);
sqlite3ShowUpsert(0);
sqlite3ShowTriggerStep(0);
sqlite3ShowTriggerStepList(0);
sqlite3ShowTrigger(0);
sqlite3ShowTriggerList(0);
sqlite3ShowWindow(0);
sqlite3ShowWinFunc(0);
}
#endif
break;
}
@@ -4358,8 +4377,8 @@ int sqlite3_test_control(int op, ...){
**
** "ptr" is a pointer to a u32.
**
** op==0 Store the current sqlite3SelectTrace in *ptr
** op==1 Set sqlite3SelectTrace to the value *ptr
** op==0 Store the current sqlite3TreeTrace in *ptr
** op==1 Set sqlite3TreeTrace to the value *ptr
** op==3 Store the current sqlite3WhereTrace in *ptr
** op==3 Set sqlite3WhereTrace to the value *ptr
*/
@@ -4367,10 +4386,10 @@ int sqlite3_test_control(int op, ...){
int opTrace = va_arg(ap, int);
u32 *ptr = va_arg(ap, u32*);
switch( opTrace ){
case 0: *ptr = sqlite3SelectTrace; break;
case 1: sqlite3SelectTrace = *ptr; break;
case 2: *ptr = sqlite3WhereTrace; break;
case 3: sqlite3WhereTrace = *ptr; break;
case 0: *ptr = sqlite3TreeTrace; break;
case 1: sqlite3TreeTrace = *ptr; break;
case 2: *ptr = sqlite3WhereTrace; break;
case 3: sqlite3WhereTrace = *ptr; break;
}
break;
}
+2 -1
View File
@@ -750,8 +750,9 @@ char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
** Free any prior content in *pz and replace it with a copy of zNew.
*/
void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
char *z = sqlite3DbStrDup(db, zNew);
sqlite3DbFree(db, *pz);
*pz = sqlite3DbStrDup(db, zNew);
*pz = z;
}
/*
+7 -2
View File
@@ -420,8 +420,13 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
*/
static int memsys5Roundup(int n){
int iFullSz;
if( n > 0x40000000 ) return 0;
for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2);
if( n<=mem5.szAtom*2 ){
if( n<=mem5.szAtom ) return mem5.szAtom;
return mem5.szAtom*2;
}
if( n>0x40000000 ) return 0;
for(iFullSz=mem5.szAtom*8; iFullSz<n; iFullSz *= 4);
if( (iFullSz/2)>=n ) return iFullSz/2;
return iFullSz;
}
+9 -3
View File
@@ -4910,11 +4910,17 @@ static int unixShmLock(
int flags /* What to do with the lock */
){
unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */
unixShm *p = pDbFd->pShm; /* The shared memory being locked */
unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */
unixShm *p; /* The shared memory being locked */
unixShmNode *pShmNode; /* The underlying file iNode */
int rc = SQLITE_OK; /* Result code */
u16 mask; /* Mask of locks to take or release */
int *aLock = pShmNode->aLock;
int *aLock;
p = pDbFd->pShm;
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
pShmNode = p->pShmNode;
if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
aLock = pShmNode->aLock;
assert( pShmNode==pDbFd->pInode->pShmNode );
assert( pShmNode->pInode==pDbFd->pInode );
+5 -1
View File
@@ -4070,10 +4070,14 @@ static int winShmLock(
winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
winShm *p = pDbFd->pShm; /* The shared memory being locked */
winShm *pX; /* For looping over all siblings */
winShmNode *pShmNode = p->pShmNode;
winShmNode *pShmNode;
int rc = SQLITE_OK; /* Result code */
u16 mask; /* Mask of locks to take or release */
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
pShmNode = p->pShmNode;
if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
assert( n>=1 );
assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
+30 -31
View File
@@ -570,7 +570,7 @@ selectnowith(A) ::= selectnowith(A) multiselect_op(Y) oneselect(Z). {
Token x;
x.n = 0;
parserDoubleLinkSelect(pParse, pRhs);
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0);
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
}
if( pRhs ){
@@ -685,7 +685,7 @@ as(X) ::= . {X.n = 0; X.z = 0;}
from(A) ::= . {A = 0;}
from(A) ::= FROM seltablist(X). {
A = X;
sqlite3SrcListShiftJoinType(A);
sqlite3SrcListShiftJoinType(pParse,A);
}
// "seltablist" is a "Select Table List" - the content of the FROM clause
@@ -695,33 +695,35 @@ stl_prefix(A) ::= seltablist(A) joinop(Y). {
if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y;
}
stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_opt(I)
on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U);
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) on_using(N). {
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N);
}
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_by(I) on_using(N). {
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N);
sqlite3SrcListIndexedBy(pParse, A, &I);
}
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U);
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N). {
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N);
sqlite3SrcListFuncArgs(pParse, A, E);
}
%ifndef SQLITE_OMIT_SUBQUERY
seltablist(A) ::= stl_prefix(A) LP select(S) RP
as(Z) on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,N,U);
seltablist(A) ::= stl_prefix(A) LP select(S) RP as(Z) on_using(N). {
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,&N);
}
seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP
as(Z) on_opt(N) using_opt(U). {
if( A==0 && Z.n==0 && N==0 && U==0 ){
seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP as(Z) on_using(N). {
if( A==0 && Z.n==0 && N.pOn==0 && N.pUsing==0 ){
A = F;
}else if( F->nSrc==1 ){
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,N,U);
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,&N);
if( A ){
SrcItem *pNew = &A->a[A->nSrc-1];
SrcItem *pOld = F->a;
pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase;
pNew->pSelect = pOld->pSelect;
if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){
pNew->fg.isNestedFrom = 1;
}
if( pOld->fg.isTabFunc ){
pNew->u1.pFuncArg = pOld->u1.pFuncArg;
pOld->u1.pFuncArg = 0;
@@ -734,9 +736,9 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
sqlite3SrcListDelete(pParse->db, F);
}else{
Select *pSubquery;
sqlite3SrcListShiftJoinType(F);
sqlite3SrcListShiftJoinType(pParse,F);
pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0);
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,N,U);
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,&N);
}
}
%endif SQLITE_OMIT_SUBQUERY
@@ -794,13 +796,14 @@ joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
//
// INSERT INTO tab SELECT * FROM aaa JOIN bbb WHERE true ON CONFLICT ...
//
// The [AND] and [OR] precedence marks in the rules for on_opt cause the
// The [AND] and [OR] precedence marks in the rules for on_using cause the
// ON in this context to always be interpreted as belonging to the JOIN.
//
%type on_opt {Expr*}
%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);}
on_opt(N) ::= ON expr(E). {N = E;}
on_opt(N) ::= . [OR] {N = 0;}
%type on_using {OnOrUsing}
//%destructor on_using {sqlite3ClearOnOrUsing(pParse->db, &$$);}
on_using(N) ::= ON expr(E). {N.pOn = E; N.pUsing = 0;}
on_using(N) ::= USING LP idlist(L) RP. {N.pOn = 0; N.pUsing = L;}
on_using(N) ::= . [OR] {N.pOn = 0; N.pUsing = 0;}
// Note that this block abuses the Token type just a little. If there is
// no "INDEXED BY" clause, the returned token is empty (z==0 && n==0). If
@@ -813,15 +816,11 @@ on_opt(N) ::= . [OR] {N = 0;}
// recognizes and interprets this as a special case.
//
%type indexed_opt {Token}
%type indexed_by {Token}
indexed_opt(A) ::= . {A.z=0; A.n=0;}
indexed_opt(A) ::= INDEXED BY nm(X). {A = X;}
indexed_opt(A) ::= NOT INDEXED. {A.z=0; A.n=1;}
%type using_opt {IdList*}
%destructor using_opt {sqlite3IdListDelete(pParse->db, $$);}
using_opt(U) ::= USING LP idlist(L) RP. {U = L;}
using_opt(U) ::= . {U = 0;}
indexed_opt(A) ::= indexed_by(A).
indexed_by(A) ::= INDEXED BY nm(X). {A = X;}
indexed_by(A) ::= NOT INDEXED. {A.z=0; A.n=1;}
%type orderby_opt {ExprList*}
%destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);}
@@ -1034,7 +1033,7 @@ idlist(A) ::= nm(Y).
p->affExpr = 0;
p->flags = EP_Leaf;
ExprClearVVAProperties(p);
p->iAgg = -1;
/* p->iAgg = -1; // Not required */
p->pLeft = p->pRight = 0;
p->pAggInfo = 0;
memset(&p->x, 0, sizeof(p->x));
+1 -2
View File
@@ -551,8 +551,7 @@ void sqlite3PcacheDrop(PgHdr *p){
** make it so.
*/
void sqlite3PcacheMakeDirty(PgHdr *p){
assert( p->nRef>0 || p->pCache->bPurgeable==0 );
testcase( p->nRef==0 );
assert( p->nRef>0 );
assert( sqlite3PcachePageSanity(p) );
if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/
p->flags &= ~PGHDR_DONT_WRITE;
+3 -5
View File
@@ -808,7 +808,7 @@ void sqlite3Pragma(
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
case PragTyp_INCREMENTAL_VACUUM: {
int iLimit, addr;
int iLimit = 0, addr;
if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
iLimit = 0x7fffffff;
}
@@ -1496,7 +1496,6 @@ void sqlite3Pragma(
HashElem *k; /* Loop counter: Next table in schema */
int x; /* result variable */
int regResult; /* 3 registers to hold a result row */
int regKey; /* Register to hold key for checking the FK */
int regRow; /* Registers to hold a row from pTab */
int addrTop; /* Top of a loop checking foreign keys */
int addrOk; /* Jump here if the key is OK */
@@ -1504,7 +1503,6 @@ void sqlite3Pragma(
regResult = pParse->nMem+1;
pParse->nMem += 4;
regKey = ++pParse->nMem;
regRow = ++pParse->nMem;
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
while( k ){
@@ -1571,9 +1569,9 @@ void sqlite3Pragma(
/* Generate code to query the parent index for a matching parent
** key. If a match is found, jump to addrOk. */
if( pIdx ){
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
sqlite3VdbeAddOp4(v, OP_Affinity, regRow, pFK->nCol, 0,
sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regRow, pFK->nCol);
VdbeCoverage(v);
}else if( pParent ){
int jmp = sqlite3VdbeCurrentAddr(v)+2;
+1 -1
View File
@@ -389,7 +389,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
sqlite3ResetAllSchemasOfConnection(db);
pDb = &db->aDb[iDb];
}else
if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){
if( rc==SQLITE_OK || ((db->flags&SQLITE_NoSchemaError) && rc!=SQLITE_NOMEM)){
/* Hack: If the SQLITE_NoSchemaError flag is set, then consider
** the schema loaded, even if errors (other than OOM) occurred. In
** this situation the current sqlite3_prepare() operation will fail,
+8 -2
View File
@@ -884,8 +884,14 @@ void sqlite3_str_vappendf(
sqlite3_str_appendall(pAccum, pItem->zName);
}else if( pItem->zAlias ){
sqlite3_str_appendall(pAccum, pItem->zAlias);
}else if( ALWAYS(pItem->pSelect) ){
sqlite3_str_appendf(pAccum, "SUBQUERY %u", pItem->pSelect->selId);
}else{
Select *pSel = pItem->pSelect;
assert( pSel!=0 );
if( pSel->selFlags & SF_NestedFrom ){
sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
}else{
sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId);
}
}
length = width = 0;
break;
+141 -51
View File
@@ -115,23 +115,6 @@ static void resolveAlias(
}
}
/*
** Return TRUE if the name zCol occurs anywhere in the USING clause.
**
** Return FALSE if the USING clause is NULL or if it does not contain
** zCol.
*/
static int nameInUsingClause(IdList *pUsing, const char *zCol){
if( pUsing ){
int k;
for(k=0; k<pUsing->nId; k++){
if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1;
}
}
return 0;
}
/*
** Subqueries stores the original database, table and column names for their
** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
@@ -208,6 +191,29 @@ Bitmask sqlite3ExprColUsed(Expr *pExpr){
}
}
/*
** Create a new expression term for the column specified by pMatch and
** iColumn. Append this new expression term to the FULL JOIN Match set
** in *ppList. Create a new *ppList if this is the first term in the
** set.
*/
static void extendFJMatch(
Parse *pParse, /* Parsing context */
ExprList **ppList, /* ExprList to extend */
SrcItem *pMatch, /* Source table containing the column */
i16 iColumn /* The column number */
){
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
if( pNew ){
pNew->iTable = pMatch->iCursor;
pNew->iColumn = iColumn;
pNew->y.pTab = pMatch->pTab;
assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
ExprSetProperty(pNew, EP_CanBeNull);
*ppList = sqlite3ExprListAppend(pParse, *ppList, pNew);
}
}
/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
** that name in the set of source tables in pSrcList and make the pExpr
@@ -253,11 +259,13 @@ static int lookupName(
NameContext *pTopNC = pNC; /* First namecontext in the list */
Schema *pSchema = 0; /* Schema of the expression */
int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
Table *pTab = 0; /* Table hold the row */
Table *pTab = 0; /* Table holding the row */
Column *pCol; /* A column of pTab */
ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */
assert( pNC ); /* the name context cannot be NULL. */
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
assert( zDb==0 || zTab!=0 );
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
/* Initialize the node to no-match */
@@ -306,26 +314,64 @@ static int lookupName(
pTab = pItem->pTab;
assert( pTab!=0 && pTab->zName!=0 );
assert( pTab->nCol>0 || pParse->nErr );
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
assert( pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
if( pItem->fg.isNestedFrom ){
/* In this case, pItem is a subquery that has been formed from a
** parenthesized subset of the FROM clause terms. Example:
** .... FROM t1 LEFT JOIN (t2 RIGHT JOIN t3 USING(x)) USING(y) ...
** \_________________________/
** This pItem -------------^
*/
int hit = 0;
assert( pItem->pSelect!=0 );
pEList = pItem->pSelect->pEList;
assert( pEList!=0 );
assert( pEList->nExpr==pTab->nCol );
for(j=0; j<pEList->nExpr; j++){
if( sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
cnt++;
cntTab = 2;
pMatch = pItem;
pExpr->iColumn = j;
hit = 1;
if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
continue;
}
if( cnt>0 ){
if( pItem->fg.isUsing==0
|| sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
){
/* Two or more tables have the same column name which is
** not joined by USING. This is an error. Signal as much
** by clearing pFJMatch and letting cnt go above 1. */
sqlite3ExprListDelete(db, pFJMatch);
pFJMatch = 0;
}else
if( (pItem->fg.jointype & JT_RIGHT)==0 ){
/* An INNER or LEFT JOIN. Use the left-most table */
continue;
}else
if( (pItem->fg.jointype & JT_LEFT)==0 ){
/* A RIGHT JOIN. Use the right-most table */
cnt = 0;
sqlite3ExprListDelete(db, pFJMatch);
pFJMatch = 0;
}else{
/* For a FULL JOIN, we must construct a coalesce() func */
extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
}
}
cnt++;
cntTab = 2;
pMatch = pItem;
pExpr->iColumn = j;
pEList->a[j].bUsed = 1;
hit = 1;
}
if( hit || zTab==0 ) continue;
}
if( zDb ){
if( pTab->pSchema!=pSchema ) continue;
if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue;
}
assert( zDb==0 || zTab!=0 );
if( zTab ){
const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
const char *zTabName;
if( zDb ){
if( pTab->pSchema!=pSchema ) continue;
if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue;
}
zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
assert( zTabName!=0 );
if( sqlite3StrICmp(zTabName, zTab)!=0 ){
continue;
@@ -340,18 +386,37 @@ static int lookupName(
if( pCol->hName==hCol
&& sqlite3StrICmp(pCol->zCnName, zCol)==0
){
/* If there has been exactly one prior match and this match
** is for the right-hand table of a NATURAL JOIN or is in a
** USING clause, then skip this match.
*/
if( cnt==1 ){
if( pItem->fg.jointype & JT_NATURAL ) continue;
if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
if( cnt>0 ){
if( pItem->fg.isUsing==0
|| sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
){
/* Two or more tables have the same column name which is
** not joined by USING. This is an error. Signal as much
** by clearing pFJMatch and letting cnt go above 1. */
sqlite3ExprListDelete(db, pFJMatch);
pFJMatch = 0;
}else
if( (pItem->fg.jointype & JT_RIGHT)==0 ){
/* An INNER or LEFT JOIN. Use the left-most table */
continue;
}else
if( (pItem->fg.jointype & JT_LEFT)==0 ){
/* A RIGHT JOIN. Use the right-most table */
cnt = 0;
sqlite3ExprListDelete(db, pFJMatch);
pFJMatch = 0;
}else{
/* For a FULL JOIN, we must construct a coalesce() func */
extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
}
}
cnt++;
pMatch = pItem;
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
if( pItem->fg.isNestedFrom ){
sqlite3SrcItemColumnUsed(pItem, j);
}
break;
}
}
@@ -364,9 +429,7 @@ static int lookupName(
pExpr->iTable = pMatch->iCursor;
assert( ExprUseYTab(pExpr) );
pExpr->y.pTab = pMatch->pTab;
/* RIGHT JOIN not (yet) supported */
assert( (pMatch->fg.jointype & JT_RIGHT)==0 );
if( (pMatch->fg.jointype & JT_LEFT)!=0 ){
if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
ExprSetProperty(pExpr, EP_CanBeNull);
}
pSchema = pExpr->y.pTab->pSchema;
@@ -607,11 +670,37 @@ static int lookupName(
}
/*
** cnt==0 means there was not match. cnt>1 means there were two or
** more matches. Either way, we have an error.
** cnt==0 means there was not match.
** cnt>1 means there were two or more matches.
**
** cnt==0 is always an error. cnt>1 is often an error, but might
** be multiple matches for a NATURAL LEFT JOIN or a LEFT JOIN USING.
*/
assert( pFJMatch==0 || cnt>0 );
assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
if( cnt!=1 ){
const char *zErr;
if( pFJMatch ){
if( pFJMatch->nExpr==cnt-1 ){
if( ExprHasProperty(pExpr,EP_Leaf) ){
ExprClearProperty(pExpr,EP_Leaf);
}else{
sqlite3ExprDelete(db, pExpr->pLeft);
pExpr->pLeft = 0;
sqlite3ExprDelete(db, pExpr->pRight);
pExpr->pRight = 0;
}
extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
pExpr->op = TK_FUNCTION;
pExpr->u.zToken = "coalesce";
pExpr->x.pList = pFJMatch;
cnt = 1;
goto lookupname_end;
}else{
sqlite3ExprListDelete(db, pFJMatch);
pFJMatch = 0;
}
}
zErr = cnt==0 ? "no such column" : "ambiguous column name";
if( zDb ){
sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol);
@@ -624,6 +713,16 @@ static int lookupName(
pParse->checkSchema = 1;
pTopNC->nNcErr++;
}
assert( pFJMatch==0 );
/* Remove all substructure from pExpr */
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
sqlite3ExprDelete(db, pExpr->pLeft);
pExpr->pLeft = 0;
sqlite3ExprDelete(db, pExpr->pRight);
pExpr->pRight = 0;
ExprSetProperty(pExpr, EP_Leaf);
}
/* If a column from a table in pSrcList is referenced, then record
** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes
@@ -643,16 +742,7 @@ static int lookupName(
pMatch->colUsed |= sqlite3ExprColUsed(pExpr);
}
/* Clean up and return
*/
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
sqlite3ExprDelete(db, pExpr->pLeft);
pExpr->pLeft = 0;
sqlite3ExprDelete(db, pExpr->pRight);
pExpr->pRight = 0;
}
pExpr->op = eNewExprOp;
ExprSetProperty(pExpr, EP_Leaf);
lookupname_end:
if( cnt==1 ){
assert( pNC!=0 );
+431 -238
View File
File diff suppressed because it is too large Load Diff
+42 -20
View File
@@ -2944,6 +2944,9 @@ static int str_in_array(const char *zStr, const char **azArray){
** all opcodes that occur between the p2 jump destination and the opcode
** itself by 2 spaces.
**
** * Do the previous for "Return" instructions for when P2 is positive.
** See tag-20220407a in wherecode.c and vdbe.c.
**
** * For each "Goto", if the jump destination is earlier in the program
** and ends on one of:
** Yield SeekGt SeekLt RowSetRead Rewind
@@ -2958,7 +2961,8 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
int iOp; /* Index of operation in p->aiIndent[] */
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
"Return", 0 };
const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
"Rewind", 0 };
const char *azGoto[] = { "Goto", 0 };
@@ -3016,7 +3020,7 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
p->aiIndent[iOp] = 0;
p->nIndent = iOp+1;
if( str_in_array(zOp, azNext) ){
if( str_in_array(zOp, azNext) && p2op>0 ){
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
}
if( str_in_array(zOp, azGoto) && p2op<p->nIndent
@@ -3042,7 +3046,7 @@ static void explain_data_delete(ShellState *p){
}
/*
** Disable and restore .wheretrace and .selecttrace settings.
** Disable and restore .wheretrace and .treetrace/.selecttrace settings.
*/
static unsigned int savedSelectTrace;
static unsigned int savedWhereTrace;
@@ -3346,6 +3350,8 @@ static void exec_prepared_stmt_columnar(
int bNextLine = 0;
int bMultiLineRowExists = 0;
int bw = p->cmOpts.bWordWrap;
const char *zEmpty = "";
const char *zShowNull = p->nullValue;
rc = sqlite3_step(pStmt);
if( rc!=SQLITE_ROW ) return;
@@ -3407,12 +3413,14 @@ static void exec_prepared_stmt_columnar(
if( wx<0 ) wx = -wx;
if( useNextLine ){
uz = azNextLine[i];
if( uz==0 ) uz = (u8*)zEmpty;
}else if( p->cmOpts.bQuote ){
sqlite3_free(azQuoted[i]);
azQuoted[i] = quoted_column(pStmt,i);
uz = (const unsigned char*)azQuoted[i];
}else{
uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
if( uz==0 ) uz = (u8*)zShowNull;
}
azData[nRow*nColumn + i]
= translateForDisplayAndDup(uz, &azNextLine[i], wx, bw);
@@ -3426,7 +3434,7 @@ static void exec_prepared_stmt_columnar(
nTotal = nColumn*(nRow+1);
for(i=0; i<nTotal; i++){
z = azData[i];
if( z==0 ) z = p->nullValue;
if( z==0 ) z = (char*)zEmpty;
n = strlenChar(z);
j = i%nColumn;
if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
@@ -3530,7 +3538,10 @@ columnar_end:
utf8_printf(p->out, "Interrupt\n");
}
nData = (nRow+1)*nColumn;
for(i=0; i<nData; i++) free(azData[i]);
for(i=0; i<nData; i++){
z = azData[i];
if( z!=zEmpty && z!=zShowNull ) free(azData[i]);
}
sqlite3_free(azData);
sqlite3_free((void*)azNextLine);
sqlite3_free(abRowDiv);
@@ -4997,8 +5008,10 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_dbdata_init(p->db, 0, 0);
#endif
#ifdef SQLITE_HAVE_ZLIB
sqlite3_zipfile_init(p->db, 0, 0);
sqlite3_sqlar_init(p->db, 0, 0);
if( !p->bSafeModePersist ){
sqlite3_zipfile_init(p->db, 0, 0);
sqlite3_sqlar_init(p->db, 0, 0);
}
#endif
sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
shellAddSchemaName, 0, 0);
@@ -7827,7 +7840,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
/*
/*
* zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it.
* zAutoColumn(0, &db, ?) => (db!=0) Form columns spec for CREATE TABLE,
* close db and set it to 0, and return the columns spec, to later
@@ -7910,6 +7923,13 @@ UPDATE ColNames AS t SET reps=\
static const char * const zColDigits = "\
SELECT CAST(ceil(log(count(*)+0.5)) AS INT) FROM ColNames \
";
#else
/* Counting on SQLITE_MAX_COLUMN < 100,000 here. (32767 is the hard limit.) */
static const char * const zColDigits = "\
SELECT CASE WHEN (nc < 10) THEN 1 WHEN (nc < 100) THEN 2 \
WHEN (nc < 1000) THEN 3 WHEN (nc < 10000) THEN 4 \
ELSE 5 FROM (SELECT count(*) AS nc FROM ColNames) \
";
#endif
static const char * const zRenameRank =
#ifdef SHELL_COLUMN_RENAME_CLEAN
@@ -7956,12 +7976,12 @@ SELECT\
','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\
||')' AS ColsSpec \
FROM (\
SELECT cpos, printf('\"%w\"',printf('%.*s%s', nlen-chop,name,suff)) AS cname \
SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \
FROM ColNames ORDER BY cpos\
)";
static const char * const zRenamesDone =
"SELECT group_concat("
" printf('\"%w\" to \"%w\"',name,printf('%.*s%s', nlen-chop, name, suff)),"
" printf('\"%w\" to \"%w\"',name,printf('%!.*s%s', nlen-chop, name, suff)),"
" ','||x'0a')"
"FROM ColNames WHERE suff<>'' OR chop!=0"
;
@@ -7995,11 +8015,7 @@ FROM (\
/* Formulate the columns spec, close the DB, zero *pDb. */
char *zColsSpec = 0;
int hasDupes = db_int(*pDb, zHasDupes);
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
#else
# define nDigits 2
#endif
if( hasDupes ){
#ifdef SHELL_COLUMN_RENAME_CLEAN
rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
@@ -9589,9 +9605,10 @@ static int do_meta_command(char *zLine, ShellState *p){
int bTxtMode = 0;
int i;
int eMode = 0;
int bBOM = 0;
int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
unsigned char zBOM[4]; /* Byte-order mark to using if --bom is present */
zBOM[0] = 0;
failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
if( c=='e' ){
eMode = 'x';
@@ -9604,7 +9621,10 @@ static int do_meta_command(char *zLine, ShellState *p){
if( z[0]=='-' ){
if( z[1]=='-' ) z++;
if( strcmp(z,"-bom")==0 ){
bBOM = 1;
zBOM[0] = 0xef;
zBOM[1] = 0xbb;
zBOM[2] = 0xbf;
zBOM[3] = 0;
}else if( c!='e' && strcmp(z,"-x")==0 ){
eMode = 'x'; /* spreadsheet */
}else if( c!='e' && strcmp(z,"-e")==0 ){
@@ -9673,7 +9693,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->out = stdout;
rc = 1;
}else{
if( bBOM ) fprintf(p->out,"\357\273\277");
if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
#endif
@@ -9686,7 +9706,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->out = stdout;
rc = 1;
} else {
if( bBOM ) fprintf(p->out,"\357\273\277");
if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
}
@@ -10107,7 +10127,9 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
if( (c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0)
|| (c=='t' && n==9 && strncmp(azArg[0], "treetrace", n)==0)
){
unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x);
}else
+9
View File
@@ -351,6 +351,11 @@ struct sqlite3_api_routines {
int (*vtab_in)(sqlite3_index_info*,int,int);
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
/* Version 3.39.0 and later */
int (*deserialize)(sqlite3*,const char*,unsigned char*,
sqlite3_int64,sqlite3_int64,unsigned);
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
};
/*
@@ -669,6 +674,10 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_vtab_in sqlite3_api->vtab_in
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
#ifndef SQLITE_OMIT_DESERIALIZE
#define sqlite3_deserialize sqlite3_api->deserialize
#define sqlite3_serialize sqlite3_api->serialize
#endif
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+166 -79
View File
@@ -939,8 +939,19 @@ typedef INT16_TYPE LogEst;
/*
** Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
**
** ROUND8() always does the rounding, for any argument.
**
** ROUND8P() assumes that the argument is already an integer number of
** pointers in size, and so it is a no-op on systems where the pointer
** size is 8.
*/
#define ROUND8(x) (((x)+7)&~7)
#if SQLITE_PTRSIZE==8
# define ROUND8P(x) (x)
#else
# define ROUND8P(x) (((x)+7)&~7)
#endif
/*
** Round down to the nearest multiple of 8
@@ -1003,22 +1014,23 @@ typedef INT16_TYPE LogEst;
#endif
/*
** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
** the Select query generator tracing logic is turned on.
** TREETRACE_ENABLED will be either 1 or 0 depending on whether or not
** the Abstract Syntax Tree tracing logic is turned on.
*/
#if !defined(SQLITE_AMALGAMATION)
extern u32 sqlite3SelectTrace;
extern u32 sqlite3TreeTrace;
#endif
#if defined(SQLITE_DEBUG) \
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE))
# define SELECTTRACE_ENABLED 1
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE) \
|| defined(SQLITE_ENABLE_TREETRACE))
# define TREETRACE_ENABLED 1
# define SELECTTRACE(K,P,S,X) \
if(sqlite3SelectTrace&(K)) \
if(sqlite3TreeTrace&(K)) \
sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
sqlite3DebugPrintf X
#else
# define SELECTTRACE(K,P,S,X)
# define SELECTTRACE_ENABLED 0
# define TREETRACE_ENABLED 0
#endif
/*
@@ -1179,6 +1191,7 @@ typedef struct Lookaside Lookaside;
typedef struct LookasideSlot LookasideSlot;
typedef struct Module Module;
typedef struct NameContext NameContext;
typedef struct OnOrUsing OnOrUsing;
typedef struct Parse Parse;
typedef struct ParseCleanup ParseCleanup;
typedef struct PreUpdate PreUpdate;
@@ -1766,6 +1779,8 @@ struct sqlite3 {
#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */
#define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */
#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */
#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */
#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -2830,7 +2845,7 @@ struct Expr {
** TK_SELECT_COLUMN: column of the result vector */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
union {
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
int iJoin; /* If EP_FromJoin, the right table of the join */
int iOfst; /* else: start of token from start of statement */
} w;
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
@@ -2873,7 +2888,7 @@ struct Expr {
#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
/* 0x400000 // Available */
#define EP_InnerJoin 0x400000 /* Originates in ON/USING of an inner join */
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
@@ -2990,6 +3005,7 @@ struct ExprList {
unsigned reusable :1; /* Constant expression is reusable */
unsigned bSorterRef :1; /* Defer evaluation until after sorting */
unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */
unsigned bUsed: 1; /* This column used in a SF_NestedFrom subquery */
union {
struct { /* Used by any ExprList other than Parse.pConsExpr */
u16 iOrderByCol; /* For ORDER BY, column number in result set */
@@ -3024,13 +3040,25 @@ struct ExprList {
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
*/
struct IdList {
int nId; /* Number of identifiers on the list */
u8 eU4; /* Which element of a.u4 is valid */
struct IdList_item {
char *zName; /* Name of the identifier */
int idx; /* Index in some Table.aCol[] of a column named zName */
} *a;
int nId; /* Number of identifiers on the list */
union {
int idx; /* Index in some Table.aCol[] of a column named zName */
Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */
} u4;
} a[1];
};
/*
** Allowed values for IdList.eType, which determines which value of the a.u4
** is valid.
*/
#define EU4_NONE 0 /* Does not use IdList.a.u4 */
#define EU4_IDX 1 /* Uses IdList.a.u4.idx */
#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
/*
** The SrcItem object represents a single term in the FROM clause of a query.
** The SrcList object is mostly an array of SrcItems.
@@ -3063,10 +3091,15 @@ struct SrcItem {
unsigned fromDDL :1; /* Comes from sqlite_schema */
unsigned isCte :1; /* This is a CTE */
unsigned notCte :1; /* This item may not match a CTE */
unsigned isUsing :1; /* u3.pUsing is valid */
unsigned isSynthUsing :1; /* u3.pUsing is synthensized from NATURAL */
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
union {
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
} u3;
Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
@@ -3078,6 +3111,15 @@ struct SrcItem {
} u2;
};
/*
** The OnOrUsing object represents either an ON clause or a USING clause.
** It can never be both at the same time, but it can be neither.
*/
struct OnOrUsing {
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
};
/*
** The following structure describes the FROM clause of a SELECT statement.
** Each table or subquery in the FROM clause is a separate element of
@@ -3106,14 +3148,15 @@ struct SrcList {
/*
** Permitted values of the SrcList.a.jointype field
*/
#define JT_INNER 0x0001 /* Any kind of inner or cross join */
#define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */
#define JT_NATURAL 0x0004 /* True for a "natural" join */
#define JT_LEFT 0x0008 /* Left outer join */
#define JT_RIGHT 0x0010 /* Right outer join */
#define JT_OUTER 0x0020 /* The "OUTER" keyword is present */
#define JT_ERROR 0x0040 /* unknown or unsupported join type */
#define JT_INNER 0x01 /* Any kind of inner or cross join */
#define JT_CROSS 0x02 /* Explicit use of the CROSS keyword */
#define JT_NATURAL 0x04 /* True for a "natural" join */
#define JT_LEFT 0x08 /* Left outer join */
#define JT_RIGHT 0x10 /* Right outer join */
#define JT_OUTER 0x20 /* The "OUTER" keyword is present */
#define JT_LTORJ 0x40 /* One of the LEFT operands of a RIGHT JOIN
** Mnemonic: Left Table Of Right Join */
#define JT_ERROR 0x80 /* unknown or unsupported join type */
/*
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()
@@ -3136,7 +3179,7 @@ struct SrcList {
#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */
#define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
/* 0x1000 not currently used */
#define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */
/* 0x2000 not currently used */
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
/* 0x8000 not currently used */
@@ -3332,6 +3375,9 @@ struct Select {
#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
/* True if S exists and has SF_NestedFrom */
#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
/*
** The results of a SELECT can be distributed in several ways, as defined
** by one of the following macros. The "SRT" prefix means "SELECT Result
@@ -3543,6 +3589,7 @@ struct Parse {
u8 okConstFactor; /* OK to factor out constants */
u8 disableLookaside; /* Number of times lookaside has been disabled */
u8 disableVtab; /* Disable all virtual tables for this parse */
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
#endif
@@ -3715,20 +3762,20 @@ struct AuthContext {
#define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */
/*
* Each trigger present in the database schema is stored as an instance of
* struct Trigger.
*
* Pointers to instances of struct Trigger are stored in two ways.
* 1. In the "trigHash" hash table (part of the sqlite3* that represents the
* database). This allows Trigger structures to be retrieved by name.
* 2. All triggers associated with a single table form a linked list, using the
* pNext member of struct Trigger. A pointer to the first element of the
* linked list is stored as the "pTrigger" member of the associated
* struct Table.
*
* The "step_list" member points to the first element of a linked list
* containing the SQL statements specified as the trigger program.
*/
** Each trigger present in the database schema is stored as an instance of
** struct Trigger.
**
** Pointers to instances of struct Trigger are stored in two ways.
** 1. In the "trigHash" hash table (part of the sqlite3* that represents the
** database). This allows Trigger structures to be retrieved by name.
** 2. All triggers associated with a single table form a linked list, using the
** pNext member of struct Trigger. A pointer to the first element of the
** linked list is stored as the "pTrigger" member of the associated
** struct Table.
**
** The "step_list" member points to the first element of a linked list
** containing the SQL statements specified as the trigger program.
*/
struct Trigger {
char *zName; /* The name of the trigger */
char *table; /* The table or view to which the trigger applies */
@@ -3755,43 +3802,48 @@ struct Trigger {
#define TRIGGER_AFTER 2
/*
* An instance of struct TriggerStep is used to store a single SQL statement
* that is a part of a trigger-program.
*
* Instances of struct TriggerStep are stored in a singly linked list (linked
* using the "pNext" member) referenced by the "step_list" member of the
* associated struct Trigger instance. The first element of the linked list is
* the first step of the trigger-program.
*
* The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
* "SELECT" statement. The meanings of the other members is determined by the
* value of "op" as follows:
*
* (op == TK_INSERT)
* orconf -> stores the ON CONFLICT algorithm
* pSelect -> If this is an INSERT INTO ... SELECT ... statement, then
* this stores a pointer to the SELECT statement. Otherwise NULL.
* zTarget -> Dequoted name of the table to insert into.
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
* this stores values to be inserted. Otherwise NULL.
* pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
* statement, then this stores the column-names to be
* inserted into.
*
* (op == TK_DELETE)
* zTarget -> Dequoted name of the table to delete from.
* pWhere -> The WHERE clause of the DELETE statement if one is specified.
* Otherwise NULL.
*
* (op == TK_UPDATE)
* zTarget -> Dequoted name of the table to update.
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
* Otherwise NULL.
* pExprList -> A list of the columns to update and the expressions to update
* them to. See sqlite3Update() documentation of "pChanges"
* argument.
*
*/
** An instance of struct TriggerStep is used to store a single SQL statement
** that is a part of a trigger-program.
**
** Instances of struct TriggerStep are stored in a singly linked list (linked
** using the "pNext" member) referenced by the "step_list" member of the
** associated struct Trigger instance. The first element of the linked list is
** the first step of the trigger-program.
**
** The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
** "SELECT" statement. The meanings of the other members is determined by the
** value of "op" as follows:
**
** (op == TK_INSERT)
** orconf -> stores the ON CONFLICT algorithm
** pSelect -> The content to be inserted - either a SELECT statement or
** a VALUES clause.
** zTarget -> Dequoted name of the table to insert into.
** pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
** statement, then this stores the column-names to be
** inserted into.
** pUpsert -> The ON CONFLICT clauses for an Upsert
**
** (op == TK_DELETE)
** zTarget -> Dequoted name of the table to delete from.
** pWhere -> The WHERE clause of the DELETE statement if one is specified.
** Otherwise NULL.
**
** (op == TK_UPDATE)
** zTarget -> Dequoted name of the table to update.
** pWhere -> The WHERE clause of the UPDATE statement if one is specified.
** Otherwise NULL.
** pExprList -> A list of the columns to update and the expressions to update
** them to. See sqlite3Update() documentation of "pChanges"
** argument.
**
** (op == TK_SELECT)
** pSelect -> The SELECT statement
**
** (op == TK_RETURNING)
** pExprList -> The list of expressions that follow the RETURNING keyword.
**
*/
struct TriggerStep {
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT,
** or TK_RETURNING */
@@ -4401,18 +4453,50 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
#endif
#if defined(SQLITE_DEBUG)
void sqlite3TreeViewLine(TreeView*, const char *zFormat, ...);
void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*);
void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
void sqlite3TreeViewBareIdList(TreeView*, const IdList*, const char*);
void sqlite3TreeViewIdList(TreeView*, const IdList*, u8, const char*);
void sqlite3TreeViewSrcList(TreeView*, const SrcList*);
void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
void sqlite3TreeViewWith(TreeView*, const With*, u8);
void sqlite3TreeViewUpsert(TreeView*, const Upsert*, u8);
void sqlite3TreeViewDelete(const With*, const SrcList*, const Expr*,
const ExprList*,const Expr*, const Trigger*);
void sqlite3TreeViewInsert(const With*, const SrcList*,
const IdList*, const Select*, const ExprList*,
int, const Upsert*, const Trigger*);
void sqlite3TreeViewUpdate(const With*, const SrcList*, const ExprList*,
const Expr*, int, const ExprList*, const Expr*,
const Upsert*, const Trigger*);
#ifndef SQLITE_OMIT_TRIGGER
void sqlite3TreeViewTriggerStep(TreeView*, const TriggerStep*, u8, u8);
void sqlite3TreeViewTrigger(TreeView*, const Trigger*, u8, u8);
#endif
#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3TreeViewWindow(TreeView*, const Window*, u8);
void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
#endif
void sqlite3ShowExpr(const Expr*);
void sqlite3ShowExprList(const ExprList*);
void sqlite3ShowIdList(const IdList*);
void sqlite3ShowSrcList(const SrcList*);
void sqlite3ShowSelect(const Select*);
void sqlite3ShowWith(const With*);
void sqlite3ShowUpsert(const Upsert*);
#ifndef SQLITE_OMIT_TRIGGER
void sqlite3ShowTriggerStep(const TriggerStep*);
void sqlite3ShowTriggerStepList(const TriggerStep*);
void sqlite3ShowTrigger(const Trigger*);
void sqlite3ShowTriggerList(const Trigger*);
#endif
#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3ShowWindow(const Window*);
void sqlite3ShowWinFunc(const Window*);
#endif
#endif
void sqlite3SetString(char **, sqlite3*, const char*);
void sqlite3ErrorMsg(Parse*, const char*, ...);
@@ -4561,13 +4645,14 @@ SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
Token*, Select*, Expr*, IdList*);
Token*, Select*, OnOrUsing*);
void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
int sqlite3IndexedByLookup(Parse *, SrcItem *);
void sqlite3SrcListShiftJoinType(SrcList*);
void sqlite3SrcListShiftJoinType(Parse*,SrcList*);
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
void sqlite3IdListDelete(sqlite3*, IdList*);
void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*);
void sqlite3SrcListDelete(sqlite3*, SrcList*);
Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
@@ -4667,6 +4752,7 @@ int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
int sqlite3ExprIsTableConstant(Expr*,int);
int sqlite3ExprIsTableConstraint(Expr*,const SrcItem*);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
int sqlite3ExprContainsSubquery(Expr*);
#endif
@@ -4764,7 +4850,8 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
int sqlite3ColumnIndex(Table *pTab, const char *zCol);
void sqlite3SetJoinExpr(Expr*,int);
void sqlite3SrcItemColumnUsed(SrcItem*,int);
void sqlite3SetJoinExpr(Expr*,int,u32);
void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
void sqlite3DeferForeignKey(Parse*, int);
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -5110,7 +5197,7 @@ int sqlite3VtabBegin(sqlite3 *, VTable *);
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
void sqlite3VtabWriteAll(sqlite3_index_info*);
void sqlite3VtabUsesAllSchemas(sqlite3_index_info*);
#endif
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
+1 -2
View File
@@ -334,8 +334,7 @@ int sqlite3_db_status(
db->pnBytesFreed = &nByte;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
sqlite3VdbeClearObject(db, pVdbe);
sqlite3DbFree(db, pVdbe);
sqlite3VdbeDelete(pVdbe);
}
db->pnBytesFreed = 0;
+3 -3
View File
@@ -8908,9 +8908,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_sync_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_fullsync_count",
(char*)&sqlite3_fullsync_count, TCL_LINK_INT);
#if defined(SQLITE_ENABLE_SELECTTRACE)
Tcl_LinkVar(interp, "sqlite3_unsupported_selecttrace",
(char*)&sqlite3SelectTrace, TCL_LINK_INT);
#if defined(SQLITE_ENABLE_TREETRACE)
Tcl_LinkVar(interp, "sqlite3_unsupported_treetrace",
(char*)&sqlite3TreeTrace, TCL_LINK_INT);
#endif
#if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST)
Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses",
+1 -1
View File
@@ -710,7 +710,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
}
sqlite3DbFree(db, pParse->pVList);
if( pParse->pVList ) sqlite3DbFreeNN(db, pParse->pVList);
db->pParse = pParentParse;
assert( nErr==0 || pParse->rc!=SQLITE_OK );
return nErr;
+438 -50
View File
@@ -24,33 +24,37 @@
** Add a new subitem to the tree. The moreToFollow flag indicates that this
** is not the last item in the tree.
*/
static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
static void sqlite3TreeViewPush(TreeView **pp, u8 moreToFollow){
TreeView *p = *pp;
if( p==0 ){
p = sqlite3_malloc64( sizeof(*p) );
if( p==0 ) return 0;
*pp = p = sqlite3_malloc64( sizeof(*p) );
if( p==0 ) return;
memset(p, 0, sizeof(*p));
}else{
p->iLevel++;
}
assert( moreToFollow==0 || moreToFollow==1 );
if( p->iLevel<(int)sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
return p;
}
/*
** Finished with one layer of the tree
*/
static void sqlite3TreeViewPop(TreeView *p){
static void sqlite3TreeViewPop(TreeView **pp){
TreeView *p = *pp;
if( p==0 ) return;
p->iLevel--;
if( p->iLevel<0 ) sqlite3_free(p);
if( p->iLevel<0 ){
sqlite3_free(p);
*pp = 0;
}
}
/*
** Generate a single line of output for the tree, with a prefix that contains
** all the appropriate tree lines
*/
static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
va_list ap;
int i;
StrAccum acc;
@@ -78,7 +82,7 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
** Shorthand for starting a new tree item that consists of a single label
*/
static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
p = sqlite3TreeViewPush(p, moreFollows);
sqlite3TreeViewPush(&p, moreFollows);
sqlite3TreeViewLine(p, "%s", zLabel);
}
@@ -95,7 +99,7 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith);
}
if( pWith->nCte>0 ){
pView = sqlite3TreeViewPush(pView, 1);
sqlite3TreeViewPush(&pView, moreToFollow);
for(i=0; i<pWith->nCte; i++){
StrAccum x;
char zLine[1000];
@@ -111,6 +115,10 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
}
sqlite3_str_appendf(&x, ")");
}
if( pCte->eM10d!=M10d_Any ){
sqlite3_str_appendf(&x, " %sMATERIALIZED",
pCte->eM10d==M10d_No ? "NOT " : "");
}
if( pCte->pUse ){
sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse,
pCte->pUse->nUse);
@@ -118,9 +126,9 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
sqlite3StrAccumFinish(&x);
sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
}
@@ -129,6 +137,7 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
*/
void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
int i;
if( pSrc==0 ) return;
for(i=0; i<pSrc->nSrc; i++){
const SrcItem *pItem = &pSrc->a[i];
StrAccum x;
@@ -140,11 +149,18 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx",
pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed);
}
if( pItem->fg.jointype & JT_LEFT ){
if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){
sqlite3_str_appendf(&x, " FULL-OUTER-JOIN");
}else if( pItem->fg.jointype & JT_LEFT ){
sqlite3_str_appendf(&x, " LEFT-JOIN");
}else if( pItem->fg.jointype & JT_RIGHT ){
sqlite3_str_appendf(&x, " RIGHT-JOIN");
}else if( pItem->fg.jointype & JT_CROSS ){
sqlite3_str_appendf(&x, " CROSS-JOIN");
}
if( pItem->fg.jointype & JT_LTORJ ){
sqlite3_str_appendf(&x, " LTORJ");
}
if( pItem->fg.fromDDL ){
sqlite3_str_appendf(&x, " DDL");
}
@@ -154,12 +170,13 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
sqlite3StrAccumFinish(&x);
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
if( pItem->pSelect ){
assert( pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
}
if( pItem->fg.isTabFunc ){
sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
}
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
}
@@ -173,11 +190,11 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
sqlite3TreeViewLine(pView, "nil-SELECT");
return;
}
pView = sqlite3TreeViewPush(pView, moreToFollow);
sqlite3TreeViewPush(&pView, moreToFollow);
if( p->pWith ){
sqlite3TreeViewWith(pView, p->pWith, 1);
cnt = 1;
sqlite3TreeViewPush(pView, 1);
sqlite3TreeViewPush(&pView, 1);
}
do{
if( p->selFlags & SF_WhereBegin ){
@@ -191,7 +208,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
(int)p->nSelectRow
);
}
if( cnt++ ) sqlite3TreeViewPop(pView);
if( cnt++ ) sqlite3TreeViewPop(&pView);
if( p->pPrior ){
n = 1000;
}else{
@@ -214,24 +231,24 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
#ifndef SQLITE_OMIT_WINDOWFUNC
if( p->pWin ){
Window *pX;
pView = sqlite3TreeViewPush(pView, (n--)>0);
sqlite3TreeViewPush(&pView, (n--)>0);
sqlite3TreeViewLine(pView, "window-functions");
for(pX=p->pWin; pX; pX=pX->pNextWin){
sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0);
}
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
#endif
if( p->pSrc && p->pSrc->nSrc ){
pView = sqlite3TreeViewPush(pView, (n--)>0);
sqlite3TreeViewPush(&pView, (n--)>0);
sqlite3TreeViewLine(pView, "FROM");
sqlite3TreeViewSrcList(pView, p->pSrc);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
if( p->pWhere ){
sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
sqlite3TreeViewExpr(pView, p->pWhere, 0);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
if( p->pGroupBy ){
sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
@@ -239,7 +256,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
if( p->pHaving ){
sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
sqlite3TreeViewExpr(pView, p->pHaving, 0);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( p->pWinDefn ){
@@ -248,7 +265,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
for(pX=p->pWinDefn; pX; pX=pX->pNextWin){
sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0);
}
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
#endif
if( p->pOrderBy ){
@@ -260,9 +277,9 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
if( p->pLimit->pRight ){
sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
if( p->pPrior ){
const char *zOp = "UNION";
@@ -275,7 +292,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
}
p = p->pPrior;
}while( p!=0 );
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
@@ -291,24 +308,24 @@ void sqlite3TreeViewBound(
switch( eBound ){
case TK_UNBOUNDED: {
sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
break;
}
case TK_CURRENT: {
sqlite3TreeViewItem(pView, "CURRENT", moreToFollow);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
break;
}
case TK_PRECEDING: {
sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow);
sqlite3TreeViewExpr(pView, pExpr, 0);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
break;
}
case TK_FOLLOWING: {
sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow);
sqlite3TreeViewExpr(pView, pExpr, 0);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
break;
}
}
@@ -324,9 +341,9 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
if( pWin->pFilter ){
sqlite3TreeViewItem(pView, "FILTER", 1);
sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
pView = sqlite3TreeViewPush(pView, more);
sqlite3TreeViewPush(&pView, more);
if( pWin->zName ){
sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin);
}else{
@@ -337,9 +354,9 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
if( pWin->eFrmType ) nElement++;
if( pWin->eExclude ) nElement++;
if( pWin->zBase ){
sqlite3TreeViewPush(pView, (--nElement)>0);
sqlite3TreeViewPush(&pView, (--nElement)>0);
sqlite3TreeViewLine(pView, "window: %s", pWin->zBase);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
if( pWin->pPartition ){
sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY");
@@ -357,7 +374,7 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
sqlite3TreeViewItem(pView, zBuf, (--nElement)>0);
sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1);
sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
if( pWin->eExclude ){
char zBuf[30];
@@ -372,11 +389,11 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
zExclude = zBuf;
break;
}
sqlite3TreeViewPush(pView, 0);
sqlite3TreeViewPush(&pView, 0);
sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
@@ -385,11 +402,11 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
** Generate a human-readable explanation for a Window Function object
*/
void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){
pView = sqlite3TreeViewPush(pView, more);
sqlite3TreeViewPush(&pView, more);
sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
pWin->pWFunc->zName, pWin->pWFunc->nArg);
sqlite3TreeViewWindow(pView, pWin, 0);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
@@ -400,10 +417,10 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
const char *zBinOp = 0; /* Binary operator */
const char *zUniOp = 0; /* Unary operator */
char zFlgs[200];
pView = sqlite3TreeViewPush(pView, moreToFollow);
sqlite3TreeViewPush(&pView, moreToFollow);
if( pExpr==0 ){
sqlite3TreeViewLine(pView, "nil");
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
return;
}
if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){
@@ -412,7 +429,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
sqlite3_str_appendf(&x, " fg.af=%x.%c",
pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
if( ExprHasProperty(pExpr, EP_FromJoin) ){
sqlite3_str_appendf(&x, " iRJT=%d", pExpr->w.iRightJoinTable);
sqlite3_str_appendf(&x, " iJoin=%d", pExpr->w.iJoin);
}
if( ExprHasProperty(pExpr, EP_FromDDL) ){
sqlite3_str_appendf(&x, " DDL");
@@ -760,7 +777,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs);
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
}
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
@@ -782,13 +799,23 @@ void sqlite3TreeViewBareExprList(
int j = pList->a[i].u.x.iOrderByCol;
char *zName = pList->a[i].zEName;
int moreToFollow = i<pList->nExpr - 1;
if( pList->a[i].eEName!=ENAME_NAME ) zName = 0;
if( j || zName ){
sqlite3TreeViewPush(pView, moreToFollow);
sqlite3TreeViewPush(&pView, moreToFollow);
moreToFollow = 0;
sqlite3TreeViewLine(pView, 0);
if( zName ){
fprintf(stdout, "AS %s ", zName);
switch( pList->a[i].eEName ){
default:
fprintf(stdout, "AS %s ", zName);
break;
case ENAME_TAB:
fprintf(stdout, "TABLE-ALIAS-NAME(\"%s\") ", zName);
if( pList->a[i].bUsed==0 ) fprintf(stdout, "(unused) ");
break;
case ENAME_SPAN:
fprintf(stdout, "SPAN(\"%s\") ", zName);
break;
}
}
if( j ){
fprintf(stdout, "iOrderByCol=%d", j);
@@ -798,7 +825,7 @@ void sqlite3TreeViewBareExprList(
}
sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow);
if( j || zName ){
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
}
}
@@ -809,9 +836,370 @@ void sqlite3TreeViewExprList(
u8 moreToFollow,
const char *zLabel
){
pView = sqlite3TreeViewPush(pView, moreToFollow);
sqlite3TreeViewPush(&pView, moreToFollow);
sqlite3TreeViewBareExprList(pView, pList, zLabel);
sqlite3TreeViewPop(pView);
sqlite3TreeViewPop(&pView);
}
/*
** Generate a human-readable explanation of an id-list.
*/
void sqlite3TreeViewBareIdList(
TreeView *pView,
const IdList *pList,
const char *zLabel
){
if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
if( pList==0 ){
sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
}else{
int i;
sqlite3TreeViewLine(pView, "%s", zLabel);
for(i=0; i<pList->nId; i++){
char *zName = pList->a[i].zName;
int moreToFollow = i<pList->nId - 1;
if( zName==0 ) zName = "(null)";
sqlite3TreeViewPush(&pView, moreToFollow);
sqlite3TreeViewLine(pView, 0);
if( pList->eU4==EU4_NONE ){
fprintf(stdout, "%s\n", zName);
}else if( pList->eU4==EU4_IDX ){
fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx);
}else{
assert( pList->eU4==EU4_EXPR );
if( pList->a[i].u4.pExpr==0 ){
fprintf(stdout, "%s (pExpr=NULL)\n", zName);
}else{
fprintf(stdout, "%s\n", zName);
sqlite3TreeViewPush(&pView, i<pList->nId-1);
sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0);
sqlite3TreeViewPop(&pView);
}
}
sqlite3TreeViewPop(&pView);
}
}
}
void sqlite3TreeViewIdList(
TreeView *pView,
const IdList *pList,
u8 moreToFollow,
const char *zLabel
){
sqlite3TreeViewPush(&pView, moreToFollow);
sqlite3TreeViewBareIdList(pView, pList, zLabel);
sqlite3TreeViewPop(&pView);
}
/*
** Generate a human-readable explanation of a list of Upsert objects
*/
void sqlite3TreeViewUpsert(
TreeView *pView,
const Upsert *pUpsert,
u8 moreToFollow
){
if( pUpsert==0 ) return;
sqlite3TreeViewPush(&pView, moreToFollow);
while( pUpsert ){
int n;
sqlite3TreeViewPush(&pView, pUpsert->pNextUpsert!=0 || moreToFollow);
sqlite3TreeViewLine(pView, "ON CONFLICT DO %s",
pUpsert->isDoUpdate ? "UPDATE" : "NOTHING");
n = (pUpsert->pUpsertSet!=0) + (pUpsert->pUpsertWhere!=0);
sqlite3TreeViewExprList(pView, pUpsert->pUpsertTarget, (n--)>0, "TARGET");
sqlite3TreeViewExprList(pView, pUpsert->pUpsertSet, (n--)>0, "SET");
if( pUpsert->pUpsertWhere ){
sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
sqlite3TreeViewExpr(pView, pUpsert->pUpsertWhere, 0);
sqlite3TreeViewPop(&pView);
}
sqlite3TreeViewPop(&pView);
pUpsert = pUpsert->pNextUpsert;
}
sqlite3TreeViewPop(&pView);
}
/*
** Generate a human-readable diagram of the data structure that go
** into generating an DELETE statement.
*/
void sqlite3TreeViewDelete(
const With *pWith,
const SrcList *pTabList,
const Expr *pWhere,
const ExprList *pOrderBy,
const Expr *pLimit,
const Trigger *pTrigger
){
int n = 0;
TreeView *pView = 0;
sqlite3TreeViewPush(&pView, 0);
sqlite3TreeViewLine(pView, "DELETE");
if( pWith ) n++;
if( pTabList ) n++;
if( pWhere ) n++;
if( pOrderBy ) n++;
if( pLimit ) n++;
if( pTrigger ) n++;
if( pWith ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewWith(pView, pWith, 0);
sqlite3TreeViewPop(&pView);
}
if( pTabList ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "FROM");
sqlite3TreeViewSrcList(pView, pTabList);
sqlite3TreeViewPop(&pView);
}
if( pWhere ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "WHERE");
sqlite3TreeViewExpr(pView, pWhere, 0);
sqlite3TreeViewPop(&pView);
}
if( pOrderBy ){
sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY");
}
if( pLimit ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "LIMIT");
sqlite3TreeViewExpr(pView, pLimit, 0);
sqlite3TreeViewPop(&pView);
}
if( pTrigger ){
sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1);
}
sqlite3TreeViewPop(&pView);
}
/*
** Generate a human-readable diagram of the data structure that go
** into generating an INSERT statement.
*/
void sqlite3TreeViewInsert(
const With *pWith,
const SrcList *pTabList,
const IdList *pColumnList,
const Select *pSelect,
const ExprList *pExprList,
int onError,
const Upsert *pUpsert,
const Trigger *pTrigger
){
TreeView *pView = 0;
int n = 0;
const char *zLabel = "INSERT";
switch( onError ){
case OE_Replace: zLabel = "REPLACE"; break;
case OE_Ignore: zLabel = "INSERT OR IGNORE"; break;
case OE_Rollback: zLabel = "INSERT OR ROLLBACK"; break;
case OE_Abort: zLabel = "INSERT OR ABORT"; break;
case OE_Fail: zLabel = "INSERT OR FAIL"; break;
}
sqlite3TreeViewPush(&pView, 0);
sqlite3TreeViewLine(pView, zLabel);
if( pWith ) n++;
if( pTabList ) n++;
if( pColumnList ) n++;
if( pSelect ) n++;
if( pExprList ) n++;
if( pUpsert ) n++;
if( pTrigger ) n++;
if( pWith ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewWith(pView, pWith, 0);
sqlite3TreeViewPop(&pView);
}
if( pTabList ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "INTO");
sqlite3TreeViewSrcList(pView, pTabList);
sqlite3TreeViewPop(&pView);
}
if( pColumnList ){
sqlite3TreeViewIdList(pView, pColumnList, (--n)>0, "COLUMNS");
}
if( pSelect ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "DATA-SOURCE");
sqlite3TreeViewSelect(pView, pSelect, 0);
sqlite3TreeViewPop(&pView);
}
if( pExprList ){
sqlite3TreeViewExprList(pView, pExprList, (--n)>0, "VALUES");
}
if( pUpsert ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "UPSERT");
sqlite3TreeViewUpsert(pView, pUpsert, 0);
sqlite3TreeViewPop(&pView);
}
if( pTrigger ){
sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1);
}
sqlite3TreeViewPop(&pView);
}
/*
** Generate a human-readable diagram of the data structure that go
** into generating an UPDATE statement.
*/
void sqlite3TreeViewUpdate(
const With *pWith,
const SrcList *pTabList,
const ExprList *pChanges,
const Expr *pWhere,
int onError,
const ExprList *pOrderBy,
const Expr *pLimit,
const Upsert *pUpsert,
const Trigger *pTrigger
){
int n = 0;
TreeView *pView = 0;
const char *zLabel = "UPDATE";
switch( onError ){
case OE_Replace: zLabel = "UPDATE OR REPLACE"; break;
case OE_Ignore: zLabel = "UPDATE OR IGNORE"; break;
case OE_Rollback: zLabel = "UPDATE OR ROLLBACK"; break;
case OE_Abort: zLabel = "UPDATE OR ABORT"; break;
case OE_Fail: zLabel = "UPDATE OR FAIL"; break;
}
sqlite3TreeViewPush(&pView, 0);
sqlite3TreeViewLine(pView, zLabel);
if( pWith ) n++;
if( pTabList ) n++;
if( pChanges ) n++;
if( pWhere ) n++;
if( pOrderBy ) n++;
if( pLimit ) n++;
if( pUpsert ) n++;
if( pTrigger ) n++;
if( pWith ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewWith(pView, pWith, 0);
sqlite3TreeViewPop(&pView);
}
if( pTabList ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "FROM");
sqlite3TreeViewSrcList(pView, pTabList);
sqlite3TreeViewPop(&pView);
}
if( pChanges ){
sqlite3TreeViewExprList(pView, pChanges, (--n)>0, "SET");
}
if( pWhere ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "WHERE");
sqlite3TreeViewExpr(pView, pWhere, 0);
sqlite3TreeViewPop(&pView);
}
if( pOrderBy ){
sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY");
}
if( pLimit ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "LIMIT");
sqlite3TreeViewExpr(pView, pLimit, 0);
sqlite3TreeViewPop(&pView);
}
if( pUpsert ){
sqlite3TreeViewPush(&pView, (--n)>0);
sqlite3TreeViewLine(pView, "UPSERT");
sqlite3TreeViewUpsert(pView, pUpsert, 0);
sqlite3TreeViewPop(&pView);
}
if( pTrigger ){
sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1);
}
sqlite3TreeViewPop(&pView);
}
#ifndef SQLITE_OMIT_TRIGGER
/*
** Show a human-readable graph of a TriggerStep
*/
void sqlite3TreeViewTriggerStep(
TreeView *pView,
const TriggerStep *pStep,
u8 moreToFollow,
u8 showFullList
){
int cnt = 0;
if( pStep==0 ) return;
sqlite3TreeViewPush(&pView,
moreToFollow || (showFullList && pStep->pNext!=0));
do{
if( cnt++ && pStep->pNext==0 ){
sqlite3TreeViewPop(&pView);
sqlite3TreeViewPush(&pView, 0);
}
sqlite3TreeViewLine(pView, "%s", pStep->zSpan ? pStep->zSpan : "RETURNING");
}while( showFullList && (pStep = pStep->pNext)!=0 );
sqlite3TreeViewPop(&pView);
}
/*
** Show a human-readable graph of a Trigger
*/
void sqlite3TreeViewTrigger(
TreeView *pView,
const Trigger *pTrigger,
u8 moreToFollow,
u8 showFullList
){
int cnt = 0;
if( pTrigger==0 ) return;
sqlite3TreeViewPush(&pView,
moreToFollow || (showFullList && pTrigger->pNext!=0));
do{
if( cnt++ && pTrigger->pNext==0 ){
sqlite3TreeViewPop(&pView);
sqlite3TreeViewPush(&pView, 0);
}
sqlite3TreeViewLine(pView, "TRIGGER %s", pTrigger->zName);
sqlite3TreeViewPush(&pView, 0);
sqlite3TreeViewTriggerStep(pView, pTrigger->step_list, 0, 1);
sqlite3TreeViewPop(&pView);
}while( showFullList && (pTrigger = pTrigger->pNext)!=0 );
sqlite3TreeViewPop(&pView);
}
#endif /* SQLITE_OMIT_TRIGGER */
/*
** These simplified versions of the tree-view routines omit unnecessary
** parameters. These variants are intended to be used from a symbolic
** debugger, such as "gdb", during interactive debugging sessions.
**
** This routines are given external linkage so that they will always be
** accessible to the debugging, and to avoid warnings about unused
** functions. But these routines only exist in debugging builds, so they
** do not contaminate the interface.
*/
void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); }
void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);}
void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); }
void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); }
void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); }
void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); }
void sqlite3ShowUpsert(const Upsert *p){ sqlite3TreeViewUpsert(0,p,0); }
#ifndef SQLITE_OMIT_TRIGGER
void sqlite3ShowTriggerStep(const TriggerStep *p){
sqlite3TreeViewTriggerStep(0,p,0,0);
}
void sqlite3ShowTriggerStepList(const TriggerStep *p){
sqlite3TreeViewTriggerStep(0,p,0,1);
}
void sqlite3ShowTrigger(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,0); }
void sqlite3ShowTriggerList(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,1);}
#endif
#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3ShowWindow(const Window *p){ sqlite3TreeViewWindow(0,p,0); }
void sqlite3ShowWinFunc(const Window *p){ sqlite3TreeViewWinFunc(0,p,0); }
#endif
#endif /* SQLITE_DEBUG */
+29 -7
View File
@@ -52,9 +52,7 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
Trigger *pList; /* List of triggers to return */
HashElem *p; /* Loop variable for TEMP triggers */
if( pParse->disableTriggers ){
return 0;
}
assert( pParse->disableTriggers==0 );
pTmpSchema = pParse->db->aDb[1].pSchema;
p = sqliteHashFirst(&pTmpSchema->trigHash);
pList = pTab->pTrigger;
@@ -67,11 +65,10 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
){
pTrig->pNext = pList;
pList = pTrig;
}else if( pTrig->op==TK_RETURNING
}else if( pTrig->op==TK_RETURNING ){
#ifndef SQLITE_OMIT_VIRTUALTABLE
&& pParse->db->pVtabCtx==0
assert( pParse->db->pVtabCtx==0 );
#endif
){
assert( pParse->bReturning );
assert( &(pParse->u1.pReturning->retTrig) == pTrig );
pTrig->table = pTab->zName;
@@ -730,13 +727,22 @@ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){
return 0;
}
/*
** Return true if any TEMP triggers exist
*/
static int tempTriggersExist(sqlite3 *db){
if( NEVER(db->aDb[1].pSchema==0) ) return 0;
if( sqliteHashFirst(&db->aDb[1].pSchema->trigHash)==0 ) return 0;
return 1;
}
/*
** Return a list of all triggers on table pTab if there exists at least
** one trigger that must be fired when an operation of type 'op' is
** performed on the table, and, if that operation is an UPDATE, if at
** least one of the columns in pChanges is being modified.
*/
Trigger *sqlite3TriggersExist(
static SQLITE_NOINLINE Trigger *triggersReallyExist(
Parse *pParse, /* Parse context */
Table *pTab, /* The table the contains the triggers */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
@@ -799,6 +805,22 @@ exit_triggers_exist:
}
return (mask ? pList : 0);
}
Trigger *sqlite3TriggersExist(
Parse *pParse, /* Parse context */
Table *pTab, /* The table the contains the triggers */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
ExprList *pChanges, /* Columns that change in an UPDATE statement */
int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
){
assert( pTab!=0 );
if( (pTab->pTrigger==0 && !tempTriggersExist(pParse->db))
|| pParse->disableTriggers
){
if( pMask ) *pMask = 0;
return 0;
}
return triggersReallyExist(pParse,pTab,op,pChanges,pMask);
}
/*
** Convert the pStep->zTarget string into a SrcList and return a pointer
+8
View File
@@ -376,6 +376,14 @@ void sqlite3Update(
# define isView 0
#endif
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x10000 ){
sqlite3TreeViewLine(0, "In sqlite3Update() at %s:%d", __FILE__, __LINE__);
sqlite3TreeViewUpdate(pParse->pWith, pTabList, pChanges, pWhere,
onError, pOrderBy, pLimit, pUpsert, pTrigger);
}
#endif
/* If there was a FROM clause, set nChangeFrom to the number of expressions
** in the change-list. Otherwise, set it to 0. There cannot be a FROM
** clause if this function is being called to generate code for part of
+212 -138
View File
@@ -266,12 +266,12 @@ static VdbeCursor *allocateCursor(
int nByte;
VdbeCursor *pCx = 0;
nByte =
ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
(eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
assert( iCur>=0 && iCur<p->nCursor );
if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
sqlite3VdbeFreeCursorNN(p, p->apCsr[iCur]);
p->apCsr[iCur] = 0;
}
@@ -301,7 +301,7 @@ static VdbeCursor *allocateCursor(
pCx->aOffset = &pCx->aType[nField];
if( eCurType==CURTYPE_BTREE ){
pCx->uc.pCursor = (BtCursor*)
&pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
&pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
sqlite3BtreeCursorZero(pCx->uc.pCursor);
}
return pCx;
@@ -740,7 +740,7 @@ int sqlite3VdbeExec(
#endif
/*** INSERT STACK UNION HERE ***/
assert( p->iVdbeMagic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlite3_step() verifies this */
sqlite3VdbeEnter(p);
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
if( db->xProgress ){
@@ -983,28 +983,39 @@ case OP_Gosub: { /* jump */
pIn1->flags = MEM_Int;
pIn1->u.i = (int)(pOp-aOp);
REGISTER_TRACE(pOp->p1, pIn1);
/* Most jump operations do a goto to this spot in order to update
** the pOp pointer. */
jump_to_p2:
pOp = &aOp[pOp->p2 - 1];
break;
goto jump_to_p2_and_check_for_interrupt;
}
/* Opcode: Return P1 * P3 * *
/* Opcode: Return P1 P2 P3 * *
**
** Jump to the next instruction after the address in register P1. After
** the jump, register P1 becomes undefined.
** Jump to the address stored in register P1. If P1 is a return address
** register, then this accomplishes a return from a subroutine.
**
** P3 is not used by the byte-code engine. However, the code generator
** sets P3 to address of the associated OP_BeginSubrtn opcode, if there is
** one.
** If P3 is 1, then the jump is only taken if register P1 holds an integer
** values, otherwise execution falls through to the next opcode, and the
** OP_Return becomes a no-op. If P3 is 0, then register P1 must hold an
** integer or else an assert() is raised. P3 should be set to 1 when
** this opcode is used in combination with OP_BeginSubrtn, and set to 0
** otherwise.
**
** The value in register P1 is unchanged by this opcode.
**
** P2 is not used by the byte-code engine. However, if P2 is positive
** and also less than the current address, then the "EXPLAIN" output
** formatter in the CLI will indent all opcodes from the P2 opcode up
** to be not including the current Return. P2 should be the first opcode
** in the subroutine from which this opcode is returnning. Thus the P2
** value is a byte-code indentation hint. See tag-20220407a in
** wherecode.c and shell.c.
*/
case OP_Return: { /* in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags==MEM_Int );
pOp = &aOp[pIn1->u.i];
pIn1->flags = MEM_Undefined;
if( pIn1->flags & MEM_Int ){
if( pOp->p3 ){ VdbeBranchTaken(1, 2); }
pOp = &aOp[pIn1->u.i];
}else if( ALWAYS(pOp->p3) ){
VdbeBranchTaken(0, 2);
}
break;
}
@@ -1027,7 +1038,12 @@ case OP_InitCoroutine: { /* jump */
assert( !VdbeMemDynamic(pOut) );
pOut->u.i = pOp->p3 - 1;
pOut->flags = MEM_Int;
if( pOp->p2 ) goto jump_to_p2;
if( pOp->p2==0 ) break;
/* Most jump operations do a goto to this spot in order to update
** the pOp pointer. */
jump_to_p2:
pOp = &aOp[pOp->p2 - 1];
break;
}
@@ -1129,11 +1145,10 @@ case OP_Halt: {
VdbeFrame *pFrame;
int pcx;
pcx = (int)(pOp - aOp);
#ifdef SQLITE_DEBUG
if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif
if( pOp->p1==SQLITE_OK && p->pFrame ){
if( p->pFrame && pOp->p1==SQLITE_OK ){
/* Halt the sub-program. Return control to the parent frame. */
pFrame = p->pFrame;
p->pFrame = pFrame->pParent;
@@ -1155,7 +1170,6 @@ case OP_Halt: {
}
p->rc = pOp->p1;
p->errorAction = (u8)pOp->p2;
p->pc = pcx;
assert( pOp->p5<=4 );
if( p->rc ){
if( pOp->p5 ){
@@ -1172,6 +1186,7 @@ case OP_Halt: {
}else{
sqlite3VdbeError(p, "%s", pOp->p4.z);
}
pcx = (int)(pOp - aOp);
sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
}
rc = sqlite3VdbeHalt(p);
@@ -1186,22 +1201,11 @@ case OP_Halt: {
goto vdbe_return;
}
/* Opcode: BeginSubrtn P1 P2 * * *
** Synopsis: r[P2]=P1
**
** Mark the beginning of a subroutine by loading the integer value P1
** into register r[P2]. The P2 register is used to store the return
** address of the subroutine call.
**
** This opcode is identical to OP_Integer. It has a different name
** only to make the byte code easier to read and verify.
*/
/* Opcode: Integer P1 P2 * * *
** Synopsis: r[P2]=P1
**
** The 32-bit integer value P1 is written into register P2.
*/
case OP_BeginSubrtn:
case OP_Integer: { /* out2 */
pOut = out2Prerelease(p, pOp);
pOut->u.i = pOp->p1;
@@ -1308,6 +1312,28 @@ case OP_String: { /* out2 */
break;
}
/* Opcode: BeginSubrtn * P2 * * *
** Synopsis: r[P2]=NULL
**
** Mark the beginning of a subroutine that can be entered in-line
** or that can be called using OP_Gosub. The subroutine should
** be terminated by an OP_Return instruction that has a P1 operand that
** is the same as the P2 operand to this opcode and that has P3 set to 1.
** If the subroutine is entered in-line, then the OP_Return will simply
** fall through. But if the subroutine is entered using OP_Gosub, then
** the OP_Return will jump back to the first instruction after the OP_Gosub.
**
** This routine works by loading a NULL into the P2 register. When the
** return address register contains a NULL, the OP_Return instruction is
** a no-op that simply falls through to the next instruction (assuming that
** the OP_Return opcode has a P3 value of 1). Thus if the subroutine is
** entered in-line, then the OP_Return will cause in-line execution to
** continue. But if the subroutine is entered via OP_Gosub, then the
** OP_Return will cause a return to the address following the OP_Gosub.
**
** This opcode is identical to OP_Null. It has a different name
** only to make the byte code easier to read and verify.
*/
/* Opcode: Null P1 P2 P3 * *
** Synopsis: r[P2..P3]=NULL
**
@@ -1320,6 +1346,7 @@ case OP_String: { /* out2 */
** NULL values will not compare equal even if SQLITE_NULLEQ is set on
** OP_Ne or OP_Eq.
*/
case OP_BeginSubrtn:
case OP_Null: { /* out2 */
int cnt;
u16 nullFlag;
@@ -1549,45 +1576,32 @@ case OP_FkCheck: {
** the result row.
*/
case OP_ResultRow: {
Mem *pMem;
int i;
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 || CORRUPT_DB );
assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
/* Invalidate all ephemeral cursor row caches */
p->cacheCtr = (p->cacheCtr + 2)|1;
/* Make sure the results of the current row are \000 terminated
** and have an assigned type. The results are de-ephemeralized as
** a side effect.
*/
pMem = p->pResultSet = &aMem[pOp->p1];
for(i=0; i<pOp->p2; i++){
assert( memIsValid(&pMem[i]) );
Deephemeralize(&pMem[i]);
assert( (pMem[i].flags & MEM_Ephem)==0
|| (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
sqlite3VdbeMemNulTerminate(&pMem[i]);
REGISTER_TRACE(pOp->p1+i, &pMem[i]);
p->pResultSet = &aMem[pOp->p1];
#ifdef SQLITE_DEBUG
/* The registers in the result will not be used again when the
** prepared statement restarts. This is because sqlite3_column()
** APIs might have caused type conversions of made other changes to
** the register values. Therefore, we can go ahead and break any
** OP_SCopy dependencies. */
pMem[i].pScopyFrom = 0;
#endif
{
Mem *pMem = p->pResultSet;
int i;
for(i=0; i<pOp->p2; i++){
assert( memIsValid(&pMem[i]) );
REGISTER_TRACE(pOp->p1+i, &pMem[i]);
/* The registers in the result will not be used again when the
** prepared statement restarts. This is because sqlite3_column()
** APIs might have caused type conversions of made other changes to
** the register values. Therefore, we can go ahead and break any
** OP_SCopy dependencies. */
pMem[i].pScopyFrom = 0;
}
}
#endif
if( db->mallocFailed ) goto no_mem;
if( db->mTrace & SQLITE_TRACE_ROW ){
db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
}
/* Return SQLITE_ROW
*/
p->pc = (int)(pOp - aOp) + 1;
rc = SQLITE_ROW;
goto vdbe_return;
@@ -2101,23 +2115,23 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
assert( (pOp->p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_TEXT || CORRUPT_DB );
/* Common case of comparison of two integers */
if( pIn3->u.i > pIn1->u.i ){
iCompare = +1;
if( sqlite3aGTb[pOp->opcode] ){
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
goto jump_to_p2;
}
iCompare = +1;
}else if( pIn3->u.i < pIn1->u.i ){
iCompare = -1;
if( sqlite3aLTb[pOp->opcode] ){
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
goto jump_to_p2;
}
iCompare = -1;
}else{
iCompare = 0;
if( sqlite3aEQb[pOp->opcode] ){
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
goto jump_to_p2;
}
iCompare = 0;
}
VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
break;
@@ -2144,11 +2158,11 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** then the result is always NULL.
** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
*/
iCompare = 1; /* Operands are not equal */
VdbeBranchTaken(2,3);
if( pOp->p5 & SQLITE_JUMPIFNULL ){
goto jump_to_p2;
}
iCompare = 1; /* Operands are not equal */
break;
}
}else{
@@ -2254,9 +2268,8 @@ case OP_ElseEq: { /* same as TK_ESCAPE, jump */
** Set the permutation used by the OP_Compare operator in the next
** instruction. The permutation is stored in the P4 operand.
**
** The permutation is only valid until the next OP_Compare that has
** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
** occur immediately prior to the OP_Compare.
** The permutation is only valid for the next opcode which must be
** an OP_Compare that has the OPFLAG_PERMUTE bit set in P5.
**
** The first integer in the P4 integer array is the length of the array
** and does not become part of the permutation.
@@ -2288,6 +2301,8 @@ case OP_Permutation: {
** The comparison is a sort comparison, so NULLs compare equal,
** NULLs are less than numbers, numbers are less than strings,
** and strings are less than blobs.
**
** This opcode must be immediately followed by an OP_Jump opcode.
*/
case OP_Compare: {
int n;
@@ -2346,6 +2361,7 @@ case OP_Compare: {
break;
}
}
assert( pOp[1].opcode==OP_Jump );
break;
}
@@ -2354,8 +2370,11 @@ case OP_Compare: {
** Jump to the instruction at address P1, P2, or P3 depending on whether
** in the most recent OP_Compare instruction the P1 vector was less than
** equal to, or greater than the P2 vector, respectively.
**
** This opcode must immediately follow an OP_Compare opcode.
*/
case OP_Jump: { /* jump */
assert( pOp>aOp && pOp[-1].opcode==OP_Compare );
if( iCompare<0 ){
VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1];
}else if( iCompare==0 ){
@@ -2660,7 +2679,7 @@ case OP_Offset: { /* out3 */
#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
/* Opcode: Column P1 P2 P3 P4 P5
** Synopsis: r[P3]=PX
** Synopsis: r[P3]=PX cursor P1 column P2
**
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
@@ -2702,7 +2721,8 @@ case OP_Column: {
op_column_restart:
assert( pC!=0 );
assert( p2<(u32)pC->nField );
assert( p2<(u32)pC->nField
|| (pC->eCurType==CURTYPE_PSEUDO && pC->seekResult==0) );
aOffset = pC->aOffset;
assert( aOffset==pC->aType+pC->nField );
assert( pC->eCurType!=CURTYPE_VTAB );
@@ -2711,10 +2731,9 @@ op_column_restart:
if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/
if( pC->nullRow ){
if( pC->eCurType==CURTYPE_PSEUDO ){
if( pC->eCurType==CURTYPE_PSEUDO && pC->seekResult>0 ){
/* For the special case of as pseudo-cursor, the seekResult field
** identifies the register that holds the record */
assert( pC->seekResult>0 );
pReg = &aMem[pC->seekResult];
assert( pReg->flags & MEM_Blob );
assert( memIsValid(pReg) );
@@ -2752,7 +2771,11 @@ op_column_restart:
assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */
}
pC->cacheStatus = p->cacheCtr;
pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
if( (aOffset[0] = pC->aRow[0])<0x80 ){
pC->iHdrOffset = 1;
}else{
pC->iHdrOffset = sqlite3GetVarint32(pC->aRow, aOffset);
}
pC->nHdrParsed = 0;
if( pC->szRow<aOffset[0] ){ /*OPTIMIZATION-IF-FALSE*/
@@ -3387,18 +3410,60 @@ case OP_MakeRecord: {
zPayload = zHdr + nHdr;
/* Write the record */
zHdr += putVarint32(zHdr, nHdr);
if( nHdr<0x80 ){
*(zHdr++) = nHdr;
}else{
zHdr += sqlite3PutVarint(zHdr,nHdr);
}
assert( pData0<=pLast );
pRec = pData0;
do{
while( 1 /*exit-by-break*/ ){
serial_type = pRec->uTemp;
/* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more
** additional varints, one per column. */
zHdr += putVarint32(zHdr, serial_type); /* serial type */
/* EVIDENCE-OF: R-64536-51728 The values for each column in the record
** additional varints, one per column.
** EVIDENCE-OF: R-64536-51728 The values for each column in the record
** immediately follow the header. */
zPayload += sqlite3VdbeSerialPut(zPayload, pRec, serial_type); /* content */
}while( (++pRec)<=pLast );
if( serial_type<=7 ){
*(zHdr++) = serial_type;
if( serial_type==0 ){
/* NULL value. No change in zPayload */
}else{
u64 v;
u32 i;
if( serial_type==7 ){
assert( sizeof(v)==sizeof(pRec->u.r) );
memcpy(&v, &pRec->u.r, sizeof(v));
swapMixedEndianFloat(v);
}else{
v = pRec->u.i;
}
len = i = sqlite3SmallTypeSizes[serial_type];
assert( i>0 );
while( 1 /*exit-by-break*/ ){
zPayload[--i] = (u8)(v&0xFF);
if( i==0 ) break;
v >>= 8;
}
zPayload += len;
}
}else if( serial_type<0x80 ){
*(zHdr++) = serial_type;
if( serial_type>=14 && pRec->n>0 ){
assert( pRec->z!=0 );
memcpy(zPayload, pRec->z, pRec->n);
zPayload += pRec->n;
}
}else{
zHdr += sqlite3PutVarint(zHdr, serial_type);
if( pRec->n ){
assert( pRec->z!=0 );
memcpy(zPayload, pRec->z, pRec->n);
zPayload += pRec->n;
}
}
if( pRec==pLast ) break;
pRec++;
}
assert( nHdr==(int)(zHdr - (u8*)pOut->z) );
assert( nByte==(int)(zPayload - (u8*)pOut->z) );
@@ -3617,7 +3682,10 @@ case OP_Savepoint: {
}
}
if( rc ) goto abort_due_to_error;
if( p->eVdbeState==VDBE_HALT_STATE ){
rc = SQLITE_DONE;
goto vdbe_return;
}
break;
}
@@ -3721,6 +3789,7 @@ case OP_AutoCommit: {
*/
case OP_Transaction: {
Btree *pBt;
Db *pDb;
int iMeta = 0;
assert( p->bIsReader );
@@ -3740,7 +3809,8 @@ case OP_Transaction: {
}
goto abort_due_to_error;
}
pBt = db->aDb[pOp->p1].pBt;
pDb = &db->aDb[pOp->p1];
pBt = pDb->pBt;
if( pBt ){
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, &iMeta);
@@ -3781,8 +3851,7 @@ case OP_Transaction: {
assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
if( rc==SQLITE_OK
&& pOp->p5
&& (iMeta!=pOp->p3
|| db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i)
&& (iMeta!=pOp->p3 || pDb->pSchema->iGeneration!=pOp->p4.i)
){
/*
** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema
@@ -4925,11 +4994,8 @@ case OP_NoConflict: /* jump, in3 */
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
int alreadyExists;
int takeJump;
int ii;
VdbeCursor *pC;
int res;
UnpackedRecord *pFree;
UnpackedRecord *pIdxKey;
UnpackedRecord r;
@@ -4944,14 +5010,15 @@ case OP_Found: { /* jump, in3 */
#ifdef SQLITE_DEBUG
pC->seekOp = pOp->opcode;
#endif
pIn3 = &aMem[pOp->p3];
r.aMem = &aMem[pOp->p3];
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
assert( pC->isTable==0 );
if( pOp->p4.i>0 ){
r.nField = (u16)pOp->p4.i;
if( r.nField>0 ){
/* Key values in an array of registers */
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p4.i;
r.aMem = pIn3;
r.default_rc = 0;
#ifdef SQLITE_DEBUG
for(ii=0; ii<r.nField; ii++){
assert( memIsValid(&r.aMem[ii]) );
@@ -4959,37 +5026,25 @@ case OP_Found: { /* jump, in3 */
if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]);
}
#endif
pIdxKey = &r;
pFree = 0;
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &pC->seekResult);
}else{
assert( pIn3->flags & MEM_Blob );
rc = ExpandBlob(pIn3);
/* Composite key generated by OP_MakeRecord */
assert( r.aMem->flags & MEM_Blob );
assert( pOp->opcode!=OP_NoConflict );
rc = ExpandBlob(r.aMem);
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
if( rc ) goto no_mem;
pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
if( pIdxKey==0 ) goto no_mem;
sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
sqlite3VdbeRecordUnpack(pC->pKeyInfo, r.aMem->n, r.aMem->z, pIdxKey);
pIdxKey->default_rc = 0;
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &pC->seekResult);
sqlite3DbFreeNN(db, pIdxKey);
}
pIdxKey->default_rc = 0;
takeJump = 0;
if( pOp->opcode==OP_NoConflict ){
/* For the OP_NoConflict opcode, take the jump if any of the
** input fields are NULL, since any key with a NULL will not
** conflict */
for(ii=0; ii<pIdxKey->nField; ii++){
if( pIdxKey->aMem[ii].flags & MEM_Null ){
takeJump = 1;
break;
}
}
}
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &res);
if( pFree ) sqlite3DbFreeNN(db, pFree);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
pC->seekResult = res;
alreadyExists = (res==0);
alreadyExists = (pC->seekResult==0);
pC->nullRow = 1-alreadyExists;
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
@@ -4997,9 +5052,25 @@ case OP_Found: { /* jump, in3 */
VdbeBranchTaken(alreadyExists!=0,2);
if( alreadyExists ) goto jump_to_p2;
}else{
VdbeBranchTaken(takeJump||alreadyExists==0,2);
if( takeJump || !alreadyExists ) goto jump_to_p2;
if( pOp->opcode==OP_IfNoHope ) pC->seekHit = pOp->p4.i;
if( !alreadyExists ){
VdbeBranchTaken(1,2);
goto jump_to_p2;
}
if( pOp->opcode==OP_NoConflict ){
/* For the OP_NoConflict opcode, take the jump if any of the
** input fields are NULL, since any key with a NULL will not
** conflict */
for(ii=0; ii<r.nField; ii++){
if( r.aMem[ii].flags & MEM_Null ){
VdbeBranchTaken(1,2);
goto jump_to_p2;
}
}
}
VdbeBranchTaken(0,2);
if( pOp->opcode==OP_IfNoHope ){
pC->seekHit = pOp->p4.i;
}
}
break;
}
@@ -5690,7 +5761,7 @@ case OP_RowData: {
}
/* Opcode: Rowid P1 P2 * * *
** Synopsis: r[P2]=rowid
** Synopsis: r[P2]=PX rowid of P1
**
** Store in register P2 an integer which is the key of the table entry that
** P1 is currently point to.
@@ -5746,16 +5817,23 @@ case OP_Rowid: { /* out2 */
** that occur while the cursor is on the null row will always
** write a NULL.
**
** Or, if P1 is a Pseudo-Cursor (a cursor opened using OP_OpenPseudo)
** just reset the cache for that cursor. This causes the row of
** content held by the pseudo-cursor to be reparsed.
** If cursor P1 is not previously opened, open it now to a special
** pseudo-cursor that always returns NULL for every column.
*/
case OP_NullRow: {
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
if( pC==0 ){
/* If the cursor is not already open, create a special kind of
** pseudo-cursor that always gives null rows. */
pC = allocateCursor(p, pOp->p1, 1, CURTYPE_PSEUDO);
if( pC==0 ) goto no_mem;
pC->seekResult = 0;
pC->isTable = 1;
pC->uc.pCursor = sqlite3BtreeFakeValidCursor();
}
pC->nullRow = 1;
pC->cacheStatus = CACHE_STALE;
if( pC->eCurType==CURTYPE_BTREE ){
@@ -6202,9 +6280,9 @@ case OP_IdxRowid: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->eCurType==CURTYPE_BTREE || IsNullCursor(pC) );
assert( pC->uc.pCursor!=0 );
assert( pC->isTable==0 );
assert( pC->isTable==0 || IsNullCursor(pC) );
assert( pC->deferredMoveto==0 );
assert( !pC->nullRow || pOp->opcode==OP_IdxRowid );
@@ -7249,6 +7327,7 @@ case OP_AggStep: {
pCtx->pVdbe = p;
pCtx->skipFlag = 0;
pCtx->isError = 0;
pCtx->enc = encoding;
pCtx->argc = n;
pOp->p4type = P4_FUNCCTX;
pOp->p4.pCtx = pCtx;
@@ -7378,9 +7457,6 @@ case OP_AggFinal: {
}
sqlite3VdbeChangeEncoding(pMem, encoding);
UPDATE_MAX_BLOBSIZE(pMem);
if( sqlite3VdbeMemTooBig(pMem) ){
goto too_big;
}
break;
}
@@ -7901,6 +7977,7 @@ case OP_VColumn: {
assert( pModule->xColumn );
memset(&sContext, 0, sizeof(sContext));
sContext.pOut = pDest;
sContext.enc = encoding;
assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
if( pOp->p5 & OPFLAG_NOCHNG ){
sqlite3VdbeMemSetNull(pDest);
@@ -7919,9 +7996,6 @@ case OP_VColumn: {
REGISTER_TRACE(pOp->p3, pDest);
UPDATE_MAX_BLOBSIZE(pDest);
if( sqlite3VdbeMemTooBig(pDest) ){
goto too_big;
}
if( rc ) goto abort_due_to_error;
break;
}
@@ -8188,6 +8262,7 @@ case OP_Function: { /* group */
if( pCtx->pOut != pOut ){
pCtx->pVdbe = p;
pCtx->pOut = pOut;
pCtx->enc = encoding;
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
}
assert( pCtx->pVdbe==p );
@@ -8214,11 +8289,10 @@ case OP_Function: { /* group */
if( rc ) goto abort_due_to_error;
}
/* Copy the result of the function into register P3 */
if( pOut->flags & (MEM_Str|MEM_Blob) ){
sqlite3VdbeChangeEncoding(pOut, encoding);
if( sqlite3VdbeMemTooBig(pOut) ) goto too_big;
}
assert( (pOut->flags&MEM_Str)==0
|| pOut->enc==encoding
|| db->mallocFailed );
assert( !sqlite3VdbeMemTooBig(pOut) );
REGISTER_TRACE(pOp->p3, pOut);
UPDATE_MAX_BLOBSIZE(pOut);
@@ -8344,7 +8418,7 @@ case OP_Init: { /* jump */
#ifndef SQLITE_OMIT_TRACE
if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
&& !p->doingRerun
&& p->minWriteFileFormat!=254 /* tag-20220401a */
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
){
#ifndef SQLITE_OMIT_DEPRECATED
@@ -8573,7 +8647,7 @@ abort_due_to_error:
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(rc, "statement aborts at %d: [%s] %s",
(int)(pOp - aOp), p->zSql, p->zErrMsg);
sqlite3VdbeHalt(p);
if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);
if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){
db->flags |= SQLITE_CorruptRdOnly;
+2 -1
View File
@@ -198,8 +198,10 @@ void sqlite3VdbeEndCoroutine(Vdbe*,int);
#endif
#if defined(SQLITE_DEBUG)
void sqlite3VdbeVerifyAbortable(Vdbe *p, int);
void sqlite3VdbeNoJumpsOutsideSubrtn(Vdbe*,int,int,int);
#else
# define sqlite3VdbeVerifyAbortable(A,B)
# define sqlite3VdbeNoJumpsOutsideSubrtn(A,B,C,D)
#endif
VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
#ifndef SQLITE_OMIT_EXPLAIN
@@ -244,7 +246,6 @@ int sqlite3VdbeMakeLabel(Parse*);
void sqlite3VdbeRunOnlyOnce(Vdbe*);
void sqlite3VdbeReusable(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
+26 -10
View File
@@ -134,6 +134,11 @@ struct VdbeCursor {
u32 aType[1]; /* Type values record decode. MUST BE LAST */
};
/* Return true if P is a null-only cursor
*/
#define IsNullCursor(P) \
((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0)
/*
** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
@@ -369,6 +374,7 @@ struct sqlite3_context {
Vdbe *pVdbe; /* The VM that owns this context */
int iOp; /* Instruction number of OP_Function */
int isError; /* Error code returned by the function. */
u8 enc; /* Encoding to use for results */
u8 skipFlag; /* Skip accumulator loading if true */
u8 argc; /* Number of arguments */
sqlite3_value *argv[1]; /* Argument set */
@@ -417,7 +423,6 @@ struct Vdbe {
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
Parse *pParse; /* Parsing context used to create this Vdbe */
ynVar nVar; /* Number of entries in aVar[] */
u32 iVdbeMagic; /* Magic number defining state of the SQL statement */
int nMem; /* Number of memory locations currently allocated */
int nCursor; /* Number of slots in apCsr[] */
u32 cacheCtr; /* VdbeCursor row cache generation counter */
@@ -455,11 +460,10 @@ struct Vdbe {
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 doingRerun; /* True if rerunning after an auto-reprepare */
u8 eVdbeState; /* On of the VDBE_*_STATE values */
bft expired:2; /* 1: recompile VM immediately 2: when convenient */
bft explain:2; /* True if EXPLAIN present on SQL command */
bft changeCntOn:1; /* True to update the change-counter */
bft runOnlyOnce:1; /* Automatically expire on reset */
bft usesStmtJournal:1; /* True if uses a statement journal */
bft readOnly:1; /* True for statements that do not write */
bft bIsReader:1; /* True for statements that read */
@@ -486,13 +490,12 @@ struct Vdbe {
};
/*
** The following are allowed values for Vdbe.magic
** The following are allowed values for Vdbe.eVdbeState
*/
#define VDBE_MAGIC_INIT 0x16bceaa5 /* Building a VDBE program */
#define VDBE_MAGIC_RUN 0x2df20da3 /* VDBE is ready to execute */
#define VDBE_MAGIC_HALT 0x319c2973 /* VDBE has completed execution */
#define VDBE_MAGIC_RESET 0x48fa9f76 /* Reset and ready to run again */
#define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */
#define VDBE_INIT_STATE 0 /* Prepared statement under construction */
#define VDBE_READY_STATE 1 /* Ready to run but not yet started */
#define VDBE_RUN_STATE 2 /* Run in progress */
#define VDBE_HALT_STATE 3 /* Finished. Need reset() or finalize() */
/*
** Structure used to store the context required by the
@@ -533,18 +536,31 @@ struct ValueList {
sqlite3_value *pOut; /* Register to hold each decoded output value */
};
/* Size of content associated with serial types that fit into a
** single-byte varint.
*/
#ifndef SQLITE_AMALGAMATION
extern const u8 sqlite3SmallTypeSizes[];
#endif
/*
** Function prototypes
*/
void sqlite3VdbeError(Vdbe*, const char *, ...);
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqlite3VdbeFreeCursorNN(Vdbe*,VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
int SQLITE_NOINLINE sqlite3VdbeHandleMovedCursor(VdbeCursor *p);
int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
int sqlite3VdbeCursorRestore(VdbeCursor*);
u32 sqlite3VdbeSerialTypeLen(u32);
u8 sqlite3VdbeOneByteSerialTypeLen(u8);
u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
u64 sqlite3FloatSwap(u64 in);
# define swapMixedEndianFloat(X) X = sqlite3FloatSwap(X)
#else
# define swapMixedEndianFloat(X)
#endif
void sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
+102 -79
View File
@@ -378,7 +378,8 @@ static void setResultStrOrError(
u8 enc, /* Encoding of z. 0 for BLOBs */
void (*xDel)(void*) /* Destructor function */
){
int rc = sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel);
Mem *pOut = pCtx->pOut;
int rc = sqlite3VdbeMemSetStr(pOut, z, n, enc, xDel);
if( rc ){
if( rc==SQLITE_TOOBIG ){
sqlite3_result_error_toobig(pCtx);
@@ -388,6 +389,11 @@ static void setResultStrOrError(
assert( rc==SQLITE_NOMEM );
sqlite3_result_error_nomem(pCtx);
}
return;
}
sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
if( sqlite3VdbeMemTooBig(pOut) ){
sqlite3_result_error_toobig(pCtx);
}
}
static int invokeValueDestructor(
@@ -531,17 +537,22 @@ void sqlite3_result_text16le(
}
#endif /* SQLITE_OMIT_UTF16 */
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
Mem *pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemCopy(pCtx->pOut, pValue);
sqlite3VdbeMemCopy(pOut, pValue);
sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
if( sqlite3VdbeMemTooBig(pOut) ){
sqlite3_result_error_toobig(pCtx);
}
}
void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0);
}
int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
Mem *pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(pCtx);
return SQLITE_TOOBIG;
}
#ifndef SQLITE_OMIT_INCRBLOB
@@ -557,8 +568,8 @@ void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
#endif
if( pCtx->pOut->flags & MEM_Null ){
sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1,
SQLITE_UTF8, SQLITE_STATIC);
setResultStrOrError(pCtx, sqlite3ErrStr(errCode), -1, SQLITE_UTF8,
SQLITE_STATIC);
}
}
@@ -632,80 +643,83 @@ static int sqlite3Step(Vdbe *p){
int rc;
assert(p);
if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){
/* We used to require that sqlite3_reset() be called before retrying
** sqlite3_step() after any error or after SQLITE_DONE. But beginning
** with version 3.7.0, we changed this so that sqlite3_reset() would
** be called automatically instead of throwing the SQLITE_MISUSE error.
** This "automatic-reset" change is not technically an incompatibility,
** since any application that receives an SQLITE_MISUSE is broken by
** definition.
**
** Nevertheless, some published applications that were originally written
** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
** returns, and those were broken by the automatic-reset change. As a
** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
** legacy behavior of returning SQLITE_MISUSE for cases where the
** previous sqlite3_step() returned something other than a SQLITE_LOCKED
** or SQLITE_BUSY error.
*/
#ifdef SQLITE_OMIT_AUTORESET
if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){
sqlite3_reset((sqlite3_stmt*)p);
}else{
return SQLITE_MISUSE_BKPT;
}
#else
sqlite3_reset((sqlite3_stmt*)p);
#endif
}
/* Check that malloc() has not failed. If it has, return early. */
db = p->db;
if( db->mallocFailed ){
p->rc = SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
if( p->eVdbeState!=VDBE_RUN_STATE ){
restart_step:
if( p->eVdbeState==VDBE_READY_STATE ){
if( p->expired ){
p->rc = SQLITE_SCHEMA;
rc = SQLITE_ERROR;
if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
/* If this statement was prepared using saved SQL and an
** error has occurred, then return the error code in p->rc to the
** caller. Set the error code in the database handle to the same
** value.
*/
rc = sqlite3VdbeTransferError(p);
}
goto end_of_step;
}
if( p->pc<0 && p->expired ){
p->rc = SQLITE_SCHEMA;
rc = SQLITE_ERROR;
if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
/* If this statement was prepared using saved SQL and an
** error has occurred, then return the error code in p->rc to the
** caller. Set the error code in the database handle to the same value.
*/
rc = sqlite3VdbeTransferError(p);
}
goto end_of_step;
}
if( p->pc<0 ){
/* If there are no other statements currently running, then
** reset the interrupt flag. This prevents a call to sqlite3_interrupt
** from interrupting a statement that has not yet started.
*/
if( db->nVdbeActive==0 ){
AtomicStore(&db->u1.isInterrupted, 0);
}
/* If there are no other statements currently running, then
** reset the interrupt flag. This prevents a call to sqlite3_interrupt
** from interrupting a statement that has not yet started.
*/
if( db->nVdbeActive==0 ){
AtomicStore(&db->u1.isInterrupted, 0);
}
assert( db->nVdbeWrite>0 || db->autoCommit==0
|| (db->nDeferredCons==0 && db->nDeferredImmCons==0)
);
assert( db->nVdbeWrite>0 || db->autoCommit==0
|| (db->nDeferredCons==0 && db->nDeferredImmCons==0)
);
#ifndef SQLITE_OMIT_TRACE
if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0
&& !db->init.busy && p->zSql ){
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}else{
assert( p->startTime==0 );
}
if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0
&& !db->init.busy && p->zSql ){
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}else{
assert( p->startTime==0 );
}
#endif
db->nVdbeActive++;
if( p->readOnly==0 ) db->nVdbeWrite++;
if( p->bIsReader ) db->nVdbeRead++;
p->pc = 0;
db->nVdbeActive++;
if( p->readOnly==0 ) db->nVdbeWrite++;
if( p->bIsReader ) db->nVdbeRead++;
p->pc = 0;
p->eVdbeState = VDBE_RUN_STATE;
}else
if( ALWAYS(p->eVdbeState==VDBE_HALT_STATE) ){
/* We used to require that sqlite3_reset() be called before retrying
** sqlite3_step() after any error or after SQLITE_DONE. But beginning
** with version 3.7.0, we changed this so that sqlite3_reset() would
** be called automatically instead of throwing the SQLITE_MISUSE error.
** This "automatic-reset" change is not technically an incompatibility,
** since any application that receives an SQLITE_MISUSE is broken by
** definition.
**
** Nevertheless, some published applications that were originally written
** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
** returns, and those were broken by the automatic-reset change. As a
** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
** legacy behavior of returning SQLITE_MISUSE for cases where the
** previous sqlite3_step() returned something other than a SQLITE_LOCKED
** or SQLITE_BUSY error.
*/
#ifdef SQLITE_OMIT_AUTORESET
if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){
sqlite3_reset((sqlite3_stmt*)p);
}else{
return SQLITE_MISUSE_BKPT;
}
#else
sqlite3_reset((sqlite3_stmt*)p);
#endif
assert( p->eVdbeState==VDBE_READY_STATE );
goto restart_step;
}
}
#ifdef SQLITE_DEBUG
p->rcApp = SQLITE_OK;
#endif
@@ -720,7 +734,12 @@ static int sqlite3Step(Vdbe *p){
db->nVdbeExec--;
}
if( rc!=SQLITE_ROW ){
if( rc==SQLITE_ROW ){
assert( p->rc==SQLITE_OK );
assert( db->mallocFailed==0 );
db->errCode = SQLITE_ROW;
return SQLITE_ROW;
}else{
#ifndef SQLITE_OMIT_TRACE
/* If the statement completed successfully, invoke the profile callback */
checkProfileCallback(db, p);
@@ -772,7 +791,6 @@ int sqlite3_step(sqlite3_stmt *pStmt){
}
db = v->db;
sqlite3_mutex_enter(db->mutex);
v->doingRerun = 0;
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
int savedPc = v->pc;
@@ -798,7 +816,13 @@ int sqlite3_step(sqlite3_stmt *pStmt){
break;
}
sqlite3_reset(pStmt);
if( savedPc>=0 ) v->doingRerun = 1;
if( savedPc>=0 ){
/* Setting minWriteFileFormat to 254 is a signal to the OP_Init and
** OP_Trace opcodes to *not* perform SQLITE_TRACE_STMT because one
** should output has already occurred due to SQLITE_SCHEMA.
** tag-20220401a */
v->minWriteFileFormat = 254;
}
assert( v->expired==0 );
}
sqlite3_mutex_leave(db->mutex);
@@ -1412,7 +1436,7 @@ static int vdbeUnbind(Vdbe *p, int i){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(p->db->mutex);
if( p->iVdbeMagic!=VDBE_MAGIC_RUN || p->pc>=0 ){
if( p->eVdbeState!=VDBE_READY_STATE ){
sqlite3Error(p->db, SQLITE_MISUSE);
sqlite3_mutex_leave(p->db->mutex);
sqlite3_log(SQLITE_MISUSE,
@@ -1765,7 +1789,7 @@ int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){
*/
int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt;
return v!=0 && v->iVdbeMagic==VDBE_MAGIC_RUN && v->pc>=0;
return v!=0 && v->eVdbeState==VDBE_RUN_STATE;
}
/*
@@ -1811,8 +1835,7 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
sqlite3_mutex_enter(db->mutex);
v = 0;
db->pnBytesFreed = (int*)&v;
sqlite3VdbeClearObject(db, pVdbe);
sqlite3DbFree(db, pVdbe);
sqlite3VdbeDelete(pVdbe);
db->pnBytesFreed = 0;
sqlite3_mutex_leave(db->mutex);
}else{
+190 -140
View File
@@ -35,7 +35,7 @@ Vdbe *sqlite3VdbeCreate(Parse *pParse){
p->pNext = db->pVdbe;
p->pPrev = 0;
db->pVdbe = p;
p->iVdbeMagic = VDBE_MAGIC_INIT;
assert( p->eVdbeState==VDBE_INIT_STATE );
p->pParse = pParse;
pParse->pVdbe = p;
assert( pParse->aLabel==0 );
@@ -236,7 +236,7 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
VdbeOp *pOp;
i = p->nOp;
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
assert( p->eVdbeState==VDBE_INIT_STATE );
assert( op>=0 && op<0xff );
if( p->nOpAlloc<=i ){
return growOp3(p, op, p1, p2, p3);
@@ -568,7 +568,7 @@ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){
void sqlite3VdbeResolveLabel(Vdbe *v, int x){
Parse *p = v->pParse;
int j = ADDR(x);
assert( v->iVdbeMagic==VDBE_MAGIC_INIT );
assert( v->eVdbeState==VDBE_INIT_STATE );
assert( j<-p->nLabel );
assert( j>=0 );
#ifdef SQLITE_DEBUG
@@ -588,14 +588,20 @@ void sqlite3VdbeResolveLabel(Vdbe *v, int x){
** Mark the VDBE as one that can only be run one time.
*/
void sqlite3VdbeRunOnlyOnce(Vdbe *p){
p->runOnlyOnce = 1;
sqlite3VdbeAddOp2(p, OP_Expire, 1, 1);
}
/*
** Mark the VDBE as one that can only be run multiple times.
*/
void sqlite3VdbeReusable(Vdbe *p){
p->runOnlyOnce = 0;
int i;
for(i=1; ALWAYS(i<p->nOp); i++){
if( ALWAYS(p->aOp[i].opcode==OP_Expire) ){
p->aOp[1].opcode = OP_Noop;
break;
}
}
}
#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
@@ -699,6 +705,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
int hasInitCoroutine = 0;
Op *pOp;
VdbeOpIter sIter;
if( v==0 ) return 0;
memset(&sIter, 0, sizeof(sIter));
sIter.v = v;
@@ -863,18 +871,104 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
if( pOp==p->aOp ) break;
pOp--;
}
sqlite3DbFree(p->db, pParse->aLabel);
pParse->aLabel = 0;
if( aLabel ){
sqlite3DbFreeNN(p->db, pParse->aLabel);
pParse->aLabel = 0;
}
pParse->nLabel = 0;
*pMaxFuncArgs = nMaxArgs;
assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
}
#ifdef SQLITE_DEBUG
/*
** Check to see if a subroutine contains a jump to a location outside of
** the subroutine. If a jump outside the subroutine is detected, add code
** that will cause the program to halt with an error message.
**
** The subroutine consists of opcodes between iFirst and iLast. Jumps to
** locations within the subroutine are acceptable. iRetReg is a register
** that contains the return address. Jumps to outside the range of iFirst
** through iLast are also acceptable as long as the jump destination is
** an OP_Return to iReturnAddr.
**
** A jump to an unresolved label means that the jump destination will be
** beyond the current address. That is normally a jump to an early
** termination and is consider acceptable.
**
** This routine only runs during debug builds. The purpose is (of course)
** to detect invalid escapes out of a subroutine. The OP_Halt opcode
** is generated rather than an assert() or other error, so that ".eqp full"
** will still work to show the original bytecode, to aid in debugging.
*/
void sqlite3VdbeNoJumpsOutsideSubrtn(
Vdbe *v, /* The byte-code program under construction */
int iFirst, /* First opcode of the subroutine */
int iLast, /* Last opcode of the subroutine */
int iRetReg /* Subroutine return address register */
){
VdbeOp *pOp;
Parse *pParse;
int i;
sqlite3_str *pErr = 0;
assert( v!=0 );
pParse = v->pParse;
assert( pParse!=0 );
if( pParse->nErr ) return;
assert( iLast>=iFirst );
assert( iLast<v->nOp );
pOp = &v->aOp[iFirst];
for(i=iFirst; i<=iLast; i++, pOp++){
if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ){
int iDest = pOp->p2; /* Jump destination */
if( iDest==0 ) continue;
if( pOp->opcode==OP_Gosub ) continue;
if( iDest<0 ){
int j = ADDR(iDest);
assert( j>=0 );
if( j>=-pParse->nLabel || pParse->aLabel[j]<0 ){
continue;
}
iDest = pParse->aLabel[j];
}
if( iDest<iFirst || iDest>iLast ){
int j = iDest;
for(; j<v->nOp; j++){
VdbeOp *pX = &v->aOp[j];
if( pX->opcode==OP_Return ){
if( pX->p1==iRetReg ) break;
continue;
}
if( pX->opcode==OP_Noop ) continue;
if( pX->opcode==OP_Explain ) continue;
if( pErr==0 ){
pErr = sqlite3_str_new(0);
}else{
sqlite3_str_appendchar(pErr, 1, '\n');
}
sqlite3_str_appendf(pErr,
"Opcode at %d jumps to %d which is outside the "
"subroutine at %d..%d",
i, iDest, iFirst, iLast);
break;
}
}
}
}
if( pErr ){
char *zErr = sqlite3_str_finish(pErr);
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_INTERNAL, OE_Abort, 0, zErr, 0);
sqlite3_free(zErr);
sqlite3MayAbort(pParse);
}
}
#endif /* SQLITE_DEBUG */
/*
** Return the address of the next instruction to be inserted.
*/
int sqlite3VdbeCurrentAddr(Vdbe *p){
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
assert( p->eVdbeState==VDBE_INIT_STATE );
return p->nOp;
}
@@ -959,7 +1053,7 @@ VdbeOp *sqlite3VdbeAddOpList(
int i;
VdbeOp *pOut, *pFirst;
assert( nOp>0 );
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
assert( p->eVdbeState==VDBE_INIT_STATE );
if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){
return 0;
}
@@ -1150,13 +1244,16 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
** nOp entries.
*/
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
assert( nOp>=0 );
if( aOp ){
Op *pOp;
for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
Op *pOp = &aOp[nOp-1];
while(1){ /* Exit via break */
if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
sqlite3DbFree(db, pOp->zComment);
#endif
if( pOp==aOp ) break;
pOp--;
}
sqlite3DbFreeNN(db, aOp);
}
@@ -1218,7 +1315,7 @@ void sqlite3VdbeReleaseRegisters(
u32 mask, /* Mask of registers to NOT release */
int bUndefine /* If true, mark registers as undefined */
){
if( N==0 ) return;
if( N==0 || OptimizationDisabled(pParse->db, SQLITE_ReleaseReg) ) return;
assert( pParse->pVdbe );
assert( iFirst>=1 );
assert( iFirst+N-1<=pParse->nMem );
@@ -1282,7 +1379,7 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
sqlite3 *db;
assert( p!=0 );
db = p->db;
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
assert( p->eVdbeState==VDBE_INIT_STATE );
assert( p->aOp!=0 || db->mallocFailed );
if( db->mallocFailed ){
if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);
@@ -1410,7 +1507,7 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
/* C89 specifies that the constant "dummy" will be initialized to all
** zeros, which is correct. MSVC generates a warning, nevertheless. */
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
assert( p->eVdbeState==VDBE_INIT_STATE );
if( addr<0 ){
addr = p->nOp - 1;
}
@@ -1477,8 +1574,13 @@ char *sqlite3VdbeDisplayComment(
if( c=='4' ){
sqlite3_str_appendall(&x, zP4);
}else if( c=='X' ){
sqlite3_str_appendall(&x, pOp->zComment);
if( pOp->zComment && pOp->zComment[0] ){
sqlite3_str_appendall(&x, pOp->zComment);
}else{
sqlite3_str_appendall(&x, zSynopsis+1);
}
seenCom = 1;
break;
}else{
int v1 = translateP(c, pOp);
int v2;
@@ -2073,7 +2175,7 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){
VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem];
assert( sqlite3VdbeFrameIsValid(p) );
for(i=0; i<p->nChildCsr; i++){
sqlite3VdbeFreeCursor(p->v, apCsr[i]);
if( apCsr[i] ) sqlite3VdbeFreeCursorNN(p->v, apCsr[i]);
}
releaseMemArray(aMem, p->nChildMem);
sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0);
@@ -2112,7 +2214,7 @@ int sqlite3VdbeList(
Op *pOp; /* Current opcode */
assert( p->explain );
assert( p->iVdbeMagic==VDBE_MAGIC_RUN );
assert( p->eVdbeState==VDBE_RUN_STATE );
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM );
/* Even though this opcode does not use dynamic strings for
@@ -2267,11 +2369,11 @@ struct ReusableSpace {
static void *allocSpace(
struct ReusableSpace *p, /* Bulk memory available for allocation */
void *pBuf, /* Pointer to a prior allocation */
sqlite3_int64 nByte /* Bytes of memory needed */
sqlite3_int64 nByte /* Bytes of memory needed. */
){
assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) );
if( pBuf==0 ){
nByte = ROUND8(nByte);
nByte = ROUND8P(nByte);
if( nByte <= p->nFree ){
p->nFree -= nByte;
pBuf = &p->pSpace[p->nFree];
@@ -2292,14 +2394,15 @@ void sqlite3VdbeRewind(Vdbe *p){
int i;
#endif
assert( p!=0 );
assert( p->iVdbeMagic==VDBE_MAGIC_INIT || p->iVdbeMagic==VDBE_MAGIC_RESET );
assert( p->eVdbeState==VDBE_INIT_STATE
|| p->eVdbeState==VDBE_READY_STATE
|| p->eVdbeState==VDBE_HALT_STATE );
/* There should be at least one opcode.
*/
assert( p->nOp>0 );
/* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
p->iVdbeMagic = VDBE_MAGIC_RUN;
p->eVdbeState = VDBE_READY_STATE;
#ifdef SQLITE_DEBUG
for(i=0; i<p->nMem; i++){
@@ -2355,7 +2458,7 @@ void sqlite3VdbeMakeReady(
assert( p!=0 );
assert( p->nOp>0 );
assert( pParse!=0 );
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
assert( p->eVdbeState==VDBE_INIT_STATE );
assert( pParse==p->pParse );
p->pVList = pParse->pVList;
pParse->pVList = 0;
@@ -2378,7 +2481,7 @@ void sqlite3VdbeMakeReady(
** opcode array. This extra memory will be reallocated for other elements
** of the prepared statement.
*/
n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */
n = ROUND8P(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */
x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */
assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */
@@ -2466,9 +2569,9 @@ void sqlite3VdbeMakeReady(
** happens to hold.
*/
void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx==0 ){
return;
}
if( pCx ) sqlite3VdbeFreeCursorNN(p,pCx);
}
void sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){
switch( pCx->eCurType ){
case CURTYPE_SORTER: {
sqlite3VdbeSorterClose(p->db, pCx);
@@ -2496,14 +2599,12 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
** Close all cursors in the current frame.
*/
static void closeCursorsInFrame(Vdbe *p){
if( p->apCsr ){
int i;
for(i=0; i<p->nCursor; i++){
VdbeCursor *pC = p->apCsr[i];
if( pC ){
sqlite3VdbeFreeCursor(p, pC);
p->apCsr[i] = 0;
}
int i;
for(i=0; i<p->nCursor; i++){
VdbeCursor *pC = p->apCsr[i];
if( pC ){
sqlite3VdbeFreeCursorNN(p, pC);
p->apCsr[i] = 0;
}
}
}
@@ -2552,9 +2653,7 @@ static void closeAllCursors(Vdbe *p){
}
assert( p->nFrame==0 );
closeCursorsInFrame(p);
if( p->aMem ){
releaseMemArray(p->aMem, p->nMem);
}
releaseMemArray(p->aMem, p->nMem);
while( p->pDelFrame ){
VdbeFrame *pDel = p->pDelFrame;
p->pDelFrame = pDel->pParent;
@@ -2994,6 +3093,7 @@ int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
p->errorAction = OE_Abort;
sqlite3VdbeError(p, "FOREIGN KEY constraint failed");
if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR;
return SQLITE_CONSTRAINT_FOREIGNKEY;
}
return SQLITE_OK;
@@ -3033,9 +3133,7 @@ int sqlite3VdbeHalt(Vdbe *p){
** one, or the complete transaction if there is no statement transaction.
*/
if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){
return SQLITE_OK;
}
assert( p->eVdbeState==VDBE_RUN_STATE );
if( db->mallocFailed ){
p->rc = SQLITE_NOMEM_BKPT;
}
@@ -3044,7 +3142,7 @@ int sqlite3VdbeHalt(Vdbe *p){
/* No commit or rollback needed if the program never started or if the
** SQL statement does not read or write a database file. */
if( p->pc>=0 && p->bIsReader ){
if( p->bIsReader ){
int mrc; /* Primary error code from p->rc */
int eStatementOp = 0;
int isSpecialError; /* Set to true if a 'special' error */
@@ -3192,15 +3290,13 @@ int sqlite3VdbeHalt(Vdbe *p){
}
/* We have successfully halted and closed the VM. Record this fact. */
if( p->pc>=0 ){
db->nVdbeActive--;
if( !p->readOnly ) db->nVdbeWrite--;
if( p->bIsReader ) db->nVdbeRead--;
assert( db->nVdbeActive>=db->nVdbeRead );
assert( db->nVdbeRead>=db->nVdbeWrite );
assert( db->nVdbeWrite>=0 );
}
p->iVdbeMagic = VDBE_MAGIC_HALT;
db->nVdbeActive--;
if( !p->readOnly ) db->nVdbeWrite--;
if( p->bIsReader ) db->nVdbeRead--;
assert( db->nVdbeActive>=db->nVdbeRead );
assert( db->nVdbeRead>=db->nVdbeWrite );
assert( db->nVdbeWrite>=0 );
p->eVdbeState = VDBE_HALT_STATE;
checkActiveVdbeCnt(db);
if( db->mallocFailed ){
p->rc = SQLITE_NOMEM_BKPT;
@@ -3282,8 +3378,8 @@ static void vdbeInvokeSqllog(Vdbe *v){
** again.
**
** To look at it another way, this routine resets the state of the
** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to
** VDBE_MAGIC_INIT.
** virtual machine from VDBE_RUN_STATE or VDBE_HALT_STATE back to
** VDBE_READY_STATE.
*/
int sqlite3VdbeReset(Vdbe *p){
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
@@ -3297,7 +3393,7 @@ int sqlite3VdbeReset(Vdbe *p){
** error, then it might not have been halted properly. So halt
** it now.
*/
sqlite3VdbeHalt(p);
if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);
/* If the VDBE has been run even partially, then transfer the error code
** and error message from the VDBE into the main database structure. But
@@ -3311,13 +3407,6 @@ int sqlite3VdbeReset(Vdbe *p){
}else{
db->errCode = p->rc;
}
if( p->runOnlyOnce ) p->expired = 1;
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call
** to sqlite3_step(). For consistency (since sqlite3_step() was
** called), set the database error in this case as well.
*/
sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
}
/* Reset register contents and reclaim error message memory.
@@ -3374,7 +3463,6 @@ int sqlite3VdbeReset(Vdbe *p){
}
}
#endif
p->iVdbeMagic = VDBE_MAGIC_RESET;
return p->rc & db->errMask;
}
@@ -3384,7 +3472,10 @@ int sqlite3VdbeReset(Vdbe *p){
*/
int sqlite3VdbeFinalize(Vdbe *p){
int rc = SQLITE_OK;
if( p->iVdbeMagic==VDBE_MAGIC_RUN || p->iVdbeMagic==VDBE_MAGIC_HALT ){
assert( VDBE_RUN_STATE>VDBE_READY_STATE );
assert( VDBE_HALT_STATE>VDBE_READY_STATE );
assert( VDBE_INIT_STATE<VDBE_READY_STATE );
if( p->eVdbeState>=VDBE_READY_STATE ){
rc = sqlite3VdbeReset(p);
assert( (rc & p->db->errMask)==rc );
}
@@ -3436,22 +3527,24 @@ void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
** the database connection and frees the object itself.
*/
void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
assert( p->db==0 || p->db==db );
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
if( p->aColName ){
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqlite3DbFreeNN(db, p->aColName);
}
for(pSub=p->pProgram; pSub; pSub=pNext){
pNext = pSub->pNext;
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
sqlite3DbFree(db, pSub);
}
if( p->iVdbeMagic!=VDBE_MAGIC_INIT ){
if( p->eVdbeState!=VDBE_INIT_STATE ){
releaseMemArray(p->aVar, p->nVar);
sqlite3DbFree(db, p->pVList);
sqlite3DbFree(db, p->pFree);
if( p->pVList ) sqlite3DbFreeNN(db, p->pVList);
if( p->pFree ) sqlite3DbFreeNN(db, p->pFree);
}
vdbeFreeOpArray(db, p->aOp, p->nOp);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
#ifdef SQLITE_ENABLE_NORMALIZE
sqlite3DbFree(db, p->zNormSql);
@@ -3484,17 +3577,17 @@ void sqlite3VdbeDelete(Vdbe *p){
db = p->db;
assert( sqlite3_mutex_held(db->mutex) );
sqlite3VdbeClearObject(db, p);
if( p->pPrev ){
p->pPrev->pNext = p->pNext;
}else{
assert( db->pVdbe==p );
db->pVdbe = p->pNext;
if( db->pnBytesFreed==0 ){
if( p->pPrev ){
p->pPrev->pNext = p->pNext;
}else{
assert( db->pVdbe==p );
db->pVdbe = p->pNext;
}
if( p->pNext ){
p->pNext->pPrev = p->pPrev;
}
}
if( p->pNext ){
p->pNext->pPrev = p->pPrev;
}
p->iVdbeMagic = VDBE_MAGIC_DEAD;
p->db = 0;
sqlite3DbFreeNN(db, p);
}
@@ -3545,7 +3638,7 @@ int SQLITE_NOINLINE sqlite3VdbeHandleMovedCursor(VdbeCursor *p){
** if need be. Return any I/O error from the restore operation.
*/
int sqlite3VdbeCursorRestore(VdbeCursor *p){
assert( p->eCurType==CURTYPE_BTREE );
assert( p->eCurType==CURTYPE_BTREE || IsNullCursor(p) );
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
return sqlite3VdbeHandleMovedCursor(p);
}
@@ -3558,7 +3651,7 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
** sqlite3VdbeSerialType()
** sqlite3VdbeSerialTypeLen()
** sqlite3VdbeSerialLen()
** sqlite3VdbeSerialPut()
** sqlite3VdbeSerialPut() <--- in-lined into OP_MakeRecord as of 2022-04-02
** sqlite3VdbeSerialGet()
**
** encapsulate the code that serializes values for storage in SQLite
@@ -3670,7 +3763,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
/*
** The sizes for serial types less than 128
*/
static const u8 sqlite3SmallTypeSizes[] = {
const u8 sqlite3SmallTypeSizes[128] = {
/* 0 1 2 3 4 5 6 7 8 9 */
/* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0,
/* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
@@ -3739,7 +3832,7 @@ u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
** so we trust him.
*/
#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
static u64 floatSwap(u64 in){
u64 sqlite3FloatSwap(u64 in){
union {
u64 r;
u32 i[2];
@@ -3752,59 +3845,8 @@ static u64 floatSwap(u64 in){
u.i[1] = t;
return u.r;
}
# define swapMixedEndianFloat(X) X = floatSwap(X)
#else
# define swapMixedEndianFloat(X)
#endif
#endif /* SQLITE_MIXED_ENDIAN_64BIT_FLOAT */
/*
** Write the serialized data blob for the value stored in pMem into
** buf. It is assumed that the caller has allocated sufficient space.
** Return the number of bytes written.
**
** nBuf is the amount of space left in buf[]. The caller is responsible
** for allocating enough space to buf[] to hold the entire field, exclusive
** of the pMem->u.nZero bytes for a MEM_Zero value.
**
** Return the number of bytes actually written into buf[]. The number
** of bytes in the zero-filled tail is included in the return value only
** if those bytes were zeroed in buf[].
*/
u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
u32 len;
/* Integer and Real */
if( serial_type<=7 && serial_type>0 ){
u64 v;
u32 i;
if( serial_type==7 ){
assert( sizeof(v)==sizeof(pMem->u.r) );
memcpy(&v, &pMem->u.r, sizeof(v));
swapMixedEndianFloat(v);
}else{
v = pMem->u.i;
}
len = i = sqlite3SmallTypeSizes[serial_type];
assert( i>0 );
do{
buf[--i] = (u8)(v&0xFF);
v >>= 8;
}while( i );
return len;
}
/* String or blob */
if( serial_type>=12 ){
assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
== (int)sqlite3VdbeSerialTypeLen(serial_type) );
len = pMem->n;
if( len>0 ) memcpy(buf, pMem->z, len);
return len;
}
/* NULL or constants 0 or 1 */
return 0;
}
/* Input "x" is a sequence of unsigned characters that represent a
** big-endian integer. Return the equivalent native integer
@@ -3970,10 +4012,10 @@ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
){
UnpackedRecord *p; /* Unpacked record to return */
int nByte; /* Number of bytes required for *p */
nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
if( !p ) return 0;
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
p->aMem = (Mem*)&((char*)p)[ROUND8P(sizeof(UnpackedRecord))];
assert( pKeyInfo->aSortFlags!=0 );
p->pKeyInfo = pKeyInfo;
p->nField = pKeyInfo->nKeyField + 1;
@@ -4471,14 +4513,22 @@ int sqlite3VdbeRecordCompareWithSkip(
** two elements in the keys are equal. Fix the various stack variables so
** that this routine begins comparing at the second field. */
if( bSkip ){
u32 s1;
idx1 = 1 + getVarint32(&aKey1[1], s1);
u32 s1 = aKey1[1];
if( s1<0x80 ){
idx1 = 2;
}else{
idx1 = 1 + sqlite3GetVarint32(&aKey1[1], &s1);
}
szHdr1 = aKey1[0];
d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1);
i = 1;
pRhs++;
}else{
idx1 = getVarint32(aKey1, szHdr1);
if( (szHdr1 = aKey1[0])<0x80 ){
idx1 = 1;
}else{
idx1 = sqlite3GetVarint32(aKey1, &szHdr1);
}
d1 = szHdr1;
i = 0;
}
+39 -22
View File
@@ -204,7 +204,11 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
|| desiredEnc==SQLITE_UTF16BE );
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
if( !(pMem->flags&MEM_Str) ){
pMem->enc = desiredEnc;
return SQLITE_OK;
}
if( pMem->enc==desiredEnc ){
return SQLITE_OK;
}
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
@@ -453,9 +457,10 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
Mem t;
assert( pFunc!=0 );
assert( pMem!=0 );
assert( pMem->db!=0 );
assert( pFunc->xFinalize!=0 );
assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( sqlite3_mutex_held(pMem->db->mutex) );
memset(&ctx, 0, sizeof(ctx));
memset(&t, 0, sizeof(t));
t.flags = MEM_Null;
@@ -463,6 +468,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
ctx.pOut = &t;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
ctx.enc = ENC(t.db);
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
assert( (pMem->flags & MEM_Dyn)==0 );
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
@@ -484,12 +490,14 @@ int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){
assert( pFunc!=0 );
assert( pFunc->xValue!=0 );
assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef );
assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) );
assert( pAccum->db!=0 );
assert( sqlite3_mutex_held(pAccum->db->mutex) );
memset(&ctx, 0, sizeof(ctx));
sqlite3VdbeMemSetNull(pOut);
ctx.pOut = pOut;
ctx.pMem = pAccum;
ctx.pFunc = pFunc;
ctx.enc = ENC(pAccum->db);
pFunc->xValue(&ctx);
return ctx.isError;
}
@@ -1107,6 +1115,13 @@ void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
** stored without allocating memory, then it is. If a memory allocation
** is required to store the string, then value of pMem is unchanged. In
** either case, SQLITE_TOOBIG is returned.
**
** The "enc" parameter is the text encoding for the string, or zero
** to store a blob.
**
** If n is negative, then the string consists of all bytes up to but
** excluding the first zero character. The n parameter must be
** non-negative for blobs.
*/
int sqlite3VdbeMemSetStr(
Mem *pMem, /* Memory cell to set to string value */
@@ -1117,11 +1132,12 @@ int sqlite3VdbeMemSetStr(
){
i64 nByte = n; /* New value for pMem->n */
int iLimit; /* Maximum allowed string or blob size */
u16 flags = 0; /* New value for pMem->flags */
u16 flags; /* New value for pMem->flags */
assert( pMem!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( enc!=0 || n>=0 );
/* If z is a NULL pointer, set pMem to contain an SQL NULL. */
if( !z ){
@@ -1134,7 +1150,6 @@ int sqlite3VdbeMemSetStr(
}else{
iLimit = SQLITE_MAX_LENGTH;
}
flags = (enc==0?MEM_Blob:MEM_Str);
if( nByte<0 ){
assert( enc!=0 );
if( enc==SQLITE_UTF8 ){
@@ -1142,7 +1157,23 @@ int sqlite3VdbeMemSetStr(
}else{
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
}
flags |= MEM_Term;
flags= MEM_Str|MEM_Term;
}else if( enc==0 ){
flags = MEM_Blob;
enc = SQLITE_UTF8;
}else{
flags = MEM_Str;
}
if( nByte>iLimit ){
if( xDel && xDel!=SQLITE_TRANSIENT ){
if( xDel==SQLITE_DYNAMIC ){
sqlite3DbFree(pMem->db, (void*)z);
}else{
xDel((void*)z);
}
}
sqlite3VdbeMemSetNull(pMem);
return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
}
/* The following block sets the new values of Mem.z and Mem.xDel. It
@@ -1154,9 +1185,6 @@ int sqlite3VdbeMemSetStr(
if( flags&MEM_Term ){
nAlloc += (enc==SQLITE_UTF8?1:2);
}
if( nByte>iLimit ){
return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
}
testcase( nAlloc==0 );
testcase( nAlloc==31 );
testcase( nAlloc==32 );
@@ -1178,16 +1206,7 @@ int sqlite3VdbeMemSetStr(
pMem->n = (int)(nByte & 0x7fffffff);
pMem->flags = flags;
if( enc ){
pMem->enc = enc;
#ifdef SQLITE_ENABLE_SESSION
}else if( pMem->db==0 ){
pMem->enc = SQLITE_UTF8;
#endif
}else{
assert( pMem->db!=0 );
pMem->enc = ENC(pMem->db);
}
pMem->enc = enc;
#ifndef SQLITE_OMIT_UTF16
if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
@@ -1195,9 +1214,6 @@ int sqlite3VdbeMemSetStr(
}
#endif
if( nByte>iLimit ){
return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
}
return SQLITE_OK;
}
@@ -1479,6 +1495,7 @@ static int valueFromFunction(
memset(&ctx, 0, sizeof(ctx));
ctx.pOut = pVal;
ctx.pFunc = pFunc;
ctx.enc = ENC(db);
pFunc->xSFunc(&ctx, nVal, apVal);
if( ctx.isError ){
rc = ctx.isError;
+185 -72
View File
@@ -102,7 +102,7 @@ int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){
}
pInner = &pWInfo->a[pWInfo->nLevel-1];
assert( pInner->addrNxt!=0 );
return pInner->addrNxt;
return pInner->pRJ ? pWInfo->iContinue : pInner->addrNxt;
}
/*
@@ -253,6 +253,30 @@ Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){
return 0;
}
/* Allocate memory that is automatically freed when pWInfo is freed.
*/
void *sqlite3WhereMalloc(WhereInfo *pWInfo, u64 nByte){
WhereMemBlock *pBlock;
pBlock = sqlite3DbMallocRawNN(pWInfo->pParse->db, nByte+sizeof(*pBlock));
if( pBlock ){
pBlock->pNext = pWInfo->pMemToFree;
pBlock->sz = nByte;
pWInfo->pMemToFree = pBlock;
pBlock++;
}
return (void*)pBlock;
}
void *sqlite3WhereRealloc(WhereInfo *pWInfo, void *pOld, u64 nByte){
void *pNew = sqlite3WhereMalloc(pWInfo, nByte);
if( pNew && pOld ){
WhereMemBlock *pOldBlk = (WhereMemBlock*)pOld;
pOldBlk--;
assert( pOldBlk->sz<nByte );
memcpy(pNew, pOld, pOldBlk->sz);
}
return pNew;
}
/*
** Create a new mask for cursor iCursor.
**
@@ -732,13 +756,13 @@ static int termCanDriveIndex(
char aff;
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
if( (pSrc->fg.jointype & JT_LEFT)
if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
&& (pTerm->eOperator & WO_IS)
){
/* Cannot use an IS term from the WHERE clause as an index driver for
** the RHS of a LEFT JOIN. Such a term can only be used if it is from
** the ON clause. */
** the RHS of a LEFT JOIN or for the LHS of a RIGHT JOIN. Such a term
** can only be used if it is from the ON clause. */
return 0;
}
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
@@ -808,8 +832,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** WHERE clause (or the ON clause of a LEFT join) that constrain which
** rows of the target table (pSrc) that can be used. */
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
&& ((pSrc->fg.jointype&JT_LEFT)==0 || ExprHasProperty(pExpr,EP_FromJoin))
&& sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor)
&& sqlite3ExprIsTableConstraint(pExpr, pSrc)
){
pPartial = sqlite3ExprAnd(pParse, pPartial,
sqlite3ExprDup(pParse->db, pExpr, 0));
@@ -1048,7 +1071,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
Expr *pExpr = pTerm->pExpr;
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
&& sqlite3ExprIsTableConstant(pExpr, iCur)
&& sqlite3ExprIsTableConstraint(pExpr, pItem)
){
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
}
@@ -1081,7 +1104,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
const SrcItem *pTabItem;
pLevel = &pWInfo->a[iLevel];
pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
if( pTabItem->fg.jointype & JT_LEFT ) continue;
if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue;
pLoop = pLevel->pWLoop;
if( NEVER(pLoop==0) ) continue;
if( pLoop->prereq & notReady ) continue;
@@ -1154,9 +1177,10 @@ static sqlite3_index_info *allocateIndexInfo(
assert( pTerm->u.x.leftColumn<pTab->nCol );
/* tag-20191211-002: WHERE-clause constraints are not useful to the
** right-hand table of a LEFT JOIN. See tag-20191211-001 for the
** right-hand table of a LEFT JOIN nor to the left-hand table of a
** RIGHT JOIN. See tag-20191211-001 for the
** equivalent restriction for ordinary tables. */
if( (pSrc->fg.jointype & JT_LEFT)!=0
if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
){
continue;
@@ -2216,15 +2240,7 @@ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
** Free a WhereInfo structure
*/
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
int i;
assert( pWInfo!=0 );
for(i=0; i<pWInfo->nLevel; i++){
WhereLevel *pLevel = &pWInfo->a[i];
if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE)!=0 ){
assert( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0 );
sqlite3DbFree(db, pLevel->u.in.aInLoop);
}
}
sqlite3WhereClauseClear(&pWInfo->sWC);
while( pWInfo->pLoops ){
WhereLoop *p = pWInfo->pLoops;
@@ -2232,6 +2248,11 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
whereLoopDelete(db, p);
}
assert( pWInfo->pExprMods==0 );
while( pWInfo->pMemToFree ){
WhereMemBlock *pNext = pWInfo->pMemToFree->pNext;
sqlite3DbFreeNN(db, pWInfo->pMemToFree);
pWInfo->pMemToFree = pNext;
}
sqlite3DbFreeNN(db, pWInfo);
}
@@ -2596,8 +2617,18 @@ static void whereLoopOutputAdjust(
/* If there are extra terms in the WHERE clause not used by an index
** that depend only on the table being scanned, and that will tend to
** cause many rows to be omitted, then mark that table as
** "self-culling". */
pLoop->wsFlags |= WHERE_SELFCULL;
** "self-culling".
**
** 2022-03-24: Self-culling only applies if either the extra terms
** are straight comparison operators that are non-true with NULL
** operand, or if the loop is not an OUTER JOIN.
*/
if( (pTerm->eOperator & 0x3f)!=0
|| (pWC->pWInfo->pTabList->a[pLoop->iTab].fg.jointype
& (JT_LEFT|JT_LTORJ))==0
){
pLoop->wsFlags |= WHERE_SELFCULL;
}
}
if( pTerm->truthProb<=0 ){
/* If a truth probability is specified using the likelihood() hints,
@@ -2801,9 +2832,10 @@ static int whereLoopAddBtreeIndex(
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
/* tag-20191211-001: Do not allow constraints from the WHERE clause to
** be used by the right table of a LEFT JOIN. Only constraints in the
** be used by the right table of a LEFT JOIN nor by the left table of a
** RIGHT JOIN. Only constraints in the
** ON clause are allowed. See tag-20191211-002 for the vtab equivalent. */
if( (pSrc->fg.jointype & JT_LEFT)!=0
if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
){
continue;
@@ -3173,7 +3205,7 @@ static int whereUsablePartialIndex(
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
Expr *pExpr;
pExpr = pTerm->pExpr;
if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->w.iRightJoinTable==iTab)
if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->w.iJoin==iTab)
&& (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin))
&& sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
&& (pTerm->wtFlags & TERM_VNULL)==0
@@ -3283,13 +3315,14 @@ static int whereLoopAddBtree(
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/* Automatic indexes */
if( !pBuilder->pOrSet /* Not part of an OR optimization */
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
&& (pWInfo->wctrlFlags & (WHERE_RIGHT_JOIN|WHERE_OR_SUBCLAUSE))==0
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
&& !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */
&& !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */
&& HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */
&& !pSrc->fg.isCorrelated /* Not a correlated subquery */
&& !pSrc->fg.isRecursive /* Not a recursive common table expression. */
&& (pSrc->fg.jointype & JT_RIGHT)==0 /* Not the right tab of a RIGHT JOIN */
){
/* Generate auto-index WhereLoops */
LogEst rLogSize; /* Logarithm of the number of rows in the table */
@@ -3779,15 +3812,26 @@ int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** Cause the prepared statement that is associated with a call to
** xBestIndex to open write transactions on all attached schemas.
** xBestIndex to potentiall use all schemas. If the statement being
** prepared is read-only, then just start read transactions on all
** schemas. But if this is a write operation, start writes on all
** schemas.
**
** This is used by the (built-in) sqlite_dbpage virtual table.
*/
void sqlite3VtabWriteAll(sqlite3_index_info *pIdxInfo){
void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
Parse *pParse = pHidden->pParse;
int nDb = pParse->db->nDb;
int i;
for(i=0; i<nDb; i++) sqlite3BeginWriteOperation(pParse, 0, i);
for(i=0; i<nDb; i++){
sqlite3CodeVerifySchema(pParse, i);
}
if( pParse->writeMask ){
for(i=0; i<nDb; i++){
sqlite3BeginWriteOperation(pParse, 0, i);
}
}
}
#endif
@@ -3970,6 +4014,9 @@ static int whereLoopAddOr(
pItem = pWInfo->pTabList->a + pNew->iTab;
iCur = pItem->iCursor;
/* The multi-index OR optimization does not work for RIGHT and FULL JOIN */
if( pItem->fg.jointype & JT_RIGHT ) return SQLITE_OK;
for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
if( (pTerm->eOperator & WO_OR)!=0
&& (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
@@ -4094,9 +4141,9 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
pNew->iTab = iTab;
pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
if( (pItem->fg.jointype & (JT_LEFT|JT_CROSS))!=0 ){
if( (pItem->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){
/* This condition is true when pItem is the FROM clause term on the
** right-hand-side of a LEFT or CROSS JOIN. */
** right-hand-side of a OUTER or CROSS JOIN. */
mPrereq = mPrior;
}else{
mPrereq = 0;
@@ -4105,7 +4152,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
if( IsVirtual(pItem->pTab) ){
SrcItem *p;
for(p=&pItem[1]; p<pEnd; p++){
if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){
if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
}
}
@@ -5168,7 +5215,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|| pTerm->pExpr->w.iRightJoinTable!=pItem->iCursor
|| pTerm->pExpr->w.iJoin!=pItem->iCursor
){
break;
}
@@ -5399,7 +5446,7 @@ WhereInfo *sqlite3WhereBegin(
** field (type Bitmask) it must be aligned on an 8-byte boundary on
** some architectures. Hence the ROUND8() below.
*/
nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
if( db->mallocFailed ){
sqlite3DbFree(db, pWInfo);
@@ -5721,8 +5768,10 @@ WhereInfo *sqlite3WhereBegin(
/* noop */
}else
#endif
if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
&& (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
if( ((pLoop->wsFlags & WHERE_IDX_ONLY)==0
&& (wctrlFlags & WHERE_OR_SUBCLAUSE)==0)
|| (pTabItem->fg.jointype & (JT_LTORJ|JT_RIGHT))!=0
){
int op = OP_OpenRead;
if( pWInfo->eOnePass!=ONEPASS_OFF ){
op = OP_OpenWrite;
@@ -5824,6 +5873,37 @@ WhereInfo *sqlite3WhereBegin(
}
}
if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb);
if( (pTabItem->fg.jointype & JT_RIGHT)!=0
&& (pLevel->pRJ = sqlite3WhereMalloc(pWInfo, sizeof(WhereRightJoin)))!=0
){
WhereRightJoin *pRJ = pLevel->pRJ;
pRJ->iMatch = pParse->nTab++;
pRJ->regBloom = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
pRJ->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
assert( pTab==pTabItem->pTab );
if( HasRowid(pTab) ){
KeyInfo *pInfo;
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0);
if( pInfo ){
pInfo->aColl[0] = 0;
pInfo->aSortFlags[0] = 0;
sqlite3VdbeAppendP4(v, pInfo, P4_KEYINFO);
}
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, pPk->nKeyCol);
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
}
pLoop->wsFlags &= ~WHERE_IDX_ONLY;
/* The nature of RIGHT JOIN processing is such that it messes up
** the output order. So omit any ORDER BY/GROUP BY elimination
** optimizations. We need to do an actual sort for RIGHT JOIN. */
pWInfo->nOBSat = 0;
pWInfo->eDistinct = WHERE_DISTINCT_UNORDERED;
}
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
if( db->mallocFailed ) goto whereBeginError;
@@ -5896,6 +5976,26 @@ whereBeginError:
}
#endif
#ifdef SQLITE_DEBUG
/*
** Return true if cursor iCur is opened by instruction k of the
** bytecode. Used inside of assert() only.
*/
static int cursorIsOpen(Vdbe *v, int iCur, int k){
while( k>=0 ){
VdbeOp *pOp = sqlite3VdbeGetOp(v,k--);
if( pOp->p1!=iCur ) continue;
if( pOp->opcode==OP_Close ) return 0;
if( pOp->opcode==OP_OpenRead ) return 1;
if( pOp->opcode==OP_OpenWrite ) return 1;
if( pOp->opcode==OP_OpenDup ) return 1;
if( pOp->opcode==OP_OpenAutoindex ) return 1;
if( pOp->opcode==OP_OpenEphemeral ) return 1;
}
return 0;
}
#endif /* SQLITE_DEBUG */
/*
** Generate the end of the WHERE loop. See comments on
** sqlite3WhereBegin() for additional information.
@@ -5916,6 +6016,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
for(i=pWInfo->nLevel-1; i>=0; i--){
int addr;
pLevel = &pWInfo->a[i];
if( pLevel->pRJ ){
/* Terminate the subroutine that forms the interior of the loop of
** the RIGHT JOIN table */
WhereRightJoin *pRJ = pLevel->pRJ;
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
pLevel->addrCont = 0;
pRJ->endSubrtn = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn, 1);
VdbeCoverage(v);
assert( pParse->withinRJSubrtn>0 );
pParse->withinRJSubrtn--;
}
pLoop = pLevel->pWLoop;
if( pLevel->op!=OP_Noop ){
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
@@ -5943,7 +6055,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
}
#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
/* The common case: Advance to the next row */
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont);
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
sqlite3VdbeChangeP5(v, pLevel->p5);
VdbeCoverage(v);
@@ -5958,7 +6070,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
#endif
}else{
}else if( pLevel->addrCont ){
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
}
if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){
@@ -6008,6 +6120,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
}
}
sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
if( pLevel->pRJ ){
sqlite3VdbeAddOp3(v, OP_Return, pLevel->pRJ->regReturn, 0, 1);
VdbeCoverage(v);
}
if( pLevel->addrSkip ){
sqlite3VdbeGoto(v, pLevel->addrSkip);
VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName));
@@ -6051,11 +6167,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
}
/* The "break" point is here, just past the end of the outer loop.
** Set it.
*/
sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
assert( pWInfo->nLevel<=pTabList->nSrc );
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
int k, last;
@@ -6066,6 +6177,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
assert( pTab!=0 );
pLoop = pLevel->pWLoop;
/* Do RIGHT JOIN processing. Generate code that will output the
** unmatched rows of the right operand of the RIGHT JOIN with
** all of the columns of the left operand set to NULL.
*/
if( pLevel->pRJ ){
sqlite3WhereRightJoinLoop(pWInfo, i, pLevel);
continue;
}
/* For a co-routine, change all OP_Column references to the table of
** the co-routine into OP_Copy of result contained in a register.
** OP_Rowid becomes OP_Null.
@@ -6077,29 +6197,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
continue;
}
#ifdef SQLITE_ENABLE_EARLY_CURSOR_CLOSE
/* Close all of the cursors that were opened by sqlite3WhereBegin.
** Except, do not close cursors that will be reused by the OR optimization
** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors
** created for the ONEPASS optimization.
*/
if( (pTab->tabFlags & TF_Ephemeral)==0
&& !IsView(pTab)
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
){
int ws = pLoop->wsFlags;
if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
}
if( (ws & WHERE_INDEXED)!=0
&& (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0
&& pLevel->iIdxCur!=pWInfo->aiCurOnePass[1]
){
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
}
}
#endif
/* If this scan uses an index, make VDBE code substitutions to read data
** from the index instead of from the table where possible. In some cases
** this optimization prevents the table from ever being read, which can
@@ -6148,14 +6245,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
){
int x = pOp->p2;
assert( pIdx->pTable==pTab );
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
if( pOp->opcode==OP_Offset ){
/* Do not need to translate the column number */
}else
#endif
if( !HasRowid(pTab) ){
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
x = pPk->aiColumn[x];
assert( x>=0 );
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
}else if( pOp->opcode==OP_Offset ){
/* Do not need to translate the column number */
#endif
}else{
testcase( x!=sqlite3StorageColumnToTable(pTab,x) );
x = sqlite3StorageColumnToTable(pTab,x);
@@ -6165,12 +6263,22 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
pOp->p2 = x;
pOp->p1 = pLevel->iIdxCur;
OpcodeRewriteTrace(db, k, pOp);
}
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0
}else{
/* Unable to translate the table reference into an index
** reference. Verify that this is harmless - that the
** table being referenced really is open.
*/
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|| pOp->opcode==OP_Offset
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|| cursorIsOpen(v,pOp->p1,k)
|| pOp->opcode==OP_Offset
);
#else
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|| cursorIsOpen(v,pOp->p1,k)
);
#endif
|| pWInfo->eOnePass );
}
}else if( pOp->opcode==OP_Rowid ){
pOp->p1 = pLevel->iIdxCur;
pOp->opcode = OP_IdxRowid;
@@ -6189,6 +6297,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
}
}
/* The "break" point is here, just past the end of the outer loop.
** Set it.
*/
sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
/* Final cleanup
*/
if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo);
+31
View File
@@ -32,6 +32,28 @@ typedef struct WhereLoopBuilder WhereLoopBuilder;
typedef struct WhereScan WhereScan;
typedef struct WhereOrCost WhereOrCost;
typedef struct WhereOrSet WhereOrSet;
typedef struct WhereMemBlock WhereMemBlock;
typedef struct WhereRightJoin WhereRightJoin;
/*
** This object is a header on a block of allocated memory that will be
** automatically freed when its WInfo oject is destructed.
*/
struct WhereMemBlock {
WhereMemBlock *pNext; /* Next block in the chain */
u8 sz; /* Bytes of space */
};
/*
** Extra information attached to a WhereLevel that is a RIGHT JOIN.
*/
struct WhereRightJoin {
int iMatch; /* Cursor used to determine prior matched rows */
int regBloom; /* Bloom filter for iRJMatch */
int regReturn; /* Return register for the interior subroutine */
int addrSubrtn; /* Starting address for the interior subroutine */
int endSubrtn; /* The last opcode in the interior subroutine */
};
/*
** This object contains information needed to implement a single nested
@@ -65,6 +87,7 @@ struct WhereLevel {
int addrLikeRep; /* LIKE range processing address */
#endif
int regFilter; /* Bloom filter */
WhereRightJoin *pRJ; /* Extra information for RIGHT JOIN */
u8 iFrom; /* Which entry in the FROM clause */
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
int p1, p2; /* Operands of the opcode used to end the loop */
@@ -478,6 +501,7 @@ struct WhereInfo {
int iEndWhere; /* End of the WHERE clause itself */
WhereLoop *pLoops; /* List of all WhereLoop objects */
WhereExprMod *pExprMods; /* Expression modifications */
WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
WhereClause sWC; /* Decomposition of the WHERE clause */
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
@@ -503,6 +527,8 @@ WhereTerm *sqlite3WhereFindTerm(
u32 op, /* Mask of WO_xx values describing operator */
Index *pIdx /* Must be compatible with this index, if not NULL */
);
void *sqlite3WhereMalloc(WhereInfo *pWInfo, u64 nByte);
void *sqlite3WhereRealloc(WhereInfo *pWInfo, void *pOld, u64 nByte);
/* wherecode.c: */
#ifndef SQLITE_OMIT_EXPLAIN
@@ -539,6 +565,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
WhereLevel *pLevel, /* The current level pointer */
Bitmask notReady /* Which tables are currently available */
);
SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
WhereInfo *pWInfo,
int iLevel,
WhereLevel *pLevel
);
/* whereexpr.c: */
void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
+170 -11
View File
@@ -204,6 +204,9 @@ int sqlite3WhereExplainOneScan(
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
}
#endif
if( pItem->fg.jointype & JT_LEFT ){
sqlite3_str_appendf(&str, " LEFT-JOIN");
}
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
if( pLoop->nOut>=10 ){
sqlite3_str_appendf(&str, " (~%llu rows)",
@@ -640,8 +643,9 @@ static int codeEqualityTerm(
i = pLevel->u.in.nIn;
pLevel->u.in.nIn += nEq;
pLevel->u.in.aInLoop =
sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
sqlite3WhereRealloc(pTerm->pWC->pWInfo,
pLevel->u.in.aInLoop,
sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
pIn = pLevel->u.in.aInLoop;
if( pIn ){
int iMap = 0; /* Index in aiMap[] */
@@ -1063,7 +1067,7 @@ static void codeCursorHint(
if( pTabItem->fg.jointype & JT_LEFT ){
Expr *pExpr = pTerm->pExpr;
if( !ExprHasProperty(pExpr, EP_FromJoin)
|| pExpr->w.iRightJoinTable!=pTabItem->iCursor
|| pExpr->w.iJoin!=pTabItem->iCursor
){
sWalker.eCode = 0;
sWalker.xExprCallback = codeCursorHintIsOrFunction;
@@ -1149,7 +1153,7 @@ static void codeDeferredSeek(
pWInfo->bDeferredSeek = 1;
sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
){
int i;
@@ -1501,7 +1505,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** initialize a memory cell that records if this table matches any
** row of the left table of the join.
*/
assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))
|| pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0
);
if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
@@ -1512,7 +1516,10 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* Compute a safe address to jump to if we discover that the table for
** this loop is empty and can never contribute content. */
for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){}
for(j=iLevel; j>0; j--){
if( pWInfo->a[j].iLeftJoin ) break;
if( pWInfo->a[j].pRJ ) break;
}
addrHalt = pWInfo->a[j].addrBrk;
/* Special case of a FROM clause subquery implemented as a co-routine */
@@ -2139,7 +2146,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* Seek the table cursor, if required */
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
&& (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0;
if( omitTable ){
/* pIdx is a covering index. No need to access the main table. */
}else if( HasRowid(pIdx->pTable) ){
@@ -2173,7 +2180,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** move forward to the next index.
** https://sqlite.org/src/info/4e8e4857d32d401f
*/
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 ){
whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
}
@@ -2192,7 +2199,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* The following assert() is not a requirement, merely an observation:
** The OR-optimization doesn't work for the right hand table of
** a LEFT JOIN: */
assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 );
assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 );
}
/* Record the instruction used to terminate the loop. */
@@ -2534,6 +2541,14 @@ Bitmask sqlite3WhereCodeOneLoopStart(
sqlite3VdbeGoto(v, pLevel->addrBrk);
sqlite3VdbeResolveLabel(v, iLoopBody);
/* Set the P2 operand of the OP_Return opcode that will end the current
** loop to point to this spot, which is the top of the next containing
** loop. The byte-code formatter will use that P2 value as a hint to
** indent everything in between the this point and the final OP_Return.
** See tag-20220407a in vdbe.c and shell.c */
assert( pLevel->op==OP_Return );
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); }
if( !untestedTerms ) disableTerm(pLevel, pTerm);
}else
@@ -2596,7 +2611,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
pE = pTerm->pExpr;
assert( pE!=0 );
if( (pTabItem->fg.jointype&JT_LEFT) && !ExprHasProperty(pE,EP_FromJoin) ){
if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ))
&& !ExprHasProperty(pE,EP_FromJoin)
){
continue;
}
@@ -2658,7 +2675,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
if( pTerm->leftCursor!=iCur ) continue;
if( pTabItem->fg.jointype & JT_LEFT ) continue;
if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue;
pE = pTerm->pExpr;
#ifdef WHERETRACE_ENABLED /* 0x800 */
if( sqlite3WhereTrace & 0x800 ){
@@ -2689,6 +2706,47 @@ Bitmask sqlite3WhereCodeOneLoopStart(
pAlt->wtFlags |= TERM_CODED;
}
/* For a RIGHT OUTER JOIN, record the fact that the current row has
** been matched at least once.
*/
if( pLevel->pRJ ){
Table *pTab;
int nPk;
int r;
int jmp1 = 0;
WhereRightJoin *pRJ = pLevel->pRJ;
/* pTab is the right-hand table of the RIGHT JOIN. Generate code that
** will record that the current row of that table has been matched at
** least once. This is accomplished by storing the PK for the row in
** both the iMatch index and the regBloom Bloom filter.
*/
pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab;
if( HasRowid(pTab) ){
r = sqlite3GetTempRange(pParse, 2);
sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
nPk = 1;
}else{
int iPk;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
nPk = pPk->nKeyCol;
r = sqlite3GetTempRange(pParse, nPk+1);
for(iPk=0; iPk<nPk; iPk++){
int iCol = pPk->aiColumn[iPk];
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+1+iPk);
}
}
jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, 0, r+1, nPk);
VdbeCoverage(v);
VdbeComment((v, "match against %s", pTab->zName));
sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r);
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r, r+1, nPk);
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
sqlite3VdbeJumpHere(v, jmp1);
sqlite3ReleaseTempRange(pParse, r, nPk+1);
}
/* For a LEFT OUTER JOIN, generate code that will record the fact that
** at least one row of the right table has matched the left table.
*/
@@ -2704,12 +2762,27 @@ Bitmask sqlite3WhereCodeOneLoopStart(
assert( pWInfo->untestedTerms );
continue;
}
if( pTabItem->fg.jointype & JT_LTORJ ) continue;
assert( pTerm->pExpr );
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
pTerm->wtFlags |= TERM_CODED;
}
}
if( pLevel->pRJ ){
/* Create a subroutine used to process all interior loops and code
** of the RIGHT JOIN. During normal operation, the subroutine will
** be in-line with the rest of the code. But at the end, a separate
** loop will run that invokes this subroutine for unmatched rows
** of pTab, with all tables to left begin set to NULL.
*/
WhereRightJoin *pRJ = pLevel->pRJ;
sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn);
pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v);
assert( pParse->withinRJSubrtn < 255 );
pParse->withinRJSubrtn++;
}
#if WHERETRACE_ENABLED /* 0x20800 */
if( sqlite3WhereTrace & 0x20000 ){
sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
@@ -2723,3 +2796,89 @@ Bitmask sqlite3WhereCodeOneLoopStart(
#endif
return pLevel->notReady;
}
/*
** Generate the code for the loop that finds all non-matched terms
** for a RIGHT JOIN.
*/
SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
WhereInfo *pWInfo,
int iLevel,
WhereLevel *pLevel
){
Parse *pParse = pWInfo->pParse;
Vdbe *v = pParse->pVdbe;
WhereRightJoin *pRJ = pLevel->pRJ;
Expr *pSubWhere = 0;
WhereClause *pWC = &pWInfo->sWC;
WhereInfo *pSubWInfo;
WhereLoop *pLoop = pLevel->pWLoop;
SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
SrcList sFrom;
Bitmask mAll = 0;
int k;
ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName));
sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
pRJ->regReturn);
for(k=0; k<iLevel; k++){
int iIdxCur;
mAll |= pWInfo->a[k].pWLoop->maskSelf;
sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
iIdxCur = pWInfo->a[k].iIdxCur;
if( iIdxCur ){
sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur);
}
}
if( (pTabItem->fg.jointype & JT_LTORJ)==0 ){
mAll |= pLoop->maskSelf;
for(k=0; k<pWC->nTerm; k++){
WhereTerm *pTerm = &pWC->a[k];
if( pTerm->wtFlags & TERM_VIRTUAL ) break;
if( pTerm->prereqAll & ~mAll ) continue;
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) ) continue;
pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
}
}
sFrom.nSrc = 1;
sFrom.nAlloc = 1;
memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem));
sFrom.a[0].fg.jointype = 0;
assert( pParse->withinRJSubrtn < 100 );
pParse->withinRJSubrtn++;
pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0,
WHERE_RIGHT_JOIN, 0);
if( pSubWInfo ){
int iCur = pLevel->iTabCur;
int r = ++pParse->nMem;
int nPk;
int jmp;
int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
Table *pTab = pTabItem->pTab;
if( HasRowid(pTab) ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
nPk = 1;
}else{
int iPk;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
nPk = pPk->nKeyCol;
pParse->nMem += nPk - 1;
for(iPk=0; iPk<nPk; iPk++){
int iCol = pPk->aiColumn[iPk];
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk);
}
}
jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk);
VdbeCoverage(v);
sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk);
VdbeCoverage(v);
sqlite3VdbeJumpHere(v, jmp);
sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn);
sqlite3WhereEnd(pSubWInfo);
}
sqlite3ExprDelete(pParse->db, pSubWhere);
ExplainQueryPlanPop(pParse);
assert( pParse->withinRJSubrtn>0 );
pParse->withinRJSubrtn--;
}
+14 -14
View File
@@ -64,7 +64,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
if( pWC->nTerm>=pWC->nSlot ){
WhereTerm *pOld = pWC->a;
sqlite3 *db = pWC->pWInfo->pParse->db;
pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
pWC->a = sqlite3WhereMalloc(pWC->pWInfo, sizeof(pWC->a[0])*pWC->nSlot*2 );
if( pWC->a==0 ){
if( wtFlags & TERM_DYNAMIC ){
sqlite3ExprDelete(db, p);
@@ -73,10 +73,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
return 0;
}
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
if( pOld!=pWC->aStatic ){
sqlite3DbFree(db, pOld);
}
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
pWC->nSlot = pWC->nSlot*2;
}
pTerm = &pWC->a[idx = pWC->nTerm++];
if( (wtFlags & TERM_VIRTUAL)==0 ) pWC->nBase = pWC->nTerm;
@@ -466,7 +463,7 @@ static int isAuxiliaryVtabOperator(
static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
if( pDerived ){
pDerived->flags |= pBase->flags & EP_FromJoin;
pDerived->w.iRightJoinTable = pBase->w.iRightJoinTable;
pDerived->w.iJoin = pBase->w.iJoin;
}
}
@@ -951,7 +948,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
int i;
for(i=0; i<pSrc->nSrc; i++){
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn);
if( pSrc->a[i].fg.isUsing==0 ){
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
}
if( pSrc->a[i].fg.isTabFunc ){
mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg);
}
@@ -1111,7 +1110,7 @@ static void exprAnalyze(
#endif
if( ExprHasProperty(pExpr, EP_FromJoin) ){
Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iRightJoinTable);
Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iJoin);
prereqAll |= x;
extraRight = x-1; /* ON clause terms may not be used with an index
** on left table of a LEFT JOIN. Ticket #3015 */
@@ -1462,7 +1461,7 @@ static void exprAnalyze(
0, sqlite3ExprDup(db, pRight, 0));
if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
ExprSetProperty(pNewExpr, EP_FromJoin);
pNewExpr->w.iRightJoinTable = pExpr->w.iRightJoinTable;
pNewExpr->w.iJoin = pExpr->w.iJoin;
}
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
@@ -1684,9 +1683,6 @@ void sqlite3WhereClauseClear(WhereClause *pWC){
a++;
}
}
if( pWC->a!=pWC->aStatic ){
sqlite3DbFree(db, pWC->a);
}
}
@@ -1813,6 +1809,7 @@ void sqlite3WhereTabFuncArgs(
if( pArgs==0 ) return;
for(j=k=0; j<pArgs->nExpr; j++){
Expr *pRhs;
u32 joinType;
while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;}
if( k>=pTab->nCol ){
sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
@@ -1829,9 +1826,12 @@ void sqlite3WhereTabFuncArgs(
pRhs = sqlite3PExpr(pParse, TK_UPLUS,
sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
if( pItem->fg.jointype & JT_LEFT ){
sqlite3SetJoinExpr(pTerm, pItem->iCursor);
if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){
joinType = EP_FromJoin;
}else{
joinType = EP_InnerJoin;
}
sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
}
}
+1 -1
View File
@@ -1729,7 +1729,7 @@ static void windowAggStep(
for(iEnd=sqlite3VdbeCurrentAddr(v); iOp<iEnd; iOp++){
VdbeOp *pOp = sqlite3VdbeGetOp(v, iOp);
if( pOp->opcode==OP_Column && pOp->p1==pWin->iEphCsr ){
if( pOp->opcode==OP_Column && pOp->p1==pMWin->iEphCsr ){
pOp->p1 = csr;
}
}
+32
View File
@@ -30,11 +30,24 @@ do_execsql_test affinity3-100 {
FROM customer c
LEFT JOIN apr i ON i.id=c.id;
CREATE VIEW v1rj AS
SELECT c.id, i.apr
FROM apr i
RIGHT JOIN customer c ON i.id=c.id;
CREATE VIEW v2 AS
SELECT c.id, v1.apr
FROM customer c
LEFT JOIN v1 ON v1.id=c.id;
CREATE VIEW v2rj AS
SELECT c.id, v1.apr
FROM v1 RIGHT JOIN customer c ON v1.id=c.id;
CREATE VIEW v2rjrj AS
SELECT c.id, v1rj.apr
FROM v1rj RIGHT JOIN customer c ON v1rj.id=c.id;
INSERT INTO customer (id) VALUES (1);
INSERT INTO apr (id, apr) VALUES (1, 12);
INSERT INTO customer (id) VALUES (2);
@@ -44,16 +57,35 @@ do_execsql_test affinity3-110 {
PRAGMA automatic_index=ON;
SELECT id, (apr / 100), typeof(apr) apr_type FROM v1;
} {1 0.12 real 2 0.1201 real}
do_execsql_test affinity3-111 {
PRAGMA automatic_index=ON;
SELECT id, (apr / 100), typeof(apr) apr_type FROM v1rj;
} {1 0.12 real 2 0.1201 real}
do_execsql_test affinity3-120 {
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2;
} {1 0.12 real 2 0.1201 real}
do_execsql_test affinity3-121 {
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rj;
} {1 0.12 real 2 0.1201 real}
do_execsql_test affinity3-122 {
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rjrj;
} {1 0.12 real 2 0.1201 real}
do_execsql_test affinity3-130 {
PRAGMA automatic_index=OFF;
SELECT id, (apr / 100), typeof(apr) apr_type FROM v1;
} {1 0.12 real 2 0.1201 real}
do_execsql_test affinity3-131 {
SELECT id, (apr / 100), typeof(apr) apr_type FROM v1rj;
} {1 0.12 real 2 0.1201 real}
do_execsql_test affinity3-140 {
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2;
} {1 0.12 real 2 0.1201 real}
do_execsql_test affinity3-141 {
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rj;
} {1 0.12 real 2 0.1201 real}
do_execsql_test affinity3-142 {
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rjrj;
} {1 0.12 real 2 0.1201 real}
# Ticket https://www.sqlite.org/src/info/7ffd1ca1d2ad4ecf (2017-01-16)
# Incorrect affinity when using automatic indexes
+11
View File
@@ -137,6 +137,17 @@ do_test aggnested-3.1 {
GROUP BY curr.id1);
}
} {1 1}
do_test aggnested-3.1-rj {
db eval {
SELECT
(SELECT sum(value2==xyz) FROM t2)
FROM
(SELECT curr.value1 as xyz
FROM t1 AS other RIGHT JOIN t1 AS curr
GROUP BY curr.id1);
}
} {1 1}
do_test aggnested-3.2 {
db eval {
DROP TABLE IF EXISTS t1;
+50
View File
@@ -686,4 +686,54 @@ do_execsql_test 28.2 {
UPDATE "t2" SET (c,d)=(a,b);
END}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 29.1 {
CREATE TABLE t1(x, y);
CREATE TRIGGER Trigger1 DELETE ON t1
BEGIN
SELECT t1.*, t1.x FROM t1 ORDER BY t1.x;
END;
}
do_execsql_test 29.2 {
ALTER TABLE t1 RENAME x TO z;
}
do_execsql_test 29.3 {
ALTER TABLE t1 RENAME TO t2;
}
do_execsql_test 29.4 {
CREATE TRIGGER tr2 AFTER DELETE ON t2 BEGIN
SELECT z, y FROM (
SELECT t2.* FROM t2
);
END;
}
do_execsql_test 29.5 {
DELETE FROM t2
}
do_execsql_test 29.6 {
ALTER TABLE t2 RENAME TO t3;
}
do_execsql_test 29.7 {
SELECT sql FROM sqlite_schema WHERE type='trigger'
} {
{CREATE TRIGGER Trigger1 DELETE ON "t3"
BEGIN
SELECT "t3".*, "t3".z FROM "t3" ORDER BY "t3".z;
END}
{CREATE TRIGGER tr2 AFTER DELETE ON "t3" BEGIN
SELECT z, y FROM (
SELECT "t3".* FROM "t3"
);
END}
}
finish_test
+19 -3
View File
@@ -283,7 +283,7 @@ do_eqp_test autoindex1-600a {
| `--CORRELATED SCALAR SUBQUERY xxxxxx
| `--SEARCH later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?)
|--SCAN x USING INDEX sheep_reg_flock_index
`--SEARCH y USING AUTOMATIC COVERING INDEX (sheep_no=?)
`--SEARCH y USING AUTOMATIC COVERING INDEX (sheep_no=?) LEFT-JOIN
}
@@ -542,7 +542,23 @@ do_execsql_test autoindex1-1020 {
SELECT count(*) FROM t11 LEFT JOIN t12 WHERE t12.y IS t11.w;
} 0
# 2022-04-25
# https://sqlite.org/forum/forumpost/0d3200f4f3bcd3a3
#
reset_db
do_execsql_test autoindex-1100 {
CREATE TABLE t1(a INT, b INT);
CREATE TABLE t2(c INT, d INT);
CREATE TABLE t3(e TEXT, f TEXT);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t2 VALUES(1, 2);
INSERT INTO t3 VALUES('abc', 'def');
} {}
do_execsql_test autoindex-1110 {
SELECT * FROM t1, t2 LEFT JOIN t3 ON (t2.d=1) WHERE t2.c = +t1.a;
} {1 1 1 2 {} {}}
do_execsql_test autoindex-1120 {
SELECT * FROM t1 LEFT JOIN t2 ON (t2.c=+t1.a) LEFT JOIN t3 ON (t2.d IS NULL);
} {1 1 1 2 {} {}}
finish_test
+25
View File
@@ -32,12 +32,21 @@ do_execsql_test autoindex4-1.1 {
do_execsql_test autoindex4-1.2 {
SELECT *, '|' FROM t1 LEFT JOIN t2 ON a=234 AND x=555;
} {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |}
do_execsql_test autoindex4-1.2-rj {
SELECT t1.*, t2.*, '|' FROM t2 RIGHT JOIN t1 ON a=234 AND x=555;
} {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |}
do_execsql_test autoindex4-1.3 {
SELECT *, '|' FROM t1 LEFT JOIN t2 ON x=555 WHERE a=234;
} {234 def {} {} | 234 ghi {} {} |}
do_execsql_test autoindex4-1.3-rj {
SELECT t1.*, t2.*, '|' FROM t2 RIGHT JOIN t1 ON x=555 WHERE a=234;
} {234 def {} {} | 234 ghi {} {} |}
do_execsql_test autoindex4-1.4 {
SELECT *, '|' FROM t1 LEFT JOIN t2 WHERE a=234 AND x=555;
} {}
do_execsql_test autoindex4-1.4-rj {
SELECT t1.*, t2.*, '|' FROM t2 RIGHT JOIN t1 WHERE a=234 AND x=555;
} {}
do_execsql_test autoindex4-2.0 {
@@ -69,6 +78,14 @@ do_execsql_test autoindex4-3.0 {
ORDER BY Items.ItemName;
} {Item1 Item2}
do_execsql_test autoindex4-3.1 {
SELECT Items.ItemName
FROM A
RIGHT JOIN Items ON (A.Name = Items.ItemName and Items.ItemName = 'dummy')
LEFT JOIN B ON (B.Name = Items.ItemName)
WHERE Items.Name = 'Parent'
ORDER BY Items.ItemName;
} {Item1 Item2}
do_execsql_test autoindex4-3.10 {
CREATE INDEX Items_x1 ON Items(ItemName,Name) WHERE ItemName = 'dummy';
SELECT Items.ItemName
@@ -78,6 +95,14 @@ do_execsql_test autoindex4-3.1 {
WHERE Items.Name = 'Parent'
ORDER BY Items.ItemName;
} {Item1 Item2}
do_execsql_test autoindex4-3.11 {
SELECT Items.ItemName
FROM A
RIGHT JOIN Items ON (A.Name = Items.ItemName and Items.ItemName = 'dummy')
LEFT JOIN B ON (B.Name = Items.ItemName)
WHERE Items.Name = 'Parent'
ORDER BY Items.ItemName;
} {Item1 Item2}
# 2021-11-30 - Enhancement to help the automatic index mechanism to
# create a partial index more often.
+3
View File
@@ -148,6 +148,9 @@ do_execsql_test btree01-2.1 {
INSERT INTO t2(y) VALUES(198),(187),(100);
SELECT y, c FROM t2 LEFT JOIN t1 ON y=a ORDER BY x;
} {198 99 187 {} 100 50}
do_execsql_test btree01-2.2 {
SELECT y, c FROM t1 RIGHT JOIN t2 ON y=a ORDER BY x;
} {198 99 187 {} 100 50}
finish_test
+21 -3
View File
@@ -684,16 +684,34 @@ do_test collate2-5.3 {
SELECT collate2t1.b FROM collate2t2 NATURAL JOIN collate2t1;
}
} {aa}
do_test collate2-5.4 {
do_test collate2-5.4.1 {
execsql {
SELECT collate2t2.b FROM collate2t1 LEFT OUTER JOIN collate2t2 USING (b) order by collate2t1.oid;
SELECT collate2t2.b FROM collate2t1 LEFT JOIN collate2t2 USING (b) order by collate2t1.oid;
}
} {{} aa {} {} {} aa {} {} {} aa {} {} {} aa {} {} {}}
do_test collate2-5.5 {
do_test collate2-5.4.2 {
execsql {
SELECT collate2t2.b FROM collate2t2 RIGHT JOIN collate2t1 ON collate2t1.b=collate2t2.b
ORDER BY collate2t1.oid;
}
} {{} aa {} {} {} aa {} {} {} aa {} {} {} aa {} {} {}}
do_test collate2-5.4.3 {
execsql {
SELECT collate2t2.b FROM collate2t1 LEFT JOIN collate2t2 ON collate2t2.b=collate2t1.b
ORDER BY collate2t1.oid;
}
} {{} aa {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}}
do_test collate2-5.5.1 {
execsql {
SELECT collate2t1.b, collate2t2.b FROM collate2t2 LEFT OUTER JOIN collate2t1 USING (b);
}
} {aa aa}
do_test collate2-5.5.2 {
execsql {
SELECT collate2t1.b, collate2t2.b
FROM collate2t1 RIGHT JOIN collate2t2 ON collate2t2.b=collate2t1.b
}
} {aa aa}
do_execsql_test 6.1 {
CREATE TABLE t1(x);
+55
View File
@@ -1429,4 +1429,59 @@ do_catchsql_test 18.1 {
} {1 {JSON cannot hold BLOB values}}
} ;# ifcapable json1
#-------------------------------------------------------------------------
reset_db
do_test 19.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 20480 pagesize 4096 filename crash-f022eb0ce64d27.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 05 .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 02 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 0f f8 00 04 0e d2 00 0f 08 0f d3 ................
| 112: 0f ae 0e d2 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 3792: 00 00 34 04 06 17 0f 11 01 57 69 6e 64 65 78 61 ..4......Windexa
| 3808: 74 31 05 43 52 45 41 54 45 20 55 4e 49 51 55 45 t1.CREATE UNIQUE
| 3824: 20 49 4e 44 45 58 20 61 20 4f 4e 20 74 31 28 61 INDEX a ON t1(a
| 3840: 2c 20 30 20 7c 20 61 29 81 23 01 07 17 11 11 01 , 0 | a).#......
| 3856: 82 31 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .1tablet1t1.CREA
| 3872: 54 45 20 54 41 42 4c 45 20 74 31 28 0a 20 20 20 TE TABLE t1(.
| 3888: 20 67 63 62 20 41 53 20 28 62 2a 31 29 2c 0a 20 gcb AS (b*1),.
| 3904: 20 20 20 61 20 49 34 54 45 47 45 52 20 50 52 49 a I4TEGER PRI
| 3920: 4d 41 52 59 20 4b 45 59 2c 0a 20 20 20 20 67 63 MARY KEY,. gc
| 3936: 63 20 41 53 20 28 74 32 2b 30 29 2c 0a 20 20 20 c AS (t2+0),.
| 3952: 20 62 20 55 4e 49 51 55 45 2c 0a 20 20 20 20 67 b UNIQUE,. g
| 3968: 63 61 20 41 53 20 28 31 2a 61 2b 30 29 2c 0a 20 ca AS (1*a+0),.
| 3984: 20 20 20 74 32 20 55 4e 49 51 55 45 0a 20 20 29 t2 UNIQUE. )
| 4000: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 23 03 WITHOUT ROWID#.
| 4016: 06 17 37 11 01 00 69 6e 64 65 78 73 71 6c 69 74 ..7...indexsqlit
| 4032: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 33 e_autoindex_t1_3
| 4048: 74 31 02 23 02 06 17 37 11 01 00 69 6e 64 65 78 t1.#...7...index
| 4064: 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e 64 65 78 sqlite_autoindex
| 4080: 5f 74 31 5f 32 74 31 02 00 00 00 08 00 00 00 00 _t1_2t1.........
| page 2 offset 4096
| 0: 0a 00 00 00 05 0f d8 00 0f f8 0f f8 9f e8 0f e0 ................
| 16: 0f d8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4048: 00 00 00 00 00 00 00 00 07 04 01 02 00 0f 13 88 ................
| 4064: 07 04 01 02 00 0e 0f a0 07 04 01 02 00 0d 0b b8 ................
| 4080: 07 04 01 02 00 0c 07 d0 07 04 01 02 00 0b 03 e8 ................
| page 5 offset 16384
| 0: 0a 00 00 00 05 0f e2 00 0f fa 0f f4 0f ee 0f e8 ................
| 16: 0f e2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4064: 00 00 05 03 01 01 0f 0f 05 03 01 01 0e 0e 05 03 ................
| 4080: 01 01 0d 0d 05 03 01 01 0c 0c 05 03 01 01 0b 0b ................
| end crash-f022eb0ce64d27.db
}]} {}
do_execsql_test 19.1 {
PRAGMA writable_schema=ON;
}
do_catchsql_test 19.2 {
UPDATE t1 SET a=1;
} {1 {UNIQUE constraint failed: index 'a'}}
finish_test
+1 -1
View File
@@ -96,7 +96,7 @@ do_join_test e_select-0.1.3 {
} {9}
do_catchsql_test e_select-0.1.4 {
SELECT count(*) FROM t1, t2 ON (t1.a=t2.a) USING (a)
} {1 {cannot have both ON and USING clauses in the same join}}
} {1 {near "USING": syntax error}}
do_catchsql_test e_select-0.1.5 {
SELECT count(*) FROM t1, t2 USING (a) ON (t1.a=t2.a)
} {1 {near "ON": syntax error}}
+6 -6
View File
@@ -94,9 +94,9 @@ do_eqp_test 1.7.1 {
SELECT * FROM t3 JOIN (SELECT 1)
} {
QUERY PLAN
|--MATERIALIZE SUBQUERY xxxxxx
|--MATERIALIZE (subquery-xxxxxx)
| `--SCAN CONSTANT ROW
|--SCAN SUBQUERY xxxxxx
|--SCAN (subquery-xxxxxx)
`--SCAN t3
}
do_eqp_test 1.7.2 {
@@ -123,13 +123,13 @@ do_eqp_test 1.8 {
SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2)
} {
QUERY PLAN
|--MATERIALIZE SUBQUERY xxxxxx
|--MATERIALIZE (subquery-xxxxxx)
| `--COMPOUND QUERY
| |--LEFT-MOST SUBQUERY
| | `--SCAN CONSTANT ROW
| `--UNION USING TEMP B-TREE
| `--SCAN CONSTANT ROW
|--SCAN SUBQUERY xxxxxx
|--SCAN (subquery-xxxxxx)
`--SCAN t3
}
do_eqp_test 1.9 {
@@ -282,10 +282,10 @@ det 3.2.1 {
SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5
} {
QUERY PLAN
|--CO-ROUTINE SUBQUERY xxxxxx
|--CO-ROUTINE (subquery-xxxxxx)
| |--SCAN t1
| `--USE TEMP B-TREE FOR ORDER BY
|--SCAN SUBQUERY xxxxxx
|--SCAN (subquery-xxxxxx)
`--USE TEMP B-TREE FOR ORDER BY
}
det 3.2.2 {
+22
View File
@@ -228,4 +228,26 @@ do_execsql_test 5.3 {
PRAGMA integrity_check;
} {ok}
#-------------------------------------------------------------------------
reset_db
forcedelete test.db2
do_execsql_test 6.1 {
PRAGMA foreign_keys = on;
CREATE TABLE c1(b);
INSERT INTO c1 VALUES(123);
}
do_execsql_test 6.2 {
ATTACH 'test.db2' AS aux;
CREATE TABLE aux.p1(a INTEGER PRIMARY KEY);
CREATE TABLE aux.c1(b REFERENCES p1(a) ON DELETE RESTRICT);
INSERT INTO aux.p1 VALUES(123);
}
do_execsql_test 6.3 {
DELETE FROM aux.p1 WHERE a=123;
}
finish_test
+1 -1
View File
@@ -100,7 +100,7 @@ do_eqp_test 4.2 {
|--MATERIALIZE rr
| `--SCAN ft4 VIRTUAL TABLE INDEX 3:
|--SCAN t4
`--SEARCH rr USING AUTOMATIC COVERING INDEX (docid=?)
`--SEARCH rr USING AUTOMATIC COVERING INDEX (docid=?) LEFT-JOIN
}
finish_test
+1 -1
View File
@@ -320,7 +320,7 @@ do_eqp_test index6-8.1 {
} {
QUERY PLAN
|--SCAN t8a
`--SEARCH t8b USING INDEX i8c (y=?)
`--SEARCH t8b USING INDEX i8c (y=?) LEFT-JOIN
}
do_execsql_test index6-8.2 {
+23 -12
View File
@@ -272,11 +272,13 @@ do_test join-2.2 {
SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1;
}
} {1 2 3 {} 2 3 4 1 3 4 5 2}
do_test join-2.3 {
catchsql {
SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2;
}
} {1 {RIGHT and FULL OUTER JOINs are not currently supported}}
#do_test join-2.3 {
# catchsql {
# SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2;
# }
#} {1 {RIGHT and FULL OUTER JOINs are not currently supported}}
do_test join-2.4 {
execsql {
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d
@@ -307,7 +309,7 @@ do_test join-3.3 {
catchsql {
SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b);
}
} {1 {cannot have both ON and USING clauses in the same join}}
} {1 {near "USING": syntax error}}
do_test join-3.4.1 {
catchsql {
SELECT * FROM t1 JOIN t2 USING(a);
@@ -330,32 +332,32 @@ do_test join-3.7 {
catchsql {
SELECT * FROM t1 INNER OUTER JOIN t2;
}
} {1 {unknown or unsupported join type: INNER OUTER}}
} {1 {unknown join type: INNER OUTER}}
do_test join-3.8 {
catchsql {
SELECT * FROM t1 INNER OUTER CROSS JOIN t2;
}
} {1 {unknown or unsupported join type: INNER OUTER CROSS}}
} {1 {unknown join type: INNER OUTER CROSS}}
do_test join-3.9 {
catchsql {
SELECT * FROM t1 OUTER NATURAL INNER JOIN t2;
}
} {1 {unknown or unsupported join type: OUTER NATURAL INNER}}
} {1 {unknown join type: OUTER NATURAL INNER}}
do_test join-3.10 {
catchsql {
SELECT * FROM t1 LEFT BOGUS JOIN t2;
}
} {1 {unknown or unsupported join type: LEFT BOGUS}}
} {1 {unknown join type: LEFT BOGUS}}
do_test join-3.11 {
catchsql {
SELECT * FROM t1 INNER BOGUS CROSS JOIN t2;
}
} {1 {unknown or unsupported join type: INNER BOGUS CROSS}}
} {1 {unknown join type: INNER BOGUS CROSS}}
do_test join-3.12 {
catchsql {
SELECT * FROM t1 NATURAL AWK SED JOIN t2;
}
} {1 {unknown or unsupported join type: NATURAL AWK SED}}
} {1 {unknown join type: NATURAL AWK SED}}
do_test join-4.1 {
execsql {
@@ -1039,5 +1041,14 @@ do_execsql_test join-25.1 {
SELECT count(*) FROM v0 LEFT JOIN t0 ON v0.c0;
} {1}
# 2022-04-21 Parser issue detected by dbsqlfuzz
#
reset_db
do_catchsql_test join-26.1 {
CREATE TABLE t4(a,b);
CREATE TABLE t5(a,c);
CREATE TABLE t6(a,d);
SELECT * FROM t5 JOIN ((t4 JOIN (t5 JOIN t6)) t7);
} {/1 {.*}/}
finish_test
+23 -8
View File
@@ -63,6 +63,12 @@ do_test join2-1.6 {
t1 NATURAL LEFT OUTER JOIN t2 NATURAL JOIN t3
}
} {1 11 111 1111}
do_test join2-1.6-rj {
execsql {
SELECT * FROM
t2 NATURAL RIGHT OUTER JOIN t1 NATURAL JOIN t3
}
} {11 111 1 1111}
ifcapable subquery {
do_test join2-1.7 {
execsql {
@@ -70,6 +76,12 @@ ifcapable subquery {
t1 NATURAL LEFT OUTER JOIN (t2 NATURAL JOIN t3)
}
} {1 11 111 1111 2 22 {} {} 3 33 {} {}}
do_test join2-1.7-rj {
execsql {
SELECT a, b, c, d FROM
t2 NATURAL JOIN t3 NATURAL RIGHT JOIN t1
}
} {1 11 111 1111 2 22 {} {} 3 33 {} {}}
}
#-------------------------------------------------------------------------
@@ -88,6 +100,9 @@ do_execsql_test 2.0 {
do_catchsql_test 2.1 {
SELECT * FROM aa LEFT JOIN cc ON (a=b) JOIN bb ON (b=coalesce(c,1));
} {1 {ON clause references tables to its right}}
do_catchsql_test 2.1b {
SELECT * FROM aa RIGHT JOIN cc ON (a=b) JOIN bb ON (b=coalesce(c,1));
} {1 {ON clause references tables to its right}}
do_catchsql_test 2.2 {
SELECT * FROM aa JOIN cc ON (a=b) JOIN bb ON (b=c);
} {0 {one one one}}
@@ -114,7 +129,7 @@ do_eqp_test 3.1 {
} {
QUERY PLAN
|--SCAN t1
`--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?)
`--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
}
do_eqp_test 3.2 {
@@ -122,7 +137,7 @@ do_eqp_test 3.2 {
} {
QUERY PLAN
|--SCAN t1
`--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?)
`--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
}
#-------------------------------------------------------------------------
@@ -162,15 +177,15 @@ do_eqp_test 4.1.5 {
} {
QUERY PLAN
|--SCAN c1
|--SEARCH c2 USING INTEGER PRIMARY KEY (rowid=?)
`--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?)
|--SEARCH c2 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
`--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
}
do_eqp_test 4.1.6 {
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
} {
QUERY PLAN
|--SCAN c1
`--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?)
`--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
}
do_execsql_test 4.2.0 {
@@ -209,15 +224,15 @@ do_eqp_test 4.2.5 {
} {
QUERY PLAN
|--SCAN c1
|--SEARCH c2 USING INDEX sqlite_autoindex_c2_1 (k=?)
`--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?)
|--SEARCH c2 USING INDEX sqlite_autoindex_c2_1 (k=?) LEFT-JOIN
`--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?) LEFT-JOIN
}
do_eqp_test 4.2.6 {
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
} {
QUERY PLAN
|--SCAN c1
`--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?)
`--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?) LEFT-JOIN
}
# 2017-11-23 (Thanksgiving day)
+36 -2
View File
@@ -280,9 +280,9 @@ do_eqp_test 7.2 {
|--SCAN t1
`--MULTI-INDEX OR
|--INDEX 1
| `--SEARCH t2 USING INDEX t2xy (x=? AND y=?)
| `--SEARCH t2 USING INDEX t2xy (x=? AND y=?) LEFT-JOIN
`--INDEX 2
`--SEARCH t2 USING INDEX t2xy (x=? AND y=?)
`--SEARCH t2 USING INDEX t2xy (x=? AND y=?) LEFT-JOIN
}
do_execsql_test 7.3 {
@@ -300,6 +300,13 @@ do_execsql_test 7.3 {
do_eqp_test 7.4 {
SELECT * FROM t3 LEFT JOIN t4 ON (t4.x = t3.x) WHERE (t4.y = ? OR t4.z = ?);
} {
QUERY PLAN
|--SCAN t3
`--SEARCH t4 USING INDEX t4xz (x=?) LEFT-JOIN
}
do_eqp_test 7.4b {
SELECT * FROM t3 CROSS JOIN t4 ON (t4.x = t3.x) WHERE (+t4.y = ? OR t4.z = ?);
} {
QUERY PLAN
|--SCAN t3
@@ -360,5 +367,32 @@ do_execsql_test 10.1 {
SELECT x FROM v3;
} {0}
# 2022-03-24 https://sqlite.org/forum/forumpost/031e262a89b6a9d2
# Bloom-filter on a LEFT JOIN with NULL-based WHERE constraints.
#
reset_db
do_execsql_test 11.1 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT);
CREATE TABLE t2(c INTEGER PRIMARY KEY, d INT);
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<8)
INSERT INTO t1(a,b) SELECT x, 10*x FROM c;
INSERT INTO t2(c,d) SELECT b*2, 100*a FROM t1;
ANALYZE;
DELETE FROM sqlite_stat1;
INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES
('t1',NULL,150105),('t2',NULL,98747);
ANALYZE sqlite_schema;
} {}
do_execsql_test 11.2 {
SELECT count(*) FROM t1 LEFT JOIN t2 ON c=b WHERE d IS NULL;
} {4}
do_execsql_test 11.3 {
SELECT count(*) FROM t1 LEFT JOIN t2 ON c=b WHERE d=100;
} {1}
do_execsql_test 11.4 {
SELECT count(*) FROM t1 LEFT JOIN t2 ON c=b WHERE d>=300;
} {2}
finish_test
+289
View File
@@ -0,0 +1,289 @@
# 2022-04-09
#
# 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.
#
# This file implements tests for RIGHT and FULL OUTER JOINs.
set testdir [file dirname $argv0]
source $testdir/tester.tcl
foreach {id schema} {
1 {
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
CREATE INDEX t1a ON t1(a);
CREATE TABLE t2(c INT, d INT);
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
CREATE INDEX t2c ON t2(c);
CREATE VIEW dual(dummy) AS VALUES('x');
}
2 {
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
CREATE INDEX t1ab ON t1(a,b);
CREATE TABLE t2(c INT, d INT);
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
CREATE INDEX t2cd ON t2(c,d);
CREATE VIEW dual(dummy) AS VALUES('x');
}
3 {
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
CREATE INDEX t1a ON t1(a);
CREATE TABLE t2(c INT, d INT PRIMARY KEY) WITHOUT ROWID;
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
CREATE INDEX t2c ON t2(c);
CREATE VIEW dual(dummy) AS VALUES('x');
}
4 {
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
CREATE TABLE t2(c INTEGER PRIMARY KEY, d INT);
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
CREATE VIEW dual(dummy) AS VALUES('x');
}
5 {
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
CREATE TABLE t2(c INT PRIMARY KEY, d INT) WITHOUT ROWID;
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
CREATE VIEW dual(dummy) AS VALUES('x');
}
6 {
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
CREATE VIEW t2(c,d) AS VALUES(3,33),(4,44),(5,55);
CREATE VIEW dual(dummy) AS VALUES('x');
}
7 {
CREATE VIEW t1(a,b) AS VALUES(1,2),(1,3),(1,4);
CREATE TABLE t2(c INTEGER PRIMARY KEY, d INT);
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
CREATE VIEW dual(dummy) AS VALUES('x');
}
8 {
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
CREATE TABLE t2(c INT, d INT);
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
CREATE VIEW dual(dummy) AS VALUES('x');
}
9 {
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
CREATE TABLE t2a(c INTEGER PRIMARY KEY, i1 INT);
CREATE TABLE t2b(i1 INTEGER PRIMARY KEY, d INT);
CREATE VIEW t2(c,d) AS SELECT c, d FROM t2a NATURAL JOIN t2b;
INSERT INTO t2a VALUES(3,93),(4,94),(5,95),(6,96),(7,97);
INSERT INTO t2b VALUES(91,11),(92,22),(93,33),(94,44),(95,55);
CREATE TABLE dual(dummy TEXT);
INSERT INTO dual(dummy) VALUES('x');
}
10 {
CREATE TABLE t1(a INT, b INT, PRIMARY KEY(a,b)) WITHOUT ROWID;
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
CREATE TABLE t2a(c INTEGER PRIMARY KEY, i1 INT);
CREATE TABLE t2b(i1 INTEGER PRIMARY KEY, d INT);
CREATE VIEW t2(c,d) AS SELECT c, d FROM t2a NATURAL JOIN t2b;
INSERT INTO t2a VALUES(3,93),(4,94),(5,95),(6,96),(7,97);
INSERT INTO t2b VALUES(91,11),(92,22),(93,33),(94,44),(95,55);
CREATE TABLE dual(dummy TEXT);
INSERT INTO dual(dummy) VALUES('x');
}
} {
reset_db
db nullvalue NULL
do_execsql_test join7-$id.setup $schema {}
# Verified against PG-14 for case 1
do_execsql_test join7-$id.10 {
SELECT b, d FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b;
} {
NULL 55
2 NULL
3 33
4 44
}
# Verified against PG-14 for case 1
do_execsql_test join7-$id.20 {
SELECT a, c FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b;
} {
NULL 5
1 NULL
1 3
1 4
}
do_execsql_test join7-$id.30 {
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b;
} {
NULL NULL 5 55
1 2 NULL NULL
1 3 3 33
1 4 4 44
}
do_execsql_test join7-$id.31 {
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c ORDER BY +b;
} {
NULL NULL 5 55
1 2 NULL NULL
1 3 3 33
1 4 4 44
}
do_execsql_test join7-$id.40 {
SELECT * FROM t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b;
} {
NULL NULL 5 55
1 3 3 33
1 4 4 44
}
do_execsql_test join7-$id.50 {
SELECT t1.*, t2.* FROM t2 LEFT OUTER JOIN t1 ON b=c ORDER BY +b;
} {
NULL NULL 5 55
1 3 3 33
1 4 4 44
}
do_execsql_test join7-$id.60 {
SELECT * FROM dual JOIN t1 ON true RIGHT OUTER JOIN t2 ON b=c ORDER BY +b;
} {
NULL NULL NULL 5 55
x 1 3 3 33
x 1 4 4 44
}
do_execsql_test join7-$id.70 {
SELECT t1.*, t2.*
FROM t2 LEFT JOIN (dual JOIN t1 ON true) ON b=c ORDER BY +b;
} {
NULL NULL 5 55
1 3 3 33
1 4 4 44
}
do_execsql_test join7-$id.80 {
SELECT * FROM dual CROSS JOIN t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b;
} {
NULL NULL NULL 5 55
x 1 3 3 33
x 1 4 4 44
}
do_execsql_test join7-$id.81 {
SELECT dual.*, t1.*, t2.*
FROM t1 CROSS JOIN dual RIGHT OUTER JOIN t2 ON b=c ORDER BY +b;
} {
NULL NULL NULL 5 55
x 1 3 3 33
x 1 4 4 44
}
do_execsql_test join7-$id.90 {
SELECT * FROM t1 LEFT OUTER JOIN t2 ON b=c ORDER BY +b;
} {
1 2 NULL NULL
1 3 3 33
1 4 4 44
}
do_execsql_test join7-$id.100 {
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND a=1 ORDER BY +b;
} {
NULL NULL 5 55
1 2 NULL NULL
1 3 3 33
1 4 4 44
}
do_execsql_test join7-$id.101 {
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c AND a=1 ORDER BY +b;
} {
NULL NULL 5 55
1 2 NULL NULL
1 3 3 33
1 4 4 44
}
# Verified against PG-14 for case 1
do_execsql_test join7-$id.110 {
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a=1 ORDER BY +b;
} {
1 2 NULL NULL
1 3 3 33
1 4 4 44
}
do_execsql_test join7-$id.111 {
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c WHERE a=1 ORDER BY +b;
} {
1 2 NULL NULL
1 3 3 33
1 4 4 44
}
# Verified against PG-14 for case 1
do_execsql_test join7-$id.115 {
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c
WHERE a=1 OR a IS NULL ORDER BY +b;
} {
NULL NULL 5 55
1 2 NULL NULL
1 3 3 33
1 4 4 44
}
do_execsql_test join7-$id.116 {
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c
WHERE a=1 OR a IS NULL ORDER BY +b;
} {
NULL NULL 5 55
1 2 NULL NULL
1 3 3 33
1 4 4 44
}
# Verified against PG-14 for case 1:
do_execsql_test join7-$id.120 {
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d;
} {
NULL NULL 5 55
}
# Verified against PG-14 for case 1:
do_execsql_test join7-$id.130 {
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND d<=0 ORDER BY +b, +d;
} {
NULL NULL 3 33
NULL NULL 4 44
NULL NULL 5 55
1 2 NULL NULL
1 3 NULL NULL
1 4 NULL NULL
}
# Verified against PG-14 for case 1:
do_execsql_test join7-$id.140 {
SELECT a, b, c, d
FROM t2 FULL OUTER JOIN t1 ON b=c AND d<=0 ORDER BY +b, +d;
} {
NULL NULL 3 33
NULL NULL 4 44
NULL NULL 5 55
1 2 NULL NULL
1 3 NULL NULL
1 4 NULL NULL
}
do_execsql_test join7-$id.141 {
SELECT a, b, c, d
FROM t2 FULL OUTER JOIN t1 ON b=c AND d<=0
ORDER BY +b, +d LIMIT 2 OFFSET 2
} {
NULL NULL 5 55
1 2 NULL NULL
}
}
finish_test
+159
View File
@@ -0,0 +1,159 @@
# 2022-04-12
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file implements tests for RIGHT and FULL OUTER JOINs.
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !vtab {
finish_test
return
}
db null NULL
do_execsql_test join8-10 {
CREATE TABLE t1(a,b,c);
CREATE TABLE t2(x,y);
CREATE INDEX t2x ON t2(x);
SELECT avg(DISTINCT b) FROM (SELECT * FROM t2 LEFT RIGHT JOIN t1 ON c);
} {NULL}
# Pending optimization opportunity:
# Row-value initialization subroutines must be called from with the
# RIGHT JOIN body subroutine before the first use of any register containing
# the results of that subroutine. This seems dodgy. Test case:
#
reset_db
do_execsql_test join8-1000 {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT,b,c,d,e,f,g,h,j,k,l,m,n,o,p,q,r,s);
CREATE INDEX t1x1 ON t1(g+h,j,k);
CREATE INDEX t1x2 ON t1(b);
INSERT INTO t1 DEFAULT VALUES;
} {}
do_catchsql_test join8-1010 {
SELECT a
FROM (
SELECT a
FROM (
SELECT a
FROM (
SELECT a FROM t1 NATURAL LEFT JOIN t1
WHERE (b, 2 ) IS ( SELECT 2 IN(2,2),2)
)
NATURAL LEFT FULL JOIN t1
WHERE ( rowid , 1 )<=(CASE 5 WHEN 619 THEN 841 ELSE 3374391096 END,0)
ORDER BY a ASC
)
NATURAL LEFT JOIN t1
WHERE (b, 2 ) IS ( SELECT 3 IN(3,3),3)
)
NATURAL LEFT FULL JOIN t1
WHERE ( rowid , 1 )<=(CASE 5 WHEN 619 THEN 841 ELSE 3374391096 END,0)
ORDER BY a ASC;
} {0 1}
# Pending issue #2: (now resolved)
# Jump to addrHalt inside the RIGHT JOIN body subroutine bypasses the
# OP_Return, resulting in a subroutine loop. Test case:
#
reset_db
do_execsql_test join8-2000 {
CREATE TABLE t1(a int, b int, c int);
INSERT INTO t1 VALUES(1,2,3),(4,5,6);
CREATE TABLE t2(d int, e int);
INSERT INTO t2 VALUES(3,333),(4,444);
CREATE TABLE t3(f int, g int);
PRAGMA automatic_index=off;
} {}
do_catchsql_test join8-2010 {
SELECT * FROM t1 RIGHT JOIN t2 ON c=d JOIN t3 ON f=e;
} {0 {}}
# Demonstrate that nested FULL JOINs and USING clauses work
#
reset_db
load_static_extension db series
do_execsql_test join8-3000 {
CREATE TABLE t1(id INTEGER PRIMARY KEY, a INT);
CREATE TABLE t2(id INTEGER PRIMARY KEY, b INT);
CREATE TABLE t3(id INTEGER PRIMARY KEY, c INT);
CREATE TABLE t4(id INTEGER PRIMARY KEY, d INT);
CREATE TABLE t5(id INTEGER PRIMARY KEY, e INT);
CREATE TABLE t6(id INTEGER PRIMARY KEY, f INT);
CREATE TABLE t7(id INTEGER PRIMARY KEY, g INT);
CREATE TABLE t8(id INTEGER PRIMARY KEY, h INT);
INSERT INTO t1 SELECT value, 1 FROM generate_series(1,256) WHERE value & 1;
INSERT INTO t2 SELECT value, 1 FROM generate_series(1,256) WHERE value & 2;
INSERT INTO t3 SELECT value, 1 FROM generate_series(1,256) WHERE value & 4;
INSERT INTO t4 SELECT value, 1 FROM generate_series(1,256) WHERE value & 8;
INSERT INTO t5 SELECT value, 1 FROM generate_series(1,256) WHERE value & 16;
INSERT INTO t6 SELECT value, 1 FROM generate_series(1,256) WHERE value & 32;
INSERT INTO t7 SELECT value, 1 FROM generate_series(1,256) WHERE value & 64;
INSERT INTO t8 SELECT value, 1 FROM generate_series(1,256) WHERE value & 128;
CREATE TABLE t9 AS
SELECT id, h, g, f, e, d, c, b, a
FROM t1
NATURAL FULL JOIN t2
NATURAL FULL JOIN t3
NATURAL FULL JOIN t4
NATURAL FULL JOIN t5
NATURAL FULL JOIN t6
NATURAL FULL JOIN t7
NATURAL FULL JOIN t8;
} {}
do_execsql_test join8-3010 {
SELECT count(*) FROM t9;
} {255}
do_execsql_test join8-3020 {
SELECT id, count(*) FROM t9 GROUP BY id HAVING count(*)!=1;
} {}
do_execsql_test join8-3030 {
UPDATE t9 SET a=0 WHERE a IS NULL;
UPDATE t9 SET b=0 WHERE b IS NULL;
UPDATE t9 SET c=0 WHERE c IS NULL;
UPDATE t9 SET d=0 WHERE d IS NULL;
UPDATE t9 SET e=0 WHERE e IS NULL;
UPDATE t9 SET f=0 WHERE f IS NULL;
UPDATE t9 SET g=0 WHERE g IS NULL;
UPDATE t9 SET h=0 WHERE h IS NULL;
SELECT count(*) FROM t9 WHERE id=128*h+64*g+32*f+16*e+8*d+4*c+2*b+a;
} {255}
do_execsql_test join8-3040 {
SELECT * FROM t9 WHERE id<>128*h+64*g+32*f+16*e+8*d+4*c+2*b+a;
} {}
# 2022-04-21 dbsqlfuzz find
#
reset_db
do_execsql_test join8-4000 {
CREATE TABLE t1(x INTEGER PRIMARY KEY, a, b);
INSERT INTO t1 VALUES(1,5555,4);
CREATE INDEX i1a ON t1(a);
CREATE INDEX i1b ON t1(b);
SELECT a FROM t1 NATURAL RIGHT JOIN t1 WHERE a=5555 OR (1,b)==(SELECT 2 IN (2,2),4);
} {5555}
# 2022-04-23 dbsqlfuzz c7ee5500e3abddec3557016de777713b80c790d3
# Escape from the right-join body subroutine via the ORDER BY LIMIT optimization.
#
reset_db
db null -
do_catchsql_test join8-5000 {
CREATE TABLE t1(x);
INSERT INTO t1(x) VALUES(NULL),(NULL);
CREATE TABLE t2(c, d);
INSERT INTO t2(c,d) SELECT x, x FROM t1;
CREATE INDEX t2dc ON t2(d, c);
SELECT (SELECT c FROM sqlite_temp_schema FULL JOIN t2 ON d IN (1,2,3) ORDER BY d) AS x FROM t1;
} {0 {- -}}
finish_test
+565
View File
@@ -0,0 +1,565 @@
# 2022-04-16
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for RIGHT and FULL OUTER JOINs.
set testdir [file dirname $argv0]
source $testdir/tester.tcl
foreach {id schema} {
1 {
CREATE TABLE t3(id INTEGER PRIMARY KEY, w TEXT);
CREATE TABLE t4(id INTEGER PRIMARY KEY, x TEXT);
CREATE TABLE t5(id INTEGER PRIMARY KEY, y TEXT);
CREATE TABLE t6(id INTEGER PRIMARY KEY, z INT);
CREATE VIEW dual(dummy) AS VALUES('x');
INSERT INTO t3(id,w) VALUES(2,'two'),(3,'three'),(6,'six'),(7,'seven');
INSERT INTO t4(id,x) VALUES(2,'alice'),(4,'bob'),(6,'cindy'),(8,'dave');
INSERT INTO t5(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow'),(4,'green'),
(5,'blue');
INSERT INTO t6(id,z) VALUES(3,333),(4,444),(5,555),(0,1000),(9,999);
}
2 {
CREATE TABLE t3(id INT PRIMARY KEY, w TEXT) WITHOUT ROWID;
CREATE TABLE t4(id INT PRIMARY KEY, x TEXT) WITHOUT ROWID;
CREATE TABLE t5(id INT PRIMARY KEY, y TEXT) WITHOUT ROWID;
CREATE TABLE t6(id INT PRIMARY KEY, z INT) WITHOUT ROWID;
CREATE TABLE dual(dummy TEXT);
INSERT INTO dual(dummy) VALUES('x');
INSERT INTO t3(id,w) VALUES(2,'two'),(3,'three'),(6,'six'),(7,'seven');
INSERT INTO t4(id,x) VALUES(2,'alice'),(4,'bob'),(6,'cindy'),(8,'dave');
INSERT INTO t5(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow'),(4,'green'),
(5,'blue');
INSERT INTO t6(id,z) VALUES(3,333),(4,444),(5,555),(0,1000),(9,999);
}
3 {
CREATE TABLE t3x(id INTEGER PRIMARY KEY, w TEXT);
CREATE TABLE t4x(id INTEGER PRIMARY KEY, x TEXT);
CREATE TABLE t5x(id INTEGER PRIMARY KEY, y TEXT);
CREATE TABLE t6x(id INTEGER PRIMARY KEY, z INT);
CREATE VIEW dual(dummy) AS VALUES('x');
INSERT INTO t3x(id,w) VALUES(2,'two'),(3,'three'),(6,'six'),(7,'seven');
INSERT INTO t4x(id,x) VALUES(2,'alice'),(4,'bob'),(6,'cindy'),(8,'dave');
INSERT INTO t5x(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow'),(4,'green'),
(5,'blue');
INSERT INTO t6x(id,z) VALUES(3,333),(4,444),(5,555),(0,1000),(9,999);
CREATE VIEW t3 AS SELECT * FROM t3x LIMIT 1000;
CREATE VIEW t4 AS SELECT * FROM t4x LIMIT 1000;
CREATE VIEW t5 AS SELECT * FROM t5x LIMIT 1000;
CREATE VIEW t6 AS SELECT * FROM t6x LIMIT 1000;
}
4 {
CREATE TABLE t3a(id INTEGER PRIMARY KEY, w TEXT);
CREATE TABLE t3b(id INTEGER PRIMARY KEY, w TEXT);
CREATE TABLE t4a(id INTEGER PRIMARY KEY, x TEXT);
CREATE TABLE t4b(id INTEGER PRIMARY KEY, x TEXT);
CREATE TABLE t5a(id INTEGER PRIMARY KEY, y TEXT);
CREATE TABLE t5b(id INTEGER PRIMARY KEY, y TEXT);
CREATE TABLE t6a(id INTEGER PRIMARY KEY, z INT);
CREATE TABLE t6b(id INTEGER PRIMARY KEY, z INT);
CREATE VIEW dual(dummy) AS VALUES('x');
INSERT INTO t3a(id,w) VALUES(2,'two'),(3,'three');
INSERT INTO t3b(id,w) VALUES(6,'six'),(7,'seven');
INSERT INTO t4a(id,x) VALUES(2,'alice'),(4,'bob');
INSERT INTO t4b(id,x) VALUES(6,'cindy'),(8,'dave');
INSERT INTO t5a(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow');
INSERT INTO t5b(id,y) VALUES(4,'green'),(5,'blue');
INSERT INTO t6a(id,z) VALUES(3,333),(4,444);
INSERT INTO t6b(id,z) VALUES(5,555),(0,1000),(9,999);
CREATE VIEW t3 AS SELECT * FROM t3a UNION ALL SELECT * FROM t3b;
CREATE VIEW t4 AS SELECT * FROM t4a UNION ALL SELECT * FROM t4b;
CREATE VIEW t5 AS SELECT * FROM t5a UNION ALL SELECT * FROM t5b;
CREATE VIEW t6 AS SELECT * FROM t6a UNION ALL SELECT * FROM t6b;
}
5 {
CREATE TABLE t3a(id INTEGER PRIMARY KEY, w TEXT) WITHOUT ROWID;
CREATE TABLE t3b(id INTEGER PRIMARY KEY, w TEXT);
CREATE TABLE t4a(id INTEGER PRIMARY KEY, x TEXT) WITHOUT ROWID;
CREATE TABLE t4b(id INTEGER PRIMARY KEY, x TEXT) WITHOUT ROWID;
CREATE TABLE t5a(id INTEGER PRIMARY KEY, y TEXT);
CREATE TABLE t5b(id INTEGER PRIMARY KEY, y TEXT) WITHOUT ROWID;
CREATE TABLE t6a(id INTEGER PRIMARY KEY, z INT);
CREATE TABLE t6b(id INTEGER PRIMARY KEY, z INT);
CREATE VIEW dual(dummy) AS VALUES('x');
INSERT INTO t3a(id,w) VALUES(2,'two'),(3,'three');
INSERT INTO t3b(id,w) VALUES(6,'six'),(7,'seven');
INSERT INTO t4a(id,x) VALUES(2,'alice'),(4,'bob');
INSERT INTO t4b(id,x) VALUES(6,'cindy'),(8,'dave');
INSERT INTO t5a(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow');
INSERT INTO t5b(id,y) VALUES(4,'green'),(5,'blue');
INSERT INTO t6a(id,z) VALUES(3,333),(4,444);
INSERT INTO t6b(id,z) VALUES(5,555),(0,1000),(9,999);
CREATE VIEW t3 AS SELECT * FROM t3a UNION ALL SELECT * FROM t3b;
CREATE VIEW t4 AS SELECT * FROM t4a UNION ALL SELECT * FROM t4b LIMIT 50;
CREATE VIEW t5 AS SELECT * FROM t5a UNION ALL SELECT * FROM t5b LIMIT 100;
CREATE VIEW t6 AS SELECT * FROM t6a UNION ALL SELECT * FROM t6b;
}
} {
reset_db
db nullvalue -
do_execsql_test join9-$id.setup $schema {}
# Verifid by PG-14 for case 1
do_execsql_test join9-$id.100 {
SELECT *, t4.id, t5.id, t6.id
FROM t4 NATURAL LEFT JOIN t5 NATURAL LEFT JOIN t6
ORDER BY 1;
} {
2 alice orange - 2 2 -
4 bob green 444 4 4 4
6 cindy - - 6 - -
8 dave - - 8 - -
}
do_execsql_test join9-$id.101 {
SELECT *, t4.id, t5.id, t6.id
FROM t4 NATURAL LEFT JOIN t5 NATURAL LEFT JOIN t6
ORDER BY id;
} {
2 alice orange - 2 2 -
4 bob green 444 4 4 4
6 cindy - - 6 - -
8 dave - - 8 - -
}
do_execsql_test join9-$id.102 {
SELECT *, t4.id, t5.id, t6.id
FROM t4 LEFT JOIN t5 USING(id) LEFT JOIN t6 USING(id)
ORDER BY id;
} {
2 alice orange - 2 2 -
4 bob green 444 4 4 4
6 cindy - - 6 - -
8 dave - - 8 - -
}
# Verifid by PG-14 using case 1
do_execsql_test join9-$id.200 {
SELECT id, x, y, z, t4.id, t5.id, t6.id
FROM t5 NATURAL RIGHT JOIN t4 NATURAL LEFT JOIN t6
ORDER BY 1;
} {
2 alice orange - 2 2 -
4 bob green 444 4 4 4
6 cindy - - 6 - -
8 dave - - 8 - -
}
do_execsql_test join9-$id.201 {
SELECT id, x, y, z, t4.id, t5.id, t6.id
FROM t5 NATURAL RIGHT JOIN t4 NATURAL LEFT JOIN t6
ORDER BY id;
} {
2 alice orange - 2 2 -
4 bob green 444 4 4 4
6 cindy - - 6 - -
8 dave - - 8 - -
}
# Verified by PG-14 using case 1
do_execsql_test join9-$id.300 {
SELECT *, t4.id, t5.id, t6.id
FROM t4 NATURAL RIGHT JOIN t5 NATURAL RIGHT JOIN t6
ORDER BY 1;
} {
0 - - 1000 - - 0
3 - yellow 333 - 3 3
4 bob green 444 4 4 4
5 - blue 555 - 5 5
9 - - 999 - - 9
}
do_execsql_test join9-$id.301 {
SELECT *, t4.id, t5.id, t6.id
FROM t4 NATURAL RIGHT JOIN t5 NATURAL RIGHT JOIN t6
ORDER BY id;
} {
0 - - 1000 - - 0
3 - yellow 333 - 3 3
4 bob green 444 4 4 4
5 - blue 555 - 5 5
9 - - 999 - - 9
}
# Verified by PG-14 for case 1
do_execsql_test join9-$id.400 {
SELECT *, t4.id, t5.id, t6.id
FROM t4 NATURAL FULL JOIN t5 NATURAL FULL JOIN t6
ORDER BY 1;
} {
0 - - 1000 - - 0
1 - red - - 1 -
2 alice orange - 2 2 -
3 - yellow 333 - 3 3
4 bob green 444 4 4 4
5 - blue 555 - 5 5
6 cindy - - 6 - -
8 dave - - 8 - -
9 - - 999 - - 9
}
do_execsql_test join9-$id.401 {
SELECT *, t4.id, t5.id, t6.id
FROM t4 NATURAL FULL JOIN t5 NATURAL FULL JOIN t6
ORDER BY id;
} {
0 - - 1000 - - 0
1 - red - - 1 -
2 alice orange - 2 2 -
3 - yellow 333 - 3 3
4 bob green 444 4 4 4
5 - blue 555 - 5 5
6 cindy - - 6 - -
8 dave - - 8 - -
9 - - 999 - - 9
}
do_execsql_test join9-$id.402 {
SELECT id, x, y, z, t4.id, t5.id, t6.id
FROM t4 NATURAL FULL JOIN t6 NATURAL FULL JOIN t5
ORDER BY id;
} {
0 - - 1000 - - 0
1 - red - - 1 -
2 alice orange - 2 2 -
3 - yellow 333 - 3 3
4 bob green 444 4 4 4
5 - blue 555 - 5 5
6 cindy - - 6 - -
8 dave - - 8 - -
9 - - 999 - - 9
}
do_execsql_test join9-$id.403 {
SELECT id, x, y, z, t4.id, t5.id, t6.id
FROM t5 NATURAL FULL JOIN t4 NATURAL FULL JOIN t6
ORDER BY id;
} {
0 - - 1000 - - 0
1 - red - - 1 -
2 alice orange - 2 2 -
3 - yellow 333 - 3 3
4 bob green 444 4 4 4
5 - blue 555 - 5 5
6 cindy - - 6 - -
8 dave - - 8 - -
9 - - 999 - - 9
}
do_execsql_test join9-$id.404 {
SELECT id, x, y, z, t4.id, t5.id, t6.id
FROM t5 NATURAL FULL JOIN t6 NATURAL FULL JOIN t4
ORDER BY id;
} {
0 - - 1000 - - 0
1 - red - - 1 -
2 alice orange - 2 2 -
3 - yellow 333 - 3 3
4 bob green 444 4 4 4
5 - blue 555 - 5 5
6 cindy - - 6 - -
8 dave - - 8 - -
9 - - 999 - - 9
}
do_execsql_test join9-$id.405 {
SELECT id, x, y, z, t4.id, t5.id, t6.id
FROM t6 NATURAL FULL JOIN t4 NATURAL FULL JOIN t5
ORDER BY id;
} {
0 - - 1000 - - 0
1 - red - - 1 -
2 alice orange - 2 2 -
3 - yellow 333 - 3 3
4 bob green 444 4 4 4
5 - blue 555 - 5 5
6 cindy - - 6 - -
8 dave - - 8 - -
9 - - 999 - - 9
}
do_execsql_test join9-$id.406 {
SELECT id, x, y, z, t4.id, t5.id, t6.id
FROM t6 NATURAL FULL JOIN t5 NATURAL FULL JOIN t4
ORDER BY id;
} {
0 - - 1000 - - 0
1 - red - - 1 -
2 alice orange - 2 2 -
3 - yellow 333 - 3 3
4 bob green 444 4 4 4
5 - blue 555 - 5 5
6 cindy - - 6 - -
8 dave - - 8 - -
9 - - 999 - - 9
}
# Verified by PG-14 using case 1
do_execsql_test join9-$id.500 {
SELECT id, w, x, y, z
FROM t3 FULL JOIN t4 USING(id)
NATURAL FULL JOIN t5
FULL JOIN t6 USING(id)
ORDER BY 1;
} {
0 - - - 1000
1 - - red -
2 two alice orange -
3 three - yellow 333
4 - bob green 444
5 - - blue 555
6 six cindy - -
7 seven - - -
8 - dave - -
9 - - - 999
}
# Verified by PG-14 using case 1
do_execsql_test join9-$id.600 {
SELECT id, w, x, y, z
FROM t3 JOIN dual AS d1 ON true
FULL JOIN t4 USING(id)
JOIN dual AS d2 ON true
NATURAL FULL JOIN t5
JOIN dual AS d3 ON true
FULL JOIN t6 USING(id)
CROSS JOIN dual AS d4
ORDER BY 1;
} {
0 - - - 1000
1 - - red -
2 two alice orange -
3 three - yellow 333
4 - bob green 444
5 - - blue 555
6 six cindy - -
7 seven - - -
8 - dave - -
9 - - - 999
}
# Verified by PG-14 using case 1
do_execsql_test join9-$id.700 {
SELECT id, w, x, y, z
FROM t3 JOIN dual AS d1 ON true
FULL JOIN t4 USING(id)
JOIN dual AS d2 ON true
NATURAL FULL JOIN t5
JOIN dual AS d3 ON true
FULL JOIN t6 USING(id)
CROSS JOIN dual AS d4
WHERE x<>'bob' OR x IS NULL
ORDER BY 1;
} {
0 - - - 1000
1 - - red -
2 two alice orange -
3 three - yellow 333
5 - - blue 555
6 six cindy - -
7 seven - - -
8 - dave - -
9 - - - 999
}
# Verified by PG-14 using case 1
do_execsql_test join9-$id.800 {
WITH t7(id,a) AS MATERIALIZED (SELECT * FROM t4 WHERE false)
SELECT *
FROM t7
JOIN t7 AS t7b USING(id)
FULL JOIN t3 USING(id);
} {
2 - - two
3 - - three
6 - - six
7 - - seven
}
# Verified by PG-14
do_execsql_test join9-$id.900 {
SELECT *
FROM (t3 NATURAL FULL JOIN t4)
NATURAL FULL JOIN
(t5 NATURAL FULL JOIN t6)
ORDER BY 1;
} {
0 - - - 1000
1 - - red -
2 two alice orange -
3 three - yellow 333
4 - bob green 444
5 - - blue 555
6 six cindy - -
7 seven - - -
8 - dave - -
9 - - - 999
}
do_execsql_test join9-$id.910 {
SELECT *
FROM t3 NATURAL FULL JOIN
(t4 NATURAL FULL JOIN
(t5 NATURAL FULL JOIN t6))
ORDER BY 1;
} {
0 - - - 1000
1 - - red -
2 two alice orange -
3 three - yellow 333
4 - bob green 444
5 - - blue 555
6 six cindy - -
7 seven - - -
8 - dave - -
9 - - - 999
}
do_execsql_test join9-$id.920 {
SELECT *
FROM t3 FULL JOIN (
t4 FULL JOIN (
t5 FULL JOIN t6 USING (id)
) USING(id)
) USING(id)
ORDER BY 1;
} {
0 - - - 1000
1 - - red -
2 two alice orange -
3 three - yellow 333
4 - bob green 444
5 - - blue 555
6 six cindy - -
7 seven - - -
8 - dave - -
9 - - - 999
}
do_execsql_test join9-$id.920 {
SELECT *
FROM t3 FULL JOIN (
t4 FULL JOIN (
t5 FULL JOIN t6 USING (id)
) USING(id)
) USING(id)
ORDER BY 1;
} {
0 - - - 1000
1 - - red -
2 two alice orange -
3 three - yellow 333
4 - bob green 444
5 - - blue 555
6 six cindy - -
7 seven - - -
8 - dave - -
9 - - - 999
}
# Verified by PG-14
do_execsql_test join9-$id.930 {
SELECT *
FROM t3 FULL JOIN (
t4 FULL JOIN (
t5 FULL JOIN t6 USING(id)
) USING(id)
) AS j1 ON j1.id=t3.id
ORDER BY coalesce(t3.id,j1.id);
} {
- - 0 - - 1000
- - 1 - red -
2 two 2 alice orange -
3 three 3 - yellow 333
- - 4 bob green 444
- - 5 - blue 555
6 six 6 cindy - -
7 seven - - - -
- - 8 dave - -
- - 9 - - 999
}
# Verified by PG-14
do_execsql_test join9-$id.940 {
SELECT *
FROM t3 FULL JOIN (
t4 RIGHT JOIN (
t5 FULL JOIN t6 USING(id)
) USING(id)
) AS j1 ON j1.id=t3.id
ORDER BY coalesce(t3.id,j1.id);
} {
- - 0 - - 1000
- - 1 - red -
2 two 2 alice orange -
3 three 3 - yellow 333
- - 4 bob green 444
- - 5 - blue 555
6 six - - - -
7 seven - - - -
- - 9 - - 999
}
# Verified by PG-14
do_execsql_test join9-$id.950 {
SELECT *
FROM t3 FULL JOIN (
t4 LEFT JOIN (
t5 FULL JOIN t6 USING(id)
) USING(id)
) AS j1 ON j1.id=t3.id
ORDER BY coalesce(t3.id,j1.id);
} {
2 two 2 alice orange -
3 three - - - -
- - 4 bob green 444
6 six 6 cindy - -
7 seven - - - -
- - 8 dave - -
}
# Restriction (27) in the query flattener
# Verified by PG-14
do_execsql_test join9-$id.1000 {
WITH t56(id,y,z) AS (SELECT * FROM t5 FULL JOIN t6 USING(id) LIMIT 50)
SELECT id,x,y,z FROM t4 JOIN t56 USING(id)
ORDER BY 1;
} {
2 alice orange -
4 bob green 444
}
# Verified by PG-14
do_execsql_test join9-$id.1010 {
SELECT id,x,y,z
FROM t4 INNER JOIN (t5 FULL JOIN t6 USING(id)) USING(id)
ORDER BY 1;
} {
2 alice orange -
4 bob green 444
}
# Verified by PG-14
do_execsql_test join9-$id.1020 {
SELECT id,x,y,z
FROM t4 FULL JOIN t5 USING(id) INNER JOIN t6 USING(id)
ORDER BY 1;
} {
3 - yellow 333
4 bob green 444
5 - blue 555
}
# Verified by PG-14
do_execsql_test join9-$id.1030 {
WITH t45(id,x,y) AS (SELECT * FROM t4 FULL JOIN t5 USING(id) LIMIT 50)
SELECT id,x,y,z FROM t45 JOIN t6 USING(id)
ORDER BY 1;
} {
3 - yellow 333
4 bob green 444
5 - blue 555
}
}
finish_test
+214
View File
@@ -0,0 +1,214 @@
# 2022-04-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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for RIGHT and FULL OUTER JOINs.
set testdir [file dirname $argv0]
source $testdir/tester.tcl
foreach {id schema} {
1 {
CREATE TABLE t1(a INT, b INT, c INT, d INT);
CREATE TABLE t2(c INT, d INT, e INT, f INT);
CREATE TABLE t3(a INT, b INT, e INT, f INT);
CREATE TABLE t4(a INT, c INT, d INT, f INT);
INSERT INTO t1 VALUES(11,21,31,41),(12,22,32,42),(15,25,35,45),(18,28,38,48);
INSERT INTO t2 VALUES(12,22,32,42),(13,23,33,43),(15,25,35,45),(17,27,37,47);
INSERT INTO t3 VALUES(14,24,34,44),(15,25,35,45),(16,26,36,46);
INSERT INTO t4 VALUES(11,21,31,41),(13,23,33,43),(16,26,36,46),(19,29,39,49);
}
2 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c INT, d INT);
CREATE TABLE t2(c INT, d INTEGER PRIMARY KEY, e INT, f INT);
CREATE TABLE t3(a INT, b INT, e INTEGER PRIMARY KEY, f INT);
CREATE TABLE t4(a INT, c INT, d INT, f INT PRIMARY KEY) WITHOUT ROWID;
INSERT INTO t1 VALUES(11,21,31,41),(12,22,32,42),(15,25,35,45),(18,28,38,48);
INSERT INTO t2 VALUES(12,22,32,42),(13,23,33,43),(15,25,35,45),(17,27,37,47);
INSERT INTO t3 VALUES(14,24,34,44),(15,25,35,45),(16,26,36,46);
INSERT INTO t4 VALUES(11,21,31,41),(13,23,33,43),(16,26,36,46),(19,29,39,49);
}
3 {
CREATE TABLE t1a(a INT, b INT, c INT, d INT);
CREATE TABLE t2a(c INT, d INT, e INT, f INT);
CREATE TABLE t3a(a INT, b INT, e INT, f INT);
CREATE TABLE t4a(a INT, c INT, d INT, f INT);
INSERT INTO t1a VALUES(11,21,31,41),(12,22,32,42);
INSERT INTO t2a VALUES(12,22,32,42),(13,23,33,43);
INSERT INTO t3a VALUES(14,24,34,44),(15,25,35,45);
INSERT INTO t4a VALUES(11,21,31,41),(13,23,33,43);
CREATE TABLE t1b(a INT, b INT, c INT, d INT);
CREATE TABLE t2b(c INT, d INT, e INT, f INT);
CREATE TABLE t3b(a INT, b INT, e INT, f INT);
CREATE TABLE t4b(a INT, c INT, d INT, f INT);
INSERT INTO t1b VALUES(15,25,35,45),(18,28,38,48);
INSERT INTO t2b VALUES(15,25,35,45),(17,27,37,47);
INSERT INTO t3b VALUES(15,25,35,45),(16,26,36,46);
INSERT INTO t4b VALUES(16,26,36,46),(19,29,39,49);
CREATE VIEW t1 AS SELECT * FROM t1a UNION SELECT * FROM t1b;
CREATE VIEW t2 AS SELECT * FROM t2a UNION SELECT * FROM t2b;
CREATE VIEW t3 AS SELECT * FROM t3a UNION SELECT * FROM t3b;
CREATE VIEW t4 AS SELECT * FROM t4a UNION SELECT * FROM t4b;
}
} {
reset_db
db nullvalue -
do_execsql_test joinA-$id.setup $schema {}
# Verified by PG-14
do_execsql_test joinA-$id.100 {
SELECT a,b,c,d,t2.e,f,t3.e
FROM t1
INNER JOIN t2 USING(c,d)
INNER JOIN t3 USING(a,b,f)
INNER JOIN t4 USING(a,c,d,f)
ORDER BY 1 nulls first, 3 nulls first;
} {}
# Verified by PG-14
do_execsql_test joinA-$id.110 {
SELECT a,b,c,d,t2.e,f,t3.e
FROM t1
LEFT JOIN t2 USING(c,d)
LEFT JOIN t3 USING(a,b,f)
LEFT JOIN t4 USING(a,c,d,f)
ORDER BY 1 nulls first, 3 nulls first;
} {
11 21 31 41 - - -
12 22 32 42 - - -
15 25 35 45 - - -
18 28 38 48 - - -
}
# Verified by PG-14
do_execsql_test joinA-$id.120 {
SELECT a,b,c,d,t2.e,f,t3.e
FROM t1
LEFT JOIN t2 USING(c,d)
RIGHT JOIN t3 USING(a,b,f)
LEFT JOIN t4 USING(a,c,d,f)
ORDER BY 1 nulls first, 3 nulls first;
} {
14 24 - - - 44 34
15 25 - - - 45 35
16 26 - - - 46 36
}
# Verified by PG-14
do_execsql_test joinA-$id.130 {
SELECT a,b,c,d,t2.e,f,t3.e
FROM t1
RIGHT JOIN t2 USING(c,d)
LEFT JOIN t3 USING(a,b,f)
RIGHT JOIN t4 USING(a,c,d,f)
ORDER BY 1 nulls first, 3 nulls first;
} {
11 - 21 31 - 41 -
13 - 23 33 - 43 -
16 - 26 36 - 46 -
19 - 29 39 - 49 -
}
# Verified by PG-14
do_execsql_test joinA-$id.140 {
SELECT a,b,c,d,t2.e,f,t3.e
FROM t1
FULL JOIN t2 USING(c,d)
LEFT JOIN t3 USING(a,b,f)
RIGHT JOIN t4 USING(a,c,d,f)
ORDER BY 1 nulls first, 3 nulls first;
} {
11 - 21 31 - 41 -
13 - 23 33 - 43 -
16 - 26 36 - 46 -
19 - 29 39 - 49 -
}
# Verified by PG-14
do_execsql_test joinA-$id.150 {
SELECT a,b,c,d,t2.e,f,t3.e
FROM t1
RIGHT JOIN t2 USING(c,d)
FULL JOIN t3 USING(a,b,f)
RIGHT JOIN t4 USING(a,c,d,f)
ORDER BY 1 nulls first, 3 nulls first;
} {
11 - 21 31 - 41 -
13 - 23 33 - 43 -
16 - 26 36 - 46 -
19 - 29 39 - 49 -
}
# Verified by PG-14
do_execsql_test joinA-$id.160 {
SELECT a,b,c,d,t2.e,f,t3.e
FROM t1
RIGHT JOIN t2 USING(c,d)
LEFT JOIN t3 USING(a,b,f)
FULL JOIN t4 USING(a,c,d,f)
ORDER BY 1 nulls first, 3 nulls first;
} {
- - 12 22 32 42 -
- - 13 23 33 43 -
- - 15 25 35 45 -
- - 17 27 37 47 -
11 - 21 31 - 41 -
13 - 23 33 - 43 -
16 - 26 36 - 46 -
19 - 29 39 - 49 -
}
# Verified by PG-14
do_execsql_test joinA-$id.170 {
SELECT a,b,c,d,t2.e,f,t3.e
FROM t1
LEFT JOIN t2 USING(c,d)
RIGHT JOIN t3 USING(a,b,f)
FULL JOIN t4 USING(a,c,d,f)
ORDER BY 1 nulls first, 3 nulls first;
} {
11 - 21 31 - 41 -
13 - 23 33 - 43 -
14 24 - - - 44 34
15 25 - - - 45 35
16 26 - - - 46 36
16 - 26 36 - 46 -
19 - 29 39 - 49 -
}
# Verified by PG-14
do_execsql_test joinA-$id.200 {
SELECT a,b,c,d,t2.e,f,t3.e
FROM t1
FULL JOIN t2 USING(c,d)
FULL JOIN t3 USING(a,b,f)
FULL JOIN t4 USING(a,c,d,f)
ORDER BY 1 nulls first, 3 nulls first;
} {
- - 12 22 32 42 -
- - 13 23 33 43 -
- - 15 25 35 45 -
- - 17 27 37 47 -
11 - 21 31 - 41 -
11 21 31 41 - - -
12 22 32 42 - - -
13 - 23 33 - 43 -
14 24 - - - 44 34
15 25 - - - 45 35
15 25 35 45 - - -
16 26 - - - 46 36
16 - 26 36 - 46 -
18 28 38 48 - - -
19 - 29 39 - 49 -
}
}
finish_test
+7252
View File
File diff suppressed because it is too large Load Diff
+17
View File
@@ -850,4 +850,21 @@ do_execsql_test json-17.1 {
SELECT * FROM t1 LEFT JOIN t2 ON (SELECT b FROM json_each ORDER BY 1);
} {}
# 2022-04-04 forum post https://sqlite.org/forum/forumpost/c082aeab43
do_execsql_test json-18.1 {
SELECT json_valid('{"":5}');
} {1}
do_execsql_test json-18.2 {
SELECT json_extract('{"":5}', '$.""');
} {5}
do_execsql_test json-18.3 {
SELECT json_extract('[3,{"a":4,"":[5,{"hi":6},7]},8]', '$[1].""[1].hi');
} {6}
do_execsql_test json-18.4 {
SELECT json_extract('[3,{"a":4,"":[5,{"hi":6},7]},8]', '$[1].""[1]."hi"');
} {6}
do_catchsql_test json-18.5 {
SELECT json_extract('{"":8}', '$.');
} {1 {JSON path error near ''}}
finish_test
+3 -3
View File
@@ -545,14 +545,14 @@ do_test select1-6.9.7 {
set x [execsql2 {
SELECT * FROM test1 a, (select 5, 6) LIMIT 1
}]
regsub -all {subquery_[0-9a-fA-F_]+} $x {subquery} x
regsub -all {subquery-\d+} $x {subquery-0} x
set x
} {a.f1 11 a.f2 22 subquery.5 5 subquery.6 6}
} {a.f1 11 a.f2 22 (subquery-0).5 5 (subquery-0).6 6}
do_test select1-6.9.8 {
set x [execsql2 {
SELECT * FROM test1 a, (select 5 AS x, 6 AS y) AS b LIMIT 1
}]
regsub -all {subquery_[0-9a-fA-F]+_} $x {subquery} x
regsub -all {subquery-\d+} $x {subquery-0} x
set x
} {a.f1 11 a.f2 22 b.x 5 b.y 6}
do_test select1-6.9.9 {
+17
View File
@@ -1221,6 +1221,23 @@ do_test shell1-8.4 {
+------------------+-----+
| 6683623321994527 | -47 |
+------------------+-----+}}
do_test shell1-8.5 {
catchcmd ":memory: --box" {
create table t(a text, b int);
insert into t values ('too long for one line', 1), ('shorter', NULL);
.header on
.width 10 10
.nullvalue NADA
select * from t;}
} {0 {┌────────────┬────────────┐
│ a │ b │
├────────────┼────────────┤
│ too long f │ 1 │
│ or one lin │ │
│ e │ │
├────────────┼────────────┤
│ shorter │ NADA │
└────────────┴────────────┘}}
#----------------------------------------------------------------------------
# Test cases shell1-9.*: Basic test that "dot" commands and SQL intermix ok.
+30
View File
@@ -540,4 +540,34 @@ Columns renamed during .import shell5.csv due to duplicates:
"CoW" to "CoW_3",
"cOw" to "cOw_4"}}
#----------------------------------------------------------------------------
# Tests for preserving utf-8 that is not also ASCII.
#
do_test shell5-6.1 {
set out [open shell5.csv w]
fconfigure $out -translation lf
puts $out {あい,うえお}
puts $out {1,2}
close $out
forcedelete test.db
catchcmd test.db {.import -csv shell5.csv t1
.mode line
SELECT * FROM t1;}
} {0 { あい = 1
うえお = 2}}
do_test shell5-6.2 {
set out [open shell5.csv w]
fconfigure $out -translation lf
puts $out {1,2}
puts $out {あい,うえお}
close $out
forcedelete test.db
catchcmd test.db {.import -csv shell5.csv t1
.mode line
SELECT * FROM t1;}
} {0 { 1 = あい
2 = うえお}}
finish_test
+1
View File
@@ -1011,6 +1011,7 @@ proc query_plan_graph {sql} {
append a [append_graph " " dx cx 0]
regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx} a
regsub -all {(MATERIALIZE|CO-ROUTINE|SUBQUERY) \d+\y} $a {\1 xxxxxx} a
regsub -all {\((join|subquery)-\d+\)} $a {(\1-xxxxxx)} a
return $a
}
+3 -3
View File
@@ -34,13 +34,13 @@ do_test tkt3935.3 {
do_test tkt3935.4 {
catchsql { SELECT a FROM (t1) AS t ON b USING(a) }
} {1 {a JOIN clause is required before ON}}
} {1 {near "USING": syntax error}}
do_test tkt3935.5 {
catchsql { SELECT a FROM (t1) AS t ON b }
} {1 {a JOIN clause is required before ON}}
do_test tkt3935.6 {
catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b USING(a) }
} {1 {a JOIN clause is required before ON}}
} {1 {near "USING": syntax error}}
do_test tkt3935.7 {
catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b }
} {1 {a JOIN clause is required before ON}}
@@ -49,7 +49,7 @@ do_test tkt3935.8 {
} {1 {a JOIN clause is required before ON}}
do_test tkt3935.9 {
catchsql { SELECT a FROM t1 AS t ON b USING(a) }
} {1 {a JOIN clause is required before ON}}
} {1 {near "USING": syntax error}}
do_test tkt3935.10 {
catchsql { SELECT a FROM t1 AS t USING(a) }
} {1 {a JOIN clause is required before USING}}
+20
View File
@@ -382,4 +382,24 @@ do_execsql_test 6.2 {
)
} {}
# 2022-03-21
# https://sqlite.org/forum/forumpost/929168fdd6
#
reset_db
do_execsql_test 7.0 {
CREATE TABLE t1(a);
INSERT INTO t1(a) VALUES(11),(22),(33),(44),(55);
CREATE VIEW t2(b,c) AS SELECT a, COUNT(*) OVER () FROM t1;
CREATE TABLE t3(x,y);
CREATE TRIGGER t2r1 INSTEAD OF UPDATE ON t2 BEGIN
INSERT INTO t3(x,y) VALUES(new.b,new.c);
END;
SELECT * FROM t2;
} {11 5 22 5 33 5 44 5 55 5}
do_execsql_test 7.1 {
UPDATE t2 SET c=t1.a FROM t1 WHERE t2.b=t1.a;
SELECT * FROM t3;
} {11 11 22 22 33 33 44 44 55 55}
finish_test
+8 -8
View File
@@ -223,11 +223,11 @@ do_test vtab6-2.2 {
SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1;
}
} {1 2 3 {} 2 3 4 1 3 4 5 2}
do_test vtab6-2.3 {
catchsql {
SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2;
}
} {1 {RIGHT and FULL OUTER JOINs are not currently supported}}
#do_test vtab6-2.3 {
# catchsql {
# SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2;
# }
#} {1 {RIGHT and FULL OUTER JOINs are not currently supported}}
do_test vtab6-2.4 {
execsql {
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d
@@ -263,7 +263,7 @@ do_test vtab6-3.3 {
catchsql {
SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b);
}
} {1 {cannot have both ON and USING clauses in the same join}}
} {1 {near "USING": syntax error}}
do_test vtab6-3.4 {
catchsql {
SELECT * FROM t1 JOIN t2 USING(a);
@@ -281,12 +281,12 @@ do_test vtab6-3.7 {
catchsql {
SELECT * FROM t1 INNER OUTER JOIN t2;
}
} {1 {unknown or unsupported join type: INNER OUTER}}
} {1 {unknown join type: INNER OUTER}}
do_test vtab6-3.7 {
catchsql {
SELECT * FROM t1 LEFT BOGUS JOIN t2;
}
} {1 {unknown or unsupported join type: LEFT BOGUS}}
} {1 {unknown join type: LEFT BOGUS}}
do_test vtab6-4.1 {
execsql {
+9
View File
@@ -1348,16 +1348,25 @@ do_execsql_test where-18.1 {
INSERT INTO t181 VALUES(1);
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL;
} {1}
do_execsql_test where-18.1rj {
SELECT DISTINCT a FROM t182 RIGHT JOIN t181 ON a=b ORDER BY c IS NULL;
} {1}
do_execsql_test where-18.2 {
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c;
} {1}
do_execsql_test where-18.3 {
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c;
} {1}
do_execsql_test where-18.3rj {
SELECT DISTINCT a FROM t182 RIGHT JOIN t181 ON a=b ORDER BY c;
} {1}
do_execsql_test where-18.4 {
INSERT INTO t181 VALUES(1),(1),(1),(1);
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c;
} {1}
do_execsql_test where-18.4rj {
SELECT DISTINCT a FROM t182 RIGHT JOIN t181 ON a=b ORDER BY +c;
} {1}
do_execsql_test where-18.5 {
INSERT INTO t181 VALUES(2);
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL, +a;
+2 -2
View File
@@ -378,9 +378,9 @@ ifcapable explain {
|--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?)
`--MULTI-INDEX OR
|--INDEX 1
| `--SEARCH t2 USING INDEX t2d (d=?)
| `--SEARCH t2 USING INDEX t2d (d=?) LEFT-JOIN
`--INDEX 2
`--SEARCH t2 USING COVERING INDEX t2f (f=?)
`--SEARCH t2 USING COVERING INDEX t2f (f=?) LEFT-JOIN
}]
}
+45
View File
@@ -365,4 +365,49 @@ do_execsql_test 9.0 {
FROM seps;
} {-22- -22-333- -333-4444- -4444-}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 10.1 {
CREATE TABLE t1(i INTEGER PRIMARY KEY, v);
INSERT INTO t1 VALUES( 1, 'one' );
INSERT INTO t1 VALUES( 2, 'two' );
}
do_execsql_test 10.2 {
SELECT
json_group_array( v ) OVER w,
json_group_array( v ) OVER w
FROM t1
window w as (
range between unbounded preceding and unbounded following
)
} {
{["one","two"]}
{["one","two"]}
{["one","two"]}
{["one","two"]}
}
do_execsql_test 10.3 {
SELECT
group_concat( v ) OVER w,
json_group_array( v ) OVER w,
json_group_array( v ) OVER w,
group_concat( v ) OVER w
FROM t1
window w as (
range between unbounded preceding and unbounded following
)
} {
one,two
{["one","two"]}
{["one","two"]}
one,two
one,two
{["one","two"]}
{["one","two"]}
one,two
}
finish_test
+4 -4
View File
@@ -1075,10 +1075,10 @@ do_execsql_test 21.2 {
# Make sure crazy nexted CTE joins terminate with an error quickly.
#
do_catchsql_test 22.1 {
WITH RECURSIVE c AS (
WITH RECURSIVE c AS (
WITH RECURSIVE c AS (
WITH RECURSIVE c AS (
WITH RECURSIVE c AS NOT MATERIALIZED (
WITH RECURSIVE c AS NOT MATERIALIZED (
WITH RECURSIVE c AS NOT MATERIALIZED (
WITH RECURSIVE c AS NOT MATERIALIZED (
WITH c AS (VALUES(0))
SELECT 1 FROM c LEFT JOIN c ON ltrim(1)
)
+68 -1
View File
@@ -229,10 +229,12 @@ do_eqp_test 211 {
} {
QUERY PLAN
|--MATERIALIZE c1
| |--MATERIALIZE c
| |--CO-ROUTINE c
| | `--SCAN 3 CONSTANT ROWS
| `--SCAN c
|--MATERIALIZE c2
| |--CO-ROUTINE c
| | `--SCAN 3 CONSTANT ROWS
| `--SCAN c
|--SCAN c1
|--SCAN c2
@@ -250,6 +252,71 @@ do_execsql_test 220 {
SELECT y FROM t2 ORDER BY y;
} {40404 40405 40406 40504 40505 40506 40604 40605 40606}
# 2022-04-22: Do not allow flattening of a MATERIALIZED CTE into
# an outer query.
#
reset_db
db null -
do_execsql_test 300 {
CREATE TABLE t2(a INT,b INT,d INT); INSERT INTO t2 VALUES(4,5,6),(7,8,9);
CREATE TABLE t3(a INT,b INT,e INT); INSERT INTO t3 VALUES(3,3,3),(8,8,8);
} {}
do_execsql_test 310 {
WITH t23 AS MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b))
SELECT * FROM t23;
} {
4 5 6 - -
7 8 9 8 8
- 3 - 3 3
}
do_eqp_test 311 {
WITH t23 AS MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b))
SELECT * FROM t23;
} {
QUERY PLAN
|--MATERIALIZE t23
| |--SCAN t2
| |--SCAN t3 LEFT-JOIN
| `--RIGHT-JOIN t3
| `--SCAN t3
`--SCAN t23
}
do_execsql_test 320 {
WITH t23 AS NOT MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b))
SELECT * FROM t23;
} {
4 5 6 - -
7 8 9 8 8
- 3 - 3 3
}
do_eqp_test 321 {
WITH t23 AS NOT MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b))
SELECT * FROM t23;
} {
QUERY PLAN
|--SCAN t2
|--SCAN t3 LEFT-JOIN
`--RIGHT-JOIN t3
`--SCAN t3
}
do_execsql_test 330 {
WITH t23 AS (SELECT * FROM t2 FULL JOIN t3 USING(b))
SELECT * FROM t23;
} {
4 5 6 - -
7 8 9 8 8
- 3 - 3 3
}
do_eqp_test 331 {
WITH t23 AS (SELECT * FROM t2 FULL JOIN t3 USING(b))
SELECT * FROM t23;
} {
QUERY PLAN
|--SCAN t2
|--SCAN t3 LEFT-JOIN
`--RIGHT-JOIN t3
`--SCAN t3
}
finish_test
+1
View File
@@ -3015,6 +3015,7 @@ void Parse(struct lemon *gp)
}
if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */
cp+=2;
if( (*cp)=='/' ) cp++;
while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){
if( c=='\n' ) lineno++;
cp++;
+1 -1
View File
@@ -158,7 +158,6 @@ set boolean_defnil_options {
SQLITE_ENABLE_QPSG
SQLITE_ENABLE_RBU
SQLITE_ENABLE_RTREE
SQLITE_ENABLE_SELECTTRACE
SQLITE_ENABLE_SESSION
SQLITE_ENABLE_SNAPSHOT
SQLITE_ENABLE_SORTER_REFERENCES
@@ -166,6 +165,7 @@ set boolean_defnil_options {
SQLITE_ENABLE_STAT4
SQLITE_ENABLE_STMT_SCANSTATUS
SQLITE_ENABLE_STMTVTAB
SQLITE_ENABLE_TREETRACE
SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SQLITE_ENABLE_UNLOCK_NOTIFY
SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+2 -1
View File
@@ -291,7 +291,8 @@ proc copy_file {filename} {
# Add the SQLITE_PRIVATE before variable declarations or
# definitions for internal use
regsub {^SQLITE_API } $line {} line
if {![regexp {^sqlite3_} $varname]} {
if {![regexp {^sqlite3_} $varname]
&& ![regexp {^sqlite3Show[A-Z]} $varname]} {
regsub {^extern } $line {} line
puts $out "SQLITE_PRIVATE $line"
} else {