Compare commits

..

216 Commits

Author SHA1 Message Date
drh 60405cd15c Version 3.34.1
FossilOrigin-Name: 10e20c0b43500cfb9bbc0eaa061c57514f715d87238f4d835880cd846b9ebd1f
2021-01-20 14:10:07 +00:00
drh b08dbd0f28 Fix an issue with sha3_query() when the first argument contains blank
SQL statements.

FossilOrigin-Name: a1a7a5f238fcfdcd56faba063e381258c9e2944d9b02b31d402a4207a607fc1c
2021-01-19 20:38:13 +00:00
drh 00a0b135ec Bump the version number to 3.34.1.
FossilOrigin-Name: cea7d0f8a3d9b3f5caae63ad555de25b53c577fc8e004127ec18cc7f0c6f1714
2021-01-19 20:17:46 +00:00
drh 90ab71bdc8 Fix a problem handling sub-queries with both a correlated WHERE clause and a "HAVING 0" clause where the parent query is itself an aggregate.
The problem was apparently introduced by check-in [6e6b3729e0549de0]

FossilOrigin-Name: 30a4c323650cc9498a6dacd1760dd5170d7cc7848c4e96ff6bd64da365f96366
2021-01-19 20:09:44 +00:00
drh 4dca7d4cfb Prevent potential segfault in the sqlite-expert idxPopulateStat1 context cleanup code.
FossilOrigin-Name: 69e31d52b2a7bde1ed72bc7b927ff451139fbc76504e750324e6368ad26b11b1
2021-01-19 20:04:37 +00:00
drh 1dc9cf947b Fix a typo in the sqlite3_free_filename() documentation.
FossilOrigin-Name: 7316ee19c590854545019a56799968143109929049424a8cc1dcf9624f98a544
2020-12-16 13:20:15 +00:00
drh 384f5c26f4 Version 3.34.0
FossilOrigin-Name: a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b
2020-12-01 16:14:00 +00:00
dan 9f4fb42730 Update the tea/win/makefile.vc file that ships as part of the autoconf package to use "sqlite3" instead of "tclsqlite3" for the installed dll filename.
FossilOrigin-Name: 23212b1a054f05773a9f69f9802035eea6a9d759a2a09e22f46d1046c058b417
2020-11-30 18:52:08 +00:00
dan aeb4e6eebd Update the tea/win/makefile.vc file that ships as part of the autoconf package to use "sqlite3" instead of "tclsqlite3" for the installed dll filename.
FossilOrigin-Name: 93d4d9dc05bb86c08a12d56b3ce68ec39b69e57951a936fb3b326812c051c3b4
2020-11-30 18:43:40 +00:00
drh 56a5747e63 Do not reuse the obsolete SQLITE_TESTCTRL_PRNG_RESET value for
SQLITE_TESTCTRL_SEEK_COUNT.  Give SEEK_COUNT its own unique value.
This avoids incompatibility with legacy test code.

FossilOrigin-Name: fdba0b129091d607dc0c1aa52f8631a208dbff22476a298bd5428e672593ed18
2020-11-30 14:20:17 +00:00
dan cad760d16e Fix a compiler warning in fts5_aux.c.
FossilOrigin-Name: 8edb983bc87898eff2cd2e7e672a32a47c71b2be9d818513d339e95560d45b2b
2020-11-27 19:40:13 +00:00
dan 6d19bf9460 Add missing cast to fts5 bm25() code.
FossilOrigin-Name: 6ff9673847c0b4174d9435e93d19af0ee7406b1a12edeb6edec98697e1646824
2020-11-27 16:15:55 +00:00
dan 3181706895 Remove a redundant "if( rc==SQLITE_OK )" from the fts5 bm25() code.
FossilOrigin-Name: d85f4f27f58adcc75fc7d59e63af95b2a338052d8748a11f22ec1e48d1aff4cc
2020-11-27 16:08:15 +00:00
dan 66efc393c5 Move an "if( rc==SQLITE_OK )" to outside a loop body in the fts5 bm25() code.
FossilOrigin-Name: 14a4dcf3474566d072007a37d214c892397c21dd3b7f8b55ad0e5edfb7130dd6
2020-11-27 16:05:31 +00:00
dan 1c5b23f170 Fix a case in the FTS5 integrity check where a corrupt database could cause a buffer overread.
FossilOrigin-Name: a32b4f650d2d543bd2773cbc8655c1679a20b35ac9ec4d08c7754ddf6d972acb
2020-11-27 15:28:26 +00:00
dan ec8962869a Update mkunicode.tcl to match the change erroneously made to machine generated file fts5_unicode2.c in [b7b7bde9].
FossilOrigin-Name: 326d579d777fdede6bc64f9525248767f4730de4e50260b0387e614a9d006416
2020-11-26 20:13:54 +00:00
drh 68b4034450 Update a requirement mark in the e_expr.test script.
FossilOrigin-Name: bb174a074b5833181900d396edda955254ea1768750a0ab3b6d714530b1fe13f
2020-11-25 18:44:20 +00:00
drh d36f588f31 Fix harmless compiler warnings about unused function parameters.
FossilOrigin-Name: 25d067c270966d9506db8bedf280883e32b69050b14bdbbeda4bb2d9a362619c
2020-11-25 16:28:04 +00:00
drh 3ef2cb5991 Fix a potential NULL pointer dereference in the geopoly_overlap() routine
of the GeoPoly extension.

FossilOrigin-Name: b5665712e667a20d42a2e892d9d540f4273609eabd56f8178e1d5664280821f3
2020-11-25 15:29:08 +00:00
drh f82d78e9c2 Fix the shell1.test test script so that it works on windows.
FossilOrigin-Name: 9bd15b07e58b1811c2a368ec76059ac683a2c35b163ef4bba01ccb8b7ca7288d
2020-11-25 14:50:42 +00:00
drh b7c46aa8c9 Change the -init option to the command-line shell to honor the -bail option.
Also change it to report an error if the filename mentioned cannot be
opened.

FossilOrigin-Name: a29f54bd2c032374d7235bb1f9d4c04c094611bbc7d274b7b92722b5b802050c
2020-11-25 13:59:47 +00:00
drh f862b55a56 Fix a typo in the sqlite3_txn_state() documentation.
FossilOrigin-Name: 5b4325295b2f17b7a4eaa2d3a30d06a24801992b3aa17c7d57e015f9f395fb95
2020-11-24 23:40:48 +00:00
drh 4989a530a1 Add the new sqlite3_txn_state() interface to the set of routines accessible
by run-time loadables extensions.

FossilOrigin-Name: db25f1dc8eb8b8bd45912e9b457d4cc32687bc4f709ce1878e9b4ccedbb18af9
2020-11-24 21:19:23 +00:00
drh a7fc1686e4 Fix a harmless typo in a comment.
FossilOrigin-Name: b2a201f1b5dc2fc94b360df4807c108fac47db2399edd8763efbdd66b71ffe5f
2020-11-24 19:55:49 +00:00
dan f5c3a75b63 Fix a bug in OOM handling code introduced by [6a28713d].
FossilOrigin-Name: 8a786ce99491401dd7660e54f1a1ba3b2300cecbe180b1a31e549ff5f5b77bdc
2020-11-24 17:55:34 +00:00
dan 2e3cb1382f Ensure that super-journal and other journal filenames passed by SQLite to an sqlite3_vfs.xOpen() implementation may be safely passed to sqlite3_uri_parameter() and similar functions.
FossilOrigin-Name: 6a28713d59cde0882c3508160347c2ea18c7c4e9bfd1b053103af2d5e12a144c
2020-11-24 16:44:09 +00:00
drh ef5b2d27b7 Remove the VERSION_NUMBER macro from configure.ac as it has been unused
since 2009 check-in [7f4810747b086498].  See also
[forum:/forumpost/bb2c634fcd|forum post bb2c634fcd].

FossilOrigin-Name: 5466dd55d4aa15fd96f00b6e205dfb868879357a476df7ffd29b97bb570629a5
2020-11-24 13:14:15 +00:00
drh de9873bb0a Syntactic changes to work around a bug in gcov 9.3.0. No changes to the
generated code for release builds.

FossilOrigin-Name: 4f1573b146193e5d552981a9d1d11e50da4da4a843f790e4af1cf0cc19a0b020
2020-11-23 21:05:29 +00:00
drh d46beb06aa In os_unix.c, put ALWAYS() on unreachable branches associated with pathname
normalization.

FossilOrigin-Name: b45a08e3c7edfa76b699d3e29f28daa5bd08039668ec57121e4e85edf36150f1
2020-11-23 17:36:06 +00:00
dan 39acaec16c Fix a test script problem causing crash8.test to fail when run with leak-sanitizer.
FossilOrigin-Name: 2c437f7a2c87129d00c71fa569315b68e0ba9514041d93503350c9ae9f080f17
2020-11-23 15:30:16 +00:00
drh 1335ec7df7 Allow "substring()" as an alias for "substr()" for compatibility with other
SQL engines.

FossilOrigin-Name: aa2ee5754c9f8378c4d490ca756a6415042904477727f0d86e9c0190b5e8b275
2020-11-23 14:50:43 +00:00
dan 6a5e21149b Add file doc/vdbesort-memory.md, containing notes on the way vdbesort.c uses heap memory.
FossilOrigin-Name: 07f53899a929cce93f17c0332819610c9517c7e54e00092af20efd746cf84438
2020-11-20 14:16:41 +00:00
drh 6fc74a4454 The xFullPathname method of the unix VFS now normalizes the filenames by
omitting surplus "/", "/./" and "/../" strings.

FossilOrigin-Name: c38dec6f52c01614c1bee8356daf0fcd9f708d029116e9bff51e06719a730dde
2020-11-19 21:12:08 +00:00
drh e5dc4a2097 More test case changes so that shared-cache mode tests all work
with normalized database names.

FossilOrigin-Name: 6f0d5f0949130a4688319adf05d37c5ccd683ca9ad2dacb7ce433a5fe18ac3c3
2020-11-19 21:01:11 +00:00
drh f4097026ef Fix the tkt3793 test case so that work even when filenames are normalized.
FossilOrigin-Name: e85d32ac6c82d39f5dc9b28f881d5d72f5e5a7e16df12c19315bfa8edea1b0b4
2020-11-19 20:07:24 +00:00
drh 5dc18e33ae Use an ephemeral table rather than a RowSet to remember rowids in the
two-pass UPDATE algorithm, as this uses much less memory for large UPDATEs.

FossilOrigin-Name: 842c432772e6cd8464cdb7bfdb38789adeea9aa9e0486d4034cc9841f085f517
2020-11-19 19:43:46 +00:00
drh 02e4b7d7df If a read() or pread() indicates that the database file is unreadable due to
filesystem damage, then it returns SQLITE_IOERR_CORRUPTFS which is then
converted into SQLITE_CORRUPT before being returned to the application.

FossilOrigin-Name: 849e4e14fd06eda512381f5f8aa65f75ad0a955e835da7c63526a53cf5e8f4dc
2020-11-18 23:44:41 +00:00
drh f56a4bfcd1 Improvements to the mechanism that attempts to report SQLITE_CORRUPT if
pread() says that the underlying filesystem is corrupt.

FossilOrigin-Name: b887c7504e7edeba758f3c1203c6cc56eef499fe05e7e6c6d82939bf7d78c57f
2020-11-18 21:50:05 +00:00
dan 8ea11095c9 Update cksumvfs.c so that if SQLITE_AMALGAMATION is defined, SQLITE_CKSUMVFS_STATIC is implied.
FossilOrigin-Name: 184e9d782dfbad8011b5b0043b3fd8e5a369ed7076e37e14b301483ce5ffe5db
2020-11-18 20:55:01 +00:00
dan c30b78f6f3 Add test infrastructure for cksumvfs. And update cksumvfs so that it works in concert with version 2 VFSs. No changes to core SQLite.
FossilOrigin-Name: 43d4801df5dc4625f6829ed8246758493842b2416ba609ee0423ef63155cece2
2020-11-18 18:36:43 +00:00
dan 8bb3961d40 Fix a problem causing sqlite3_carray_bind() to return an undefined value.
FossilOrigin-Name: 083203a549d3cf26991d8626b308ff1e9e44be6abb72ab3d38e5fd53c99aed7f
2020-11-18 14:30:53 +00:00
dan 5011bb8dd2 Update test code to fix a problem with SQLITE_OMIT_VIRTUAL_TABLE builds.
FossilOrigin-Name: 29c779a07bf6ede1ec2cdb4695d801a5c113ab4b12d6cd22bcee8d2adb06891e
2020-11-18 14:12:20 +00:00
drh 5a07d10fd1 On unix, for certain error codes of read()/pread() return
SQLITE_IOERR_CORRUPTFS instead of SQLITE_IOERR_READ.  And then convert this
error into SQLITE_CORRUPT prior to returning back to the application.

FossilOrigin-Name: 9538ea8447e7b07c05197d6ff2208d3e97b45798736c85b63e8f0c7a3a98c1f3
2020-11-18 12:48:48 +00:00
drh 32881bebbe Claw back most of the performance lost in the previous commit.
FossilOrigin-Name: df8ce2675b070fcdc338918e7652a26ffc90439fe399ceac206fadf8a93a681f
2020-11-17 21:26:13 +00:00
dan aff1a57f4d Fix trivial memory leaks in the shell and sqldiff programs.
FossilOrigin-Name: 272793e5edc47e431be77d589718a001f2696869e3e15f1371a1890645a995a7
2020-11-17 21:09:56 +00:00
dan 12c9994659 Fix test file busy2.test so that it works with the "inmemory_journal" permutation.
FossilOrigin-Name: b192fdddb63ac56fd6725032af110a069baac52347c0012c130bf34f3cbe69e4
2020-11-17 18:25:48 +00:00
drh ea847f1b94 Add a single-argument form to the CARRAY table-valued function, with
content bound using the sqlite3_carray_bind() interface that is included
with the extension.

FossilOrigin-Name: 7b229cb1202be203a87b8f47d284313f357deb1e6dfeb94bba7b46744c33512e
2020-11-17 14:41:37 +00:00
drh 7f42dcd901 Enhance the unix VFS so that it removes extra "/", "/./" and "/../" from
the database filename.

FossilOrigin-Name: 7ba89d3e5c68d970ed26c2ec6e6e34bae535c2cc0b22a022d20ac9ff4527b8ab
2020-11-16 18:45:21 +00:00
drh ea2487200f Modify UPDATE so that two-pass updates on a rowid table use an ephemeral
table to store rowids rather than a RowSet.  This uses less memory, though
it is slower.

FossilOrigin-Name: 4673096dd8c5ed7aed098ff518a6d01d35c40fad991b89fddd91c19a727a4308
2020-11-14 20:03:34 +00:00
drh b035b87ef8 Improved diagnostics output with ".wheretrace 0x800". No changes to
non-debug builds.

FossilOrigin-Name: 772ae83c61c87a9004a614d8ec120ba843286bff1edbd20b987fd592ced84d79
2020-11-12 18:16:01 +00:00
drh 75e6bbbeca Fix a typo in a comment. No changes to code.
FossilOrigin-Name: 572f1ed59d29e74f810c74ef9e72ebc94c2d3e04befc03a1f88034f04a9c60a8
2020-11-11 19:11:44 +00:00
drh 235667a858 Use NEVER and ALWAYS macros to confirm that the return value from
sqlite3ExprSkipCollateAndLikely() is never NULL in some of its use cases.

FossilOrigin-Name: 76d2eb86e109fc3cbdba2e8175c22ed7660b59bb9315f6c55c565587f33ad43b
2020-11-08 20:44:30 +00:00
drh 78043e891a Add ALWAYS() to conditionals associated with SHM locking that are always true.
FossilOrigin-Name: b599e89076d60afede7d2b3503b9338ca863d0c2d25799afe4080a6186386ea9
2020-11-06 16:48:55 +00:00
drh 4e451aad54 Suppress errors associated with TEMP triggers that reference objects in
non-TEMP databases.  This is a continuation of the fix for ticket #3810
shown in check-in [ba1afc040171810d]
from [/timeline?c=trunk:200908061743|2009-08-06], based on a bug report in
[forum:/forumpost/157dc791df|forum post 157dc791df]

FossilOrigin-Name: 991ca9b26bacd8f6b64498057fe28f2068466a220f372fd365b6685f583f0e92
2020-11-05 19:13:44 +00:00
drh 114cb01796 Remove unused variable from speedtest1.c
FossilOrigin-Name: c0a18565e614021b74646de7efd11d3d46894ef9132fb26787ab0269dc6a647c
2020-11-05 14:50:21 +00:00
drh 6d5ab2a1d6 Fix an another OSS-Fuzz discovered assertion fault due to ALTER TABLE and
strange triggers.

FossilOrigin-Name: 6646d7898ca1d2f71ec906d9613fbfc5c59c6cf05f053529e6e32ab826d1cb78
2020-11-02 00:40:05 +00:00
drh 2fa7818571 Add the -tabs command-line option to the CLI.
FossilOrigin-Name: 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d
2020-10-31 18:58:37 +00:00
dan 7a39faecc2 Update the ALTER TABLE command to correctly handle UPDATE ... FROM statements within trigger programs.
FossilOrigin-Name: 3e6af890406b58da1c4aebec4d483be7ab0fdb589ef7a4c4e987d6bde18d6b97
2020-10-31 16:33:01 +00:00
drh ed7974dee5 Always create a statement journal when using the OP_ParseSchema opcode,
as you never know when it might fail.  See the discussion on
[forum:/forumpost/daa2c728cc|forum post daa2c728cc].

FossilOrigin-Name: aa512f72cf5adfece6299db17bd122aeff0cdee2a25f83f60e2ebb05e99c9591
2020-10-26 18:14:12 +00:00
dan 19f7bd3b07 Ensure that the table argument passed to Tcl_GetIndexFromObjStruct() in the sessions module test code is declared "static".
FossilOrigin-Name: 80eba105d6d1b49ba8ca2ad4e14ddec2de0bdc2f6686c2f8a1c1d24fc1fe846f
2020-10-26 16:22:31 +00:00
dan d1d43efa4f Prevent fts5 tokenizer unicode61 from considering '\0' to be a token characters, even if other characters of class "Cc" are.
FossilOrigin-Name: b7b7bde9b7a03665e3691c6d51118965f216d2dfb1617f138b9f9e60e418ed2f
2020-10-26 13:24:36 +00:00
drh beb22d086b Minor tweaks to query planning weights so that when STAT4 is enabled
and functioning, a full table scan is more likely to be selected if
that seems like the fastest solution.  Only do this when STAT4 info
is available because an error has a large potential downside.

FossilOrigin-Name: 0e7e113d9f2c929c1f8a85e2cfad8e2e60f0e8770212b5e5320fb2a2c42911f8
2020-10-22 18:50:30 +00:00
drh 461ff3594b Test case updates.
FossilOrigin-Name: 27c681c9c6672ad7098d8ff2c41e76d3e9e55866b6327ed85e73f63bd623ceed
2020-10-22 18:16:17 +00:00
drh 403869680b Sometimes it makes sense to do a full table scan rather than try to use
an index when most of the rows will be selected.  This branch is trying to
tune the query planner to make that happen more often.

FossilOrigin-Name: 0f42099ad65855c94af8472f3a6fddac7fc2a82e8fdfcc06a298eb6683a28688
2020-10-22 15:47:48 +00:00
drh 672f07c642 Fix the sqlite3_hard_heap_limit() so that it works with sqlite3_realloc64()
in addition to sqlite3_malloc64().  Improvements to OOM processing and
debugging aids in the fuzzcheck utility.

FossilOrigin-Name: 602d7369166d406a26834aa47d71d565a17d377d32e41f308821a50b41f91896
2020-10-20 14:40:53 +00:00
drh 1a56fce614 Fix an assert() inside of debug-only code that can fail following an OOM.
FossilOrigin-Name: 79da254f41a0d7d5fdc57f0cc40b3560bfcf7f79eed24a9fada1b6b4ca3adb5a
2020-10-20 12:37:51 +00:00
drh 94d6f3f836 Fix an incorrect table ref-count in the new recursive CTE logic that might
result in a reference to freed memory following a syntax error.

FossilOrigin-Name: 75a0288871ccb2a69a636cbb328fe19045a0d0ef96a193ecd118b9a196784d2d
2020-10-19 20:49:54 +00:00
drh 787f6d418d Enhance recursive common table expressions to support two or more
recursive terms.

FossilOrigin-Name: 77e64647ec429c6e0d884abbd00dabebe738f89544a4984d6fd7a702b928ccfd
2020-10-19 12:35:08 +00:00
drh 07d7a8dca9 New test cases for recursive CTEs with multiple recursive terms.
FossilOrigin-Name: cd5182bd6f5969ba0812275f471224908296960358013327cebbe0c52b820f04
2020-10-19 01:44:43 +00:00
drh 340558540e Allow multiple recursive terms in the compound SELECT of a recursive CTE.
This facilitates writing a query to find find the connected components of
an undirected graph.

FossilOrigin-Name: 5481fa8c79c34f434e99ab633ff3d0942a309a74fb0cf38e3d3617b51d5d21dd
2020-10-19 01:23:48 +00:00
mistachkin a00a016740 Fix harmless compiler warnings.
FossilOrigin-Name: 7f8802bb7be61fdf7c7a591945d533d848bc46d2989f7739dd9ad89e1b6a9c65
2020-10-18 18:35:34 +00:00
drh ff01ee34c9 Fix the SQLITE_DESERIALIZE_FREEONCLOSE flag so that it works as it is
documented to work.
See [forum:/forumpost/ba1dff667a|forum post ba1dff667a]

FossilOrigin-Name: d6fac8a1d3efeb2c4f03dae437b5b314765c93770a70603803a8039291dbcabb
2020-10-17 22:13:16 +00:00
drh e93986a93b Fix an incorrect printf() in debugging logic in where.c.
Problem reported [forum:/info/80a9c47769772207|by forum post 80a9c47769772207].

FossilOrigin-Name: 883da4dadc88809192e4ed2f753f8883471fb43aa330bc58b017c66e1acedc6c
2020-10-17 19:09:04 +00:00
drh 71cb422055 Minor fixes to the cksumvfs documentation in the header comment of the source
file.  Enhance speedtest1.c so that it can more easily do performance
comparisons of cksumvfs.

FossilOrigin-Name: ed3bb818f58b75c087f2875331ec944397b6c61a5b14d8af4b9ec6f376bd1872
2020-10-15 17:59:38 +00:00
drh f8c4c3a09f The windows VFS accepts query parameter "exclusive=true" to cause it to
take a mandatory file lock, preventing other applications from even
reading the file.

FossilOrigin-Name: 05b573fdb27abec7d75aa1375325d45043cfd674f5b346fb341f001d7e04d160
2020-10-15 14:37:27 +00:00
mistachkin d5157e01b8 Enhancements to TclKit batch tool for MSVC.
FossilOrigin-Name: 2a8a4552112be6e39e3475e9a8579582b5157086d3efd37971463c0e3958068d
2020-10-14 21:31:20 +00:00
mistachkin 05881886a6 Fix typo in a documentation comment.
FossilOrigin-Name: 462adc7d6b14de3862c2a3e57dba7efaf2ba9c104e1c127a5801a7b892059872
2020-10-14 21:30:56 +00:00
drh 7207be402d Enhanced documentation for sqlite3_vtab_nochange() to make it clear that
it is an optimization and that virtual table implementations should be
prepared for it to always return false.

FossilOrigin-Name: 3e2643619d122616663688533977d6c60d45a269b4e2bdc330fd3ee5d39f2e03
2020-10-14 15:46:29 +00:00
dan f6b0464e36 Fix some fts5 problems with signed integer overflow causing segfaults in -ftrapv builds.
FossilOrigin-Name: 7e17c2f4b7dc9b563d0b4da949bb134dc7c4fc9c86ce03891432a884ca6409d5
2020-10-12 18:09:16 +00:00
drh c6712647c6 Improved quoting of the table name argument for the ".import" command
of the CLI.  See [forum:34591fefbe|forum post 34591fefbe].

FossilOrigin-Name: ce97b56d63d6e03b909e049a0a62251d98c7bf643448193a28b42a5871899387
2020-10-12 17:57:29 +00:00
drh c196219dd4 Add options --data-only and --nosys to the ".dump" command in the CLI.
FossilOrigin-Name: 57123b14a71027c21cb5eee089fcbc9330d07bf9091b01aecc4f9e3b9e4f7b09
2020-10-12 16:54:28 +00:00
dan 936a30598e Fix ALTER TABLE so that it can run even if the schema contains unknown collation sequences.
FossilOrigin-Name: bc4bb9433fed519386511796cce475d74100b8ed707cdbffd8cbdf683b0faf35
2020-10-12 15:27:50 +00:00
drh bbb29ecfb4 Add the --nosys option to the .schema command in the CLI.
FossilOrigin-Name: b72ee694532c0c5d2285dd580154546eb592fd6892cad9ad7a49e98737adb974
2020-10-12 14:56:47 +00:00
dan 4d906f1b5a Fix UPDATE FROM statements on virtual tables that are declared WITHOUT ROWID.
FossilOrigin-Name: bcb0bc6a7b7006f07adb7266b1fecca39bf85a0adea6d78a341623a3546f2c2a
2020-10-12 14:29:11 +00:00
drh 1ca037f41e Fix BEGIN IMMEDIATE and BEGIN EXCLUSIVE so that they work even if one or
more of the database files in the connection are read-only.  Test cases
for this are in TH3.

FossilOrigin-Name: 2fa08c3963f008d4723c3f4f4496abcb6d4b575c85ba4a911a6aed5730b5948b
2020-10-12 13:24:00 +00:00
drh 0897c3c056 In the CSV extension, use SQLITE_TRANSIENT rather than SQLITE_STATIC on
return values that can in fact change.

FossilOrigin-Name: 54b54f02c66c5aeaa3504c52a04614e2fb4d7260da8367840d5ea5a71cdc2fda
2020-10-07 11:24:45 +00:00
dan f46be6a1b9 Allow fts5 trigram tables created with detail=column or detail=none to optimize LIKE and GLOB queries. Allow case-insensitive tables to optimize GLOB as well as LIKE.
FossilOrigin-Name: 64782463be62b72b5cd0bfaa7c9b69aa487d807c5fe0e65a272080b7739fd21b
2020-10-05 16:41:56 +00:00
dan a344ad47f3 Do not apply affinities when creating entries for automatic indexes on views. Fix for [95302bdb].
FossilOrigin-Name: df12f097224ebc9473d9e2a8933bd7efed6490d09af2c012c9b59a7892369b7f
2020-10-03 19:16:36 +00:00
dan 12a6a1eaf9 Fix a segfault caused by running "column LIKE NULL" against an fts5 table using the trigram tokenizer. Fix for [e33ee62575fc22].
FossilOrigin-Name: 6e72a08de764077f2bba6f7e3b99ea29001941671a971f2ccf7ceeb9c682fb1a
2020-10-03 17:06:02 +00:00
dan 95dca8d0cf FTS5 does not handle tokens that contain embedded nul characters. Prevent the trigram tokenizer from returning such tokens. Fix for [2ba5930b2].
FossilOrigin-Name: b1d048748c054575425a4bebf0c5d09962f9329d5ce6a978cf54e508b238584c
2020-10-03 14:36:06 +00:00
dan 7093a3be03 Fix some test code so that testfixture can build with SQLITE_OMIT_WAL defined.
FossilOrigin-Name: dd009cd7aec3598e930806907601f4f0f9b0021ea99fa6c5e29e88f1246066ed
2020-10-02 15:15:18 +00:00
drh 7d14ffe4e1 Additional corner-case fixes for the in-scan-vs-index or OP_SeekScan
optimization.

FossilOrigin-Name: ad5ab24ebd557e7af1d92ab3fbcb3747c04da5ad4ed779fb6391dc94042687dd
2020-10-02 13:48:57 +00:00
drh 64208b50ce Remove an incorrect assert() from the OP_SeekScan opcode.
FossilOrigin-Name: c0400f8c0bcb85ba39004feff753eae2f8e82065539e52b5788febd7644c417b
2020-10-02 12:49:06 +00:00
drh 9bb612f2c8 Fix a faulty assert() statement. Add new test cases.
FossilOrigin-Name: 80ecdb3da4558bb08ee3ec6edbde906ad5b3b8182e672b5ba0d5dfa8041cee0a
2020-10-02 12:42:51 +00:00
drh 04e70ce07d For the OP_SeekScan optimization, the OP_IdxGT does not necessarily come
right after the OP_SeekGE.   So use the P2 operand of OP_SeekScan to point
to the first instruction after OP_IdxGT.  Problem found by dbsqlfuzz.

FossilOrigin-Name: 091d71939411bf2079098f09ddc0525f11f380119fd27114e2b3eec9a8ac0db4
2020-10-02 11:55:07 +00:00
drh 4ad1a1c74c Disable the OP_SeekScan opcode of the in-scan-vs-index optimization when
in PRAGMA reverse_unordered_selects mode, as the OP_SeekScan only works
with forwards scans.  Thanks to OSSFuzz for pointing out the problem to
us.

FossilOrigin-Name: c75c3a3b756635bfdab44e4b56a337e4a88af3a8803cd3e9a67abf3d0d3450dc
2020-10-02 02:02:18 +00:00
dan d7d406e81c Add experimental "trigram" tokenizer to fts5.
FossilOrigin-Name: c4e8ec7907de7cb9e610ef9f4930caf5c046618151fb4f61d5716b9fa3f31423
2020-10-01 17:24:36 +00:00
dan a22c1c84cc Add the -trigram option to the fts5txt2db.tcl script.
FossilOrigin-Name: a394dd260252e7b7dcbc90fd321dfd40d9375f0598ea52b01001c568cbdbafce
2020-10-01 17:15:12 +00:00
dan ccf578d435 Add tests for the trigram tokenizer. Fix minor issues.
FossilOrigin-Name: 897ced99b44085012aa44d3264940dcbd4c77b295a894a1b58fb2c03a0f7fee8
2020-10-01 16:10:22 +00:00
drh deaa61072d Fix the OP_SeekScan opcode so that its variable names do not cause problems
for the test/vdbe-compress.tcl script.

FossilOrigin-Name: 7a78274a072324b94d6f79e5b7a198b2fa9321ff5d6a528b51f57d3ee95c765b
2020-10-01 15:46:21 +00:00
drh 644f43c0f7 Remove a debugging printf() accidentally left in the previous check-in.
FossilOrigin-Name: e9d1efa597fb073dc4bc4286e03059a350ed05d3e6476cd3247e6cde626f458b
2020-10-01 14:38:39 +00:00
drh 67306cb3b4 The IN-early-out optimization does not work for virtual tables. Do
not try to use it there.  Fix for ticket [2d5a3163563d559f].  Test
cases in TH3.

FossilOrigin-Name: dbec6910d9648f4907373c818a5cb347a2e487784208751ccecfacca752ff99d
2020-10-01 14:36:15 +00:00
dan 33a99fad08 Add experimental unicode-aware trigram tokenizer to fts5. And support for LIKE and GLOB optimizations for fts5 tables that use said tokenizer.
FossilOrigin-Name: 0d7810c1aea93c0a3da1ccc4911dbce8a1b6e1dbfe1ab7e800289a0c783b5985
2020-09-30 20:35:37 +00:00
drh fad4dd0fd1 Improved query optimization for multi-column indexes where the second or
later columns are constrained by an IN operator and the earlier index columns
limit the search to a small number of rows.  Use the new OP_SeekScan opcode
which does scanning of the relevant range of the index but gives up and
falls back to doing a seek if the number of rows scanned grows to large,
in order to guard against pathological cases where the estimated number
of rows to be scanned is far too small.

FossilOrigin-Name: 4a43430fd23f88352c33b29c4c105b72f6dc821f94bf362040c41a1648c402e5
2020-09-30 18:06:51 +00:00
drh 4f65b3bbfb For the OP_SeekScan opcode, adjust the number of steps run before giving
up based on the estimated number of comparisons needed to perform a seek.

FossilOrigin-Name: dc4172e6b8e1f62dc7329a3adb2223f290bc4c8055c265e88182ef432f4bcf10
2020-09-30 18:03:22 +00:00
drh 395a60dad4 Back out the incorrect optimization of check-in [e51ecadcbdef5ce6] as
ticket [5c4e7aa793943803] reports a case where the optimization does not
work.

FossilOrigin-Name: 7395e96b8cc370c8ac2657fb805915b0992a15d80f8bf256d277b423fec64675
2020-09-30 17:32:22 +00:00
drh af3711536b In the query flattener when substituting expression Y in place of expression X,
if X is marked has having come from an ON or USING clause of a LEFT JOIN, then
be sure that all subexpressions of Y, not just the root node of Y, are
similarly marked.  Otherwise, if Y is an AND operator, it will be split up
during WHERE clause analysis and the subexpressions will not get the special
treatment needed by LEFT JOIN ON/USING clauses.
Fix for ticket [66e4b0e271c47145].

FossilOrigin-Name: 69f9eb7343a416c5ab426c8e1b9f0ae576544b4ccc5d87f5481c8ff884f696e1
2020-09-30 15:36:03 +00:00
shearer 1e6c58dee2 Better understanding of savepoint code
FossilOrigin-Name: ce6d8d621505f25e4fd43e7cf27445e1a2ddd58d79108d63499c2ae30cc9f610
2020-09-30 09:17:53 +00:00
drh a957e22fa4 Add an sqlite3FaultSim() call to btreeNext() to make it easier to
simulate I/O errors in calls to sqlite3BtreeNext(), and in OP_SeekScan.

FossilOrigin-Name: 29cca775d3f5411624f0a8d55d34a038a24f1009d25b097315adb64e70c4b299
2020-09-30 00:48:45 +00:00
drh f287d00108 In the OP_SeekScan opcode, changes to pOp must occur after the call
to VdbeBranchTaken() so that the VdbeBranchTaken() attributes the branch
to the correct opcode.

FossilOrigin-Name: 61fbe7aa7cc0e8fe3e6b1c5aec277183d8cd7c86b1e835c38e0b37a9b8063343
2020-09-30 00:10:22 +00:00
drh a54e1b1fc8 The OP_SeekScan opcode is a no-op if the cursor is not pointing to a valid
row upon entry.

FossilOrigin-Name: 4afc96b5fe80bd192a23e0230edc207e641931c3bf48296b1a385c786386f1b7
2020-09-29 23:52:25 +00:00
drh 0b2949c36e Coverage testing of the OP_SeekScan opcode. Fix a problem that comes up when
OP_SeekScan reaches the end of the table.

FossilOrigin-Name: 9e57e758a6a33f54d28a546b4eebfb5cfacef30dc4e0207e43bb9d2c06fc3439
2020-09-29 20:22:19 +00:00
drh dfbaae7572 Improved comments on the new OP_SeekScan opcode.
FossilOrigin-Name: 6110fdd5bb7b4ae5c065404c802ae726362ef084966b73cffe58c4bfb98689d2
2020-09-29 17:29:11 +00:00
drh c40076a8cf Improved performance by manually in-lining the sqlite3VdbeIdxKeyCompare()
routine for the OP_IdxGT opcode and its kin.

FossilOrigin-Name: 2206a2c848a122ee220c89427f9be0460cba0706f58852139d7b37184ce29a29
2020-09-29 16:05:09 +00:00
drh 46f0f4e56d Typo fix to repair the early-out optimization. Also avoid unnecessary
OP_SeekHit opcodes.

FossilOrigin-Name: 8fd7d8dfcd515aa6b65d6eb27b033d3b3a31db467b9100cc13c62bc60113019e
2020-09-29 15:32:54 +00:00
drh f761d937c2 The OP_SeekScan opcode works, but using it requires disabling the
IN-earlyout optimization because the OP_IfNoHope opcode might move the
cursor.

FossilOrigin-Name: f3c36b840c9a29c0add28039db216f4207a308e5057fc76e3f0004024a8267ac
2020-09-29 01:48:46 +00:00
drh 68cf0ace3d Revisiting the IN-scan optimization to try to fix it for the corner case
where the statistics deceive the query planner into using a scan when
an indexed lookup would be better.  This check-in changes the code
generation to do the IN-scan using a new OP_SeekScan opcode.  That new
opcode is designed to abandon the scan and fall back to a seek if
it doesn't find a match quickly enough.  For this work-in-progress check-in, 
OP_SeekScan is still a no-op and OP_SeekGE still ends up doing all the work.

FossilOrigin-Name: d720b6981eeb0ffdb14494ca63eca298ee724ae4ad4863c7c7cbfdad7fa52519
2020-09-28 19:51:54 +00:00
drh 75fa266341 Small performance improvement and size reduction by reducing the size of
the WhereTerm object.

FossilOrigin-Name: 43f7ddad800acf40917c5cc3d926640dbec17c34d5f1cbbb74bd80f44eeed0a5
2020-09-28 15:49:43 +00:00
drh f573b4fb94 Avoid the possibility of integer overflow on the --pagecache option to
the CLI. See [forum:10a2892377|forum post 10a2892377]

FossilOrigin-Name: d3d13df31a97648f952beb2e1a783f947a80ec843227985ad9ebd14452d2f654
2020-09-28 13:34:05 +00:00
mistachkin 273ee15121 Fix harmless compiler warning seen with MSVC.
FossilOrigin-Name: 4591ee03d7a1ef3f0f6ad0629493fdb7a1c0ddb3277a9e87aa244cb0ca770593
2020-09-21 20:18:44 +00:00
dan 7548ab20e6 In fts5 integrity checks, do not compare the contents of the index against an external content table unless specifically requested.
FossilOrigin-Name: 782163693f37aeb65209bebbaeb6659a36881b8c4b4bec778b366658488bf966
2020-09-21 14:53:21 +00:00
drh 9ca41fbfa9 Remove a new assert() that the compiler finds is always true at compile-time,
to avoid a compiler warning.

FossilOrigin-Name: 8bbaee238593741da107b92b254cb5f0cf8b6bcc760bf2b25d20e46c8edee2a9
2020-09-20 13:33:28 +00:00
drh 79d9af960b Attempt to silence harmless static analyzer warnings in Lemon and in the
Lemon-generated parser.

FossilOrigin-Name: de8ce22a46c90afa5475cd24c28b7a82b26410dc72d662af2f9d9e5e528e0eec
2020-09-20 12:10:28 +00:00
dan 68cffa65fb Fix a typo in the documentation comment for sqlite3_preupdate_hook().
FossilOrigin-Name: 4542d194e2fef5e21e1c3679914bd9e21fab31cfb111cf640524fb3514a8afa3
2020-09-17 21:11:25 +00:00
dan 39c7125a97 Fix a problem in sqlite-expert causing it to ignore equality constraints on the second or subsequent columns of a multi-column PRIMARY KEY.
FossilOrigin-Name: c666c85a433fbc83edef4dbfb0399672e570f5d7979ab61cb39ff5488595d822
2020-09-17 17:01:16 +00:00
dan f2e151aeab Fix a problem in fts5 causing the in-memory hash table to be flushed more often than necessary.
FossilOrigin-Name: 9a55601d072bcd1ac0f6f1633216c7c8b3ff3e037451e2cfd285cbe19b60b9fc
2020-09-17 15:16:50 +00:00
dan 3acd3fb9d8 Fix a "jump depends on unitialized value" valgrind/asan error in fts5.
FossilOrigin-Name: 66f94d623c16b4527e42f0519e32ec78eaf9ee6fd61ee7d0eb657cc59a8f7d68
2020-09-17 14:16:02 +00:00
drh f2fa084cf1 Earlier detection of corruption in the rtreecheck() SQL function to prevent
a (harmless) read of an uninitialized value.

FossilOrigin-Name: e2074b24788149562b15022ccd2784d6649f08ebc41410e3bfb2401baf0892e2
2020-09-17 11:56:04 +00:00
drh bc2e95140b Prevent use-after-free of the u.vtab.idxStr string following an OOM
while generating the OP_VFilter opcode.

FossilOrigin-Name: 751fe4edb2d4602e652523c2759de3f4fffd29d5c66cae68caf45b30fd8b750a
2020-09-17 11:32:14 +00:00
drh f1ea425560 DISTINCT may not be ignored inside a UNION ALL common table expression.
Fix for ticket [c51489c3b8f919c5]

FossilOrigin-Name: 7d2b590d3abd66a7e6ae9046198eb669e0fd2f223f7691281e9ad795a12b8903
2020-09-17 00:46:09 +00:00
drh d96e3821e4 Fix a pair of assert()s in "PRAGMA foreign_key_check" that might have given
a false-positive following an OOM.

FossilOrigin-Name: 9ea3039b538ffd0f348c8fbc9452af1fbf899a1f668af9a2404bdd0f8dd21351
2020-09-16 19:48:23 +00:00
drh 18ef40e563 Fix harmless compiler warnings in Lemon.
FossilOrigin-Name: 6c94ba4b1c16b676978808dcb24f63c2f22915af5dcfe9f635c037011affcf4b
2020-09-16 16:55:56 +00:00
dan b5a69238b4 Fix a buffer overread found by OSSFuzz that could occur if a WITHOUT ROWID table with many columns was NATURAL JOINed against itself.
FossilOrigin-Name: 3d35fa0be866213274fc09250225b345f6b08a9b4ec373d53d95e627e24512be
2020-09-15 20:48:30 +00:00
drh ddcfe92105 Do not invoke usleep() for more than 999999 microseconds.
FossilOrigin-Name: 1f5ed852f25515bbc0a7aaf236fdef40fa7e31805eee1249277fde4e68f95130
2020-09-15 12:29:35 +00:00
dan 86f477edaa Catch fts5 index corruption caused by issuing 'delete' commands with incorrect data earlier in some cases. Also fix a couple of test script problems.
FossilOrigin-Name: b79f19edfd33c2a75f936c352668e14e81f35acf4f07edc27a21f941a7304b38
2020-09-11 15:01:49 +00:00
drh 94acc2ef42 Try again to fix the typo in the sqlite3_txn_state() documentation.
FossilOrigin-Name: 6d1ab0403c2855b595f5d294305f41f56a7a93503f2a58d1b1d12431d480704e
2020-09-10 15:09:11 +00:00
drh 4fb8452875 Fix typo in the documentation for the new sqlite3_txn_state() interface.
FossilOrigin-Name: 23f7d01758cbcf22bd34e78fb8284c7af18f3059a03c4ff6ab3e556ca11fce19
2020-09-10 14:54:57 +00:00
drh 786142a994 If an amalgamation is created using SQLITE_ENABLE_UPDATE_DELETE_LIMIT,
ensure that it can still be compiled without that option by setting the
SQLITE_UDL_CAPABLE_PARSER flag in the preamble.

FossilOrigin-Name: 5b905d7d7714d1d2c433ff58f5d6917d6d27302d44ca347aa740e768f1354b16
2020-09-10 12:41:46 +00:00
dan ebd2ecdda7 Fix another (harmless in practice) tsan error in shared-cache mode.
FossilOrigin-Name: 5a74fa3f0a64f462c8add9beae231a9bbdd19e54d07b54f08726cb1411fc8d3a
2020-09-07 11:14:27 +00:00
drh 8ab0809473 Remove an artifical limitation on the length of columns in the "box"
output mode of the command-line shell.

FossilOrigin-Name: 783fa887c9ed1a7d72c310df1dd9de91c016061b05fdeec87fbb2a7eb0b952ea
2020-09-06 17:40:38 +00:00
drh 2b75d3beb0 Fix a bug in Fossil that might cause it to crash if there is
a multi-terminal token with a space following the "|" separator.
This does not affect SQLite.

FossilOrigin-Name: 430c5d1da57af452f236cc862139d84ab97b6020f6d327dae5268c58e6e83a87
2020-09-05 06:21:54 +00:00
dan 78f04753ae Fix a tsan error that could occur when using shared-cache mode.
FossilOrigin-Name: de80bc87300257cc49d98e2d22e914211f213dce912f320c8b37b3883c73923c
2020-09-04 19:10:43 +00:00
dan 2b06b0769e Ensure that the busy-handler count is reset at the end of each sqlite3_file_control() and sqlite3_prepare() (and _v2() and _v3()).
FossilOrigin-Name: 5dd05940617fb05ee2faf212b15afc3a8e9695318eccb76761b37359fea681d1
2020-09-04 17:30:59 +00:00
mistachkin 52cfe0312a Fix harmless compiler warning.
FossilOrigin-Name: a711e8cd2c7b64e06241736ecef478ac64ddbe7b58e0933b6febba63f7fb06e1
2020-09-01 19:02:52 +00:00
drh 512aa78ca2 In the Lemon output, add a prefix comment that explains that the output file
is automatically generated and shows the name of the source file.

FossilOrigin-Name: d34caf3bb63d0512ea116a8c8c8343b76aa39441bd4b3e98231747a705b91d54
2020-09-01 12:26:55 +00:00
drh 60c71b02ca Lemon updates: (1) include the #defines for all tokens in the generated C
file, so that the C-file can be stand-alone.  (2) If the grammar begins with
a %include {...} directive on line one, make that directive the header for
the generated C file.  (3) Enhance the lemon.html documentation.

FossilOrigin-Name: 84d54eb35716174195ee7e5ac846f47308e5dbb0056e8ff568daa133860bab74
2020-09-01 11:20:03 +00:00
drh fa17e134b2 Improvements to the IN-early-out optimization so that it works more
efficiently when there are two or more indexed IN clauses on a single table.

FossilOrigin-Name: 35505c68c1945c35babd2496e02bc4907a15c8e7b8d77f05f230bd0e9d4891d7
2020-09-01 01:52:03 +00:00
drh d321b6f4ad Fix a harmless compiler warning.
FossilOrigin-Name: 3ca0b7d54d73d07cd6b32e650a809174bb1cd66ce5ecdb36f65b70899ea05824
2020-09-01 00:26:21 +00:00
drh 37ccfcfeb9 New test-control that returns the number of calls to
sqlite3BtreeMovetoUnpacked() on the main database and then resets the
counter.  This only works for SQLITE_DEBUG builds.

FossilOrigin-Name: dca5b91926431768babac28a6faf7674a5014db95caba727995b470e92b3182a
2020-08-31 18:49:04 +00:00
drh c51ceeb049 Fix the documentation for the OP_IdxGT family of opcodes to show that the
P5 operand is not used.

FossilOrigin-Name: 62f7d2a61259f296ffdcb3b3ee1a13925c4563ac8ed669f8a8a63fc7bc3a0a37
2020-08-31 12:29:03 +00:00
dan acd3c8a995 Fix a sanitizer warning in zipfile.c.
FossilOrigin-Name: ded1a75b3cf39834d38a385f38ae969b296f6c9409856b7eea08645e861b1ac2
2020-08-29 19:00:19 +00:00
dan d49c0c83ef Improve performance of wal-mode locking on unix in cases where there are hundreds of connections to a single database within the same process.
FossilOrigin-Name: a1c19eea8f141b89a0921da0724096feb21a772ef6654f164e2c36ebf9f7871e
2020-08-29 15:15:07 +00:00
dan 6acdee6765 Fix handling of an xShmLock(SHARED, UNLOCK) call when the caller does not hold any lock on the specified slot, but another connection in the same process holds an EXCLUSIVE.
FossilOrigin-Name: 3eb365027b885e1f61965efd53a3643b6ff441ae01e79038a091314516a50dd4
2020-08-28 20:01:06 +00:00
dan 8337da6678 Modify the unixShmLock() function to avoid iterating through the (possibly large) set of connections to the same database file.
FossilOrigin-Name: e0faddf0dfc3a40b6b94408296dd781dd0264ecc9f2129ce4405438433fb00e0
2020-08-28 19:27:15 +00:00
mistachkin 72c38d87bf Add the miscellaneous 'series' extension to the shell.
FossilOrigin-Name: fc0856dccfab273d50457052fa3c6da768d0eb2504ad04d9540da4e3222fc829
2020-08-28 18:47:39 +00:00
drh 7b8524168e Update Lemon documentation. Patches from sgbeal.
FossilOrigin-Name: f5dc83442bf010bc4083e083b3a1acbb9918b7e685ca676dd899a0e09df196bc
2020-08-28 13:10:00 +00:00
drh e2678b93af Fix a couple of unreachable branches.
FossilOrigin-Name: f2d26f2b11317abd4f993faa1a4df7afcd1a2d4e448ecc69ca05e9ebf102cd62
2020-08-28 12:58:21 +00:00
dan 832aa023c6 Add fts5 test to confirm that for a table with columns a, b, c and d, "{a b}" and "-{c d}" are handled similarly.
FossilOrigin-Name: 1a04920998368e56276fd0b100be8343609c6ff8a731cf8e26a0490f9c6dabdf
2020-08-28 11:19:49 +00:00
drh 04cd60e18c Remove a (harmless) redundant variable from the CLI implementation.
FossilOrigin-Name: 3f7bbb840de0a9b1ca89288805cb151aea6fcb82efda9ba39f51abf1b17c070b
2020-08-27 20:55:54 +00:00
drh 92e21ef079 Include the original text of the CHECK constraint in the error message for
anonymous CHECK constraints.

FossilOrigin-Name: 5ce34a955bb36d77edc9951cb7ac2ef9c876d7d3ff5852af682f558e248f428c
2020-08-27 18:36:30 +00:00
drh 359941bd33 Apple the same fix for ticket [9eda2697f5cc1aba] to text-to-integer
conversions that was done for floating point conversions by
check-in [1c76f1d8ec0937a2].

FossilOrigin-Name: aafb7a21041090e529491b0ce30c3902420be0551b1b2c55840a5fbb9105fb7d
2020-08-27 16:28:30 +00:00
dan ca3ee7e18a Do not attempt to run test script analyze3.test as part of the "prepare" permutation.
FossilOrigin-Name: f7f13cb1bc699c034a3f5f7a2431c8055cb79e2a14d5e70e1fc5dd6dec00fb26
2020-08-27 14:53:47 +00:00
drh 60081a0382 Enhance the ".databases" command in the CLI so that it shows the result
of sqlite3_db_readonly() and sqlite3_txn_state() for each database file.

FossilOrigin-Name: 0ffd16d23dd3b6467cce31af506c70fde44c3796d386c2a03896e43a6d683e60
2020-08-26 19:07:18 +00:00
drh 30497f4169 If the argument to the ".read" command in the CLI begins with "|" then
run the remainder of the argument as a command and read input from the
output of that command.

FossilOrigin-Name: 6c716f4b556ea8f9c9f15cffd81cb970488eadf1d5da2ba6b366d3bdeb36e492
2020-08-26 10:50:48 +00:00
drh 99744fa4ab Add support for the sqlite3_txn_state() interface.
FossilOrigin-Name: ad195e3dd89d0f33b50070c18fb8f43c4eb24162515dfdd7c04d9e7d96b902a2
2020-08-25 19:09:07 +00:00
drh 58d6f633ba Reduce the N in the logN term for the sorting cost associated with computing
DISTINCT by B-Tree by half, under the assumption that the DISTINCT will
eliminate about half the rows of output.  This is really a wild guess.  But
we do not have any better way of estimating what the row-count reduction due
to DISTINCT will actually be.

FossilOrigin-Name: 8787417ec1da8071d84c6ff0d7a90b5fd458ab6baba871327f36bc4e1bceca61
2020-08-24 23:44:27 +00:00
dan 599456f0ab Correctly handle expressions like "x IS (not) true/false" within the rhs of IN() expressions. Fix for [f3ff1472].
FossilOrigin-Name: 493a25949b9a6d0be82169b597133e491d8be4f4147b6eae135b06c1d810abd3
2020-08-24 10:52:52 +00:00
dan 6c3b4b07d1 Fix a crash that could occur in SQLITE_MAX_EXPR_DEPTH=0 builds when processing SQL containing syntax errors.
FossilOrigin-Name: 5f58dd3a19605b6f49b4364fa29892502eff35f12a7693a8694100e1844711ea
2020-08-20 16:25:26 +00:00
dan 7b14b990d0 Avoid a buffer overrun in test code that could occur if certain test functions were passed a hex-string containing an odd number of digits.
FossilOrigin-Name: 3c5e63c22ffbfeb66eb6ee38912d29fad6f2bd4d74b6a25e89bd36bf40eaa661
2020-08-20 11:03:33 +00:00
drh 14f38b3d0a Try to make SQLite easier to compiler for Mac Catalyst. See
[https://sqlite.org/forum/forumpost/803387a1c5|forum post 803387a1c5].

FossilOrigin-Name: e1595a20d71e61957944cc2b634578968cda8fba08a1f1e75edba20dc9c6080b
2020-08-19 23:51:54 +00:00
drh 46fe138d98 Do not skip over TK_IF_NULL_ROW operators when bypassing TK_COLLATE operators.
Fix to check-in [ac31edd3eeafcef4] which was itself a fix for ticket
[45f4bf4eb4ffd788].

FossilOrigin-Name: 871f2ddcfbb9196dbd851a350e3471ee6d242d86bbd755201f7e2406fce3ac55
2020-08-19 23:32:06 +00:00
dan 1d42e619ac Update releasetest_data.tcl so that the "Fast-One" configuration runs bigmmap.test as part of release testing.
FossilOrigin-Name: a0aa35aaa5694a96638a7c7b1cd69c7523750cbe95831a13c1ee5a6d48256b76
2020-08-19 15:24:19 +00:00
dan fce445b8fa Fix a problem in test file bigmmap.test.
FossilOrigin-Name: d8e47382160e98be646ce3ba568578493088d1bb11d513ded3e00b576fb07f06
2020-08-19 15:21:52 +00:00
drh 9191c702fc Fix the -quote option on the CLI to set the correct column separator.
FossilOrigin-Name: c778f8295c3c9b6cd6107b33fd7664ae75c97840fc974c9f971755a523f185c4
2020-08-17 09:11:21 +00:00
drh 1d8f892a31 Optimization to sqlite3BeginWriteOperation().
FossilOrigin-Name: 2173d4c6e3addc75964508f2fc8e42755376b3bc285286fa90df4831a6fa280b
2020-08-16 00:30:44 +00:00
drh 45d827cb6a Optimization of the sqlite3SrcListDelete() routine.
FossilOrigin-Name: 1b4acd1ac4a8d24f8804c6d0770f5b0022f569d51742b6954b26e525f04d38ca
2020-08-15 23:48:22 +00:00
drh 289a0c849b Remove more unnecessary sqlite3GetVdbe() calls, replacing them with assert()s.
FossilOrigin-Name: b7dc932197665f0ebde3ffb8f0785c22da07ce307cfd5f0eab69e86e4b38fcde
2020-08-15 22:23:00 +00:00
drh f0b41745c5 Avoid unnecessary calls to the sqlite3GetVdbe() routine. Add assert()
statements to prove each call is unnecessary.

FossilOrigin-Name: 86d3790caf92e9cb7a9aaaa110f309b4b6945ac30cfd53fc3e5aa1ec3075ada5
2020-08-15 21:55:14 +00:00
drh 398221e2ad Omit the unnecessary not-NULL check on the upper bound of a forward index
range scan.  The subsequent OP_IdxGT will always catch the NULL.  Similarly,
omit the not-NULL check on the lower bound of a reverse index range scan,
as the SeekLE opcode will disallow the NULL.

FossilOrigin-Name: e51ecadcbdef5ce6e41d68412aee70aa4a1416c850358a6fa7e9a1ab443e719d
2020-08-15 19:58:59 +00:00
drh 861889e4f8 When doing an UPDATE or DELETE using a multi-column index where only a few
of the earlier columns of the index are useful for the index lookup,
postpone doing the main table seek until after all WHERE clause constraints
have been evaluated, in case those constraints can be covered by unused
later terms of the index, thus avoiding unnecessary main table seeks.

FossilOrigin-Name: 7fee0b1075d622835dc6828c061be516102da9e2809f52d9ab7c4bbef7dfb871
2020-08-14 21:51:02 +00:00
drh a3d6d6a93f Update the version number to 3.34.0 for the next development cycle.
FossilOrigin-Name: 70f34f3df5358d36c8578afbc05756450c46da36b8dce339ed87fc0b9d4057cb
2020-08-14 21:37:32 +00:00
drh f8556d0106 Optimizations to the logic that converts main table accesses into equivalent
index accesses.  Code is now slightly smaller and faster than trunk.

FossilOrigin-Name: 611b640442025e57b8e161f8ddac1f19bd3be9a3d5266f4cef287595c3ed9257
2020-08-14 21:32:16 +00:00
drh 68c0c71065 For UPDATE and DELETE, use OP_DeferredSeek always. If the seek must later
be resolved, add the OP_FinishSeek opcode after all WHERE clause terms have
been processed.  This obviates the need for the WHERE_SEEK_TABLE and
WHERE_SEEK_UNIQ_TABLE flags to sqlite3WhereBegin() and the ensuing
complication, and it allows the covering index optimization to be used
further into WHERE clause processing.

FossilOrigin-Name: a495f60d315e34b1a1bc5fb1336e05047add52c8fb2710b577c97b10a5e734f6
2020-08-14 20:04:26 +00:00
drh 5e6d90fe15 Experimental change to try to get some DELETE operations to access values
using the index rather than the main table, so as to avoid unnecessary
main table seeks.

FossilOrigin-Name: 2f7cb6ab39e54fd6eb3a280d3022c3d4f4ed92e83af7226e63e0199a96397a6b
2020-08-14 17:39:31 +00:00
dan e0404386f2 Fix an inconsequential memory leak in sqldiff. Update the "Sanitize" case in wapptest.tcl to use -fsanitize=address,undefined, and to run more tests.
FossilOrigin-Name: 613fb5c2525be77e48bad0a74e8b7bf53489365060fb9c7713a0caddb1820c71
2020-08-14 16:14:40 +00:00
drh ef215fbf3b Version 3.33.0
FossilOrigin-Name: fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f
2020-08-14 13:23:32 +00:00
dan 96e337df6b Fix "make test" handling of environment variable QUICKTEST_OMIT so that it can be used to exclude test files in other than the main test directory.
FossilOrigin-Name: b050976079ba4a22d4dfeadb81f40cf71da6588c95bf2b634d88b416de5accd7
2020-08-13 17:27:57 +00:00
drh a3e6495970 Improvement on the previous fix.
FossilOrigin-Name: f6cffa2d50bfebe5b025f412b7a49b7fdafb798aaf1ddc80e6656ccd1f012a7f
2020-08-12 16:19:12 +00:00
drh b6a74caf93 Fix an assertion() fault in ALTER TABLE found by OSSFuzz. Test case in TH3.
FossilOrigin-Name: 41de742c5713ab1a0c0c15c44af3ffac40bbc527ae2dc11d829ba9773eb4c84a
2020-08-12 15:39:43 +00:00
drh c08716a317 Fix harmless USAN warnings from gcc9.
FossilOrigin-Name: 72c4c69fea13f5e24df25645e6941ce3ff896f0a3c73cd63329f819cc907ab40
2020-08-11 21:53:42 +00:00
drh 4dfdb86c8d New test cases for the use of the ieee754 and decimal extensions in the CLI.
FossilOrigin-Name: bc1590f32fc4e2696b4126bd0302cb6405031dd4f55b86f3f1611f7f39299f85
2020-08-11 18:17:04 +00:00
dan 91faeec8d0 Modify a test for corruption within the wal checkpoint code to account for the pending-byte page. And for the fact that test configurations might move the pending-byte page.
FossilOrigin-Name: 7dfb74c37e678dde347d9d85846672f82ad282e300e32676330b764be2e4d580
2020-08-11 18:00:10 +00:00
drh 8c1fbe81d0 Minor comment fixes. No changes to code.
FossilOrigin-Name: 533aeb90085d989078073067172135db98e37e00be84f99757255858126196e4
2020-08-11 17:20:02 +00:00
drh 24c22753fc Remove an unused #define from sqliteInt.h.
FossilOrigin-Name: d5b254f94c1ce6f0f26024d0b9c80e610f7cc891360bc4c2cb116e9eda2874b3
2020-08-11 16:46:21 +00:00
drh 47eb561c40 Simplify #ifdefs associated with Parse.eParseMode. Fix an #ifdef error
associated with SQLITE_OMIT_AUTOVACUUM.

FossilOrigin-Name: 5bbd4bddd3b9fa64d134ed62bce3eb4a09456bf24dec2474b5d764a3a3775964
2020-08-10 21:01:32 +00:00
dan 9f567eb9f5 Fix a problem causing test failures in corruptL.test for some permutations.
FossilOrigin-Name: 680bdc6524ad6af0e74401e96e3a576145042fb865c1582bfaffc11d4ff76a4f
2020-08-10 19:35:01 +00:00
dan 26c48d2aab Fix a problem building fts3 separately from the amalgamation.
FossilOrigin-Name: 2a167cfbb2abd76e1b33116b671e58a767fc972dd79bee0004aad09a1dd2b487
2020-08-10 19:30:21 +00:00
dan 12a4c41917 Fix a shell tool build error caused by some combinations of options.
FossilOrigin-Name: 33cd5341ac2ec84c86fbd3371f15c9153f83c1739f85dd8c3956fe2093d49afd
2020-08-10 14:34:36 +00:00
drh 08b9208660 Fix harmless compiler warnings that surface in newer versions of GCC.
FossilOrigin-Name: 9d670a318381f219b467653f5f9539097808b887ae37291ce13be462dedfb18d
2020-08-10 14:18:00 +00:00
dan ed0af52cb1 Fix another test script problem in walvfs.test.
FossilOrigin-Name: 1b89d3931e368a66be5075bdf49eedd3839591ee268e3ac293040b5bf7639746
2020-08-10 11:21:48 +00:00
dan 80aff0847e Fix minor test script problems.
FossilOrigin-Name: 5d54cd44d076cfede60bd404a59bd700a950420b961ae9fdec4365a3e4ed18ed
2020-08-10 10:43:43 +00:00
drh 14d093f847 Fix a harmless compiler warning.
FossilOrigin-Name: 6f91769fdb0734905f05e1f4d1c81364e6e874450c9f13a0de2259d564f582a7
2020-08-09 17:58:45 +00:00
drh 8afc09dea3 Fix the check-in at [41474548ef3f7454] so that it computes the pointer in
time for error checking at the end of the routine in the case of a non-OOM
error.

FossilOrigin-Name: 13d2fed760e7d0def573c56b7181f45622b0ed78d61952a6de901f96949d074e
2020-08-08 20:15:16 +00:00
dan 07066d90f6 Fix test script busy2.test so that it works with the inmemory-journal permutation.
FossilOrigin-Name: b412d1d175fde9c6402b6fda7c73ac2db2471f2c9416d5c5073549732dea6d98
2020-08-08 20:11:22 +00:00
dan 47d38e2444 Changes to busy2.test, corruptL.test and fkey5.test so that new test cases pass with all test permutations.
FossilOrigin-Name: d62d1711e2b0f18bb4dfb8899299c8e5b4c8205989b719699da60bcfe1884cf3
2020-08-08 20:03:12 +00:00
dan 35a37c2a47 Fix a test script problem causing an error for SQLITE_ENABLE_OVERSIZE_CELL_CHECK builds in corruptL.test.
FossilOrigin-Name: a85520e0074d574cb4ac5239bb225f8f0b0b3ea1d782cd1cbc79797b4c583fb0
2020-08-08 19:52:53 +00:00
drh c664355c0f Move a pointer computation until after OOM checks to avoid a nuisance USAN
warning.

FossilOrigin-Name: 41474548ef3f7454e44fbf648429730b3f5ba1ff0086fd2f2d0e59b8f51d85e6
2020-08-08 17:55:39 +00:00
dan a6c13b22b2 Change the name of sqlite3SelectTrace to sqlite3_unsupported_selecttrace.
FossilOrigin-Name: 5ecd03a27b81637ec92af654451a8fff46f1768ddb7c7a443d2a4a933b4475c1
2020-08-08 17:02:39 +00:00
drh d43c0cbed2 Update requirement marks due to wording improvements in the documentation.
FossilOrigin-Name: bf875a1c7fcb2b41a4d3bd741bb358a635b869d0b6fc9d24385cd5779686d78c
2020-08-08 15:40:42 +00:00
drh 7033ce4fdc Reorder declarations in the decimal extension for C89.
FossilOrigin-Name: eface2da2c0b3daee2a5fd640cca3d3757d0930f62900fc810c50c104635241d
2020-08-08 00:44:45 +00:00
drh 799443b14f Do the oversize-WAL corruption test before the size hint is issued.
FossilOrigin-Name: fdc5fb902d7f2d10f73e64fe30c67153b59b26c5d707fc9c354e90967dbcc214
2020-08-07 19:52:01 +00:00
dan 26b9540fc2 Fix a file-descriptor leak in test script corruptL.test.
FossilOrigin-Name: ec2c340c39bc78e4bce0eb01ea408c95ba121103cc77f300f29f3001fc345c20
2020-08-07 18:52:03 +00:00
dan 88819d5870 Return an SQLITE_CORRUPT error if the final expected size of the database when checkpointing is not reasonable - where reasonable is defined (basically) as the sum of the sizes of the database and wal files.
FossilOrigin-Name: e2799563c8a97f617c6d932719b312e3d5bff051a9a397492df8d88e8bb4260a
2020-08-07 16:28:02 +00:00
drh b19493434f Add the --checkpoint option to speedtest1.
FossilOrigin-Name: 4cffa9bb44d6f0bdb23cae913adfb224f0814e65a2abb9120179f0b288e70f77
2020-08-07 14:47:55 +00:00
drh 2c40b8f3da Fix compilation issues with MSVC.
FossilOrigin-Name: c5a7e6d2c203ebe5f22ab5c676d33759b542ac57c8bad85d8f561a53bd26917c
2020-08-07 14:22:56 +00:00
drh f82ce382f9 Fix the columnar output modes in the CLI so that they work with parameters.
See [https://sqlite.org/forum/forumpost/17ba6aac24] for details of the
problem fixed.

FossilOrigin-Name: d573aa9b1299bc25e46fc8a4b4f7c665263490db86c66f11e2d903dcd7071995
2020-08-06 16:45:22 +00:00
177 changed files with 6770 additions and 1293 deletions
+3
View File
@@ -441,6 +441,7 @@ TESTSRC += \
$(TOP)/ext/expert/test_expert.c \
$(TOP)/ext/misc/amatch.c \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/cksumvfs.c \
$(TOP)/ext/misc/closure.c \
$(TOP)/ext/misc/csv.c \
$(TOP)/ext/misc/decimal.c \
@@ -1086,6 +1087,7 @@ SHELL_SRC = \
$(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/ieee754.c \
$(TOP)/ext/misc/series.c \
$(TOP)/ext/misc/shathree.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/uint.c \
@@ -1232,6 +1234,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DESERIALIZE
TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
TESTFIXTURE_SRC1 = sqlite3.c
+3
View File
@@ -1558,6 +1558,7 @@ TESTEXT = \
$(TOP)\ext\expert\test_expert.c \
$(TOP)\ext\misc\amatch.c \
$(TOP)\ext\misc\carray.c \
$(TOP)\ext\misc\cksumvfs.c \
$(TOP)\ext\misc\closure.c \
$(TOP)\ext\misc\csv.c \
$(TOP)\ext\misc\decimal.c \
@@ -2208,6 +2209,7 @@ SHELL_SRC = \
$(TOP)\ext\misc\decimal.c \
$(TOP)\ext\misc\fileio.c \
$(TOP)\ext\misc\ieee754.c \
$(TOP)\ext\misc\series.c \
$(TOP)\ext\misc\shathree.c \
$(TOP)\ext\misc\uint.c \
$(TOP)\ext\expert\sqlite3expert.c \
@@ -2386,6 +2388,7 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CKSUMVFS_STATIC=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
+1 -1
View File
@@ -1 +1 @@
3.33.0
3.34.1
+1 -1
View File
@@ -153,7 +153,7 @@ Please `cd` to its location first.
#
#-------------------------------------------------------------------------
PROJECT = tclsqlite3
PROJECT = sqlite3
!include "rules.vc"
# nmakehelp -V <file> <tag> will search the file for tag, skips until a
Vendored
+23 -30
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.33.0.
# Generated by GNU Autoconf 2.69 for sqlite 3.34.1.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -726,8 +726,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.33.0'
PACKAGE_STRING='sqlite 3.33.0'
PACKAGE_VERSION='3.34.1'
PACKAGE_STRING='sqlite 3.34.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -799,7 +799,6 @@ TEMP_STORE
ALLOWRELEASE
SQLITE_THREADSAFE
BUILD_CC
VERSION_NUMBER
RELEASE
VERSION
program_prefix
@@ -1467,7 +1466,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sqlite 3.33.0 to adapt to many kinds of systems.
\`configure' configures sqlite 3.34.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1532,7 +1531,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.33.0:";;
short | recursive ) echo "Configuration of sqlite 3.34.1:";;
esac
cat <<\_ACEOF
@@ -1659,7 +1658,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.33.0
sqlite configure 3.34.1
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2078,7 +2077,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.33.0, which was
It was created by sqlite $as_me 3.34.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3936,13 +3935,13 @@ if ${lt_cv_nm_interface+:} false; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:3939: $ac_compile\"" >&5)
(eval echo "\"\$as_me:3938: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:3942: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:3941: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:3945: output\"" >&5)
(eval echo "\"\$as_me:3944: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -5148,7 +5147,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 5151 "configure"' > conftest.$ac_ext
echo '#line 5150 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -6673,11 +6672,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:6676: $lt_compile\"" >&5)
(eval echo "\"\$as_me:6675: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:6680: \$? = $ac_status" >&5
echo "$as_me:6679: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7012,11 +7011,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7015: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7014: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:7019: \$? = $ac_status" >&5
echo "$as_me:7018: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7117,11 +7116,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7120: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7119: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7124: \$? = $ac_status" >&5
echo "$as_me:7123: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -7172,11 +7171,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7175: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7174: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7179: \$? = $ac_status" >&5
echo "$as_me:7178: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9552,7 +9551,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9555 "configure"
#line 9554 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9648,7 +9647,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9651 "configure"
#line 9650 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10388,12 +10387,6 @@ RELEASE=`cat $srcdir/VERSION`
{ $as_echo "$as_me:${as_lineno-$LINENO}: Release set to $RELEASE" >&5
$as_echo "$as_me: Release set to $RELEASE" >&6;}
VERSION_NUMBER=`cat $srcdir/VERSION \
| sed 's/[^0-9]/ /g' \
| awk '{printf "%d%03d%03d",$1,$2,$3}'`
{ $as_echo "$as_me:${as_lineno-$LINENO}: Version number set to $VERSION_NUMBER" >&5
$as_echo "$as_me: Version number set to $VERSION_NUMBER" >&6;}
#########
# Locate a compiler for the build machine. This compiler should
@@ -12243,7 +12236,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.33.0, which was
This file was extended by sqlite $as_me 3.34.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12309,7 +12302,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
sqlite config.status 3.33.0
sqlite config.status 3.34.1
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
-5
View File
@@ -155,11 +155,6 @@ AC_SUBST(VERSION)
RELEASE=`cat $srcdir/VERSION`
AC_MSG_NOTICE(Release set to $RELEASE)
AC_SUBST(RELEASE)
VERSION_NUMBER=[`cat $srcdir/VERSION \
| sed 's/[^0-9]/ /g' \
| awk '{printf "%d%03d%03d",$1,$2,$3}'`]
AC_MSG_NOTICE(Version number set to $VERSION_NUMBER)
AC_SUBST(VERSION_NUMBER)
#########
# Locate a compiler for the build machine. This compiler should
+329 -170
View File
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
20-11-2020
# Memory Allocation In vdbesort.c
Memory allocation is slightly different depending on:
* whether or not SQLITE_CONFIG_SMALL_MALLOC is set, and
* whether or not worker threads are enabled.
## SQLITE_CONFIG_SMALL_MALLOC=0
Assuming SQLITE_CONFIG_SMALL_MALLOC is not set, keys passed to the sorter are
added to an in-memory buffer. This buffer is grown using sqlite3Realloc() as
required it reaches the size configured for the main pager cache using "PRAGMA
cache_size". i.e. if the user has executed "PRAGMA main.cache_size = -2048",
then this buffer is allowed to grow up to 2MB in size.
Once the buffer has grown to its threshold, keys are sorted and written to
a temp file. If worker threads are not enabled, this is the only significant
allocation the sorter module makes. After keys are sorted and flushed out to
the temp file, the buffer is reused to accumulate the next batch of keys.
If worker threads are available, then the buffer is passed to a worker thread
to sort and flush once it is full, and a new buffer allocated to allow the
main thread to continue to accumulate keys. Buffers are reused once they
have been flushed, so in this case at most (nWorker+1) buffers are allocated
and used, where nWorker is the number of configured worker threads.
There are no other significant users of heap memory in the sorter module.
Once sorted buffers of keys have been flushed to disk, they are read back
either by mapping the file (via sqlite3_file.xFetch()) or else read back
in one page at a time.
All buffers are allocated by the main thread. A sorter object is associated
with a single database connection, to which it holds a pointer.
## SQLITE_CONFIG_SMALL_MALLOC=1
This case is similar to the above, except that instead of accumulating
multiple keys in a single large buffer, sqlite3VdbeSorterWrite() stores
keys in a regular heap-memory linked list (one allocation per element).
List elements are freed as they are flushed to disk, either by the main
thread or by a worker thread.
Each time a key is added the sorter (and an allocation made),
sqlite3HeapNearlyFull() is called. If it returns true, the current
list of keys is flushed to a temporary file, even if it has not yet
reached the size threshold.
+41
View File
@@ -326,6 +326,47 @@ do_setup_rec_test $tn.16 {
SCAN TABLE t1
}
do_setup_rec_test $tn.17.1 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE a=?
} {
(no new indexes)
SEARCH TABLE example USING INDEX sqlite_autoindex_example_1 (A=?)
}
do_setup_rec_test $tn.17.2 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE b=?
} {
CREATE INDEX example_idx_00000042 ON example(B);
SEARCH TABLE example USING INDEX example_idx_00000042 (B=?)
}
do_setup_rec_test $tn.17.3 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE a=? AND b=?
} {
(no new indexes)
SEARCH TABLE example USING INDEX sqlite_autoindex_example_1 (A=? AND B=?)
}
do_setup_rec_test $tn.17.4 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE a=? AND b>?
} {
(no new indexes)
SEARCH TABLE example USING INDEX sqlite_autoindex_example_1 (A=? AND B>?)
}
do_setup_rec_test $tn.17.5 {
CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B));
} {
SELECT * FROM example WHERE a>? AND b=?
} {
CREATE INDEX example_idx_0000cb3f ON example(B, A);
SEARCH TABLE example USING INDEX example_idx_0000cb3f (B=? AND A>?)
}
}
proc do_candidates_test {tn sql res} {
+8 -4
View File
@@ -685,6 +685,7 @@ static int idxGetTableInfo(
IdxTable *pNew = 0;
int rc, rc2;
char *pCsr = 0;
int nPk = 0;
rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_info=%Q", zTab);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
@@ -695,6 +696,7 @@ static int idxGetTableInfo(
);
nByte += 1 + STRLEN(zCol);
nCol++;
nPk += (sqlite3_column_int(p1, 5)>0);
}
rc2 = sqlite3_reset(p1);
if( rc==SQLITE_OK ) rc = rc2;
@@ -714,7 +716,7 @@ static int idxGetTableInfo(
const char *zCol = (const char*)sqlite3_column_text(p1, 1);
int nCopy = STRLEN(zCol) + 1;
pNew->aCol[nCol].zName = pCsr;
pNew->aCol[nCol].iPk = sqlite3_column_int(p1, 5);
pNew->aCol[nCol].iPk = (sqlite3_column_int(p1, 5)==1 && nPk==1);
memcpy(pCsr, zCol, nCopy);
pCsr += nCopy;
@@ -1719,10 +1721,12 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
idxFinalize(&rc, pIndexXInfo);
idxFinalize(&rc, pWrite);
for(i=0; i<pCtx->nSlot; i++){
sqlite3_free(pCtx->aSlot[i].z);
if( pCtx ){
for(i=0; i<pCtx->nSlot; i++){
sqlite3_free(pCtx->aSlot[i].z);
}
sqlite3_free(pCtx);
}
sqlite3_free(pCtx);
if( rc==SQLITE_OK ){
rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
+5 -1
View File
@@ -3479,7 +3479,7 @@ static int fts3ColumnMethod(
break;
}else{
iCol = p->nColumn;
/* fall-through */
/* no break */ deliberate_fall_through
}
default:
@@ -3722,9 +3722,13 @@ static void fts3SnippetFunc(
switch( nVal ){
case 6: nToken = sqlite3_value_int(apVal[5]);
/* no break */ deliberate_fall_through
case 5: iCol = sqlite3_value_int(apVal[4]);
/* no break */ deliberate_fall_through
case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
/* no break */ deliberate_fall_through
case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
/* no break */ deliberate_fall_through
case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
}
if( !zEllipsis || !zEnd || !zStart ){
+2
View File
@@ -199,6 +199,8 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
#define deliberate_fall_through
#endif /* SQLITE_AMALGAMATION */
#ifdef SQLITE_DEBUG
+2 -1
View File
@@ -188,7 +188,8 @@ static int fts3tokConnectMethod(
assert( (rc==SQLITE_OK)==(pMod!=0) );
if( rc==SQLITE_OK ){
const char * const *azArg = (const char * const *)&azDequote[1];
const char * const *azArg = 0;
if( nDequote>1 ) azArg = (const char * const *)&azDequote[1];
rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
}
+1
View File
@@ -742,6 +742,7 @@ proc print_categories {lMap} {
}
iTbl++;
}
aAscii[0] = 0; /* 0x00 is never a token character */
}
}]
}
+23 -9
View File
@@ -184,6 +184,7 @@ struct Fts5Config {
Fts5Tokenizer *pTok;
fts5_tokenizer *pTokApi;
int bLock; /* True when table is preparing statement */
int ePattern; /* FTS_PATTERN_XXX constant */
/* Values loaded from the %_config table */
int iCookie; /* Incremented when %_config is modified */
@@ -204,17 +205,19 @@ struct Fts5Config {
};
/* Current expected value of %_config table 'version' field */
#define FTS5_CURRENT_VERSION 4
#define FTS5_CURRENT_VERSION 4
#define FTS5_CONTENT_NORMAL 0
#define FTS5_CONTENT_NONE 1
#define FTS5_CONTENT_EXTERNAL 2
#define FTS5_DETAIL_FULL 0
#define FTS5_DETAIL_NONE 1
#define FTS5_DETAIL_COLUMNS 2
#define FTS5_DETAIL_FULL 0
#define FTS5_DETAIL_NONE 1
#define FTS5_DETAIL_COLUMNS 2
#define FTS5_PATTERN_NONE 0
#define FTS5_PATTERN_LIKE 65 /* matches SQLITE_INDEX_CONSTRAINT_LIKE */
#define FTS5_PATTERN_GLOB 66 /* matches SQLITE_INDEX_CONSTRAINT_GLOB */
int sqlite3Fts5ConfigParse(
Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**
@@ -484,7 +487,7 @@ int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
/*
** Functions called by the storage module as part of integrity-check.
*/
int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum, int bUseCksum);
/*
** Called during virtual module initialization to register UDF
@@ -554,8 +557,7 @@ int sqlite3Fts5GetTokenizer(
Fts5Global*,
const char **azArg,
int nArg,
Fts5Tokenizer**,
fts5_tokenizer**,
Fts5Config*,
char **pzErr
);
@@ -639,7 +641,7 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*);
@@ -684,11 +686,19 @@ struct Fts5Token {
/* Parse a MATCH expression. */
int sqlite3Fts5ExprNew(
Fts5Config *pConfig,
int bPhraseToAnd,
int iCol, /* Column on LHS of MATCH operator */
const char *zExpr,
Fts5Expr **ppNew,
char **pzErr
);
int sqlite3Fts5ExprPattern(
Fts5Config *pConfig,
int bGlob,
int iCol,
const char *zText,
Fts5Expr **pp
);
/*
** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc);
@@ -797,6 +807,10 @@ int sqlite3Fts5AuxInit(fts5_api*);
*/
int sqlite3Fts5TokenizerInit(fts5_api*);
int sqlite3Fts5TokenizerPattern(
int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
Fts5Tokenizer *pTok
);
/*
** End of interface to code in fts5_tokenizer.c.
**************************************************************************/
+10 -12
View File
@@ -566,7 +566,7 @@ static int fts5Bm25GetData(
int rc = SQLITE_OK; /* Return code */
Fts5Bm25Data *p; /* Object to return */
p = pApi->xGetAuxdata(pFts, 0);
p = (Fts5Bm25Data*)pApi->xGetAuxdata(pFts, 0);
if( p==0 ){
int nPhrase; /* Number of phrases in query */
sqlite3_int64 nRow = 0; /* Number of rows in table */
@@ -640,7 +640,7 @@ static void fts5Bm25Function(
){
const double k1 = 1.2; /* Constant "k1" from BM25 formula */
const double b = 0.75; /* Constant "b" from BM25 formula */
int rc = SQLITE_OK; /* Error code */
int rc; /* Error code */
double score = 0.0; /* SQL function return value */
Fts5Bm25Data *pData; /* Values allocated/calculated once only */
int i; /* Iterator variable */
@@ -672,17 +672,15 @@ static void fts5Bm25Function(
D = (double)nTok;
}
/* Determine the BM25 score for the current row. */
for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){
score += pData->aIDF[i] * (
( aFreq[i] * (k1 + 1.0) ) /
( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
);
}
/* If no error has occurred, return the calculated score. Otherwise,
** throw an SQL exception. */
/* Determine and return the BM25 score for the current row. Or, if an
** error has occurred, throw an exception. */
if( rc==SQLITE_OK ){
for(i=0; i<pData->nPhrase; i++){
score += pData->aIDF[i] * (
( aFreq[i] * (k1 + 1.0) ) /
( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
);
}
sqlite3_result_double(pCtx, -1.0 * score);
}else{
sqlite3_result_error_code(pCtx, rc);
+2 -4
View File
@@ -325,7 +325,7 @@ static int fts5ConfigParseSpecial(
rc = SQLITE_ERROR;
}else{
rc = sqlite3Fts5GetTokenizer(pGlobal,
(const char**)azArg, (int)nArg, &pConfig->pTok, &pConfig->pTokApi,
(const char**)azArg, (int)nArg, pConfig,
pzErr
);
}
@@ -397,9 +397,7 @@ static int fts5ConfigParseSpecial(
*/
static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){
assert( pConfig->pTok==0 && pConfig->pTokApi==0 );
return sqlite3Fts5GetTokenizer(
pGlobal, 0, 0, &pConfig->pTok, &pConfig->pTokApi, 0
);
return sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0);
}
/*
+215 -52
View File
@@ -128,6 +128,7 @@ struct Fts5Parse {
int nPhrase; /* Size of apPhrase array */
Fts5ExprPhrase **apPhrase; /* Array of all phrases */
Fts5ExprNode *pExpr; /* Result of a successful parse */
int bPhraseToAnd; /* Convert "a+b" to "a AND b" */
};
void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
@@ -216,6 +217,7 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); }
int sqlite3Fts5ExprNew(
Fts5Config *pConfig, /* FTS5 Configuration */
int bPhraseToAnd,
int iCol,
const char *zExpr, /* Expression text */
Fts5Expr **ppNew,
@@ -231,6 +233,7 @@ int sqlite3Fts5ExprNew(
*ppNew = 0;
*pzErr = 0;
memset(&sParse, 0, sizeof(sParse));
sParse.bPhraseToAnd = bPhraseToAnd;
pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc);
if( pEngine==0 ){ return SQLITE_NOMEM; }
sParse.pConfig = pConfig;
@@ -273,6 +276,7 @@ int sqlite3Fts5ExprNew(
pNew->pConfig = pConfig;
pNew->apExprPhrase = sParse.apPhrase;
pNew->nPhrase = sParse.nPhrase;
pNew->bDesc = 0;
sParse.apPhrase = 0;
}
}else{
@@ -284,6 +288,81 @@ int sqlite3Fts5ExprNew(
return sParse.rc;
}
/*
** This function is only called when using the special 'trigram' tokenizer.
** Argument zText contains the text of a LIKE or GLOB pattern matched
** against column iCol. This function creates and compiles an FTS5 MATCH
** expression that will match a superset of the rows matched by the LIKE or
** GLOB. If successful, SQLITE_OK is returned. Otherwise, an SQLite error
** code.
*/
int sqlite3Fts5ExprPattern(
Fts5Config *pConfig, int bGlob, int iCol, const char *zText, Fts5Expr **pp
){
i64 nText = strlen(zText);
char *zExpr = (char*)sqlite3_malloc64(nText*4 + 1);
int rc = SQLITE_OK;
if( zExpr==0 ){
rc = SQLITE_NOMEM;
}else{
char aSpec[3];
int iOut = 0;
int i = 0;
int iFirst = 0;
if( bGlob==0 ){
aSpec[0] = '_';
aSpec[1] = '%';
aSpec[2] = 0;
}else{
aSpec[0] = '*';
aSpec[1] = '?';
aSpec[2] = '[';
}
while( i<=nText ){
if( i==nText
|| zText[i]==aSpec[0] || zText[i]==aSpec[1] || zText[i]==aSpec[2]
){
if( i-iFirst>=3 ){
int jj;
zExpr[iOut++] = '"';
for(jj=iFirst; jj<i; jj++){
zExpr[iOut++] = zText[jj];
if( zText[jj]=='"' ) zExpr[iOut++] = '"';
}
zExpr[iOut++] = '"';
zExpr[iOut++] = ' ';
}
if( zText[i]==aSpec[2] ){
i += 2;
if( zText[i-1]=='^' ) i++;
while( i<nText && zText[i]!=']' ) i++;
}
iFirst = i+1;
}
i++;
}
if( iOut>0 ){
int bAnd = 0;
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
bAnd = 1;
if( pConfig->eDetail==FTS5_DETAIL_NONE ){
iCol = pConfig->nCol;
}
}
zExpr[iOut] = '\0';
rc = sqlite3Fts5ExprNew(pConfig, bAnd, iCol, zExpr, pp,pConfig->pzErrmsg);
}else{
*pp = 0;
}
sqlite3_free(zExpr);
}
return rc;
}
/*
** Free the expression node object passed as the only argument.
*/
@@ -1661,6 +1740,20 @@ void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){
pParse->pExpr = p;
}
static int parseGrowPhraseArray(Fts5Parse *pParse){
if( (pParse->nPhrase % 8)==0 ){
sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
Fts5ExprPhrase **apNew;
apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte);
if( apNew==0 ){
pParse->rc = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
pParse->apPhrase = apNew;
}
return SQLITE_OK;
}
/*
** This function is called by the parser to process a string token. The
** string may or may not be quoted. In any case it is tokenized and a
@@ -1696,16 +1789,9 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
}else{
if( pAppend==0 ){
if( (pParse->nPhrase % 8)==0 ){
sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
Fts5ExprPhrase **apNew;
apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte);
if( apNew==0 ){
pParse->rc = SQLITE_NOMEM;
fts5ExprPhraseFree(sCtx.pPhrase);
return 0;
}
pParse->apPhrase = apNew;
if( parseGrowPhraseArray(pParse) ){
fts5ExprPhraseFree(sCtx.pPhrase);
return 0;
}
pParse->nPhrase++;
}
@@ -2112,6 +2198,67 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
}
}
/*
** This function is used when parsing LIKE or GLOB patterns against
** trigram indexes that specify either detail=column or detail=none.
** It converts a phrase:
**
** abc + def + ghi
**
** into an AND tree:
**
** abc AND def AND ghi
*/
static Fts5ExprNode *fts5ParsePhraseToAnd(
Fts5Parse *pParse,
Fts5ExprNearset *pNear
){
int nTerm = pNear->apPhrase[0]->nTerm;
int ii;
int nByte;
Fts5ExprNode *pRet;
assert( pNear->nPhrase==1 );
assert( pParse->bPhraseToAnd );
nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
pRet->eType = FTS5_AND;
pRet->nChild = nTerm;
fts5ExprAssignXNext(pRet);
pParse->nPhrase--;
for(ii=0; ii<nTerm; ii++){
Fts5ExprPhrase *pPhrase = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(
&pParse->rc, sizeof(Fts5ExprPhrase)
);
if( pPhrase ){
if( parseGrowPhraseArray(pParse) ){
fts5ExprPhraseFree(pPhrase);
}else{
pParse->apPhrase[pParse->nPhrase++] = pPhrase;
pPhrase->nTerm = 1;
pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup(
&pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1
);
pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING,
0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase)
);
}
}
}
if( pParse->rc ){
sqlite3Fts5ParseNodeFree(pRet);
pRet = 0;
}else{
sqlite3Fts5ParseNearsetFree(pNear);
}
}
return pRet;
}
/*
** Allocate and return a new expression object. If anything goes wrong (i.e.
** OOM error), leave an error code in pParse and return NULL.
@@ -2136,51 +2283,58 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
if( eType!=FTS5_STRING && pLeft==0 ) return pRight;
if( eType!=FTS5_STRING && pRight==0 ) return pLeft;
if( eType==FTS5_NOT ){
nChild = 2;
}else if( eType==FTS5_AND || eType==FTS5_OR ){
nChild = 2;
if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
if( pRight->eType==eType ) nChild += pRight->nChild-1;
}
if( eType==FTS5_STRING
&& pParse->bPhraseToAnd
&& pNear->apPhrase[0]->nTerm>1
){
pRet = fts5ParsePhraseToAnd(pParse, pNear);
}else{
if( eType==FTS5_NOT ){
nChild = 2;
}else if( eType==FTS5_AND || eType==FTS5_OR ){
nChild = 2;
if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
if( pRight->eType==eType ) nChild += pRight->nChild-1;
}
nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
pRet->eType = eType;
pRet->pNear = pNear;
fts5ExprAssignXNext(pRet);
if( eType==FTS5_STRING ){
int iPhrase;
for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
pNear->apPhrase[iPhrase]->pNode = pRet;
if( pNear->apPhrase[iPhrase]->nTerm==0 ){
pRet->xNext = 0;
pRet->eType = FTS5_EOF;
if( pRet ){
pRet->eType = eType;
pRet->pNear = pNear;
fts5ExprAssignXNext(pRet);
if( eType==FTS5_STRING ){
int iPhrase;
for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
pNear->apPhrase[iPhrase]->pNode = pRet;
if( pNear->apPhrase[iPhrase]->nTerm==0 ){
pRet->xNext = 0;
pRet->eType = FTS5_EOF;
}
}
}
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
if( pNear->nPhrase!=1
|| pPhrase->nTerm>1
|| (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
){
assert( pParse->rc==SQLITE_OK );
pParse->rc = SQLITE_ERROR;
assert( pParse->zErr==0 );
pParse->zErr = sqlite3_mprintf(
"fts5: %s queries are not supported (detail!=full)",
pNear->nPhrase==1 ? "phrase": "NEAR"
);
sqlite3_free(pRet);
pRet = 0;
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
if( pNear->nPhrase!=1
|| pPhrase->nTerm>1
|| (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
){
assert( pParse->rc==SQLITE_OK );
pParse->rc = SQLITE_ERROR;
assert( pParse->zErr==0 );
pParse->zErr = sqlite3_mprintf(
"fts5: %s queries are not supported (detail!=full)",
pNear->nPhrase==1 ? "phrase": "NEAR"
);
sqlite3_free(pRet);
pRet = 0;
}
}
}else{
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
}
}else{
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
}
}
}
@@ -2401,8 +2555,17 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
int iTerm;
if( pNear->pColset ){
int iCol = pNear->pColset->aiCol[0];
zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]);
int ii;
Fts5Colset *pColset = pNear->pColset;
if( pColset->nCol>1 ) zRet = fts5PrintfAppend(zRet, "{");
for(ii=0; ii<pColset->nCol; ii++){
zRet = fts5PrintfAppend(zRet, "%s%s",
pConfig->azCol[pColset->aiCol[ii]], ii==pColset->nCol-1 ? "" : " "
);
}
if( zRet ){
zRet = fts5PrintfAppend(zRet, "%s : ", pColset->nCol>1 ? "}" : "");
}
if( zRet==0 ) return 0;
}
@@ -2525,7 +2688,7 @@ static void fts5ExprFunction(
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
rc = sqlite3Fts5ExprNew(pConfig, 0, pConfig->nCol, zExpr, &pExpr, &zErr);
}
if( rc==SQLITE_OK ){
char *zText;
+2 -2
View File
@@ -306,7 +306,6 @@ int sqlite3Fts5HashWrite(
p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
}
nIncr += p->nData;
}else{
/* Appending to an existing hash-entry. Check that there is enough
@@ -339,8 +338,9 @@ int sqlite3Fts5HashWrite(
/* If this is a new rowid, append the 4-byte size field for the previous
** entry, and the new rowid for this entry. */
if( iRowid!=p->iRowid ){
u64 iDiff = (u64)iRowid - (u64)p->iRowid;
fts5HashAddPoslistSize(pHash, p, 0);
p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iDiff);
p->iRowid = iRowid;
bNew = 1;
p->iSzPoslist = p->nData;
+13 -9
View File
@@ -1754,7 +1754,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
ASSERT_SZLEAF_OK(pIter->pLeaf);
while( 1 ){
i64 iDelta = 0;
u64 iDelta = 0;
if( eDetail==FTS5_DETAIL_NONE ){
/* todo */
@@ -1769,7 +1769,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
i += nPos;
}
if( i>=n ) break;
i += fts5GetVarint(&a[i], (u64*)&iDelta);
i += fts5GetVarint(&a[i], &iDelta);
pIter->iRowid += iDelta;
/* If necessary, grow the pIter->aRowidOffset[] array. */
@@ -1868,7 +1868,7 @@ static void fts5SegIterNext_Reverse(
if( pIter->iRowidOffset>0 ){
u8 *a = pIter->pLeaf->p;
int iOff;
i64 iDelta;
u64 iDelta;
pIter->iRowidOffset--;
pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset];
@@ -1877,7 +1877,7 @@ static void fts5SegIterNext_Reverse(
if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){
iOff += pIter->nPos;
}
fts5GetVarint(&a[iOff], (u64*)&iDelta);
fts5GetVarint(&a[iOff], &iDelta);
pIter->iRowid -= iDelta;
}else{
fts5SegIterReverseNewPage(p, pIter);
@@ -4997,7 +4997,9 @@ static void fts5MergePrefixLists(
** at most 20 bytes of unexpected space. */
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
fts5BufferZero(&tmp);
sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist + 10 + 10);
sqlite3Fts5BufferSize(&p->rc, &tmp,
i1.nPoslist + i2.nPoslist + 10 + 10 + FTS5_DATA_ZERO_PADDING
);
if( p->rc ) break;
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
@@ -5071,9 +5073,10 @@ static void fts5MergePrefixLists(
}
assert_nc( out.n<=(p1->n+p2->n+9) );
fts5BufferSet(&p->rc, p1, out.n, out.p);
fts5BufferFree(p1);
fts5BufferFree(&tmp);
fts5BufferFree(&out);
memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING);
*p1 = out;
}
}
@@ -6059,7 +6062,7 @@ static void fts5IndexIntegrityCheckSegment(
** error, or some other SQLite error code if another error (e.g. OOM)
** occurs.
*/
int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
int eDetail = p->pConfig->eDetail;
u64 cksum2 = 0; /* Checksum based on contents of indexes */
Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */
@@ -6120,6 +6123,7 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
}else{
poslist.n = 0;
fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
fts5BufferAppendBlob(&p->rc, &poslist, 4, (const u8*)"\0\0\0\0");
while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
int iCol = FTS5_POS2COLUMN(iPos);
int iTokOff = FTS5_POS2OFFSET(iPos);
@@ -6130,7 +6134,7 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
fts5MultiIterFree(pIter);
if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
fts5StructureRelease(pStruct);
#ifdef SQLITE_DEBUG
+80 -37
View File
@@ -464,6 +464,23 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
#endif
}
static int fts5UsePatternMatch(
Fts5Config *pConfig,
struct sqlite3_index_constraint *p
){
assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB );
assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE );
if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
return 1;
}
if( pConfig->ePattern==FTS5_PATTERN_LIKE
&& (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB)
){
return 1;
}
return 0;
}
/*
** Implementation of the xBestIndex method for FTS5 tables. Within the
** WHERE constraint, it searches for the following:
@@ -493,7 +510,9 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
**
** Match against table column: "m"
** Match against rank column: "r"
** Match against other column: "<column-number>"
** Match against other column: "M<column-number>"
** LIKE against other column: "L<column-number>"
** GLOB against other column: "G<column-number>"
** Equality constraint against the rowid: "="
** A < or <= against the rowid: "<"
** A > or >= against the rowid: ">"
@@ -554,7 +573,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
return SQLITE_ERROR;
}
idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 6 + 1);
idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1);
if( idxStr==0 ) return SQLITE_NOMEM;
pInfo->idxStr = idxStr;
pInfo->needToFreeIdxStr = 1;
@@ -578,25 +597,29 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
if( bSeenRank ) continue;
idxStr[iIdxStr++] = 'r';
bSeenRank = 1;
}else{
}else if( iCol>=0 ){
bSeenMatch = 1;
idxStr[iIdxStr++] = 'm';
if( iCol<nCol ){
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]);
assert( idxStr[iIdxStr]=='\0' );
}
idxStr[iIdxStr++] = 'M';
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]);
assert( idxStr[iIdxStr]=='\0' );
}
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
pInfo->aConstraintUsage[i].omit = 1;
}
}
else if( p->usable && bSeenEq==0
&& p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0
){
idxStr[iIdxStr++] = '=';
bSeenEq = 1;
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
}else if( p->usable ){
if( iCol>=0 && iCol<nCol && fts5UsePatternMatch(pConfig, p) ){
assert( p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB );
idxStr[iIdxStr++] = p->op==FTS5_PATTERN_LIKE ? 'L' : 'G';
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]);
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
assert( idxStr[iIdxStr]=='\0' );
}else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){
idxStr[iIdxStr++] = '=';
bSeenEq = 1;
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
}
}
}
@@ -1229,19 +1252,14 @@ static int fts5FilterMethod(
case 'r':
pRank = apVal[i];
break;
case 'm': {
case 'M': {
const char *zText = (const char*)sqlite3_value_text(apVal[i]);
if( zText==0 ) zText = "";
if( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ){
iCol = 0;
do{
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
iIdxStr++;
}while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
}else{
iCol = pConfig->nCol;
}
iCol = 0;
do{
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
iIdxStr++;
}while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
if( zText[0]=='*' ){
/* The user has issued a query of the form "MATCH '*...'". This
@@ -1251,7 +1269,7 @@ static int fts5FilterMethod(
goto filter_out;
}else{
char **pzErr = &pTab->p.base.zErrMsg;
rc = sqlite3Fts5ExprNew(pConfig, iCol, zText, &pExpr, pzErr);
rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
pExpr = 0;
@@ -1261,6 +1279,25 @@ static int fts5FilterMethod(
break;
}
case 'L':
case 'G': {
int bGlob = (idxStr[iIdxStr-1]=='G');
const char *zText = (const char*)sqlite3_value_text(apVal[i]);
iCol = 0;
do{
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
iIdxStr++;
}while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
if( zText ){
rc = sqlite3Fts5ExprPattern(pConfig, bGlob, iCol, zText, &pExpr);
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
pExpr = 0;
}
if( rc!=SQLITE_OK ) goto filter_out;
break;
}
case '=':
pRowidEq = apVal[i];
break;
@@ -1508,7 +1545,8 @@ static int fts5SpecialInsert(
int nMerge = sqlite3_value_int(pVal);
rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
}else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
int iArg = sqlite3_value_int(pVal);
rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, iArg);
#ifdef SQLITE_DEBUG
}else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
pConfig->bPrefixIndex = sqlite3_value_int(pVal);
@@ -2671,8 +2709,7 @@ int sqlite3Fts5GetTokenizer(
Fts5Global *pGlobal,
const char **azArg,
int nArg,
Fts5Tokenizer **ppTok,
fts5_tokenizer **ppTokApi,
Fts5Config *pConfig,
char **pzErr
){
Fts5TokenizerModule *pMod;
@@ -2684,16 +2721,22 @@ int sqlite3Fts5GetTokenizer(
rc = SQLITE_ERROR;
*pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
}else{
rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok);
*ppTokApi = &pMod->x;
if( rc!=SQLITE_OK && pzErr ){
*pzErr = sqlite3_mprintf("error in tokenizer constructor");
rc = pMod->x.xCreate(
pMod->pUserData, &azArg[1], (nArg?nArg-1:0), &pConfig->pTok
);
pConfig->pTokApi = &pMod->x;
if( rc!=SQLITE_OK ){
if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor");
}else{
pConfig->ePattern = sqlite3Fts5TokenizerPattern(
pMod->x.xCreate, pConfig->pTok
);
}
}
if( rc!=SQLITE_OK ){
*ppTokApi = 0;
*ppTok = 0;
pConfig->pTokApi = 0;
pConfig->pTok = 0;
}
return rc;
+78 -65
View File
@@ -429,9 +429,16 @@ static int fts5StorageDeleteFromIndex(
zText, nText, (void*)&ctx, fts5StorageInsertCallback
);
p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
if( p->aTotalSize[iCol-1]<0 ){
rc = FTS5_CORRUPT;
}
}
}
p->nTotalRow--;
if( rc==SQLITE_OK && p->nTotalRow<1 ){
rc = FTS5_CORRUPT;
}else{
p->nTotalRow--;
}
rc2 = sqlite3_reset(pSeek);
if( rc==SQLITE_OK ) rc = rc2;
@@ -874,13 +881,14 @@ static int fts5StorageIntegrityCallback(
** some other SQLite error code if an error occurs while attempting to
** determine this.
*/
int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){
Fts5Config *pConfig = p->pConfig;
int rc; /* Return code */
int rc = SQLITE_OK; /* Return code */
int *aColSize; /* Array of size pConfig->nCol */
i64 *aTotalSize; /* Array of size pConfig->nCol */
Fts5IntegrityCtx ctx;
sqlite3_stmt *pScan;
int bUseCksum;
memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
ctx.pConfig = p->pConfig;
@@ -889,83 +897,88 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
aColSize = (int*)&aTotalSize[pConfig->nCol];
memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
/* Generate the expected index checksum based on the contents of the
** %_content table. This block stores the checksum in ctx.cksum. */
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
if( rc==SQLITE_OK ){
int rc2;
while( SQLITE_ROW==sqlite3_step(pScan) ){
int i;
ctx.iRowid = sqlite3_column_int64(pScan, 0);
ctx.szCol = 0;
if( pConfig->bColumnsize ){
rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
}
if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i] ) continue;
ctx.iCol = i;
bUseCksum = (pConfig->eContent==FTS5_CONTENT_NORMAL
|| (pConfig->eContent==FTS5_CONTENT_EXTERNAL && iArg)
);
if( bUseCksum ){
/* Generate the expected index checksum based on the contents of the
** %_content table. This block stores the checksum in ctx.cksum. */
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
if( rc==SQLITE_OK ){
int rc2;
while( SQLITE_ROW==sqlite3_step(pScan) ){
int i;
ctx.iRowid = sqlite3_column_int64(pScan, 0);
ctx.szCol = 0;
if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
if( pConfig->bColumnsize ){
rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
}
if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
if( rc==SQLITE_OK ){
const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
int nText = sqlite3_column_bytes(pScan, i+1);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
zText, nText,
(void*)&ctx,
fts5StorageIntegrityCallback
);
}
if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
rc = FTS5_CORRUPT;
}
aTotalSize[i] += ctx.szCol;
if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
sqlite3Fts5TermsetFree(ctx.pTermset);
ctx.pTermset = 0;
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i] ) continue;
ctx.iCol = i;
ctx.szCol = 0;
if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
if( rc==SQLITE_OK ){
const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
int nText = sqlite3_column_bytes(pScan, i+1);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
zText, nText,
(void*)&ctx,
fts5StorageIntegrityCallback
);
}
if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
rc = FTS5_CORRUPT;
}
aTotalSize[i] += ctx.szCol;
if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
sqlite3Fts5TermsetFree(ctx.pTermset);
ctx.pTermset = 0;
}
}
sqlite3Fts5TermsetFree(ctx.pTermset);
ctx.pTermset = 0;
if( rc!=SQLITE_OK ) break;
}
sqlite3Fts5TermsetFree(ctx.pTermset);
ctx.pTermset = 0;
if( rc!=SQLITE_OK ) break;
rc2 = sqlite3_reset(pScan);
if( rc==SQLITE_OK ) rc = rc2;
}
rc2 = sqlite3_reset(pScan);
if( rc==SQLITE_OK ) rc = rc2;
}
/* Test that the "totals" (sometimes called "averages") record looks Ok */
if( rc==SQLITE_OK ){
int i;
rc = fts5StorageLoadTotals(p, 0);
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT;
/* Test that the "totals" (sometimes called "averages") record looks Ok */
if( rc==SQLITE_OK ){
int i;
rc = fts5StorageLoadTotals(p, 0);
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT;
}
}
}
/* Check that the %_docsize and %_content tables contain the expected
** number of rows. */
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
i64 nRow = 0;
rc = fts5StorageCount(p, "content", &nRow);
if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
}
if( rc==SQLITE_OK && pConfig->bColumnsize ){
i64 nRow = 0;
rc = fts5StorageCount(p, "docsize", &nRow);
if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
/* Check that the %_docsize and %_content tables contain the expected
** number of rows. */
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
i64 nRow = 0;
rc = fts5StorageCount(p, "content", &nRow);
if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
}
if( rc==SQLITE_OK && pConfig->bColumnsize ){
i64 nRow = 0;
rc = fts5StorageCount(p, "docsize", &nRow);
if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
}
}
/* Pass the expected checksum down to the FTS index module. It will
** verify, amongst other things, that it matches the checksum generated by
** inspecting the index itself. */
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum);
rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum, bUseCksum);
}
sqlite3_free(aTotalSize);
+128
View File
@@ -1258,6 +1258,133 @@ static int fts5PorterTokenize(
);
}
/**************************************************************************
** Start of trigram implementation.
*/
typedef struct TrigramTokenizer TrigramTokenizer;
struct TrigramTokenizer {
int bFold; /* True to fold to lower-case */
};
/*
** Free a trigram tokenizer.
*/
static void fts5TriDelete(Fts5Tokenizer *p){
sqlite3_free(p);
}
/*
** Allocate a trigram tokenizer.
*/
static int fts5TriCreate(
void *pUnused,
const char **azArg,
int nArg,
Fts5Tokenizer **ppOut
){
int rc = SQLITE_OK;
TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
UNUSED_PARAM(pUnused);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
int i;
pNew->bFold = 1;
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
rc = SQLITE_ERROR;
}else{
pNew->bFold = (zArg[0]=='0');
}
}else{
rc = SQLITE_ERROR;
}
}
if( rc!=SQLITE_OK ){
fts5TriDelete((Fts5Tokenizer*)pNew);
pNew = 0;
}
}
*ppOut = (Fts5Tokenizer*)pNew;
return rc;
}
/*
** Trigram tokenizer tokenize routine.
*/
static int fts5TriTokenize(
Fts5Tokenizer *pTok,
void *pCtx,
int unusedFlags,
const char *pText, int nText,
int (*xToken)(void*, int, const char*, int, int, int)
){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
int rc = SQLITE_OK;
char aBuf[32];
const unsigned char *zIn = (const unsigned char*)pText;
const unsigned char *zEof = &zIn[nText];
u32 iCode;
UNUSED_PARAM(unusedFlags);
while( 1 ){
char *zOut = aBuf;
int iStart = zIn - (const unsigned char*)pText;
const unsigned char *zNext;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
zNext = zIn;
if( zIn<zEof ){
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
}else{
break;
}
if( zIn<zEof ){
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
}else{
break;
}
rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);
if( rc!=SQLITE_OK ) break;
zIn = zNext;
}
return rc;
}
/*
** Argument xCreate is a pointer to a constructor function for a tokenizer.
** pTok is a tokenizer previously created using the same method. This function
** returns one of FTS5_PATTERN_NONE, FTS5_PATTERN_LIKE or FTS5_PATTERN_GLOB
** indicating the style of pattern matching that the tokenizer can support.
** In practice, this is:
**
** "trigram" tokenizer, case_sensitive=1 - FTS5_PATTERN_GLOB
** "trigram" tokenizer, case_sensitive=0 (the default) - FTS5_PATTERN_LIKE
** all other tokenizers - FTS5_PATTERN_NONE
*/
int sqlite3Fts5TokenizerPattern(
int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
Fts5Tokenizer *pTok
){
if( xCreate==fts5TriCreate ){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
}
return FTS5_PATTERN_NONE;
}
/*
** Register all built-in tokenizers with FTS5.
*/
@@ -1269,6 +1396,7 @@ int sqlite3Fts5TokenizerInit(fts5_api *pApi){
{ "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
{ "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
{ "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
};
int rc = SQLITE_OK; /* Return code */
+2
View File
@@ -773,4 +773,6 @@ void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
}
iTbl++;
}
aAscii[0] = 0; /* 0x00 is never a token character */
}
+19
View File
@@ -82,5 +82,24 @@ foreach_detail_mode $::testprefix {
} {1 {unable to use function MATCH in the requested context}}
}
#-------------------------------------------------------------------------
# Confirm that the expression parser creates the same expression tree
# for:
#
# {a b} : (abc AND def)
# -{c d} : (abc AND def)
#
# Assuming that the table columns are (a, b, c, d).
#
do_execsql_test 5.1 {
SELECT fts5_expr('abcd AND cdef');
} {{"abcd" AND "cdef"}}
do_execsql_test 5.2 {
SELECT fts5_expr('{a b} : (abcd AND cdef)', 'a', 'b', 'c', 'd');
} {{{a b} : "abcd" AND {a b} : "cdef"}}
do_execsql_test 5.3 {
SELECT fts5_expr('-{c d} : (abcd AND cdef)', 'a', 'b', 'c', 'd');
} {{{a b} : "abcd" AND {a b} : "cdef"}}
finish_test
+185 -1
View File
@@ -9691,7 +9691,7 @@ do_test 65.0 {
do_catchsql_test 65.1 {
SELECT ( MATCH (t1,591)) FROM t1 WHERE t1 MATCH 'e*eŸ'
} {1 {database disk image is malformed}}
} {1 {malformed database schema (t2) - invalid rootpage}}
#-------------------------------------------------------------------------
#
@@ -10324,6 +10324,190 @@ do_catchsql_test 69.2 {
SELECT * FROM t1 WHERE a MATCH 'fx*'
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 70.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 24576 pagesize 4096 filename sql022250.txt.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 00 .....@ ........
| 96: 00 00 00 00 0d 00 00 00 06 0d e2 00 0f c4 0f 6a ...............j
| 112: 0e fc 0e 9d 0e 3d 0d e2 00 00 00 00 00 00 00 00 .....=..........
| 3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74 ..Y...!!..tablet
| 3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6e tt_configttt_con
| 3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45 fig.CREATE TABLE
| 3600: 20 27 74 74 74 5f 63 6f 6e 66 69 67 27 28 6b 20 'ttt_config'(k
| 3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 PRIMARY KEY, v)
| 3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 15 07 WITHOUT ROWID^..
| 3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 64 .##...tablettt_d
| 3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a ocsizettt_docsiz
| 3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 e.CREATE TABLE '
| 3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 ttt_docsize'(id
| 3712: 49 4d 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 IMTEGER PRIMARY
| 3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 20 29 5d 04 07 KEY, sz BLO )]..
| 3744: 17 23 23 01 81 01 74 61 62 6c 65 74 74 74 5f 63 .##...tablettt_c
| 3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e ontentttt_conten
| 3776: 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE '
| 3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 ttt_content'(id
| 3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
| 3824: 4b 45 59 2c 20 63 30 2c 20 63 31 29 6c 03 07 17 KEY, c0, c1)l...
| 3840: 1b 1b 01 81 2f 74 61 62 6c 65 74 74 74 5f 69 64 ..../tablettt_id
| 3856: 78 74 74 74 5f 69 64 78 03 43 52 45 41 54 45 20 xttt_idx.CREATE
| 3872: 54 41 42 4c 45 20 27 74 74 74 5f 69 64 78 27 28 TABLE 'ttt_idx'(
| 3888: 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e segid, term, pgn
| 3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 73 o, PRIMARY KEY(s
| 3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54 egid, term)) WIT
| 3936: 48 4f 55 54 20 52 4f 57 49 44 58 02 07 17 1d 1d HOUT ROWIDX.....
| 3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61 ...tablettt_data
| 3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 20 ttt_data.CREATE
| 3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27 TABLE 'ttt_data'
| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
| 4032: 4c 4f 42 29 3a 01 06 17 13 13 08 5f 74 61 62 6c LOB):......_tabl
| 4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49 ettttttCREATE VI
| 4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 RTUAL TABLE ttt
| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
| page 2 offset 4096
| 0: 0d 0f 54 00 05 0e 81 00 0f e7 0e 81 0f af 0f 58 ..T............X
| 16: 0e 98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 3712: 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 03 01 .....0..........
| 3728: 01 01 02 01 01 03 01 01 81 24 8c 80 80 80 80 01 .........$......
| 3744: 04 00 82 4c 00 00 00 9b 02 30 65 03 1a 02 05 05 ...L.....0e.....
| 3760: 07 05 01 01 04 03 03 08 03 03 01 2e 02 05 05 07 ................
| 3776: 05 07 05 07 05 01 01 14 03 03 08 03 03 08 03 bf ................
| 3792: 07 f2 f3 02 01 65 03 1e 03 05 05 04 05 05 01 01 .....e..........
| 3808: 03 06 04 04 06 04 03 01 36 03 05 05 04 05 05 04 ........6.......
| 3824: 05 15 04 05 05 01 01 03 06 04 04 06 04 04 a1 04 ................
| 3840: 04 06 04 03 03 01 65 03 14 04 05 07 05 05 01 01 ......e.........
| 3856: 02 09 0a 01 20 04 05 07 05 07 05 07 05 05 01 01 .... ...........
| 3872: 02 0f da 0a 0a 04 01 64 f3 02 0a 01 06 0a 0a 0a .......d........
| 3888: 05 01 65 03 06 01 01 0a 01 0a 01 01 0a 0a 0a 04 ..e.............
| 3904: 2b 31 21 0b 0f ef 00 14 2a 00 00 00 00 01 02 02 +1!.....*.......
| 3920: 00 02 01 01 01 02 01 01 50 88 80 80 80 80 01 04 ........P.......
| 3936: 00 81 24 00 00 00 47 01 30 65 02 1a 02 05 05 07 ..$...G.0e......
| 3952: 05 01 01 04 03 03 08 03 03 02 01 65 02 1d f3 05 ...........e....
| 3968: 05 04 05 05 01 01 04 06 04 04 06 04 03 03 01 65 ...............e
| 3984: 02 14 04 05 07 05 05 01 01 02 08 0a 04 01 65 02 ..............e.
| 4000: 02 0a 05 01 65 02 06 01 01 0a 04 12 14 0f 06 31 ....e..........1
| 4016: 84 80 80 80 80 01 03 00 68 00 00 00 2b 02 30 65 ........h...+.0e
| 4032: 01 10 02 05 05 01 01 04 03 03 02 01 66 01 12 03 ............f...
| 4048: 05 05 01 01 03 06 04 03 03 01 65 01 0e 04 05 05 ..........e.....
| 4064: 01 01 02 08 04 0d 0e 06 01 03 00 12 04 4c 4c 00 .............LL.
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 3 offset 8192
| 0: 0a 2f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ./..............
| page 4 offset 12288
| 3344: 00 00 00 00 00 00 00 00 00 00 81 52 04 06 10 81 ...........R....
| 3360: 5d 81 55 65 20 65 65 20 65 65 65 20 65 20 65 65 ].Ue ee eee e ee
| 3376: 20 65 65 65 20 65 20 65 65 20 65 65 65 65 20 65 eee e ee eeee e
| 3392: 65 20 65 65 65 24 a5 20 65 65 20 65 65 65 20 65 e eee$. ee eee e
| 3408: 24 05 65 20 65 65 65 65 20 65 65 20 65 65 65 20 $.e eeee ee eee
| 3424: 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 e ee eee e ee ee
| 3440: 65 65 20 65 65 20 65 65 65 20 65 20 65 65 10 65 ee ee eee e ee.e
| 3456: 65 65 20 65 20 65 65 20 65 65 65 65 65 65 20 65 ee e ee eeeeee e
| 3472: 65 20 65 20 65 20 65 20 65 65 20 65 65 65 20 65 e e e e ee eee e
| 3488: 1f 20 65 65 66 65 65 20 65 65 20 65 20 65 20 2d . eefee ee e e -
| page 5 offset 16384
| 4064: 00 00 00 00 05 04 d0 00 10 21 21 05 03 03 00 10 .........!!.....
| 4080: 11 11 05 02 03 00 10 11 10 05 01 03 00 10 09 09 ................
| page 6 offset 20480
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| end sql022250.txt.db
}]} {}
do_catchsql_test 70.1 {
SELECT snippet(ttt, -1, '', '','','>')FROM ttt('e* NOT ee*e* NOT ee*');
} {1 {database disk image is malformed}}
do_catchsql_test 70.2 {
SELECT snippet(ttt, -1, '', '','',13)FROM ttt('e* NOT ee*e* NOT ee*')
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 71.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 28672 pagesize 4096 filename sql025294.txt.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 00 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........
| 96: 00 00 00 00 0d 00 00 00 07 0d d2 00 0f c4 0f 6d ...............m
| 112: 0f 02 0e ab 0e 4e 0d f6 0d d2 00 00 00 00 00 00 .....N..........
| 3536: 00 00 22 07 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
| 3552: 32 74 32 07 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
| 3568: 20 74 32 28 78 29 56 06 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
| 3584: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
| 3600: 6f 6e 66 69 67 06 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
| 3616: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
| 3632: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
| 3648: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 05 WITHOUT ROWID[.
| 3664: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
| 3680: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
| 3696: 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
| 3712: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
| 3728: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
| 3744: 59 2c 20 73 7a 20 42 4c 4f 42 29 55 04 06 17 21 Y, sz BLOB)U...!
| 3760: 21 01 77 74 61 62 6c 65 74 31 5f 63 6f 6e 74 65 !.wtablet1_conte
| 3776: 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 04 43 52 45 ntt1_content.CRE
| 3792: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 6f ATE TABLE 't1_co
| 3808: 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 45 ntent'(id INTEGE
| 3824: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 63 R PRIMARY KEY, c
| 3840: 30 29 69 03 07 17 19 19 01 81 2d 74 61 62 6c 65 0)i.......-table
| 3856: 74 31 5f 69 64 78 74 31 5f 69 64 78 03 43 52 45 t1_idxt1_idx.CRE
| 3872: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 69 64 ATE TABLE 't1_id
| 3888: 78 27 28 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 x'(segid, term,
| 3904: 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 pgno, PRIMARY KE
| 3920: 59 28 73 65 67 69 64 2c 20 74 65 72 6d 29 29 20 Y(segid, term))
| 3936: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 55 02 07 WITHOUT ROWIDU..
| 3952: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 64 61 ......tablet1_da
| 3968: 74 61 74 31 5f 64 61 74 61 02 43 52 45 41 54 45 tat1_data.CREATE
| 3984: 20 54 41 42 4c 45 20 27 74 31 5f 64 61 74 61 27 TABLE 't1_data'
| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 4016: 41 52 58 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARX KEY, block B
| 4032: 4c 4f 42 29 3a 01 06 17 11 11 08 63 74 61 62 6c LOB):......ctabl
| 4048: 65 74 31 74 31 43 52 45 41 54 45 20 56 49 52 54 et1t1CREATE VIRT
| 4064: 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 53 49 UAL TABLE t1 USI
| 4080: 4e 47 20 66 74 73 35 28 63 6f 6e 74 65 6e 74 29 NG fts5(content)
| page 2 offset 4096
| 0: 0d 00 00 00 03 0f bd 00 0f e8 0f ef 0f bd 00 00 ................
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 24 84 80 .............$..
| 4032: 80 80 80 01 03 00 4e 00 00 00 1e 06 30 61 62 61 ......N.....0aba
| 4048: 60 eb 01 02 02 04 01 66 74 02 02 02 04 04 6e 64 `......ft.....nd
| 4064: 6f 6e 03 01 f2 04 1a 07 05 01 03 00 10 03 03 0f on..............
| 4080: 0a 03 00 24 00 00 00 00 01 01 4b 00 01 01 01 01 ...$......K.....
| page 3 offset 8192
| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 03 0f e0 00 0f f6 0f ec 0f e0 00 00 ................
| 4064: 0a 03 03 00 1b 61 62 61 6e 64 6f 6e 08 02 03 00 .....abandon....
| 4080: 17 61 62 61 66 74 08 01 03 00 17 61 62 61 63 6b .abaft.....aback
| page 5 offset 16384
| 0: 0d 00 00 00 03 0f ee 00 0f fa 0f f4 0f ee 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 03 ................
| 4080: 03 00 0e 01 04 02 03 00 0e 01 04 01 03 00 0e 01 ................
| page 6 offset 20480
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| page 7 offset 24576
| 0: 0d 00 00 00 03 0f d6 00 0f f4 0f e1 00 00 00 00 ................
| 4048: 00 00 00 00 00 00 09 03 02 1b 72 65 62 75 69 6c ..........rebuil
| 4064: 64 11 02 02 2b 69 6e 74 65 67 72 69 74 79 2d 63 d...+integrity-c
| 4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 heck....optimize
| end sql025294.txt.db
}]} {}
do_catchsql_test 71.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {database disk image is malformed}}
sqlite3_fts5_may_be_corrupt 0
finish_test
+43
View File
@@ -50,4 +50,47 @@ do_test 1.2 {
}
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE TABLE test (
id INTEGER PRIMARY KEY,
name TEXT,
value TEXT
);
CREATE VIRTUAL TABLE test_idx USING fts5(
name, content=test, content_rowid=id
);
}
do_catchsql_test 2.1 {
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 1, 'quick');
} {1 {database disk image is malformed}}
do_catchsql_test 2.2 {
INSERT INTO test_idx(rowid, name) VALUES(123, 'one one one');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
} {1 {database disk image is malformed}}
do_execsql_test 2.3 {
DROP TABLE test_idx;
CREATE VIRTUAL TABLE test_idx USING fts5(
name, content=test, content_rowid=id
);
INSERT INTO test_idx(rowid, name) VALUES(123, 'one one one');
INSERT INTO test_idx(rowid, name) VALUES(124, 'two two two');
INSERT INTO test_idx(rowid, name) VALUES(125, 'two two two');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one');
}
do_catchsql_test 2.4 {
SELECT rowid FROM test_idx WHERE test_idx MATCH 'two' ORDER BY rank;
} {1 {database disk image is malformed}}
finish_test
+1 -1
View File
@@ -14,7 +14,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5faultA
set testprefix fts5faultD
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts5 {
+71
View File
@@ -0,0 +1,71 @@
# 2016 February 2
#
# 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 is focused on OOM errors.
#
source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5faultE
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
faultsim_save_and_close
do_faultsim_test 1 -prep {
faultsim_restore_and_reopen
} -body {
execsql { CREATE VIRTUAL TABLE t1 USING fts5(x, y, tokenize=trigram) }
} -test {
faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}}
}
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, y, tokenize=trigram);
}
faultsim_save_and_close
do_faultsim_test 2 -prep {
faultsim_restore_and_reopen
} -body {
execsql {
INSERT INTO t1 VALUES('abcdefghijklmnopqrstuvwxyz', NULL);
SELECT count(*) FROM t1 WHERE x LIKE '%mnop%' AND t1 MATCH 'jkl';
}
} -test {
faultsim_test_result {0 1} {1 {vtable constructor failed: t1}}
}
reset_db
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, y, tokenize=trigram, detail=none);
INSERT INTO t1 VALUES('abcdefghijklmnopqrstuvwxyz', NULL);
}
faultsim_save_and_close
do_faultsim_test 3 -prep {
faultsim_restore_and_reopen
} -body {
execsql {
SELECT count(*) FROM t1 WHERE x LIKE '%mnopqrs%' AND t1 MATCH 'abc'
}
} -test {
faultsim_test_result {0 1} {1 {vtable constructor failed: t1}}
}
finish_test
+38 -1
View File
@@ -112,7 +112,7 @@ foreach_detail_mode $testprefix {
# Add a small and very large token with the same hash value to an
# empty table. At one point this would provoke an asan error.
#
do_test 2.0 {
do_test 1.5 {
set big [string repeat 12345 40]
set hash [sqlite3_fts5_token_hash 1024 $big]
while {1} {
@@ -128,4 +128,41 @@ foreach_detail_mode $testprefix {
} ;# foreach_detail_mode
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.1 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
INSERT INTO t1(t1, rank) VALUES('hashsize', 1024);
INSERT INTO t1(t1, rank) VALUES('automerge', 0);
INSERT INTO t1(t1, rank) VALUES('crisismerge', 1000);
}
do_execsql_test 2.2 {
BEGIN;
INSERT INTO t1 VALUES('abc def ghi');
SELECT count(*) FROM t1_data;
} {2}
do_execsql_test 2.3 {
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1024
)
INSERT INTO t1 SELECT 'abc def ghi' FROM s;
SELECT (SELECT count(*) FROM t1_data) > 10;
} {1}
do_execsql_test 2.4 {
COMMIT;
DROP TABLE t1;
CREATE VIRTUAL TABLE t1 USING fts5(x);
INSERT INTO t1(t1, rank) VALUES('hashsize', 1024);
INSERT INTO t1(t1, rank) VALUES('automerge', 0);
INSERT INTO t1(t1, rank) VALUES('crisismerge', 1000);
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1024
)
INSERT INTO t1 SELECT 'abc' || i || ' def' || i || ' ghi' || i FROM s;
SELECT (SELECT count(*) FROM t1_data) > 100;
} {1}
finish_test
+36 -1
View File
@@ -273,7 +273,6 @@ do_execsql_test 9.1.2 {
SELECT quote(x'37');
} {X'37'}
breakpoint
do_execsql_test 9.2 {
INSERT INTO vt0 VALUES (SUBSTR(x'37', 0));
-- INSERT INTO vt0 VALUES (x'37');
@@ -282,4 +281,40 @@ do_execsql_test 9.3 {
INSERT INTO vt0(vt0) VALUES('integrity-check');
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 10.0 {
CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b);
CREATE VIRTUAL TABLE vt0 USING fts5(a, b, content=t1);
INSERT INTO vt0(rowid, a, b) VALUES(1, 'abc', 'def');
}
do_catchsql_test 10.1 {
INSERT INTO vt0(vt0) VALUES('integrity-check');
} {0 {}}
do_catchsql_test 10.2 {
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0);
} {0 {}}
do_catchsql_test 10.3 {
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
} {1 {database disk image is malformed}}
do_catchsql_test 10.3 {
INSERT INTO t1 VALUES(1, 'abc', 'def');
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
} {0 {}}
do_execsql_test 10.4 {
CREATE VIRTUAL TABLE vt1 USING fts5(a, b, content=);
INSERT INTO vt1(rowid, a, b) VALUES(1, 'abc', 'def');
}
do_catchsql_test 10.5.1 {
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0);
} {0 {}}
do_catchsql_test 10.5.2 {
INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1);
} {0 {}}
do_catchsql_test 10.5.3 {
INSERT INTO vt0(vt0) VALUES('integrity-check');
} {0 {}}
finish_test
+2 -2
View File
@@ -31,7 +31,7 @@ do_eqp_test 1.1 {
} {
QUERY PLAN
|--SCAN TABLE t1
`--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:m
`--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:M1
}
do_eqp_test 1.2 {
@@ -46,7 +46,7 @@ do_eqp_test 1.3 {
SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff
} {
QUERY PLAN
|--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:m
|--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:M1
`--USE TEMP B-TREE FOR ORDER BY
}
+35
View File
@@ -111,5 +111,40 @@ do_catchsql_test 2.1 {
SELECT * FROM t4;
} {1 {SQL logic error}}
#-------------------------------------------------------------------------
# Embedded 0x00 characters.
#
reset_db
do_execsql_test 3.1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(z);
CREATE VIRTUAL TABLE tt USING fts5vocab(t1, 'instance');
INSERT INTO t1 VALUES('abc' || char(0) || 'def');
SELECT * FROM tt;
} { abc 1 z 0 def 1 z 1 }
do_execsql_test 3.1.1 {
SELECT hex(z) FROM t1;
} {61626300646566}
do_execsql_test 3.1.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
} {}
do_execsql_test 3.2.0 {
CREATE VIRTUAL TABLE t2 USING fts5(z,
tokenize="unicode61 categories 'L* N* Co Cc'"
);
CREATE VIRTUAL TABLE tu USING fts5vocab(t2, 'instance');
INSERT INTO t2 VALUES('abc' || char(0) || 'def');
SELECT * FROM tu;
} { abc 1 z 0 def 1 z 1 }
do_execsql_test 3.2.1 {
SELECT hex(z) FROM t1;
} {61626300646566}
do_execsql_test 3.2.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
} {}
finish_test
+201
View File
@@ -0,0 +1,201 @@
# 2020 September 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.
#
#*************************************************************************
#
# Tests for the fts5 "trigram" tokenizer.
#
source [file join [file dirname [info script]] fts5_common.tcl]
ifcapable !fts5 { finish_test ; return }
set ::testprefix fts5trigram
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize=trigram);
INSERT INTO t1 VALUES('abcdefghijklm');
INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}
foreach {tn s res} {
1 abc "(abc)defghijklm"
2 defgh "abc(defgh)ijklm"
3 abcdefghijklm "(abcdefghijklm)"
4 กรุ "(กรุ)งเทพมหานคร"
5 งเทพมห "กรุ(งเทพมห)านคร"
6 กรุงเทพมหานคร "(กรุงเทพมหานคร)"
7 Abc "(abc)defghijklm"
8 deFgh "abc(defgh)ijklm"
9 aBcdefGhijKlm "(abcdefghijklm)"
} {
do_execsql_test 1.1.$tn {
SELECT highlight(t1, 0, '(', ')') FROM t1($s)
} $res
}
do_execsql_test 1.2.0 {
SELECT fts5_expr('ABCD', 'tokenize=trigram')
} {{"abc" + "bcd"}}
do_execsql_test 1.2.1 {
SELECT * FROM t1 WHERE y LIKE ? ESCAPE 'a'
}
foreach {tn like res} {
1 {%cDef%} 1
2 {cDef%} {}
3 {%f%} 1
4 {%f_h%} 1
5 {%f_g%} {}
6 {abc%klm} 1
7 {ABCDEFG%} 1
8 {%รุงเ%} 2
} {
do_execsql_test 1.3.$tn {
SELECT rowid FROM t1 WHERE y LIKE $like
} $res
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize="trigram case_sensitive 1");
INSERT INTO t1 VALUES('abcdefghijklm');
INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}
foreach {tn s res} {
1 abc "(abc)defghijklm"
2 defgh "abc(defgh)ijklm"
3 abcdefghijklm "(abcdefghijklm)"
4 กรุ "(กรุ)งเทพมหานคร"
5 งเทพมห "กรุ(งเทพมห)านคร"
6 กรุงเทพมหานคร "(กรุงเทพมหานคร)"
7 Abc ""
8 deFgh ""
9 aBcdefGhijKlm ""
} {
do_execsql_test 2.1.$tn {
SELECT highlight(t1, 0, '(', ')') FROM t1($s)
} $res
}
foreach {tn like res} {
1 {%cDef%} 1
2 {cDef%} {}
3 {%f%} 1
4 {%f_h%} 1
5 {%f_g%} {}
6 {abc%klm} 1
7 {ABCDEFG%} 1
8 {%รุงเ%} 2
} {
do_execsql_test 2.2.$tn {
SELECT rowid FROM t1 WHERE y LIKE $like
} $res
}
foreach {tn like res} {
1 {*cdef*} 1
2 {cdef*} {}
3 {*f*} 1
4 {*f?h*} 1
5 {*f?g*} {}
6 {abc*klm} 1
7 {abcdefg*} 1
8 {*รุงเ*} 2
9 {abc[d]efg*} 1
10 {abc[]d]efg*} 1
11 {abc[^]d]efg*} {}
12 {abc[^]XYZ]efg*} 1
} {
do_execsql_test 2.3.$tn {
SELECT rowid FROM t1 WHERE y GLOB $like
} $res
}
do_execsql_test 2.3.null.1 {
SELECT rowid FROM t1 WHERE y LIKE NULL
}
#-------------------------------------------------------------------------
reset_db
do_catchsql_test 3.1 {
CREATE VIRTUAL TABLE ttt USING fts5(c, tokenize="trigram case_sensitive 2");
} {1 {error in tokenizer constructor}}
do_catchsql_test 3.2 {
CREATE VIRTUAL TABLE ttt USING fts5(c, tokenize="trigram case_sensitive 11");
} {1 {error in tokenizer constructor}}
do_catchsql_test 3.3 {
CREATE VIRTUAL TABLE ttt USING fts5(c, "tokenize=trigram case_sensitive 1");
} {0 {}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE t0 USING fts5(b, tokenize = "trigram");
}
do_execsql_test 4.1 {
INSERT INTO t0 VALUES (x'000b01');
}
do_execsql_test 4.2 {
INSERT INTO t0(t0) VALUES('integrity-check');
}
#-------------------------------------------------------------------------
reset_db
foreach_detail_mode $::testprefix {
foreach {ci} {0 1} {
reset_db
do_execsql_test 5.cs=$ci.0.1 "
CREATE VIRTUAL TABLE t1 USING fts5(
y, tokenize=\"trigram case_sensitive $ci\", detail=%DETAIL%
);
"
do_execsql_test 5.cs=$ci.0.2 {
INSERT INTO t1 VALUES('abcdefghijklm');
INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}
foreach {tn like res} {
1 {%cDef%} 1
2 {cDef%} {}
3 {%f%} 1
4 {%f_h%} 1
5 {%f_g%} {}
6 {abc%klm} 1
7 {ABCDEFG%} 1
8 {%รุงเ%} 2
} {
do_execsql_test 5.cs=$ci.1.$tn {
SELECT rowid FROM t1 WHERE y LIKE $like
} $res
}
}
}
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE ci0 USING fts5(x, tokenize="trigram");
CREATE VIRTUAL TABLE ci1 USING fts5(x, tokenize="trigram case_sensitive 1");
}
# LIKE and GLOB both work with case-insensitive tokenizers. Only GLOB works
# with case-sensitive.
do_eqp_test 6.1 {
SELECT * FROM ci0 WHERE x LIKE ?
} {VIRTUAL TABLE INDEX 0:L0}
do_eqp_test 6.2 {
SELECT * FROM ci0 WHERE x GLOB ?
} {VIRTUAL TABLE INDEX 0:G0}
do_eqp_test 6.3 {
SELECT * FROM ci1 WHERE x LIKE ?
} {{SCAN TABLE ci1 VIRTUAL TABLE INDEX 0:}}
do_eqp_test 6.4 {
SELECT * FROM ci1 WHERE x GLOB ?
} {VIRTUAL TABLE INDEX 0:G0}
finish_test
+2
View File
@@ -12,6 +12,7 @@ proc process_cmdline {} {
cmdline::process ::A $::argv {
{fts5 "use fts5 (this is the default)"}
{fts4 "use fts4"}
{trigram "Use tokenize=trigram"}
{colsize "10 10 10" "list of column sizes"}
{tblname "t1" "table name to create"}
{detail "full" "Fts5 detail mode to use"}
@@ -175,6 +176,7 @@ proc create_table {} {
set sql "CREATE VIRTUAL TABLE IF NOT EXISTS $A(tblname) USING $A(fts) ("
append sql [join $cols ,]
if {$A(fts)=="fts5"} { append sql ",detail=$A(detail)" }
if {$A(trigram)} { append sql ",tokenize=trigram" }
append sql ", prefix='$A(prefix)');"
db eval $sql
+156 -41
View File
@@ -57,21 +57,32 @@ SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
** Must exactly match the definitions in carray.h.
*/
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
#define CARRAY_DOUBLE 2 /* Data is doubles */
#define CARRAY_TEXT 3 /* Data is char* */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Allowed datatypes
*/
#define CARRAY_INT32 0
#define CARRAY_INT64 1
#define CARRAY_DOUBLE 2
#define CARRAY_TEXT 3
/*
** Names of types
** Names of allowed datatypes
*/
static const char *azType[] = { "int32", "int64", "double", "char*" };
/*
** Structure used to hold the sqlite3_carray_bind() information
*/
typedef struct carray_bind carray_bind;
struct carray_bind {
void *aData; /* The data */
int nData; /* Number of elements */
int mFlags; /* Control flags */
void (*xDel)(void*); /* Destructor for aData */
};
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
** serve as the underlying representation of a cursor that scans
@@ -239,28 +250,39 @@ static int carrayFilter(
int argc, sqlite3_value **argv
){
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
if( idxNum ){
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
if( idxNum<3 ){
pCur->eType = CARRAY_INT32;
}else{
unsigned char i;
const char *zType = (const char*)sqlite3_value_text(argv[2]);
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
}
if( i>=sizeof(azType)/sizeof(azType[0]) ){
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
"unknown datatype: %Q", zType);
return SQLITE_ERROR;
}else{
pCur->eType = i;
}
pCur->pPtr = 0;
pCur->iCnt = 0;
switch( idxNum ){
case 1: {
carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind");
if( pBind==0 ) break;
pCur->pPtr = pBind->aData;
pCur->iCnt = pBind->nData;
pCur->eType = pBind->mFlags & 0x03;
break;
}
case 2:
case 3: {
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
if( idxNum<3 ){
pCur->eType = CARRAY_INT32;
}else{
unsigned char i;
const char *zType = (const char*)sqlite3_value_text(argv[2]);
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
}
if( i>=sizeof(azType)/sizeof(azType[0]) ){
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
"unknown datatype: %Q", zType);
return SQLITE_ERROR;
}else{
pCur->eType = i;
}
}
break;
}
}else{
pCur->pPtr = 0;
pCur->iCnt = 0;
}
pCur->iRowid = 1;
return SQLITE_OK;
@@ -275,9 +297,16 @@ static int carrayFilter(
** In this implementation idxNum is used to represent the
** query plan. idxStr is unused.
**
** idxNum is 2 if the pointer= and count= constraints exist,
** 3 if the ctype= constraint also exists, and is 0 otherwise.
** If idxNum is 0, then carray becomes an empty table.
** idxNum is:
**
** 1 If only the pointer= constraint exists. In this case, the
** parameter must be bound using sqlite3_carray_bind().
**
** 2 if the pointer= and count= constraints exist.
**
** 3 if the ctype= constraint also exists.
**
** idxNum is 0 otherwise and carray becomes an empty table.
*/
static int carrayBestIndex(
sqlite3_vtab *tab,
@@ -305,18 +334,21 @@ static int carrayBestIndex(
break;
}
}
if( ptrIdx>=0 && cntIdx>=0 ){
if( ptrIdx>=0 ){
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
pIdxInfo->estimatedCost = (double)1;
pIdxInfo->estimatedRows = 100;
pIdxInfo->idxNum = 2;
if( ctypeIdx>=0 ){
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
pIdxInfo->idxNum = 3;
pIdxInfo->idxNum = 1;
if( cntIdx>=0 ){
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
pIdxInfo->idxNum = 2;
if( ctypeIdx>=0 ){
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
pIdxInfo->idxNum = 3;
}
}
}else{
pIdxInfo->estimatedCost = (double)2147483647;
@@ -353,6 +385,89 @@ static sqlite3_module carrayModule = {
0, /* xRename */
};
/*
** Destructor for the carray_bind object
*/
static void carrayBindDel(void *pPtr){
carray_bind *p = (carray_bind*)pPtr;
if( p->xDel!=SQLITE_STATIC ){
p->xDel(p->aData);
}
sqlite3_free(p);
}
/*
** Invoke this interface in order to bind to the single-argument
** version of CARRAY().
*/
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_carray_bind(
sqlite3_stmt *pStmt,
int idx,
void *aData,
int nData,
int mFlags,
void (*xDestroy)(void*)
){
carray_bind *pNew;
int i;
pNew = sqlite3_malloc64(sizeof(*pNew));
if( pNew==0 ){
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
xDestroy(aData);
}
return SQLITE_NOMEM;
}
pNew->nData = nData;
pNew->mFlags = mFlags;
if( xDestroy==SQLITE_TRANSIENT ){
sqlite3_int64 sz = nData;
switch( mFlags & 0x03 ){
case CARRAY_INT32: sz *= 4; break;
case CARRAY_INT64: sz *= 8; break;
case CARRAY_DOUBLE: sz *= 8; break;
case CARRAY_TEXT: sz *= sizeof(char*); break;
}
if( (mFlags & 0x03)==CARRAY_TEXT ){
for(i=0; i<nData; i++){
const char *z = ((char**)aData)[i];
if( z ) sz += strlen(z) + 1;
}
}
pNew->aData = sqlite3_malloc64( sz );
if( pNew->aData==0 ){
sqlite3_free(pNew);
return SQLITE_NOMEM;
}
if( (mFlags & 0x03)==CARRAY_TEXT ){
char **az = (char**)pNew->aData;
char *z = (char*)&az[nData];
for(i=0; i<nData; i++){
const char *zData = ((char**)aData)[i];
sqlite3_int64 n;
if( zData==0 ){
az[i] = 0;
continue;
}
az[i] = z;
n = strlen(zData);
memcpy(z, zData, n+1);
z += n+1;
}
}else{
memcpy(pNew->aData, aData, sz*nData);
}
pNew->xDel = sqlite3_free;
}else{
pNew->aData = aData;
pNew->xDel = xDestroy;
}
return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
}
/*
** For testing purpose in the TCL test harness, we need a method for
** setting the pointer value. The inttoptr(X) SQL function accomplishes
+23
View File
@@ -0,0 +1,23 @@
/*
** Interface definitions for the CARRAY table-valued function
** extension.
*/
/* Use this interface to bind an array to the single-argument version
** of CARRAY().
*/
int sqlite3_carray_bind(
sqlite3_stmt *pStmt, /* Statement to be bound */
int i, /* Parameter index */
void *aData, /* Pointer to array data */
int nData, /* Number of data elements */
int mFlags, /* CARRAY flags */
void (*xDel)(void*) /* Destructgor for aData*/
);
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
*/
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
#define CARRAY_DOUBLE 2 /* Data is doubles */
#define CARRAY_TEXT 3 /* Data is char* */
+29 -8
View File
@@ -54,11 +54,11 @@
** statically linked against the application, initialize it using
** a single API call as follows:
**
** sqlite3_cksumvfs_init();
** sqlite3_register_cksumvfs();
**
** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new
** default VFS and it uses the prior default VFS as the next VFS
** down in the stack. This is normally what you want. However, it
** down in the stack. This is normally what you want. However, in
** complex situations where multiple VFS shims are being loaded,
** it might be important to ensure that cksumvfs is loaded in the
** correct order so that it sequences itself into the default VFS
@@ -79,7 +79,7 @@
** the reserve-bytes value to 8 by runing:
**
** int n = 8;
** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVED_BYTES, &n);
** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n);
**
** If you do this immediately after creating a new database file,
** before anything else has been written into the file, then that
@@ -157,6 +157,9 @@
** value at offset 20 the SQLite database header is exactly 8. If
** the reserved-space value is not 8, this module is a no-op.
*/
#if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC)
# define SQLITE_CKSUMVFS_STATIC
#endif
#ifdef SQLITE_CKSUMVFS_STATIC
# include "sqlite3.h"
#else
@@ -176,7 +179,7 @@ typedef struct CksmFile CksmFile;
/*
** Useful datatype abbreviations
*/
#if !defined(SQLITE_CORE)
#if !defined(SQLITE_AMALGAMATION)
typedef unsigned char u8;
typedef unsigned int u32;
#endif
@@ -395,7 +398,9 @@ static int cksmRead(
pFile = ORIGFILE(pFile);
rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst);
if( rc==SQLITE_OK ){
if( iOfst==0 && iAmt>=100 && memcmp(zBuf,"SQLite format 3",16)==0 ){
if( iOfst==0 && iAmt>=100 && (
memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0
)){
u8 *d = (u8*)zBuf;
char hasCorrectReserveSize = (d[20]==8);
cksmSetFlags(p, hasCorrectReserveSize);
@@ -434,7 +439,9 @@ static int cksmWrite(
){
CksmFile *p = (CksmFile *)pFile;
pFile = ORIGFILE(pFile);
if( iOfst==0 && iAmt>=100 && memcmp(zBuf,"SQLite format 3",16)==0 ){
if( iOfst==0 && iAmt>=100 && (
memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0
)){
u8 *d = (u8*)zBuf;
char hasCorrectReserveSize = (d[20]==8);
cksmSetFlags(p, hasCorrectReserveSize);
@@ -604,13 +611,20 @@ static int cksmFetch(
return SQLITE_OK;
}
pFile = ORIGFILE(pFile);
return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp);
if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){
return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp);
}
*pp = 0;
return SQLITE_OK;
}
/* Release a memory-mapped page */
static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
pFile = ORIGFILE(pFile);
return pFile->pMethods->xUnfetch(pFile, iOfst, pPage);
if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){
return pFile->pMethods->xUnfetch(pFile, iOfst, pPage);
}
return SQLITE_OK;
}
/*
@@ -763,6 +777,13 @@ int sqlite3_register_cksumvfs(const char *NotUsed){
(void)NotUsed;
return cksmRegisterVfs();
}
int sqlite3_unregister_cksumvfs(void){
if( sqlite3_vfs_find("cksmvfs") ){
sqlite3_vfs_unregister(&cksm_vfs);
sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc);
}
return SQLITE_OK;
}
#endif /* defined(SQLITE_CKSUMVFS_STATIC */
#if !defined(SQLITE_CKSUMVFS_STATIC)
+1 -1
View File
@@ -776,7 +776,7 @@ static int csvtabColumn(
CsvCursor *pCur = (CsvCursor*)cur;
CsvTable *pTab = (CsvTable*)cur->pVtab;
if( i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 ){
sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_STATIC);
sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_TRANSIENT);
}
return SQLITE_OK;
}
+2 -1
View File
@@ -599,7 +599,6 @@ int sqlite3_decimal_init(
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
static const struct {
const char *zFuncName;
int nArg;
@@ -614,6 +613,8 @@ int sqlite3_decimal_init(
unsigned int i;
(void)pzErrMsg; /* Unused parameter */
SQLITE_EXTENSION_INIT2(pApi);
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+7 -2
View File
@@ -42,6 +42,10 @@ SQLITE_EXTENSION_INIT1
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
#endif
#ifndef deliberate_fall_through
# define deliberate_fall_through
#endif
/*
** Versions of isspace(), isalnum() and isdigit() to which it is safe
** to pass signed char values.
@@ -460,7 +464,7 @@ static void jsonRenderNode(
jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
break;
}
/* Fall through into the next case */
/* no break */ deliberate_fall_through
}
case JSON_REAL:
case JSON_INT: {
@@ -601,7 +605,7 @@ static void jsonReturn(
sqlite3_result_int64(pCtx, i);
int_done:
break;
int_as_real: /* fall through to real */;
int_as_real: i=0; /* no break */ deliberate_fall_through
}
case JSON_REAL: {
double r;
@@ -2304,6 +2308,7 @@ static int jsonEachColumn(
}
/* For json_each() path and root are the same so fall through
** into the root case */
/* no break */ deliberate_fall_through
}
default: {
const char *zRoot = p->zRoot;
+9
View File
@@ -286,6 +286,13 @@ static const unsigned char sqlite3CtypeMap[256] = {
#define TK_VARIABLE TK_LITERAL
#define TK_BLOB TK_LITERAL
/* Disable nuisence warnings about case fall-through */
#if !defined(deliberate_fall_through) && defined(__GCC__) && __GCC__>=7
# define deliberate_fall_through __attribute__((fallthrough));
#else
# define deliberate_fall_through
#endif
/*
** Return the length (in bytes) of the token that begins at z[0].
** Store the token type in *tokenType before returning.
@@ -436,6 +443,7 @@ static int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/* If the next character is a digit, this is a floating point
** number that begins with ".". Fall thru into the next case */
/* no break */ deliberate_fall_through
}
case CC_DIGIT: {
*tokenType = TK_INTEGER;
@@ -528,6 +536,7 @@ static int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/* If it is not a BLOB literal, then it must be an ID, since no
** SQL keywords start with the letter 'x'. Fall through */
/* no break */ deliberate_fall_through
}
case CC_ID: {
i = 1;
+17 -6
View File
@@ -106,10 +106,10 @@ struct series_cursor {
*/
static int seriesConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
void *pUnused,
int argcUnused, const char *const*argvUnused,
sqlite3_vtab **ppVtab,
char **pzErr
char **pzErrUnused
){
sqlite3_vtab *pNew;
int rc;
@@ -120,6 +120,10 @@ static int seriesConnect(
#define SERIES_COLUMN_STOP 2
#define SERIES_COLUMN_STEP 3
(void)pUnused;
(void)argcUnused;
(void)argvUnused;
(void)pzErrUnused;
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
if( rc==SQLITE_OK ){
@@ -142,8 +146,9 @@ static int seriesDisconnect(sqlite3_vtab *pVtab){
/*
** Constructor for a new series_cursor object.
*/
static int seriesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){
series_cursor *pCur;
(void)pUnused;
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
@@ -250,11 +255,12 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
*/
static int seriesFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int idxNum, const char *idxStrUnused,
int argc, sqlite3_value **argv
){
series_cursor *pCur = (series_cursor *)pVtabCursor;
int i = 0;
(void)idxStrUnused;
if( idxNum & 1 ){
pCur->mnValue = sqlite3_value_int64(argv[i++]);
}else{
@@ -311,7 +317,7 @@ static int seriesFilter(
** (8) output in descending order
*/
static int seriesBestIndex(
sqlite3_vtab *tab,
sqlite3_vtab *tabUnused,
sqlite3_index_info *pIdxInfo
){
int i, j; /* Loop over constraints */
@@ -325,6 +331,7 @@ static int seriesBestIndex(
** are the last three columns in the virtual table. */
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
(void)tabUnused;
aIdx[0] = aIdx[1] = aIdx[2] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
@@ -398,6 +405,10 @@ static sqlite3_module seriesModule = {
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
0 /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+5 -3
View File
@@ -621,9 +621,11 @@ static void sha3QueryFunc(
}
nCol = sqlite3_column_count(pStmt);
z = sqlite3_sql(pStmt);
n = (int)strlen(z);
hash_step_vformat(&cx,"S%d:",n);
SHA3Update(&cx,(unsigned char*)z,n);
if( z ){
n = (int)strlen(z);
hash_step_vformat(&cx,"S%d:",n);
SHA3Update(&cx,(unsigned char*)z,n);
}
/* Compute a hash over the result of the query */
while( SQLITE_ROW==sqlite3_step(pStmt) ){
+9 -7
View File
@@ -523,14 +523,16 @@ static int zipfileAppendData(
const u8 *aWrite,
int nWrite
){
size_t n;
fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
if( (int)n!=nWrite ){
pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
return SQLITE_ERROR;
if( nWrite>0 ){
size_t n = nWrite;
fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
if( (int)n!=nWrite ){
pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
return SQLITE_ERROR;
}
pTab->szCurrent += nWrite;
}
pTab->szCurrent += nWrite;
return SQLITE_OK;
}
+1 -1
View File
@@ -1075,7 +1075,7 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){
geopolyAddSegments(p, p1, 1);
geopolyAddSegments(p, p2, 2);
pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent);
rX = pThisEvent->x==0.0 ? -1.0 : 0.0;
rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0;
memset(aOverlap, 0, sizeof(aOverlap));
while( pThisEvent ){
if( pThisEvent->x!=rX ){
+1 -1
View File
@@ -759,7 +759,7 @@ static int nodeAcquire(
** are the leaves, and so on. If the depth as specified on the root node
** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt.
*/
if( pNode && iNode==1 ){
if( pNode && rc==SQLITE_OK && iNode==1 ){
pRtree->iDepth = readInt16(pNode->zData);
if( pRtree->iDepth>RTREE_MAX_DEPTH ){
rc = SQLITE_CORRUPT_VTAB;
+7 -2
View File
@@ -2956,8 +2956,13 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
}
p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
p->abPK = (u8*)&p->apValue[p->nCol*2];
p->zTab = (char*)&p->abPK[p->nCol];
if( p->apValue==0 ){
p->abPK = 0;
p->zTab = 0;
}else{
p->abPK = (u8*)&p->apValue[p->nCol*2];
p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0;
}
return (p->rc = rc);
}
+3 -3
View File
@@ -227,7 +227,7 @@ static int SQLITE_TCLAPI test_session_cmd(
){
TestSession *p = (TestSession*)clientData;
sqlite3_session *pSession = p->pSession;
struct SessionSubcmd {
static struct SessionSubcmd {
const char *zSub;
int nArg;
const char *zMsg;
@@ -1131,7 +1131,7 @@ static int SQLITE_TCLAPI test_rebaser_cmd(
int objc,
Tcl_Obj *CONST objv[]
){
struct RebaseSubcmd {
static struct RebaseSubcmd {
const char *zSub;
int nArg;
const char *zMsg;
@@ -1248,7 +1248,7 @@ static int SQLITE_TCLAPI test_sqlite3session_config(
int objc,
Tcl_Obj *CONST objv[]
){
struct ConfigOpt {
static struct ConfigOpt {
const char *zSub;
int op;
} aSub[] = {
+2
View File
@@ -361,6 +361,7 @@ TESTSRC = \
TESTSRC += \
$(TOP)/ext/misc/amatch.c \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/cksumvfs.c \
$(TOP)/ext/misc/closure.c \
$(TOP)/ext/misc/csv.c \
$(TOP)/ext/misc/decimal.c \
@@ -912,6 +913,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
$(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
+1895 -12
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
af07d8458ae5e2933134b706f80f9538f011970221904bf9f50ed6e47d306e14
10e20c0b43500cfb9bbc0eaa061c57514f715d87238f4d835880cd846b9ebd1f
+20 -6
View File
@@ -1194,15 +1194,23 @@ static int renameResolveTrigger(Parse *pParse){
SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
if( pSrc ){
int i;
for(i=0; i<pSrc->nSrc; i++){
for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
struct SrcList_item *p = &pSrc->a[i];
p->pTab = sqlite3LocateTableItem(pParse, 0, p);
p->iCursor = pParse->nTab++;
if( p->pTab==0 ){
rc = SQLITE_ERROR;
if( p->pSelect ){
sqlite3SelectPrep(pParse, p->pSelect, 0);
sqlite3ExpandSubquery(pParse, p);
assert( i>0 );
assert( pStep->pFrom->a[i-1].pSelect );
sqlite3SelectPrep(pParse, pStep->pFrom->a[i-1].pSelect, 0);
}else{
p->pTab->nTabRef++;
rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
p->pTab = sqlite3LocateTableItem(pParse, 0, p);
if( p->pTab==0 ){
rc = SQLITE_ERROR;
}else{
p->pTab->nTabRef++;
rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
}
}
}
sNC.pSrcList = pSrc;
@@ -1264,6 +1272,12 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
}
if( pStep->pFrom ){
int i;
for(i=0; i<pStep->pFrom->nSrc; i++){
sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
}
}
}
}
+1
View File
@@ -1772,6 +1772,7 @@ static int loadStatTbl(
}
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
pIdx->pTable->tabFlags |= TF_HasStat4;
for(i=0; i<nSample; i++){
pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
+3 -1
View File
@@ -293,7 +293,9 @@ static void detachFunc(
sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
goto detach_error;
}
if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
if( sqlite3BtreeTxnState(pDb->pBt)!=SQLITE_TXN_NONE
|| sqlite3BtreeIsInBackup(pDb->pBt)
){
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
goto detach_error;
}
+4 -4
View File
@@ -123,7 +123,7 @@ static int setDestPgsz(sqlite3_backup *p){
** message in database handle db.
*/
static int checkReadTransaction(sqlite3 *db, Btree *p){
if( sqlite3BtreeIsInReadTrans(p) ){
if( sqlite3BtreeTxnState(p)!=SQLITE_TXN_NONE ){
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use");
return SQLITE_ERROR;
}
@@ -354,7 +354,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
** one now. If a transaction is opened here, then it will be closed
** before this function exits.
*/
if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){
if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){
rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0);
bCloseTrans = 1;
}
@@ -726,7 +726,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
sqlite3BtreeEnter(pTo);
sqlite3BtreeEnter(pFrom);
assert( sqlite3BtreeIsInTrans(pTo) );
assert( sqlite3BtreeTxnState(pTo)==SQLITE_TXN_WRITE );
pFd = sqlite3PagerFile(sqlite3BtreePager(pTo));
if( pFd->pMethods ){
i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom);
@@ -762,7 +762,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
}
assert( sqlite3BtreeIsInTrans(pTo)==0 );
assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE );
copy_finished:
sqlite3BtreeLeave(pFrom);
sqlite3BtreeLeave(pTo);
+23 -13
View File
@@ -112,6 +112,17 @@ int sqlite3_enable_shared_cache(int enable){
#define hasReadConflicts(a, b) 0
#endif
#ifdef SQLITE_DEBUG
/*
** Return and reset the seek counter for a Btree object.
*/
sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){
u64 n = pBt->nSeek;
pBt->nSeek = 0;
return n;
}
#endif
/*
** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single
** (MemPage*) as an argument. The (MemPage*) must not be NULL.
@@ -2605,7 +2616,7 @@ btree_open_out:
** do not change the pager-cache size.
*/
if( sqlite3BtreeSchema(p, 0, 0)==0 ){
sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
sqlite3BtreeSetCacheSize(p, SQLITE_DEFAULT_CACHE_SIZE);
}
pFile = sqlite3PagerFile(pBt->pPager);
@@ -5459,6 +5470,10 @@ int sqlite3BtreeMovetoUnpacked(
}
}
#ifdef SQLITE_DEBUG
pCur->pBtree->nSeek++; /* Performance measurement during testing */
#endif
if( pIdxKey ){
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
pIdxKey->errCode = 0;
@@ -5735,7 +5750,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
pPage = pCur->pPage;
idx = ++pCur->ix;
if( !pPage->isInit ){
if( !pPage->isInit || sqlite3FaultSim(412) ){
/* The only known way for this to happen is for there to be a
** recursive SQL function that does a DELETE operation as part of a
** SELECT which deletes content out from under an active cursor
@@ -10262,8 +10277,8 @@ char *sqlite3BtreeIntegrityCheck(
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
}
}
#endif
}
}
/* Clean up and report errors.
@@ -10310,11 +10325,12 @@ const char *sqlite3BtreeGetJournalname(Btree *p){
}
/*
** Return non-zero if a transaction is active.
** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE
** to describe the current transaction state of Btree p.
*/
int sqlite3BtreeIsInTrans(Btree *p){
int sqlite3BtreeTxnState(Btree *p){
assert( p==0 || sqlite3_mutex_held(p->db->mutex) );
return (p && (p->inTrans==TRANS_WRITE));
return p ? p->inTrans : 0;
}
#ifndef SQLITE_OMIT_WAL
@@ -10343,14 +10359,8 @@ int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){
#endif
/*
** Return non-zero if a read (or write) transaction is active.
** Return true if there is currently a backup running on Btree p.
*/
int sqlite3BtreeIsInReadTrans(Btree *p){
assert( p );
assert( sqlite3_mutex_held(p->db->mutex) );
return p->inTrans!=TRANS_NONE;
}
int sqlite3BtreeIsInBackup(Btree *p){
assert( p );
assert( sqlite3_mutex_held(p->db->mutex) );
+16 -2
View File
@@ -85,16 +85,24 @@ int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*,int,int);
int sqlite3BtreeBeginStmt(Btree*,int);
int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeTxnState(Btree*);
int sqlite3BtreeIsInBackup(Btree*);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *pBtree);
#ifndef SQLITE_OMIT_SHARED_CACHE
int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock);
#endif
/* Savepoints are named, nestable SQL transactions mostly implemented */
/* in vdbe.c and pager.c See https://sqlite.org/lang_savepoint.html */
int sqlite3BtreeSavepoint(Btree *, int, int);
/* "Checkpoint" only refers to WAL. See https://sqlite.org/wal.html#ckpt */
#ifndef SQLITE_OMIT_WAL
int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
#endif
const char *sqlite3BtreeGetFilename(Btree *);
const char *sqlite3BtreeGetJournalname(Btree *);
int sqlite3BtreeCopyFile(Btree *, Btree *);
@@ -331,6 +339,12 @@ int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
int sqlite3BtreeIsReadonly(Btree *pBt);
int sqlite3HeaderSizeBtree(void);
#ifdef SQLITE_DEBUG
sqlite3_uint64 sqlite3BtreeSeekCount(Btree*);
#else
# define sqlite3BtreeSeekCount(X) 0
#endif
#ifndef NDEBUG
int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
+17
View File
@@ -353,6 +353,9 @@ struct Btree {
u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
Btree *pNext; /* List of other sharable Btrees from the same db */
Btree *pPrev; /* Back pointer of the same list */
#ifdef SQLITE_DEBUG
u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
BtLock lock; /* Object used to lock page 1 */
#endif
@@ -364,11 +367,25 @@ struct Btree {
** If the shared-data extension is enabled, there may be multiple users
** of the Btree structure. At most one of these may open a write transaction,
** but any number may have active read transactions.
**
** These values must match SQLITE_TXN_NONE, SQLITE_TXN_READ, and
** SQLITE_TXN_WRITE
*/
#define TRANS_NONE 0
#define TRANS_READ 1
#define TRANS_WRITE 2
#if TRANS_NONE!=SQLITE_TXN_NONE
# error wrong numeric code for no-transaction
#endif
#if TRANS_READ!=SQLITE_TXN_READ
# error wrong numeric code for read-transaction
#endif
#if TRANS_WRITE!=SQLITE_TXN_WRITE
# error wrong numeric code for write-transaction
#endif
/*
** An instance of this object represents a single database file.
**
+49 -29
View File
@@ -53,7 +53,7 @@ void sqlite3TableLock(
u8 isWriteLock, /* True for a write lock */
const char *zName /* Name of the table to be locked */
){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
Parse *pToplevel;
int i;
int nBytes;
TableLock *p;
@@ -61,6 +61,7 @@ void sqlite3TableLock(
if( iDb==1 ) return;
if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return;
pToplevel = sqlite3ParseToplevel(pParse);
for(i=0; i<pToplevel->nTableLock; i++){
p = &pToplevel->aTableLock[i];
if( p->iDb==iDb && p->iTab==iTab ){
@@ -90,10 +91,8 @@ void sqlite3TableLock(
*/
static void codeTableLocks(Parse *pParse){
int i;
Vdbe *pVdbe;
pVdbe = sqlite3GetVdbe(pParse);
assert( pVdbe!=0 ); /* sqlite3GetVdbe cannot fail: VDBE already allocated */
Vdbe *pVdbe = pParse->pVdbe;
assert( pVdbe!=0 );
for(i=0; i<pParse->nTableLock; i++){
TableLock *p = &pParse->aTableLock[i];
@@ -1618,8 +1617,10 @@ primary_key_exit:
** Add a new CHECK constraint to the table currently under construction.
*/
void sqlite3AddCheckConstraint(
Parse *pParse, /* Parsing context */
Expr *pCheckExpr /* The check expression */
Parse *pParse, /* Parsing context */
Expr *pCheckExpr, /* The check expression */
const char *zStart, /* Opening "(" */
const char *zEnd /* Closing ")" */
){
#ifndef SQLITE_OMIT_CHECK
Table *pTab = pParse->pNewTable;
@@ -1630,6 +1631,13 @@ void sqlite3AddCheckConstraint(
pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
if( pParse->constraintName.n ){
sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
}else{
Token t;
for(zStart++; sqlite3Isspace(zStart[0]); zStart++){}
while( sqlite3Isspace(zEnd[-1]) ){ zEnd--; }
t.z = zStart;
t.n = (int)(zEnd - t.z);
sqlite3ExprListSetName(pParse, pTab->pCheck, &t, 1);
}
}else
#endif
@@ -1648,7 +1656,7 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){
char *zColl; /* Dequoted name of collation sequence */
sqlite3 *db;
if( (p = pParse->pNewTable)==0 ) return;
if( (p = pParse->pNewTable)==0 || IN_RENAME_OBJECT ) return;
i = p->nCol-1;
db = pParse->db;
zColl = sqlite3NameFromToken(db, pToken);
@@ -1883,12 +1891,15 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
int nByte;
if( pIdx->nColumn>=N ) return SQLITE_OK;
assert( pIdx->isResized==0 );
nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N;
zExtra = sqlite3DbMallocZero(db, nByte);
if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
pIdx->azColl = (const char**)zExtra;
zExtra += sizeof(char*)*N;
memcpy(zExtra, pIdx->aiRowLogEst, sizeof(LogEst)*(pIdx->nKeyCol+1));
pIdx->aiRowLogEst = (LogEst*)zExtra;
zExtra += sizeof(LogEst)*N;
memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn);
pIdx->aiColumn = (i16*)zExtra;
zExtra += sizeof(i16)*N;
@@ -2703,10 +2714,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable->pSelect );
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
#ifndef SQLITE_OMIT_ALTERTABLE
u8 eParseMode = pParse->eParseMode;
pParse->eParseMode = PARSE_MODE_NORMAL;
#endif
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
@@ -2754,9 +2763,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
sqlite3DeleteTable(db, pSelTab);
sqlite3SelectDelete(db, pSel);
EnableLookaside;
#ifndef SQLITE_OMIT_ALTERTABLE
pParse->eParseMode = eParseMode;
#endif
} else {
nErr++;
}
@@ -4094,7 +4101,7 @@ void sqlite3DefaultRowEst(Index *pIdx){
** table but other parts we are having to guess at, then do not let the
** estimated number of rows in the table be less than 1000 (LogEst 99).
** Failure to do this can cause the indexes for which we do not have
** stat1 data to be ignored by the query planner. tag-20200527-1
** stat1 data to be ignored by the query planner.
*/
x = pIdx->pTable->nRowLogEst;
assert( 99==sqlite3LogEst(1000) );
@@ -4453,7 +4460,7 @@ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
assert(pList || pParse->db->mallocFailed );
if( pList ){
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->iCursor>=0 ) break;
if( pItem->iCursor>=0 ) continue;
pItem->iCursor = pParse->nTab++;
if( pItem->pSelect ){
sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
@@ -4470,15 +4477,15 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
struct SrcList_item *pItem;
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
sqlite3DbFree(db, pItem->zDatabase);
if( pItem->zDatabase ) sqlite3DbFreeNN(db, pItem->zDatabase);
sqlite3DbFree(db, pItem->zName);
sqlite3DbFree(db, pItem->zAlias);
if( pItem->zAlias ) sqlite3DbFreeNN(db, pItem->zAlias);
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
sqlite3DeleteTable(db, pItem->pTab);
sqlite3SelectDelete(db, pItem->pSelect);
sqlite3ExprDelete(db, pItem->pOn);
sqlite3IdListDelete(db, pItem->pUsing);
if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
if( pItem->pOn ) sqlite3ExprDelete(db, pItem->pOn);
if( pItem->pUsing ) sqlite3IdListDelete(db, pItem->pUsing);
}
sqlite3DbFreeNN(db, pList);
}
@@ -4650,7 +4657,16 @@ void sqlite3BeginTransaction(Parse *pParse, int type){
if( !v ) return;
if( type!=TK_DEFERRED ){
for(i=0; i<db->nDb; i++){
sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
int eTxnType;
Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeIsReadonly(pBt) ){
eTxnType = 0; /* Read txn */
}else if( type==TK_EXCLUSIVE ){
eTxnType = 2; /* Exclusive txn */
}else{
eTxnType = 1; /* Write txn */
}
sqlite3VdbeAddOp2(v, OP_Transaction, i, eTxnType);
sqlite3VdbeUsesBtree(v, i);
}
}
@@ -4739,13 +4755,11 @@ int sqlite3OpenTempDatabase(Parse *pParse){
** will occur at the end of the top-level VDBE and will be generated
** later, by sqlite3FinishCoding().
*/
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
assert( iDb>=0 && iDb<pParse->db->nDb );
assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 );
static void sqlite3CodeVerifySchemaAtToplevel(Parse *pToplevel, int iDb){
assert( iDb>=0 && iDb<pToplevel->db->nDb );
assert( pToplevel->db->aDb[iDb].pBt!=0 || iDb==1 );
assert( iDb<SQLITE_MAX_ATTACHED+2 );
assert( sqlite3SchemaMutexHeld(pParse->db, iDb, 0) );
assert( sqlite3SchemaMutexHeld(pToplevel->db, iDb, 0) );
if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
DbMaskSet(pToplevel->cookieMask, iDb);
if( !OMIT_TEMPDB && iDb==1 ){
@@ -4753,6 +4767,10 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
}
}
}
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
sqlite3CodeVerifySchemaAtToplevel(sqlite3ParseToplevel(pParse), iDb);
}
/*
** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each
@@ -4784,7 +4802,7 @@ void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){
*/
void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3CodeVerifySchemaAtToplevel(pToplevel, iDb);
DbMaskSet(pToplevel->writeMask, iDb);
pToplevel->isMultiWrite |= setStatement;
}
@@ -4835,7 +4853,9 @@ void sqlite3HaltConstraint(
i8 p4type, /* P4_STATIC or P4_TRANSIENT */
u8 p5Errmsg /* P5_ErrMsg type */
){
Vdbe *v = sqlite3GetVdbe(pParse);
Vdbe *v;
assert( pParse->pVdbe!=0 );
v = sqlite3GetVdbe(pParse);
assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested );
if( onError==OE_Abort ){
sqlite3MayAbort(pParse);
+5 -12
View File
@@ -425,7 +425,7 @@ void sqlite3DeleteFrom(
}else
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
{
u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE;
u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
if( HasRowid(pTab) ){
@@ -461,6 +461,9 @@ void sqlite3DeleteFrom(
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse);
if( sqlite3WhereUsesDeferredSeek(pWInfo) ){
sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur);
}
/* Keep track of the number of rows to be deleted */
if( memCnt ){
@@ -495,6 +498,7 @@ void sqlite3DeleteFrom(
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen);
addrBypass = sqlite3VdbeMakeLabel(pParse);
}else{
if( pPk ){
/* Add the PK key for this row to the temporary table */
@@ -508,13 +512,6 @@ void sqlite3DeleteFrom(
nKey = 1; /* OP_DeferredSeek always uses a single rowid */
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
}
}
/* If this DELETE cannot use the ONEPASS strategy, this is the
** end of the WHERE loop */
if( eOnePass!=ONEPASS_OFF ){
addrBypass = sqlite3VdbeMakeLabel(pParse);
}else{
sqlite3WhereEnd(pWInfo);
}
@@ -945,10 +942,6 @@ int sqlite3GenerateIndexKey(
}
if( regOut ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
if( pIdx->pTable->pSelect ){
const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx);
sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT);
}
}
sqlite3ReleaseTempRange(pParse, regBase, nCol);
return regBase;
+18 -11
View File
@@ -44,8 +44,10 @@ char sqlite3TableColumnAffinity(Table *pTab, int iCol){
*/
char sqlite3ExprAffinity(const Expr *pExpr){
int op;
while( ExprHasProperty(pExpr, EP_Skip) ){
assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW );
while( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){
assert( pExpr->op==TK_COLLATE
|| pExpr->op==TK_IF_NULL_ROW
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) );
pExpr = pExpr->pLeft;
assert( pExpr!=0 );
}
@@ -115,7 +117,7 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
*/
Expr *sqlite3ExprSkipCollate(Expr *pExpr){
while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){
assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW );
assert( pExpr->op==TK_COLLATE );
pExpr = pExpr->pLeft;
}
return pExpr;
@@ -134,7 +136,7 @@ Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
assert( pExpr->op==TK_FUNCTION );
pExpr = pExpr->x.pList->a[0].pExpr;
}else{
assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW );
assert( pExpr->op==TK_COLLATE );
pExpr = pExpr->pLeft;
}
}
@@ -768,6 +770,7 @@ int sqlite3SelectExprHeight(Select *p){
** Expr.flags.
*/
void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
if( pParse->nErr ) return;
if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){
p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
}
@@ -2029,7 +2032,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
if( sqlite3ExprIdToTrueFalse(pExpr) ){
return WRC_Prune;
}
/* Fall thru */
/* no break */ deliberate_fall_through
case TK_COLUMN:
case TK_AGG_FUNCTION:
case TK_AGG_COLUMN:
@@ -2043,7 +2046,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
return WRC_Continue;
}
/* Fall through */
/* no break */ deliberate_fall_through
case TK_IF_NULL_ROW:
case TK_REGISTER:
case TK_DOT:
@@ -2064,7 +2067,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
pWalker->eCode = 0;
return WRC_Abort;
}
/* Fall through */
/* no break */ deliberate_fall_through
default:
testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */
testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */
@@ -3620,6 +3623,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
*/
static void exprToRegister(Expr *pExpr, int iReg){
Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
if( NEVER(p==0) ) return;
p->op2 = p->op;
p->op = TK_REGISTER;
p->iTable = iReg;
@@ -3836,6 +3840,7 @@ expr_code_doover:
return target;
}
/* Otherwise, fall thru into the TK_COLUMN case */
/* no break */ deliberate_fall_through
}
case TK_COLUMN: {
int iTab = pExpr->iTable;
@@ -4606,6 +4611,7 @@ int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
int r2;
pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
if( ConstFactorOk(pParse)
&& ALWAYS(pExpr!=0)
&& pExpr->op!=TK_REGISTER
&& sqlite3ExprIsConstantNotJoin(pExpr)
){
@@ -4901,7 +4907,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
testcase( op==TK_ISNOT );
op = (op==TK_IS) ? TK_EQ : TK_NE;
jumpIfNull = SQLITE_NULLEQ;
/* Fall thru */
/* no break */ deliberate_fall_through
case TK_LT:
case TK_LE:
case TK_GT:
@@ -5077,7 +5083,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
testcase( pExpr->op==TK_ISNOT );
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
jumpIfNull = SQLITE_NULLEQ;
/* Fall thru */
/* no break */ deliberate_fall_through
case TK_LT:
case TK_LE:
case TK_GT:
@@ -5389,13 +5395,13 @@ static int exprImpliesNotNull(
case TK_RSHIFT:
case TK_CONCAT:
seenNot = 1;
/* Fall thru */
/* no break */ deliberate_fall_through
case TK_STAR:
case TK_REM:
case TK_BITAND:
case TK_SLASH: {
if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
/* Fall thru into the next case */
/* no break */ deliberate_fall_through
}
case TK_SPAN:
case TK_COLLATE:
@@ -5544,6 +5550,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
){
return WRC_Prune;
}
/* no break */ deliberate_fall_through
}
default:
return WRC_Continue;
+1
View File
@@ -1359,6 +1359,7 @@ static Trigger *fkActionTrigger(
pStep->op = TK_DELETE;
break;
}
/* no break */ deliberate_fall_through
default:
pStep->op = TK_UPDATE;
}
+2
View File
@@ -1995,6 +1995,8 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(substring, 2, 0, 0, substrFunc ),
FUNCTION(substring, 3, 0, 0, substrFunc ),
WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
+1 -1
View File
@@ -303,7 +303,7 @@ int sqlite3PendingByte = 0x40000000;
/*
** Flags for select tracing and the ".selecttrace" macro of the CLI
*/
/**/ u32 sqlite3SelectTrace = 0;
u32 sqlite3_unsupported_selecttrace = 0;
#include "opcodes.h"
/*
+10 -9
View File
@@ -32,7 +32,8 @@ void sqlite3OpenTable(
){
Vdbe *v;
assert( !IsVirtual(pTab) );
v = sqlite3GetVdbe(pParse);
assert( pParse->pVdbe!=0 );
v = pParse->pVdbe;
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(pParse, iDb, pTab->tnum,
(opcode==OP_OpenWrite)?1:0, pTab->zName);
@@ -1531,7 +1532,7 @@ void sqlite3GenerateConstraintChecks(
isUpdate = regOldData!=0;
db = pParse->db;
v = sqlite3GetVdbe(pParse);
v = pParse->pVdbe;
assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
nCol = pTab->nCol;
@@ -1612,7 +1613,7 @@ void sqlite3GenerateConstraintChecks(
}
case OE_Abort:
sqlite3MayAbort(pParse);
/* Fall through */
/* no break */ deliberate_fall_through
case OE_Rollback:
case OE_Fail: {
char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
@@ -1685,7 +1686,7 @@ void sqlite3GenerateConstraintChecks(
sqlite3VdbeGoto(v, ignoreDest);
}else{
char *zName = pCheck->a[i].zEName;
if( zName==0 ) zName = pTab->zName;
assert( zName!=0 || pParse->db->mallocFailed );
if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
onError, zName, P4_TRANSIENT,
@@ -1840,7 +1841,7 @@ void sqlite3GenerateConstraintChecks(
switch( onError ){
default: {
onError = OE_Abort;
/* Fall thru into the next case */
/* no break */ deliberate_fall_through
}
case OE_Rollback:
case OE_Abort:
@@ -1901,7 +1902,7 @@ void sqlite3GenerateConstraintChecks(
#ifndef SQLITE_OMIT_UPSERT
case OE_Update: {
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
/* Fall through */
/* no break */ deliberate_fall_through
}
#endif
case OE_Ignore: {
@@ -2122,7 +2123,7 @@ void sqlite3GenerateConstraintChecks(
#ifndef SQLITE_OMIT_UPSERT
case OE_Update: {
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
/* Fall through */
/* no break */ deliberate_fall_through
}
#endif
case OE_Ignore: {
@@ -2304,7 +2305,7 @@ void sqlite3CompleteInsertion(
|| update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION)
);
v = sqlite3GetVdbe(pParse);
v = pParse->pVdbe;
assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
@@ -2405,7 +2406,7 @@ int sqlite3OpenTableAndIndices(
return 0;
}
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
v = sqlite3GetVdbe(pParse);
v = pParse->pVdbe;
assert( v!=0 );
if( iBase<0 ) iBase = pParse->nTab;
iDataCur = iBase++;
+2
View File
@@ -478,6 +478,8 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_create_filename,
sqlite3_free_filename,
sqlite3_database_file_object,
/* Version 3.34.0 and later */
sqlite3_txn_state,
};
/* True if x is the directory separator character
+61 -10
View File
@@ -897,7 +897,7 @@ int sqlite3_db_cacheflush(sqlite3 *db){
sqlite3BtreeEnterAll(db);
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeIsInTrans(pBt) ){
if( pBt && sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){
Pager *pPager = sqlite3BtreePager(pBt);
rc = sqlite3PagerFlush(pPager);
if( rc==SQLITE_BUSY ){
@@ -1202,7 +1202,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
}
sqlite3_mutex_enter(db->mutex);
if( db->mTrace & SQLITE_TRACE_CLOSE ){
db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
}
/* Force xDisconnect calls on all virtual tables */
@@ -1241,6 +1241,36 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
return SQLITE_OK;
}
/*
** Return the transaction state for a single databse, or the maximum
** transaction state over all attached databases if zSchema is null.
*/
int sqlite3_txn_state(sqlite3 *db, const char *zSchema){
int iDb, nDb;
int iTxn = -1;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return -1;
}
#endif
sqlite3_mutex_enter(db->mutex);
if( zSchema ){
nDb = iDb = sqlite3FindDbName(db, zSchema);
if( iDb<0 ) nDb--;
}else{
iDb = 0;
nDb = db->nDb-1;
}
for(; iDb<=nDb; iDb++){
Btree *pBt = db->aDb[iDb].pBt;
int x = pBt!=0 ? sqlite3BtreeTxnState(pBt) : SQLITE_TXN_NONE;
if( x>iTxn ) iTxn = x;
}
sqlite3_mutex_leave(db->mutex);
return iTxn;
}
/*
** Two variations on the public interface for closing a database
** connection. The sqlite3_close() version returns SQLITE_BUSY and
@@ -1401,7 +1431,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
if( p ){
if( sqlite3BtreeIsInTrans(p) ){
if( sqlite3BtreeTxnState(p)==SQLITE_TXN_WRITE ){
inTrans = 1;
}
sqlite3BtreeRollback(p, tripCode, !schemaChange);
@@ -2091,7 +2121,7 @@ void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
db->trace.xLegacy = xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return pOld;
@@ -2115,7 +2145,7 @@ int sqlite3_trace_v2(
if( mTrace==0 ) xTrace = 0;
if( xTrace==0 ) mTrace = 0;
db->mTrace = mTrace;
db->xTrace = xTrace;
db->trace.xV2 = xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
@@ -3822,7 +3852,9 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
}
rc = SQLITE_OK;
}else{
int nSave = db->busyHandler.nBusy;
rc = sqlite3OsFileControl(fd, op, pArg);
db->busyHandler.nBusy = nSave;
}
sqlite3BtreeLeave(pBtree);
}
@@ -4095,7 +4127,7 @@ int sqlite3_test_control(int op, ...){
** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the
** verification of rootpage numbers when parsing the schema. This
** is useful to make it easier to reach strange internal error states
** during testing. The EXTRA_SCHEMA_CHECKS settting is always enabled
** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled
** in production.
*/
case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
@@ -4205,6 +4237,25 @@ int sqlite3_test_control(int op, ...){
sqlite3ResultIntReal(pCtx);
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_SEEK_COUNT,
** sqlite3 *db, // Database connection
** u64 *pnSeek // Write seek count here
** );
**
** This test-control queries the seek-counter on the "main" database
** file. The seek-counter is written into *pnSeek and is then reset.
** The seek-count is only available if compiled with SQLITE_DEBUG.
*/
case SQLITE_TESTCTRL_SEEK_COUNT: {
sqlite3 *db = va_arg(ap, sqlite3*);
u64 *pn = va_arg(ap, sqlite3_uint64*);
*pn = sqlite3BtreeSeekCount(db->aDb->pBt);
(void)db; /* Silence harmless unused variable warning */
break;
}
}
va_end(ap);
#endif /* SQLITE_UNTESTABLE */
@@ -4440,7 +4491,7 @@ int sqlite3_snapshot_get(
int iDb = sqlite3FindDbName(db, zDb);
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( 0==sqlite3BtreeIsInTrans(pBt) ){
if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
@@ -4476,10 +4527,10 @@ int sqlite3_snapshot_open(
iDb = sqlite3FindDbName(db, zDb);
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( sqlite3BtreeIsInTrans(pBt)==0 ){
if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ){
Pager *pPager = sqlite3BtreePager(pBt);
int bUnlock = 0;
if( sqlite3BtreeIsInReadTrans(pBt) ){
if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_NONE ){
if( db->nVdbeActive==0 ){
rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot);
if( rc==SQLITE_OK ){
@@ -4528,7 +4579,7 @@ int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
iDb = sqlite3FindDbName(db, zDb);
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
if( SQLITE_TXN_NONE==sqlite3BtreeTxnState(pBt) ){
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
+16 -8
View File
@@ -474,12 +474,17 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
if( nOld==nNew ){
pNew = pOld;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_int64 nUsed;
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
nDiff = nNew - nOld;
if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >=
mem0.alarmThreshold-nDiff ){
sqlite3MallocAlarm(nDiff);
if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){
sqlite3_mutex_leave(mem0.mutex);
return 0;
}
}
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
@@ -786,12 +791,15 @@ void sqlite3OomClear(sqlite3 *db){
}
/*
** Take actions at the end of an API call to indicate an OOM error
** Take actions at the end of an API call to deal with error codes.
*/
static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
sqlite3OomClear(db);
sqlite3Error(db, SQLITE_NOMEM);
return SQLITE_NOMEM_BKPT;
static SQLITE_NOINLINE int apiHandleError(sqlite3 *db, int rc){
if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomClear(db);
sqlite3Error(db, SQLITE_NOMEM);
return SQLITE_NOMEM_BKPT;
}
return rc & db->errMask;
}
/*
@@ -813,8 +821,8 @@ int sqlite3ApiExit(sqlite3* db, int rc){
*/
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
return apiOomError(db);
if( db->mallocFailed || rc ){
return apiHandleError(db, rc);
}
return rc & db->errMask;
}
+15 -4
View File
@@ -126,11 +126,14 @@ static const sqlite3_io_methods memdb_io_methods = {
** Close an memdb-file.
**
** The pData pointer is owned by the application, so there is nothing
** to free.
** to free. Unless the SQLITE_DESERIALIZE_FREEONCLOSE flag is set,
** in which case we own the pData pointer and need to free it.
*/
static int memdbClose(sqlite3_file *pFile){
MemFile *p = (MemFile *)pFile;
if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ) sqlite3_free(p->aData);
if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){
sqlite3_free(p->aData);
}
return SQLITE_OK;
}
@@ -573,8 +576,12 @@ int sqlite3_deserialize(
goto end_deserialize;
}
zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
}
if( rc ) goto end_deserialize;
db->init.iDb = (u8)iDb;
db->init.reopenMemdb = 1;
@@ -589,6 +596,7 @@ int sqlite3_deserialize(
rc = SQLITE_ERROR;
}else{
p->aData = pData;
pData = 0;
p->sz = szDb;
p->szAlloc = szBuf;
p->szMax = szBuf;
@@ -601,6 +609,9 @@ int sqlite3_deserialize(
end_deserialize:
sqlite3_finalize(pStmt);
if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){
sqlite3_free(pData);
}
sqlite3_mutex_leave(db->mutex);
return rc;
}
+165 -56
View File
@@ -122,7 +122,8 @@
# if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
(__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \
&& (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))
&& (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))\
&& (!defined(TARGET_OS_MACCATALYST) || (TARGET_OS_MACCATALYST==0))
# undef HAVE_GETHOSTUUID
# define HAVE_GETHOSTUUID 1
# else
@@ -1544,6 +1545,9 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
return rc;
}
/* Forward declaration*/
static int unixSleep(sqlite3_vfs*,int);
/*
** Set a posix-advisory-lock.
**
@@ -1573,7 +1577,7 @@ static int osSetPosixAdvisoryLock(
** generic posix, however, there is no such API. So we simply try the
** lock once every millisecond until either the timeout expires, or until
** the lock is obtained. */
usleep(1000);
unixSleep(0,1000);
rc = osFcntl(h,F_SETLK,pLock);
tm--;
}
@@ -2144,6 +2148,7 @@ static int unixClose(sqlite3_file *id){
}
sqlite3_mutex_leave(pInode->pLockMutex);
releaseInodeInfo(pFile);
assert( pFile->pShm==0 );
rc = closeUnixFile(id);
unixLeaveMutex();
return rc;
@@ -3370,7 +3375,24 @@ static int unixRead(
if( got==amt ){
return SQLITE_OK;
}else if( got<0 ){
/* lastErrno set by seekAndRead */
/* pFile->lastErrno has been set by seekAndRead().
** Usually we return SQLITE_IOERR_READ here, though for some
** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The
** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT
** prior to returning to the application by the sqlite3ApiExit()
** routine.
*/
switch( pFile->lastErrno ){
case ERANGE:
case EIO:
#ifdef ENXIO
case ENXIO:
#endif
#ifdef EDEVERR
case EDEVERR:
#endif
return SQLITE_IOERR_CORRUPTFS;
}
return SQLITE_IOERR_READ;
}else{
storeLastErrno(pFile, 0); /* not a system error */
@@ -4254,6 +4276,7 @@ struct unixShmNode {
char **apRegion; /* Array of mapped shared-memory regions */
int nRef; /* Number of unixShm objects pointing to this */
unixShm *pFirst; /* All unixShm objects pointing to this */
int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */
#ifdef SQLITE_DEBUG
u8 exclMask; /* Mask of exclusive locks held */
u8 sharedMask; /* Mask of shared locks held */
@@ -4794,6 +4817,38 @@ shmpage_out:
return rc;
}
/*
** Check that the pShmNode->aLock[] array comports with the locking bitmasks
** held by each client. Return true if it does, or false otherwise. This
** is to be used in an assert(). e.g.
**
** assert( assertLockingArrayOk(pShmNode) );
*/
#ifdef SQLITE_DEBUG
static int assertLockingArrayOk(unixShmNode *pShmNode){
unixShm *pX;
int aLock[SQLITE_SHM_NLOCK];
assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
memset(aLock, 0, sizeof(aLock));
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
int i;
for(i=0; i<SQLITE_SHM_NLOCK; i++){
if( pX->exclMask & (1<<i) ){
assert( aLock[i]==0 );
aLock[i] = -1;
}else if( pX->sharedMask & (1<<i) ){
assert( aLock[i]>=0 );
aLock[i]++;
}
}
}
assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) );
return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0);
}
#endif
/*
** Change the lock state for a shared-memory segment.
**
@@ -4810,10 +4865,10 @@ static int unixShmLock(
){
unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */
unixShm *p = pDbFd->pShm; /* The shared memory being locked */
unixShm *pX; /* For looping over all siblings */
unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */
int rc = SQLITE_OK; /* Result code */
u16 mask; /* Mask of locks to take or release */
int *aLock = pShmNode->aLock;
assert( pShmNode==pDbFd->pInode->pShmNode );
assert( pShmNode->pInode==pDbFd->pInode );
@@ -4852,78 +4907,76 @@ static int unixShmLock(
mask = (1<<(ofst+n)) - (1<<ofst);
assert( n>1 || mask==(1<<ofst) );
sqlite3_mutex_enter(pShmNode->pShmMutex);
assert( assertLockingArrayOk(pShmNode) );
if( flags & SQLITE_SHM_UNLOCK ){
u16 allMask = 0; /* Mask of locks held by siblings */
if( (p->exclMask|p->sharedMask) & mask ){
int ii;
int bUnlock = 1;
/* See if any siblings hold this same lock */
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
if( pX==p ) continue;
assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
allMask |= pX->sharedMask;
for(ii=ofst; ii<ofst+n; ii++){
if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
bUnlock = 0;
}
}
if( bUnlock ){
rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
if( rc==SQLITE_OK ){
memset(&aLock[ofst], 0, sizeof(int)*n);
}
}else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
assert( n==1 && aLock[ofst]>1 );
aLock[ofst]--;
}
/* Undo the local locks */
if( rc==SQLITE_OK ){
p->exclMask &= ~mask;
p->sharedMask &= ~mask;
}
}
/* Unlock the system-level locks */
if( (mask & allMask)==0 ){
rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
/* Undo the local locks */
if( rc==SQLITE_OK ){
p->exclMask &= ~mask;
p->sharedMask &= ~mask;
}
}else if( flags & SQLITE_SHM_SHARED ){
u16 allShared = 0; /* Union of locks held by connections other than "p" */
/* Find out which shared locks are already held by sibling connections.
** If any sibling already holds an exclusive lock, go ahead and return
** SQLITE_BUSY.
*/
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
if( (pX->exclMask & mask)!=0 ){
assert( n==1 );
assert( (p->exclMask & (1<<ofst))==0 );
if( (p->sharedMask & mask)==0 ){
if( aLock[ofst]<0 ){
rc = SQLITE_BUSY;
break;
}
allShared |= pX->sharedMask;
}
/* Get shared locks at the system level, if necessary */
if( rc==SQLITE_OK ){
if( (allShared & mask)==0 ){
}else if( aLock[ofst]==0 ){
rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
}
/* Get the local shared locks */
if( rc==SQLITE_OK ){
p->sharedMask |= mask;
/* Get the local shared locks */
if( rc==SQLITE_OK ){
p->sharedMask |= mask;
aLock[ofst]++;
}
}
}else{
/* Make sure no sibling connections hold locks that will block this
** lock. If any do, return SQLITE_BUSY right away.
*/
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
** lock. If any do, return SQLITE_BUSY right away. */
int ii;
for(ii=ofst; ii<ofst+n; ii++){
assert( (p->sharedMask & mask)==0 );
if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
rc = SQLITE_BUSY;
break;
}
}
/* Get the exclusive locks at the system level. Then if successful
** also mark the local connection as being locked.
*/
/* Get the exclusive locks at the system level. Then if successful
** also update the in-memory values. */
if( rc==SQLITE_OK ){
rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
if( rc==SQLITE_OK ){
assert( (p->sharedMask & mask)==0 );
p->exclMask |= mask;
for(ii=ofst; ii<ofst+n; ii++){
aLock[ii] = -1;
}
}
}
}
assert( assertLockingArrayOk(pShmNode) );
sqlite3_mutex_leave(pShmNode->pShmMutex);
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
p->id, osGetpid(0), p->sharedMask, p->exclMask));
@@ -6300,7 +6353,26 @@ static int unixAccess(
}
/*
** If the last component of the pathname in z[0]..z[j-1] is something
** other than ".." then back it out and return true. If the last
** component is empty or if it is ".." then return false.
*/
static int unixBackupDir(const char *z, int *pJ){
int j = *pJ;
int i;
if( j<=0 ) return 0;
for(i=j-1; ALWAYS(i>0) && z[i-1]!='/'; i--){}
if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
*pJ = i-1;
return 1;
}
/*
** Convert a relative pathname into a full pathname. Also
** simplify the pathname as follows:
**
** Remove all instances of /./
** Remove all isntances of /X/../ for any X
*/
static int mkFullPathname(
const char *zPath, /* Input path */
@@ -6309,6 +6381,7 @@ static int mkFullPathname(
){
int nPath = sqlite3Strlen30(zPath);
int iOff = 0;
int i, j;
if( zPath[0]!='/' ){
if( osGetcwd(zOut, nOut-2)==0 ){
return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
@@ -6323,6 +6396,41 @@ static int mkFullPathname(
return SQLITE_CANTOPEN_BKPT;
}
sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
/* Remove duplicate '/' characters. Except, two // at the beginning
** of a pathname is allowed since this is important on windows. */
for(i=j=1; zOut[i]; i++){
zOut[j++] = zOut[i];
while( zOut[i]=='/' && zOut[i+1]=='/' ) i++;
}
zOut[j] = 0;
assert( zOut[0]=='/' );
for(i=j=0; zOut[i]; i++){
if( zOut[i]=='/' ){
/* Skip over internal "/." directory components */
if( zOut[i+1]=='.' && zOut[i+2]=='/' ){
i += 1;
continue;
}
/* If this is a "/.." directory component then back out the
** previous term of the directory if it is something other than "..".
*/
if( zOut[i+1]=='.'
&& zOut[i+2]=='.'
&& zOut[i+3]=='/'
&& unixBackupDir(zOut, &j)
){
i += 2;
continue;
}
}
if( ALWAYS(j>=0) ) zOut[j] = zOut[i];
j++;
}
if( NEVER(j==0) ) zOut[j++] = '/';
zOut[j] = 0;
return SQLITE_OK;
}
@@ -6543,7 +6651,8 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
UNUSED_PARAMETER(NotUsed);
return microseconds;
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
usleep(microseconds);
if( microseconds>=1000000 ) sleep(microseconds/1000000);
if( microseconds%1000000 ) usleep(microseconds%1000000);
UNUSED_PARAMETER(NotUsed);
return microseconds;
#else
@@ -7116,7 +7225,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
if( nTries==1 ){
conchModTime = buf.st_mtimespec;
usleep(500000); /* wait 0.5 sec and try the lock again*/
unixSleep(0,500000); /* wait 0.5 sec and try the lock again*/
continue;
}
@@ -7142,7 +7251,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
/* don't break the lock on short read or a version mismatch */
return SQLITE_BUSY;
}
usleep(10000000); /* wait 10 sec and try the lock again */
unixSleep(0,10000000); /* wait 10 sec and try the lock again */
continue;
}
+5 -1
View File
@@ -5126,7 +5126,11 @@ static int winOpen(
dwCreationDisposition = OPEN_EXISTING;
}
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
if( 0==sqlite3_uri_boolean(zName, "exclusive", 0) ){
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
}else{
dwShareMode = 0;
}
if( isDelete ){
#if SQLITE_OS_WINCE
+15 -5
View File
@@ -2486,18 +2486,20 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
i64 nSuperJournal; /* Size of super-journal file */
char *zJournal; /* Pointer to one journal within MJ file */
char *zSuperPtr; /* Space to hold super-journal filename */
char *zFree = 0; /* Free this buffer */
int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
/* Allocate space for both the pJournal and pSuper file descriptors.
** If successful, open the super-journal file for reading.
*/
pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
if( !pSuper ){
rc = SQLITE_NOMEM_BKPT;
pJournal = 0;
}else{
const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0);
pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
}
if( rc!=SQLITE_OK ) goto delsuper_out;
@@ -2509,11 +2511,13 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
if( rc!=SQLITE_OK ) goto delsuper_out;
nSuperPtr = pVfs->mxPathname+1;
zSuperJournal = sqlite3Malloc(nSuperJournal + nSuperPtr + 2);
if( !zSuperJournal ){
zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2);
if( !zFree ){
rc = SQLITE_NOMEM_BKPT;
goto delsuper_out;
}
zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0;
zSuperJournal = &zFree[4];
zSuperPtr = &zSuperJournal[nSuperJournal+2];
rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0);
if( rc!=SQLITE_OK ) goto delsuper_out;
@@ -2561,7 +2565,7 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
rc = sqlite3OsDelete(pVfs, zSuper, 0);
delsuper_out:
sqlite3_free(zSuperJournal);
sqlite3_free(zFree);
if( pSuper ){
sqlite3OsClose(pSuper);
assert( !isOpen(pJournal) );
@@ -2899,7 +2903,11 @@ end_playback:
pPager->changeCountDone = pPager->tempFile;
if( rc==SQLITE_OK ){
zSuper = pPager->pTmpSpace;
/* Leave 4 bytes of space before the super-journal filename in memory.
** This is because it may end up being passed to sqlite3OsOpen(), in
** which case it requires 4 0x00 bytes in memory immediately before
** the filename. */
zSuper = &pPager->pTmpSpace[4];
rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
testcase( rc!=SQLITE_OK );
}
@@ -2916,6 +2924,8 @@ end_playback:
/* If there was a super-journal and this routine will return success,
** see if it is possible to delete the super-journal.
*/
assert( zSuper==&pPager->pTmpSpace[4] );
memset(&zSuper[-4], 0, 4);
rc = pager_delsuper(pPager, zSuper);
testcase( rc!=SQLITE_OK );
}
+14 -8
View File
@@ -1,5 +1,6 @@
%include {
/*
** 2001 September 15
** 2001-09-15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -9,11 +10,16 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains SQLite's grammar for SQL. Process this file
** using the lemon parser generator to generate C code that runs
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
** This file contains SQLite's SQL parser.
**
** The canonical source code to this file ("parse.y") is a Lemon grammar
** file that specifies the input grammar and actions to take while parsing.
** That input file is processed by Lemon to generate a C-language
** implementation of a parser for the given grammer. You might be reading
** this comment as part of the translated C-code. Edits should be made
** to the original parse.y sources.
*/
}
// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_
@@ -366,7 +372,7 @@ ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
{sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X);}
ccons ::= CHECK LP(A) expr(X) RP(B). {sqlite3AddCheckConstraint(pParse,X,A.z,B.z);}
ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
@@ -420,8 +426,8 @@ tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R).
tcons ::= UNIQUE LP sortlist(X) RP onconf(R).
{sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
tcons ::= CHECK LP expr(E) RP onconf.
{sqlite3AddCheckConstraint(pParse,E);}
tcons ::= CHECK LP(A) expr(E) RP(B) onconf.
{sqlite3AddCheckConstraint(pParse,E,A.z,B.z);}
tcons ::= FOREIGN KEY LP eidlist(FA) RP
REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). {
sqlite3CreateForeignKey(pParse, FA, &T, TA, R);
+5 -3
View File
@@ -131,7 +131,9 @@ static int getTempStore(const char *z){
static int invalidateTempStorage(Parse *pParse){
sqlite3 *db = pParse->db;
if( db->aDb[1].pBt!=0 ){
if( !db->autoCommit || sqlite3BtreeIsInReadTrans(db->aDb[1].pBt) ){
if( !db->autoCommit
|| sqlite3BtreeTxnState(db->aDb[1].pBt)!=SQLITE_TXN_NONE
){
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
"from within a transaction");
return SQLITE_ERROR;
@@ -1451,7 +1453,7 @@ void sqlite3Pragma(
aiCols = 0;
if( pParent ){
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
assert( x==0 );
assert( x==0 || db->mallocFailed );
}
addrOk = sqlite3VdbeMakeLabel(pParse);
@@ -1476,7 +1478,7 @@ void sqlite3Pragma(
int jmp = sqlite3VdbeCurrentAddr(v)+2;
sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v);
sqlite3VdbeGoto(v, addrOk);
assert( pFK->nCol==1 );
assert( pFK->nCol==1 || db->mallocFailed );
}
/* Generate code to report an FK violation to the caller. */
+3 -2
View File
@@ -240,7 +240,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
** on the b-tree database, open one now. If a transaction is opened, it
** will be closed before this function returns. */
sqlite3BtreeEnter(pDb->pBt);
if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){
if( sqlite3BtreeTxnState(pDb->pBt)==SQLITE_TXN_NONE ){
rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0);
if( rc!=SQLITE_OK ){
sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc));
@@ -483,7 +483,7 @@ static void schemaIsValid(Parse *pParse){
/* If there is not already a read-only (or read-write) transaction opened
** on the b-tree database, open one now. If a transaction is opened, it
** will be closed immediately after reading the meta-value. */
if( !sqlite3BtreeIsInReadTrans(pBt) ){
if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_NONE ){
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomFault(db);
@@ -746,6 +746,7 @@ static int sqlite3LockAndPrepare(
sqlite3BtreeLeaveAll(db);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
db->busyHandler.nBusy = 0;
sqlite3_mutex_leave(db->mutex);
return rc;
}
+6 -7
View File
@@ -407,11 +407,11 @@ void sqlite3_str_vappendf(
case etPOINTER:
flag_long = sizeof(char*)==sizeof(i64) ? 2 :
sizeof(char*)==sizeof(long int) ? 1 : 0;
/* Fall through into the next case */
/* no break */ deliberate_fall_through
case etORDINAL:
case etRADIX:
cThousand = 0;
/* Fall through into the next case */
/* no break */ deliberate_fall_through
case etDECIMAL:
if( infop->flags & FLAG_SIGNED ){
i64 v;
@@ -427,11 +427,10 @@ void sqlite3_str_vappendf(
v = va_arg(ap,int);
}
if( v<0 ){
if( v==SMALLEST_INT64 ){
longvalue = ((u64)1)<<63;
}else{
longvalue = -v;
}
testcase( v==SMALLEST_INT64 );
testcase( v==(-1) );
longvalue = ~v;
longvalue++;
prefix = '-';
}else{
longvalue = v;
+4 -2
View File
@@ -1075,7 +1075,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
assert( !ExprHasProperty(pExpr, EP_Reduced) );
/* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
** and "x IS NOT FALSE". */
if( pRight && pRight->op==TK_ID ){
if( pRight && (pRight->op==TK_ID || pRight->op==TK_TRUEFALSE) ){
int rc = resolveExprStep(pWalker, pRight);
if( rc==WRC_Abort ) return WRC_Abort;
if( pRight->op==TK_TRUEFALSE ){
@@ -1084,7 +1084,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
}
/* Fall thru */
/* no break */ deliberate_fall_through
}
case TK_BETWEEN:
case TK_EQ:
@@ -1284,6 +1284,7 @@ static int resolveCompoundOrderBy(
Expr *pE, *pDup;
if( pItem->done ) continue;
pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
if( NEVER(pE==0) ) continue;
if( sqlite3ExprIsInteger(pE, &iCol) ){
if( iCol<=0 || iCol>pEList->nExpr ){
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
@@ -1463,6 +1464,7 @@ static int resolveOrderGroupBy(
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
Expr *pE = pItem->pExpr;
Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE);
if( NEVER(pE2==0) ) continue;
if( zType[0]!='G' ){
iCol = resolveAsName(pParse, pSelect->pEList, pE2);
if( iCol>0 ){
+90 -60
View File
@@ -1972,6 +1972,7 @@ int sqlite3ColumnsFromExprList(
char *zName; /* Column name */
int nName; /* Size of name in zName[] */
Hash ht; /* Hash table of column names */
Table *pTab;
sqlite3HashInit(&ht);
if( pEList ){
@@ -1994,15 +1995,13 @@ int sqlite3ColumnsFromExprList(
/* If the column contains an "AS <name>" phrase, use <name> as the name */
}else{
Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
while( pColExpr->op==TK_DOT ){
while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){
pColExpr = pColExpr->pRight;
assert( pColExpr!=0 );
}
if( pColExpr->op==TK_COLUMN ){
if( pColExpr->op==TK_COLUMN && (pTab = pColExpr->y.pTab)!=0 ){
/* For columns use the column name name */
int iCol = pColExpr->iColumn;
Table *pTab = pColExpr->y.pTab;
assert( pTab!=0 );
if( iCol<0 ) iCol = pTab->iPKey;
zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
}else if( pColExpr->op==TK_ID ){
@@ -2340,6 +2339,7 @@ static void generateWithRecursiveQuery(
int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */
Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */
Select *pSetup = p->pPrior; /* The setup query */
Select *pFirstRec; /* Left-most recursive term */
int addrTop; /* Top of the loop */
int addrCont, addrBreak; /* CONTINUE and BREAK addresses */
int iCurrent = 0; /* The Current table */
@@ -2415,7 +2415,25 @@ static void generateWithRecursiveQuery(
/* Detach the ORDER BY clause from the compound SELECT */
p->pOrderBy = 0;
/* Figure out how many elements of the compound SELECT are part of the
** recursive query. Make sure no recursive elements use aggregate
** functions. Mark the recursive elements as UNION ALL even if they
** are really UNION because the distinctness will be enforced by the
** iDistinct table. pFirstRec is left pointing to the left-most
** recursive term of the CTE.
*/
pFirstRec = p;
for(pFirstRec=p; ALWAYS(pFirstRec!=0); pFirstRec=pFirstRec->pPrior){
if( pFirstRec->selFlags & SF_Aggregate ){
sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
goto end_of_recursive_query;
}
pFirstRec->op = TK_ALL;
if( (pFirstRec->pPrior->selFlags & SF_Recursive)==0 ) break;
}
/* Store the results of the setup-query in Queue. */
pSetup = pFirstRec->pPrior;
pSetup->pNext = 0;
ExplainQueryPlan((pParse, 1, "SETUP"));
rc = sqlite3Select(pParse, pSetup, &destQueue);
@@ -2448,15 +2466,11 @@ static void generateWithRecursiveQuery(
/* Execute the recursive SELECT taking the single row in Current as
** the value for the recursive-table. Store the results in the Queue.
*/
if( p->selFlags & SF_Aggregate ){
sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
}else{
p->pPrior = 0;
ExplainQueryPlan((pParse, 1, "RECURSIVE STEP"));
sqlite3Select(pParse, p, &destQueue);
assert( p->pPrior==0 );
p->pPrior = pSetup;
}
pFirstRec->pPrior = 0;
ExplainQueryPlan((pParse, 1, "RECURSIVE STEP"));
sqlite3Select(pParse, p, &destQueue);
assert( pFirstRec->pPrior==0 );
pFirstRec->pPrior = pSetup;
/* Keep running the loop until the Queue is empty */
sqlite3VdbeGoto(v, addrTop);
@@ -2525,6 +2539,16 @@ static int multiSelectValues(
return rc;
}
/*
** Return true if the SELECT statement which is known to be the recursive
** part of a recursive CTE still has its anchor terms attached. If the
** anchor terms have already been removed, then return false.
*/
static int hasAnchor(Select *p){
while( p && (p->selFlags & SF_Recursive)!=0 ){ p = p->pPrior; }
return p!=0;
}
/*
** This routine is called to process a compound query form from
** two or more separate queries using UNION, UNION ALL, EXCEPT, or
@@ -2610,7 +2634,7 @@ static int multiSelect(
assert( p->pEList->nExpr==pPrior->pEList->nExpr );
#ifndef SQLITE_OMIT_CTE
if( p->selFlags & SF_Recursive ){
if( (p->selFlags & SF_Recursive)!=0 && hasAnchor(p) ){
generateWithRecursiveQuery(pParse, p, &dest);
}else
#endif
@@ -2701,6 +2725,7 @@ static int multiSelect(
findRightmost(p)->selFlags |= SF_UsesEphemeral;
assert( p->pEList );
}
/* Code the SELECT statements to our left
*/
@@ -3506,7 +3531,7 @@ static Expr *substExpr(
ifNullRow.op = TK_IF_NULL_ROW;
ifNullRow.pLeft = pCopy;
ifNullRow.iTable = pSubst->iNewTable;
ifNullRow.flags = EP_Skip;
ifNullRow.flags = EP_IfNullRow;
pCopy = &ifNullRow;
}
testcase( ExprHasProperty(pCopy, EP_Subquery) );
@@ -3515,8 +3540,7 @@ static Expr *substExpr(
ExprSetProperty(pNew, EP_CanBeNull);
}
if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){
pNew->iRightJoinTable = pExpr->iRightJoinTable;
ExprSetProperty(pNew, EP_FromJoin);
sqlite3SetJoinExpr(pNew, pExpr->iRightJoinTable);
}
sqlite3ExprDelete(db, pExpr);
pExpr = pNew;
@@ -4186,7 +4210,7 @@ static int flattenSubquery(
sqlite3SelectDelete(db, pSub1);
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x100 ){
if( sqlite3_unsupported_selecttrace & 0x100 ){
SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -4795,8 +4819,10 @@ static int withExpand(
ExprList *pEList;
Select *pSel;
Select *pLeft; /* Left-most SELECT statement */
Select *pRecTerm; /* Left-most recursive term */
int bMayRecursive; /* True if compound joined by UNION [ALL] */
With *pSavedWith; /* Initial value of pParse->pWith */
int iRecTab = -1; /* Cursor for recursive table */
/* If pCte->zCteErr is non-NULL at this point, then this is an illegal
** recursive reference to CTE pCte. Leave an error in pParse and return
@@ -4821,44 +4847,48 @@ static int withExpand(
assert( pFrom->pSelect );
/* Check if this is a recursive CTE. */
pSel = pFrom->pSelect;
pRecTerm = pSel = pFrom->pSelect;
bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
if( bMayRecursive ){
while( bMayRecursive && pRecTerm->op==pSel->op ){
int i;
SrcList *pSrc = pFrom->pSelect->pSrc;
SrcList *pSrc = pRecTerm->pSrc;
assert( pRecTerm->pPrior!=0 );
for(i=0; i<pSrc->nSrc; i++){
struct SrcList_item *pItem = &pSrc->a[i];
if( pItem->zDatabase==0
&& pItem->zName!=0
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName)
){
){
pItem->pTab = pTab;
pItem->fg.isRecursive = 1;
pTab->nTabRef++;
pSel->selFlags |= SF_Recursive;
pItem->fg.isRecursive = 1;
if( pRecTerm->selFlags & SF_Recursive ){
sqlite3ErrorMsg(pParse,
"multiple references to recursive table: %s", pCte->zName
);
return SQLITE_ERROR;
}
pRecTerm->selFlags |= SF_Recursive;
if( iRecTab<0 ) iRecTab = pParse->nTab++;
pItem->iCursor = iRecTab;
}
}
if( (pRecTerm->selFlags & SF_Recursive)==0 ) break;
pRecTerm = pRecTerm->pPrior;
}
/* Only one recursive reference is permitted. */
if( pTab->nTabRef>2 ){
sqlite3ErrorMsg(
pParse, "multiple references to recursive table: %s", pCte->zName
);
return SQLITE_ERROR;
}
assert( pTab->nTabRef==1 ||
((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
pCte->zCteErr = "circular reference: %s";
pSavedWith = pParse->pWith;
pParse->pWith = pWith;
if( bMayRecursive ){
Select *pPrior = pSel->pPrior;
assert( pPrior->pWith==0 );
pPrior->pWith = pSel->pWith;
sqlite3WalkSelect(pWalker, pPrior);
pPrior->pWith = 0;
if( pSel->selFlags & SF_Recursive ){
assert( pRecTerm!=0 );
assert( (pRecTerm->selFlags & SF_Recursive)==0 );
assert( pRecTerm->pNext!=0 );
assert( (pRecTerm->pNext->selFlags & SF_Recursive)!=0 );
assert( pRecTerm->pWith==0 );
pRecTerm->pWith = pSel->pWith;
sqlite3WalkSelect(pWalker, pRecTerm);
pRecTerm->pWith = 0;
}else{
sqlite3WalkSelect(pWalker, pSel);
}
@@ -5585,7 +5615,9 @@ static void explainSimpleCount(
static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
if( pExpr->op!=TK_AND ){
Select *pS = pWalker->u.pSelect;
if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) ){
if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy)
&& ExprAlwaysFalse(pExpr)==0
){
sqlite3 *db = pWalker->pParse->db;
Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1");
if( pNew ){
@@ -5624,7 +5656,7 @@ static void havingToWhere(Parse *pParse, Select *p){
sWalker.u.pSelect = p;
sqlite3WalkExpr(&sWalker, p->pHaving);
#if SELECTTRACE_ENABLED
if( sWalker.eCode && (sqlite3SelectTrace & 0x100)!=0 ){
if( sWalker.eCode && (sqlite3_unsupported_selecttrace & 0x100)!=0 ){
SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -5746,7 +5778,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
p->selFlags &= ~SF_Aggregate;
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x400 ){
if( sqlite3_unsupported_selecttrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -5799,7 +5831,7 @@ int sqlite3Select(
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
#if SELECTTRACE_ENABLED
SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
if( sqlite3SelectTrace & 0x100 ){
if( sqlite3_unsupported_selecttrace & 0x100 ){
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -5808,13 +5840,11 @@ int sqlite3Select(
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
if( IgnorableOrderby(pDest) ){
assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo ||
pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo);
/* If ORDER BY makes no difference in the output then neither does
** DISTINCT so it can be removed too. */
if( IgnorableDistinct(pDest) ){
assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo );
/* All of these destinations are also able to ignore the ORDER BY clause */
sqlite3ExprListDelete(db, p->pOrderBy);
p->pOrderBy = 0;
p->selFlags &= ~SF_Distinct;
@@ -5826,7 +5856,7 @@ int sqlite3Select(
}
assert( p->pEList!=0 );
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x104 ){
if( sqlite3_unsupported_selecttrace & 0x104 ){
SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -5861,7 +5891,7 @@ int sqlite3Select(
goto select_end;
}
#if SELECTTRACE_ENABLED
if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){
if( p->pWin && (sqlite3_unsupported_selecttrace & 0x108)!=0 ){
SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -5968,7 +5998,7 @@ int sqlite3Select(
rc = multiSelect(pParse, p, pDest);
#if SELECTTRACE_ENABLED
SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -5987,7 +6017,7 @@ int sqlite3Select(
&& propagateConstants(pParse, p)
){
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x100 ){
if( sqlite3_unsupported_selecttrace & 0x100 ){
SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -6075,7 +6105,7 @@ int sqlite3Select(
(pItem->fg.jointype & JT_OUTER)!=0)
){
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x100 ){
if( sqlite3_unsupported_selecttrace & 0x100 ){
SELECTTRACE(0x100,pParse,p,
("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
sqlite3TreeViewSelect(0, p, 0);
@@ -6175,7 +6205,7 @@ int sqlite3Select(
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x400 ){
if( sqlite3_unsupported_selecttrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -6211,7 +6241,7 @@ int sqlite3Select(
assert( sDistinct.isTnct );
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x400 ){
if( sqlite3_unsupported_selecttrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -6459,7 +6489,7 @@ int sqlite3Select(
pAggInfo->mxReg = pParse->nMem;
if( db->mallocFailed ) goto select_end;
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x400 ){
if( sqlite3_unsupported_selecttrace & 0x400 ){
int ii;
SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
sqlite3TreeViewSelect(0, p, 0);
@@ -6878,7 +6908,7 @@ select_end:
#if SELECTTRACE_ENABLED
SELECTTRACE(0x1,pParse,p,("end processing\n"));
if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
sqlite3TreeViewSelect(0, p, 0);
}
#endif
+198 -78
View File
@@ -553,8 +553,6 @@ static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
int i;
int n;
int aw = w<0 ? -w : w;
char zBuf[1000];
if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3;
for(i=n=0; zUtf[i]; i++){
if( (zUtf[i]&0xc0)!=0x80 ){
n++;
@@ -1028,6 +1026,7 @@ INCLUDE ../ext/misc/memtrace.c
INCLUDE ../ext/misc/uint.c
INCLUDE ../ext/misc/decimal.c
INCLUDE ../ext/misc/ieee754.c
INCLUDE ../ext/misc/series.c
#ifdef SQLITE_HAVE_ZLIB
INCLUDE ../ext/misc/zipfile.c
INCLUDE ../ext/misc/sqlar.c
@@ -1185,6 +1184,8 @@ struct ShellState {
#define SHFLG_CountChanges 0x00000020 /* .changes setting */
#define SHFLG_Echo 0x00000040 /* .echo or --echo setting */
#define SHFLG_HeaderSet 0x00000080 /* .header has been used */
#define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */
#define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */
/*
** Macros for testing and setting shellFlgs
@@ -2881,7 +2882,7 @@ static void explain_data_delete(ShellState *p){
** Disable and restore .wheretrace and .selecttrace settings.
*/
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
extern int sqlite3SelectTrace;
extern unsigned int sqlite3_unsupported_selecttrace;
static int savedSelectTrace;
#endif
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
@@ -2890,8 +2891,8 @@ static int savedWhereTrace;
#endif
static void disable_debug_trace_modes(void){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
savedSelectTrace = sqlite3SelectTrace;
sqlite3SelectTrace = 0;
savedSelectTrace = sqlite3_unsupported_selecttrace;
sqlite3_unsupported_selecttrace = 0;
#endif
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
savedWhereTrace = sqlite3WhereTrace;
@@ -2900,7 +2901,7 @@ static void disable_debug_trace_modes(void){
}
static void restore_debug_trace_modes(void){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
sqlite3SelectTrace = savedSelectTrace;
sqlite3_unsupported_selecttrace = savedSelectTrace;
#endif
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
sqlite3WhereTrace = savedWhereTrace;
@@ -3051,25 +3052,38 @@ static void exec_prepared_stmt_columnar(
ShellState *p, /* Pointer to ShellState */
sqlite3_stmt *pStmt /* Statment to run */
){
int nRow = 0;
sqlite3_int64 nRow = 0;
int nColumn = 0;
char **azData = 0;
char *zMsg = 0;
sqlite3_int64 nAlloc = 0;
const char *z;
int rc;
int i, j, nTotal, w, n;
sqlite3_int64 i, nData;
int j, nTotal, w, n;
const char *colSep = 0;
const char *rowSep = 0;
rc = sqlite3_get_table(p->db, sqlite3_sql(pStmt),
&azData, &nRow, &nColumn, &zMsg);
if( rc ){
utf8_printf(p->out, "ERROR: %s\n", zMsg);
sqlite3_free(zMsg);
sqlite3_free_table(azData);
return;
rc = sqlite3_step(pStmt);
if( rc!=SQLITE_ROW ) return;
nColumn = sqlite3_column_count(pStmt);
nAlloc = nColumn*4;
azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
if( azData==0 ) shell_out_of_memory();
for(i=0; i<nColumn; i++){
azData[i] = strdup(sqlite3_column_name(pStmt,i));
}
if( nRow==0 || nColumn==0 ) goto columnar_end;
do{
if( (nRow+2)*nColumn >= nAlloc ){
nAlloc *= 2;
azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
if( azData==0 ) shell_out_of_memory();
}
nRow++;
for(i=0; i<nColumn; i++){
z = (const char*)sqlite3_column_text(pStmt,i);
azData[nRow*nColumn + i] = z ? strdup(z) : 0;
}
}while( (rc = sqlite3_step(pStmt))==SQLITE_ROW );
if( nColumn>p->nWidth ){
p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
if( p->colWidth==0 ) shell_out_of_memory();
@@ -3179,7 +3193,9 @@ columnar_end:
if( seenInterrupt ){
utf8_printf(p->out, "Interrupt\n");
}
sqlite3_free_table(azData);
nData = (nRow+1)*nColumn;
for(i=0; i<nData; i++) free(azData[i]);
sqlite3_free(azData);
}
/*
@@ -3690,19 +3706,25 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
const char *zType;
const char *zSql;
ShellState *p = (ShellState *)pArg;
int dataOnly;
int noSys;
UNUSED_PARAMETER(azNotUsed);
if( nArg!=3 || azArg==0 ) return 0;
zTable = azArg[0];
zType = azArg[1];
zSql = azArg[2];
dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0;
noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
if( strcmp(zTable, "sqlite_sequence")==0 ){
raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
raw_printf(p->out, "ANALYZE sqlite_schema;\n");
if( strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
if( !dataOnly ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
if( !dataOnly ) raw_printf(p->out, "ANALYZE sqlite_schema;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( dataOnly ){
/* no-op */
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
char *zIns;
if( !p->writableSchema ){
@@ -3875,8 +3897,10 @@ static const char *(azHelp[]) = {
".dbinfo ?DB? Show status information about the database",
".dump ?TABLE? Render database content as SQL",
" Options:",
" --preserve-rowids Include ROWID values in the output",
" --data-only Output only INSERT statements",
" --newlines Allow unescaped newline characters in output",
" --nosys Omit system tables (ex: \"sqlite_stat1\")",
" --preserve-rowids Include ROWID values in the output",
" TABLE is a LIKE pattern for the tables to dump",
" Additional LIKE patterns can be given in subsequent arguments",
".echo on|off Turn command echo on or off",
@@ -4001,8 +4025,9 @@ static const char *(azHelp[]) = {
".save FILE Write in-memory database into FILE",
".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off",
".schema ?PATTERN? Show the CREATE statements matching PATTERN",
" Options:",
" --indent Try to pretty-print the schema",
" Options:",
" --indent Try to pretty-print the schema",
" --nosys Omit objects whose names start with \"sqlite_\"",
".selftest ?OPTIONS? Run tests defined in the SELFTEST table",
" Options:",
" --init Create a new SELFTEST table",
@@ -4411,6 +4436,20 @@ static void shellIdQuote(
}
}
/*
** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X.
*/
static void shellUSleepFunc(
sqlite3_context *context,
int argcUnused,
sqlite3_value **argv
){
int sleep = sqlite3_value_int(argv[0]);
(void)argcUnused;
sqlite3_sleep(sleep/1000);
sqlite3_result_int(context, sleep);
}
/*
** Scalar function "shell_escape_crnl" used by the .recover command.
** The argument passed to this function is the output of built-in
@@ -4575,6 +4614,7 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_uint_init(p->db, 0, 0);
sqlite3_decimal_init(p->db, 0, 0);
sqlite3_ieee_init(p->db, 0, 0);
sqlite3_series_init(p->db, 0, 0);
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
sqlite3_dbdata_init(p->db, 0, 0);
#endif
@@ -4594,6 +4634,8 @@ static void open_db(ShellState *p, int openFlags){
shellInt32, 0, 0);
sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0,
shellIdQuote, 0, 0);
sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0,
shellUSleepFunc, 0, 0);
#ifndef SQLITE_NOHAVE_SYSTEM
sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
editFunc, 0, 0);
@@ -7568,21 +7610,41 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
ShellState data;
char *zErrMsg = 0;
char **azName = 0;
int nName = 0;
sqlite3_stmt *pStmt;
int i;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.cMode = data.mode = MODE_List;
sqlite3_snprintf(sizeof(data.colSeparator),data.colSeparator,": ");
data.cnt = 0;
sqlite3_exec(p->db, "SELECT name, file FROM pragma_database_list",
callback, &data, &zErrMsg);
if( zErrMsg ){
utf8_printf(stderr,"Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
rc = 1;
}else{
while( sqlite3_step(pStmt)==SQLITE_ROW ){
const char *zSchema = (const char *)sqlite3_column_text(pStmt,1);
const char *zFile = (const char*)sqlite3_column_text(pStmt,2);
azName = sqlite3_realloc(azName, (nName+1)*2*sizeof(char*));
if( azName==0 ){ shell_out_of_memory(); /* Does not return */ }
azName[nName*2] = strdup(zSchema);
azName[nName*2+1] = strdup(zFile);
nName++;
}
}
sqlite3_finalize(pStmt);
for(i=0; i<nName; i++){
int eTxn = sqlite3_txn_state(p->db, azName[i*2]);
int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]);
const char *z = azName[i*2+1];
utf8_printf(p->out, "%s: %s %s%s\n",
azName[i*2],
z && z[0] ? z : "\"\"",
bRdonly ? "r/o" : "r/w",
eTxn==SQLITE_TXN_NONE ? "" :
eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
free(azName[i*2]);
free(azName[i*2+1]);
}
sqlite3_free(azName);
}else
if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){
@@ -7641,7 +7703,9 @@ static int do_meta_command(char *zLine, ShellState *p){
int i;
int savedShowHeader = p->showHeader;
int savedShellFlags = p->shellFlgs;
ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo);
ShellClearFlag(p,
SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo
|SHFLG_DumpDataOnly|SHFLG_DumpNoSys);
for(i=1; i<nArg; i++){
if( azArg[i][0]=='-' ){
const char *z = azArg[i]+1;
@@ -7660,6 +7724,12 @@ static int do_meta_command(char *zLine, ShellState *p){
if( strcmp(z,"newlines")==0 ){
ShellSetFlag(p, SHFLG_Newlines);
}else
if( strcmp(z,"data-only")==0 ){
ShellSetFlag(p, SHFLG_DumpDataOnly);
}else
if( strcmp(z,"nosys")==0 ){
ShellSetFlag(p, SHFLG_DumpNoSys);
}else
{
raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
rc = 1;
@@ -7676,11 +7746,13 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
/* When playing back a "dump", the content might appear in an order
** which causes immediate foreign key constraints to be violated.
** So disable foreign-key constraint enforcement to prevent problems. */
raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
raw_printf(p->out, "BEGIN TRANSACTION;\n");
if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
/* When playing back a "dump", the content might appear in an order
** which causes immediate foreign key constraints to be violated.
** So disable foreign-key constraint enforcement to prevent problems. */
raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
raw_printf(p->out, "BEGIN TRANSACTION;\n");
}
p->writableSchema = 0;
p->showHeader = 0;
/* Set writable_schema=ON since doing so forces SQLite to initialize
@@ -7698,14 +7770,16 @@ static int do_meta_command(char *zLine, ShellState *p){
);
run_schema_dump_query(p,zSql);
sqlite3_free(zSql);
zSql = sqlite3_mprintf(
"SELECT sql FROM sqlite_schema "
"WHERE (%s) AND sql NOT NULL"
" AND type IN ('index','trigger','view')",
zLike
);
run_table_dump_query(p, zSql);
sqlite3_free(zSql);
if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
zSql = sqlite3_mprintf(
"SELECT sql FROM sqlite_schema "
"WHERE (%s) AND sql NOT NULL"
" AND type IN ('index','trigger','view')",
zLike
);
run_table_dump_query(p, zSql);
sqlite3_free(zSql);
}
sqlite3_free(zLike);
if( p->writableSchema ){
raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
@@ -7713,7 +7787,9 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
}
p->showHeader = savedShowHeader;
p->shellFlgs = savedShellFlags;
}else
@@ -8152,7 +8228,7 @@ static int do_meta_command(char *zLine, ShellState *p){
while( (nSkip--)>0 ){
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
}
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
zSql = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
if( zSql==0 ){
import_cleanup(&sCtx);
shell_out_of_memory();
@@ -8161,7 +8237,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\"", zTable);
char cSep = '(';
while( xRead(&sCtx) ){
zCreate = sqlite3_mprintf("%z%c\n \"%w\" TEXT", zCreate, cSep, sCtx.z);
@@ -8182,7 +8258,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
sqlite3_free(zCreate);
if( rc ){
utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
utf8_printf(stderr, "CREATE TABLE \"%s\"(...) failed: %s\n", zTable,
sqlite3_errmsg(p->db));
import_cleanup(&sCtx);
rc = 1;
@@ -8947,9 +9023,16 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
goto meta_command_exit;
}
if( notNormalFile(azArg[1])
|| (p->in = fopen(azArg[1], "rb"))==0
){
if( azArg[1][0]=='|' ){
p->in = popen(azArg[1]+1, "r");
if( p->in==0 ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
rc = process_input(p);
pclose(p->in);
}
}else if( notNormalFile(azArg[1]) || (p->in = fopen(azArg[1], "rb"))==0 ){
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
@@ -9031,6 +9114,7 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zName = 0;
int iSchema = 0;
int bDebug = 0;
int bNoSystemTabs = 0;
int ii;
open_db(p, 0);
@@ -9043,10 +9127,16 @@ static int do_meta_command(char *zLine, ShellState *p){
data.cMode = data.mode = MODE_Pretty;
}else if( optionMatch(azArg[ii],"debug") ){
bDebug = 1;
}else if( optionMatch(azArg[ii],"nosys") ){
bNoSystemTabs = 1;
}else if( azArg[ii][0]=='-' ){
utf8_printf(stderr, "Unknown option: \"%s\"\n", azArg[ii]);
rc = 1;
goto meta_command_exit;
}else if( zName==0 ){
zName = azArg[ii];
}else{
raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
raw_printf(stderr, "Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?\n");
rc = 1;
goto meta_command_exit;
}
@@ -9132,7 +9222,10 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&sSelect, " AND ", 0);
sqlite3_free(zQarg);
}
appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
if( bNoSystemTabs ){
appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0);
}
appendText(&sSelect, "sql IS NOT NULL"
" ORDER BY snum, rowid", 0);
if( bDebug ){
utf8_printf(p->out, "SQL: %s;\n", sSelect.z);
@@ -9155,7 +9248,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
sqlite3SelectTrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
sqlite3_unsupported_selecttrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
}else
#endif
@@ -9829,6 +9922,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" },
{ "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" },
{ "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, "SEED ?db?" },
{ "seek_count", SQLITE_TESTCTRL_SEEK_COUNT, "" },
};
int testctrl = -1;
int iCtrl = -1;
@@ -9891,7 +9985,6 @@ static int do_meta_command(char *zLine, ShellState *p){
/* sqlite3_test_control(int) */
case SQLITE_TESTCTRL_PRNG_SAVE:
case SQLITE_TESTCTRL_PRNG_RESTORE:
case SQLITE_TESTCTRL_PRNG_RESET:
case SQLITE_TESTCTRL_BYTEORDER:
if( nArg==2 ){
rc2 = sqlite3_test_control(testctrl);
@@ -9965,6 +10058,14 @@ static int do_meta_command(char *zLine, ShellState *p){
}
break;
case SQLITE_TESTCTRL_SEEK_COUNT: {
u64 x = 0;
rc2 = sqlite3_test_control(testctrl, p->db, &x);
utf8_printf(p->out, "%llu\n", x);
isOk = 3;
break;
}
#ifdef YYCOVERAGE
case SQLITE_TESTCTRL_PARSER_COVERAGE:
if( nArg==2 ){
@@ -10543,8 +10644,11 @@ static void process_sqliterc(
if( stdin_is_interactive ){
utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
}
process_input(p);
if( process_input(p) && bail_on_error ) exit(1);
fclose(p->in);
}else if( sqliterc_override!=0 ){
utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc);
if( bail_on_error ) exit(1);
}
p->in = inSaved;
p->lineno = savedLineno;
@@ -10603,6 +10707,7 @@ static const char zOptions[] =
#endif
" -stats print memory stats before each finalize\n"
" -table set output mode to 'table'\n"
" -tabs set output mode to 'tabs'\n"
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
#ifdef SQLITE_ENABLE_VFSTRACE
@@ -10860,11 +10965,14 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
(void)cmdline_option_value(argc, argv, ++i);
#endif
}else if( strcmp(z,"-pagecache")==0 ){
int n, sz;
sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
sqlite3_int64 n, sz;
sz = integerValue(cmdline_option_value(argc,argv,++i));
if( sz>70000 ) sz = 70000;
if( sz<0 ) sz = 0;
n = (int)integerValue(cmdline_option_value(argc,argv,++i));
n = integerValue(cmdline_option_value(argc,argv,++i));
if( sz>0 && n>0 && 0xffffffffffffLL/sz<n ){
n = 0xffffffffffffLL/sz;
}
sqlite3_config(SQLITE_CONFIG_PAGECACHE,
(n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
data.shellFlgs |= SHFLG_Pagecache;
@@ -10926,6 +11034,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( strcmp(z, "-memtrace")==0 ){
sqlite3MemTraceActivate(stderr);
}else if( strcmp(z,"-bail")==0 ){
bail_on_error = 1;
}
}
verify_uninitialized();
@@ -11000,6 +11110,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
data.mode = MODE_List;
}else if( strcmp(z,"-quote")==0 ){
data.mode = MODE_Quote;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
}else if( strcmp(z,"-line")==0 ){
data.mode = MODE_Line;
}else if( strcmp(z,"-column")==0 ){
@@ -11033,10 +11145,12 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
data.openFlags |= SQLITE_OPEN_NOFOLLOW;
}else if( strcmp(z,"-ascii")==0 ){
data.mode = MODE_Ascii;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
SEP_Unit);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
SEP_Record);
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Unit);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Record);
}else if( strcmp(z,"-tabs")==0 ){
data.mode = MODE_List;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Tab);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
}else if( strcmp(z,"-separator")==0 ){
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
"%s",cmdline_option_value(argc,argv,++i));
@@ -11068,7 +11182,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
*/
ShellSetFlag(&data, SHFLG_Backslash);
}else if( strcmp(z,"-bail")==0 ){
bail_on_error = 1;
/* No-op. The bail_on_error flag should already be set. */
}else if( strcmp(z,"-version")==0 ){
printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
return 0;
@@ -11156,20 +11270,25 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
for(i=0; i<nCmd; i++){
if( azCmd[i][0]=='.' ){
rc = do_meta_command(azCmd[i], &data);
if( rc ) return rc==2 ? 0 : rc;
if( rc ){
free(azCmd);
return rc==2 ? 0 : rc;
}
}else{
open_db(&data, 0);
rc = shell_exec(&data, azCmd[i], &zErrMsg);
if( zErrMsg!=0 ){
utf8_printf(stderr,"Error: %s\n", zErrMsg);
if( zErrMsg || rc ){
if( zErrMsg!=0 ){
utf8_printf(stderr,"Error: %s\n", zErrMsg);
}else{
utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
}
sqlite3_free(zErrMsg);
free(azCmd);
return rc!=0 ? rc : 1;
}else if( rc!=0 ){
utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
return rc;
}
}
}
free(azCmd);
}else{
/* Run commands received from standard input
*/
@@ -11215,6 +11334,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
rc = process_input(&data);
}
}
free(azCmd);
set_table_name(&data, 0);
if( data.db ){
session_close_all(&data);
+69 -6
View File
@@ -504,6 +504,7 @@ int sqlite3_exec(
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
@@ -3696,7 +3697,7 @@ sqlite3_file *sqlite3_database_file_object(const char*);
** If the Y parameter to sqlite3_free_filename(Y) is anything other
** than a NULL pointer or a pointer previously acquired from
** sqlite3_create_filename(), then bad things such as heap
** corruption or segfaults may occur. The value Y should be
** corruption or segfaults may occur. The value Y should not be
** used again after sqlite3_free_filename(Y) has been called. This means
** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
** then the corresponding [sqlite3_module.xClose() method should also be
@@ -6186,6 +6187,57 @@ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
*/
int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine the transaction state of a database
** METHOD: sqlite3
**
** ^The sqlite3_txn_state(D,S) interface returns the current
** [transaction state] of schema S in database connection D. ^If S is NULL,
** then the highest transaction state of any schema on database connection D
** is returned. Transaction states are (in order of lowest to highest):
** <ol>
** <li value="0"> SQLITE_TXN_NONE
** <li value="1"> SQLITE_TXN_READ
** <li value="2"> SQLITE_TXN_WRITE
** </ol>
** ^If the S argument to sqlite3_txn_state(D,S) is not the name of
** a valid schema, then -1 is returned.
*/
int sqlite3_txn_state(sqlite3*,const char *zSchema);
/*
** CAPI3REF: Allowed return values from [sqlite3_txn_state()]
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
** ^The [sqlite3_txn_state(D,S)] interface returns one of these
** constants in order to describe the transaction state of schema S
** in [database connection] D.
**
** <dl>
** [[SQLITE_TXN_NONE]] <dt>SQLITE_TXN_NONE</dt>
** <dd>The SQLITE_TXN_NONE state means that no transaction is currently
** pending.</dd>
**
** [[SQLITE_TXN_READ]] <dt>SQLITE_TXN_READ</dt>
** <dd>The SQLITE_TXN_READ state means that the database is currently
** in a read transaction. Content has been read from the database file
** but nothing in the database file has changed. The transaction state
** will advanced to SQLITE_TXN_WRITE if any changes occur and there are
** no other conflicting concurrent write transactions. The transaction
** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or
** [COMMIT].</dd>
**
** [[SQLITE_TXN_WRITE]] <dt>SQLITE_TXN_WRITE</dt>
** <dd>The SQLITE_TXN_WRITE state means that the database is currently
** in a write transaction. Content has been written to the database file
** but has not yet committed. The transaction state will change to
** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
*/
#define SQLITE_TXN_NONE 0
#define SQLITE_TXN_READ 1
#define SQLITE_TXN_WRITE 2
/*
** CAPI3REF: Find the next prepared statement
** METHOD: sqlite3
@@ -7712,7 +7764,8 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
#define SQLITE_TESTCTRL_PRNG_SEED 28
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
#define SQLITE_TESTCTRL_SEEK_COUNT 30
#define SQLITE_TESTCTRL_LAST 30 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -9192,10 +9245,11 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
**
** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
** method of a [virtual table], then it returns true if and only if the
** method of a [virtual table], then it might return true if the
** column is being fetched as part of an UPDATE operation during which the
** column value will not change. Applications might use this to substitute
** a return value that is less expensive to compute and that the corresponding
** column value will not change. The virtual table implementation can use
** this hint as permission to substitute a return value that is less
** expensive to compute and that the corresponding
** [xUpdate] method understands as a "no-change" value.
**
** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
@@ -9204,6 +9258,12 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
** In that case, [sqlite3_value_nochange(X)] will return true for the
** same column in the [xUpdate] method.
**
** The sqlite3_vtab_nochange() routine is an optimization. Virtual table
** implementations should continue to give a correct answer even if the
** sqlite3_vtab_nochange() interface were to always return false. In the
** current implementation, the sqlite3_vtab_nochange() interface does always
** returns false for the enhanced [UPDATE FROM] statement.
*/
int sqlite3_vtab_nochange(sqlite3_context*);
@@ -9345,6 +9405,7 @@ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
/*
** CAPI3REF: Flush caches to disk mid-transaction
** METHOD: sqlite3
**
** ^If a write-transaction is open on [database connection] D when the
** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
@@ -9377,6 +9438,7 @@ int sqlite3_db_cacheflush(sqlite3*);
/*
** CAPI3REF: The pre-update hook.
** METHOD: sqlite3
**
** ^These interfaces are only available if SQLite is compiled using the
** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
@@ -9417,7 +9479,7 @@ int sqlite3_db_cacheflush(sqlite3*);
** seventh parameter is the final rowid value of the row being inserted
** or updated. The value of the seventh parameter passed to the callback
** function is not defined for operations on WITHOUT ROWID tables, or for
** INSERT operations on rowid tables.
** DELETE operations on rowid tables.
**
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
@@ -9479,6 +9541,7 @@ int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
/*
** CAPI3REF: Low-level system error code
** METHOD: sqlite3
**
** ^Attempt to return the underlying operating system error code or error
** number that caused the most recent I/O error or failure to open a file.
+4
View File
@@ -335,6 +335,8 @@ struct sqlite3_api_routines {
int,const char**);
void (*free_filename)(char*);
sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*);
};
/*
@@ -639,6 +641,8 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_create_filename sqlite3_api->create_filename
#define sqlite3_free_filename sqlite3_api->free_filename
#define sqlite3_database_file_object sqlite3_api->database_file_object
/* Version 3.34.0 and later */
#define sqlite3_txn_state sqlite3_api->txn_state
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+30 -22
View File
@@ -128,6 +128,15 @@
# define _BSD_SOURCE
#endif
/*
** Macro to disable warnings about missing "break" at the end of a "case".
*/
#if GCC_VERSION>=7000000
# define deliberate_fall_through __attribute__((fallthrough));
#else
# define deliberate_fall_through
#endif
/*
** For MinGW, check to see if we can include the header file containing its
** version information, among other things. Normally, this internal MinGW
@@ -983,7 +992,7 @@ typedef INT16_TYPE LogEst;
#if defined(SQLITE_ENABLE_SELECTTRACE)
# define SELECTTRACE_ENABLED 1
# define SELECTTRACE(K,P,S,X) \
if(sqlite3SelectTrace&(K)) \
if(sqlite3_unsupported_selecttrace&(K)) \
sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
sqlite3DebugPrintf X
#else
@@ -1046,7 +1055,7 @@ struct BusyHandler {
** pointer will work here as long as it is distinct from SQLITE_STATIC
** and SQLITE_TRANSIENT.
*/
#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize)
#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomFault)
/*
** When SQLITE_OMIT_WSD is defined, it means that the target platform does
@@ -1497,7 +1506,10 @@ struct sqlite3 {
int nVDestroy; /* Number of active OP_VDestroy operations */
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
int (*xTrace)(u32,void*,void*,void*); /* Trace function */
union {
void (*xLegacy)(void*,const char*); /* Legacy trace function */
int (*xV2)(u32,void*,void*,void*); /* V2 Trace function */
} trace;
void *pTraceArg; /* Argument to the trace function */
#ifndef SQLITE_OMIT_DEPRECATED
void (*xProfile)(void*,const char*,u64); /* Profiling function */
@@ -2175,6 +2187,7 @@ struct Table {
#define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */
#define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */
#define TF_Shadow 0x1000 /* True for a shadow table */
#define TF_HasStat4 0x2000 /* STAT4 info available for this table */
/*
** Test to see whether or not a table is a virtual table. This is
@@ -2540,11 +2553,6 @@ struct AggInfo {
AggInfo *pNext; /* Next in list of them all */
};
/*
** Value for AggInfo.iAggMagic when the structure is valid
*/
#define AggInfoMagic 0x2059e99e
/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
@@ -2708,7 +2716,7 @@ struct Expr {
#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
#define EP_Win 0x008000 /* Contains window functions */
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
/* 0x020000 // available for reuse */
#define EP_IfNullRow 0x020000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
@@ -2946,9 +2954,9 @@ struct SrcList {
#define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */
#define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */
#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */
#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */
/* 0x0400 not currently used */
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
#define WHERE_SEEK_UNIQ_TABLE 0x1000 /* Do not defer seeks if unique */
/* 0x1000 not currently used */
/* 0x2000 not currently used */
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
/* 0x8000 not currently used */
@@ -3145,9 +3153,6 @@ struct Select {
** statements within triggers whose only purpose is
** the side-effects of functions.
**
** All of the above are free to ignore their ORDER BY clause. Those that
** follow must honor the ORDER BY clause.
**
** SRT_Output Generate a row of output (using the OP_ResultRow
** opcode) for each row in the result set.
**
@@ -3204,13 +3209,18 @@ struct Select {
#define SRT_Except 2 /* Remove result from a UNION index */
#define SRT_Exists 3 /* Store 1 if the result is not empty */
#define SRT_Discard 4 /* Do not save the results anywhere */
#define SRT_Fifo 5 /* Store result as data with an automatic rowid */
#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */
#define SRT_DistFifo 5 /* Like SRT_Fifo, but unique results only */
#define SRT_DistQueue 6 /* Like SRT_Queue, but unique results only */
/* The DISTINCT clause is ignored for all of the above. Not that
** IgnorableDistinct() implies IgnorableOrderby() */
#define IgnorableDistinct(X) ((X->eDest)<=SRT_DistQueue)
#define SRT_Queue 7 /* Store result in an queue */
#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */
#define SRT_Fifo 8 /* Store result as data with an automatic rowid */
/* The ORDER BY clause is ignored for all of the above */
#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue)
#define IgnorableOrderby(X) ((X->eDest)<=SRT_Fifo)
#define SRT_Output 9 /* Output each row of result */
#define SRT_Mem 10 /* Store result in a memory cell */
@@ -3383,9 +3393,7 @@ struct Parse {
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
u8 explain; /* True if the EXPLAIN flag is found on the query */
#if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE))
u8 eParseMode; /* PARSE_MODE_XXX constant */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
int nVtabLock; /* Number of virtual tables to lock */
#endif
@@ -4179,7 +4187,7 @@ void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
void sqlite3AddColumn(Parse*,Token*,Token*);
void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*);
void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
void sqlite3AddCollateType(Parse*, Token*);
void sqlite3AddGenerated(Parse*,Expr*,Token*);
@@ -4586,7 +4594,7 @@ extern const unsigned char sqlite3UpperToLower[];
extern const unsigned char sqlite3CtypeMap[];
extern SQLITE_WSD struct Sqlite3Config sqlite3Config;
extern FuncDefHash sqlite3BuiltinFunctions;
extern u32 sqlite3SelectTrace;
extern u32 sqlite3_unsupported_selecttrace;
#ifndef SQLITE_OMIT_WSD
extern int sqlite3PendingByte;
#endif
+1 -5
View File
@@ -60,11 +60,7 @@
** The maximum depth of an expression tree. This is limited to
** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
** want to place more severe limits on the complexity of an
** expression.
**
** A value of 0 used to mean that the limit was not enforced.
** But that is no longer true. The limit is now strictly enforced
** at all times.
** expression. A value of 0 means that there is no limit.
*/
#ifndef SQLITE_MAX_EXPR_DEPTH
# define SQLITE_MAX_EXPR_DEPTH 1000
+1 -1
View File
@@ -352,7 +352,7 @@ int sqlite3_db_status(
*/
case SQLITE_DBSTATUS_CACHE_SPILL:
op = SQLITE_DBSTATUS_CACHE_WRITE+1;
/* Fall through into the next case */
/* no break */ deliberate_fall_through
case SQLITE_DBSTATUS_CACHE_HIT:
case SQLITE_DBSTATUS_CACHE_MISS:
case SQLITE_DBSTATUS_CACHE_WRITE:{
+335 -4
View File
@@ -3940,7 +3940,7 @@ static int SQLITE_TCLAPI test_bind_blob(
char zBuf[200];
sqlite3_snprintf(sizeof(zBuf), zBuf,
"cannot use %d blob bytes, have %d", bytes, len);
Tcl_AppendResult(interp, zBuf, -1);
Tcl_AppendResult(interp, zBuf, (char*)0);
return TCL_ERROR;
}
@@ -3953,6 +3953,195 @@ static int SQLITE_TCLAPI test_bind_blob(
return TCL_OK;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** sqlite3_carray_bind [options...] STMT NAME VALUE ...
**
** Options:
** -transient
** -static
** -int32
** -int64
** -double
** -text
**
** Each call clears static data. Called with no options does nothing
** but clear static data.
*/
static int SQLITE_TCLAPI test_carray_bind(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_stmt *pStmt;
int eType = 0; /* CARRAY_INT32 */
int nData = 0;
void *aData = 0;
int isTransient = 0;
int isStatic = 0;
int idx;
int i, j;
int rc;
void (*xDel)(void*) = sqlite3_free;
static void *aStaticData = 0;
static int nStaticData = 0;
static int eStaticType = 0;
extern int sqlite3_carray_bind(
sqlite3_stmt *pStmt,
int i,
void *aData,
int nData,
int mFlags,
void (*xDestroy)(void*)
);
if( aStaticData ){
/* Always clear preexisting static data on every call */
if( eStaticType==3 ){
for(i=0; i<nStaticData; i++){
sqlite3_free(((char**)aStaticData)[i]);
}
}
sqlite3_free(aStaticData);
aStaticData = 0;
nStaticData = 0;
eStaticType = 0;
}
if( objc==1 ) return TCL_OK;
for(i=1; i<objc && Tcl_GetString(objv[i])[0]=='-'; i++){
const char *z = Tcl_GetString(objv[i]);
if( strcmp(z, "-transient")==0 ){
isTransient = 1;
xDel = SQLITE_TRANSIENT;
}else
if( strcmp(z, "-static")==0 ){
isStatic = 1;
xDel = SQLITE_STATIC;
}else
if( strcmp(z, "-int32")==0 ){
eType = 0; /* CARRAY_INT32 */
}else
if( strcmp(z, "-int64")==0 ){
eType = 1; /* CARRAY_INT64 */
}else
if( strcmp(z, "-double")==0 ){
eType = 2; /* CARRAY_DOUBLE */
}else
if( strcmp(z, "-text")==0 ){
eType = 3; /* CARRAY_TEXT */
}else
if( strcmp(z, "--")==0 ){
break;
}else
{
Tcl_AppendResult(interp, "unknown option: ", z, (char*)0);
return TCL_ERROR;
}
}
if( eType==3 && !isStatic && !isTransient ){
Tcl_AppendResult(interp, "text data must be either -static or -transient",
(char*)0);
return TCL_ERROR;
}
if( isStatic && isTransient ){
Tcl_AppendResult(interp, "cannot be both -static and -transient",
(char*)0);
return TCL_ERROR;
}
if( objc-i < 2 ){
Tcl_WrongNumArgs(interp, 1, objv, "[OPTIONS] STMT IDX VALUE ...");
return TCL_ERROR;
}
if( getStmtPointer(interp, Tcl_GetString(objv[i]), &pStmt) ) return TCL_ERROR;
i++;
if( Tcl_GetIntFromObj(interp, objv[i], &idx) ) return TCL_ERROR;
i++;
nData = objc - i;
switch( eType + 4*(nData<=0) ){
case 0: { /* INT32 */
int *a = sqlite3_malloc( sizeof(int)*nData );
if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
for(j=0; j<nData; j++){
int v;
if( Tcl_GetIntFromObj(interp, objv[i+j], &v) ){
sqlite3_free(a);
return TCL_ERROR;
}
a[j] = v;
}
aData = a;
break;
}
case 1: { /* INT64 */
sqlite3_int64 *a = sqlite3_malloc( sizeof(sqlite3_int64)*nData );
if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
for(j=0; j<nData; j++){
Tcl_WideInt v;
if( Tcl_GetWideIntFromObj(interp, objv[i+j], &v) ){
sqlite3_free(a);
return TCL_ERROR;
}
a[j] = v;
}
aData = a;
break;
}
case 2: { /* DOUBLE */
double *a = sqlite3_malloc( sizeof(double)*nData );
if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
for(j=0; j<nData; j++){
double v;
if( Tcl_GetDoubleFromObj(interp, objv[i+j], &v) ){
sqlite3_free(a);
return TCL_ERROR;
}
a[j] = v;
}
aData = a;
break;
}
case 3: { /* TEXT */
char **a = sqlite3_malloc( sizeof(char*)*nData );
if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
for(j=0; j<nData; j++){
const char *v = Tcl_GetString(objv[i+j]);
a[j] = sqlite3_mprintf("%s", v);
}
aData = a;
break;
}
case 4: { /* nData==0 */
aData = "";
xDel = SQLITE_STATIC;
isTransient = 0;
isStatic = 0;
break;
}
}
if( isStatic ){
aStaticData = aData;
nStaticData = nData;
eStaticType = eType;
}
rc = sqlite3_carray_bind(pStmt, idx, aData, nData, eType, xDel);
if( isTransient ){
if( eType==3 ){
for(i=0; i<nData; i++) sqlite3_free(((char**)aData)[i]);
}
sqlite3_free(aData);
}
carray_bind_done:
if( rc ){
Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0);
return TCL_ERROR;
}
return TCL_OK;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/*
** Usage: sqlite3_bind_parameter_count STMT
**
@@ -6239,6 +6428,36 @@ static int SQLITE_TCLAPI file_control_vfsname(
return TCL_OK;
}
/*
** tclcmd: file_control_reservebytes DB N
*/
static int SQLITE_TCLAPI file_control_reservebytes(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3 *db;
const char *zDbName = "main";
int n = 0;
int rc;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB N");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
|| Tcl_GetIntFromObj(interp, objv[2], &n)
){
return TCL_ERROR;
}
rc = sqlite3_file_control(db, zDbName, SQLITE_FCNTL_RESERVE_BYTES, (void*)&n);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
return TCL_OK;
}
/*
** tclcmd: file_control_tempfilename DB ?AUXDB?
**
@@ -7749,6 +7968,33 @@ static int SQLITE_TCLAPI test_sqlite3_db_config(
Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
return TCL_OK;
}
/*
** tclcmd: sqlite3_txn_state DB ?SCHEMA?
**
** Invoke sqlite3_txn_state(DB,SCHEMA) and return the
** numeric value that results. Use NULL for SCHEMA if the 3 argument
** is omitted.
*/
static int SQLITE_TCLAPI test_sqlite3_txn_state(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
const char *zSchema;
int iTxn;
if( objc!=2 && objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB ?SCHEMA?");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
zSchema = objc==3 ? Tcl_GetString(objv[2]) : 0;
iTxn = sqlite3_txn_state(db, zSchema);
Tcl_SetObjResult(interp, Tcl_NewIntObj(iTxn));
return TCL_OK;
}
/*
** Change the name of the main database schema from "main" to "icecube".
@@ -7802,6 +8048,83 @@ static int SQLITE_TCLAPI test_mmap_warm(
}
}
/*
** Usage: test_write_db DB OFFSET DATA
**
** Obtain the sqlite3_file* object for the database file for the "main" db
** of handle DB. Then invoke its xWrite method to write data DATA to offset
** OFFSET.
*/
static int SQLITE_TCLAPI test_write_db(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db = 0;
Tcl_WideInt iOff = 0;
const unsigned char *aData = 0;
int nData = 0;
sqlite3_file *pFile = 0;
int rc;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB OFFSET DATA");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
if( Tcl_GetWideIntFromObj(interp, objv[2], &iOff) ) return TCL_ERROR;
aData = Tcl_GetByteArrayFromObj(objv[3], &nData);
sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFile);
rc = pFile->pMethods->xWrite(pFile, aData, nData, iOff);
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
return TCL_OK;
}
/*
** Usage: sqlite3_register_cksumvfs
**
*/
static int SQLITE_TCLAPI test_register_cksumvfs(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
if( objc!=1 ){
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}else{
extern int sqlite3_register_cksumvfs(const char*);
int rc = sqlite3_register_cksumvfs(0);
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
}
return TCL_OK;
}
/*
** Usage: sqlite3_unregister_cksumvfs
**
*/
static int SQLITE_TCLAPI test_unregister_cksumvfs(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
if( objc!=1 ){
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}else{
extern int sqlite3_unregister_cksumvfs(void);
int rc = sqlite3_unregister_cksumvfs();
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
}
return TCL_OK;
}
/*
** Usage: decode_hexdb TEXT
**
@@ -7950,6 +8273,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
void *clientData;
} aObjCmd[] = {
{ "sqlite3_db_config", test_sqlite3_db_config, 0 },
{ "sqlite3_txn_state", test_sqlite3_txn_state, 0 },
{ "bad_behavior", test_bad_behavior, (void*)&iZero },
{ "register_dbstat_vtab", test_register_dbstat_vtab },
{ "sqlite3_connection_pointer", get_sqlite_pointer, 0 },
@@ -7966,6 +8290,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_bind_text", test_bind_text ,0 },
{ "sqlite3_bind_text16", test_bind_text16 ,0 },
{ "sqlite3_bind_blob", test_bind_blob ,0 },
#ifndef SQLITE_OMIT_VIRTUALTABLE
{ "sqlite3_carray_bind", test_carray_bind ,0 },
#endif
{ "sqlite3_bind_parameter_count", test_bind_parameter_count, 0},
{ "sqlite3_bind_parameter_name", test_bind_parameter_name, 0},
{ "sqlite3_bind_parameter_index", test_bind_parameter_index, 0},
@@ -8097,6 +8424,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "file_control_persist_wal", file_control_persist_wal, 0 },
{ "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
{ "file_control_vfsname", file_control_vfsname, 0 },
{ "file_control_reservebytes", file_control_reservebytes, 0 },
{ "file_control_tempfilename", file_control_tempfilename, 0 },
{ "sqlite3_vfs_list", vfs_list, 0 },
{ "sqlite3_create_function_v2", test_create_function_v2, 0 },
@@ -8166,6 +8494,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_mmap_warm", test_mmap_warm, 0 },
{ "sqlite3_config_sorterref", test_config_sorterref, 0 },
{ "decode_hexdb", test_decode_hexdb, 0 },
{ "test_write_db", test_write_db, 0 },
{ "sqlite3_register_cksumvfs", test_register_cksumvfs, 0 },
{ "sqlite3_unregister_cksumvfs", test_unregister_cksumvfs, 0 },
};
static int bitmask_size = sizeof(Bitmask)*8;
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
@@ -8191,7 +8522,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif
#endif
#if defined(SQLITE_ENABLE_SELECTTRACE)
extern u32 sqlite3SelectTrace;
extern u32 sqlite3_unsupported_selecttrace;
#endif
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
@@ -8279,8 +8610,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
Tcl_LinkVar(interp, "sqlite_fullsync_count",
(char*)&sqlite3_fullsync_count, TCL_LINK_INT);
#if defined(SQLITE_ENABLE_SELECTTRACE)
Tcl_LinkVar(interp, "sqlite3SelectTrace",
(char*)&sqlite3SelectTrace, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite3_unsupported_selecttrace",
(char*)&sqlite3_unsupported_selecttrace, TCL_LINK_INT);
#endif
#if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST)
Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses",
+8 -4
View File
@@ -550,13 +550,16 @@ static int cfDeviceCharacteristics(sqlite3_file *pFile){
** Pass-throughs for WAL support.
*/
static int cfShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
return sqlite3OsShmLock(((CrashFile*)pFile)->pRealFile, ofst, n, flags);
sqlite3_file *pReal = ((CrashFile*)pFile)->pRealFile;
return pReal->pMethods->xShmLock(pReal, ofst, n, flags);
}
static void cfShmBarrier(sqlite3_file *pFile){
sqlite3OsShmBarrier(((CrashFile*)pFile)->pRealFile);
sqlite3_file *pReal = ((CrashFile*)pFile)->pRealFile;
pReal->pMethods->xShmBarrier(pReal);
}
static int cfShmUnmap(sqlite3_file *pFile, int delFlag){
return sqlite3OsShmUnmap(((CrashFile*)pFile)->pRealFile, delFlag);
sqlite3_file *pReal = ((CrashFile*)pFile)->pRealFile;
return pReal->pMethods->xShmUnmap(pReal, delFlag);
}
static int cfShmMap(
sqlite3_file *pFile, /* Handle open on database file */
@@ -565,7 +568,8 @@ static int cfShmMap(
int w, /* True to extend file if necessary */
void volatile **pp /* OUT: Mapped memory */
){
return sqlite3OsShmMap(((CrashFile*)pFile)->pRealFile, iRegion, sz, w, pp);
sqlite3_file *pReal = ((CrashFile*)pFile)->pRealFile;
return pReal->pMethods->xShmMap(pReal, iRegion, sz, w, pp);
}
static const sqlite3_io_methods CrashFileVtab = {
+4 -4
View File
@@ -191,7 +191,7 @@ static int devsymDeviceCharacteristics(sqlite3_file *pFile){
*/
static int devsymShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmLock(p->pReal, ofst, n, flags);
return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
}
static int devsymShmMap(
sqlite3_file *pFile,
@@ -201,15 +201,15 @@ static int devsymShmMap(
void volatile **pp
){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
return p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
}
static void devsymShmBarrier(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
sqlite3OsShmBarrier(p->pReal);
p->pReal->pMethods->xShmBarrier(p->pReal);
}
static int devsymShmUnmap(sqlite3_file *pFile, int delFlag){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmUnmap(p->pReal, delFlag);
return p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
}
+3 -3
View File
@@ -168,7 +168,7 @@ static int SQLITE_TCLAPI hexio_write(
if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
zFile = Tcl_GetString(objv[1]);
zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn);
aOut = sqlite3_malloc( nIn/2 );
aOut = sqlite3_malloc( 1 + nIn/2 );
if( aOut==0 ){
return TCL_ERROR;
}
@@ -213,7 +213,7 @@ static int SQLITE_TCLAPI hexio_get_int(
return TCL_ERROR;
}
zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn);
aOut = sqlite3_malloc( nIn/2 );
aOut = sqlite3_malloc( 1 + nIn/2 );
if( aOut==0 ){
return TCL_ERROR;
}
@@ -309,7 +309,7 @@ static int SQLITE_TCLAPI utf8_to_utf8(
return TCL_ERROR;
}
zOrig = (unsigned char *)Tcl_GetStringFromObj(objv[1], &n);
z = sqlite3_malloc( n+3 );
z = sqlite3_malloc( n+4 );
n = sqlite3TestHexToBin(zOrig, n, z);
z[n] = 0;
nOut = sqlite3Utf8To8(z);
+8 -4
View File
@@ -895,7 +895,8 @@ static int tvfsShmMap(
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
if( p->isFullshm ){
return sqlite3OsShmMap(pFd->pReal, iPage, pgsz, isWrite, pp);
sqlite3_file *pReal = pFd->pReal;
return pReal->pMethods->xShmMap(pReal, iPage, pgsz, isWrite, pp);
}
if( 0==pFd->pShm ){
@@ -945,7 +946,8 @@ static int tvfsShmLock(
char zLock[80];
if( p->isFullshm ){
return sqlite3OsShmLock(pFd->pReal, ofst, n, flags);
sqlite3_file *pReal = pFd->pReal;
return pReal->pMethods->xShmLock(pReal, ofst, n, flags);
}
if( p->pScript && p->mask&TESTVFS_SHMLOCK_MASK ){
@@ -1009,7 +1011,8 @@ static void tvfsShmBarrier(sqlite3_file *pFile){
}
if( p->isFullshm ){
sqlite3OsShmBarrier(pFd->pReal);
sqlite3_file *pReal = pFd->pReal;
pReal->pMethods->xShmBarrier(pReal);
return;
}
}
@@ -1025,7 +1028,8 @@ static int tvfsShmUnmap(
TestvfsFd **ppFd;
if( p->isFullshm ){
return sqlite3OsShmUnmap(pFd->pReal, deleteFlag);
sqlite3_file *pReal = pFd->pReal;
return pReal->pMethods->xShmUnmap(pReal, deleteFlag);
}
if( !pBuffer ) return SQLITE_OK;
+2
View File
@@ -422,6 +422,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/* If the next character is a digit, this is a floating point
** number that begins with ".". Fall thru into the next case */
/* no break */ deliberate_fall_through
}
case CC_DIGIT: {
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
@@ -526,6 +527,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
#endif
/* If it is not a BLOB literal, then it must be an ID, since no
** SQL keywords start with the letter 'x'. Fall through */
/* no break */ deliberate_fall_through
}
case CC_ID: {
i = 1;
+21 -15
View File
@@ -157,22 +157,11 @@ void sqlite3BeginTrigger(
pTab = sqlite3SrcListLookup(pParse, pTableName);
if( !pTab ){
/* The table does not exist. */
if( db->init.iDb==1 ){
/* Ticket #3810.
** Normally, whenever a table is dropped, all associated triggers are
** dropped too. But if a TEMP trigger is created on a non-TEMP table
** and the table is dropped by a different database connection, the
** trigger is not visible to the database connection that does the
** drop so the trigger cannot be dropped. This results in an
** "orphaned trigger" - a trigger whose associated table is missing.
*/
db->init.orphanTrigger = 1;
}
goto trigger_cleanup;
goto trigger_orphan_error;
}
if( IsVirtual(pTab) ){
sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
goto trigger_cleanup;
goto trigger_orphan_error;
}
/* Check that the trigger name is not reserved and that no trigger of the
@@ -210,12 +199,12 @@ void sqlite3BeginTrigger(
if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
goto trigger_cleanup;
goto trigger_orphan_error;
}
if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
" trigger on table: %S", pTableName, 0);
goto trigger_cleanup;
goto trigger_orphan_error;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -275,6 +264,23 @@ trigger_cleanup:
}else{
assert( pParse->pNewTrigger==pTrigger );
}
return;
trigger_orphan_error:
if( db->init.iDb==1 ){
/* Ticket #3810.
** Normally, whenever a table is dropped, all associated triggers are
** dropped too. But if a TEMP trigger is created on a non-TEMP table
** and the table is dropped by a different database connection, the
** trigger is not visible to the database connection that does the
** drop so the trigger cannot be dropped. This results in an
** "orphaned trigger" - a trigger whose associated table is missing.
**
** 2020-11-05 see also https://sqlite.org/forum/forumpost/157dc791df
*/
db->init.orphanTrigger = 1;
}
goto trigger_cleanup;
}
/*
+29 -13
View File
@@ -234,7 +234,7 @@ static void updateFromSelect(
#endif
pList = sqlite3ExprListAppend(pParse, pList, pNew);
}
eDest = SRT_Upfrom;
eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom;
}else if( pTab->pSelect ){
for(i=0; i<pTab->nCol; i++){
pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
@@ -651,6 +651,8 @@ void sqlite3Update(
if( nChangeFrom==0 && HasRowid(pTab) ){
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
iEph = pParse->nTab++;
addrOpen = sqlite3VdbeAddOp3(v, OP_OpenEphemeral, iEph, 0, regRowSet);
}else{
assert( pPk!=0 || HasRowid(pTab) );
nPk = pPk ? pPk->nKeyCol : 0;
@@ -705,7 +707,7 @@ void sqlite3Update(
** be deleted as a result of REPLACE conflict handling. Any of these
** things might disturb a cursor being used to scan through the table
** or index, causing a single-pass approach to malfunction. */
flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
flags = WHERE_ONEPASS_DESIRED;
if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
flags |= WHERE_ONEPASS_MULTIROW;
}
@@ -742,9 +744,10 @@ void sqlite3Update(
** leave it in register regOldRowid. */
sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
if( eOnePass==ONEPASS_OFF ){
/* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */
aRegIdx[nAllIdx] = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iEph, regRowSet, regOldRowid);
}else{
if( ALWAYS(addrOpen) ) sqlite3VdbeChangeToNoop(v, addrOpen);
}
}else{
/* Read the PK of the current row into an array of registers. In
@@ -832,8 +835,9 @@ void sqlite3Update(
VdbeCoverage(v);
}
}else{
labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak,
regOldRowid);
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
labelContinue = sqlite3VdbeMakeLabel(pParse);
addrTop = sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid);
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
VdbeCoverage(v);
@@ -1083,11 +1087,9 @@ void sqlite3Update(
}else if( eOnePass==ONEPASS_MULTI ){
sqlite3VdbeResolveLabel(v, labelContinue);
sqlite3WhereEnd(pWInfo);
}else if( pPk || nChangeFrom ){
}else{
sqlite3VdbeResolveLabel(v, labelContinue);
sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
}else{
sqlite3VdbeGoto(v, labelContinue);
}
sqlite3VdbeResolveLabel(v, labelBreak);
@@ -1187,12 +1189,26 @@ static void updateVirtualTable(
regArg = pParse->nMem + 1;
pParse->nMem += nArg;
if( pSrc->nSrc>1 ){
Index *pPk = 0;
Expr *pRow;
ExprList *pList;
if( pRowid ){
pRow = sqlite3ExprDup(db, pRowid, 0);
if( HasRowid(pTab) ){
if( pRowid ){
pRow = sqlite3ExprDup(db, pRowid, 0);
}else{
pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0);
}
}else{
pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0);
i16 iPk; /* PRIMARY KEY column */
pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pPk!=0 );
assert( pPk->nKeyCol==1 );
iPk = pPk->aiColumn[0];
if( aXRef[iPk]>=0 ){
pRow = sqlite3ExprDup(db, pChanges->a[aXRef[iPk]].pExpr, 0);
}else{
pRow = exprRowColumn(pParse, iPk);
}
}
pList = sqlite3ExprListAppend(pParse, 0, pRow);
@@ -1206,7 +1222,7 @@ static void updateVirtualTable(
}
}
updateFromSelect(pParse, ephemTab, 0, pList, pSrc, pWhere, 0, 0);
updateFromSelect(pParse, ephemTab, pPk, pList, pSrc, pWhere, 0, 0);
sqlite3ExprListDelete(db, pList);
eOnePass = ONEPASS_OFF;
}else{
+1
View File
@@ -681,6 +681,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
incr = 1;
}else{
incr = 2;
length &= ~1;
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
for(i=3-enc; i<length && zNum[i]==0; i+=2){}
nonNum = i<length;
+2 -2
View File
@@ -339,8 +339,8 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
BTREE_APPLICATION_ID, 0, /* Preserve the application id */
};
assert( 1==sqlite3BtreeIsInTrans(pTemp) );
assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) );
assert( SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pTemp) );
assert( pOut!=0 || SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pMain) );
/* Copy Btree meta values */
for(i=0; i<ArraySize(aCopy); i+=2){
+237 -36
View File
@@ -1033,6 +1033,7 @@ case OP_HaltIfNull: { /* in3 */
#endif
if( (pIn3->flags & MEM_Null)==0 ) break;
/* Fall through into OP_Halt */
/* no break */ deliberate_fall_through
}
/* Opcode: Halt P1 P2 * P4 P5
@@ -1203,6 +1204,7 @@ case OP_String8: { /* same as TK_STRING, out2 */
pOp->opcode = OP_String;
assert( rc==SQLITE_OK );
/* Fall through to the next case, OP_String */
/* no break */ deliberate_fall_through
}
/* Opcode: String P1 P2 P3 P4 P5
@@ -1514,7 +1516,7 @@ case OP_ResultRow: {
if( db->mallocFailed ) goto no_mem;
if( db->mTrace & SQLITE_TRACE_ROW ){
db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
}
@@ -3485,7 +3487,8 @@ case OP_AutoCommit: {
** active.
** If P2 is non-zero, then a write-transaction is started, or if a
** read-transaction is already active, it is upgraded to a write-transaction.
** If P2 is zero, then a read-transaction is started.
** If P2 is zero, then a read-transaction is started. If P2 is 2 or more
** then an exclusive transaction is started.
**
** P1 is the index of the database file on which the transaction is
** started. Index 0 is the main database file and index 1 is the
@@ -3519,6 +3522,7 @@ case OP_Transaction: {
assert( p->bIsReader );
assert( p->readOnly==0 || pOp->p2==0 );
assert( pOp->p2>=0 && pOp->p2<=2 );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){
@@ -3544,7 +3548,7 @@ case OP_Transaction: {
&& pOp->p2
&& (db->autoCommit==0 || db->nVdbeRead>1)
){
assert( sqlite3BtreeIsInTrans(pBt) );
assert( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE );
if( p->iStatement==0 ){
assert( db->nStatement>=0 && db->nSavepoint>=0 );
db->nStatement++;
@@ -3897,7 +3901,7 @@ case OP_OpenDup: {
}
/* Opcode: OpenEphemeral P1 P2 * P4 P5
/* Opcode: OpenEphemeral P1 P2 P3 P4 P5
** Synopsis: nColumn=P2
**
** Open a new cursor P1 to a transient table.
@@ -3917,6 +3921,10 @@ case OP_OpenDup: {
** in btree.h. These flags control aspects of the operation of
** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are
** added automatically.
**
** If P3 is positive, then reg[P3] is modified slightly so that it
** can be used as zero-length data for OP_Insert. This is an optimization
** that avoids an extra OP_Blob opcode to initialize that register.
*/
/* Opcode: OpenAutoindex P1 P2 * P4 *
** Synopsis: nColumn=P2
@@ -3939,6 +3947,15 @@ case OP_OpenEphemeral: {
SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 );
assert( pOp->p2>=0 );
if( pOp->p3>0 ){
/* Make register reg[P3] into a value that can be used as the data
** form sqlite3BtreeInsert() where the length of the data is zero. */
assert( pOp->p2==0 ); /* Only used when number of columns is zero */
assert( pOp->opcode==OP_OpenEphemeral );
assert( aMem[pOp->p3].flags & MEM_Null );
aMem[pOp->p3].n = 0;
aMem[pOp->p3].z = "";
}
pCx = p->apCsr[pOp->p1];
if( pCx && pCx->pBtx ){
/* If the ephermeral table is already open, erase all existing content
@@ -4381,22 +4398,172 @@ seek_not_found:
break;
}
/* Opcode: SeekHit P1 P2 * * *
** Synopsis: seekHit=P2
/* Opcode: SeekScan P1 P2 * * *
** Synopsis: Scan-ahead up to P1 rows
**
** Set the seekHit flag on cursor P1 to the value in P2.
** The seekHit flag is used by the IfNoHope opcode.
** This opcode is a prefix opcode to OP_SeekGE. In other words, this
** opcode must be immediately followed by OP_SeekGE. This constraint is
** checked by assert() statements.
**
** P1 must be a valid b-tree cursor. P2 must be a boolean value,
** either 0 or 1.
** This opcode uses the P1 through P4 operands of the subsequent
** OP_SeekGE. In the text that follows, the operands of the subsequent
** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only
** the P1 and P2 operands of this opcode are also used, and are called
** This.P1 and This.P2.
**
** This opcode helps to optimize IN operators on a multi-column index
** where the IN operator is on the later terms of the index by avoiding
** unnecessary seeks on the btree, substituting steps to the next row
** of the b-tree instead. A correct answer is obtained if this opcode
** is omitted or is a no-op.
**
** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which
** is the desired entry that we want the cursor SeekGE.P1 to be pointing
** to. Call this SeekGE.P4/P5 row the "target".
**
** If the SeekGE.P1 cursor is not currently pointing to a valid row,
** then this opcode is a no-op and control passes through into the OP_SeekGE.
**
** If the SeekGE.P1 cursor is pointing to a valid row, then that row
** might be the target row, or it might be near and slightly before the
** target row. This opcode attempts to position the cursor on the target
** row by, perhaps by invoking sqlite3BtreeStep() on the cursor
** between 0 and This.P1 times.
**
** There are three possible outcomes from this opcode:<ol>
**
** <li> If after This.P1 steps, the cursor is still point to a place that
** is earlier in the btree than the target row,
** then fall through into the subsquence OP_SeekGE opcode.
**
** <li> If the cursor is successfully moved to the target row by 0 or more
** sqlite3BtreeNext() calls, then jump to This.P2, which will land just
** past the OP_IdxGT opcode that follows the OP_SeekGE.
**
** <li> If the cursor ends up past the target row (indicating the the target
** row does not exist in the btree) then jump to SeekOP.P2.
** </ol>
*/
case OP_SeekScan: {
VdbeCursor *pC;
int res;
int nStep;
UnpackedRecord r;
assert( pOp[1].opcode==OP_SeekGE );
/* pOp->p2 points to the first instruction past the OP_IdxGT that
** follows the OP_SeekGE. */
assert( pOp->p2>=(int)(pOp-aOp)+2 );
assert( aOp[pOp->p2-1].opcode==OP_IdxGT );
assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
assert( pOp->p1>0 );
pC = p->apCsr[pOp[1].p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
assert( !pC->isTable );
if( !sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) ){
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... cursor not valid - fall through\n");
}
#endif
break;
}
nStep = pOp->p1;
assert( nStep>=1 );
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp[1].p4.i;
r.default_rc = 0;
r.aMem = &aMem[pOp[1].p3];
#ifdef SQLITE_DEBUG
{
int i;
for(i=0; i<r.nField; i++){
assert( memIsValid(&r.aMem[i]) );
REGISTER_TRACE(pOp[1].p3+i, &aMem[pOp[1].p3+i]);
}
}
#endif
res = 0; /* Not needed. Only used to silence a warning. */
while(1){
rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
if( rc ) goto abort_due_to_error;
if( res>0 ){
seekscan_search_fail:
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then skip\n", pOp->p1 - nStep);
}
#endif
VdbeBranchTaken(1,3);
pOp++;
goto jump_to_p2;
}
if( res==0 ){
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then success\n", pOp->p1 - nStep);
}
#endif
VdbeBranchTaken(2,3);
goto jump_to_p2;
break;
}
if( nStep<=0 ){
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... fall through after %d steps\n", pOp->p1);
}
#endif
VdbeBranchTaken(0,3);
break;
}
nStep--;
rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
if( rc ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
goto seekscan_search_fail;
}else{
goto abort_due_to_error;
}
}
}
break;
}
/* Opcode: SeekHit P1 P2 P3 * *
** Synopsis: set P2<=seekHit<=P3
**
** Increase or decrease the seekHit value for cursor P1, if necessary,
** so that it is no less than P2 and no greater than P3.
**
** The seekHit integer represents the maximum of terms in an index for which
** there is known to be at least one match. If the seekHit value is smaller
** than the total number of equality terms in an index lookup, then the
** OP_IfNoHope opcode might run to see if the IN loop can be abandoned
** early, thus saving work. This is part of the IN-early-out optimization.
**
** P1 must be a valid b-tree cursor.
*/
case OP_SeekHit: {
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pOp->p2==0 || pOp->p2==1 );
pC->seekHit = pOp->p2 & 1;
assert( pOp->p3>=pOp->p2 );
if( pC->seekHit<pOp->p2 ){
pC->seekHit = pOp->p2;
}else if( pC->seekHit>pOp->p3 ){
pC->seekHit = pOp->p3;
}
break;
}
@@ -4454,16 +4621,20 @@ case OP_IfNotOpen: { /* jump */
** Synopsis: key=r[P3@P4]
**
** Register P3 is the first of P4 registers that form an unpacked
** record.
** record. Cursor P1 is an index btree. P2 is a jump destination.
** In other words, the operands to this opcode are the same as the
** operands to OP_NotFound and OP_IdxGT.
**
** Cursor P1 is on an index btree. If the seekHit flag is set on P1, then
** this opcode is a no-op. But if the seekHit flag of P1 is clear, then
** check to see if there is any entry in P1 that matches the
** prefix identified by P3 and P4. If no entry matches the prefix,
** jump to P2. Otherwise fall through.
** This opcode is an optimization attempt only. If this opcode always
** falls through, the correct answer is still obtained, but extra works
** is performed.
**
** This opcode behaves like OP_NotFound if the seekHit
** flag is clear and it behaves like OP_Noop if the seekHit flag is set.
** A value of N in the seekHit flag of cursor P1 means that there exists
** a key P3:N that will match some record in the index. We want to know
** if it is possible for a record P3:P4 to match some record in the
** index. If it is not possible, we can skips some work. So if seekHit
** is less than P4, attempt to find out if a match is possible by running
** OP_NotFound.
**
** This opcode is used in IN clause processing for a multi-column key.
** If an IN clause is attached to an element of the key other than the
@@ -4505,8 +4676,9 @@ case OP_IfNoHope: { /* jump, in3 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
if( pC->seekHit ) break;
if( pC->seekHit>=pOp->p4.i ) break;
/* Fall through into OP_NotFound */
/* no break */ deliberate_fall_through
}
case OP_NoConflict: /* jump, in3 */
case OP_NotFound: /* jump, in3 */
@@ -4586,6 +4758,7 @@ case OP_Found: { /* jump, in3 */
}else{
VdbeBranchTaken(takeJump||alreadyExists==0,2);
if( takeJump || !alreadyExists ) goto jump_to_p2;
if( pOp->opcode==OP_IfNoHope ) pC->seekHit = pOp->p4.i;
}
break;
}
@@ -4661,6 +4834,7 @@ case OP_SeekRowid: { /* jump, in3 */
goto notExistsWithKey;
}
/* Fall through into OP_NotExists */
/* no break */ deliberate_fall_through
case OP_NotExists: /* jump, in3 */
pIn3 = &aMem[pOp->p3];
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
@@ -4941,7 +5115,7 @@ case OP_Insert: {
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
assert( pData->flags & (MEM_Blob|MEM_Str) );
assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 );
x.pData = pData->z;
x.nData = pData->n;
seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
@@ -5432,6 +5606,7 @@ case OP_Sort: { /* jump */
#endif
p->aCounter[SQLITE_STMTSTATUS_SORT]++;
/* Fall through into OP_Rewind */
/* no break */ deliberate_fall_through
}
/* Opcode: Rewind P1 P2 * * *
**
@@ -5816,7 +5991,7 @@ case OP_FinishSeek: {
break;
}
/* Opcode: IdxGE P1 P2 P3 P4 P5
/* Opcode: IdxGE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** The P4 register values beginning with P3 form an unpacked index
@@ -5827,7 +6002,7 @@ case OP_FinishSeek: {
** If the P1 index entry is greater than or equal to the key value
** then jump to P2. Otherwise fall through to the next instruction.
*/
/* Opcode: IdxGT P1 P2 P3 P4 P5
/* Opcode: IdxGT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** The P4 register values beginning with P3 form an unpacked index
@@ -5838,7 +6013,7 @@ case OP_FinishSeek: {
** If the P1 index entry is greater than the key value
** then jump to P2. Otherwise fall through to the next instruction.
*/
/* Opcode: IdxLT P1 P2 P3 P4 P5
/* Opcode: IdxLT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** The P4 register values beginning with P3 form an unpacked index
@@ -5849,7 +6024,7 @@ case OP_FinishSeek: {
** If the P1 index entry is less than the key value then jump to P2.
** Otherwise fall through to the next instruction.
*/
/* Opcode: IdxLE P1 P2 P3 P4 P5
/* Opcode: IdxLE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** The P4 register values beginning with P3 form an unpacked index
@@ -5875,7 +6050,6 @@ case OP_IdxGE: { /* jump */
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0);
assert( pC->deferredMoveto==0 );
assert( pOp->p5==0 || pOp->p5==1 );
assert( pOp->p4type==P4_INT32 );
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p4.i;
@@ -5896,8 +6070,31 @@ case OP_IdxGE: { /* jump */
}
}
#endif
res = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
/* Inlined version of sqlite3VdbeIdxKeyCompare() */
{
i64 nCellKey = 0;
BtCursor *pCur;
Mem m;
assert( pC->eCurType==CURTYPE_BTREE );
pCur = pC->uc.pCursor;
assert( sqlite3BtreeCursorIsValid(pCur) );
nCellKey = sqlite3BtreePayloadSize(pCur);
/* nCellKey will always be between 0 and 0xffffffff because of the way
** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
if( nCellKey<=0 || nCellKey>0x7fffffff ){
rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error;
}
sqlite3VdbeMemInit(&m, db, 0);
rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m);
if( rc ) goto abort_due_to_error;
res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, &r, 0);
sqlite3VdbeMemRelease(&m);
}
/* End of inlined sqlite3VdbeIdxKeyCompare() */
assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) );
if( (pOp->opcode&1)==(OP_IdxLT&1) ){
assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT );
@@ -5907,7 +6104,7 @@ case OP_IdxGE: { /* jump */
res++;
}
VdbeBranchTaken(res>0,2);
if( rc ) goto abort_due_to_error;
assert( rc==SQLITE_OK );
if( res>0 ) goto jump_to_p2;
break;
}
@@ -6785,6 +6982,7 @@ case OP_AggStep: {
pOp->opcode = OP_AggStep1;
/* Fall through into OP_AggStep */
/* no break */ deliberate_fall_through
}
case OP_AggStep1: {
int i;
@@ -7032,7 +7230,7 @@ case OP_JournalMode: { /* out2 */
/* Open a transaction on the database file. Regardless of the journal
** mode, this transaction always uses a rollback journal.
*/
assert( sqlite3BtreeIsInTrans(pBt)==0 );
assert( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE );
if( rc==SQLITE_OK ){
rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
}
@@ -7774,18 +7972,17 @@ case OP_Init: { /* jump */
){
#ifndef SQLITE_OMIT_DEPRECATED
if( db->mTrace & SQLITE_TRACE_LEGACY ){
void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
char *z = sqlite3VdbeExpandSql(p, zTrace);
x(db->pTraceArg, z);
db->trace.xLegacy(db->pTraceArg, z);
sqlite3_free(z);
}else
#endif
if( db->nVdbeExec>1 ){
char *z = sqlite3MPrintf(db, "-- %s", zTrace);
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
(void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
sqlite3DbFree(db, z);
}else{
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
(void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
}
}
#ifdef SQLITE_USE_FCNTL_TRACE
@@ -7973,7 +8170,11 @@ default: { /* This is really OP_Noop, OP_Explain */
** an error of some kind.
*/
abort_due_to_error:
if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT;
if( db->mallocFailed ){
rc = SQLITE_NOMEM_BKPT;
}else if( rc==SQLITE_IOERR_CORRUPTFS ){
rc = SQLITE_CORRUPT_BKPT;
}
assert( rc );
if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
+1 -1
View File
@@ -86,7 +86,7 @@ struct VdbeCursor {
Bool isEphemeral:1; /* True for an ephemeral table */
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
Btree *pBtx; /* Separate file holding temporary table */
i64 seqCount; /* Sequence counter */
u32 *aAltMap; /* Mapping from table to index column numbers */
+1 -1
View File
@@ -73,7 +73,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
}
#endif
if( db->mTrace & SQLITE_TRACE_PROFILE ){
db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
}
p->startTime = 0;
}
+12 -7
View File
@@ -475,6 +475,7 @@ void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
int j;
sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
sqlite3MayAbort(p->pParse);
}
/*
@@ -703,7 +704,7 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|| opcode==OP_VDestroy
|| opcode==OP_VCreate
|| (opcode==OP_ParseSchema && pOp->p4.z==0)
|| opcode==OP_ParseSchema
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
){
@@ -808,7 +809,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
switch( pOp->opcode ){
case OP_Transaction: {
if( pOp->p2!=0 ) p->readOnly = 0;
/* fall thru */
/* no break */ deliberate_fall_through
}
case OP_AutoCommit:
case OP_Savepoint: {
@@ -855,6 +856,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
n = pOp[-1].p1;
if( n>nMaxArgs ) nMaxArgs = n;
/* Fall through into the default case */
/* no break */ deliberate_fall_through
}
#endif
default: {
@@ -1520,7 +1522,7 @@ char *sqlite3VdbeDisplayComment(
sqlite3_str_appendf(&x, "%d", v1);
}else if( pCtx->argc>1 ){
sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1);
}else{
}else if( x.accError==0 ){
assert( x.nChar>2 );
x.nChar -= 2;
ii++;
@@ -2662,7 +2664,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
*/
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeIsInTrans(pBt) ){
if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){
/* Whether or not a database might need a super-journal depends upon
** its journal mode (among other things). This matrix determines which
** journal modes use a super-journal and which do not */
@@ -2797,7 +2799,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
*/
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeIsInTrans(pBt) ){
if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){
char const *zFile = sqlite3BtreeGetJournalname(pBt);
if( zFile==0 ){
continue; /* Ignore TEMP and :memory: databases */
@@ -4293,9 +4295,12 @@ SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
static int sqlite3IntFloatCompare(i64 i, double r){
if( sizeof(LONGDOUBLE_TYPE)>8 ){
LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
testcase( x<r );
testcase( x>r );
testcase( x==r );
if( x<r ) return -1;
if( x>r ) return +1;
return 0;
if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */
return 0; /*NO_TEST*/ /* work around bugs in gcov */
}else{
i64 y;
double s;
+4 -1
View File
@@ -970,13 +970,16 @@ int sqlite3VdbeSorterInit(
if( pSorter==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
Btree *pBt = db->aDb[0].pBt;
pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz);
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
pKeyInfo->db = 0;
if( nField && nWorker==0 ){
pKeyInfo->nKeyField = nField;
}
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
sqlite3BtreeEnter(pBt);
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(pBt);
sqlite3BtreeLeave(pBt);
pSorter->nTask = nWorker + 1;
pSorter->iPrev = (u8)(nWorker - 1);
pSorter->bUseThreads = (pSorter->nTask>1);

Some files were not shown because too many files have changed in this diff Show More